all repos — dwm @ 04eb016e782743ec88f150ec6f5389703bed3ce2

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