]> git.decadent.org.uk Git - ion3.git/blob - ioncore/regbind.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / regbind.c
1 /*
2  * ion/regbind.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2009. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10 #include <libtu/objp.h>
11 #include <libmainloop/defer.h>
12 #include "common.h"
13 #include "region.h"
14 #include "binding.h"
15 #include "regbind.h"
16
17
18 /*{{{ Grab/ungrab */
19
20
21 static void do_binding_grab_on_ungrab_on(const WRegion *reg, 
22                                          const WBinding *binding,
23                                          const WBindmap *bindmap, bool grab)
24 {
25     Window win=region_xwindow(reg);
26     WRegBindingInfo *r;
27     
28     for(r=reg->bindings; r!=NULL; r=r->next){
29         if(r->bindmap==bindmap)
30             continue;
31         if(bindmap_lookup_binding(r->bindmap, binding->act, binding->state,
32                                   binding->kcb)!=NULL)
33             break;
34     }
35     if(r==NULL && binding->area==0){
36         if(grab)
37             binding_grab_on(binding, win);
38         else
39             binding_ungrab_on(binding, win);
40     }
41 }
42
43
44 static void do_binding_grab_on_ungrab_ons(const WRegion *reg, 
45                                           const WBindmap *bindmap,
46                                           bool grab)
47 {
48     Rb_node node=NULL;
49     WBinding *binding=NULL;
50     
51     if(!(reg->flags&REGION_BINDINGS_ARE_GRABBED) ||
52        bindmap->bindings==NULL){
53         return;
54     }
55     
56     FOR_ALL_BINDINGS(binding, node, bindmap->bindings){
57         do_binding_grab_on_ungrab_on(reg, binding, bindmap, grab);
58     }
59 }
60
61
62 static void grab_ungrabbed_bindings(const WRegion *reg, const WBindmap *bindmap)
63 {
64     do_binding_grab_on_ungrab_ons(reg, bindmap, TRUE);
65 }
66
67
68 static void ungrab_freed_bindings(const WRegion *reg, const WBindmap *bindmap)
69 {
70     do_binding_grab_on_ungrab_ons(reg, bindmap, FALSE);
71 }
72
73
74 void rbind_binding_added(const WRegBindingInfo *rbind, 
75                          const WBinding *binding,
76                          const WBindmap *bindmap)
77 {
78     if(binding->area==0 && rbind->reg->flags&REGION_BINDINGS_ARE_GRABBED)
79         do_binding_grab_on_ungrab_on(rbind->reg, binding, rbind->bindmap, TRUE);
80 }
81
82
83 void rbind_binding_removed(const WRegBindingInfo *rbind, 
84                            const WBinding *binding,
85                            const WBindmap *bindmap)
86 {
87     if(binding->area==0 && rbind->reg->flags&REGION_BINDINGS_ARE_GRABBED)
88         do_binding_grab_on_ungrab_on(rbind->reg, binding, rbind->bindmap, FALSE);
89 }
90
91
92 /*}}}*/
93
94
95 /*{{{ Find */
96
97
98 static WRegBindingInfo *find_rbind(WRegion *reg, WBindmap *bindmap,
99                                    WRegion *owner)
100 {
101     WRegBindingInfo *rbind;
102     
103     for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
104         if(rbind->bindmap==bindmap && rbind->owner==owner)
105             return rbind;
106     }
107     
108     return NULL;
109 }
110
111
112 /*}}}*/
113
114
115 /*{{{ Interface */
116
117
118 static WRegBindingInfo *region_do_add_bindmap_owned(WRegion *reg, 
119                                                     WBindmap *bindmap, 
120                                                     WRegion *owner,
121                                                     bool first)
122 {
123     WRegBindingInfo *rbind;
124     
125     if(bindmap==NULL)
126         return NULL;
127     
128     rbind=ALLOC(WRegBindingInfo);
129     
130     if(rbind==NULL)
131         return NULL;
132     
133     rbind->bindmap=bindmap;
134     rbind->owner=owner;
135     rbind->reg=reg;
136     rbind->tmp=0;
137     
138     LINK_ITEM(bindmap->rbind_list, rbind, bm_next, bm_prev);
139
140     if(region_xwindow(reg)!=None && !(reg->flags&REGION_GRAB_ON_PARENT))
141         grab_ungrabbed_bindings(reg, bindmap);
142     
143     /* Link to reg's rbind list*/ {
144         WRegBindingInfo *b=reg->bindings;
145         if(first){
146             LINK_ITEM_FIRST(b, rbind, next, prev);
147         }else{
148             LINK_ITEM_LAST(b, rbind, next, prev);
149         }
150         reg->bindings=b;
151     }
152     
153     return rbind;
154 }
155
156
157 bool region_add_bindmap(WRegion *reg, WBindmap *bindmap)
158 {
159     if(find_rbind(reg, bindmap, NULL)!=NULL)
160         return FALSE;
161     return (region_do_add_bindmap_owned(reg, bindmap, NULL, TRUE)!=NULL);
162 }
163
164
165 static void remove_rbind(WRegion *reg, WRegBindingInfo *rbind)
166 {
167     UNLINK_ITEM(rbind->bindmap->rbind_list, rbind, bm_next, bm_prev);
168     
169     /* Unlink from reg's rbind list*/ {
170         WRegBindingInfo *b=reg->bindings;
171         UNLINK_ITEM(b, rbind, next, prev);
172         reg->bindings=b;
173     }
174     
175     if(region_xwindow(reg)!=None && !(reg->flags&REGION_GRAB_ON_PARENT))
176         ungrab_freed_bindings(reg, rbind->bindmap);
177
178     free(rbind);
179 }
180
181
182 void region_remove_bindmap(WRegion *reg, WBindmap *bindmap)
183 {
184     WRegBindingInfo *rbind=find_rbind(reg, bindmap, NULL);
185     if(rbind!=NULL)
186         remove_rbind(reg, rbind);
187 }
188
189
190 void region_remove_bindings(WRegion *reg)
191 {
192     WRegBindingInfo *rbind;
193     
194     while((rbind=(WRegBindingInfo*)reg->bindings)!=NULL)
195         remove_rbind(reg, rbind);
196 }
197
198
199 WBinding *region_lookup_keybinding(WRegion *reg, 
200                                    int act, uint state, uint kcb, 
201                                    const WSubmapState *sc,
202                                    WRegion **binding_owner_ret)
203 {
204     WRegBindingInfo *rbind=NULL;
205     WBinding *binding=NULL;
206     const WSubmapState *s=NULL;
207     WBindmap *bindmap=NULL;
208     int i;
209     
210     *binding_owner_ret=reg;
211
212     for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
213         bindmap=rbind->bindmap;
214         
215         for(s=sc; s!=NULL && bindmap!=NULL; s=s->next){
216             binding=bindmap_lookup_binding(bindmap, BINDING_KEYPRESS, s->state, s->key);
217
218             if(binding==NULL){
219                 bindmap=NULL;
220                 break;
221             }
222             
223             bindmap=binding->submap;
224         }
225         
226         if(bindmap==NULL){
227             /* There may be no next iteration so we must reset binding here
228              * because we have not found a proper binding.
229              */
230             binding=NULL;
231             continue;
232         }
233
234         binding=bindmap_lookup_binding(bindmap, act, state, kcb);
235         
236         if(binding!=NULL)
237             break;
238     }
239     
240     if(binding!=NULL && rbind->owner!=NULL)
241         *binding_owner_ret=rbind->owner;
242     
243     return binding;
244 }
245
246
247 WBinding *region_lookup_binding(WRegion *reg, int act, uint state,
248                                 uint kcb, int area)
249 {
250     WRegBindingInfo *rbind;
251     WBinding *binding=NULL;
252     
253     for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
254         if(rbind->owner!=NULL)
255             continue;
256         binding=bindmap_lookup_binding_area(rbind->bindmap, act, state, kcb, area);
257         if(binding!=NULL)
258             break;
259     }
260     
261     return binding;
262 }
263
264
265 /*}}}*/
266
267
268 /*{{{ Update */
269
270
271 static void add_bindings(WRegion *reg, WRegion *r2)
272 {
273     WRegion *rx=REGION_MANAGER(r2);
274     WRegBindingInfo *rbind, *rb2;
275     WBinding *binding=NULL;
276     
277     if(rx!=NULL && REGION_PARENT_REG(rx)==reg){
278         /* The recursion is here to get the bindmaps correctly ordered. */
279         add_bindings(reg, rx);
280     }
281     
282     if(r2->flags&REGION_GRAB_ON_PARENT){
283         for(rb2=(WRegBindingInfo*)r2->bindings; rb2!=NULL; rb2=rb2->next){
284             rbind=find_rbind(reg, rb2->bindmap, r2);
285             if(rbind==NULL){
286                 rbind=region_do_add_bindmap_owned(reg, rb2->bindmap, 
287                                                   r2, TRUE);
288             }
289             if(rbind!=NULL)
290                 rbind->tmp=1;
291         }
292     }
293 }
294
295
296 void region_do_update_owned_grabs(WRegion *reg)
297 {
298     WRegBindingInfo *rbind, *rb2;
299
300     reg->flags&=~REGION_BINDING_UPDATE_SCHEDULED;
301     
302     /* clear flags */
303     for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next)
304         rbind->tmp=0;
305     
306     /* make new grabs */
307     if(reg->active_sub!=NULL)
308         add_bindings(reg, reg->active_sub);
309     
310     /* remove old grabs */
311     for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rb2){
312         rb2=rbind->next;
313         if(rbind->tmp!=1 && rbind->owner!=NULL)
314             remove_rbind(reg, rbind);
315     }
316 }
317
318 void region_update_owned_grabs(WRegion *reg)
319 {
320     if(reg->flags&REGION_BINDING_UPDATE_SCHEDULED 
321        || OBJ_IS_BEING_DESTROYED(reg)
322        || ioncore_g.opmode==IONCORE_OPMODE_DEINIT){
323         return;
324     }
325     
326     if(mainloop_defer_action((Obj*)reg, 
327                              (WDeferredAction*)region_do_update_owned_grabs)){
328         reg->flags|=REGION_BINDING_UPDATE_SCHEDULED;
329     }else{
330         region_do_update_owned_grabs(reg);
331     }
332 }
333
334
335 /*}}}*/