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"
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
)
45 CASE_EVENT(MapRequest
)
46 ioncore_handle_map_request(&(ev
->xmaprequest
));
48 CASE_EVENT(ConfigureRequest
)
49 ioncore_handle_configure_request(&(ev
->xconfigurerequest
));
51 CASE_EVENT(UnmapNotify
)
52 ioncore_handle_unmap_notify(&(ev
->xunmap
));
54 CASE_EVENT(DestroyNotify
)
55 ioncore_handle_destroy_notify(&(ev
->xdestroywindow
));
57 CASE_EVENT(ClientMessage
)
58 ioncore_handle_client_message(&(ev
->xclient
));
60 CASE_EVENT(PropertyNotify
)
61 ioncore_handle_property(&(ev
->xproperty
));
64 ioncore_handle_focus_in(&(ev
->xfocus
));
67 ioncore_handle_focus_out(&(ev
->xfocus
));
69 CASE_EVENT(EnterNotify
)
70 ioncore_handle_enter_window(ev
);
73 ioncore_handle_expose(&(ev
->xexpose
));
76 ioncore_handle_keyboard(ev
);
78 CASE_EVENT(KeyRelease
)
79 ioncore_handle_keyboard(ev
);
81 CASE_EVENT(ButtonPress
)
82 ioncore_handle_buttonpress(ev
);
84 CASE_EVENT(ColormapNotify
)
85 ioncore_handle_colormap_notify(&(ev
->xcolormap
));
87 CASE_EVENT(MappingNotify
)
88 ioncore_handle_mapping_notify(ev
);
90 CASE_EVENT(SelectionClear
)
91 ioncore_clear_selection();
93 CASE_EVENT(SelectionNotify
)
94 ioncore_handle_selection(&(ev
->xselection
));
96 CASE_EVENT(SelectionRequest
)
97 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 */
157 void ioncore_handle_configure_request(XConfigureRequestEvent
*ev
)
162 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
165 wc
.border_width
=ev
->border_width
;
166 wc
.sibling
=ev
->above
;
167 wc
.stack_mode
=ev
->detail
;
171 wc
.height
=ev
->height
;
172 XConfigureWindow(ioncore_g
.dpy
, ev
->window
, ev
->value_mask
, &wc
);
176 clientwin_handle_configure_request(cwin
, ev
);
180 void ioncore_handle_client_message(const XClientMessageEvent
*ev
)
182 netwm_handle_client_message(ev
);
187 if(ev
->message_type
!=ioncore_g
.atom_wm_change_state
)
190 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
195 if(ev
->format
==32 && ev
->data
.l
[0]==IconicState
){
196 if(cwin
->state
==NormalState
)
197 iconify_clientwin(cwin
);
203 static bool pchg_mrsh_extl(ExtlFn fn
, void **p
)
205 extl_call(fn
, "oi", NULL
, p
[0], ((XPropertyEvent
*)p
[1])->atom
);
209 static bool pchg_mrsh(void (*fn
)(void *p1
, void *p2
), void **p
)
216 void ioncore_handle_property(const XPropertyEvent
*ev
)
220 cwin
=XWINDOW_REGION_OF_T(ev
->window
, WClientWin
);
225 if(ev
->atom
==XA_WM_HINTS
){
227 hints
=XGetWMHints(ioncore_g
.dpy
, ev
->window
);
228 /* region_notify/clear_activity take care of checking current state */
230 if(hints
->flags
&XUrgencyHint
){
231 if(!region_skip_focus((WRegion
*)cwin
))
232 region_set_activity((WRegion
*)cwin
, SETPARAM_SET
);
234 region_set_activity((WRegion
*)cwin
, SETPARAM_UNSET
);
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
);
252 netwm_handle_property(cwin
, ev
);
255 /* Call property hook */
260 hook_call(clientwin_property_change_hook
, p
,
261 (WHookMarshall
*)pchg_mrsh
,
262 (WHookMarshallExtl
*)pchg_mrsh_extl
);
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();
289 void ioncore_handle_expose(const XExposeEvent
*ev
)
294 while(XCheckWindowEvent(ioncore_g
.dpy
, ev
->window
, ExposureMask
, &tmp
))
297 wwin
=XWINDOW_REGION_OF_T(ev
->window
, WWindow
);
300 window_draw(wwin
, FALSE
);
307 /*{{{ Enter window, focus */
310 void ioncore_handle_enter_window(XEvent
*ev
)
312 XEnterWindowEvent
*eev
=&(ev
->xcrossing
);
315 if(ioncore_g
.input_mode
!=IONCORE_INPUTMODE_NORMAL
||
316 ioncore_g
.no_mousefocus
){
320 if(eev
->mode
!=NotifyNormal
&& !ioncore_g
.warp_enabled
)
323 reg
=XWINDOW_REGION_OF_T(eev
->window
, WRegion
);
328 if(REGION_IS_ACTIVE(reg
))
331 if(region_skip_focus(reg
))
334 if(ioncore_g
.focus_next
!=NULL
&&
335 ioncore_g
.focus_next_source
<IONCORE_FOCUSNEXT_ENTERWINDOW
){
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
;
348 r2
=REGION_PARENT_REG(r2
);
352 if(region_goto_flags(reg
, (REGION_GOTO_FOCUS
|
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
;
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
)
378 reg
=XWINDOW_REGION_OF_T(ev
->window
, WRegion
);
383 D(fprintf(stderr
, "FI: %s %p %d %d\n", OBJ_TYPESTR(reg
), reg
, ev
->mode
, ev
->detail
);)
385 if(ev
->mode
==NotifyGrab
)
388 if(ev
->detail
==NotifyPointer
)
392 if(OBJ_IS(reg
, WWindow
)){
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
){
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
;
418 /* Something got the focus, don't use fallback. */
419 ioncore_g
.focus_next
=NULL
;
424 void ioncore_handle_focus_out(const XFocusChangeEvent
*ev
)
429 reg
=XWINDOW_REGION_OF_T(ev
->window
, WRegion
);
434 D(fprintf(stderr
, "FO: %s %p %d %d\n", OBJ_TYPESTR(reg
), reg
, ev
->mode
, ev
->detail
);)
436 if(ev
->mode
==NotifyGrab
)
439 if(ev
->detail
==NotifyPointer
)
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
)){
448 XUnsetICFocus(wwin
->xic
);
451 if(ev
->detail
!=NotifyInferior
)
452 region_lost_focus(reg
);
454 region_got_focus(reg
);
461 /*{{{ Pointer, keyboard */
464 void ioncore_handle_buttonpress(XEvent
*ev
)
469 if(ioncore_grab_held())
472 if(!ioncore_do_handle_buttonpress(&(ev
->xbutton
)))
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
483 if(XPeekEvent(ioncore_g
.dpy
, &tmp
)){
484 if(tmp
.type
==MotionNotify
|| tmp
.type
==ButtonRelease
)
485 XNextEvent(ioncore_g
.dpy
, ev
);
490 CASE_EVENT(ButtonRelease
)
491 if(ioncore_do_handle_buttonrelease(&ev
->xbutton
))
494 CASE_EVENT(MotionNotify
)
495 ioncore_do_handle_motionnotify(&ev
->xmotion
);
498 ioncore_handle_expose(&(ev
->xexpose
));
501 CASE_EVENT(KeyRelease
)
502 ioncore_handle_grabs(ev
);
505 ioncore_handle_focus_in(&(ev
->xfocus
));
508 ioncore_handle_focus_out(&(ev
->xfocus
));
515 void ioncore_handle_keyboard(XEvent
*ev
)
517 if(ioncore_handle_grabs(ev
))
520 if(ev
->type
==KeyPress
)
521 ioncore_do_handle_keypress(&(ev
->xkey
));