annotate main.c @ 5:e060ab82b136

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