all repos — dwm @ e7438365417ba4bb0cff56b44b029c797be18fe5

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