Manpage formatting
[notion.git] / ioncore / eventh.c
blob3023417b9bd103b59c04428eeb3757229ab2e104
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"
33 /*{{{ ioncore_handle_event */
36 #define CASE_EVENT(EV) case EV: /*\
37 fprintf(stderr, "[%#lx] %s\n", ev->xany.window, #EV);*/
40 bool ioncore_handle_event(XEvent *ev)
43 switch(ev->type){
44 CASE_EVENT(MapRequest)
45 ioncore_handle_map_request(&(ev->xmaprequest));
46 break;
47 CASE_EVENT(ConfigureRequest)
48 ioncore_handle_configure_request(&(ev->xconfigurerequest));
49 break;
50 CASE_EVENT(UnmapNotify)
51 ioncore_handle_unmap_notify(&(ev->xunmap));
52 break;
53 CASE_EVENT(DestroyNotify)
54 ioncore_handle_destroy_notify(&(ev->xdestroywindow));
55 break;
56 CASE_EVENT(ClientMessage)
57 ioncore_handle_client_message(&(ev->xclient));
58 break;
59 CASE_EVENT(PropertyNotify)
60 ioncore_handle_property(&(ev->xproperty));
61 break;
62 CASE_EVENT(FocusIn)
63 ioncore_handle_focus_in(&(ev->xfocus));
64 break;
65 CASE_EVENT(FocusOut)
66 ioncore_handle_focus_out(&(ev->xfocus));
67 break;
68 CASE_EVENT(EnterNotify)
69 ioncore_handle_enter_window(ev);
70 break;
71 CASE_EVENT(Expose)
72 ioncore_handle_expose(&(ev->xexpose));
73 break;
74 CASE_EVENT(KeyPress)
75 ioncore_handle_keyboard(ev);
76 break;
77 CASE_EVENT(KeyRelease)
78 ioncore_handle_keyboard(ev);
79 break;
80 CASE_EVENT(ButtonPress)
81 ioncore_handle_buttonpress(ev);
82 break;
83 CASE_EVENT(ColormapNotify)
84 ioncore_handle_colormap_notify(&(ev->xcolormap));
85 break;
86 CASE_EVENT(MappingNotify)
87 ioncore_handle_mapping_notify(ev);
88 break;
89 CASE_EVENT(SelectionClear)
90 ioncore_clear_selection();
91 break;
92 CASE_EVENT(SelectionNotify)
93 ioncore_handle_selection(&(ev->xselection));
94 break;
95 CASE_EVENT(SelectionRequest)
96 ioncore_handle_selection_request(&(ev->xselectionrequest));
97 break;
98 default:
99 return FALSE;
102 return TRUE;
106 /*}}}*/
109 /*{{{ Map, unmap, destroy */
112 void ioncore_handle_map_request(const XMapRequestEvent *ev)
114 WRegion *reg;
116 reg=XWINDOW_REGION_OF(ev->window);
118 if(reg!=NULL)
119 return;
121 ioncore_manage_clientwin(ev->window, TRUE);
125 void ioncore_handle_unmap_notify(const XUnmapEvent *ev)
127 WClientWin *cwin;
129 /* We are not interested in SubstructureNotify -unmaps. */
130 if(ev->event!=ev->window && ev->send_event!=True)
131 return;
133 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
135 if(cwin!=NULL)
136 clientwin_unmapped(cwin);
140 void ioncore_handle_destroy_notify(const XDestroyWindowEvent *ev)
142 WClientWin *cwin;
144 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
146 if(cwin!=NULL)
147 clientwin_destroyed(cwin);
151 /*}}}*/
154 /*{{{ Client configure/property/message */
156 void ioncore_handle_configure_request(XConfigureRequestEvent *ev)
158 WClientWin *cwin;
159 XWindowChanges wc;
161 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
163 if(cwin==NULL){
164 wc.border_width=ev->border_width;
165 wc.sibling=ev->above;
166 wc.stack_mode=ev->detail;
167 wc.x=ev->x;
168 wc.y=ev->y;
169 wc.width=ev->width;
170 wc.height=ev->height;
171 XConfigureWindow(ioncore_g.dpy, ev->window, ev->value_mask, &wc);
172 return;
175 clientwin_handle_configure_request(cwin, ev);
179 void ioncore_handle_client_message(const XClientMessageEvent *ev)
181 netwm_handle_client_message(ev);
183 #if 0
184 WClientWin *cwin;
186 if(ev->message_type!=ioncore_g.atom_wm_change_state)
187 return;
189 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
191 if(cwin==NULL)
192 return;
194 if(ev->format==32 && ev->data.l[0]==IconicState){
195 if(cwin->state==NormalState)
196 iconify_clientwin(cwin);
198 #endif
202 static bool pchg_mrsh_extl(ExtlFn fn, void **p)
204 extl_call(fn, "oi", NULL, p[0], ((XPropertyEvent*)p[1])->atom);
205 return TRUE;
208 static bool pchg_mrsh(void (*fn)(void *p1, void *p2), void **p)
210 fn(p[0], p[1]);
211 return TRUE;
215 void ioncore_handle_property(const XPropertyEvent *ev)
217 WClientWin *cwin;
219 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
221 if(cwin==NULL)
222 return;
224 if(ev->atom==XA_WM_HINTS){
225 XWMHints *hints;
226 hints=XGetWMHints(ioncore_g.dpy, ev->window);
227 /* region_notify/clear_activity take care of checking current state */
228 if(hints!=NULL){
229 if(hints->flags&XUrgencyHint){
230 if(!region_skip_focus((WRegion*)cwin))
231 region_set_activity((WRegion*)cwin, SETPARAM_SET);
232 }else{
233 region_set_activity((WRegion*)cwin, SETPARAM_UNSET);
236 XFree(hints);
237 }else if(ev->atom==XA_WM_NORMAL_HINTS){
238 clientwin_get_size_hints(cwin);
239 }else if(ev->atom==XA_WM_NAME){
240 if(!(cwin->flags&CLIENTWIN_USE_NET_WM_NAME))
241 clientwin_get_set_name(cwin);
242 }else if(ev->atom==XA_WM_TRANSIENT_FOR){
243 clientwin_tfor_changed(cwin);
244 }else if(ev->atom==ioncore_g.atom_wm_protocols){
245 clientwin_get_protocols(cwin);
246 }else{
247 netwm_handle_property(cwin, ev);
250 /* Call property hook */
252 void *p[2];
253 p[0]=(void*)cwin;
254 p[1]=(void*)ev;
255 hook_call(clientwin_property_change_hook, p,
256 (WHookMarshall*)pchg_mrsh,
257 (WHookMarshallExtl*)pchg_mrsh_extl);
262 /*}}}*/
265 /*{{{ Misc. notifies */
268 void ioncore_handle_mapping_notify(XEvent *ev)
271 XRefreshKeyboardMapping(&(ev->xmapping));
272 }while(XCheckTypedEvent(ioncore_g.dpy, MappingNotify, ev));
274 ioncore_refresh_bindmaps();
278 /*}}}*/
281 /*{{{ Expose */
284 void ioncore_handle_expose(const XExposeEvent *ev)
286 WWindow *wwin;
287 WRootWin *rootwin;
288 XEvent tmp;
290 while(XCheckWindowEvent(ioncore_g.dpy, ev->window, ExposureMask, &tmp))
291 /* nothing */;
293 wwin=XWINDOW_REGION_OF_T(ev->window, WWindow);
295 if(wwin!=NULL)
296 window_draw(wwin, FALSE);
300 /*}}}*/
303 /*{{{ Enter window, focus */
306 void ioncore_handle_enter_window(XEvent *ev)
308 XEnterWindowEvent *eev=&(ev->xcrossing);
309 WRegion *reg=NULL;
311 if(ioncore_g.input_mode!=IONCORE_INPUTMODE_NORMAL ||
312 ioncore_g.no_mousefocus){
313 return;
316 if(eev->mode!=NotifyNormal && !ioncore_g.warp_enabled)
317 return;
319 reg=XWINDOW_REGION_OF_T(eev->window, WRegion);
321 if(reg==NULL)
322 return;
324 if(REGION_IS_ACTIVE(reg))
325 return;
327 if(region_skip_focus(reg))
328 return;
330 if(ioncore_g.focus_next!=NULL &&
331 ioncore_g.focus_next_source<IONCORE_FOCUSNEXT_ENTERWINDOW){
332 return;
335 /* If a child of 'reg' is to be focused, do not process this
336 * event. (ioncore_g.focus_next should only be set here by
337 * another call to use from ioncore_handle_enter_window below.)
339 if(ioncore_g.focus_next!=NULL){
340 WRegion *r2=ioncore_g.focus_next;
341 while(r2!=NULL){
342 if(r2==reg)
343 return;
344 r2=REGION_PARENT_REG(r2);
348 if(region_goto_flags(reg, (REGION_GOTO_FOCUS|
349 REGION_GOTO_NOWARP|
350 REGION_GOTO_ENTERWINDOW))){
351 ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_ENTERWINDOW;
356 static bool pointer_in_root(Window root1)
358 Window root2=None, win;
359 int x, y, wx, wy;
360 uint mask;
362 XQueryPointer(ioncore_g.dpy, root1, &root2, &win,
363 &x, &y, &wx, &wy, &mask);
365 return (root1==root2);
369 void ioncore_handle_focus_in(const XFocusChangeEvent *ev)
371 WRegion *reg;
372 WWindow *wwin;
374 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
376 if(reg==NULL)
377 return;
379 D(fprintf(stderr, "FI: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
381 if(ev->mode==NotifyGrab)
382 return;
384 if(ev->detail==NotifyPointer)
385 return;
387 /* Input contexts */
388 if(OBJ_IS(reg, WWindow)){
389 wwin=(WWindow*)reg;
390 if(wwin->xic!=NULL)
391 XSetICFocus(wwin->xic);
394 if(ev->detail!=NotifyInferior)
395 netwm_set_active(reg);
397 region_got_focus(reg);
399 if(ioncore_g.focus_next!=NULL &&
400 ioncore_g.focus_next_source<IONCORE_FOCUSNEXT_FALLBACK){
401 return;
404 if((ev->detail==NotifyPointerRoot || ev->detail==NotifyDetailNone)
405 && ev->window==region_root_of(reg) /* OBJ_IS(reg, WRootWin) */){
406 /* Restore focus if it was returned to a root window and we don't
407 * know of a pending focus change.
409 if(pointer_in_root(ev->window)){
410 region_set_focus(reg);
411 ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_FALLBACK;
413 }else{
414 /* Something got the focus, don't use fallback. */
415 ioncore_g.focus_next=NULL;
420 void ioncore_handle_focus_out(const XFocusChangeEvent *ev)
422 WRegion *reg;
423 WWindow *wwin;
425 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
427 if(reg==NULL)
428 return;
430 D(fprintf(stderr, "FO: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
432 if(ev->mode==NotifyGrab)
433 return;
435 if(ev->detail==NotifyPointer)
436 return;
438 D(if(OBJ_IS(reg, WRootWin))
439 fprintf(stderr, "scr-out %d %d %d\n", ((WRootWin*)reg)->xscr, ev->mode, ev->detail));
441 if(OBJ_IS(reg, WWindow)){
442 wwin=(WWindow*)reg;
443 if(wwin->xic!=NULL)
444 XUnsetICFocus(wwin->xic);
447 if(ev->detail!=NotifyInferior)
448 region_lost_focus(reg);
449 else
450 region_got_focus(reg);
454 /*}}}*/
457 /*{{{ Pointer, keyboard */
460 void ioncore_handle_buttonpress(XEvent *ev)
462 XEvent tmp;
463 Window win_pressed;
464 bool finished=FALSE;
466 if(ioncore_grab_held())
467 return;
469 win_pressed=ev->xbutton.window;
471 if(!ioncore_do_handle_buttonpress(&(ev->xbutton)))
472 return;
474 while(!finished && ioncore_grab_held()){
475 XFlush(ioncore_g.dpy);
476 ioncore_get_event(ev, IONCORE_EVENTMASK_PTRLOOP);
478 if(ev->type==MotionNotify){
479 /* Handle sequences of MotionNotify (possibly followed by button
480 * release) as one.
482 if(XPeekEvent(ioncore_g.dpy, &tmp)){
483 if(tmp.type==MotionNotify || tmp.type==ButtonRelease)
484 XNextEvent(ioncore_g.dpy, ev);
488 switch(ev->type){
489 CASE_EVENT(ButtonRelease)
490 if(ioncore_do_handle_buttonrelease(&ev->xbutton))
491 finished=TRUE;
492 break;
493 CASE_EVENT(MotionNotify)
494 ioncore_do_handle_motionnotify(&ev->xmotion);
495 break;
496 CASE_EVENT(Expose)
497 ioncore_handle_expose(&(ev->xexpose));
498 break;
499 CASE_EVENT(KeyPress)
500 CASE_EVENT(KeyRelease)
501 ioncore_handle_grabs(ev);
502 break;
503 CASE_EVENT(FocusIn)
504 ioncore_handle_focus_in(&(ev->xfocus));
505 break;
506 CASE_EVENT(FocusOut)
507 ioncore_handle_focus_out(&(ev->xfocus));
508 break;
514 void ioncore_handle_keyboard(XEvent *ev)
516 if(ioncore_handle_grabs(ev))
517 return;
519 if(ev->type==KeyPress)
520 ioncore_do_handle_keypress(&(ev->xkey));
524 /*}}}*/