all repos — dwm @ e1deda9e040c052af62aecc2fb4ee770fb2496a2

fork of suckless dynamic window manager

event.c (view raw)

  1/* © 2006-2007 Anselm R. Garbe <garbeam at gmail dot com>
  2 * © 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
  3 * © 2007 Premysl Hruby <dfenze at gmail dot com>
  4 * See LICENSE file for license details. */
  5#include "dwm.h"
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <X11/keysym.h>
  9#include <X11/Xatom.h>
 10
 11/* static */
 12
 13typedef struct {
 14	unsigned long mod;
 15	KeySym keysym;
 16	void (*func)(const char *arg);
 17	const char *arg;
 18} Key;
 19
 20KEYS
 21
 22#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
 23#define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
 24
 25static Client *
 26getclient(Window w) {
 27	Client *c;
 28
 29	for(c = clients; c && c->win != w; c = c->next);
 30	return c;
 31}
 32
 33static void
 34movemouse(Client *c) {
 35	int x1, y1, ocx, ocy, di, nx, ny;
 36	unsigned int dui;
 37	Window dummy;
 38	XEvent ev;
 39
 40	ocx = nx = c->x;
 41	ocy = ny = c->y;
 42	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 43			None, cursor[CurMove], CurrentTime) != GrabSuccess)
 44		return;
 45	c->ismax = False;
 46	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
 47	for(;;) {
 48		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
 49		switch (ev.type) {
 50		case ButtonRelease:
 51			XUngrabPointer(dpy, CurrentTime);
 52			return;
 53		case ConfigureRequest:
 54		case Expose:
 55		case MapRequest:
 56			handler[ev.type](&ev);
 57			break;
 58		case MotionNotify:
 59			XSync(dpy, False);
 60			nx = ocx + (ev.xmotion.x - x1);
 61			ny = ocy + (ev.xmotion.y - y1);
 62			if(abs(wax + nx) < SNAP)
 63				nx = wax;
 64			else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
 65				nx = wax + waw - c->w - 2 * c->border;
 66			if(abs(way - ny) < SNAP)
 67				ny = way;
 68			else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
 69				ny = way + wah - c->h - 2 * c->border;
 70			resize(c, nx, ny, c->w, c->h, False);
 71			break;
 72		}
 73	}
 74}
 75
 76static void
 77resizemouse(Client *c) {
 78	int ocx, ocy;
 79	int nw, nh;
 80	XEvent ev;
 81
 82	ocx = c->x;
 83	ocy = c->y;
 84	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 85			None, cursor[CurResize], CurrentTime) != GrabSuccess)
 86		return;
 87	c->ismax = False;
 88	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
 89	for(;;) {
 90		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
 91		switch(ev.type) {
 92		case ButtonRelease:
 93			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
 94					c->w + c->border - 1, c->h + c->border - 1);
 95			XUngrabPointer(dpy, CurrentTime);
 96			while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
 97			return;
 98		case ConfigureRequest:
 99		case Expose:
100		case MapRequest:
101			handler[ev.type](&ev);
102			break;
103		case MotionNotify:
104			XSync(dpy, False);
105			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
106				nw = 1;
107			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
108				nh = 1;
109			resize(c, c->x, c->y, nw, nh, True);
110			break;
111		}
112	}
113}
114
115static void
116buttonpress(XEvent *e) {
117	static char buf[32];
118	unsigned int i, x;
119	Client *c;
120	XButtonPressedEvent *ev = &e->xbutton;
121
122	buf[0] = 0;
123	if(barwin == ev->window) {
124		x = 0;
125		for(i = 0; i < ntags; i++) {
126			x += textw(tags[i]);
127			if(ev->x < x) {
128				snprintf(buf, sizeof buf, "%d", i);
129				if(ev->button == Button1) {
130					if(ev->state & MODKEY)
131						tag(buf);
132					else
133						view(buf);
134				}
135				else if(ev->button == Button3) {
136					if(ev->state & MODKEY)
137						toggletag(buf);
138					else
139						toggleview(buf);
140				}
141				return;
142			}
143		}
144		if(ev->x < x + blw)
145			switch(ev->button) {
146			case Button1:
147				setlayout(NULL);
148				break;
149			}
150	}
151	else if((c = getclient(ev->window))) {
152		focus(c);
153		if(CLEANMASK(ev->state) != MODKEY)
154			return;
155		if(ev->button == Button1 && (lt->arrange == floating || c->isfloating)) {
156			restack();
157			movemouse(c);
158		}
159		else if(ev->button == Button2)
160			zoom(NULL);
161		else if(ev->button == Button3
162		&& (lt->arrange == floating || c->isfloating) && !c->isfixed)
163		{
164			restack();
165			resizemouse(c);
166		}
167	}
168}
169
170static void
171configurerequest(XEvent *e) {
172	Client *c;
173	XConfigureRequestEvent *ev = &e->xconfigurerequest;
174	XWindowChanges wc;
175
176	if((c = getclient(ev->window))) {
177		c->ismax = False;
178		if(ev->value_mask & CWBorderWidth)
179			c->border = ev->border_width;
180		if(c->isfixed || c->isfloating || (lt->arrange == floating)) {
181			if(ev->value_mask & CWX)
182				c->x = ev->x;
183			if(ev->value_mask & CWY)
184				c->y = ev->y;
185			if(ev->value_mask & CWWidth)
186				c->w = ev->width;
187			if(ev->value_mask & CWHeight)
188				c->h = ev->height;
189			if((c->x + c->w) > sw && c->isfloating)
190				c->x = sw / 2 - c->w / 2; /* center in x direction */
191			if((c->y + c->h) > sh && c->isfloating)
192				c->y = sh / 2 - c->h / 2; /* center in y direction */
193			if((ev->value_mask & (CWX | CWY))
194			&& !(ev->value_mask & (CWWidth | CWHeight)))
195				configure(c);
196			if(isvisible(c))
197				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
198		}
199		else
200			configure(c);
201	}
202	else {
203		wc.x = ev->x;
204		wc.y = ev->y;
205		wc.width = ev->width;
206		wc.height = ev->height;
207		wc.border_width = ev->border_width;
208		wc.sibling = ev->above;
209		wc.stack_mode = ev->detail;
210		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
211	}
212	XSync(dpy, False);
213}
214
215static void
216configurenotify(XEvent *e) {
217	XConfigureEvent *ev = &e->xconfigure;
218
219	if (ev->window == root && (ev->width != sw || ev->height != sh)) {
220		sw = ev->width;
221		sh = ev->height;
222		XFreePixmap(dpy, dc.drawable);
223		dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
224		XResizeWindow(dpy, barwin, sw, bh);
225		updatebarpos();
226		lt->arrange();
227	}
228}
229
230static void
231destroynotify(XEvent *e) {
232	Client *c;
233	XDestroyWindowEvent *ev = &e->xdestroywindow;
234
235	if((c = getclient(ev->window)))
236		unmanage(c);
237}
238
239static void
240enternotify(XEvent *e) {
241	Client *c;
242	XCrossingEvent *ev = &e->xcrossing;
243
244	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
245		return;
246	if(c = getclient(ev->window))
247		focus(c);
248	else if(ev->window == root) {
249		selscreen = True;
250		focus(NULL);
251	}
252}
253
254static void
255expose(XEvent *e) {
256	XExposeEvent *ev = &e->xexpose;
257
258	if(ev->count == 0) {
259		if(barwin == ev->window)
260			drawstatus();
261	}
262}
263
264static void
265keypress(XEvent *e) {
266	static unsigned int len = sizeof key / sizeof key[0];
267	unsigned int i;
268	KeySym keysym;
269	XKeyEvent *ev = &e->xkey;
270
271	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
272	for(i = 0; i < len; i++)
273		if(keysym == key[i].keysym
274		&& CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
275		{
276			if(key[i].func)
277				key[i].func(key[i].arg);
278		}
279}
280
281static void
282leavenotify(XEvent *e) {
283	XCrossingEvent *ev = &e->xcrossing;
284
285	if((ev->window == root) && !ev->same_screen) {
286		selscreen = False;
287		focus(NULL);
288	}
289}
290
291static void
292mappingnotify(XEvent *e) {
293	XMappingEvent *ev = &e->xmapping;
294
295	XRefreshKeyboardMapping(ev);
296	if(ev->request == MappingKeyboard)
297		grabkeys();
298}
299
300static void
301maprequest(XEvent *e) {
302	static XWindowAttributes wa;
303	XMapRequestEvent *ev = &e->xmaprequest;
304
305	if(!XGetWindowAttributes(dpy, ev->window, &wa))
306		return;
307	if(wa.override_redirect)
308		return;
309	if(!getclient(ev->window))
310		manage(ev->window, &wa);
311}
312
313static void
314propertynotify(XEvent *e) {
315	Client *c;
316	Window trans;
317	XPropertyEvent *ev = &e->xproperty;
318
319	if(ev->state == PropertyDelete)
320		return; /* ignore */
321	if((c = getclient(ev->window))) {
322		switch (ev->atom) {
323			default: break;
324			case XA_WM_TRANSIENT_FOR:
325				XGetTransientForHint(dpy, c->win, &trans);
326				if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
327					lt->arrange();
328				break;
329			case XA_WM_NORMAL_HINTS:
330				updatesizehints(c);
331				break;
332		}
333		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
334			updatetitle(c);
335			if(c == sel)
336				drawstatus();
337		}
338	}
339}
340
341static void
342unmapnotify(XEvent *e) {
343	Client *c;
344	XUnmapEvent *ev = &e->xunmap;
345
346	if((c = getclient(ev->window)))
347		unmanage(c);
348}
349
350/* extern */
351
352void (*handler[LASTEvent]) (XEvent *) = {
353	[ButtonPress] = buttonpress,
354	[ConfigureRequest] = configurerequest,
355	[ConfigureNotify] = configurenotify,
356	[DestroyNotify] = destroynotify,
357	[EnterNotify] = enternotify,
358	[LeaveNotify] = leavenotify,
359	[Expose] = expose,
360	[KeyPress] = keypress,
361	[MappingNotify] = mappingnotify,
362	[MapRequest] = maprequest,
363	[PropertyNotify] = propertynotify,
364	[UnmapNotify] = unmapnotify
365};
366
367void
368grabkeys(void) {
369	static unsigned int len = sizeof key / sizeof key[0];
370	unsigned int i;
371	KeyCode code;
372
373	XUngrabKey(dpy, AnyKey, AnyModifier, root);
374	for(i = 0; i < len; i++) {
375		code = XKeysymToKeycode(dpy, key[i].keysym);
376		XGrabKey(dpy, code, key[i].mod, root, True,
377				GrabModeAsync, GrabModeAsync);
378		XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
379				GrabModeAsync, GrabModeAsync);
380		XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
381				GrabModeAsync, GrabModeAsync);
382		XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
383				GrabModeAsync, GrabModeAsync);
384	}
385}