aboutsummaryrefslogtreecommitdiffstats
path: root/dwm.c
diff options
context:
space:
mode:
authorJoe <rbo@gmx.us>2024-12-19 15:06:27 +0100
committerJoe <rbo@gmx.us>2024-12-19 15:06:27 +0100
commit03765f41f101502e9825047419fa9d8667e710ea (patch)
treecef6445d9c3df3081aed9f8cd28555ecfd88e401 /dwm.c
parentconflict (diff)
downloaddwm-03765f41f101502e9825047419fa9d8667e710ea.tar.gz
dwm-03765f41f101502e9825047419fa9d8667e710ea.tar.bz2
dwm-03765f41f101502e9825047419fa9d8667e710ea.tar.xz
dwm-03765f41f101502e9825047419fa9d8667e710ea.tar.zst
dwm-03765f41f101502e9825047419fa9d8667e710ea.zip
6.5
Diffstat (limited to '')
-rw-r--r--dwm.c1275
1 files changed, 825 insertions, 450 deletions
diff --git a/dwm.c b/dwm.c
index d6788e0..6379295 100644
--- a/dwm.c
+++ b/dwm.c
@@ -40,6 +40,12 @@
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
+#include <X11/Xlib-xcb.h>
+#include <xcb/res.h>
+#ifdef __OpenBSD__
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif /* __OpenBSD */
#include "drw.h"
#include "util.h"
@@ -51,7 +57,6 @@
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
#define ISVISIBLEONTAG(C, T) ((C->tags & T))
#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags])
-#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
@@ -106,13 +111,15 @@ struct Client {
int x, y, w, h;
int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
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;
- unsigned int switchtotag;
- int isfixed, isfloating, isfreesize, isurgent, neverfocus, oldstate, isfullscreen;
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow, isforegrounded;
+ pid_t pid;
Client *next;
Client *snext;
+ Client *tnext;
+ Client *swallowing;
Monitor *mon;
Window win;
};
@@ -147,6 +154,7 @@ struct Monitor {
Client *clients;
Client *sel;
Client *stack;
+ Client *foregrounded;
Monitor *next;
Window barwin;
const Layout *lt[2];
@@ -158,9 +166,9 @@ typedef struct {
const char *instance;
const char *title;
unsigned int tags;
- unsigned int switchtotag;
int isfloating;
- int isfreesize;
+ int isterminal;
+ int noswallow;
int monitor;
} Rule;
@@ -179,6 +187,10 @@ static void attach(Client *c);
static void attachBelow(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
+static void bstack(Monitor *m);
+static void bstackhoriz(Monitor *m);
+static void centeredmaster(Monitor *m);
+static void centeredfloatingmaster(Monitor *m);
static void checkotherwm(void);
static void cleanup(void);
static void cleanupmon(Monitor *mon);
@@ -203,7 +215,7 @@ 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 unsigned int getsystraywidth();
+static unsigned int getsystraywidth(void);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, int focused);
static void grabkeys(void);
@@ -215,9 +227,10 @@ static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
static void movemouse(const Arg *arg);
+static void movestack(const Arg *arg);
static Client *nexttagged(Client *c);
static Client *nexttiled(Client *c);
-static void pop(Client *);
+static void nrowgrid(Monitor *m);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static Monitor *recttomon(int x, int y, int w, int h);
@@ -241,7 +254,6 @@ 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 Monitor *systraytomon(Monitor *m);
static void switchtag(const Arg *arg);
@@ -250,9 +262,10 @@ static void tagmon(const Arg *arg);
static void tagnextmon(const Arg *arg);
static void tagprevmon(const Arg *arg);
static void tagothermon(const Arg *arg, int dir);
-static void tile(Monitor *);
+static void tile(Monitor *m);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
+static void toggleforegrounded(const Arg *arg);
static void togglefullscr(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
@@ -276,15 +289,17 @@ static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static Client *wintosystrayicon(Window w);
+static void winview(const Arg* arg);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
-static void centeredmaster(Monitor *m);
-static void centeredfloatingmaster(Monitor *m);
-static void bstack(Monitor *m);
-static void bstackhoriz(Monitor *m);
-static void stairs(Monitor *m);
+
+static pid_t getparentprocess(pid_t p);
+static int isdescprocess(pid_t p, pid_t c);
+static Client *swallowingclient(Window w);
+static Client *termforwin(const Client *c);
+static pid_t winpid(Window w);
/* variables */
static Systray *systray = NULL;
@@ -293,7 +308,7 @@ static const char broken[] = "broken";
static char stext[256];
static int screen;
static int sw, sh; /* X display screen geometry width, height */
-static int bh, blw = 0; /* bar geometry */
+static int bh; /* bar height */
static int lrpad; /* sum of left and right padding for text */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
@@ -316,12 +331,14 @@ static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
static int running = 1;
static Cur *cursor[CurLast];
static Clr **scheme;
-static Clr **tagscheme;
static Display *dpy;
static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
+static xcb_connection_t *xcon;
+
+
/* configuration, allows nested code to access above variables */
#include "config.h"
@@ -349,7 +366,6 @@ applyrules(Client *c)
/* rule matching */
c->isfloating = 0;
- c->isfreesize = 1;
c->tags = 0;
XGetClassHint(dpy, c->win, &ch);
class = ch.res_class ? ch.res_class : broken;
@@ -361,17 +377,13 @@ applyrules(Client *c)
&& (!r->class || strstr(class, r->class))
&& (!r->instance || strstr(instance, r->instance)))
{
+ c->isterminal = r->isterminal;
+ c->noswallow = r->noswallow;
c->isfloating = r->isfloating;
- c->isfreesize = r->isfreesize;
c->tags |= r->tags;
for (m = mons; m && m->num != r->monitor; m = m->next);
if (m)
c->mon = m;
- if (r->switchtotag) {
- Arg a = { .ui = r->tags };
- c->switchtotag = selmon->tagset[selmon->seltags];
- view(&a);
- }
}
}
if (ch.res_class)
@@ -414,6 +426,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 */
@@ -475,18 +489,19 @@ attach(Client *c)
c->next = c->mon->clients;
c->mon->clients = c;
}
+
void
attachBelow(Client *c)
{
//If there is nothing on the monitor or the selected client is floating, attach as normal
if(c->mon->sel == NULL || c->mon->sel->isfloating) {
- Client *at = nexttagged(c);
- if(!at) {
- attach(c);
- return;
- }
- c->next = at->next;
- at->next = c;
+ Client *at = nexttagged(c);
+ if(!at) {
+ attach(c);
+ return;
+ }
+ c->next = at->next;
+ at->next = c;
return;
}
@@ -505,6 +520,68 @@ attachstack(Client *c)
}
void
+attachforegrounded (Client *c)
+{
+ c->tnext = c->mon->foregrounded;
+ c->mon->foregrounded = c;
+}
+
+void
+detachforegrounded (Client *c)
+{
+ Client **tc;
+ for (tc = &c->mon->foregrounded; *tc && *tc != c; tc = &(*tc)->tnext);
+ *tc = c->tnext;
+}
+
+void
+swallow(Client *p, Client *c)
+{
+
+ if (c->noswallow || c->isterminal)
+ return;
+ if (c->noswallow && !swallowfloating && c->isfloating)
+ return;
+
+ detach(c);
+ detachstack(c);
+
+ setclientstate(c, WithdrawnState);
+ XUnmapWindow(dpy, p->win);
+
+ p->swallowing = c;
+ c->mon = p->mon;
+
+ Window w = p->win;
+ p->win = c->win;
+ c->win = w;
+ updatetitle(p);
+ XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
+ arrange(p->mon);
+ configure(p);
+ updateclientlist();
+}
+
+void
+unswallow(Client *c)
+{
+ c->win = c->swallowing->win;
+
+ free(c->swallowing);
+ c->swallowing = NULL;
+
+ /* unfullscreen the client */
+ setfullscreen(c, 0);
+ updatetitle(c);
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ setclientstate(c, NormalState);
+ focus(NULL);
+ arrange(c->mon);
+}
+
+void
buttonpress(XEvent *e)
{
unsigned int i, x, click;
@@ -532,7 +609,7 @@ buttonpress(XEvent *e)
if(i < LENGTH(tags) && (drawtagmask & DRAWCLASSICTAGS)) {
click = ClkTagBar;
arg.ui = 1 << i;
- } else if((ev->x < x + columns * bh / tagrows) && (drawtagmask & DRAWTAGGRID) != 0) {
+ } else if(ev->x < x + columns * bh / tagrows && (drawtagmask & DRAWTAGGRID)) {
click = ClkTagBar;
i = (ev->x - x) / (bh / tagrows);
i = i + columns * (ev->y / (bh / tagrows));
@@ -541,7 +618,7 @@ buttonpress(XEvent *e)
}
arg.ui = 1 << i;
}
- else if(ev->x < x + blw + columns * bh / tagrows)
+ else if (ev->x < x + TEXTW(selmon->ltsymbol) + columns * bh / tagrows)
click = ClkLtSymbol;
else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth())
click = ClkStatusText;
@@ -559,6 +636,171 @@ buttonpress(XEvent *e)
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
}
+static void
+bstack(Monitor *m) {
+ int w, h, mh, mx, tx, ty, tw;
+ unsigned int i, n;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+ if (n > m->nmaster) {
+ mh = m->nmaster ? m->mfact * m->wh : 0;
+ tw = m->ww / (n - m->nmaster);
+ ty = m->wy + mh;
+ } else {
+ mh = m->wh;
+ tw = m->ww;
+ ty = m->wy;
+ }
+ for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i < m->nmaster) {
+ w = (m->ww - mx) / (MIN(n, m->nmaster) - i);
+ resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0);
+ mx += WIDTH(c);
+ } else {
+ h = m->wh - mh;
+ resize(c, tx, ty, tw - (2 * c->bw), h - (2 * c->bw), 0);
+ if (tw != m->ww)
+ tx += WIDTH(c);
+ }
+ }
+}
+
+static void
+bstackhoriz(Monitor *m) {
+ int w, mh, mx, tx, ty, th;
+ unsigned int i, n;
+ Client *c;
+
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+ if (n > m->nmaster) {
+ mh = m->nmaster ? m->mfact * m->wh : 0;
+ th = (m->wh - mh) / (n - m->nmaster);
+ ty = m->wy + mh;
+ } else {
+ th = mh = m->wh;
+ ty = m->wy;
+ }
+ for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
+ if (i < m->nmaster) {
+ w = (m->ww - mx) / (MIN(n, m->nmaster) - i);
+ resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0);
+ mx += WIDTH(c);
+ } else {
+ resize(c, tx, ty, m->ww - (2 * c->bw), th - (2 * c->bw), 0);
+ if (th != m->wh)
+ ty += HEIGHT(c);
+ }
+ }
+}
+
+void
+centeredmaster(Monitor *m)
+{
+ unsigned int i, n, h, mw, mx, my, oty, ety, tw;
+ Client *c;
+
+ /* count number of clients in the selected monitor */
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+
+ /* initialize areas */
+ mw = m->ww;
+ mx = 0;
+ my = 0;
+ tw = mw;
+
+ if (n > m->nmaster) {
+ /* go mfact box in the center if more than nmaster clients */
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ tw = m->ww - mw;
+
+ if (n - m->nmaster > 1) {
+ /* only one client */
+ mx = (m->ww - mw) / 2;
+ tw = (m->ww - mw) / 2;
+ }
+ }
+
+ oty = 0;
+ ety = 0;
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ /* nmaster clients are stacked vertically, in the center
+ * of the screen */
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+ resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw),
+ h - (2*c->bw), 0);
+ my += HEIGHT(c);
+ } else {
+ /* stack clients are stacked vertically */
+ if ((i - m->nmaster) % 2 ) {
+ h = (m->wh - ety) / ( (1 + n - i) / 2);
+ resize(c, m->wx, m->wy + ety, tw - (2*c->bw),
+ h - (2*c->bw), 0);
+ ety += HEIGHT(c);
+ } else {
+ h = (m->wh - oty) / ((1 + n - i) / 2);
+ resize(c, m->wx + mx + mw, m->wy + oty,
+ tw - (2*c->bw), h - (2*c->bw), 0);
+ oty += HEIGHT(c);
+ }
+ }
+}
+
+void
+centeredfloatingmaster(Monitor *m)
+{
+ unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx;
+ Client *c;
+
+ /* count number of clients in the selected monitor */
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if (n == 0)
+ return;
+
+ /* initialize nmaster area */
+ if (n > m->nmaster) {
+ /* go mfact box in the center if more than nmaster clients */
+ if (m->ww > m->wh) {
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ mh = m->nmaster ? m->wh * 0.9 : 0;
+ } else {
+ mh = m->nmaster ? m->wh * m->mfact : 0;
+ mw = m->nmaster ? m->ww * 0.9 : 0;
+ }
+ mx = mxo = (m->ww - mw) / 2;
+ my = myo = (m->wh - mh) / 2;
+ } else {
+ /* go fullscreen if all clients are in the master area */
+ mh = m->wh;
+ mw = m->ww;
+ mx = mxo = 0;
+ my = myo = 0;
+ }
+
+ for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ /* nmaster clients are stacked horizontally, in the center
+ * of the screen */
+ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i);
+ resize(c, m->wx + mx, m->wy + my, w - (2*c->bw),
+ mh - (2*c->bw), 0);
+ mx += WIDTH(c);
+ } else {
+ /* stack clients are stacked horizontally */
+ w = (m->ww - tx) / (n - i);
+ resize(c, m->wx + tx, m->wy, w - (2*c->bw),
+ m->wh - (2*c->bw), 0);
+ tx += WIDTH(c);
+ }
+}
+
void
checkotherwm(void)
{
@@ -597,6 +839,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);
@@ -828,6 +1071,8 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+ else if ((c = swallowingclient(ev->window)))
+ unmanage(c->swallowing, 1);
else if ((c = wintosystrayicon(ev->window))) {
removesystrayicon(c);
resizebarwin(selmon);
@@ -907,7 +1152,7 @@ drawbar(Monitor *m)
if (drawtagmask & DRAWCLASSICTAGS)
for (i = 0; i < LENGTH(tags); i++) {
w = TEXTW(tags[i]);
- drw_setscheme(drw, (m->tagset[m->seltags] & 1 << i ? tagscheme[i] : scheme[SchemeNorm]));
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
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,
@@ -918,7 +1163,7 @@ drawbar(Monitor *m)
if (drawtagmask & DRAWTAGGRID) {
drawtaggrid(m,&x,occ);
}
- w = blw = TEXTW(m->ltsymbol);
+ w = TEXTW(m->ltsymbol);
drw_setscheme(drw, scheme[SchemeNorm]);
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
@@ -945,9 +1190,11 @@ drawbar(Monitor *m)
continue;
tw = MIN(m->sel == c ? w : mw, TEXTW(c->name));
- drw_setscheme(drw, scheme[m == selmon && m->sel == c ? SchemeSel : SchemeNorm]);
+ drw_setscheme(drw, scheme[SchemeNorm]);
if (tw > lrpad / 2)
- drw_text(drw, x, 0, tw, bh, lrpad / 2, c->name, 0);
+ drw_text(drw, x, text_ypos, tw, bh, lrpad / 2, c->name, 0);
+ drw_setscheme(drw, scheme[m == selmon && m->sel == c ? SchemeSel : SchemeNorm]);
+ drw_rect(drw, x , bh - brdsh_ypos , tw , brdsh_w , 1, 1);
if (c->isfloating)
drw_rect(drw, x + boxs, boxs, boxw, boxw, c->isfixed, 0);
x += tw;
@@ -969,47 +1216,48 @@ drawbars(void)
drawbar(m);
}
-void drawtaggrid(Monitor *m, int *x_pos, unsigned int occ)
+void
+drawtaggrid(Monitor *m, int *x_pos, unsigned int occ)
{
- unsigned int x, y, h, max_x, columns;
- int invert, i,j, k;
+ unsigned int x, y, h, max_x, columns;
+ int invert, i,j, k;
- h = bh / tagrows;
- x = max_x = *x_pos;
- y = 0;
- columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
+ h = bh / tagrows;
+ x = max_x = *x_pos;
+ y = 0;
+ columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
- /* Firstly we will fill the borders of squares */
+ /* Firstly we will fill the borders of squares */
- XSetForeground(drw->dpy, drw->gc, scheme[SchemeNorm][ColBorder].pixel);
- XFillRectangle(dpy, drw->drawable, drw->gc, x, y, h*columns + 1, bh);
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeNorm][ColBorder].pixel);
+ XFillRectangle(dpy, drw->drawable, drw->gc, x, y, h*columns + 1, bh);
- /* We will draw LENGTH(tags) squares in tagraws raws. */
+ /* We will draw LENGTH(tags) squares in tagraws raws. */
for(j = 0, i= 0; j < tagrows; j++) {
- x = *x_pos;
- for (k = 0; k < columns && i < LENGTH(tags); k++, i++) {
- invert = m->tagset[m->seltags] & 1 << i ? 0 : 1;
-
- /* Select active color for current square */
- XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeSel][ColBg].pixel :
- scheme[SchemeNorm][ColFg].pixel);
- XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h-1);
-
- /* Mark square if tag has client */
- if (occ & 1 << i) {
- XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeSel][ColFg].pixel :
- scheme[SchemeNorm][ColBg].pixel);
- XFillRectangle(dpy, drw->drawable, drw->gc, x + 1, y + 1,
- h / 2, h / 2);
- }
- x += h;
- if (x > max_x) {
- max_x = x;
- }
- }
- y += h;
+ x = *x_pos;
+ for (k = 0; k < columns && i < LENGTH(tags); k++, i++) {
+ invert = m->tagset[m->seltags] & 1 << i ? 0 : 1;
+
+ /* Select active color for current square */
+ XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeSel][ColBg].pixel :
+ scheme[SchemeNorm][ColFg].pixel);
+ XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h-1);
+
+ /* Mark square if tag has client */
+ if (occ & 1 << i) {
+ XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeSel][ColFg].pixel :
+ scheme[SchemeNorm][ColBg].pixel);
+ XFillRectangle(dpy, drw->drawable, drw->gc, x + 1, y + 1,
+ h / 2, h / 2);
+ }
+ x += h;
+ if (x > max_x) {
+ max_x = x;
+ }
+ }
+ y += h;
}
- *x_pos = max_x + 1;
+ *x_pos = max_x + 1;
}
void
@@ -1184,13 +1432,11 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size)
text[0] = '\0';
if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
return 0;
- if (name.encoding == XA_STRING)
+ if (name.encoding == XA_STRING) {
strncpy(text, (char *)name.value, size - 1);
- else {
- if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
- strncpy(text, *list, size - 1);
- XFreeStringList(list);
- }
+ } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
+ strncpy(text, *list, size - 1);
+ XFreeStringList(list);
}
text[size - 1] = '\0';
XFree(name.value);
@@ -1223,16 +1469,26 @@ grabkeys(void)
{
updatenumlockmask();
{
- unsigned int i, j;
+ unsigned int i, j, k;
unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
- KeyCode code;
+ int start, end, skip;
+ KeySym *syms;
XUngrabKey(dpy, AnyKey, AnyModifier, root);
- for (i = 0; i < LENGTH(keys); i++)
- 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);
+ XDisplayKeycodes(dpy, &start, &end);
+ syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
+ if (!syms)
+ return;
+ for (k = start; k <= end; k++)
+ for (i = 0; i < LENGTH(keys); i++)
+ /* skip modifier codes, we do that ourselves */
+ if (keys[i].keysym == syms[(k - start) * skip])
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabKey(dpy, k,
+ keys[i].mod | modifiers[j],
+ root, True,
+ GrabModeAsync, GrabModeAsync);
+ XFree(syms);
}
}
@@ -1291,12 +1547,13 @@ killclient(const Arg *arg)
void
manage(Window w, XWindowAttributes *wa)
{
- Client *c, *t = NULL;
+ Client *c, *t = NULL, *term = NULL;
Window trans = None;
XWindowChanges wc;
c = ecalloc(1, sizeof(Client));
c->win = w;
+ c->pid = winpid(w);
/* geometry */
c->x = c->oldx = wa->x;
c->y = c->oldy = wa->y;
@@ -1311,16 +1568,15 @@ manage(Window w, XWindowAttributes *wa)
} else {
c->mon = selmon;
applyrules(c);
+ term = termforwin(c);
}
- if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
- c->x = c->mon->mx + c->mon->mw - WIDTH(c);
- if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
- c->y = c->mon->my + c->mon->mh - HEIGHT(c);
- 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);
+ if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
+ c->x = c->mon->wx + c->mon->ww - WIDTH(c);
+ if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
+ c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
+ c->x = MAX(c->x, c->mon->wx);
+ c->y = MAX(c->y, c->mon->wy);
c->bw = borderpx;
wc.border_width = c->bw;
@@ -1336,7 +1592,6 @@ manage(Window w, XWindowAttributes *wa)
c->sfy = c->y;
c->sfw = c->w;
c->sfh = c->h;
-
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
grabbuttons(c, 0);
if (!c->isfloating)
@@ -1349,11 +1604,15 @@ manage(Window w, XWindowAttributes *wa)
(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(selmon->sel && selmon->sel->isfullscreen && !c->isfloating)
+ setfullscreen(selmon->sel, 0);
if (c->mon == selmon)
unfocus(selmon->sel, 0);
c->mon->sel = c;
arrange(c->mon);
XMapWindow(dpy, c->win);
+ if (term)
+ swallow(term, c);
focus(NULL);
}
@@ -1380,9 +1639,7 @@ maprequest(XEvent *e)
updatesystray();
}
- if (!XGetWindowAttributes(dpy, ev->window, &wa))
- return;
- if (wa.override_redirect)
+ if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
return;
if (!wintoclient(ev->window))
manage(ev->window, &wa);
@@ -1463,6 +1720,55 @@ movemouse(const Arg *arg)
}
}
+void
+movestack(const Arg *arg) {
+ Client *c = NULL, *p = NULL, *pc = NULL, *i;
+
+ if(arg->i > 0) {
+ /* find the client after selmon->sel */
+ for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
+ if(!c)
+ for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
+
+ }
+ else {
+ /* find the client before selmon->sel */
+ for(i = selmon->clients; i != selmon->sel; i = i->next)
+ if(ISVISIBLE(i) && !i->isfloating)
+ c = i;
+ if(!c)
+ for(; i; i = i->next)
+ if(ISVISIBLE(i) && !i->isfloating)
+ c = i;
+ }
+ /* find the client before selmon->sel and c */
+ for(i = selmon->clients; i && (!p || !pc); i = i->next) {
+ if(i->next == selmon->sel)
+ p = i;
+ if(i->next == c)
+ pc = i;
+ }
+
+ /* swap c and selmon->sel selmon->clients in the selmon->clients list */
+ if(c && c != selmon->sel) {
+ Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next;
+ selmon->sel->next = c->next==selmon->sel?c:c->next;
+ c->next = temp;
+
+ if(p && p != c)
+ p->next = c;
+ if(pc && pc != selmon->sel)
+ pc->next = selmon->sel;
+
+ if(selmon->sel == selmon->clients)
+ selmon->clients = c;
+ else if(c == selmon->clients)
+ selmon->clients = selmon->sel;
+
+ arrange(selmon);
+ }
+}
+
Client *
nexttagged(Client *c) {
Client *walked = c->mon->clients;
@@ -1480,13 +1786,90 @@ nexttiled(Client *c)
return c;
}
+Client*
+nextforegrounded(Client *c)
+{
+ for (; c && (!c->isforegrounded || !ISVISIBLE(c)); c = c->tnext);
+ return c;
+}
+
void
-pop(Client *c)
+arrangeforegrounded (Monitor *m)
{
- detach(c);
- attach(c);
- focus(c);
- arrange(c->mon);
+ unsigned int n,i,x,y,w,h;
+ Client *c;
+
+ for (n = 0, c = nextforegrounded(m->foregrounded); c; c = nextforegrounded(c->tnext), n++);
+ if (n == 0)
+ return;
+
+ for (i = 0, c = nextforegrounded(m->foregrounded); c; c = nextforegrounded(c->tnext), i++){
+ if (n == 1) {
+ x = m->mx + (m->mw - m->mw * fgw) / 2;
+ y = m->my + (m->mh - m->mh * fgh) / 2;
+ w = (m->mw * fgw) - (2 * (m->foregrounded->bw));
+ h = (m->mh * fgh) - (2 * (m->foregrounded->bw));
+ } else {
+ x = m->mx + (n - 1 - i) * (m->mw / n);
+ y = m->my + (m->mh - m->mh * fgh) / 2;
+ w = (m->mw * (1 / (float)n)) - (2 * (m->foregrounded->bw));
+ h = (m->mh * fgh) - (2 * (m->foregrounded->bw));
+ }
+ resize(c,x,y,w,h,0);
+ }
+}
+
+void
+nrowgrid(Monitor *m)
+{
+ unsigned int n = 0, i = 0, ri = 0, ci = 0; /* counters */
+ unsigned int cx, cy, cw, ch; /* client geometry */
+ unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */
+ unsigned int cols, rows = m->nmaster + 1;
+ Client *c;
+
+ /* count clients */
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+
+ /* nothing to do here */
+ if (n == 0)
+ return;
+
+ /* force 2 clients to always split vertically */
+ if (FORCE_VSPLIT && n == 2)
+ rows = 1;
+
+ /* never allow empty rows */
+ if (n < rows)
+ rows = n;
+
+ /* define first row */
+ cols = n / rows;
+ uc = cols;
+ cy = m->wy;
+ ch = m->wh / rows;
+ uh = ch;
+
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), i++, ci++) {
+ if (ci == cols) {
+ uw = 0;
+ ci = 0;
+ ri++;
+
+ /* next row */
+ cols = (n - uc) / (rows - ri);
+ uc += cols;
+ cy = m->wy + uh;
+ ch = (m->wh - uh) / (rows - ri);
+ uh += ch;
+ }
+
+ cx = m->wx + uw;
+ cw = (m->ww - uw) / (cols - ci);
+ uw += cw;
+
+ resize(c, cx, cy, cw - 2 * c->bw, ch - 2 * c->bw, 0);
+ }
}
void
@@ -1520,7 +1903,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);
@@ -1879,9 +2262,16 @@ setup(void)
int i;
XSetWindowAttributes wa;
Atom utf8string;
+ struct sigaction sa;
+
+ /* do not transform children into zombies when they terminate */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
- /* clean up any zombies immediately */
- sigchld(0);
+ /* clean up any zombies (inherited from .xinitrc etc) immediately */
+ while (waitpid(-1, NULL, WNOHANG) > 0);
/* init screen */
screen = DefaultScreen(dpy);
@@ -1892,7 +2282,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 = drw->fonts->h + 2;
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@@ -1921,14 +2311,9 @@ setup(void)
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
/* init appearance */
- if (LENGTH(tags) > LENGTH(tagsel))
- die("too few color schemes for the tags");
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
for (i = 0; i < LENGTH(colors); i++)
scheme[i] = drw_scm_create(drw, colors[i], 3);
- tagscheme = ecalloc(LENGTH(tagsel), sizeof(Clr *));
- for (i = 0; i < LENGTH(tagsel); i++)
- tagscheme[i] = drw_scm_create(drw, tagsel[i], 2);
/* init system tray */
updatesystray();
/* init bars */
@@ -1957,7 +2342,6 @@ setup(void)
focus(NULL);
}
-
void
seturgent(Client *c, int urg)
{
@@ -1988,140 +2372,103 @@ showhide(Client *c)
XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
}
}
-void switchtag(const Arg *arg)
-{
- unsigned int columns;
- unsigned int new_tagset = 0;
- unsigned int pos, i;
- int col, row;
- Arg new_arg;
-
- columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
-
- for (i = 0; i < LENGTH(tags); ++i) {
- if (!(selmon->tagset[selmon->seltags] & 1 << i)) {
- continue;
- }
- pos = i;
- row = pos / columns;
- col = pos % columns;
- if (arg->ui & SWITCHTAG_UP) { /* UP */
- row --;
- if (row < 0) {
- row = tagrows - 1;
- }
- do {
- pos = row * columns + col;
- row --;
- } while (pos >= LENGTH(tags));
- }
- if (arg->ui & SWITCHTAG_DOWN) { /* DOWN */
- row ++;
- if (row >= tagrows) {
- row = 0;
- }
- pos = row * columns + col;
- if (pos >= LENGTH(tags)) {
- row = 0;
- }
- pos = row * columns + col;
- }
- if (arg->ui & SWITCHTAG_LEFT) { /* LEFT */
- col --;
- if (col < 0) {
- col = columns - 1;
- }
- do {
- pos = row * columns + col;
- col --;
- } while (pos >= LENGTH(tags));
- }
- if (arg->ui & SWITCHTAG_RIGHT) { /* RIGHT */
- col ++;
- if (col >= columns) {
- col = 0;
- }
- pos = row * columns + col;
- if (pos >= LENGTH(tags)) {
- col = 0;
- pos = row * columns + col;
- }
- }
- new_tagset |= 1 << pos;
- }
- new_arg.ui = new_tagset;
- if (arg->ui & SWITCHTAG_TOGGLETAG) {
- toggletag(&new_arg);
- }
- if (arg->ui & SWITCHTAG_TAG) {
- tag(&new_arg);
- }
- if (arg->ui & SWITCHTAG_VIEW) {
- view (&new_arg);
- }
- if (arg->ui & SWITCHTAG_TOGGLEVIEW) {
- toggleview (&new_arg);
- }
-}
-
-void
-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)
{
- if (arg->v == dmenu_cmd)
+ struct sigaction sa;
+
+ if (arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
setsid();
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGCHLD, &sa, NULL);
+
execvp(((char **)arg->v)[0], (char **)arg->v);
- fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
- perror(" failed");
- exit(EXIT_SUCCESS);
+ die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
}
}
void
-stairs(Monitor *m)
+switchtag(const Arg *arg)
{
- unsigned int i, n, h, mw, my;
- unsigned int ox, oy, ow, oh; /* stair offset values */
- Client *c;
-
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
- if (n == 0)
- return;
+ unsigned int columns;
+ unsigned int new_tagset = 0;
+ unsigned int pos, i;
+ int col, row;
+ Arg new_arg;
- if (n > m->nmaster)
- mw = m->nmaster ? m->ww * m->mfact : 0;
- else
- mw = m->ww - m->gappx;
+ columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
- for (i = 0, my = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
- 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;
- } else {
- oy = i - m->nmaster;
- ox = stairdirection ? n - i - 1 : (stairsamesize ? i - m->nmaster : 0);
- ow = stairsamesize ? n - m->nmaster - 1 : n - i - 1;
- oh = stairsamesize ? ow : i - m->nmaster;
- resize(c,
- m->wx + mw + (ox * stairpx) + m->gappx,
- m->wy + (oy * stairpx) + m->gappx,
- m->ww - mw - (2 * c->bw) - (ow * stairpx) - (2 * m->gappx),
- m->wh - (2 * c->bw) - (oh * stairpx) - (2 * m->gappx),
- 0);
+ for (i = 0; i < LENGTH(tags); ++i) {
+ if (!(selmon->tagset[selmon->seltags] & 1 << i)) {
+ continue;
+ }
+ pos = i;
+ row = pos / columns;
+ col = pos % columns;
+ if (arg->ui & SWITCHTAG_UP) { /* UP */
+ row --;
+ if (row < 0) {
+ row = tagrows - 1;
+ }
+ do {
+ pos = row * columns + col;
+ row --;
+ } while (pos >= LENGTH(tags));
}
+ if (arg->ui & SWITCHTAG_DOWN) { /* DOWN */
+ row ++;
+ if (row >= tagrows) {
+ row = 0;
+ }
+ pos = row * columns + col;
+ if (pos >= LENGTH(tags)) {
+ row = 0;
+ }
+ pos = row * columns + col;
+ }
+ if (arg->ui & SWITCHTAG_LEFT) { /* LEFT */
+ col --;
+ if (col < 0) {
+ col = columns - 1;
+ }
+ do {
+ pos = row * columns + col;
+ col --;
+ } while (pos >= LENGTH(tags));
+ }
+ if (arg->ui & SWITCHTAG_RIGHT) { /* RIGHT */
+ col ++;
+ if (col >= columns) {
+ col = 0;
+ }
+ pos = row * columns + col;
+ if (pos >= LENGTH(tags)) {
+ col = 0;
+ pos = row * columns + col;
+ }
+ }
+ new_tagset |= 1 << pos;
+ }
+ new_arg.ui = new_tagset;
+ if (arg->ui & SWITCHTAG_TOGGLETAG) {
+ toggletag(&new_arg);
+ }
+ if (arg->ui & SWITCHTAG_TAG) {
+ tag(&new_arg);
+ }
+ if (arg->ui & SWITCHTAG_VIEW) {
+ view (&new_arg);
+ }
+ if (arg->ui & SWITCHTAG_TOGGLEVIEW) {
+ toggleview (&new_arg);
}
}
@@ -2188,7 +2535,7 @@ tile(Monitor *m)
else
mw = m->ww - m->gappx;
for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
+ 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)
@@ -2240,14 +2587,37 @@ togglefloating(const Arg *arg)
selmon->sel->sfw = selmon->sel->w;
selmon->sel->sfh = selmon->sel->h;
}
+ if (selmon->sel->isforegrounded) {
+ selmon->sel->isforegrounded = 0;
+ detachforegrounded(selmon->sel);
+ arrangeforegrounded(selmon);
+ }
+ arrange(selmon);
+}
+
+void
+toggleforegrounded(const Arg *arg)
+{
+ if (!selmon->sel)
+ return;
+ if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ return;
+
+ selmon->sel->isforegrounded || selmon->sel->isfloating ?
+ detachforegrounded(selmon->sel) : attachforegrounded(selmon->sel);
+
+ selmon->sel->isforegrounded = selmon->sel->isfloating =
+ !selmon->sel->isfloating && !selmon->sel->isforegrounded;
+
+ arrangeforegrounded(selmon);
arrange(selmon);
}
void
togglefullscr(const Arg *arg)
{
- if(selmon->sel)
- setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
+ if(selmon->sel)
+ setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
}
void
@@ -2320,12 +2690,33 @@ unmanage(Client *c, int destroyed)
Monitor *m = c->mon;
XWindowChanges wc;
+ if (c->swallowing) {
+ unswallow(c);
+ return;
+ }
+
+ Client *s = swallowingclient(c->win);
+ if (s) {
+ free(s->swallowing);
+ s->swallowing = NULL;
+ arrange(m);
+ focus(NULL);
+ return;
+ }
+
detach(c);
detachstack(c);
+
+ if (c->isforegrounded){
+ detachforegrounded(c);
+ arrangeforegrounded(m);
+ }
+
if (!destroyed) {
wc.border_width = c->oldbw;
XGrabServer(dpy); /* avoid race conditions */
XSetErrorHandler(xerrordummy);
+ XSelectInput(dpy, c->win, NoEventMask);
XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
setclientstate(c, WithdrawnState);
@@ -2334,12 +2725,11 @@ unmanage(Client *c, int destroyed)
XUngrabServer(dpy);
}
free(c);
- focus(NULL);
- updateclientlist();
- arrange(m);
- if (c->switchtotag) {
- Arg a = { .ui = c->switchtotag };
- view(&a);
+
+ if (!s) {
+ arrange(m);
+ focus(NULL);
+ updateclientlist();
}
}
@@ -2405,7 +2795,7 @@ updatebarpos(Monitor *m)
}
void
-updateclientlist()
+updateclientlist(void)
{
Client *c;
Monitor *m;
@@ -2439,43 +2829,43 @@ 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);
- attachBelow(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);
+ attachBelow(c);
+ attachstack(c);
}
+ if (m == selmon)
+ selmon = mons;
+ cleanupmon(m);
}
free(unique);
} else
@@ -2521,7 +2911,7 @@ updatesizehints(Client *c)
if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
/* size is uninitialized, ensure that size.flags aren't used */
- size.flags = 0;
+ size.flags = PSize;
if (size.flags & PBaseSize) {
c->basew = size.base_width;
c->baseh = size.base_height;
@@ -2553,18 +2943,15 @@ updatesizehints(Client *c)
c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
} else
c->maxa = c->mina = 0.0;
- if((size.flags & PSize) && c->isfreesize) {
- c->basew = size.base_width;
- c->baseh = size.base_height;
- c->isfloating = 1;
- }
c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
+ c->hintsvalid = 1;
}
void
updatestatus(void)
{
Monitor* m;
+
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
strcpy(stext, "dwm-"VERSION);
for(m = mons; m; m = m->next)
@@ -2707,10 +3094,8 @@ updatewindowtype(Client *c)
if (state == netatom[NetWMFullscreen])
setfullscreen(c, 1);
- if (wtype == netatom[NetWMWindowTypeDialog]) {
+ if (wtype == netatom[NetWMWindowTypeDialog])
c->isfloating = 1;
- c->isfreesize = 1;
- }
}
void
@@ -2770,6 +3155,137 @@ view(const Arg *arg)
arrange(selmon);
}
+pid_t
+winpid(Window w)
+{
+ pid_t result = 0;
+
+#ifdef __linux__
+ xcb_res_client_id_spec_t spec = {0};
+ spec.client = w;
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
+
+ xcb_generic_error_t *e = NULL;
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
+
+ if (!r)
+ return (pid_t)0;
+
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
+ spec = i.data->spec;
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
+ result = *t;
+ break;
+ }
+ }
+
+ free(r);
+
+ if (result == (pid_t)-1)
+ result = 0;
+
+#endif /* __linux__ */
+
+#ifdef __OpenBSD__
+ Atom type;
+ int format;
+ unsigned long len, bytes;
+ unsigned char *prop;
+ pid_t ret;
+
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
+ return 0;
+
+ ret = *(pid_t*)prop;
+ XFree(prop);
+ result = ret;
+
+#endif /* __OpenBSD__ */
+ return result;
+}
+
+pid_t
+getparentprocess(pid_t p)
+{
+ unsigned int v = 0;
+ int s;
+
+#ifdef __linux__
+ FILE *f;
+ char buf[256];
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
+
+ if (!(f = fopen(buf, "r")))
+ return 0;
+
+ s = fscanf(f, "%*u %*s %*c %u", &v);
+ (void)s;
+ fclose(f);
+#endif /* __linux__*/
+
+#ifdef __OpenBSD__
+ int n;
+ kvm_t *kd;
+ struct kinfo_proc *kp;
+
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
+ if (!kd)
+ return 0;
+
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
+ v = kp->p_ppid;
+#endif /* __OpenBSD__ */
+
+ return (pid_t)v;
+}
+
+int
+isdescprocess(pid_t p, pid_t c)
+{
+ while (p != c && c != 0)
+ c = getparentprocess(c);
+
+ return (int)c;
+}
+
+Client *
+termforwin(const Client *w)
+{
+ Client *c;
+ Monitor *m;
+
+ if (!w->pid || w->isterminal)
+ return NULL;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+Client *
+swallowingclient(Window w)
+{
+ Client *c;
+ Monitor *m;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->swallowing && c->swallowing->win == w)
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
Client *
wintoclient(Window w)
{
@@ -2810,6 +3326,29 @@ wintomon(Window w)
return selmon;
}
+/* Selects for the view of the focused window. The list of tags */
+/* to be displayed is matched to the focused window tag list. */
+void
+winview(const Arg* arg){
+ Window win, win_r, win_p, *win_c;
+ unsigned nc;
+ int unused;
+ Client* c;
+ Arg a;
+
+ if (!XGetInputFocus(dpy, &win, &unused))
+ return;
+ while (XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc)
+ && win_p != win_r)
+ win = win_p;
+
+ if (!(c = wintoclient(win)))
+ return;
+
+ a.ui = c->tags;
+ view(&a);
+}
+
/* 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. */
@@ -2868,8 +3407,7 @@ zoom(const Arg *arg)
Client *c = selmon->sel;
Client *at = NULL, *cold, *cprevious = NULL;
- if (!selmon->lt[selmon->sellt]->arrange
- || (selmon->sel && selmon->sel->isfloating))
+ if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
return;
if (c == nexttiled(selmon->clients)) {
at = findbefore(prevzoom);
@@ -2911,10 +3449,12 @@ main(int argc, char *argv[])
fputs("warning: no locale support\n", stderr);
if (!(dpy = XOpenDisplay(NULL)))
die("dwm: cannot open display");
+ if (!(xcon = XGetXCBConnection(dpy)))
+ die("dwm: cannot get xcb connection\n");
checkotherwm();
setup();
#ifdef __OpenBSD__
- if (pledge("stdio rpath proc exec", NULL) == -1)
+ if (pledge("stdio rpath proc exec ps", NULL) == -1)
die("pledge");
#endif /* __OpenBSD__ */
scan();
@@ -2923,168 +3463,3 @@ main(int argc, char *argv[])
XCloseDisplay(dpy);
return EXIT_SUCCESS;
}
-
-static void
-bstack(Monitor *m) {
- int w, h, mh, mx, tx, ty, tw;
- unsigned int i, n;
- Client *c;
-
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
- if (n == 0)
- return;
- if (n > m->nmaster) {
- mh = m->nmaster ? m->mfact * m->wh : 0;
- tw = m->ww / (n - m->nmaster);
- ty = m->wy + mh;
- } else {
- mh = m->wh;
- tw = m->ww;
- ty = m->wy;
- }
- for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
- if (i < m->nmaster) {
- w = (m->ww - mx) / (MIN(n, m->nmaster) - i);
- resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0);
- mx += WIDTH(c);
- } else {
- h = m->wh - mh;
- resize(c, tx, ty, tw - (2 * c->bw), h - (2 * c->bw), 0);
- if (tw != m->ww)
- tx += WIDTH(c);
- }
- }
-}
-
-static void
-bstackhoriz(Monitor *m) {
- int w, mh, mx, tx, ty, th;
- unsigned int i, n;
- Client *c;
-
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
- if (n == 0)
- return;
- if (n > m->nmaster) {
- mh = m->nmaster ? m->mfact * m->wh : 0;
- th = (m->wh - mh) / (n - m->nmaster);
- ty = m->wy + mh;
- } else {
- th = mh = m->wh;
- ty = m->wy;
- }
- for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
- if (i < m->nmaster) {
- w = (m->ww - mx) / (MIN(n, m->nmaster) - i);
- resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0);
- mx += WIDTH(c);
- } else {
- resize(c, tx, ty, m->ww - (2 * c->bw), th - (2 * c->bw), 0);
- if (th != m->wh)
- ty += HEIGHT(c);
- }
- }
-}
-
-void
-centeredmaster(Monitor *m)
-{
- unsigned int i, n, h, mw, mx, my, oty, ety, tw;
- Client *c;
-
- /* count number of clients in the selected monitor */
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
- if (n == 0)
- return;
-
- /* initialize areas */
- mw = m->ww;
- mx = 0;
- my = 0;
- tw = mw;
-
- if (n > m->nmaster) {
- /* go mfact box in the center if more than nmaster clients */
- mw = m->nmaster ? m->ww * m->mfact : 0;
- tw = m->ww - mw;
-
- if (n - m->nmaster > 1) {
- /* only one client */
- mx = (m->ww - mw) / 2;
- tw = (m->ww - mw) / 2;
- }
- }
-
- oty = 0;
- ety = 0;
- for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
- /* nmaster clients are stacked vertically, in the center
- * of the screen */
- h = (m->wh - my) / (MIN(n, m->nmaster) - i);
- resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw),
- h - (2*c->bw), 0);
- my += HEIGHT(c);
- } else {
- /* stack clients are stacked vertically */
- if ((i - m->nmaster) % 2 ) {
- h = (m->wh - ety) / ( (1 + n - i) / 2);
- resize(c, m->wx, m->wy + ety, tw - (2*c->bw),
- h - (2*c->bw), 0);
- ety += HEIGHT(c);
- } else {
- h = (m->wh - oty) / ((1 + n - i) / 2);
- resize(c, m->wx + mx + mw, m->wy + oty,
- tw - (2*c->bw), h - (2*c->bw), 0);
- oty += HEIGHT(c);
- }
- }
-}
-
-void
-centeredfloatingmaster(Monitor *m)
-{
- unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx;
- Client *c;
-
- /* count number of clients in the selected monitor */
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
- if (n == 0)
- return;
-
- /* initialize nmaster area */
- if (n > m->nmaster) {
- /* go mfact box in the center if more than nmaster clients */
- if (m->ww > m->wh) {
- mw = m->nmaster ? m->ww * m->mfact : 0;
- mh = m->nmaster ? m->wh * 0.9 : 0;
- } else {
- mh = m->nmaster ? m->wh * m->mfact : 0;
- mw = m->nmaster ? m->ww * 0.9 : 0;
- }
- mx = mxo = (m->ww - mw) / 2;
- my = myo = (m->wh - mh) / 2;
- } else {
- /* go fullscreen if all clients are in the master area */
- mh = m->wh;
- mw = m->ww;
- mx = mxo = 0;
- my = myo = 0;
- }
-
- for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
- /* nmaster clients are stacked horizontally, in the center
- * of the screen */
- w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i);
- resize(c, m->wx + mx, m->wy + my, w - (2*c->bw),
- mh - (2*c->bw), 0);
- mx += WIDTH(c);
- } else {
- /* stack clients are stacked horizontally */
- w = (m->ww - tx) / (n - i);
- resize(c, m->wx + tx, m->wy, w - (2*c->bw),
- m->wh - (2*c->bw), 0);
- tx += WIDTH(c);
- }
-}