summaryrefslogtreecommitdiff
path: root/dwm.c
diff options
context:
space:
mode:
Diffstat (limited to 'dwm.c')
-rw-r--r--dwm.c364
1 files changed, 126 insertions, 238 deletions
diff --git a/dwm.c b/dwm.c
index f5bdff0..f79ad07 100644
--- a/dwm.c
+++ b/dwm.c
@@ -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. */