diff options
| -rw-r--r-- | client.h | 8 | ||||
| -rw-r--r-- | config.def.h | 8 | ||||
| -rw-r--r-- | dwl.c | 113 | 
3 files changed, 121 insertions, 8 deletions
@@ -167,6 +167,14 @@ client_get_appid(Client *c)  	return c->surface.xdg->toplevel->app_id;  } +#ifdef XWAYLAND +static inline int +client_get_pid(Client *c) +{ +	return c->surface.xwayland->pid; +} +#endif +  static inline void  client_get_geometry(Client *c, struct wlr_box *geom)  { diff --git a/config.def.h b/config.def.h index f505aa7..d41d85f 100644 --- a/config.def.h +++ b/config.def.h @@ -14,11 +14,13 @@ static const float fullscreen_bg[]         = {0.1,  0.1,   0.1,  1.0};  static const int tagcount = TAGCOUNT;  static const Rule rules[] = { -	/* app_id     title       tags mask     isfloating   monitor */ +	/* app_id     title       tags mask     isfloating  isterm  noswallow  monitor */  	/* examples: -	{ "Gimp",     NULL,       0,            1,           -1 }, +	{ "Gimp",     NULL,       0,            1,          0,      1,         -1 },  	*/ -	{ "firefox",  NULL,       1 << 8,       0,           -1 }, +	{ "firefox",  NULL,       1 << 8,       0,          0,      1,         -1 }, +	{ "foot",     NULL,       0,            0,          1,      1,         -1 }, +	{ "wev",      NULL,       0,		0,          0,      1,         -1 },  };  /* layout(s) */ @@ -95,7 +95,8 @@ typedef struct {  } Button;  typedef struct Monitor Monitor; -typedef struct { +typedef struct Client Client; +struct Client {  	/* Must keep these three elements in this order */  	unsigned int type; /* XDGShell or X11* */  	struct wlr_box geom; /* layout-relative, includes border */ @@ -124,9 +125,11 @@ typedef struct {  #endif  	unsigned int bw;  	uint32_t tags; -	int isfloating, isurgent, isfullscreen; +	int isfloating, isurgent, isfullscreen, isterm, noswallow;  	uint32_t resize; /* configure serial of a pending resize */ -} Client; +	pid_t pid; +	Client *swallowing, *swallowedby; +};  typedef struct {  	uint32_t mod; @@ -208,6 +211,8 @@ typedef struct {  	const char *title;  	uint32_t tags;  	int isfloating; +	int isterm; +	int noswallow;  	int monitor;  } Rule; @@ -318,6 +323,10 @@ static Monitor *xytomon(double x, double y);  static void xytonode(double x, double y, struct wlr_surface **psurface,  		Client **pc, LayerSurface **pl, double *nx, double *ny);  static void zoom(const Arg *arg); +static pid_t getparentprocess(pid_t p); +static int isdescprocess(pid_t p, pid_t c); +static Client *termforwin(Client *w); +static void swallow(Client *c, Client *w);  /* variables */  static const char broken[] = "broken"; @@ -456,10 +465,17 @@ applyrules(Client *c)  	if (!(title = client_get_title(c)))  		title = broken; +	if (client_is_x11(c)) +	{ +		c->pid = client_get_pid(c); +	} +  	for (r = rules; r < END(rules); r++) {  		if ((!r->title || strstr(title, r->title))  				&& (!r->id || strstr(appid, r->id))) {  			c->isfloating = r->isfloating; +			c->isterm     = r->isterm; +			c->noswallow  = r->noswallow;  			newtags |= r->tags;  			i = 0;  			wl_list_for_each(m, &mons, link) @@ -1005,6 +1021,8 @@ createnotify(struct wl_listener *listener, void *data)  	c->surface.xdg = xdg_surface;  	c->bw = borderpx; +	wl_client_get_credentials(c->surface.xdg->client->client, &c->pid, NULL, NULL); +  	LISTEN(&xdg_surface->events.map, &c->map, mapnotify);  	LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify);  	LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); @@ -1351,6 +1369,61 @@ handlesig(int signo)  	}  } +pid_t +getparentprocess(pid_t p) +{ +	unsigned int v = 0; + +	FILE *f; +	char buf[256]; +	snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); + +	if (!(f = fopen(buf, "r"))) +		return 0; + +	fscanf(f, "%*u %*s %*c %u", &v); +	fclose(f); + +	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(Client *w) +{ +	Client *c; + +	if (!w->pid || w->isterm || w->noswallow) +		return NULL; + +	wl_list_for_each(c, &fstack, flink) +		if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) +			return c; + +	return NULL; +} + +void +swallow(Client *c, Client *w) { +	c->bw = w->bw; +	c->isfloating = w->isfloating; +	c->isurgent = w->isurgent; +	c->isfullscreen = w->isfullscreen; +	resize(c, w->geom, 0); +	wl_list_insert(&w->link, &c->link); +	wl_list_insert(&w->flink, &c->flink); +	wlr_scene_node_set_enabled(&w->scene->node, 0); +	wlr_scene_node_set_enabled(&c->scene->node, 1); +} +  void  incnmaster(const Arg *arg)  { @@ -1597,6 +1670,20 @@ mapnotify(struct wl_listener *listener, void *data)  	}  	printstatus(); +	if (!c->noswallow && !client_is_float_type(c)) { +		p = termforwin(c); +		if (p) { +			c->swallowedby = p; +			p->swallowing  = c; +			wl_list_remove(&c->link); +			wl_list_remove(&c->flink); +			swallow(c,p); +			wl_list_remove(&p->link); +			wl_list_remove(&p->flink); +			setfullscreen(c, p->isfullscreen); +		} +	} +  unset_fullscreen:  	m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);  	wl_list_for_each(w, &clients, link) @@ -2111,6 +2198,8 @@ setmon(Client *c, Monitor *m, uint32_t newtags)  		setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */  		setfloating(c, c->isfloating);  	} +	if (c->swallowedby) +		setmon(c->swallowedby, m, newtags);  	focusclient(focustop(selmon), 1);  } @@ -2482,15 +2571,29 @@ unmapnotify(struct wl_listener *listener, void *data)  		grabc = NULL;  	} +	if (c->swallowedby) { +		setfullscreen(c->swallowedby, c->isfullscreen); +		swallow(c->swallowedby, c); +		c->swallowedby->swallowing = NULL; +		c->swallowedby = NULL; +	} +  	if (client_is_unmanaged(c)) {  		if (c == exclusive_focus)  			exclusive_focus = NULL;  		if (client_surface(c) == seat->keyboard_state.focused_surface)  			focusclient(focustop(selmon), 1);  	} else { -		wl_list_remove(&c->link); +		if (!c->swallowing) +			wl_list_remove(&c->link);  		setmon(c, NULL, 0); -		wl_list_remove(&c->flink); +		if (!c->swallowing) +			wl_list_remove(&c->flink); +	} + +	if (c->swallowing) { +		c->swallowing->swallowedby = NULL; +		c->swallowing = NULL;  	}  	wl_list_remove(&c->commit.link);  | 
