all repos — dwm @ adaa28a6e600f636f5e86244ccef69e98419ba1a

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