Consistency fixes
[notion.git] / ioncore / eventh.c
blobbcc6f4c0b82454f097fe4f6e88b7f99077f25129
1 /*
2 * ion/ioncore/eventh.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <sys/time.h>
13 #include <libtu/objp.h>
14 #include "common.h"
15 #include "global.h"
16 #include "rootwin.h"
17 #include "property.h"
18 #include "pointer.h"
19 #include "key.h"
20 #include "focus.h"
21 #include "selection.h"
22 #include "event.h"
23 #include "eventh.h"
24 #include "clientwin.h"
25 #include "colormap.h"
26 #include "grab.h"
27 #include "bindmaps.h"
28 #include "activity.h"
29 #include "netwm.h"
30 #include "xwindow.h"
31 #include "log.h"
34 /*{{{ ioncore_handle_event */
37 #define CASE_EVENT(EV) case EV: /*\
38 fprintf(stderr, "[%#lx] %s\n", ev->xany.window, #EV);*/
41 bool ioncore_handle_event(XEvent *ev)
44 switch(ev->type){
45 CASE_EVENT(MapRequest)
46 ioncore_handle_map_request(&(ev->xmaprequest));
47 break;
48 CASE_EVENT(ConfigureRequest)
49 ioncore_handle_configure_request(&(ev->xconfigurerequest));
50 break;
51 CASE_EVENT(UnmapNotify)
52 ioncore_handle_unmap_notify(&(ev->xunmap));
53 break;
54 CASE_EVENT(DestroyNotify)
55 ioncore_handle_destroy_notify(&(ev->xdestroywindow));
56 break;
57 CASE_EVENT(ClientMessage)
58 ioncore_handle_client_message(&(ev->xclient));
59 break;
60 CASE_EVENT(PropertyNotify)
61 ioncore_handle_property(&(ev->xproperty));
62 break;
63 CASE_EVENT(FocusIn)
64 ioncore_handle_focus_in(&(ev->xfocus));
65 break;
66 CASE_EVENT(FocusOut)
67 ioncore_handle_focus_out(&(ev->xfocus));
68 break;
69 CASE_EVENT(EnterNotify)
70 ioncore_handle_enter_window(ev);
71 break;
72 CASE_EVENT(Expose)
73 ioncore_handle_expose(&(ev->xexpose));
74 break;
75 CASE_EVENT(KeyPress)
76 ioncore_handle_keyboard(ev);
77 break;
78 CASE_EVENT(KeyRelease)
79 ioncore_handle_keyboard(ev);
80 break;
81 CASE_EVENT(ButtonPress)
82 ioncore_handle_buttonpress(ev);
83 break;
84 CASE_EVENT(ColormapNotify)
85 ioncore_handle_colormap_notify(&(ev->xcolormap));
86 break;
87 CASE_EVENT(MappingNotify)
88 ioncore_handle_mapping_notify(ev);
89 break;
90 CASE_EVENT(SelectionClear)
91 ioncore_clear_selection();
92 break;
93 CASE_EVENT(SelectionNotify)
94 ioncore_handle_selection(&(ev->xselection));
95 break;
96 CASE_EVENT(SelectionRequest)
97 ioncore_handle_selection_request(&(ev->xselectionrequest));
98 break;
99 default:
100 return FALSE;
103 return TRUE;
107 /*}}}*/
110 /*{{{ Map, unmap, destroy */
113 void ioncore_handle_map_request(const XMapRequestEvent *ev)
115 WRegion *reg;
117 reg=XWINDOW_REGION_OF(ev->window);
119 if(reg!=NULL)
120 return;
122 ioncore_manage_clientwin(ev->window, TRUE);
126 void ioncore_handle_unmap_notify(const XUnmapEvent *ev)
128 WClientWin *cwin;
130 /* We are not interested in SubstructureNotify -unmaps. */
131 if(ev->event!=ev->window && ev->send_event!=True)
132 return;
134 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
136 if(cwin!=NULL)
137 clientwin_unmapped(cwin);
141 void ioncore_handle_destroy_notify(const XDestroyWindowEvent *ev)
143 WClientWin *cwin;
145 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
147 if(cwin!=NULL)
148 clientwin_destroyed(cwin);
152 /*}}}*/
155 /*{{{ Client configure/property/message */
157 void ioncore_handle_configure_request(XConfigureRequestEvent *ev)
159 WClientWin *cwin;
160 XWindowChanges wc;
162 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
164 if(cwin==NULL){
165 wc.border_width=ev->border_width;
166 wc.sibling=ev->above;
167 wc.stack_mode=ev->detail;
168 wc.x=ev->x;
169 wc.y=ev->y;
170 wc.width=ev->width;
171 wc.height=ev->height;
172 XConfigureWindow(ioncore_g.dpy, ev->window, ev->value_mask, &wc);
173 return;
176 clientwin_handle_configure_request(cwin, ev);
180 void ioncore_handle_client_message(const XClientMessageEvent *ev)
182 netwm_handle_client_message(ev);
184 #if 0
185 WClientWin *cwin;
187 if(ev->message_type!=ioncore_g.atom_wm_change_state)
188 return;
190 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
192 if(cwin==NULL)
193 return;
195 if(ev->format==32 && ev->data.l[0]==IconicState){
196 if(cwin->state==NormalState)
197 iconify_clientwin(cwin);
199 #endif
203 static bool pchg_mrsh_extl(ExtlFn fn, void **p)
205 extl_call(fn, "oi", NULL, p[0], ((XPropertyEvent*)p[1])->atom);
206 return TRUE;
209 static bool pchg_mrsh(void (*fn)(void *p1, void *p2), void **p)
211 fn(p[0], p[1]);
212 return TRUE;
216 void ioncore_handle_property(const XPropertyEvent *ev)
218 WClientWin *cwin;
220 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
222 if(cwin==NULL)
223 return;
225 if(ev->atom==XA_WM_HINTS){
226 XWMHints *hints;
227 hints=XGetWMHints(ioncore_g.dpy, ev->window);
228 /* region_notify/clear_activity take care of checking current state */
229 if(hints!=NULL){
230 if(hints->flags&XUrgencyHint){
231 if(!region_skip_focus((WRegion*)cwin))
232 region_set_activity((WRegion*)cwin, SETPARAM_SET);
233 }else{
234 region_set_activity((WRegion*)cwin, SETPARAM_UNSET);
237 XFree(hints);
238 }else if(ev->atom==XA_WM_NORMAL_HINTS){
239 if(ev->state==PropertyNewValue){
240 if(clientwin_get_size_hints(cwin)<0)
241 LOG(WARN, GENERAL, "Retrieving sizehints failed for cwin '%s'", cwin->region.ni.name);
242 }else if(ev->state==PropertyDelete)
243 clientwin_reset_size_hints(cwin);
244 }else if(ev->atom==XA_WM_NAME){
245 if(!(cwin->flags&CLIENTWIN_USE_NET_WM_NAME))
246 clientwin_get_set_name(cwin);
247 }else if(ev->atom==XA_WM_TRANSIENT_FOR){
248 clientwin_tfor_changed(cwin);
249 }else if(ev->atom==ioncore_g.atom_wm_protocols){
250 clientwin_get_protocols(cwin);
251 }else{
252 netwm_handle_property(cwin, ev);
255 /* Call property hook */
257 void *p[2];
258 p[0]=(void*)cwin;
259 p[1]=(void*)ev;
260 hook_call(clientwin_property_change_hook, p,
261 (WHookMarshall*)pchg_mrsh,
262 (WHookMarshallExtl*)pchg_mrsh_extl);
267 /*}}}*/
270 /*{{{ Misc. notifies */
273 void ioncore_handle_mapping_notify(XEvent *ev)
276 XRefreshKeyboardMapping(&(ev->xmapping));
277 }while(XCheckTypedEvent(ioncore_g.dpy, MappingNotify, ev));
279 ioncore_refresh_bindmaps();
283 /*}}}*/
286 /*{{{ Expose */
289 void ioncore_handle_expose(const XExposeEvent *ev)
291 WWindow *wwin;
292 XEvent tmp;
294 while(XCheckWindowEvent(ioncore_g.dpy, ev->window, ExposureMask, &tmp))
295 /* nothing */;
297 wwin=XWINDOW_REGION_OF_T(ev->window, WWindow);
299 if(wwin!=NULL)
300 window_draw(wwin, FALSE);
304 /*}}}*/
307 /*{{{ Enter window, focus */
310 void ioncore_handle_enter_window(XEvent *ev)
312 XEnterWindowEvent *eev=&(ev->xcrossing);
313 WRegion *reg=NULL;
315 if(ioncore_g.input_mode!=IONCORE_INPUTMODE_NORMAL ||
316 ioncore_g.no_mousefocus){
317 return;
320 if(eev->mode!=NotifyNormal && !ioncore_g.warp_enabled)
321 return;
323 reg=XWINDOW_REGION_OF_T(eev->window, WRegion);
325 if(reg==NULL)
326 return;
328 if(REGION_IS_ACTIVE(reg))
329 return;
331 if(region_skip_focus(reg))
332 return;
334 if(ioncore_g.focus_next!=NULL &&
335 ioncore_g.focus_next_source<IONCORE_FOCUSNEXT_ENTERWINDOW){
336 return;
339 /* If a child of 'reg' is to be focused, do not process this
340 * event. (ioncore_g.focus_next should only be set here by
341 * another call to use from ioncore_handle_enter_window below.)
343 if(ioncore_g.focus_next!=NULL){
344 WRegion *r2=ioncore_g.focus_next;
345 while(r2!=NULL){
346 if(r2==reg)
347 return;
348 r2=REGION_PARENT_REG(r2);
352 if(region_goto_flags(reg, (REGION_GOTO_FOCUS|
353 REGION_GOTO_NOWARP|
354 REGION_GOTO_ENTERWINDOW))){
355 ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_ENTERWINDOW;
360 static bool pointer_in_root(Window root1)
362 Window root2=None, win;
363 int x, y, wx, wy;
364 uint mask;
366 XQueryPointer(ioncore_g.dpy, root1, &root2, &win,
367 &x, &y, &wx, &wy, &mask);
369 return (root1==root2);
373 void ioncore_handle_focus_in(const XFocusChangeEvent *ev)
375 WRegion *reg;
376 WWindow *wwin;
378 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
380 if(reg==NULL)
381 return;
383 D(fprintf(stderr, "FI: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
385 if(ev->mode==NotifyGrab)
386 return;
388 if(ev->detail==NotifyPointer)
389 return;
391 /* Input contexts */
392 if(OBJ_IS(reg, WWindow)){
393 wwin=(WWindow*)reg;
394 if(wwin->xic!=NULL)
395 XSetICFocus(wwin->xic);
398 if(ev->detail!=NotifyInferior)
399 netwm_set_active(reg);
401 region_got_focus(reg);
403 if(ioncore_g.focus_next!=NULL &&
404 ioncore_g.focus_next_source<IONCORE_FOCUSNEXT_FALLBACK){
405 return;
408 if((ev->detail==NotifyPointerRoot || ev->detail==NotifyDetailNone)
409 && ev->window==region_root_of(reg) /* OBJ_IS(reg, WRootWin) */){
410 /* Restore focus if it was returned to a root window and we don't
411 * know of a pending focus change.
413 if(pointer_in_root(ev->window)){
414 region_set_focus(reg);
415 ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_FALLBACK;
417 }else{
418 /* Something got the focus, don't use fallback. */
419 ioncore_g.focus_next=NULL;
424 void ioncore_handle_focus_out(const XFocusChangeEvent *ev)
426 WRegion *reg;
427 WWindow *wwin;
429 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
431 if(reg==NULL)
432 return;
434 D(fprintf(stderr, "FO: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
436 if(ev->mode==NotifyGrab)
437 return;
439 if(ev->detail==NotifyPointer)
440 return;
442 D(if(OBJ_IS(reg, WRootWin))
443 fprintf(stderr, "scr-out %d %d %d\n", ((WRootWin*)reg)->xscr, ev->mode, ev->detail));
445 if(OBJ_IS(reg, WWindow)){
446 wwin=(WWindow*)reg;
447 if(wwin->xic!=NULL)
448 XUnsetICFocus(wwin->xic);
451 if(ev->detail!=NotifyInferior)
452 region_lost_focus(reg);
453 else
454 region_got_focus(reg);
458 /*}}}*/
461 /*{{{ Pointer, keyboard */
464 void ioncore_handle_buttonpress(XEvent *ev)
466 XEvent tmp;
467 bool finished=FALSE;
469 if(ioncore_grab_held())
470 return;
472 if(!ioncore_do_handle_buttonpress(&(ev->xbutton)))
473 return;
475 while(!finished && ioncore_grab_held()){
476 XFlush(ioncore_g.dpy);
477 ioncore_get_event(ev, IONCORE_EVENTMASK_PTRLOOP);
479 if(ev->type==MotionNotify){
480 /* Handle sequences of MotionNotify (possibly followed by button
481 * release) as one.
483 if(XPeekEvent(ioncore_g.dpy, &tmp)){
484 if(tmp.type==MotionNotify || tmp.type==ButtonRelease)
485 XNextEvent(ioncore_g.dpy, ev);
489 switch(ev->type){
490 CASE_EVENT(ButtonRelease)
491 if(ioncore_do_handle_buttonrelease(&ev->xbutton))
492 finished=TRUE;
493 break;
494 CASE_EVENT(MotionNotify)
495 ioncore_do_handle_motionnotify(&ev->xmotion);
496 break;
497 CASE_EVENT(Expose)
498 ioncore_handle_expose(&(ev->xexpose));
499 break;
500 CASE_EVENT(KeyPress)
501 CASE_EVENT(KeyRelease)
502 ioncore_handle_grabs(ev);
503 break;
504 CASE_EVENT(FocusIn)
505 ioncore_handle_focus_in(&(ev->xfocus));
506 break;
507 CASE_EVENT(FocusOut)
508 ioncore_handle_focus_out(&(ev->xfocus));
509 break;
515 void ioncore_handle_keyboard(XEvent *ev)
517 if(ioncore_handle_grabs(ev))
518 return;
520 if(ev->type==KeyPress)
521 ioncore_do_handle_keypress(&(ev->xkey));
525 /*}}}*/