sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dwm-swallow-20160717-56a31dc.diff (9208B)


      1 diff --git a/config.def.h b/config.def.h
      2 index fd77a07..69976b3 100644
      3 --- a/config.def.h
      4 +++ b/config.def.h
      5 @@ -26,9 +26,10 @@ static const Rule rules[] = {
      6  	 *	WM_CLASS(STRING) = instance, class
      7  	 *	WM_NAME(STRING) = title
      8  	 */
      9 -	/* class      instance    title       tags mask     isfloating   monitor */
     10 -	{ "Gimp",     NULL,       NULL,       0,            1,           -1 },
     11 -	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
     12 +	/* class      instance    title       tags mask     isfloating   isterminal noswallow monitor */
     13 +	{ "Gimp",     NULL,       NULL,       0,            1,           0,         0,        -1 },
     14 +	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           0,         0,        -1 },
     15 +	{ "st",       NULL,       NULL,       0,            0,           1,         1,        -1 },
     16  };
     17  
     18  /* layout(s) */
     19 diff --git a/config.mk b/config.mk
     20 index 80dc936..5ed14e3 100644
     21 --- a/config.mk
     22 +++ b/config.mk
     23 @@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2
     24  
     25  # includes and libs
     26  INCS = -I${X11INC} -I${FREETYPEINC}
     27 -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
     28 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res
     29  
     30  # flags
     31  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
     32 diff --git a/dwm.c b/dwm.c
     33 index b2bc9bd..528df2f 100644
     34 --- a/dwm.c
     35 +++ b/dwm.c
     36 @@ -40,6 +40,8 @@
     37  #include <X11/extensions/Xinerama.h>
     38  #endif /* XINERAMA */
     39  #include <X11/Xft/Xft.h>
     40 +#include <X11/Xlib-xcb.h>
     41 +#include <xcb/res.h>
     42  
     43  #include "drw.h"
     44  #include "util.h"
     45 @@ -93,9 +95,11 @@ struct Client {
     46  	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
     47  	int bw, oldbw;
     48  	unsigned int tags;
     49 -	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
     50 +	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
     51 +	pid_t pid;
     52  	Client *next;
     53  	Client *snext;
     54 +	Client *swallowing;
     55  	Monitor *mon;
     56  	Window win;
     57  };
     58 @@ -139,6 +143,8 @@ typedef struct {
     59  	const char *title;
     60  	unsigned int tags;
     61  	int isfloating;
     62 +	int isterminal;
     63 +	int noswallow;
     64  	int monitor;
     65  } Rule;
     66  
     67 @@ -171,12 +177,14 @@ static void focus(Client *c);
     68  static void focusin(XEvent *e);
     69  static void focusmon(const Arg *arg);
     70  static void focusstack(const Arg *arg);
     71 +static pid_t getparentprocess(pid_t p);
     72  static int getrootptr(int *x, int *y);
     73  static long getstate(Window w);
     74  static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
     75  static void grabbuttons(Client *c, int focused);
     76  static void grabkeys(void);
     77  static void incnmaster(const Arg *arg);
     78 +static int isdescprocess(pid_t p, pid_t c);
     79  static void keypress(XEvent *e);
     80  static void killclient(const Arg *arg);
     81  static void manage(Window w, XWindowAttributes *wa);
     82 @@ -207,8 +215,10 @@ static void setup(void);
     83  static void showhide(Client *c);
     84  static void sigchld(int unused);
     85  static void spawn(const Arg *arg);
     86 +static Client *swallowingclient(Window w);
     87  static void tag(const Arg *arg);
     88  static void tagmon(const Arg *arg);
     89 +static Client *termforwin(const Client *c);
     90  static void tile(Monitor *);
     91  static void togglebar(const Arg *arg);
     92  static void togglefloating(const Arg *arg);
     93 @@ -228,6 +238,7 @@ static void updatewindowtype(Client *c);
     94  static void updatetitle(Client *c);
     95  static void updatewmhints(Client *c);
     96  static void view(const Arg *arg);
     97 +static pid_t winpid(Window w);
     98  static Client *wintoclient(Window w);
     99  static Monitor *wintomon(Window w);
    100  static int xerror(Display *dpy, XErrorEvent *ee);
    101 @@ -269,6 +280,8 @@ static Drw *drw;
    102  static Monitor *mons, *selmon;
    103  static Window root;
    104  
    105 +static xcb_connection_t *xcon;
    106 +
    107  /* configuration, allows nested code to access above variables */
    108  #include "config.h"
    109  
    110 @@ -298,6 +311,7 @@ applyrules(Client *c)
    111  		&& (!r->class || strstr(class, r->class))
    112  		&& (!r->instance || strstr(instance, r->instance)))
    113  		{
    114 +			c->isterminal = r->isterminal;
    115  			c->isfloating = r->isfloating;
    116  			c->tags |= r->tags;
    117  			for (m = mons; m && m->num != r->monitor; m = m->next);
    118 @@ -415,6 +429,47 @@ attachstack(Client *c)
    119  }
    120  
    121  void
    122 +swallow(Client *p, Client *c)
    123 +{
    124 +	if (c->noswallow || c->isterminal)
    125 +		return;
    126 +
    127 +	detach(c);
    128 +	detachstack(c);
    129 +
    130 +	setclientstate(c, WithdrawnState);
    131 +	XUnmapWindow(dpy, p->win);
    132 +
    133 +	p->swallowing = c;
    134 +	c->mon = p->mon;
    135 +
    136 +	Window w = p->win;
    137 +	p->win = c->win;
    138 +	c->win = w;
    139 +	updatetitle(p);
    140 +	arrange(p->mon);
    141 +	XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
    142 +	configure(p);
    143 +	updateclientlist();
    144 +}
    145 +
    146 +void
    147 +unswallow(Client *c)
    148 +{
    149 +	c->win = c->swallowing->win;
    150 +
    151 +	free(c->swallowing);
    152 +	c->swallowing = NULL;
    153 +
    154 +	updatetitle(c);
    155 +	arrange(c->mon);
    156 +	XMapWindow(dpy, c->win);
    157 +	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
    158 +	configure(c);
    159 +	setclientstate(c, NormalState);
    160 +}
    161 +
    162 +void
    163  buttonpress(XEvent *e)
    164  {
    165  	unsigned int i, x, click;
    166 @@ -477,7 +531,7 @@ cleanup(void)
    167  	selmon->lt[selmon->sellt] = &foo;
    168  	for (m = mons; m; m = m->next)
    169  		while (m->stack)
    170 -			unmanage(m->stack, 0);
    171 +			unmanage(m->stack, 0); // XXX - unmanage swallowing windows too
    172  	XUngrabKey(dpy, AnyKey, AnyModifier, root);
    173  	while (mons)
    174  		cleanupmon(mons);
    175 @@ -665,6 +719,9 @@ destroynotify(XEvent *e)
    176  
    177  	if ((c = wintoclient(ev->window)))
    178  		unmanage(c, 1);
    179 +
    180 +	else if ((c = swallowingclient(ev->window)))
    181 +		unmanage(c->swallowing, 1);
    182  }
    183  
    184  void
    185 @@ -1034,12 +1091,13 @@ killclient(const Arg *arg)
    186  void
    187  manage(Window w, XWindowAttributes *wa)
    188  {
    189 -	Client *c, *t = NULL;
    190 +	Client *c, *t = NULL, *term = NULL;
    191  	Window trans = None;
    192  	XWindowChanges wc;
    193  
    194  	c = ecalloc(1, sizeof(Client));
    195  	c->win = w;
    196 +	c->pid = winpid(w);
    197  	/* geometry */
    198  	c->x = c->oldx = wa->x;
    199  	c->y = c->oldy = wa->y;
    200 @@ -1054,6 +1112,7 @@ manage(Window w, XWindowAttributes *wa)
    201  	} else {
    202  		c->mon = selmon;
    203  		applyrules(c);
    204 +		term = termforwin(c);
    205  	}
    206  
    207  	if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
    208 @@ -1090,6 +1149,8 @@ manage(Window w, XWindowAttributes *wa)
    209  	c->mon->sel = c;
    210  	arrange(c->mon);
    211  	XMapWindow(dpy, c->win);
    212 +	if (term)
    213 +		swallow(term, c);
    214  	focus(NULL);
    215  }
    216  
    217 @@ -1757,6 +1818,20 @@ unmanage(Client *c, int destroyed)
    218  	Monitor *m = c->mon;
    219  	XWindowChanges wc;
    220  
    221 +	if (c->swallowing) {
    222 +		unswallow(c);
    223 +		return;
    224 +	}
    225 +
    226 +	Client *s = swallowingclient(c->win);
    227 +	if (s) {
    228 +		free(s->swallowing);
    229 +		s->swallowing = NULL;
    230 +		arrange(m);
    231 +        focus(NULL);
    232 +		return;
    233 +	}
    234 +
    235  	/* The server grab construct avoids race conditions. */
    236  	detach(c);
    237  	detachstack(c);
    238 @@ -1772,9 +1847,12 @@ unmanage(Client *c, int destroyed)
    239  		XUngrabServer(dpy);
    240  	}
    241  	free(c);
    242 -	focus(NULL);
    243 -	updateclientlist();
    244 -	arrange(m);
    245 +
    246 +	if (!s) {
    247 +		arrange(m);
    248 +		focus(NULL);
    249 +		updateclientlist();
    250 +	}
    251  }
    252  
    253  void
    254 @@ -2039,16 +2117,116 @@ view(const Arg *arg)
    255  	arrange(selmon);
    256  }
    257  
    258 +pid_t
    259 +winpid(Window w)
    260 +{
    261 +	pid_t result = 0;
    262 +
    263 +	xcb_res_client_id_spec_t spec = {0};
    264 +	spec.client = w;
    265 +	spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
    266 +
    267 +	xcb_generic_error_t *e = NULL;
    268 +	xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
    269 +	xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
    270 +
    271 +	if (!r)
    272 +		return (pid_t)0;
    273 +
    274 +	xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
    275 +	for (; i.rem; xcb_res_client_id_value_next(&i)) {
    276 +		spec = i.data->spec;
    277 +		if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
    278 +			uint32_t *t = xcb_res_client_id_value_value(i.data);
    279 +			result = *t;
    280 +			break;
    281 +		}
    282 +	}
    283 +
    284 +	free(r);
    285 +
    286 +	if (result == (pid_t)-1)
    287 +		result = 0;
    288 +	return result;
    289 +}
    290 +
    291 +pid_t
    292 +getparentprocess(pid_t p)
    293 +{
    294 +	unsigned int v = 0;
    295 +
    296 +#ifdef __linux__
    297 +	FILE *f;
    298 +	char buf[256];
    299 +	snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
    300 +
    301 +	if (!(f = fopen(buf, "r")))
    302 +		return 0;
    303 +
    304 +	fscanf(f, "%*u %*s %*c %u", &v);
    305 +	fclose(f);
    306 +#endif /* __linux__ */
    307 +
    308 +	return (pid_t)v;
    309 +}
    310 +
    311 +int
    312 +isdescprocess(pid_t p, pid_t c)
    313 +{
    314 +	while (p != c && c != 0)
    315 +		c = getparentprocess(c);
    316 +
    317 +	return (int)c;
    318 +}
    319 +
    320 +Client *
    321 +termforwin(const Client *w)
    322 +{
    323 +	Client *c;
    324 +	Monitor *m;
    325 +
    326 +	if (!w->pid || w->isterminal)
    327 +		return NULL;
    328 +
    329 +	for (m = mons; m; m = m->next) {
    330 +		for (c = m->clients; c; c = c->next) {
    331 +			if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
    332 +				return c;
    333 +		}
    334 +	}
    335 +
    336 +	return NULL;
    337 +}
    338 +
    339 +Client *
    340 +swallowingclient(Window w)
    341 +{
    342 +	Client *c;
    343 +	Monitor *m;
    344 +
    345 +	for (m = mons; m; m = m->next) {
    346 +		for (c = m->clients; c; c = c->next) {
    347 +			if (c->swallowing && c->swallowing->win == w)
    348 +				return c;
    349 +		}
    350 +	}
    351 +
    352 +	return NULL;
    353 +}
    354 +
    355  Client *
    356  wintoclient(Window w)
    357  {
    358  	Client *c;
    359  	Monitor *m;
    360  
    361 -	for (m = mons; m; m = m->next)
    362 -		for (c = m->clients; c; c = c->next)
    363 +	for (m = mons; m; m = m->next) {
    364 +		for (c = m->clients; c; c = c->next) {
    365  			if (c->win == w)
    366  				return c;
    367 +		}
    368 +	}
    369 +
    370  	return NULL;
    371  }
    372  
    373 @@ -2130,6 +2308,8 @@ main(int argc, char *argv[])
    374  		fputs("warning: no locale support\n", stderr);
    375  	if (!(dpy = XOpenDisplay(NULL)))
    376  		die("dwm: cannot open display\n");
    377 +	if (!(xcon = XGetXCBConnection(dpy)))
    378 +		die("dwm: cannot get xcb connection\n");
    379  	checkotherwm();
    380  	setup();
    381  	scan();