4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
13 #include <libtu/objp.h>
21 #include "selection.h"
24 #include "clientwin.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)
44 CASE_EVENT(MapRequest)
45 ioncore_handle_map_request(&(ev->xmaprequest));
47 CASE_EVENT(ConfigureRequest)
48 ioncore_handle_configure_request(&(ev->xconfigurerequest));
50 CASE_EVENT(UnmapNotify)
51 ioncore_handle_unmap_notify(&(ev->xunmap));
53 CASE_EVENT(DestroyNotify)
54 ioncore_handle_destroy_notify(&(ev->xdestroywindow));
56 CASE_EVENT(ClientMessage)
57 ioncore_handle_client_message(&(ev->xclient));
59 CASE_EVENT(PropertyNotify)
60 ioncore_handle_property(&(ev->xproperty));
63 ioncore_handle_focus_in(&(ev->xfocus));
66 ioncore_handle_focus_out(&(ev->xfocus));
68 CASE_EVENT(EnterNotify)
69 ioncore_handle_enter_window(ev);
72 ioncore_handle_expose(&(ev->xexpose));
75 ioncore_handle_keyboard(ev);
77 CASE_EVENT(KeyRelease)
78 ioncore_handle_keyboard(ev);
80 CASE_EVENT(ButtonPress)
81 ioncore_handle_buttonpress(ev);
83 CASE_EVENT(ColormapNotify)
84 ioncore_handle_colormap_notify(&(ev->xcolormap));
86 CASE_EVENT(MappingNotify)
87 ioncore_handle_mapping_notify(ev);
89 CASE_EVENT(SelectionClear)
90 ioncore_clear_selection();
92 CASE_EVENT(SelectionNotify)
93 ioncore_handle_selection(&(ev->xselection));
95 CASE_EVENT(SelectionRequest)
96 ioncore_handle_selection_request(&(ev->xselectionrequest));
107 /*{{{ Map, unmap, destroy */
110 void ioncore_handle_map_request(const XMapRequestEvent *ev)
114 reg=XWINDOW_REGION_OF(ev->window);
119 ioncore_manage_clientwin(ev->window, TRUE);
123 void ioncore_handle_unmap_notify(const XUnmapEvent *ev)
127 /* We are not interested in SubstructureNotify -unmaps. */
128 if(ev->event!=ev->window && ev->send_event!=True)
131 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
134 clientwin_unmapped(cwin);
138 void ioncore_handle_destroy_notify(const XDestroyWindowEvent *ev)
142 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
145 clientwin_destroyed(cwin);
152 /*{{{ Client configure/property/message */
155 void ioncore_handle_configure_request(XConfigureRequestEvent *ev)
160 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
163 wc.border_width=ev->border_width;
164 wc.sibling=ev->above;
165 wc.stack_mode=ev->detail;
169 wc.height=ev->height;
170 XConfigureWindow(ioncore_g.dpy, ev->window, ev->value_mask, &wc);
174 clientwin_handle_configure_request(cwin, ev);
178 void ioncore_handle_client_message(const XClientMessageEvent *ev)
180 netwm_handle_client_message(ev);
185 if(ev->message_type!=ioncore_g.atom_wm_change_state)
188 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
193 if(ev->format==32 && ev->data.l[0]==IconicState){
194 if(cwin->state==NormalState)
195 iconify_clientwin(cwin);
201 static bool pchg_mrsh_extl(ExtlFn fn, void **p)
203 extl_call(fn, "oi", NULL, p[0], ((XPropertyEvent*)p[1])->atom);
207 static bool pchg_mrsh(void (*fn)(void *p1, void *p2), void **p)
214 void ioncore_handle_property(const XPropertyEvent *ev)
218 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
223 if(ev->atom==XA_WM_HINTS){
225 hints=XGetWMHints(ioncore_g.dpy, ev->window);
226 /* region_notify/clear_activity take care of checking current state */
228 if(hints->flags&XUrgencyHint){
229 if(!region_skip_focus((WRegion*)cwin))
230 region_set_activity((WRegion*)cwin, SETPARAM_SET);
232 region_set_activity((WRegion*)cwin, SETPARAM_UNSET);
236 }else if(ev->atom==XA_WM_NORMAL_HINTS){
237 clientwin_get_size_hints(cwin);
238 }else if(ev->atom==XA_WM_NAME){
239 if(!(cwin->flags&CLIENTWIN_USE_NET_WM_NAME))
240 clientwin_get_set_name(cwin);
241 }else if(ev->atom==XA_WM_TRANSIENT_FOR){
242 clientwin_tfor_changed(cwin);
243 }else if(ev->atom==ioncore_g.atom_wm_protocols){
244 clientwin_get_protocols(cwin);
246 netwm_handle_property(cwin, ev);
249 /* Call property hook */
254 hook_call(clientwin_property_change_hook, p,
255 (WHookMarshall*)pchg_mrsh,
256 (WHookMarshallExtl*)pchg_mrsh_extl);
264 /*{{{ Misc. notifies */
267 void ioncore_handle_mapping_notify(XEvent *ev)
270 XRefreshKeyboardMapping(&(ev->xmapping));
271 }while(XCheckTypedEvent(ioncore_g.dpy, MappingNotify, ev));
273 ioncore_refresh_bindmaps();
283 void ioncore_handle_expose(const XExposeEvent *ev)
289 while(XCheckWindowEvent(ioncore_g.dpy, ev->window, ExposureMask, &tmp))
292 wwin=XWINDOW_REGION_OF_T(ev->window, WWindow);
295 window_draw(wwin, FALSE);
302 /*{{{ Enter window, focus */
305 void ioncore_handle_enter_window(XEvent *ev)
307 XEnterWindowEvent *eev=&(ev->xcrossing);
310 if(ioncore_g.input_mode!=IONCORE_INPUTMODE_NORMAL ||
311 ioncore_g.no_mousefocus){
315 if(eev->mode!=NotifyNormal && !ioncore_g.warp_enabled)
318 reg=XWINDOW_REGION_OF_T(eev->window, WRegion);
323 if(REGION_IS_ACTIVE(reg))
326 if(region_skip_focus(reg))
329 if(ioncore_g.focus_next!=NULL &&
330 ioncore_g.focus_next_source<IONCORE_FOCUSNEXT_ENTERWINDOW){
334 /* If a child of 'reg' is to be focused, do not process this
335 * event. (ioncore_g.focus_next should only be set here by
336 * another call to use from ioncore_handle_enter_window below.)
338 if(ioncore_g.focus_next!=NULL){
339 WRegion *r2=ioncore_g.focus_next;
343 r2=REGION_PARENT_REG(r2);
347 if(region_goto_flags(reg, (REGION_GOTO_FOCUS|
349 REGION_GOTO_ENTERWINDOW))){
350 ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_ENTERWINDOW;
355 static bool pointer_in_root(Window root1)
357 Window root2=None, win;
361 XQueryPointer(ioncore_g.dpy, root1, &root2, &win,
362 &x, &y, &wx, &wy, &mask);
364 return (root1==root2);
368 void ioncore_handle_focus_in(const XFocusChangeEvent *ev)
373 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
378 D(fprintf(stderr, "FI: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
380 if(ev->mode==NotifyGrab)
383 if(ev->detail==NotifyPointer)
387 if(OBJ_IS(reg, WWindow)){
390 XSetICFocus(wwin->xic);
393 if(ev->detail!=NotifyInferior)
394 netwm_set_active(reg);
396 region_got_focus(reg);
398 if(ioncore_g.focus_next!=NULL &&
399 ioncore_g.focus_next_source<IONCORE_FOCUSNEXT_FALLBACK){
403 if((ev->detail==NotifyPointerRoot || ev->detail==NotifyDetailNone)
404 && ev->window==region_root_of(reg) /* OBJ_IS(reg, WRootWin) */){
405 /* Restore focus if it was returned to a root window and we don't
406 * know of a pending focus change.
408 if(pointer_in_root(ev->window)){
409 region_set_focus(reg);
410 ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_FALLBACK;
413 /* Something got the focus, don't use fallback. */
414 ioncore_g.focus_next=NULL;
419 void ioncore_handle_focus_out(const XFocusChangeEvent *ev)
424 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
429 D(fprintf(stderr, "FO: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
431 if(ev->mode==NotifyGrab)
434 if(ev->detail==NotifyPointer)
437 D(if(OBJ_IS(reg, WRootWin))
438 fprintf(stderr, "scr-out %d %d %d\n", ((WRootWin*)reg)->xscr, ev->mode, ev->detail));
440 if(OBJ_IS(reg, WWindow)){
443 XUnsetICFocus(wwin->xic);
446 if(ev->detail!=NotifyInferior)
447 region_lost_focus(reg);
449 region_got_focus(reg);
456 /*{{{ Pointer, keyboard */
459 void ioncore_handle_buttonpress(XEvent *ev)
465 if(ioncore_grab_held())
468 win_pressed=ev->xbutton.window;
470 if(!ioncore_do_handle_buttonpress(&(ev->xbutton)))
473 while(!finished && ioncore_grab_held()){
474 XFlush(ioncore_g.dpy);
475 ioncore_get_event(ev, IONCORE_EVENTMASK_PTRLOOP);
477 if(ev->type==MotionNotify){
478 /* Handle sequences of MotionNotify (possibly followed by button
481 if(XPeekEvent(ioncore_g.dpy, &tmp)){
482 if(tmp.type==MotionNotify || tmp.type==ButtonRelease)
483 XNextEvent(ioncore_g.dpy, ev);
488 CASE_EVENT(ButtonRelease)
489 if(ioncore_do_handle_buttonrelease(&ev->xbutton))
492 CASE_EVENT(MotionNotify)
493 ioncore_do_handle_motionnotify(&ev->xmotion);
496 ioncore_handle_expose(&(ev->xexpose));
499 CASE_EVENT(KeyRelease)
500 ioncore_handle_grabs(ev);
503 ioncore_handle_focus_in(&(ev->xfocus));
506 ioncore_handle_focus_out(&(ev->xfocus));
513 void ioncore_handle_keyboard(XEvent *ev)
515 if(ioncore_handle_grabs(ev))
518 if(ev->type==KeyPress)
519 ioncore_do_handle_keypress(&(ev->xkey));