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