1 /* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
2  * See LICENSE file for license details.
3  */
4 #include "dat.h"
5 #include <X11/keysym.h>
6 #include "fns.h"
7 
8 long	ignoreenter;
9 
10 typedef void (*EvHandler)(XEvent*);
11 
12 void
dispatch_event(XEvent * e)13 dispatch_event(XEvent *e) {
14 	Dprint(DEvent, "%E\n", e);
15 	if(e->type < nelem(handler)) {
16 		if(handler[e->type])
17 			handler[e->type](e);
18 	}else
19 		xext_event(e);
20 }
21 
22 #define handle(w, fn, ev) \
23 	BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev))
24 
25 static int
findtime(Display * d,XEvent * e,XPointer v)26 findtime(Display *d, XEvent *e, XPointer v) {
27 	Window *w;
28 
29 	w = (Window*)v;
30 	if(e->type == PropertyNotify && e->xproperty.window == w->xid) {
31 		xtime = e->xproperty.time;
32 		return true;
33 	}
34 	return false;
35 }
36 
37 void
xtime_kludge(void)38 xtime_kludge(void) {
39 	/* Round trip. */
40 	static Window *w;
41 	WinAttr wa;
42 	XEvent e;
43 	long l;
44 
45 	if(w == nil) {
46 		w = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, InputOnly, &wa, 0);
47 		selectinput(w, PropertyChangeMask);
48 	}
49 	changeprop_long(w, "ATOM", "ATOM", &l, 0);
50 	sync();
51 	XIfEvent(display, &e, findtime, (void*)w);
52 }
53 
54 uint
flushevents(long event_mask,bool dispatch)55 flushevents(long event_mask, bool dispatch) {
56 	XEvent ev;
57 	uint n = 0;
58 
59 	while(XCheckMaskEvent(display, event_mask, &ev)) {
60 		if(dispatch)
61 			dispatch_event(&ev);
62 		n++;
63 	}
64 	return n;
65 }
66 
67 static Bool
findenter(Display * d,XEvent * e,XPointer v)68 findenter(Display *d, XEvent *e, XPointer v) {
69 	long *l;
70 
71 	USED(d);
72 	l = (long*)v;
73 	if(*l)
74 		return false;
75 	if(e->type == EnterNotify)
76 		return true;
77 	if(e->type == MotionNotify)
78 		(*l)++;
79 	return false;
80 }
81 
82 /* This isn't perfect. If there were motion events in the queue
83  * before this was called, then it flushes nothing. If we don't
84  * check for them, we might lose a legitamate enter event.
85  */
86 uint
flushenterevents(void)87 flushenterevents(void) {
88 	XEvent e;
89 	long l;
90 	int n;
91 
92 	l = 0;
93 	n = 0;
94 	while(XCheckIfEvent(display, &e, findenter, (void*)&l))
95 		n++;
96 	return n;
97 }
98 
99 static void
buttonrelease(XButtonPressedEvent * ev)100 buttonrelease(XButtonPressedEvent *ev) {
101 	Window *w;
102 
103 	if((w = findwin(ev->window)))
104 		handle(w, bup, ev);
105 }
106 
107 static void
buttonpress(XButtonPressedEvent * ev)108 buttonpress(XButtonPressedEvent *ev) {
109 	Window *w;
110 
111 	if((w = findwin(ev->window)))
112 		handle(w, bdown, ev);
113 	else
114 		XAllowEvents(display, ReplayPointer, ev->time);
115 }
116 
117 static void
configurerequest(XConfigureRequestEvent * ev)118 configurerequest(XConfigureRequestEvent *ev) {
119 	XWindowChanges wc;
120 	Window *w;
121 
122 	if((w = findwin(ev->window)))
123 		handle(w, configreq, ev);
124 	else{
125 		wc.x = ev->x;
126 		wc.y = ev->y;
127 		wc.width = ev->width;
128 		wc.height = ev->height;
129 		wc.border_width = ev->border_width;
130 		wc.sibling = ev->above;
131 		wc.stack_mode = ev->detail;
132 		XConfigureWindow(display, ev->window, ev->value_mask, &wc);
133 	}
134 }
135 
136 static void
configurenotify(XConfigureEvent * ev)137 configurenotify(XConfigureEvent *ev) {
138 	Window *w;
139 
140 	ignoreenter = ev->serial;
141 	if((w = findwin(ev->window)))
142 		handle(w, config, ev);
143 }
144 
145 static void
clientmessage(XClientMessageEvent * ev)146 clientmessage(XClientMessageEvent *ev) {
147 
148 	if(ewmh_clientmessage(ev))
149 		return;
150 	if(xdnd_clientmessage(ev))
151 		return;
152 }
153 
154 static void
destroynotify(XDestroyWindowEvent * ev)155 destroynotify(XDestroyWindowEvent *ev) {
156 	Window *w;
157 	Client *c;
158 
159 	if((w = findwin(ev->window)))
160 		handle(w, destroy, ev);
161 	else {
162 		if((c = win2client(ev->window)))
163 			fprint(2, "Badness: Unhandled DestroyNotify: "
164 				  "Client: %p, Window: %W, Name: %s\n",
165 				  c, &c->w, c->name);
166 	}
167 }
168 
169 static void
enternotify(XCrossingEvent * ev)170 enternotify(XCrossingEvent *ev) {
171 	Window *w;
172 
173 	xtime = ev->time;
174 	if(ev->mode != NotifyNormal)
175 		return;
176 
177 	if((w = findwin(ev->window)))
178 		handle(w, enter, ev);
179 }
180 
181 static void
leavenotify(XCrossingEvent * ev)182 leavenotify(XCrossingEvent *ev) {
183 	Window *w;
184 
185 	xtime = ev->time;
186 	if((w = findwin(ev->window)))
187 		handle(w, leave, ev);
188 }
189 
190 void
print_focus(const char * fn,Client * c,const char * to)191 print_focus(const char *fn, Client *c, const char *to) {
192 	Dprint(DFocus, "%s() disp.focus:\n", fn);
193 	Dprint(DFocus, "\t%C => %C\n", disp.focus, c);
194 	Dprint(DFocus, "\t%s => %s\n", clientname(disp.focus), to);
195 }
196 
197 static void
focusin(XFocusChangeEvent * ev)198 focusin(XFocusChangeEvent *ev) {
199 	Window *w;
200 	Client *c;
201 
202 	/* Yes, we're focusing in on nothing, here. */
203 	if(ev->detail == NotifyDetailNone) {
204 		print_focus("focusin", &c_magic, "<magic[none]>");
205 		disp.focus = &c_magic;
206 		setfocus(screen->barwin, RevertToParent);
207 		return;
208 	}
209 
210 	if(!((ev->detail == NotifyNonlinear)
211 	   ||(ev->detail == NotifyNonlinearVirtual)
212 	   ||(ev->detail == NotifyVirtual)
213 	   ||(ev->detail == NotifyInferior)
214 	   ||(ev->detail == NotifyAncestor)))
215 		return;
216 	if((ev->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root))
217 		return;
218 
219 	if(ev->window == screen->barwin->xid) {
220 		print_focus("focusin", nil, "<nil>");
221 		disp.focus = nil;
222 	}
223 	else if((w = findwin(ev->window)))
224 		handle(w, focusin, ev);
225 	else if(ev->mode == NotifyGrab) {
226 		/* Some unmanaged window has grabbed focus */
227 		if((c = disp.focus)) {
228 			print_focus("focusin", &c_magic, "<magic>");
229 			disp.focus = &c_magic;
230 			if(c->sel)
231 				frame_draw(c->sel);
232 		}
233 	}
234 }
235 
236 static void
focusout(XFocusChangeEvent * ev)237 focusout(XFocusChangeEvent *ev) {
238 	XEvent me;
239 	Window *w;
240 
241 	if(!((ev->detail == NotifyNonlinear)
242 	   ||(ev->detail == NotifyNonlinearVirtual)
243 	   ||(ev->detail == NotifyVirtual)
244 	   ||(ev->detail == NotifyInferior)
245 	   ||(ev->detail == NotifyAncestor)))
246 		return;
247 	if(ev->mode == NotifyUngrab)
248 		disp.hasgrab = nil;
249 
250 	if((ev->mode == NotifyGrab)
251 	&& XCheckMaskEvent(display, KeyPressMask, &me))
252 		dispatch_event(&me);
253 	else if((w = findwin(ev->window)))
254 		handle(w, focusout, ev);
255 }
256 
257 static void
expose(XExposeEvent * ev)258 expose(XExposeEvent *ev) {
259 	Window *w;
260 
261 	if(ev->count == 0)
262 		if((w = findwin(ev->window)))
263 			handle(w, expose, ev);
264 }
265 
266 static void
keypress(XKeyEvent * ev)267 keypress(XKeyEvent *ev) {
268 	Window *w;
269 
270 	xtime = ev->time;
271 	if((w = findwin(ev->window)))
272 		handle(w, kdown, ev);
273 }
274 
275 static void
mappingnotify(XMappingEvent * ev)276 mappingnotify(XMappingEvent *ev) {
277 
278 	XRefreshKeyboardMapping(ev);
279 	if(ev->request == MappingKeyboard)
280 		update_keys();
281 }
282 
283 static void
maprequest(XMapRequestEvent * ev)284 maprequest(XMapRequestEvent *ev) {
285 	Window *w;
286 
287 	if((w = findwin(ev->parent)))
288 		handle(w, mapreq, ev);
289 }
290 
291 static void
motionnotify(XMotionEvent * ev)292 motionnotify(XMotionEvent *ev) {
293 	Window *w;
294 
295 	xtime = ev->time;
296 	if((w = findwin(ev->window)))
297 		handle(w, motion, ev);
298 }
299 
300 static void
propertynotify(XPropertyEvent * ev)301 propertynotify(XPropertyEvent *ev) {
302 	Window *w;
303 
304 	xtime = ev->time;
305 	if((w = findwin(ev->window)))
306 		handle(w, property, ev);
307 }
308 
309 static void
mapnotify(XMapEvent * ev)310 mapnotify(XMapEvent *ev) {
311 	Window *w;
312 
313 	ignoreenter = ev->serial;
314 	if((w = findwin(ev->window)))
315 		handle(w, map, ev);
316 }
317 
318 static void
unmapnotify(XUnmapEvent * ev)319 unmapnotify(XUnmapEvent *ev) {
320 	Window *w;
321 
322 	ignoreenter = ev->serial;
323 	if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) {
324 		w->mapped = false;
325 		if(ev->send_event || w->unmapped-- == 0)
326 			handle(w, unmap, ev);
327 	}
328 }
329 
330 EvHandler handler[LASTEvent] = {
331 	[ButtonPress] =		(EvHandler)buttonpress,
332 	[ButtonRelease] =	(EvHandler)buttonrelease,
333 	[ConfigureRequest] =	(EvHandler)configurerequest,
334 	[ConfigureNotify] =	(EvHandler)configurenotify,
335 	[ClientMessage] =	(EvHandler)clientmessage,
336 	[DestroyNotify] =	(EvHandler)destroynotify,
337 	[EnterNotify] =		(EvHandler)enternotify,
338 	[Expose] =		(EvHandler)expose,
339 	[FocusIn] =		(EvHandler)focusin,
340 	[FocusOut] =		(EvHandler)focusout,
341 	[KeyPress] =		(EvHandler)keypress,
342 	[LeaveNotify] =		(EvHandler)leavenotify,
343 	[MapNotify] =		(EvHandler)mapnotify,
344 	[MapRequest] =		(EvHandler)maprequest,
345 	[MappingNotify] =	(EvHandler)mappingnotify,
346 	[MotionNotify] =	(EvHandler)motionnotify,
347 	[PropertyNotify] =	(EvHandler)propertynotify,
348 	[UnmapNotify] =		(EvHandler)unmapnotify,
349 };
350 
351 void
check_x_event(IxpConn * c)352 check_x_event(IxpConn *c) {
353 	XEvent ev;
354 
355 	USED(c);
356 	while(XPending(display)) {
357 		XNextEvent(display, &ev);
358 		dispatch_event(&ev);
359 	}
360 }
361 
362