all repos — dwm @ 399993c6b5d594278bf822e2981ebfe8bfcb58c7

fork of suckless dynamic window manager

event.c (view raw)

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