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