all repos — dwm @ 4641aa2925731ac180b08c80f57db176391ea4a9

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 <math.h>
  7#include <stdlib.h>
  8#include <string.h>
  9#include <X11/Xatom.h>
 10
 11#include "util.h"
 12#include "wm.h"
 13
 14void
 15arrange(void *aux)
 16{
 17	Client *c;
 18	int n, cols, rows, gw, gh, i, j;
 19    float rt, fd;
 20
 21	if(!clients)
 22		return;
 23	for(n = 0, c = clients; c; c = c->next, n++);
 24	rt = sqrt(n);
 25	if(modff(rt, &fd) < 0.5)
 26		rows = floor(rt);
 27	else
 28		rows = ceil(rt);
 29	if(rows * rows < n)
 30		cols = rows + 1;
 31	else
 32		cols = rows;
 33
 34	gw = (sw - 1)  / cols;
 35	gh = (sh - bh - 1) / rows;
 36
 37	for(i = j = 0, c = clients; c; c = c->next) {
 38		c->x = i * gw;
 39		c->y = j * gh + bh;
 40		c->w = gw;
 41		c->h = gh;
 42		resize(c);
 43		if(++i == cols) {
 44			j++;
 45			i = 0;
 46		}
 47	}
 48}
 49
 50void
 51sel(void *aux)
 52{
 53	const char *arg = aux;
 54	Client *c = NULL;
 55
 56	if(!arg || !stack)
 57		return;
 58	if(!strncmp(arg, "next", 5))
 59		c = stack->snext ? stack->snext : stack;
 60	else if(!strncmp(arg, "prev", 5))
 61		for(c = stack; c && c->snext; c = c->snext);
 62	if(!c)
 63		c = stack;
 64	raise(c);
 65	focus(c);
 66}
 67
 68void
 69kill(void *aux)
 70{
 71	Client *c = stack;
 72
 73	if(!c)
 74		return;
 75	if(c->proto & WM_PROTOCOL_DELWIN)
 76		send_message(c->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
 77	else
 78		XKillClient(dpy, c->win);
 79}
 80
 81static void
 82resize_title(Client *c)
 83{
 84	c->tw = textw(&brush.font, c->name) + bh;
 85	if(c->tw > c->w)
 86		c->tw = c->w + 2;
 87	c->tx = c->x + c->w - c->tw + 2;
 88	c->ty = c->y;
 89	XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
 90}
 91
 92void
 93update_name(Client *c)
 94{
 95	XTextProperty name;
 96	int n;
 97	char **list = NULL;
 98
 99	name.nitems = 0;
100	c->name[0] = 0;
101	XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
102	if(!name.nitems)
103		XGetWMName(dpy, c->win, &name);
104	if(!name.nitems)
105		return;
106	if(name.encoding == XA_STRING)
107		strncpy(c->name, (char *)name.value, sizeof(c->name));
108	else {
109		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
110				&& n > 0 && *list)
111		{
112			strncpy(c->name, *list, sizeof(c->name));
113			XFreeStringList(list);
114		}
115	}
116	XFree(name.value);
117	resize_title(c);
118}
119
120void
121update_size(Client *c)
122{
123	XSizeHints size;
124	long msize;
125	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
126		size.flags = PSize;
127	c->flags = size.flags;
128	if(c->flags & PBaseSize) {
129		c->basew = size.base_width;
130		c->baseh = size.base_height;
131	}
132	else
133		c->basew = c->baseh = 0;
134	if(c->flags & PResizeInc) {
135		c->incw = size.width_inc;
136		c->inch = size.height_inc;
137	}
138	else
139		c->incw = c->inch = 0;
140	if(c->flags & PMaxSize) {
141		c->maxw = size.max_width;
142		c->maxh = size.max_height;
143	}
144	else
145		c->maxw = c->maxh = 0;
146	if(c->flags & PMinSize) {
147		c->minw = size.min_width;
148		c->minh = size.min_height;
149	}
150	else
151		c->minw = c->minh = 0;
152}
153
154void
155raise(Client *c)
156{
157	XRaiseWindow(dpy, c->win);
158	XRaiseWindow(dpy, c->title);
159}
160
161void
162lower(Client *c)
163{
164	XLowerWindow(dpy, c->title);
165	XLowerWindow(dpy, c->win);
166}
167
168void
169focus(Client *c)
170{
171	Client **l, *old;
172
173	old = stack;
174	for(l = &stack; *l && *l != c; l = &(*l)->snext);
175	eassert(*l == c);
176	*l = c->snext;
177	c->snext = stack;
178	stack = c;
179	if(old && old != c) {
180		XMapWindow(dpy, old->title);
181		draw_client(old);
182	}
183	XUnmapWindow(dpy, c->title);
184	draw_client(c);
185	XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
186	XFlush(dpy);
187}
188
189void
190manage(Window w, XWindowAttributes *wa)
191{
192	Client *c, **l;
193	XSetWindowAttributes twa;
194
195	c = emallocz(sizeof(Client));
196	c->win = w;
197	c->tx = c->x = wa->x;
198	c->ty = c->y = wa->y;
199	if(c->y < bh)
200		c->ty = c->y += bh;
201	c->tw = c->w = wa->width;
202	c->h = wa->height;
203	c->th = bh;
204	update_size(c);
205	XSetWindowBorderWidth(dpy, c->win, 1);
206	XSetWindowBorder(dpy, c->win, brush.border);
207	XSelectInput(dpy, c->win,
208			StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
209	XGetTransientForHint(dpy, c->win, &c->trans);
210	twa.override_redirect = 1;
211	twa.background_pixmap = ParentRelative;
212	twa.event_mask = ExposureMask;
213
214	c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
215			0, DefaultDepth(dpy, screen), CopyFromParent,
216			DefaultVisual(dpy, screen),
217			CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
218	update_name(c);
219
220	for(l=&clients; *l; l=&(*l)->next);
221	c->next = *l; /* *l == nil */
222	*l = c;
223	c->snext = stack;
224	stack = c;
225	XMapRaised(dpy, c->win);
226	XMapRaised(dpy, c->title);
227	XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
228			GrabModeAsync, GrabModeSync, None, None);
229	XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
230			GrabModeAsync, GrabModeSync, None, None);
231	XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
232			GrabModeAsync, GrabModeSync, None, None);
233	resize(c);
234	focus(c);
235}
236
237void
238resize(Client *c)
239{
240	XConfigureEvent e;
241
242	resize_title(c);
243	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
244	e.type = ConfigureNotify;
245	e.event = c->win;
246	e.window = c->win;
247	e.x = c->x;
248	e.y = c->y;
249	e.width = c->w;
250	e.height = c->h;
251	e.border_width = 0;
252	e.above = None;
253	e.override_redirect = False;
254	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
255	XFlush(dpy);
256}
257
258static int
259dummy_error_handler(Display *dpy, XErrorEvent *error)
260{
261	return 0;
262}
263
264void
265unmanage(Client *c)
266{
267	Client **l;
268
269	XGrabServer(dpy);
270	XSetErrorHandler(dummy_error_handler);
271
272	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
273	XDestroyWindow(dpy, c->title);
274
275	for(l=&clients; *l && *l != c; l=&(*l)->next);
276	eassert(*l == c);
277	*l = c->next;
278	for(l=&stack; *l && *l != c; l=&(*l)->snext);
279	eassert(*l == c);
280	*l = c->snext;
281	free(c);
282
283	XFlush(dpy);
284	XSetErrorHandler(error_handler);
285	XUngrabServer(dpy);
286	if(stack)
287		focus(stack);
288}
289
290Client *
291gettitle(Window w)
292{
293	Client *c;
294	for(c = clients; c; c = c->next)
295		if(c->title == w)
296			return c;
297	return NULL;
298}
299
300Client *
301getclient(Window w)
302{
303	Client *c;
304	for(c = clients; c; c = c->next)
305		if(c->win == w)
306			return c;
307	return NULL;
308}
309
310void
311draw_client(Client *c)
312{
313	if(c == stack) {
314		draw_bar();
315		return;
316	}
317
318	brush.x = brush.y = 0;
319	brush.w = c->tw;
320	brush.h = c->th;
321
322	draw(dpy, &brush, True, c->name);
323	XCopyArea(dpy, brush.drawable, c->title, brush.gc,
324			0, 0, c->tw, c->th, 0, 0);
325	XFlush(dpy);
326}