]> git.decadent.org.uk Git - ion3.git/blob - ioncore/grab.c
aad2dfdf9b69057812a09c490fae8e37a05f98af
[ion3.git] / ioncore / grab.c
1 /*
2  * ion/ioncore/grab.c
3  * 
4  * Copyright (c) Lukas Schroeder 2002,
5  *               Tuomo Valkonen 2003-2007.
6  *
7  * Ion is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  */
12
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <sys/time.h>
16
17 #define XK_MISCELLANY
18 #include <X11/keysymdef.h>
19
20 #include "common.h"
21 #include "global.h"
22 #include "event.h"
23 #include "cursor.h"
24 #include "grab.h"
25
26
27 /*{{{ Definitions */
28
29
30 typedef struct _grab_status{
31     WRegion *holder;
32     GrabHandler *handler;
33     GrabKilledHandler *killedhandler;
34     Watch watch;
35     long eventmask;
36     long flags;
37     
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;
43
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;
49
50
51 /*}}}*/
52
53
54 /*{{{ do_grab/ungrab */
55
56
57 static void grab_kb_ptr(Window win, Window confine_to, int cursor, 
58                         long eventmask)
59 {
60     ioncore_g.input_mode=IONCORE_INPUTMODE_GRAB;
61     
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);
70 }
71
72
73 static void ungrab_kb_ptr()
74 {
75     XUngrabKeyboard(ioncore_g.dpy, CurrentTime);
76     XUngrabPointer(ioncore_g.dpy, CurrentTime);
77     
78     ioncore_g.input_mode=IONCORE_INPUTMODE_NORMAL;
79 }
80
81
82 /*}}}*/
83
84
85 /*{{{ Functions for installing grabs */
86
87
88 static void do_holder_remove(WRegion *holder, bool killed);
89
90
91 static void grab_watch_handler(Watch *w, Obj *obj)
92 {
93     do_holder_remove((WRegion*)obj, TRUE);
94 }
95
96
97 static void do_grab_install(GrabStatus *grab)
98 {
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;
103 }
104
105
106 void ioncore_grab_establish(WRegion *reg, GrabHandler *func, 
107                             GrabKilledHandler *kh,
108                             long eventmask)
109 {
110     assert((~eventmask)&(KeyPressMask|KeyReleaseMask));
111     
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         do_grab_install(current_grab);
123     }
124 }
125
126
127 /*}}}*/
128
129
130 /*{{{ Grab removal functions */
131
132
133 static void do_grab_remove()
134 {
135     current_grab=NULL;
136     ungrab_kb_ptr();
137     
138     while(idx_grab>0 && grabs[idx_grab-1].remove==TRUE){
139         watch_reset(&grabs[idx_grab-1].watch);
140         idx_grab--;
141     }
142     
143     assert(idx_grab>=0);
144     
145     if(idx_grab>0){
146         current_grab=&grabs[idx_grab-1];
147         do_grab_install(current_grab);
148     }
149 }
150
151
152 static void mark_for_removal(GrabStatus *grab, bool killed)
153 {
154     if(!grab->remove){
155         grab->remove=TRUE;
156         if(killed && grab->killedhandler!=NULL && grab->holder!=NULL)
157             grab->killedhandler(grab->holder);
158     }
159     
160     if(grabs[idx_grab-1].remove)
161         do_grab_remove();
162 }
163
164
165 static void do_holder_remove(WRegion *holder, bool killed)
166 {
167     int i;
168     
169     for(i=idx_grab-1; i>=0; i--){
170         if(grabs[i].holder==holder)
171             mark_for_removal(grabs+i, killed);
172     }
173 }
174
175
176 void ioncore_grab_holder_remove(WRegion *holder)
177 {
178     do_holder_remove(holder, FALSE);
179 }
180
181
182 void ioncore_grab_remove(GrabHandler *func)
183 {
184     int i;
185     for(i=idx_grab-1; i>=0; i--){
186         if(grabs[i].handler==func){
187             mark_for_removal(grabs+i, FALSE);
188             break;
189         }
190     }
191 }
192
193
194 /*}}}*/
195
196
197 /*{{{ Grab handler calling */
198
199
200 bool ioncore_handle_grabs(XEvent *ev)
201 {
202     GrabStatus *gr;
203     int gr_sqid;
204     
205     while(current_grab && current_grab->remove)
206         do_grab_remove();
207     
208     if(current_grab==NULL || current_grab->holder==NULL ||
209        current_grab->handler==NULL){
210         return FALSE;
211     }
212     
213     /* Escape key is harcoded to always kill active grab. */
214     if(ev->type==KeyPress && XLookupKeysym(&(ev->xkey), 0)==XK_Escape){
215         mark_for_removal(current_grab, TRUE);
216         return TRUE;
217     }
218     
219     if(ev->type!=KeyRelease && ev->type!=KeyPress)
220         return FALSE;
221     
222     /* We must check that the grab pointed to by current_grab still
223      * is the same grab and not already released or replaced by
224      * another grab.
225      */
226     gr=current_grab;
227     gr_sqid=gr->sqid;
228     if(gr->handler(gr->holder, ev) && gr->sqid==gr_sqid)
229         mark_for_removal(gr, FALSE);
230     
231     return TRUE;
232 }
233
234
235 /*}}}*/
236
237
238 /*{{{ Misc. */
239
240
241 bool ioncore_grab_held()
242 {
243     return idx_grab>0;
244 }
245
246
247 void ioncore_change_grab_cursor(int cursor)
248 {
249     if(current_grab!=NULL){
250         current_grab->cursor=cursor;
251         XChangeActivePointerGrab(ioncore_g.dpy, IONCORE_EVENTMASK_PTRGRAB,
252                                  ioncore_xcursor(cursor), CurrentTime);
253     }
254 }
255
256
257 void ioncore_grab_confine_to(Window confine_to)
258 {
259     if(current_grab!=NULL){
260         current_grab->confine_to=confine_to;
261         XGrabPointer(ioncore_g.dpy, region_root_of(current_grab->holder),
262                      True, IONCORE_EVENTMASK_PTRGRAB, GrabModeAsync, 
263                      GrabModeAsync, confine_to, 
264                      ioncore_xcursor(IONCORE_CURSOR_DEFAULT), 
265                      CurrentTime);
266     }
267 }
268
269
270 WRegion *ioncore_grab_get_holder()
271 {
272     if (ioncore_grab_held())
273         return grabs[idx_grab-1].holder;
274     return NULL;
275 }
276
277
278 WRegion *ioncore_grab_get_my_holder(GrabHandler *func)
279 {
280     int i;
281     for(i=idx_grab-1; i>=0; i--)
282         if(grabs[i].handler==func)
283             return grabs[i].holder;
284     return NULL;
285 }
286
287
288 /*}}}*/
289