X-Git-Url: https://git.danieliu.xyz/?p=dwm.git;a=blobdiff_plain;f=dwm.c;h=b0d99c05ffed432638a943610625fa5adbbfb400;hp=3d6cc28ed228e9dbb93b4ab5e24295f5dd719bf7;hb=a9b6a312a77b9cc81ca8b08a95c09e9f7948d7a6;hpb=975c8983762246b50026d43079c60a78b341f81c diff --git a/dwm.c b/dwm.c index 3d6cc28..b0d99c0 100644 --- a/dwm.c +++ b/dwm.c @@ -3,7 +3,7 @@ * dynamic window manager is designed like any other X client as well. It is * driven through handling X events. In contrast to other X clients, a window * manager selects for SubstructureRedirectMask on the root window, to receive - * events about window (dis-)appearance. Only one X connection at a time is + * events about window (dis-)appearance. Only one X connection at a time is * allowed to select for this event mask. * * The event handlers of dwm are organized in an array which is accessed @@ -11,7 +11,7 @@ * in O(1) time. * * Each child of the root window is called a client, except windows which have - * set the override_redirect flag. Clients are organized in a linked client + * set the override_redirect flag. Clients are organized in a linked client * list on each monitor, the focus history is remembered through a stack list * on each monitor. Each client contains a bit array to indicate the tags of a * client. @@ -61,7 +61,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { SchemeNorm, SchemeSel }; /* color schemes */ -enum { NetSupported, NetWMName, NetWMState, +enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ @@ -153,7 +153,6 @@ static void buttonpress(XEvent *e); static void checkotherwm(void); static void cleanup(void); static void cleanupmon(Monitor *mon); -static void clearurgent(Client *c); static void clientmessage(XEvent *e); static void configure(Client *c); static void configurenotify(XEvent *e); @@ -204,6 +203,7 @@ static void setfullscreen(Client *c, int fullscreen); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); +static void seturgent(Client *c, int urg); static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); @@ -267,7 +267,7 @@ static Scm *scheme; static Display *dpy; static Drw *drw; static Monitor *mons, *selmon; -static Window root; +static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ #include "config.h" @@ -446,6 +446,8 @@ buttonpress(XEvent *e) click = ClkWinTitle; } else if ((c = wintoclient(ev->window))) { focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); click = ClkClientWin; } for (i = 0; i < LENGTH(buttons); i++) @@ -485,6 +487,7 @@ cleanup(void) drw_cur_free(drw, cursor[i]); for (i = 0; i < LENGTH(colors); i++) free(scheme[i]); + XDestroyWindow(dpy, wmcheckwin); drw_free(drw); XSync(dpy, False); XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); @@ -507,19 +510,6 @@ cleanupmon(Monitor *mon) free(mon); } -void -clearurgent(Client *c) -{ - XWMHints *wmh; - - c->isurgent = 0; - if (!(wmh = XGetWMHints(dpy, c->win))) - return; - wmh->flags &= ~XUrgencyHint; - XSetWMHints(dpy, c->win, wmh); - XFree(wmh); -} - void clientmessage(XEvent *e) { @@ -529,15 +519,13 @@ clientmessage(XEvent *e) if (!c) return; if (cme->message_type == netatom[NetWMState]) { - if (cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen]) + if (cme->data.l[1] == netatom[NetWMFullscreen] + || cme->data.l[2] == netatom[NetWMFullscreen]) setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ - || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); } else if (cme->message_type == netatom[NetActiveWindow]) { - if (!ISVISIBLE(c)) { - c->mon->seltags ^= 1; - c->mon->tagset[c->mon->seltags] = c->tags; - } - pop(c); + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); } } @@ -733,8 +721,8 @@ drawbar(Monitor *m) drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); if (occ & 1 << i) drw_rect(drw, x + boxs, boxs, boxw, boxw, - m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - urg & 1 << i); + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); x += w; } w = blw = TEXTW(m->ltsymbol); @@ -798,14 +786,13 @@ focus(Client *c) { if (!c || !ISVISIBLE(c)) for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); - /* was if (selmon->sel) */ if (selmon->sel && selmon->sel != c) unfocus(selmon->sel, 0); if (c) { if (c->mon != selmon) selmon = c->mon; if (c->isurgent) - clearurgent(c); + seturgent(c, 0); detachstack(c); attachstack(c); grabbuttons(c, 1); @@ -819,7 +806,7 @@ focus(Client *c) drawbars(); } -/* there are some broken focus acquiring clients */ +/* there are some broken focus acquiring clients needing extra handling */ void focusin(XEvent *e) { @@ -838,8 +825,7 @@ focusmon(const Arg *arg) return; if ((m = dirtomon(arg->i)) == selmon) return; - unfocus(selmon->sel, 0); /* s/1/0/ fixes input focus issues - in gedit and anjuta */ + unfocus(selmon->sel, 0); selmon = m; focus(NULL); } @@ -879,7 +865,7 @@ getatomprop(Client *c, Atom prop) Atom da, atom = None; if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, - &da, &di, &dl, &dl, &p) == Success && p) { + &da, &di, &dl, &dl, &p) == Success && p) { atom = *(Atom *)p; XFree(p); } @@ -906,7 +892,7 @@ getstate(Window w) Atom real; if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], - &real, &format, &n, &extra, (unsigned char **)&p) != Success) + &real, &format, &n, &extra, (unsigned char **)&p) != Success) return -1; if (n != 0) result = *p; @@ -948,17 +934,16 @@ grabbuttons(Client *c, int focused) unsigned int i, j; unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; XUngrabButton(dpy, AnyButton, AnyModifier, c->win); - if (focused) { - for (i = 0; i < LENGTH(buttons); i++) - if (buttons[i].click == ClkClientWin) - for (j = 0; j < LENGTH(modifiers); j++) - XGrabButton(dpy, buttons[i].button, - buttons[i].mask | modifiers[j], - c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - } else + if (!focused) XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, - BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].click == ClkClientWin) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); } } @@ -976,7 +961,7 @@ grabkeys(void) if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) for (j = 0; j < LENGTH(modifiers); j++) XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, - True, GrabModeAsync, GrabModeAsync); + True, GrabModeAsync, GrabModeAsync); } } @@ -1063,7 +1048,7 @@ manage(Window w, XWindowAttributes *wa) c->x = MAX(c->x, c->mon->mx); /* only fix client y-offset, if the client center might cover the bar */ c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) - && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); c->bw = borderpx; wc.border_width = c->bw; @@ -1082,7 +1067,7 @@ manage(Window w, XWindowAttributes *wa) attach(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); + (unsigned char *) &(c->win), 1); XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ setclientstate(c, NormalState); if (c->mon == selmon) @@ -1166,7 +1151,7 @@ movemouse(const Arg *arg) ocx = c->x; ocy = c->y; if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, - None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) return; if (!getrootptr(&x, &y)) return; @@ -1185,20 +1170,17 @@ movemouse(const Arg *arg) nx = ocx + (ev.xmotion.x - x); ny = ocy + (ev.xmotion.y - y); - if (nx >= selmon->wx && nx <= selmon->wx + selmon->ww - && 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) - nx = selmon->wx + selmon->ww - WIDTH(c); - if (abs(selmon->wy - ny) < snap) - ny = selmon->wy; - 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)) - togglefloating(NULL); - } + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + 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)) + togglefloating(NULL); if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) resize(c, nx, ny, c->w, c->h, 1); break; @@ -1244,7 +1226,7 @@ propertynotify(XEvent *e) default: break; case XA_WM_TRANSIENT_FOR: if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && - (c->isfloating = (wintoclient(trans)) != NULL)) + (c->isfloating = (wintoclient(trans)) != NULL)) arrange(c->mon); break; case XA_WM_NORMAL_HINTS: @@ -1324,7 +1306,7 @@ resizemouse(const Arg *arg) ocx = c->x; ocy = c->y; if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, - None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) return; XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); do { @@ -1449,7 +1431,7 @@ setclientstate(Client *c, long state) long data[] = { state, None }; XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, - PropModeReplace, (unsigned char *)data, 2); + PropModeReplace, (unsigned char *)data, 2); } int @@ -1483,8 +1465,8 @@ setfocus(Client *c) if (!c->neverfocus) { XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); XChangeProperty(dpy, root, netatom[NetActiveWindow], - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &(c->win), 1); + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); } sendevent(c, wmatom[WMTakeFocus]); } @@ -1494,7 +1476,7 @@ setfullscreen(Client *c, int fullscreen) { if (fullscreen && !c->isfullscreen) { XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, - PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); c->isfullscreen = 1; c->oldstate = c->isfloating; c->oldbw = c->bw; @@ -1504,7 +1486,7 @@ setfullscreen(Client *c, int fullscreen) XRaiseWindow(dpy, c->win); } else if (!fullscreen && c->isfullscreen){ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, - PropModeReplace, (unsigned char*)0, 0); + PropModeReplace, (unsigned char*)0, 0); c->isfullscreen = 0; c->isfloating = c->oldstate; c->bw = c->oldbw; @@ -1531,7 +1513,7 @@ setlayout(const Arg *arg) drawbar(selmon); } -/* arg > 1.0 will set mfact absolutly */ +/* arg > 1.0 will set mfact absolutely */ void setmfact(const Arg *arg) { @@ -1551,6 +1533,7 @@ setup(void) { int i; XSetWindowAttributes wa; + Atom utf8string; /* clean up any zombies immediately */ sigchld(0); @@ -1567,6 +1550,7 @@ setup(void) bh = drw->fonts->h + 2; updategeom(); /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); @@ -1575,6 +1559,7 @@ setup(void) netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); @@ -1590,20 +1575,43 @@ setup(void) /* init bars */ updatebars(); updatestatus(); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 4); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); /* EWMH support per view */ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, - PropModeReplace, (unsigned char *) netatom, NetLast); + PropModeReplace, (unsigned char *) netatom, NetLast); XDeleteProperty(dpy, root, netatom[NetClientList]); - /* select for events */ + /* select events */ wa.cursor = cursor[CurNormal]->cursor; - wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask - |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask + |ButtonPressMask|PointerMotionMask|EnterWindowMask + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); XSelectInput(dpy, root, wa.event_mask); grabkeys(); focus(NULL); } + +void +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + void showhide(Client *c) { @@ -1709,7 +1717,7 @@ togglefloating(const Arg *arg) selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; if (selmon->sel->isfloating) resize(selmon->sel, selmon->sel->x, selmon->sel->y, - selmon->sel->w, selmon->sel->h, 0); + selmon->sel->w, selmon->sel->h, 0); arrange(selmon); } @@ -1759,12 +1767,11 @@ unmanage(Client *c, int destroyed) Monitor *m = c->mon; XWindowChanges wc; - /* The server grab construct avoids race conditions. */ detach(c); detachstack(c); if (!destroyed) { wc.border_width = c->oldbw; - XGrabServer(dpy); + XGrabServer(dpy); /* avoid race conditions */ XSetErrorHandler(xerrordummy); XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ XUngrabButton(dpy, AnyButton, AnyModifier, c->win); @@ -1802,14 +1809,16 @@ updatebars(void) .background_pixmap = ParentRelative, .event_mask = ButtonPressMask|ExposureMask }; + XClassHint ch = {"dwm", "dwm"}; for (m = mons; m; m = m->next) { if (m->barwin) continue; m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), - CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); XMapRaised(dpy, m->barwin); + XSetClassHint(dpy, m->barwin, &ch); } } @@ -1836,8 +1845,8 @@ updateclientlist() for (m = mons; m; m = m->next) for (c = m->clients; c; c = c->next) XChangeProperty(dpy, root, netatom[NetClientList], - XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); } int @@ -1861,8 +1870,8 @@ updategeom(void) memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); XFree(info); nn = j; - if (n <= nn) { - for (i = 0; i < (nn - n); i++) { /* new monitors available */ + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { for (m = mons; m && m->next; m = m->next); if (m) m->next = createmon(); @@ -1871,8 +1880,8 @@ updategeom(void) } for (i = 0, m = mons; i < nn && m; m = m->next, i++) if (i >= n - || (unique[i].x_org != m->mx || unique[i].y_org != m->my - || unique[i].width != m->mw || unique[i].height != m->mh)) + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) { dirty = 1; m->num = i; @@ -1882,13 +1891,11 @@ updategeom(void) m->mh = m->wh = unique[i].height; updatebarpos(m); } - } else { - /* less monitors available nn < n */ + } else { /* less monitors available nn < n */ for (i = nn; i < n; i++) { for (m = mons; m && m->next; m = m->next); - while (m->clients) { + while ((c = m->clients)) { dirty = 1; - c = m->clients; m->clients = c->next; detachstack(c); c->mon = mons; @@ -1903,8 +1910,7 @@ updategeom(void) free(unique); } else #endif /* XINERAMA */ - /* default monitor setup */ - { + { /* default monitor setup */ if (!mons) mons = createmon(); if (mons->mw != sw || mons->mh != sh) { @@ -1932,7 +1938,7 @@ updatenumlockmask(void) for (i = 0; i < 8; i++) for (j = 0; j < modmap->max_keypermod; j++) if (modmap->modifiermap[i * modmap->max_keypermod + j] - == XKeysymToKeycode(dpy, XK_Num_Lock)) + == XKeysymToKeycode(dpy, XK_Num_Lock)) numlockmask = (1 << i); XFreeModifiermap(modmap); } @@ -1977,8 +1983,7 @@ updatesizehints(Client *c) c->maxa = (float)size.max_aspect.x / size.max_aspect.y; } else c->maxa = c->mina = 0.0; - c->isfixed = (c->maxw && c->minw && c->maxh && c->minh - && c->maxw == c->minw && c->maxh == c->minh); + c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); } void @@ -2072,8 +2077,8 @@ wintomon(Window w) } /* There's no way to check accesses to destroyed windows, thus those cases are - * ignored (especially on UnmapNotify's). Other types of errors call Xlibs - * default error handler, which may call exit. */ + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ int xerror(Display *dpy, XErrorEvent *ee) { @@ -2088,7 +2093,7 @@ xerror(Display *dpy, XErrorEvent *ee) || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) return 0; fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", - ee->request_code, ee->error_code); + ee->request_code, ee->error_code); return xerrorxlib(dpy, ee); /* may call exit */ }