aewl

annotate main.c @ 384:126e78129f1d

configurenotify remembers max geom now, and restores this if necessary, however it accepts to touch the max size on configurerequest, this shouldn't break fillscreen apps (tested with mplayer)
author Anselm R. Garbe <arg@10kloc.org>
date Tue, 29 Aug 2006 17:31:55 +0200
parents 175045ce7537
children 052657ff2e7b
rev   line source
garbeam@0 1 /*
garbeam@0 2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
garbeam@0 3 * See LICENSE file for license details.
garbeam@0 4 */
garbeam@0 5
garbeam@76 6 #include "dwm.h"
garbeam@59 7 #include <errno.h>
garbeam@0 8 #include <stdio.h>
garbeam@0 9 #include <stdlib.h>
garbeam@57 10 #include <string.h>
garbeam@59 11 #include <unistd.h>
arg@138 12 #include <sys/select.h>
garbeam@0 13 #include <X11/cursorfont.h>
arg@291 14 #include <X11/keysym.h>
garbeam@0 15 #include <X11/Xatom.h>
garbeam@0 16 #include <X11/Xproto.h>
garbeam@0 17
arg@333 18 /* extern */
arg@333 19
arg@333 20 char stext[1024];
arg@333 21 Bool *seltag;
arg@362 22 int bx, by, bw, bh, bmw, mw, screen, sx, sy, sw, sh;
arg@362 23 unsigned int ntags, numlockmask;
arg@333 24 Atom wmatom[WMLast], netatom[NetLast];
arg@333 25 Bool running = True;
arg@333 26 Bool issel = True;
arg@333 27 Client *clients = NULL;
arg@333 28 Client *sel = NULL;
arg@333 29 Cursor cursor[CurLast];
arg@333 30 Display *dpy;
arg@333 31 DC dc = {0};
arg@333 32 Window root, barwin;
arg@333 33
garbeam@84 34 /* static */
garbeam@0 35
arg@123 36 static int (*xerrorxlib)(Display *, XErrorEvent *);
arg@302 37 static Bool otherwm, readin;
garbeam@0 38
garbeam@0 39 static void
garbeam@76 40 cleanup()
garbeam@76 41 {
arg@302 42 close(STDIN_FILENO);
garbeam@76 43 while(sel) {
arg@99 44 resize(sel, True, TopLeft);
garbeam@76 45 unmanage(sel);
garbeam@76 46 }
arg@295 47 if(dc.font.set)
arg@295 48 XFreeFontSet(dpy, dc.font.set);
arg@295 49 else
arg@295 50 XFreeFont(dpy, dc.font.xfont);
arg@292 51 XUngrabKey(dpy, AnyKey, AnyModifier, root);
arg@295 52 XFreePixmap(dpy, dc.drawable);
arg@295 53 XFreeGC(dpy, dc.gc);
arg@309 54 XDestroyWindow(dpy, barwin);
garbeam@76 55 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
arg@292 56 XSync(dpy, False);
garbeam@76 57 }
garbeam@0 58
garbeam@0 59 static void
garbeam@75 60 scan()
garbeam@0 61 {
garbeam@0 62 unsigned int i, num;
arg@123 63 Window *wins, d1, d2;
garbeam@0 64 XWindowAttributes wa;
garbeam@0 65
arg@292 66 wins = NULL;
garbeam@0 67 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
garbeam@0 68 for(i = 0; i < num; i++) {
garbeam@0 69 if(!XGetWindowAttributes(dpy, wins[i], &wa))
garbeam@0 70 continue;
garbeam@0 71 if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
garbeam@0 72 continue;
garbeam@0 73 if(wa.map_state == IsViewable)
garbeam@10 74 manage(wins[i], &wa);
garbeam@0 75 }
garbeam@0 76 }
garbeam@0 77 if(wins)
garbeam@0 78 XFree(wins);
garbeam@0 79 }
garbeam@0 80
arg@333 81 static void
arg@333 82 setup()
arg@333 83 {
arg@333 84 int i, j;
arg@333 85 unsigned int mask;
arg@333 86 Window w;
arg@333 87 XModifierKeymap *modmap;
arg@333 88 XSetWindowAttributes wa;
arg@333 89
arg@333 90 /* init atoms */
arg@333 91 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
arg@333 92 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
arg@333 93 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
arg@333 94 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
arg@333 95 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
arg@333 96 PropModeReplace, (unsigned char *) netatom, NetLast);
arg@333 97
arg@333 98 /* init cursors */
arg@333 99 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
arg@333 100 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
arg@333 101 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
arg@333 102
arg@333 103 modmap = XGetModifierMapping(dpy);
arg@333 104 for (i = 0; i < 8; i++) {
arg@333 105 for (j = 0; j < modmap->max_keypermod; j++) {
arg@333 106 if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
arg@333 107 numlockmask = (1 << i);
arg@333 108 }
arg@333 109 }
arg@333 110 XFree(modmap);
arg@333 111
arg@333 112 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | EnterWindowMask | LeaveWindowMask;
arg@333 113 wa.cursor = cursor[CurNormal];
arg@333 114 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
arg@333 115
arg@333 116 grabkeys();
arg@333 117 initrregs();
arg@333 118
arg@333 119 for(ntags = 0; tags[ntags]; ntags++);
arg@333 120 seltag = emallocz(sizeof(Bool) * ntags);
arg@333 121 seltag[0] = True;
arg@333 122
arg@333 123 /* style */
arg@353 124 dc.norm[ColBG] = getcolor(NORMBGCOLOR);
arg@353 125 dc.norm[ColFG] = getcolor(NORMFGCOLOR);
arg@353 126 dc.sel[ColBG] = getcolor(SELBGCOLOR);
arg@353 127 dc.sel[ColFG] = getcolor(SELFGCOLOR);
arg@353 128 dc.status[ColBG] = getcolor(STATUSBGCOLOR);
arg@353 129 dc.status[ColFG] = getcolor(STATUSFGCOLOR);
arg@333 130 setfont(FONT);
arg@333 131
arg@362 132 bmw = textw(FLOATSYMBOL) > textw(TILESYMBOL) ? textw(FLOATSYMBOL) : textw(TILESYMBOL);
arg@333 133 sx = sy = 0;
arg@333 134 sw = DisplayWidth(dpy, screen);
arg@333 135 sh = DisplayHeight(dpy, screen);
arg@333 136 mw = (sw * MASTERW) / 100;
arg@333 137
arg@333 138 bx = by = 0;
arg@333 139 bw = sw;
arg@353 140 dc.h = bh = dc.font.height + 2;
arg@333 141 wa.override_redirect = 1;
arg@333 142 wa.background_pixmap = ParentRelative;
arg@333 143 wa.event_mask = ButtonPressMask | ExposureMask;
arg@333 144 barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen),
arg@333 145 CopyFromParent, DefaultVisual(dpy, screen),
arg@333 146 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
arg@333 147 XDefineCursor(dpy, barwin, cursor[CurNormal]);
arg@333 148 XMapRaised(dpy, barwin);
arg@333 149
arg@333 150 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
arg@333 151 dc.gc = XCreateGC(dpy, root, 0, 0);
arg@344 152 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
arg@333 153
arg@333 154 issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
arg@333 155 strcpy(stext, "dwm-"VERSION);
arg@333 156 }
arg@333 157
garbeam@76 158 /*
garbeam@76 159 * Startup Error handler to check if another window manager
garbeam@76 160 * is already running.
garbeam@76 161 */
garbeam@76 162 static int
garbeam@76 163 xerrorstart(Display *dsply, XErrorEvent *ee)
garbeam@76 164 {
garbeam@76 165 otherwm = True;
garbeam@76 166 return -1;
garbeam@76 167 }
garbeam@76 168
garbeam@84 169 /* extern */
garbeam@84 170
garbeam@13 171 int
garbeam@75 172 getproto(Window w)
garbeam@13 173 {
arg@329 174 int i, format, protos, status;
arg@328 175 unsigned long extra, res;
arg@328 176 Atom *protocols, real;
garbeam@13 177
arg@329 178 protos = 0;
arg@329 179 status = XGetWindowProperty(dpy, w, wmatom[WMProtocols], 0L, 20L, False,
arg@329 180 XA_ATOM, &real, &format, &res, &extra, (unsigned char **)&protocols);
arg@328 181 if(status != Success || protocols == 0)
garbeam@13 182 return protos;
arg@329 183 for(i = 0; i < res; i++)
garbeam@77 184 if(protocols[i] == wmatom[WMDelete])
arg@157 185 protos |= PROTODELWIN;
arg@328 186 free(protocols);
garbeam@13 187 return protos;
garbeam@13 188 }
garbeam@13 189
garbeam@13 190 void
garbeam@74 191 sendevent(Window w, Atom a, long value)
garbeam@13 192 {
garbeam@13 193 XEvent e;
garbeam@13 194
garbeam@13 195 e.type = ClientMessage;
garbeam@13 196 e.xclient.window = w;
garbeam@13 197 e.xclient.message_type = a;
garbeam@13 198 e.xclient.format = 32;
garbeam@13 199 e.xclient.data.l[0] = value;
garbeam@13 200 e.xclient.data.l[1] = CurrentTime;
garbeam@13 201 XSendEvent(dpy, w, False, NoEventMask, &e);
garbeam@79 202 XSync(dpy, False);
garbeam@13 203 }
garbeam@13 204
garbeam@76 205 void
garbeam@76 206 quit(Arg *arg)
garbeam@75 207 {
arg@302 208 readin = running = False;
garbeam@75 209 }
garbeam@75 210
garbeam@75 211 /*
garbeam@84 212 * There's no way to check accesses to destroyed windows, thus those cases are
garbeam@84 213 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
garbeam@84 214 * default error handler, which calls exit().
garbeam@0 215 */
garbeam@10 216 int
garbeam@75 217 xerror(Display *dpy, XErrorEvent *ee)
garbeam@0 218 {
garbeam@75 219 if(ee->error_code == BadWindow
arg@123 220 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
arg@123 221 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
arg@123 222 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
arg@123 223 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
arg@123 224 || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
arg@123 225 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess))
garbeam@0 226 return 0;
garbeam@34 227 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
arg@123 228 ee->request_code, ee->error_code);
garbeam@75 229 return xerrorxlib(dpy, ee); /* may call exit() */
garbeam@27 230 }
garbeam@27 231
garbeam@0 232 int
garbeam@0 233 main(int argc, char *argv[])
garbeam@0 234 {
arg@333 235 int r, xfd;
garbeam@59 236 fd_set rd;
garbeam@0 237
arg@137 238 if(argc == 2 && !strncmp("-v", argv[1], 3)) {
arg@137 239 fputs("dwm-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
arg@137 240 exit(EXIT_SUCCESS);
garbeam@0 241 }
arg@137 242 else if(argc != 1)
arg@137 243 eprint("usage: dwm [-v]\n");
garbeam@0 244
garbeam@0 245 dpy = XOpenDisplay(0);
garbeam@0 246 if(!dpy)
arg@197 247 eprint("dwm: cannot open display\n");
garbeam@0 248
arg@265 249 xfd = ConnectionNumber(dpy);
garbeam@0 250 screen = DefaultScreen(dpy);
garbeam@0 251 root = RootWindow(dpy, screen);
garbeam@0 252
garbeam@75 253 otherwm = False;
garbeam@75 254 XSetErrorHandler(xerrorstart);
arg@197 255 /* this causes an error if some other window manager is running */
garbeam@0 256 XSelectInput(dpy, root, SubstructureRedirectMask);
garbeam@78 257 XSync(dpy, False);
garbeam@0 258
garbeam@75 259 if(otherwm)
garbeam@75 260 eprint("dwm: another window manager is already running\n");
garbeam@0 261
arg@292 262 XSync(dpy, False);
garbeam@78 263 XSetErrorHandler(NULL);
garbeam@75 264 xerrorxlib = XSetErrorHandler(xerror);
arg@275 265 XSync(dpy, False);
garbeam@0 266
arg@333 267 setup();
garbeam@74 268 drawstatus();
garbeam@75 269 scan();
garbeam@3 270
arg@214 271 /* main event loop, also reads status text from stdin */
arg@242 272 XSync(dpy, False);
arg@292 273 procevent();
arg@302 274 readin = True;
garbeam@5 275 while(running) {
garbeam@59 276 FD_ZERO(&rd);
arg@164 277 if(readin)
arg@164 278 FD_SET(STDIN_FILENO, &rd);
arg@265 279 FD_SET(xfd, &rd);
arg@333 280 r = select(xfd + 1, &rd, NULL, NULL, NULL);
arg@333 281 if((r == -1) && (errno == EINTR))
garbeam@59 282 continue;
arg@333 283 if(r > 0) {
arg@164 284 if(readin && FD_ISSET(STDIN_FILENO, &rd)) {
arg@164 285 readin = NULL != fgets(stext, sizeof(stext), stdin);
arg@164 286 if(readin)
arg@164 287 stext[strlen(stext) - 1] = 0;
arg@162 288 else
arg@164 289 strcpy(stext, "broken pipe");
garbeam@74 290 drawstatus();
garbeam@59 291 }
garbeam@59 292 }
arg@333 293 else if(r < 0)
arg@316 294 eprint("select failed\n");
arg@293 295 procevent();
garbeam@5 296 }
garbeam@0 297 cleanup();
garbeam@0 298 XCloseDisplay(dpy);
garbeam@0 299
garbeam@0 300 return 0;
garbeam@0 301 }