4 * Copyright (c) Lukas Schroeder 2002,
5 * Tuomo Valkonen 2003-2009.
7 * See the included file LICENSE for details.
9 * Alternatively, you may apply the Clarified Artistic License to this file,
10 * since Lukas' contributions were originally under that.
18 #include <X11/keysymdef.h>
30 typedef struct _grab_status
{
33 GrabKilledHandler
*killedhandler
;
38 bool remove
; /* TRUE, if entry marked for removal by do_grab_remove() */
45 static GrabStatus grabs
[MAX_GRABS
];
46 static GrabStatus
*current_grab
;
47 static int idx_grab
=0;
48 static int last_sqid
=0;
54 /*{{{ do_grab/ungrab */
57 static void grab_kb_ptr(Window win
, Window confine_to
, int cursor
,
60 ioncore_g
.input_mode
=IONCORE_INPUTMODE_GRAB
;
62 XSelectInput(ioncore_g
.dpy
, win
, IONCORE_EVENTMASK_ROOT
&~eventmask
);
63 XGrabPointer(ioncore_g
.dpy
, win
, True
, IONCORE_EVENTMASK_PTRGRAB
,
64 GrabModeAsync
, GrabModeAsync
, confine_to
,
65 ioncore_xcursor(cursor
), CurrentTime
);
66 XGrabKeyboard(ioncore_g
.dpy
, win
, False
, GrabModeAsync
,
67 GrabModeAsync
, CurrentTime
);
68 XSync(ioncore_g
.dpy
, False
);
69 XSelectInput(ioncore_g
.dpy
, win
, IONCORE_EVENTMASK_ROOT
);
73 static void ungrab_kb_ptr()
75 XUngrabKeyboard(ioncore_g
.dpy
, CurrentTime
);
76 XUngrabPointer(ioncore_g
.dpy
, CurrentTime
);
78 ioncore_g
.input_mode
=IONCORE_INPUTMODE_NORMAL
;
85 /*{{{ Functions for installing grabs */
88 static void do_holder_remove(WRegion
*holder
, bool killed
);
91 static void grab_watch_handler(Watch
*w
, Obj
*obj
)
93 do_holder_remove((WRegion
*)obj
, TRUE
);
97 static void do_grab_install(GrabStatus
*grab
)
99 watch_setup(&grab
->watch
, (Obj
*)grab
->holder
, grab_watch_handler
);
100 grab_kb_ptr(region_root_of(grab
->holder
), grab
->confine_to
,
101 grab
->cursor
, grab
->eventmask
);
106 void ioncore_grab_establish(WRegion
*reg
, GrabHandler
*func
,
107 GrabKilledHandler
*kh
,
110 assert((~eventmask
)&(KeyPressMask
|KeyReleaseMask
));
112 if(idx_grab
<MAX_GRABS
){
113 current_grab
=&grabs
[idx_grab
++];
114 current_grab
->holder
=reg
;
115 current_grab
->handler
=func
;
116 current_grab
->killedhandler
=kh
;
117 current_grab
->eventmask
=eventmask
;
118 current_grab
->remove
=FALSE
;
119 current_grab
->cursor
=IONCORE_CURSOR_DEFAULT
;
120 current_grab
->confine_to
=None
; /*region_root_of(reg);*/
121 current_grab
->sqid
=last_sqid
++;
122 watch_init(¤t_grab
->watch
);
123 do_grab_install(current_grab
);
131 /*{{{ Grab removal functions */
134 static void do_grab_remove()
139 while(idx_grab
>0 && grabs
[idx_grab
-1].remove
==TRUE
){
140 watch_reset(&grabs
[idx_grab
-1].watch
);
147 current_grab
=&grabs
[idx_grab
-1];
148 do_grab_install(current_grab
);
153 static void mark_for_removal(GrabStatus
*grab
, bool killed
)
157 if(killed
&& grab
->killedhandler
!=NULL
&& grab
->holder
!=NULL
)
158 grab
->killedhandler(grab
->holder
);
161 if(grabs
[idx_grab
-1].remove
)
166 static void do_holder_remove(WRegion
*holder
, bool killed
)
170 for(i
=idx_grab
-1; i
>=0; i
--){
171 if(grabs
[i
].holder
==holder
)
172 mark_for_removal(grabs
+i
, killed
);
177 void ioncore_grab_holder_remove(WRegion
*holder
)
179 do_holder_remove(holder
, FALSE
);
183 void ioncore_grab_remove(GrabHandler
*func
)
186 for(i
=idx_grab
-1; i
>=0; i
--){
187 if(grabs
[i
].handler
==func
){
188 mark_for_removal(grabs
+i
, FALSE
);
198 /*{{{ Grab handler calling */
201 bool ioncore_handle_grabs(XEvent
*ev
)
206 while(current_grab
&& current_grab
->remove
)
209 if(current_grab
==NULL
|| current_grab
->holder
==NULL
||
210 current_grab
->handler
==NULL
){
214 /* Escape key is harcoded to always kill active grab. */
215 if(ev
->type
==KeyPress
&& XLookupKeysym(&(ev
->xkey
), 0)==XK_Escape
){
216 mark_for_removal(current_grab
, TRUE
);
220 if(ev
->type
!=KeyRelease
&& ev
->type
!=KeyPress
)
223 /* We must check that the grab pointed to by current_grab still
224 * is the same grab and not already released or replaced by
229 if(gr
->handler(gr
->holder
, ev
) && gr
->sqid
==gr_sqid
)
230 mark_for_removal(gr
, FALSE
);
242 bool ioncore_grab_held()
248 void ioncore_change_grab_cursor(int cursor
)
250 if(current_grab
!=NULL
){
251 current_grab
->cursor
=cursor
;
252 XChangeActivePointerGrab(ioncore_g
.dpy
, IONCORE_EVENTMASK_PTRGRAB
,
253 ioncore_xcursor(cursor
), CurrentTime
);
258 void ioncore_grab_confine_to(Window confine_to
)
260 if(current_grab
!=NULL
){
261 current_grab
->confine_to
=confine_to
;
262 XGrabPointer(ioncore_g
.dpy
, region_root_of(current_grab
->holder
),
263 True
, IONCORE_EVENTMASK_PTRGRAB
, GrabModeAsync
,
264 GrabModeAsync
, confine_to
,
265 ioncore_xcursor(IONCORE_CURSOR_DEFAULT
),
271 WRegion
*ioncore_grab_get_holder()
273 if (ioncore_grab_held())
274 return grabs
[idx_grab
-1].holder
;
279 WRegion
*ioncore_grab_get_my_holder(GrabHandler
*func
)
282 for(i
=idx_grab
-1; i
>=0; i
--)
283 if(grabs
[i
].handler
==func
)
284 return grabs
[i
].holder
;