all repos — dwm @ c0705eeb65733e8c5091e47d5bdc701a0779a949

fork of suckless dynamic window manager

client.c (view raw)

  1/*
  2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
  3 * See LICENSE file for license details.
  4 */
  5
  6#include <stdlib.h>
  7#include <stdio.h>
  8#include <string.h>
  9#include <X11/Xatom.h>
 10#include <X11/Xutil.h>
 11
 12#include "dwm.h"
 13
 14static Rule rule[] = {
 15	/* class			instance	tags						floating */
 16	{ "Firefox-bin",	"Gecko",	{ [Twww] = "www" },			False },
 17};
 18
 19Client *
 20getnext(Client *c)
 21{
 22	for(; c && !c->tags[tsel]; c = c->next);
 23	return c;
 24}
 25
 26void
 27ban(Client *c)
 28{
 29	XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
 30	XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
 31}
 32
 33static void
 34resize_title(Client *c)
 35{
 36	int i;
 37
 38	c->tw = 0;
 39	for(i = 0; i < TLast; i++)
 40		if(c->tags[i])
 41			c->tw += textw(c->tags[i]);
 42	c->tw += textw(c->name);
 43	if(c->tw > c->w)
 44		c->tw = c->w + 2;
 45	c->tx = c->x + c->w - c->tw + 2;
 46	c->ty = c->y;
 47	XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
 48}
 49
 50void
 51settitle(Client *c)
 52{
 53	XTextProperty name;
 54	int n;
 55	char **list = NULL;
 56
 57	name.nitems = 0;
 58	c->name[0] = 0;
 59	XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
 60	if(!name.nitems)
 61		XGetWMName(dpy, c->win, &name);
 62	if(!name.nitems)
 63		return;
 64	if(name.encoding == XA_STRING)
 65		strncpy(c->name, (char *)name.value, sizeof(c->name));
 66	else {
 67		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
 68				&& n > 0 && *list)
 69		{
 70			strncpy(c->name, *list, sizeof(c->name));
 71			XFreeStringList(list);
 72		}
 73	}
 74	XFree(name.value);
 75	resize_title(c);
 76}
 77
 78void
 79setsize(Client *c)
 80{
 81	XSizeHints size;
 82	long msize;
 83	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
 84		size.flags = PSize;
 85	c->flags = size.flags;
 86	if(c->flags & PBaseSize) {
 87		c->basew = size.base_width;
 88		c->baseh = size.base_height;
 89	}
 90	else
 91		c->basew = c->baseh = 0;
 92	if(c->flags & PResizeInc) {
 93		c->incw = size.width_inc;
 94		c->inch = size.height_inc;
 95	}
 96	else
 97		c->incw = c->inch = 0;
 98	if(c->flags & PMaxSize) {
 99		c->maxw = size.max_width;
100		c->maxh = size.max_height;
101	}
102	else
103		c->maxw = c->maxh = 0;
104	if(c->flags & PMinSize) {
105		c->minw = size.min_width;
106		c->minh = size.min_height;
107	}
108	else
109		c->minw = c->minh = 0;
110	if(c->flags & PWinGravity)
111		c->grav = size.win_gravity;
112	else
113		c->grav = NorthWestGravity;
114}
115
116void
117higher(Client *c)
118{
119	XRaiseWindow(dpy, c->win);
120	XRaiseWindow(dpy, c->title);
121}
122
123void
124lower(Client *c)
125{
126	XLowerWindow(dpy, c->title);
127	XLowerWindow(dpy, c->win);
128}
129
130void
131focus(Client *c)
132{
133	Client *old = sel;
134	XEvent ev;
135
136	XFlush(dpy);
137	sel = c;
138	if(old && old != c)
139		drawtitle(old);
140	drawtitle(c);
141	XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
142	XFlush(dpy);
143	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
144}
145
146static void
147init_tags(Client *c)
148{
149	XClassHint ch;
150	static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0;
151	unsigned int i, j;
152	Bool matched = False;
153
154	if(!len) {
155		c->tags[tsel] = tags[tsel];
156		return;
157	}
158
159	if(XGetClassHint(dpy, c->win, &ch)) {
160		if(ch.res_class && ch.res_name) {
161			for(i = 0; i < len; i++)
162				if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class))
163					&& !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance)))
164				{
165					for(j = 0; j < TLast; j++)
166						c->tags[j] = rule[i].tags[j];
167					c->floating = rule[i].floating;
168					matched = True;
169					break;
170				}
171		}
172		if(ch.res_class)
173			XFree(ch.res_class);
174		if(ch.res_name)
175			XFree(ch.res_name);
176	}
177
178	if(!matched)
179		c->tags[tsel] = tags[tsel];
180}
181
182void
183manage(Window w, XWindowAttributes *wa)
184{
185	Client *c, **l;
186	XSetWindowAttributes twa;
187	Window trans;
188
189	c = emallocz(sizeof(Client));
190	c->win = w;
191	c->tx = c->x = wa->x;
192	c->ty = c->y = wa->y;
193	if(c->y < bh)
194		c->ty = c->y += bh;
195	c->tw = c->w = wa->width;
196	c->h = wa->height;
197	c->th = bh;
198	c->border = 1;
199	c->proto = proto(c->win);
200	setsize(c);
201	XSelectInput(dpy, c->win,
202			StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
203	XGetTransientForHint(dpy, c->win, &trans);
204	twa.override_redirect = 1;
205	twa.background_pixmap = ParentRelative;
206	twa.event_mask = ExposureMask;
207
208	c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
209			0, DefaultDepth(dpy, screen), CopyFromParent,
210			DefaultVisual(dpy, screen),
211			CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
212
213	settitle(c);
214	init_tags(c);
215
216	for(l = &clients; *l; l = &(*l)->next);
217	c->next = *l; /* *l == nil */
218	*l = c;
219
220	XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
221			GrabModeAsync, GrabModeSync, None, None);
222	XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
223			GrabModeAsync, GrabModeSync, None, None);
224	XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
225			GrabModeAsync, GrabModeSync, None, None);
226
227	if(!c->floating)
228		c->floating = trans
229			|| ((c->maxw == c->minw) && (c->maxh == c->minh));
230
231	arrange(NULL);
232	/* mapping the window now prevents flicker */
233	if(c->tags[tsel]) {
234		XMapRaised(dpy, c->win);
235		XMapRaised(dpy, c->title);
236		focus(c);
237	}
238	else {
239		ban(c);
240		XMapRaised(dpy, c->win);
241		XMapRaised(dpy, c->title);
242	}
243}
244
245void
246gravitate(Client *c, Bool invert)
247{
248	int dx = 0, dy = 0;
249
250	switch(c->grav) {
251	case StaticGravity:
252	case NorthWestGravity:
253	case NorthGravity:
254	case NorthEastGravity:
255		dy = c->border;
256		break;
257	case EastGravity:
258	case CenterGravity:
259	case WestGravity:
260		dy = -(c->h / 2) + c->border;
261		break;
262	case SouthEastGravity:
263	case SouthGravity:
264	case SouthWestGravity:
265		dy = -c->h;
266		break;
267	default:
268		break;
269	}
270
271	switch (c->grav) {
272	case StaticGravity:
273	case NorthWestGravity:
274	case WestGravity:
275	case SouthWestGravity:
276		dx = c->border;
277		break;
278	case NorthGravity:
279	case CenterGravity:
280	case SouthGravity:
281		dx = -(c->w / 2) + c->border;
282		break;
283	case NorthEastGravity:
284	case EastGravity:
285	case SouthEastGravity:
286		dx = -(c->w + c->border);
287		break;
288	default:
289		break;
290	}
291
292	if(invert) {
293		dx = -dx;
294		dy = -dy;
295	}
296	c->x += dx;
297	c->y += dy;
298}
299
300
301void
302resize(Client *c, Bool inc)
303{
304	XConfigureEvent e;
305
306	if(inc) {
307		if(c->incw)
308			c->w -= (c->w - c->basew) % c->incw;
309		if(c->inch)
310			c->h -= (c->h - c->baseh) % c->inch;
311	}
312	if(c->x > sw) /* might happen on restart */
313		c->x = sw - c->w;
314	if(c->y > sh)
315		c->ty = c->y = sh - c->h;
316	if(c->minw && c->w < c->minw)
317		c->w = c->minw;
318	if(c->minh && c->h < c->minh)
319		c->h = c->minh;
320	if(c->maxw && c->w > c->maxw)
321		c->w = c->maxw;
322	if(c->maxh && c->h > c->maxh)
323		c->h = c->maxh;
324	resize_title(c);
325	XSetWindowBorderWidth(dpy, c->win, 1);
326	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
327	e.type = ConfigureNotify;
328	e.event = c->win;
329	e.window = c->win;
330	e.x = c->x;
331	e.y = c->y;
332	e.width = c->w;
333	e.height = c->h;
334	e.border_width = c->border;
335	e.above = None;
336	e.override_redirect = False;
337	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
338	XFlush(dpy);
339}
340
341static int
342dummy_xerror(Display *dsply, XErrorEvent *err)
343{
344	return 0;
345}
346
347void
348unmanage(Client *c)
349{
350	Client **l;
351
352	XGrabServer(dpy);
353	XSetErrorHandler(dummy_xerror);
354
355	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
356	XDestroyWindow(dpy, c->title);
357
358	for(l = &clients; *l && *l != c; l = &(*l)->next);
359	*l = c->next;
360	for(l = &clients; *l; l = &(*l)->next)
361		if((*l)->revert == c)
362			(*l)->revert = NULL;
363	if(sel == c)
364		sel = sel->revert ? sel->revert : clients;
365
366	free(c);
367
368	XFlush(dpy);
369	XSetErrorHandler(xerror);
370	XUngrabServer(dpy);
371	arrange(NULL);
372	if(sel)
373		focus(sel);
374}
375
376Client *
377gettitle(Window w)
378{
379	Client *c;
380	for(c = clients; c; c = c->next)
381		if(c->title == w)
382			return c;
383	return NULL;
384}
385
386Client *
387getclient(Window w)
388{
389	Client *c;
390	for(c = clients; c; c = c->next)
391		if(c->win == w)
392			return c;
393	return NULL;
394}