Update contrib
[notion/jeffpc.git] / ioncore / regbind.c
bloba50da9d0af871c38a33414eec69b837b2173bed7
1 /*
2 * ion/regbind.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
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"
18 /*{{{ Grab/ungrab */
21 static void do_binding_grab_on_ungrab_on(const WRegion *reg,
22 const WBinding *binding,
23 const WBindmap *bindmap, bool grab)
25 Window win=region_xwindow(reg);
26 WRegBindingInfo *r;
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;
35 if(r==NULL && binding->area==0){
36 if(grab)
37 binding_grab_on(binding, win);
38 else
39 binding_ungrab_on(binding, win);
44 static void do_binding_grab_on_ungrab_ons(const WRegion *reg,
45 const WBindmap *bindmap,
46 bool grab)
48 Rb_node node=NULL;
49 WBinding *binding=NULL;
51 if(!(reg->flags&REGION_BINDINGS_ARE_GRABBED) ||
52 bindmap->bindings==NULL){
53 return;
56 FOR_ALL_BINDINGS(binding, node, bindmap->bindings){
57 do_binding_grab_on_ungrab_on(reg, binding, bindmap, grab);
62 static void grab_ungrabbed_bindings(const WRegion *reg, const WBindmap *bindmap)
64 do_binding_grab_on_ungrab_ons(reg, bindmap, TRUE);
68 static void ungrab_freed_bindings(const WRegion *reg, const WBindmap *bindmap)
70 do_binding_grab_on_ungrab_ons(reg, bindmap, FALSE);
74 void rbind_binding_added(const WRegBindingInfo *rbind,
75 const WBinding *binding,
76 const WBindmap *bindmap)
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);
83 void rbind_binding_removed(const WRegBindingInfo *rbind,
84 const WBinding *binding,
85 const WBindmap *bindmap)
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);
92 /*}}}*/
95 /*{{{ Find */
98 static WRegBindingInfo *find_rbind(WRegion *reg, WBindmap *bindmap,
99 WRegion *owner)
101 WRegBindingInfo *rbind;
103 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
104 if(rbind->bindmap==bindmap && rbind->owner==owner)
105 return rbind;
108 return NULL;
112 /*}}}*/
115 /*{{{ Interface */
118 static WRegBindingInfo *region_do_add_bindmap_owned(WRegion *reg,
119 WBindmap *bindmap,
120 WRegion *owner,
121 bool first)
123 WRegBindingInfo *rbind;
125 if(bindmap==NULL)
126 return NULL;
128 rbind=ALLOC(WRegBindingInfo);
130 if(rbind==NULL)
131 return NULL;
133 rbind->bindmap=bindmap;
134 rbind->owner=owner;
135 rbind->reg=reg;
136 rbind->tmp=0;
138 LINK_ITEM(bindmap->rbind_list, rbind, bm_next, bm_prev);
140 if(region_xwindow(reg)!=None && !(reg->flags&REGION_GRAB_ON_PARENT))
141 grab_ungrabbed_bindings(reg, bindmap);
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);
150 reg->bindings=b;
153 return rbind;
157 bool region_add_bindmap(WRegion *reg, WBindmap *bindmap)
159 if(find_rbind(reg, bindmap, NULL)!=NULL)
160 return FALSE;
161 return (region_do_add_bindmap_owned(reg, bindmap, NULL, TRUE)!=NULL);
165 static void remove_rbind(WRegion *reg, WRegBindingInfo *rbind)
167 UNLINK_ITEM(rbind->bindmap->rbind_list, rbind, bm_next, bm_prev);
169 /* Unlink from reg's rbind list*/ {
170 WRegBindingInfo *b=reg->bindings;
171 UNLINK_ITEM(b, rbind, next, prev);
172 reg->bindings=b;
175 if(region_xwindow(reg)!=None && !(reg->flags&REGION_GRAB_ON_PARENT))
176 ungrab_freed_bindings(reg, rbind->bindmap);
178 free(rbind);
182 void region_remove_bindmap(WRegion *reg, WBindmap *bindmap)
184 WRegBindingInfo *rbind=find_rbind(reg, bindmap, NULL);
185 if(rbind!=NULL)
186 remove_rbind(reg, rbind);
190 void region_remove_bindings(WRegion *reg)
192 WRegBindingInfo *rbind;
194 while((rbind=(WRegBindingInfo*)reg->bindings)!=NULL)
195 remove_rbind(reg, rbind);
199 WBinding *region_lookup_keybinding(WRegion *reg,
200 int act, uint state, uint kcb,
201 const WSubmapState *sc,
202 WRegion **binding_owner_ret)
204 WRegBindingInfo *rbind=NULL;
205 WBinding *binding=NULL;
206 const WSubmapState *s=NULL;
207 WBindmap *bindmap=NULL;
208 int i;
210 *binding_owner_ret=reg;
212 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
213 bindmap=rbind->bindmap;
215 for(s=sc; s!=NULL && bindmap!=NULL; s=s->next){
216 binding=bindmap_lookup_binding(bindmap, BINDING_KEYPRESS, s->state, s->key);
218 if(binding==NULL){
219 bindmap=NULL;
220 break;
223 bindmap=binding->submap;
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.
230 binding=NULL;
231 continue;
234 binding=bindmap_lookup_binding(bindmap, act, state, kcb);
236 if(binding!=NULL)
237 break;
240 if(binding!=NULL && rbind->owner!=NULL)
241 *binding_owner_ret=rbind->owner;
243 return binding;
247 WBinding *region_lookup_binding(WRegion *reg, int act, uint state,
248 uint kcb, int area)
250 WRegBindingInfo *rbind;
251 WBinding *binding=NULL;
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;
261 return binding;
265 /*}}}*/
268 /*{{{ Update */
271 static void add_bindings(WRegion *reg, WRegion *r2)
273 WRegion *rx=REGION_MANAGER(r2);
274 WRegBindingInfo *rbind, *rb2;
275 WBinding *binding=NULL;
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);
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);
289 if(rbind!=NULL)
290 rbind->tmp=1;
296 void region_do_update_owned_grabs(WRegion *reg)
298 WRegBindingInfo *rbind, *rb2;
300 reg->flags&=~REGION_BINDING_UPDATE_SCHEDULED;
302 /* clear flags */
303 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next)
304 rbind->tmp=0;
306 /* make new grabs */
307 if(reg->active_sub!=NULL)
308 add_bindings(reg, reg->active_sub);
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);
318 void region_update_owned_grabs(WRegion *reg)
320 if(reg->flags&REGION_BINDING_UPDATE_SCHEDULED
321 || OBJ_IS_BEING_DESTROYED(reg)
322 || ioncore_g.opmode==IONCORE_OPMODE_DEINIT){
323 return;
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);
335 /*}}}*/