annotate main.c @ 6:0968b3739b8d

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