all repos — dwm @ 04dec4c94390fdf57893615de5b5872dd5abbce4

fork of suckless dynamic window manager

event.c (view raw)

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