Merge branch 'contrib_goto_focus'
[notion.git] / ioncore / grab.c
blobf2f282ecc3fd4c38d0d8d07e616e5cd3ec3357cd
1 /*
2 * ion/ioncore/grab.c
3 *
4 * Copyright (c) Lukas Schroeder 2002,
5 * Tuomo Valkonen 2003-2009.
7 * See the included file LICENSE for details.
8 *
9 * Alternatively, you may apply the Clarified Artistic License to this file,
10 * since Lukas' contributions were originally under that.
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <sys/time.h>
17 #define XK_MISCELLANY
18 #include <X11/keysymdef.h>
20 #include "common.h"
21 #include "global.h"
22 #include "event.h"
23 #include "cursor.h"
24 #include "grab.h"
27 /*{{{ Definitions */
30 typedef struct _grab_status{
31 WRegion *holder;
32 GrabHandler *handler;
33 GrabKilledHandler *killedhandler;
34 Watch watch;
35 long eventmask;
36 long flags;
38 bool remove; /* TRUE, if entry marked for removal by do_grab_remove() */
39 int cursor;
40 Window confine_to;
41 int sqid;
42 }GrabStatus;
44 #define MAX_GRABS 4
45 static GrabStatus grabs[MAX_GRABS];
46 static GrabStatus *current_grab;
47 static int idx_grab=0;
48 static int last_sqid=0;
51 /*}}}*/
54 /*{{{ do_grab/ungrab */
57 static void grab_kb_ptr(Window win, Window confine_to, int cursor,
58 long eventmask)
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;
82 /*}}}*/
85 /*{{{ Functions for installing grabs */
88 static void do_holder_remove(WRegion *holder, bool killed);
91 static void grab_watch_handler(Watch *UNUSED(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);
102 current_grab=grab;
106 void ioncore_grab_establish(WRegion *reg, GrabHandler *func,
107 GrabKilledHandler *kh,
108 long eventmask)
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(&current_grab->watch);
123 do_grab_install(current_grab);
128 /*}}}*/
131 /*{{{ Grab removal functions */
134 static void do_grab_remove()
136 current_grab=NULL;
137 ungrab_kb_ptr();
139 while(idx_grab>0 && grabs[idx_grab-1].remove==TRUE){
140 watch_reset(&grabs[idx_grab-1].watch);
141 idx_grab--;
144 assert(idx_grab>=0);
146 if(idx_grab>0){
147 current_grab=&grabs[idx_grab-1];
148 do_grab_install(current_grab);
153 static void mark_for_removal(GrabStatus *grab, bool killed)
155 if(!grab->remove){
156 grab->remove=TRUE;
157 if(killed && grab->killedhandler!=NULL && grab->holder!=NULL)
158 grab->killedhandler(grab->holder);
161 if(grabs[idx_grab-1].remove)
162 do_grab_remove();
166 static void do_holder_remove(WRegion *holder, bool killed)
168 int i;
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)
185 int i;
186 for(i=idx_grab-1; i>=0; i--){
187 if(grabs[i].handler==func){
188 mark_for_removal(grabs+i, FALSE);
189 break;
195 /*}}}*/
198 /*{{{ Grab handler calling */
201 bool ioncore_handle_grabs(XEvent *ev)
203 GrabStatus *gr;
204 int gr_sqid;
206 while(current_grab && current_grab->remove)
207 do_grab_remove();
209 if(current_grab==NULL || current_grab->holder==NULL ||
210 current_grab->handler==NULL){
211 return FALSE;
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);
217 return TRUE;
220 if(ev->type!=KeyRelease && ev->type!=KeyPress)
221 return FALSE;
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
225 * another grab.
227 gr=current_grab;
228 gr_sqid=gr->sqid;
229 if(gr->handler(gr->holder, ev) && gr->sqid==gr_sqid)
230 mark_for_removal(gr, FALSE);
232 return TRUE;
236 /*}}}*/
239 /*{{{ Misc. */
242 bool ioncore_grab_held()
244 return idx_grab>0;
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),
266 CurrentTime);
271 WRegion *ioncore_grab_get_holder()
273 if (ioncore_grab_held())
274 return grabs[idx_grab-1].holder;
275 return NULL;
279 WRegion *ioncore_grab_get_my_holder(GrabHandler *func)
281 int i;
282 for(i=idx_grab-1; i>=0; i--)
283 if(grabs[i].handler==func)
284 return grabs[i].holder;
285 return NULL;
289 /*}}}*/