all repos — dwm @ dba23062bad40afb1a90f60b6897cf9e1ca5035b

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