annotate main.c @ 1:ba504f41828f

add prev/next control to view_tags() and setlayouts()
author paulo@localhost
date Mon, 23 Mar 2009 00:14:48 -0700
parents
children faa4cb9d7bd6
rev   line source
paulo@0 1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
paulo@0 2 * See LICENSE file for license details.
paulo@0 3 */
paulo@0 4
paulo@0 5 #include "dwm.h"
paulo@0 6 #include <errno.h>
paulo@0 7 #include <locale.h>
paulo@0 8 #include <stdio.h>
paulo@0 9 #include <stdlib.h>
paulo@0 10 #include <string.h>
paulo@0 11 #include <unistd.h>
paulo@0 12 #include <sys/select.h>
paulo@0 13 #include <X11/cursorfont.h>
paulo@0 14 #include <X11/keysym.h>
paulo@0 15 #include <X11/Xatom.h>
paulo@0 16 #include <X11/Xproto.h>
paulo@0 17
paulo@0 18 /* extern */
paulo@0 19
paulo@0 20 char stext[256];
paulo@0 21 int screen, sx, sy, sw, sh, wax, way, waw, wah;
paulo@0 22 unsigned int bh, ntags, numlockmask;
paulo@0 23 Atom wmatom[WMLast], netatom[NetLast];
paulo@0 24 Bool *seltag;
paulo@0 25 Bool selscreen = True;
paulo@0 26 Client *clients = NULL;
paulo@0 27 Client *sel = NULL;
paulo@0 28 Client *stack = NULL;
paulo@0 29 Cursor cursor[CurLast];
paulo@0 30 Display *dpy;
paulo@0 31 DC dc = {0};
paulo@0 32 Window root, barwin;
paulo@0 33
paulo@0 34 /* static */
paulo@0 35
paulo@0 36 static int (*xerrorxlib)(Display *, XErrorEvent *);
paulo@0 37 static Bool otherwm, readin;
paulo@0 38 static Bool running = True;
paulo@0 39
paulo@0 40 static void
paulo@0 41 cleanup(void) {
paulo@0 42 close(STDIN_FILENO);
paulo@0 43 while(stack) {
paulo@0 44 if(stack->isbanned)
paulo@0 45 XMoveWindow(dpy, stack->win, stack->x, stack->y);
paulo@0 46 unmanage(stack);
paulo@0 47 }
paulo@0 48 if(dc.font.set)
paulo@0 49 XFreeFontSet(dpy, dc.font.set);
paulo@0 50 else
paulo@0 51 XFreeFont(dpy, dc.font.xfont);
paulo@0 52 XUngrabKey(dpy, AnyKey, AnyModifier, root);
paulo@0 53 XFreePixmap(dpy, dc.drawable);
paulo@0 54 XFreeGC(dpy, dc.gc);
paulo@0 55 XDestroyWindow(dpy, barwin);
paulo@0 56 XFreeCursor(dpy, cursor[CurNormal]);
paulo@0 57 XFreeCursor(dpy, cursor[CurResize]);
paulo@0 58 XFreeCursor(dpy, cursor[CurMove]);
paulo@0 59 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
paulo@0 60 XSync(dpy, False);
paulo@0 61 free(seltag);
paulo@0 62 }
paulo@0 63
paulo@0 64 static unsigned long
paulo@0 65 initcolor(const char *colstr) {
paulo@0 66 Colormap cmap = DefaultColormap(dpy, screen);
paulo@0 67 XColor color;
paulo@0 68
paulo@0 69 if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
paulo@0 70 eprint("error, cannot allocate color '%s'\n", colstr);
paulo@0 71 return color.pixel;
paulo@0 72 }
paulo@0 73
paulo@0 74 static void
paulo@0 75 initfont(const char *fontstr) {
paulo@0 76 char *def, **missing;
paulo@0 77 int i, n;
paulo@0 78
paulo@0 79 missing = NULL;
paulo@0 80 if(dc.font.set)
paulo@0 81 XFreeFontSet(dpy, dc.font.set);
paulo@0 82 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
paulo@0 83 if(missing) {
paulo@0 84 while(n--)
paulo@0 85 fprintf(stderr, "missing fontset: %s\n", missing[n]);
paulo@0 86 XFreeStringList(missing);
paulo@0 87 }
paulo@0 88 if(dc.font.set) {
paulo@0 89 XFontSetExtents *font_extents;
paulo@0 90 XFontStruct **xfonts;
paulo@0 91 char **font_names;
paulo@0 92 dc.font.ascent = dc.font.descent = 0;
paulo@0 93 font_extents = XExtentsOfFontSet(dc.font.set);
paulo@0 94 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
paulo@0 95 for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
paulo@0 96 if(dc.font.ascent < (*xfonts)->ascent)
paulo@0 97 dc.font.ascent = (*xfonts)->ascent;
paulo@0 98 if(dc.font.descent < (*xfonts)->descent)
paulo@0 99 dc.font.descent = (*xfonts)->descent;
paulo@0 100 xfonts++;
paulo@0 101 }
paulo@0 102 }
paulo@0 103 else {
paulo@0 104 if(dc.font.xfont)
paulo@0 105 XFreeFont(dpy, dc.font.xfont);
paulo@0 106 dc.font.xfont = NULL;
paulo@0 107 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
paulo@0 108 eprint("error, cannot load font: '%s'\n", fontstr);
paulo@0 109 dc.font.ascent = dc.font.xfont->ascent;
paulo@0 110 dc.font.descent = dc.font.xfont->descent;
paulo@0 111 }
paulo@0 112 dc.font.height = dc.font.ascent + dc.font.descent;
paulo@0 113 }
paulo@0 114
paulo@0 115 static void
paulo@0 116 scan(void) {
paulo@0 117 unsigned int i, num;
paulo@0 118 Window *wins, d1, d2;
paulo@0 119 XWindowAttributes wa;
paulo@0 120
paulo@0 121 wins = NULL;
paulo@0 122 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
paulo@0 123 for(i = 0; i < num; i++) {
paulo@0 124 if(!XGetWindowAttributes(dpy, wins[i], &wa)
paulo@0 125 || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
paulo@0 126 continue;
paulo@0 127 if(wa.map_state == IsViewable)
paulo@0 128 manage(wins[i], &wa);
paulo@0 129 }
paulo@0 130 }
paulo@0 131 if(wins)
paulo@0 132 XFree(wins);
paulo@0 133 }
paulo@0 134
paulo@0 135 static void
paulo@0 136 setup(void) {
paulo@0 137 int i, j;
paulo@0 138 unsigned int mask;
paulo@0 139 Window w;
paulo@0 140 XModifierKeymap *modmap;
paulo@0 141 XSetWindowAttributes wa;
paulo@0 142
paulo@0 143 /* init atoms */
paulo@0 144 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
paulo@0 145 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
paulo@0 146 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
paulo@0 147 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
paulo@0 148 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
paulo@0 149 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
paulo@0 150 PropModeReplace, (unsigned char *) netatom, NetLast);
paulo@0 151 /* init cursors */
paulo@0 152 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
paulo@0 153 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
paulo@0 154 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
paulo@0 155 /* init modifier map */
paulo@0 156 numlockmask = 0;
paulo@0 157 modmap = XGetModifierMapping(dpy);
paulo@0 158 for (i = 0; i < 8; i++)
paulo@0 159 for (j = 0; j < modmap->max_keypermod; j++) {
paulo@0 160 if(modmap->modifiermap[i * modmap->max_keypermod + j]
paulo@0 161 == XKeysymToKeycode(dpy, XK_Num_Lock))
paulo@0 162 numlockmask = (1 << i);
paulo@0 163 }
paulo@0 164 XFreeModifiermap(modmap);
paulo@0 165 /* select for events */
paulo@0 166 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
paulo@0 167 | EnterWindowMask | LeaveWindowMask;
paulo@0 168 wa.cursor = cursor[CurNormal];
paulo@0 169 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
paulo@0 170 grabkeys();
paulo@0 171 compileregs();
paulo@0 172 for(ntags = 0; tags[ntags]; ntags++);
paulo@0 173 seltag = emallocz(sizeof(Bool) * ntags);
paulo@0 174 seltag[0] = True;
paulo@0 175 /* style */
paulo@0 176 dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
paulo@0 177 dc.norm[ColBG] = initcolor(NORMBGCOLOR);
paulo@0 178 dc.norm[ColFG] = initcolor(NORMFGCOLOR);
paulo@0 179 dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
paulo@0 180 dc.sel[ColBG] = initcolor(SELBGCOLOR);
paulo@0 181 dc.sel[ColFG] = initcolor(SELFGCOLOR);
paulo@0 182 initfont(FONT);
paulo@0 183 /* geometry */
paulo@0 184 sx = sy = 0;
paulo@0 185 sw = DisplayWidth(dpy, screen);
paulo@0 186 sh = DisplayHeight(dpy, screen);
paulo@0 187 initlayouts();
paulo@0 188 /* bar */
paulo@0 189 dc.h = bh = dc.font.height + 2;
paulo@0 190 wa.override_redirect = 1;
paulo@0 191 wa.background_pixmap = ParentRelative;
paulo@0 192 wa.event_mask = ButtonPressMask | ExposureMask;
paulo@0 193 barwin = XCreateWindow(dpy, root, sx, sy + (TOPBAR ? 0 : sh - bh), sw, bh, 0,
paulo@0 194 DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
paulo@0 195 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
paulo@0 196 XDefineCursor(dpy, barwin, cursor[CurNormal]);
paulo@0 197 XMapRaised(dpy, barwin);
paulo@0 198 strcpy(stext, "dwm-"VERSION);
paulo@0 199 /* windowarea */
paulo@0 200 wax = sx;
paulo@0 201 way = sy + (TOPBAR ? bh : 0);
paulo@0 202 wah = sh - bh;
paulo@0 203 waw = sw;
paulo@0 204 /* pixmap for everything */
paulo@0 205 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
paulo@0 206 dc.gc = XCreateGC(dpy, root, 0, 0);
paulo@0 207 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
paulo@0 208 /* multihead support */
paulo@0 209 selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
paulo@0 210 }
paulo@0 211
paulo@0 212 /*
paulo@0 213 * Startup Error handler to check if another window manager
paulo@0 214 * is already running.
paulo@0 215 */
paulo@0 216 static int
paulo@0 217 xerrorstart(Display *dsply, XErrorEvent *ee) {
paulo@0 218 otherwm = True;
paulo@0 219 return -1;
paulo@0 220 }
paulo@0 221
paulo@0 222 /* extern */
paulo@0 223
paulo@0 224 void
paulo@0 225 sendevent(Window w, Atom a, long value) {
paulo@0 226 XEvent e;
paulo@0 227
paulo@0 228 e.type = ClientMessage;
paulo@0 229 e.xclient.window = w;
paulo@0 230 e.xclient.message_type = a;
paulo@0 231 e.xclient.format = 32;
paulo@0 232 e.xclient.data.l[0] = value;
paulo@0 233 e.xclient.data.l[1] = CurrentTime;
paulo@0 234 XSendEvent(dpy, w, False, NoEventMask, &e);
paulo@0 235 XSync(dpy, False);
paulo@0 236 }
paulo@0 237
paulo@0 238 void
paulo@0 239 quit(Arg *arg) {
paulo@0 240 readin = running = False;
paulo@0 241 }
paulo@0 242
paulo@0 243 /* There's no way to check accesses to destroyed windows, thus those cases are
paulo@0 244 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
paulo@0 245 * default error handler, which may call exit.
paulo@0 246 */
paulo@0 247 int
paulo@0 248 xerror(Display *dpy, XErrorEvent *ee) {
paulo@0 249 if(ee->error_code == BadWindow
paulo@0 250 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
paulo@0 251 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
paulo@0 252 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
paulo@0 253 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
paulo@0 254 || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
paulo@0 255 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
paulo@0 256 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
paulo@0 257 return 0;
paulo@0 258 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
paulo@0 259 ee->request_code, ee->error_code);
paulo@0 260 return xerrorxlib(dpy, ee); /* may call exit */
paulo@0 261 }
paulo@0 262
paulo@0 263 int
paulo@0 264 main(int argc, char *argv[]) {
paulo@0 265 char *p;
paulo@0 266 int r, xfd;
paulo@0 267 fd_set rd;
paulo@0 268 XEvent ev;
paulo@0 269
paulo@0 270 if(argc == 2 && !strncmp("-v", argv[1], 3))
paulo@0 271 eprint("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n");
paulo@0 272 else if(argc != 1)
paulo@0 273 eprint("usage: dwm [-v]\n");
paulo@0 274 setlocale(LC_CTYPE, "");
paulo@0 275 if(!(dpy = XOpenDisplay(0)))
paulo@0 276 eprint("dwm: cannot open display\n");
paulo@0 277 xfd = ConnectionNumber(dpy);
paulo@0 278 screen = DefaultScreen(dpy);
paulo@0 279 root = RootWindow(dpy, screen);
paulo@0 280 otherwm = False;
paulo@0 281 XSetErrorHandler(xerrorstart);
paulo@0 282 /* this causes an error if some other window manager is running */
paulo@0 283 XSelectInput(dpy, root, SubstructureRedirectMask);
paulo@0 284 XSync(dpy, False);
paulo@0 285 if(otherwm)
paulo@0 286 eprint("dwm: another window manager is already running\n");
paulo@0 287
paulo@0 288 XSync(dpy, False);
paulo@0 289 XSetErrorHandler(NULL);
paulo@0 290 xerrorxlib = XSetErrorHandler(xerror);
paulo@0 291 XSync(dpy, False);
paulo@0 292 setup();
paulo@0 293 drawstatus();
paulo@0 294 scan();
paulo@0 295
paulo@0 296 /* main event loop, also reads status text from stdin */
paulo@0 297 XSync(dpy, False);
paulo@0 298 readin = True;
paulo@0 299 while(running) {
paulo@0 300 FD_ZERO(&rd);
paulo@0 301 if(readin)
paulo@0 302 FD_SET(STDIN_FILENO, &rd);
paulo@0 303 FD_SET(xfd, &rd);
paulo@0 304 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
paulo@0 305 if(errno == EINTR)
paulo@0 306 continue;
paulo@0 307 eprint("select failed\n");
paulo@0 308 }
paulo@0 309 if(FD_ISSET(STDIN_FILENO, &rd)) {
paulo@0 310 switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) {
paulo@0 311 case -1:
paulo@0 312 strncpy(stext, strerror(errno), sizeof stext - 1);
paulo@0 313 stext[sizeof stext - 1] = '\0';
paulo@0 314 readin = False;
paulo@0 315 break;
paulo@0 316 case 0:
paulo@0 317 strncpy(stext, "EOF", 4);
paulo@0 318 readin = False;
paulo@0 319 break;
paulo@0 320 default:
paulo@0 321 for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0');
paulo@0 322 for(; p >= stext && *p != '\n'; --p);
paulo@0 323 if(p > stext)
paulo@0 324 strncpy(stext, p + 1, sizeof stext);
paulo@0 325 }
paulo@0 326 drawstatus();
paulo@0 327 }
paulo@0 328 if(FD_ISSET(xfd, &rd))
paulo@0 329 while(XPending(dpy)) {
paulo@0 330 XNextEvent(dpy, &ev);
paulo@0 331 if(handler[ev.type])
paulo@0 332 (handler[ev.type])(&ev); /* call handler */
paulo@0 333 }
paulo@0 334 }
paulo@0 335 cleanup();
paulo@0 336 XCloseDisplay(dpy);
paulo@0 337 return 0;
paulo@0 338 }