1 /* Copyright ©2006-2010 Kris Maglione <fbsdaemon@gmail.com>
2  * See LICENSE file for license details.
3  */
4 #include "dat.h"
5 #include "fns.h"
6 
7 static void (*handler[LASTEvent])(XEvent*);
8 
9 void
dispatch_event(XEvent * e)10 dispatch_event(XEvent *e) {
11 	/* print("%E\n", e); */
12 	if(e->type < nelem(handler) && handler[e->type])
13 		handler[e->type](e);
14 }
15 
16 #define handle(w, fn, ev) \
17 	BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev))
18 
19 #ifdef notdef
20 uint
flushevents(long event_mask,bool dispatch)21 flushevents(long event_mask, bool dispatch) {
22 	XEvent ev;
23 	uint n = 0;
24 
25 	while(XCheckMaskEvent(display, event_mask, &ev)) {
26 		if(dispatch)
27 			dispatch_event(&ev);
28 		n++;
29 	}
30 	return n;
31 }
32 
33 static int
findenter(Display * d,XEvent * e,XPointer v)34 findenter(Display *d, XEvent *e, XPointer v) {
35 	long *l;
36 
37 	USED(d);
38 	l = (long*)v;
39 	if(*l)
40 		return false;
41 	if(e->type == EnterNotify)
42 		return true;
43 	if(e->type == MotionNotify)
44 		(*l)++;
45 	return false;
46 }
47 
48 /* This isn't perfect. If there were motion events in the queue
49  * before this was called, then it flushes nothing. If we don't
50  * check for them, we might lose a legitamate enter event.
51  */
52 uint
flushenterevents(void)53 flushenterevents(void) {
54 	XEvent e;
55 	long l;
56 	int n;
57 
58 	l = 0;
59 	n = 0;
60 	while(XCheckIfEvent(display, &e, findenter, (void*)&l))
61 		n++;
62 	return n;
63 }
64 #endif
65 
66 static int
findtime(Display * d,XEvent * e,XPointer v)67 findtime(Display *d, XEvent *e, XPointer v) {
68 	Window *w;
69 
70 	w = (Window*)v;
71 	if(e->type == PropertyNotify && e->xproperty.window == w->xid) {
72 		xtime = e->xproperty.time;
73 		return true;
74 	}
75 	return false;
76 }
77 
78 void
xtime_kludge(void)79 xtime_kludge(void) {
80 	Window *w;
81 	WinAttr wa;
82 	XEvent e;
83 	long l;
84 
85 	w = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, InputOnly, &wa, 0);
86 
87 	XSelectInput(display, w->xid, PropertyChangeMask);
88 	changeprop_long(w, "ATOM", "ATOM", &l, 0);
89 	XIfEvent(display, &e, findtime, (void*)w);
90 
91 	destroywindow(w);
92 }
93 
94 static void
buttonrelease(XEvent * e)95 buttonrelease(XEvent *e) {
96 	XButtonPressedEvent *ev;
97 	Window *w;
98 
99 	ev = &e->xbutton;
100 	if((w = findwin(ev->window)))
101 		handle(w, bup, ev);
102 }
103 
104 static void
buttonpress(XEvent * e)105 buttonpress(XEvent *e) {
106 	XButtonPressedEvent *ev;
107 	Window *w;
108 
109 	ev = &e->xbutton;
110 	if((w = findwin(ev->window)))
111 		handle(w, bdown, ev);
112 	else
113 		XAllowEvents(display, ReplayPointer, ev->time);
114 }
115 
116 static void
clientmessage(XEvent * e)117 clientmessage(XEvent *e) {
118 	XClientMessageEvent *ev;
119 
120 	ev = &e->xclient;
121 	USED(ev);
122 }
123 
124 static void
configurenotify(XEvent * e)125 configurenotify(XEvent *e) {
126 	XConfigureEvent *ev;
127 	Window *w;
128 
129 	ev = &e->xconfigure;
130 	if((w = findwin(ev->window)))
131 		handle(w, config, ev);
132 }
133 
134 static void
destroynotify(XEvent * e)135 destroynotify(XEvent *e) {
136 	XDestroyWindowEvent *ev;
137 	Window *w;
138 
139 	ev = &e->xdestroywindow;
140 	if((w = findwin(ev->window)))
141 		handle(w, destroy, ev);
142 }
143 
144 static void
enternotify(XEvent * e)145 enternotify(XEvent *e) {
146 	XCrossingEvent *ev;
147 	Window *w;
148 
149 	ev = &e->xcrossing;
150 	xtime = ev->time;
151 	if(ev->mode != NotifyNormal)
152 		return;
153 
154 	if((w = findwin(ev->window)))
155 		handle(w, enter, ev);
156 }
157 
158 static void
leavenotify(XEvent * e)159 leavenotify(XEvent *e) {
160 	XCrossingEvent *ev;
161 
162 	ev = &e->xcrossing;
163 	xtime = ev->time;
164 }
165 
166 static void
focusin(XEvent * e)167 focusin(XEvent *e) {
168 	XFocusChangeEvent *ev;
169 	Window *w;
170 
171 	ev = &e->xfocus;
172 	/* Yes, we're focusing in on nothing, here. */
173 	if(ev->detail == NotifyDetailNone) {
174 		/* FIXME: Do something. */
175 		return;
176 	}
177 
178 	if(!((ev->detail == NotifyNonlinear)
179 	   ||(ev->detail == NotifyNonlinearVirtual)
180 	   ||(ev->detail == NotifyVirtual)
181 	   ||(ev->detail == NotifyInferior)
182 	   ||(ev->detail == NotifyAncestor)))
183 		return;
184 	if((ev->mode == NotifyWhileGrabbed))
185 		return;
186 
187 	if((w = findwin(ev->window)))
188 		handle(w, focusin, ev);
189 }
190 
191 static void
focusout(XEvent * e)192 focusout(XEvent *e) {
193 	XFocusChangeEvent *ev;
194 	Window *w;
195 
196 	ev = &e->xfocus;
197 	if(!((ev->detail == NotifyNonlinear)
198 	   ||(ev->detail == NotifyNonlinearVirtual)
199 	   ||(ev->detail == NotifyVirtual)
200 	   ||(ev->detail == NotifyInferior)
201 	   ||(ev->detail == NotifyAncestor)))
202 		return;
203 
204 	if((w = findwin(ev->window)))
205 		handle(w, focusout, ev);
206 }
207 
208 static void
expose(XEvent * e)209 expose(XEvent *e) {
210 	XExposeEvent *ev;
211 	Window *w;
212 
213 	ev = &e->xexpose;
214 	if(ev->count == 0) {
215 		if((w = findwin(ev->window)))
216 			handle(w, expose, ev);
217 	}
218 }
219 
220 static void
keypress(XEvent * e)221 keypress(XEvent *e) {
222 	XKeyEvent *ev;
223 
224 	ev = &e->xkey;
225 	xtime = ev->time;
226 }
227 
228 static void
mappingnotify(XEvent * e)229 mappingnotify(XEvent *e) {
230 	XMappingEvent *ev;
231 
232 	ev = &e->xmapping;
233 	/* Why do you need me to tell you this? */
234 	XRefreshKeyboardMapping(ev);
235 }
236 
237 static void
motionnotify(XEvent * e)238 motionnotify(XEvent *e) {
239 	XMotionEvent *ev;
240 	Window *w;
241 
242 	ev = &e->xmotion;
243 	xtime = ev->time;
244 	if((w = findwin(ev->window)))
245 		handle(w, motion, ev);
246 }
247 
248 static void
propertynotify(XEvent * e)249 propertynotify(XEvent *e) {
250 	XPropertyEvent *ev;
251 	Window *w;
252 
253 	ev = &e->xproperty;
254 	xtime = ev->time;
255 	if((w = findwin(ev->window)))
256 		handle(w, property, ev);
257 }
258 
259 static void
mapnotify(XEvent * e)260 mapnotify(XEvent *e) {
261 	XMapEvent *ev;
262 	Window *w;
263 
264 	ev = &e->xmap;
265 	if((w = findwin(ev->window)))
266 		handle(w, map, ev);
267 }
268 
269 static void
unmapnotify(XEvent * e)270 unmapnotify(XEvent *e) {
271 	XUnmapEvent *ev;
272 	Window *w;
273 
274 	ev = &e->xunmap;
275 	if((w = findwin(ev->window)) && w->parent && (ev->event == w->parent->xid)) {
276 		if(ev->send_event || w->unmapped-- == 0)
277 			handle(w, unmap, ev);
278 	}
279 }
280 
281 static void (*handler[LASTEvent])(XEvent*) = {
282 	[ButtonPress] = buttonpress,
283 	[ButtonRelease] = buttonrelease,
284 	[ClientMessage] = clientmessage,
285 	[ConfigureNotify] = configurenotify,
286 	[DestroyNotify] = destroynotify,
287 	[EnterNotify] = enternotify,
288 	[Expose] = expose,
289 	[FocusIn] = focusin,
290 	[FocusOut] = focusout,
291 	[KeyPress] = keypress,
292 	[LeaveNotify] = leavenotify,
293 	[MapNotify] = mapnotify,
294 	[MappingNotify] = mappingnotify,
295 	[MotionNotify] = motionnotify,
296 	[PropertyNotify] = propertynotify,
297 	[UnmapNotify] = unmapnotify,
298 };
299 
300 void
xevent_loop(void)301 xevent_loop(void) {
302 	XEvent ev;
303 
304 	while(running) {
305 		XNextEvent(display, &ev);
306 		dispatch_event(&ev);
307 	}
308 }
309 
310