diff options
Diffstat (limited to 'dwm.c')
| -rw-r--r-- | dwm.c | 364 |
1 files changed, 126 insertions, 238 deletions
@@ -47,8 +47,8 @@ /* macros */ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) -#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \ - * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my))) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) @@ -89,7 +89,7 @@ struct Client { float mina, maxa; int x, y, w, h; int oldx, oldy, oldw, oldh; - int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; @@ -116,8 +116,7 @@ struct Monitor { float mfact; int nmaster; int num; - int by, bh; /* bar geometry */ - int tx, tw; /* bar tray geometry */ + int by; /* bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ int gappx; /* gaps between windows */ @@ -131,7 +130,6 @@ struct Monitor { Client *stack; Monitor *next; Window barwin; - Window traywin; const Layout *lt[2]; }; @@ -171,16 +169,17 @@ static void expose(XEvent *e); static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); +static void focusstack(const Arg *arg); +static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); +static void incnmaster(const Arg *arg); static void keypress(XEvent *e); static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); -static void managealtbar(Window win, XWindowAttributes *wa); -static void managetray(Window win, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); static void monocle(Monitor *m); @@ -197,32 +196,29 @@ static void resizemouse(const Arg *arg); static void restack(Monitor *m); static void run(void); static void scan(void); -static void scantray(void); static int sendevent(Client *c, Atom proto); static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); static void setfullscreen(Client *c, int fullscreen); -static void fullscreen(const Arg *arg); static void setgaps(const Arg *arg); 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); -static void spawnbar(); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); +static void togglefullscr(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); -static void unmanagealtbar(Window w); -static void unmanagetray(Window w); static void unmapnotify(XEvent *e); static void updatebarpos(Monitor *m); static void updatebars(void); @@ -237,7 +233,6 @@ static void updatewmhints(Client *c); static void view(const Arg *arg); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); -static int wmclasscontains(Window win, const char *class, const char *name); static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); @@ -353,6 +348,8 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) if (*w < bh) *w = bh; if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + if (!c->hintsvalid) + updatesizehints(c); /* see last two sentences in ICCCM 4.1.2.3 */ baseismin = c->basew == c->minw && c->baseh == c->minh; if (!baseismin) { /* temporarily remove base dimensions */ @@ -448,7 +445,7 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + blw) click = ClkLtSymbol; - else if (ev->x > selmon->ww - TEXTW(stext)) + else if (ev->x > selmon->ww - (int)TEXTW(stext)) click = ClkStatusText; else click = ClkWinTitle; @@ -495,6 +492,7 @@ cleanup(void) drw_cur_free(drw, cursor[i]); for (i = 0; i < LENGTH(colors); i++) free(scheme[i]); + free(scheme); XDestroyWindow(dpy, wmcheckwin); drw_free(drw); XSync(dpy, False); @@ -513,10 +511,8 @@ cleanupmon(Monitor *mon) for (m = mons; m && m->next != mon; m = m->next); m->next = mon->next; } - if (!usealtbar) { - XUnmapWindow(dpy, mon->barwin); - XDestroyWindow(dpy, mon->barwin); - } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); free(mon); } @@ -578,7 +574,7 @@ configurenotify(XEvent *e) for (c = m->clients; c; c = c->next) if (c->isfullscreen) resizeclient(c, m->mx, m->my, m->mw, m->mh); - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); } focus(NULL); arrange(NULL); @@ -648,9 +644,8 @@ createmon(void) m->mfact = mfact; m->nmaster = nmaster; m->showbar = showbar; - m->gappx = gappx; m->topbar = topbar; - m->bh = bh; + m->gappx = gappx; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); @@ -661,15 +656,10 @@ void destroynotify(XEvent *e) { Client *c; - Monitor *m; XDestroyWindowEvent *ev = &e->xdestroywindow; if ((c = wintoclient(ev->window))) unmanage(c, 1); - else if ((m = wintomon(ev->window)) && m->barwin == ev->window) - unmanagealtbar(ev->window); - else if (m->traywin == ev->window) - unmanagetray(ev->window); } void @@ -713,20 +703,20 @@ dirtomon(int dir) void drawbar(Monitor *m) { - if (usealtbar) - return; - - int x, w, sw = 0; + int x, w, tw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; Client *c; + if (!m->showbar) + return; + /* draw status first so it can be overdrawn by tags later */ if (m == selmon) { /* status is only drawn on selected monitor */ drw_setscheme(drw, scheme[SchemeNorm]); - sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ - drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); + tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ + drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); } for (c = m->clients; c; c = c->next) { @@ -749,7 +739,7 @@ drawbar(Monitor *m) drw_setscheme(drw, scheme[SchemeNorm]); x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - if ((w = m->ww - sw - x) > bh) { + if ((w = m->ww - tw - x) > bh) { if (m->sel) { drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); @@ -850,6 +840,32 @@ focusmon(const Arg *arg) focus(NULL); } +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + Atom getatomprop(Client *c, Atom prop) { @@ -958,6 +974,13 @@ grabkeys(void) } } +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + #ifdef XINERAMA static int isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) @@ -1067,45 +1090,6 @@ manage(Window w, XWindowAttributes *wa) } void -managealtbar(Window win, XWindowAttributes *wa) -{ - Monitor *m; - if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height))) - return; - - m->barwin = win; - m->by = wa->y; - bh = m->bh = wa->height; - updatebarpos(m); - arrange(m); - XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); - XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height); - XMapWindow(dpy, win); - XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &win, 1); -} - -void -managetray(Window win, XWindowAttributes *wa) -{ - Monitor *m; - if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height))) - return; - - m->traywin = win; - m->tx = wa->x; - m->tw = wa->width; - updatebarpos(m); - arrange(m); - XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); - XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height); - XMapWindow(dpy, win); - XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &win, 1); -} - - -void mappingnotify(XEvent *e) { XMappingEvent *ev = &e->xmapping; @@ -1125,9 +1109,7 @@ maprequest(XEvent *e) return; if (wa.override_redirect) return; - if (wmclasscontains(ev->window, altbarclass, "")) - managealtbar(ev->window, &wa); - else if (!wintoclient(ev->window)) + if (!wintoclient(ev->window)) manage(ev->window, &wa); } @@ -1259,7 +1241,7 @@ propertynotify(XEvent *e) arrange(c->mon); break; case XA_WM_NORMAL_HINTS: - updatesizehints(c); + c->hintsvalid = 0; break; case XA_WM_HINTS: updatewmhints(c); @@ -1423,9 +1405,7 @@ scan(void) if (!XGetWindowAttributes(dpy, wins[i], &wa) || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) continue; - if (wmclasscontains(wins[i], altbarclass, "")) - managealtbar(wins[i], &wa); - else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) manage(wins[i], &wa); } for (i = 0; i < num; i++) { /* now the transients */ @@ -1441,29 +1421,6 @@ scan(void) } void -scantray(void) -{ - unsigned int num; - Window d1, d2, *wins = NULL; - XWindowAttributes wa; - - if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { - for (unsigned int i = 0; i < num; i++) { - if (wmclasscontains(wins[i], altbarclass, alttrayname)) { - if (!XGetWindowAttributes(dpy, wins[i], &wa)) - break; - managetray(wins[i], &wa); - } - } - } - - if (wins) - XFree(wins); -} - - - -void sendmon(Client *c, Monitor *m) { if (c->mon == m) @@ -1563,19 +1520,6 @@ setgaps(const Arg *arg) arrange(selmon); } -Layout *last_layout; -void -fullscreen(const Arg *arg) -{ - if (selmon->showbar) { - for(last_layout = (Layout *)layouts; last_layout != selmon->lt[selmon->sellt]; last_layout++); - setlayout(&((Arg) { .v = &layouts[2] })); - } else { - setlayout(&((Arg) { .v = last_layout })); - } - togglebar(arg); -} - void setlayout(const Arg *arg) { @@ -1590,6 +1534,21 @@ setlayout(const Arg *arg) drawbar(selmon); } +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.05 || f > 0.95) + return; + selmon->mfact = f; + arrange(selmon); +} + void setup(void) { @@ -1609,8 +1568,7 @@ setup(void) if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) die("no fonts could be loaded."); lrpad = drw->fonts->h; - bh = user_bh ? user_bh : drw->fonts->h + 2; - //bh = usealtbar ? 0 : drw->fonts->h + 2; + bh = user_bh ? user_bh : drw->fonts->h + 2; updategeom(); /* init atoms */ utf8string = XInternAtom(dpy, "UTF8_STRING", False); @@ -1659,7 +1617,6 @@ setup(void) XSelectInput(dpy, root, wa.event_mask); grabkeys(); focus(NULL); - spawnbar(); } @@ -1719,13 +1676,6 @@ spawn(const Arg *arg) } void -spawnbar() -{ - if (*altbarcmd) - system(altbarcmd); -} - -void tag(const Arg *arg) { if (selmon->sel && arg->ui & TAGMASK) { @@ -1761,31 +1711,20 @@ tile(Monitor *m) if (i < m->nmaster) { h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); - if (my + HEIGHT(c) + m->gappx < m->wh) - my += HEIGHT(c) + m->gappx; + my += HEIGHT(c) + m->gappx; } else { h = (m->wh - ty) / (n - i) - m->gappx; resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); - if (ty + HEIGHT(c) + m->gappx < m->wh) - ty += HEIGHT(c) + m->gappx; + ty += HEIGHT(c) + m->gappx; } } void togglebar(const Arg *arg) { - /** - * Polybar tray does not raise maprequest event. It must be manually scanned - * for. Scanning it too early while the tray is being populated would give - * wrong dimensions. - */ - if (!selmon->traywin) - scantray(); - selmon->showbar = !selmon->showbar; updatebarpos(selmon); - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh); - XMoveResizeWindow(dpy, selmon->traywin, selmon->tx, selmon->by, selmon->tw, selmon->bh); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); } @@ -1804,6 +1743,13 @@ togglefloating(const Arg *arg) } void +togglefullscr(const Arg *arg) +{ + if(selmon->sel) + setfullscreen(selmon->sel, !selmon->sel->isfullscreen); +} + +void toggletag(const Arg *arg) { unsigned int newtags; @@ -1869,40 +1815,9 @@ unmanage(Client *c, int destroyed) } void -unmanagealtbar(Window w) -{ - Monitor *m = wintomon(w); - - if (!m) - return; - - m->barwin = 0; - m->by = 0; - m->bh = 0; - updatebarpos(m); - arrange(m); -} - -void -unmanagetray(Window w) -{ - Monitor *m = wintomon(w); - - if (!m) - return; - - m->traywin = 0; - m->tx = 0; - m->tw = 0; - updatebarpos(m); - arrange(m); -} - -void unmapnotify(XEvent *e) { Client *c; - Monitor *m; XUnmapEvent *ev = &e->xunmap; if ((c = wintoclient(ev->window))) { @@ -1910,18 +1825,12 @@ unmapnotify(XEvent *e) setclientstate(c, WithdrawnState); else unmanage(c, 0); - } else if ((m = wintomon(ev->window)) && m->barwin == ev->window) - unmanagealtbar(ev->window); - else if (m->traywin == ev->window) - unmanagetray(ev->window); + } } void updatebars(void) { - if (usealtbar) - return; - Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, @@ -1947,11 +1856,11 @@ updatebarpos(Monitor *m) m->wy = m->my; m->wh = m->mh; if (m->showbar) { - m->wh -= m->bh; + m->wh -= bh; m->by = m->topbar ? m->wy : m->wy + m->wh; - m->wy = m->topbar ? m->wy + m->bh : m->wy; + m->wy = m->topbar ? m->wy + bh : m->wy; } else - m->by = -m->bh; + m->by = -bh; } void @@ -1989,42 +1898,42 @@ updategeom(void) memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); XFree(info); nn = j; - 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(); - else - mons = createmon(); + + /* new monitors if nn > n */ + for (i = n; i < nn; i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + 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) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); } - 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) - { - dirty = 1; - m->num = i; - m->mx = m->wx = unique[i].x_org; - m->my = m->wy = unique[i].y_org; - m->mw = m->ww = unique[i].width; - m->mh = m->wh = unique[i].height; - updatebarpos(m); - } - } else { /* less monitors available nn < n */ - for (i = nn; i < n; i++) { - for (m = mons; m && m->next; m = m->next); - while ((c = m->clients)) { - dirty = 1; - m->clients = c->next; - detachstack(c); - c->mon = mons; - attach(c); - attachstack(c); - } - if (m == selmon) - selmon = mons; - cleanupmon(m); + /* removed monitors if n > nn */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while ((c = m->clients)) { + dirty = 1; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); } + if (m == selmon) + selmon = mons; + cleanupmon(m); } free(unique); } else @@ -2103,6 +2012,7 @@ updatesizehints(Client *c) } else c->maxa = c->mina = 0.0; c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); + c->hintsvalid = 1; } void @@ -2188,35 +2098,13 @@ wintomon(Window w) if (w == root && getrootptr(&x, &y)) return recttomon(x, y, 1, 1); for (m = mons; m; m = m->next) - if (w == m->barwin || w == m->traywin) + if (w == m->barwin) return m; if ((c = wintoclient(w))) return c->mon; return selmon; } -int -wmclasscontains(Window win, const char *class, const char *name) -{ - XClassHint ch = { NULL, NULL }; - int res = 1; - - if (XGetClassHint(dpy, win, &ch)) { - if (ch.res_name && strstr(ch.res_name, name) == NULL) - res = 0; - if (ch.res_class && strstr(ch.res_class, class) == NULL) - res = 0; - } else - res = 0; - - if (ch.res_class) - XFree(ch.res_class); - if (ch.res_name) - XFree(ch.res_name); - - return res; -} - /* 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. */ |
