all repos — dwm @ 1e7e57dad3e3ac750421795f60867f65b4ff0f67

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