X-Git-Url: https://jasonwoof.com/gitweb/?p=dwm.git;a=blobdiff_plain;f=dwm.c;h=413e79541b2b0d5b1abca311df621a779f58fc48;hp=bfeae15a3232c624c378cda06caa3c96ff6d7dde;hb=eb260b1a414fb82fc01d3638e3e77495297c45d5;hpb=fc21dd4b7e65bb511ac10f8bd8f469fe0f00a76e diff --git a/dwm.c b/dwm.c index bfeae15..413e795 100644 --- a/dwm.c +++ b/dwm.c @@ -51,7 +51,7 @@ #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) -#define TAGMASK ((int)((1LL << LENGTH(tags)) - 1)) +#define TAGMASK ((1 << LENGTH(tags)) - 1) #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height) /* enums */ @@ -207,7 +207,7 @@ static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); static void showhide(Client *c); -static void sigchld(int signal); +static void sigchld(int unused); static void spawn(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); @@ -218,7 +218,7 @@ static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c); -static void unmanage(Client *c); +static void unmanage(Client *c, Bool destroyed); static void unmapnotify(XEvent *e); static void updategeom(void); static void updatebarpos(Monitor *m); @@ -237,6 +237,7 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); /* variables */ +static const char broken[] = "broken"; static char stext[256], ntext[8]; static int screen; static int sw, sh; /* X display screen geometry width, height */ @@ -270,11 +271,12 @@ static Window root; #include "config.h" /* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { char limitexceeded[sizeof(unsigned int) * 8 < LENGTH(tags) ? -1 : 1]; }; +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; /* function implementations */ void applyrules(Client *c) { + const char *class, *instance; unsigned int i; const Rule *r; Monitor *m; @@ -283,11 +285,13 @@ applyrules(Client *c) { /* rule matching */ c->isfloating = c->tags = 0; if(XGetClassHint(dpy, c->win, &ch)) { + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; for(i = 0; i < LENGTH(rules); i++) { r = &rules[i]; if((!r->title || strstr(c->name, r->title)) - && (!r->class || (ch.res_class && strstr(ch.res_class, r->class))) - && (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) { c->isfloating = r->isfloating; c->tags |= r->tags; @@ -346,9 +350,9 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { /* adjust for aspect limits */ if(c->mina > 0 && c->maxa > 0) { if(c->maxa < (float)*w / *h) - *w = *h * c->maxa; + *w = *h * c->maxa + 0.5; else if(c->mina < (float)*h / *w) - *h = *w * c->mina; + *h = *w * c->mina + 0.5; } if(baseismin) { /* increment calculation requires this */ *w -= c->basew; @@ -376,7 +380,6 @@ void arrange(void) { Monitor *m; - /* optimise two loops into one, check focus(NULL) */ for(m = mons; m; m = m->next) showhide(m->stack); focus(NULL); @@ -416,9 +419,9 @@ buttonpress(XEvent *e) { } if(ev->window == selmon->barwin) { i = x = 0; - do + do { x += TEXTW(tags[i]); - while(ev->x >= x && ++i < LENGTH(tags)); + } while(ev->x >= x && ++i < LENGTH(tags)); if(i < LENGTH(tags)) { click = ClkTagBar; arg.ui = 1 << i; @@ -436,7 +439,7 @@ buttonpress(XEvent *e) { } for(i = 0; i < LENGTH(buttons); i++) if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button - && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); } @@ -463,7 +466,7 @@ cleanup(void) { selmon->lt[selmon->sellt] = &foo; for(m = mons; m; m = m->next) while(m->stack) - unmanage(m->stack); + unmanage(m->stack, False); if(dc.font.set) XFreeFontSet(dpy, dc.font.set); else @@ -527,7 +530,7 @@ configurenotify(XEvent *e) { Monitor *m; XConfigureEvent *ev = &e->xconfigure; - if(ev->window == root && (ev->width != sw || ev->height != sh)) { + if(ev->window == root) { sw = ev->width; sh = ev->height; updategeom(); @@ -561,9 +564,9 @@ configurerequest(XEvent *e) { c->w = ev->width; if(ev->value_mask & CWHeight) c->h = ev->height; - if((c->x - m->mx + c->w) > m->mw && c->isfloating) + if((c->x + c->w) > m->mx + m->mw && c->isfloating) c->x = m->mx + (m->mw / 2 - c->w / 2); /* center in x direction */ - if((c->y - m->my + c->h) > m->mh && c->isfloating) + if((c->y + c->h) > m->my + m->mh && c->isfloating) c->y = m->my + (m->mh / 2 - c->h / 2); /* center in y direction */ if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) configure(c); @@ -592,7 +595,7 @@ destroynotify(XEvent *e) { XDestroyWindowEvent *ev = &e->xdestroywindow; if((c = wintoclient(ev->window))) - unmanage(c); + unmanage(c, True); } void @@ -881,7 +884,7 @@ getstate(Window w) { Atom real; status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], - &real, &format, &n, &extra, (unsigned char **)&p); + &real, &format, &n, &extra, (unsigned char **)&p); if(status != Success) return -1; if(n != 0) @@ -905,9 +908,7 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) { if(name.encoding == XA_STRING) strncpy(text, (char *)name.value, size - 1); else { - if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success - && n > 0 && *list) - { + if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { strncpy(text, *list, size - 1); XFreeStringList(list); } @@ -973,6 +974,7 @@ initfont(const char *fontstr) { XFontSetExtents *font_extents; XFontStruct **xfonts; char **font_names; + dc.font.ascent = dc.font.descent = 0; font_extents = XExtentsOfFontSet(dc.font.set); n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); @@ -1017,8 +1019,8 @@ keypress(XEvent *e) { keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); for(i = 0; i < LENGTH(keys); i++) if(keysym == keys[i].keysym - && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) - && keys[i].func) + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) keys[i].func(&(keys[i].arg)); } @@ -1039,6 +1041,7 @@ killclient(const Arg *arg) { } else XKillClient(dpy, selmon->sel->win); + XSync(dpy, False); } void @@ -1163,7 +1166,7 @@ movemouse(const Arg *arg) { nx = ocx + (ev.xmotion.x - x); ny = ocy + (ev.xmotion.y - y); if(snap && nx >= selmon->wx && nx <= selmon->wx + selmon->ww - && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) { + && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) { if(abs(selmon->wx - nx) < snap) nx = selmon->wx; else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) @@ -1173,15 +1176,14 @@ movemouse(const Arg *arg) { else if(abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) ny = selmon->wy + selmon->wh - HEIGHT(c); if(!c->isfloating && selmon->lt[selmon->sellt]->arrange - && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) togglefloating(NULL); } if(!selmon->lt[selmon->sellt]->arrange || c->isfloating) resize(c, nx, ny, c->w, c->h, True); break; } - } - while(ev.type != ButtonRelease); + } while(ev.type != ButtonRelease); XUngrabPointer(dpy, CurrentTime); if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { sendmon(c, m); @@ -1234,8 +1236,8 @@ propertynotify(XEvent *e) { } if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { updatetitle(c); - if(c == selmon->sel) - drawbars(); + if(c == c->mon->sel) + drawbar(c->mon); } } } @@ -1275,7 +1277,7 @@ resizemouse(const Arg *arg) { ocx = c->x; ocy = c->y; if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, - None, cursor[CurResize], CurrentTime) != GrabSuccess) + None, cursor[CurResize], CurrentTime) != GrabSuccess) return; XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); do { @@ -1290,17 +1292,17 @@ resizemouse(const Arg *arg) { nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); if(snap && nw >= selmon->wx && nw <= selmon->wx + selmon->ww - && nh >= selmon->wy && nh <= selmon->wy + selmon->wh) { + && nh >= selmon->wy && nh <= selmon->wy + selmon->wh) + { if(!c->isfloating && selmon->lt[selmon->sellt]->arrange - && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) togglefloating(NULL); } if(!selmon->lt[selmon->sellt]->arrange || c->isfloating) resize(c, c->x, c->y, nw, nh, True); break; } - } - while(ev.type != ButtonRelease); + } while(ev.type != ButtonRelease); XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); XUngrabPointer(dpy, CurrentTime); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); @@ -1343,7 +1345,7 @@ run(void) { XSync(dpy, False); while(running && !XNextEvent(dpy, &ev)) if(handler[ev.type]) - (handler[ev.type])(&ev); /* call handler */ + handler[ev.type](&ev); /* call handler */ } void @@ -1427,6 +1429,9 @@ setup(void) { int w; XSetWindowAttributes wa; + /* clean up any zombies immediately */ + sigchld(0); + /* init screen */ screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); @@ -1470,8 +1475,8 @@ setup(void) { /* select for events */ wa.cursor = cursor[CurNormal]; wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask - |EnterWindowMask|LeaveWindowMask|StructureNotifyMask - |PropertyChangeMask; + |EnterWindowMask|LeaveWindowMask|StructureNotifyMask + |PropertyChangeMask; XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); XSelectInput(dpy, root, wa.event_mask); grabkeys(); @@ -1495,13 +1500,14 @@ showhide(Client *c) { void -sigchld(int signal) { +sigchld(int unused) { + if(signal(SIGCHLD, sigchld) == SIG_ERR) + die("Can't install SIGCHLD handler"); while(0 < waitpid(-1, NULL, WNOHANG)); } void spawn(const Arg *arg) { - signal(SIGCHLD, sigchld); if(fork() == 0) { if(dpy) close(ConnectionNumber(dpy)); @@ -1590,23 +1596,23 @@ togglefloating(const Arg *arg) { void toggletag(const Arg *arg) { - unsigned int mask; + unsigned int newtags; if(!selmon->sel) return; - mask = selmon->sel->tags ^ (arg->ui & TAGMASK); - if(mask) { - selmon->sel->tags = mask; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if(newtags) { + selmon->sel->tags = newtags; arrange(); } } void toggleview(const Arg *arg) { - unsigned int mask = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); - if(mask) { - selmon->tagset[selmon->seltags] = mask; + if(newtagset) { + selmon->tagset[selmon->seltags] = newtagset; arrange(); } } @@ -1621,24 +1627,25 @@ unfocus(Client *c) { } void -unmanage(Client *c) { +unmanage(Client *c, Bool destroyed) { XWindowChanges wc; - wc.border_width = c->oldbw; /* The server grab construct avoids race conditions. */ - XGrabServer(dpy); - XSetErrorHandler(xerrordummy); - XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ detach(c); detachstack(c); - XUngrabButton(dpy, AnyButton, AnyModifier, c->win); - setclientstate(c, WithdrawnState); + if(!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } free(c); - XSync(dpy, False); - XSetErrorHandler(xerror); - XUngrabServer(dpy); focus(NULL); - arrange(); } void @@ -1647,7 +1654,7 @@ unmapnotify(XEvent *e) { XUnmapEvent *ev = &e->xunmap; if((c = wintoclient(ev->window))) - unmanage(c); + unmanage(c, False); } void @@ -1687,10 +1694,16 @@ updategeom(void) { Monitor *newmons = NULL, *m = NULL, *tm; #ifdef XINERAMA + int nn; XineramaScreenInfo *info = NULL; if(XineramaIsActive(dpy)) info = XineramaQueryScreens(dpy, &n); + for(i = 1, nn = n; i < n; i++) + if(info[i - 1].x_org == info[i].x_org && info[i - 1].y_org == info[i].y_org + && info[i - 1].width == info[i].width && info[i - 1].height == info[i].height) + --nn; + n = nn; /* we only consider unique geometries as separate screens */ #endif /* XINERAMA */ /* allocate monitor(s) for the new geometry setup */ for(i = 0; i < n; i++) { @@ -1806,8 +1819,8 @@ updatesizehints(Client *c) { else c->minw = c->minh = 0; if(size.flags & PAspect) { - c->mina = (float)size.min_aspect.y / (float)size.min_aspect.x; - c->maxa = (float)size.max_aspect.x / (float)size.max_aspect.y; + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; } else c->maxa = c->mina = 0.0; @@ -1819,6 +1832,8 @@ void updatetitle(Client *c) { if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if(c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); } void