4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
16 #include <libtu/objp.h>
24 #include "selection.h"
27 #include "clientwin.h"
36 /*{{{ ioncore_handle_event */
39 #define CASE_EVENT(EV) case EV: /*\
40 fprintf(stderr, "[%#lx] %s\n", ev->xany.window, #EV);*/
43 bool ioncore_handle_event(XEvent *ev)
47 CASE_EVENT(MapRequest)
48 ioncore_handle_map_request(&(ev->xmaprequest));
50 CASE_EVENT(ConfigureRequest)
51 ioncore_handle_configure_request(&(ev->xconfigurerequest));
53 CASE_EVENT(UnmapNotify)
54 ioncore_handle_unmap_notify(&(ev->xunmap));
56 CASE_EVENT(DestroyNotify)
57 ioncore_handle_destroy_notify(&(ev->xdestroywindow));
59 CASE_EVENT(ClientMessage)
60 ioncore_handle_client_message(&(ev->xclient));
62 CASE_EVENT(PropertyNotify)
63 ioncore_handle_property(&(ev->xproperty));
66 ioncore_handle_focus_in(&(ev->xfocus), FALSE);
69 ioncore_handle_focus_out(&(ev->xfocus));
71 CASE_EVENT(EnterNotify)
72 ioncore_handle_enter_window(ev);
75 ioncore_handle_expose(&(ev->xexpose));
78 ioncore_handle_keyboard(ev);
80 CASE_EVENT(KeyRelease)
81 ioncore_handle_keyboard(ev);
83 CASE_EVENT(ButtonPress)
84 ioncore_handle_buttonpress(ev);
86 CASE_EVENT(ColormapNotify)
87 ioncore_handle_colormap_notify(&(ev->xcolormap));
89 CASE_EVENT(MappingNotify)
90 ioncore_handle_mapping_notify(ev);
92 CASE_EVENT(SelectionClear)
93 ioncore_clear_selection();
95 CASE_EVENT(SelectionNotify)
96 ioncore_handle_selection(&(ev->xselection));
98 CASE_EVENT(SelectionRequest)
99 ioncore_handle_selection_request(&(ev->xselectionrequest));
110 /*{{{ Map, unmap, destroy */
113 void ioncore_handle_map_request(const XMapRequestEvent *ev)
117 reg=XWINDOW_REGION_OF(ev->window);
122 ioncore_manage_clientwin(ev->window, TRUE);
126 void ioncore_handle_unmap_notify(const XUnmapEvent *ev)
130 /* We are not interested in SubstructureNotify -unmaps. */
131 if(ev->event!=ev->window && ev->send_event!=True)
134 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
137 clientwin_unmapped(cwin);
141 void ioncore_handle_destroy_notify(const XDestroyWindowEvent *ev)
145 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
148 clientwin_destroyed(cwin);
155 /*{{{ Client configure/property/message */
158 void ioncore_handle_configure_request(XConfigureRequestEvent *ev)
163 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
166 wc.border_width=ev->border_width;
167 wc.sibling=ev->above;
168 wc.stack_mode=ev->detail;
172 wc.height=ev->height;
173 XConfigureWindow(ioncore_g.dpy, ev->window, ev->value_mask, &wc);
177 clientwin_handle_configure_request(cwin, ev);
181 void ioncore_handle_client_message(const XClientMessageEvent *ev)
183 netwm_handle_client_message(ev);
188 if(ev->message_type!=ioncore_g.atom_wm_change_state)
191 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
196 if(ev->format==32 && ev->data.l[0]==IconicState){
197 if(cwin->state==NormalState)
198 iconify_clientwin(cwin);
204 static bool pchg_mrsh_extl(ExtlFn fn, void **p)
206 extl_call(fn, "oi", NULL, p[0], ((XPropertyEvent*)p[1])->atom);
210 static bool pchg_mrsh(void (*fn)(void *p1, void *p2), void **p)
217 void ioncore_handle_property(const XPropertyEvent *ev)
221 cwin=XWINDOW_REGION_OF_T(ev->window, WClientWin);
226 if(ev->atom==XA_WM_HINTS){
228 hints=XGetWMHints(ioncore_g.dpy, ev->window);
229 /* region_notify/clear_activity take care of checking current state */
231 if(hints->flags&XUrgencyHint){
232 if(!region_skip_focus((WRegion*)cwin))
233 region_set_activity((WRegion*)cwin, SETPARAM_SET);
235 region_set_activity((WRegion*)cwin, SETPARAM_UNSET);
239 }else if(ev->atom==XA_WM_NORMAL_HINTS){
240 clientwin_get_size_hints(cwin);
241 }else if(ev->atom==XA_WM_NAME){
242 if(!(cwin->flags&CLIENTWIN_USE_NET_WM_NAME))
243 clientwin_get_set_name(cwin);
244 }else if(ev->atom==XA_WM_TRANSIENT_FOR){
245 clientwin_tfor_changed(cwin);
246 }else if(ev->atom==ioncore_g.atom_wm_protocols){
247 clientwin_get_protocols(cwin);
249 netwm_handle_property(cwin, ev);
252 /* Call property hook */
257 hook_call(clientwin_property_change_hook, p,
258 (WHookMarshall*)pchg_mrsh,
259 (WHookMarshallExtl*)pchg_mrsh_extl);
267 /*{{{ Misc. notifies */
270 void ioncore_handle_mapping_notify(XEvent *ev)
273 XRefreshKeyboardMapping(&(ev->xmapping));
274 }while(XCheckTypedEvent(ioncore_g.dpy, MappingNotify, ev));
276 ioncore_refresh_bindmaps();
286 void ioncore_handle_expose(const XExposeEvent *ev)
292 while(XCheckWindowEvent(ioncore_g.dpy, ev->window, ExposureMask, &tmp))
295 wwin=XWINDOW_REGION_OF_T(ev->window, WWindow);
298 window_draw(wwin, FALSE);
305 /*{{{ Enter window, focus */
308 static void do_handle_enter_window(XEvent *ev)
310 XEnterWindowEvent *eev=&(ev->xcrossing);
313 if(ioncore_g.input_mode!=IONCORE_INPUTMODE_NORMAL)
316 reg=XWINDOW_REGION_OF_T(eev->window, WRegion);
321 if(REGION_IS_ACTIVE(reg))
324 if(region_skip_focus(reg))
327 /* If a child of 'reg' is to be focused, do not process this
328 * event. (ioncore_g.focus_next should only be set here by
329 * another call to use from ioncore_handle_enter_window below.)
331 if(ioncore_g.focus_next!=NULL){
332 WRegion *r2=ioncore_g.focus_next;
336 r2=REGION_PARENT_REG(r2);
340 region_goto_flags(reg, (REGION_GOTO_FOCUS|
342 REGION_GOTO_ENTERWINDOW));
346 void ioncore_handle_enter_window(XEvent *ev)
349 /* *sigh*, it doesn't seem reasonably simply possible to
350 * process events in-order.
352 do_handle_enter_window(ev);
353 }while(XCheckMaskEvent(ioncore_g.dpy, EnterWindowMask, ev));
357 static bool pointer_in_root(Window root1)
359 Window root2=None, win;
363 XQueryPointer(ioncore_g.dpy, root1, &root2, &win,
364 &x, &y, &wx, &wy, &mask);
366 return (root1==root2);
371 void ioncore_handle_focus_in(const XFocusChangeEvent *ev, bool skip)
376 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
381 D(fprintf(stderr, "FI: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
383 if(ev->mode==NotifyGrab)
386 if(ev->detail==NotifyPointer)
389 if(ev->window==region_root_of(reg)){ /* OBJ_IS(reg, WRootWin) */
390 D(fprintf(stderr, "scr-in %d %d %d\n", ROOTWIN_OF(reg)->xscr,
391 ev->mode, ev->detail));
392 if((ev->detail==NotifyPointerRoot || ev->detail==NotifyDetailNone) &&
393 pointer_in_root(ev->window) && ioncore_g.focus_next==NULL){
396 region_set_focus(reg);
402 if(OBJ_IS(reg, WWindow)){
405 XSetICFocus(wwin->xic);
408 if(ev->detail!=NotifyInferior)
409 netwm_set_active(reg);
411 region_got_focus(reg);
415 void ioncore_handle_focus_out(const XFocusChangeEvent *ev)
420 reg=XWINDOW_REGION_OF_T(ev->window, WRegion);
425 D(fprintf(stderr, "FO: %s %p %d %d\n", OBJ_TYPESTR(reg), reg, ev->mode, ev->detail);)
427 if(ev->mode==NotifyGrab)
430 if(ev->detail==NotifyPointer)
433 D(if(OBJ_IS(reg, WRootWin))
434 fprintf(stderr, "scr-out %d %d %d\n", ((WRootWin*)reg)->xscr, ev->mode, ev->detail));
436 if(OBJ_IS(reg, WWindow)){
439 XUnsetICFocus(wwin->xic);
442 if(ev->detail!=NotifyInferior)
443 region_lost_focus(reg);
445 region_got_focus(reg);
452 /*{{{ Pointer, keyboard */
455 void ioncore_handle_buttonpress(XEvent *ev)
461 if(ioncore_grab_held())
464 win_pressed=ev->xbutton.window;
466 if(!ioncore_do_handle_buttonpress(&(ev->xbutton)))
469 while(!finished && ioncore_grab_held()){
470 XFlush(ioncore_g.dpy);
471 ioncore_get_event(ev, IONCORE_EVENTMASK_PTRLOOP);
473 if(ev->type==MotionNotify){
474 /* Handle sequences of MotionNotify (possibly followed by button
477 if(XPeekEvent(ioncore_g.dpy, &tmp)){
478 if(tmp.type==MotionNotify || tmp.type==ButtonRelease)
479 XNextEvent(ioncore_g.dpy, ev);
484 CASE_EVENT(ButtonRelease)
485 if(ioncore_do_handle_buttonrelease(&ev->xbutton))
488 CASE_EVENT(MotionNotify)
489 ioncore_do_handle_motionnotify(&ev->xmotion);
492 ioncore_handle_expose(&(ev->xexpose));
495 CASE_EVENT(KeyRelease)
496 ioncore_handle_grabs(ev);
499 ioncore_handle_focus_in(&(ev->xfocus), FALSE);
502 ioncore_handle_focus_out(&(ev->xfocus));
509 void ioncore_handle_keyboard(XEvent *ev)
511 if(ioncore_handle_grabs(ev))
514 if(ev->type==KeyPress)
515 ioncore_do_handle_keypress(&(ev->xkey));