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
));
109 /*{{{ Map, unmap, destroy */
112 void ioncore_handle_map_request(const XMapRequestEvent
*ev
)
116 reg
=XWINDOW_REGION_OF(ev
->window
);
121 ioncore_manage_clientwin(ev
->window
, TRUE
);
125 void ioncore_handle_unmap_notify(const XUnmapEvent
*ev
)
129 /* We are not interested in SubstructureNotify -unmaps. */
130 if(ev
->event
!=ev
->window
&& ev
->send_event
!=True
)
133 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
136 clientwin_unmapped(cwin
);
140 void ioncore_handle_destroy_notify(const XDestroyWindowEvent
*ev
)
144 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
147 clientwin_destroyed(cwin
);
154 /*{{{ Client configure/property/message */
156 void ioncore_handle_configure_request(XConfigureRequestEvent
*ev
)
161 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
164 wc
.border_width
=ev
->border_width
;
165 wc
.sibling
=ev
->above
;
166 wc
.stack_mode
=ev
->detail
;
170 wc
.height
=ev
->height
;
171 XConfigureWindow(ioncore_g
.dpy
, ev
->window
, ev
->value_mask
, &wc
);
175 clientwin_handle_configure_request(cwin
, ev
);
179 void ioncore_handle_client_message(const XClientMessageEvent
*ev
)
181 netwm_handle_client_message(ev
);
186 if(ev
->message_type
!=ioncore_g
.atom_wm_change_state
)
189 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
194 if(ev
->format
==32 && ev
->data
.l
[0]==IconicState
){
195 if(cwin
->state
==NormalState
)
196 iconify_clientwin(cwin
);
202 static bool pchg_mrsh_extl(ExtlFn fn
, void **p
)
204 extl_call(fn
, "oi", NULL
, p
[0], ((XPropertyEvent
*)p
[1])->atom
);
208 static bool pchg_mrsh(void (*fn
)(void *p1
, void *p2
), void **p
)
215 void ioncore_handle_property(const XPropertyEvent
*ev
)
219 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
224 if(ev
->atom
==XA_WM_HINTS
){
226 hints
=XGetWMHints(ioncore_g
.dpy
, ev
->window
);
227 /* region_notify/clear_activity take care of checking current state */
229 if(hints
->flags
&XUrgencyHint
){
230 if(!region_skip_focus((WRegion
*)cwin
))
231 region_set_activity((WRegion
*)cwin
, SETPARAM_SET
);
233 region_set_activity((WRegion
*)cwin
, SETPARAM_UNSET
);
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
);
247 netwm_handle_property(cwin
, ev
);
250 /* Call property hook */
255 hook_call(clientwin_property_change_hook
, p
,
256 (WHookMarshall
*)pchg_mrsh
,
257 (WHookMarshallExtl
*)pchg_mrsh_extl
);
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();
284 void ioncore_handle_expose(const XExposeEvent
*ev
)
290 while(XCheckWindowEvent(ioncore_g
.dpy
, ev
->window
, ExposureMask
, &tmp
))
293 wwin
=XWINDOW_REGION_OF_T(ev
->window
, WWindow
);
296 window_draw(wwin
, FALSE
);
303 /*{{{ Enter window, focus */
306 void ioncore_handle_enter_window(XEvent
*ev
)
308 XEnterWindowEvent
*eev
=&(ev
->xcrossing
);
311 if(ioncore_g
.input_mode
!=IONCORE_INPUTMODE_NORMAL
||
312 ioncore_g
.no_mousefocus
){
316 if(eev
->mode
!=NotifyNormal
&& !ioncore_g
.warp_enabled
)
319 reg
=XWINDOW_REGION_OF_T(eev
->window
, WRegion
);
324 if(REGION_IS_ACTIVE(reg
))
327 if(region_skip_focus(reg
))
330 if(ioncore_g
.focus_next
!=NULL
&&
331 ioncore_g
.focus_next_source
<IONCORE_FOCUSNEXT_ENTERWINDOW
){
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
;
344 r2
=REGION_PARENT_REG(r2
);
348 if(region_goto_flags(reg
, (REGION_GOTO_FOCUS
|
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
;
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
)
374 reg
=XWINDOW_REGION_OF_T(ev
->window
, WRegion
);
379 D(fprintf(stderr
, "FI: %s %p %d %d\n", OBJ_TYPESTR(reg
), reg
, ev
->mode
, ev
->detail
);)
381 if(ev
->mode
==NotifyGrab
)
384 if(ev
->detail
==NotifyPointer
)
388 if(OBJ_IS(reg
, WWindow
)){
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
){
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
;
414 /* Something got the focus, don't use fallback. */
415 ioncore_g
.focus_next
=NULL
;
420 void ioncore_handle_focus_out(const XFocusChangeEvent
*ev
)
425 reg
=XWINDOW_REGION_OF_T(ev
->window
, WRegion
);
430 D(fprintf(stderr
, "FO: %s %p %d %d\n", OBJ_TYPESTR(reg
), reg
, ev
->mode
, ev
->detail
);)
432 if(ev
->mode
==NotifyGrab
)
435 if(ev
->detail
==NotifyPointer
)
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
)){
444 XUnsetICFocus(wwin
->xic
);
447 if(ev
->detail
!=NotifyInferior
)
448 region_lost_focus(reg
);
450 region_got_focus(reg
);
457 /*{{{ Pointer, keyboard */
460 void ioncore_handle_buttonpress(XEvent
*ev
)
466 if(ioncore_grab_held())
469 win_pressed
=ev
->xbutton
.window
;
471 if(!ioncore_do_handle_buttonpress(&(ev
->xbutton
)))
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
482 if(XPeekEvent(ioncore_g
.dpy
, &tmp
)){
483 if(tmp
.type
==MotionNotify
|| tmp
.type
==ButtonRelease
)
484 XNextEvent(ioncore_g
.dpy
, ev
);
489 CASE_EVENT(ButtonRelease
)
490 if(ioncore_do_handle_buttonrelease(&ev
->xbutton
))
493 CASE_EVENT(MotionNotify
)
494 ioncore_do_handle_motionnotify(&ev
->xmotion
);
497 ioncore_handle_expose(&(ev
->xexpose
));
500 CASE_EVENT(KeyRelease
)
501 ioncore_handle_grabs(ev
);
504 ioncore_handle_focus_in(&(ev
->xfocus
));
507 ioncore_handle_focus_out(&(ev
->xfocus
));
514 void ioncore_handle_keyboard(XEvent
*ev
)
516 if(ioncore_handle_grabs(ev
))
519 if(ev
->type
==KeyPress
)
520 ioncore_do_handle_keypress(&(ev
->xkey
));