all repos — dwm @ f1294353f200bf646b40d85906bac4d204eea5fa

fork of suckless dynamic window manager

event.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#include "dwm.h"
  6
  7#include <stdlib.h>
  8#include <X11/keysym.h>
  9#include <X11/Xatom.h>
 10
 11#define ButtonMask      (ButtonPressMask | ButtonReleaseMask)
 12#define MouseMask       (ButtonMask | PointerMotionMask)
 13
 14/* CUSTOMIZE */
 15const char *browse[] = { "firefox", NULL };
 16const char *gimp[] = { "gimp", NULL };
 17const char *term[] = { 
 18	"urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-cr", "white",
 19	"-fn", "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", NULL
 20};
 21const char *xlock[] = { "xlock", NULL };
 22
 23Key key[] = {
 24	/* modifier				key			function	arguments */
 25	{ ControlMask,			XK_0,		appendtag,	{ .i = Tscratch } }, 
 26	{ ControlMask,			XK_1,		appendtag,	{ .i = Tdev } }, 
 27	{ ControlMask,			XK_2,		appendtag,	{ .i = Twww } }, 
 28	{ ControlMask,			XK_3,		appendtag,	{ .i = Twork } }, 
 29	{ Mod1Mask,				XK_0,		view,		{ .i = Tscratch } }, 
 30	{ Mod1Mask,				XK_1,		view,		{ .i = Tdev } }, 
 31	{ Mod1Mask,				XK_2,		view,		{ .i = Twww } }, 
 32	{ Mod1Mask,				XK_3,		view,		{ .i = Twork } }, 
 33	{ Mod1Mask,				XK_j,		focusnext,		{ 0 } }, 
 34	{ Mod1Mask,				XK_k,		focusprev,		{ 0 } },
 35	{ Mod1Mask,				XK_m,		maximize,		{ 0 } }, 
 36	{ Mod1Mask,				XK_space,	dotile,		{ 0 } }, 
 37	{ Mod1Mask,				XK_Return,	zoom,		{ 0 } },
 38	{ ControlMask|ShiftMask,XK_0,		heretag,	{ .i = Tscratch } }, 
 39	{ ControlMask|ShiftMask,XK_1,		heretag,	{ .i = Tdev } }, 
 40	{ ControlMask|ShiftMask,XK_2,		heretag,	{ .i = Twww } }, 
 41	{ ControlMask|ShiftMask,XK_3,		heretag,	{ .i = Twork } }, 
 42	{ Mod1Mask|ShiftMask,	XK_0,		replacetag,		{ .i = Tscratch } }, 
 43	{ Mod1Mask|ShiftMask,	XK_1,		replacetag,		{ .i = Tdev } }, 
 44	{ Mod1Mask|ShiftMask,	XK_2,		replacetag,		{ .i = Twww } }, 
 45	{ Mod1Mask|ShiftMask,	XK_3,		replacetag,		{ .i = Twork } }, 
 46	{ Mod1Mask|ShiftMask,	XK_c,		killclient,		{ 0 } }, 
 47	{ Mod1Mask|ShiftMask,	XK_g,		spawn,		{ .argv = gimp } },
 48	{ Mod1Mask|ShiftMask,	XK_l,		spawn,		{ .argv = xlock } },
 49	{ Mod1Mask|ShiftMask,	XK_q,		quit,		{ 0 } },
 50	{ Mod1Mask|ShiftMask,	XK_space,	dofloat,	{ 0 } }, 
 51	{ Mod1Mask|ShiftMask,	XK_w,		spawn,		{ .argv = browse } },
 52	{ Mod1Mask|ShiftMask,	XK_Return,	spawn,		{ .argv = term } },
 53};
 54
 55/* static */
 56
 57static void
 58movemouse(Client *c)
 59{
 60	XEvent ev;
 61	int x1, y1, ocx, ocy, di;
 62	unsigned int dui;
 63	Window dummy;
 64
 65	ocx = *c->x;
 66	ocy = *c->y;
 67	if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
 68				None, cursor[CurMove], CurrentTime) != GrabSuccess)
 69		return;
 70	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
 71	for(;;) {
 72		XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
 73		switch (ev.type) {
 74		default: break;
 75		case Expose:
 76			handler[Expose](&ev);
 77			break;
 78		case MotionNotify:
 79			XSync(dpy, False);
 80			*c->x = ocx + (ev.xmotion.x - x1);
 81			*c->y = ocy + (ev.xmotion.y - y1);
 82			resize(c, False);
 83			break;
 84		case ButtonRelease:
 85			XUngrabPointer(dpy, CurrentTime);
 86			return;
 87		}
 88	}
 89}
 90
 91static void
 92resizemouse(Client *c)
 93{
 94	XEvent ev;
 95	int ocx, ocy;
 96
 97	ocx = *c->x;
 98	ocy = *c->y;
 99	if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync,
100				None, cursor[CurResize], CurrentTime) != GrabSuccess)
101		return;
102	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, *c->w, *c->h);
103	for(;;) {
104		XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
105		switch(ev.type) {
106		default: break;
107		case Expose:
108			handler[Expose](&ev);
109			break;
110		case MotionNotify:
111			XSync(dpy, False);
112			*c->w = abs(ocx - ev.xmotion.x);
113			*c->h = abs(ocy - ev.xmotion.y);
114			*c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - *c->w;
115			*c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - *c->h;
116			resize(c, True);
117			break;
118		case ButtonRelease:
119			XUngrabPointer(dpy, CurrentTime);
120			return;
121		}
122	}
123}
124
125static void
126buttonpress(XEvent *e)
127{
128	int x;
129	Arg a;
130	XButtonPressedEvent *ev = &e->xbutton;
131	Client *c;
132
133	if(barwin == ev->window) {
134		switch(ev->button) {
135		default:
136			x = 0;
137			for(a.i = 0; a.i < TLast; a.i++) {
138				x += textw(tags[a.i]);
139				if(ev->x < x) {
140					view(&a);
141					break;
142				}
143			}
144			break;
145		case Button4:
146			a.i = (tsel + 1 < TLast) ? tsel + 1 : 0;
147			view(&a);
148			break;
149		case Button5:
150			a.i = (tsel - 1 >= 0) ? tsel - 1 : TLast - 1;
151			view(&a);
152			break;
153		}
154	}
155	else if((c = getclient(ev->window))) {
156		if(arrange == dotile && !c->isfloat) {
157			if((ev->state & ControlMask) && (ev->button == Button1))
158				zoom(NULL);
159			return;
160		}
161		/* floating windows */
162		higher(c);
163		switch(ev->button) {
164		default:
165			break;
166		case Button1:
167			movemouse(c);
168			break;
169		case Button2:
170			lower(c);
171			break;
172		case Button3:
173			resizemouse(c);
174			break;
175		}
176	}
177}
178
179static void
180configurerequest(XEvent *e)
181{
182	XConfigureRequestEvent *ev = &e->xconfigurerequest;
183	XWindowChanges wc;
184	Client *c;
185
186	ev->value_mask &= ~CWSibling;
187	if((c = getclient(ev->window))) {
188		gravitate(c, True);
189		if(ev->value_mask & CWX)
190			*c->x = ev->x;
191		if(ev->value_mask & CWY)
192			*c->y = ev->y;
193		if(ev->value_mask & CWWidth)
194			*c->w = ev->width;
195		if(ev->value_mask & CWHeight)
196			*c->h = ev->height;
197		if(ev->value_mask & CWBorderWidth)
198			c->border = 1;
199		gravitate(c, False);
200		resize(c, True);
201	}
202
203	wc.x = ev->x;
204	wc.y = ev->y;
205	wc.width = ev->width;
206	wc.height = ev->height;
207	wc.border_width = 1;
208	wc.sibling = None;
209	wc.stack_mode = Above;
210	ev->value_mask &= ~CWStackMode;
211	ev->value_mask |= CWBorderWidth;
212	XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
213	XSync(dpy, False);
214}
215
216static void
217destroynotify(XEvent *e)
218{
219	Client *c;
220	XDestroyWindowEvent *ev = &e->xdestroywindow;
221
222	if((c = getclient(ev->window)))
223		unmanage(c);
224}
225
226static void
227enternotify(XEvent *e)
228{
229	XCrossingEvent *ev = &e->xcrossing;
230	Client *c;
231
232	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
233		return;
234
235	if((c = getclient(ev->window)))
236		focus(c);
237	else if(ev->window == root)
238		issel = True;
239}
240
241static void
242expose(XEvent *e)
243{
244	XExposeEvent *ev = &e->xexpose;
245	Client *c;
246
247	if(ev->count == 0) {
248		if(barwin == ev->window)
249			drawstatus();
250		else if((c = getctitle(ev->window)))
251			drawtitle(c);
252	}
253}
254
255static void
256keypress(XEvent *e)
257{
258	XKeyEvent *ev = &e->xkey;
259	static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
260	unsigned int i;
261	KeySym keysym;
262
263	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
264	for(i = 0; i < len; i++)
265		if((keysym == key[i].keysym) && (key[i].mod == ev->state)) {
266			if(key[i].func)
267				key[i].func(&key[i].arg);
268			return;
269		}
270}
271
272static void
273leavenotify(XEvent *e)
274{
275	XCrossingEvent *ev = &e->xcrossing;
276
277	if((ev->window == root) && !ev->same_screen)
278		issel = True;
279}
280
281static void
282maprequest(XEvent *e)
283{
284	XMapRequestEvent *ev = &e->xmaprequest;
285	static XWindowAttributes wa;
286
287	if(!XGetWindowAttributes(dpy, ev->window, &wa))
288		return;
289
290	if(wa.override_redirect) {
291		XSelectInput(dpy, ev->window,
292				(StructureNotifyMask | PropertyChangeMask));
293		return;
294	}
295
296	if(!getclient(ev->window))
297		manage(ev->window, &wa);
298}
299
300static void
301propertynotify(XEvent *e)
302{
303	XPropertyEvent *ev = &e->xproperty;
304	Window trans;
305	Client *c;
306
307	if(ev->state == PropertyDelete)
308		return; /* ignore */
309
310	if((c = getclient(ev->window))) {
311		if(ev->atom == wmatom[WMProtocols]) {
312			c->proto = getproto(c->win);
313			return;
314		}
315		switch (ev->atom) {
316			default: break;
317			case XA_WM_TRANSIENT_FOR:
318				XGetTransientForHint(dpy, c->win, &trans);
319				if(!c->isfloat && (c->isfloat = (trans != 0)))
320					arrange(NULL);
321				break;
322			case XA_WM_NORMAL_HINTS:
323				setsize(c);
324				break;
325		}
326		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
327			settitle(c);
328			drawtitle(c);
329		}
330	}
331}
332
333static void
334unmapnotify(XEvent *e)
335{
336	Client *c;
337	XUnmapEvent *ev = &e->xunmap;
338
339	if((c = getclient(ev->window)))
340		unmanage(c);
341}
342
343/* extern */
344
345void (*handler[LASTEvent]) (XEvent *) = {
346	[ButtonPress] = buttonpress,
347	[ConfigureRequest] = configurerequest,
348	[DestroyNotify] = destroynotify,
349	[EnterNotify] = enternotify,
350	[LeaveNotify] = leavenotify,
351	[Expose] = expose,
352	[KeyPress] = keypress,
353	[MapRequest] = maprequest,
354	[PropertyNotify] = propertynotify,
355	[UnmapNotify] = unmapnotify
356};
357
358void
359grabkeys()
360{
361	static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0;
362	unsigned int i;
363	KeyCode code;
364
365	for(i = 0; i < len; i++) {
366		code = XKeysymToKeycode(dpy, key[i].keysym);
367		XUngrabKey(dpy, code, key[i].mod, root);
368		XGrabKey(dpy, code, key[i].mod, root, True,
369				GrabModeAsync, GrabModeAsync);
370	}
371}