4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
13 #include <libtu/objp.h>
14 #include <libmainloop/defer.h>
24 static void do_binding_grab_on_ungrab_on(const WRegion *reg,
25 const WBinding *binding,
26 const WBindmap *bindmap, bool grab)
28 Window win=region_xwindow(reg);
31 for(r=reg->bindings; r!=NULL; r=r->next){
32 if(r->bindmap==bindmap)
34 if(bindmap_lookup_binding(r->bindmap, binding->act, binding->state,
38 if(r==NULL && binding->area==0){
40 binding_grab_on(binding, win);
42 binding_ungrab_on(binding, win);
47 static void do_binding_grab_on_ungrab_ons(const WRegion *reg,
48 const WBindmap *bindmap,
52 WBinding *binding=NULL;
54 if(!(reg->flags®ION_BINDINGS_ARE_GRABBED) ||
55 bindmap->bindings==NULL){
59 FOR_ALL_BINDINGS(binding, node, bindmap->bindings){
60 do_binding_grab_on_ungrab_on(reg, binding, bindmap, grab);
65 static void grab_ungrabbed_bindings(const WRegion *reg, const WBindmap *bindmap)
67 do_binding_grab_on_ungrab_ons(reg, bindmap, TRUE);
71 static void ungrab_freed_bindings(const WRegion *reg, const WBindmap *bindmap)
73 do_binding_grab_on_ungrab_ons(reg, bindmap, FALSE);
77 void rbind_binding_added(const WRegBindingInfo *rbind,
78 const WBinding *binding,
79 const WBindmap *bindmap)
81 if(binding->area==0 && rbind->reg->flags®ION_BINDINGS_ARE_GRABBED)
82 do_binding_grab_on_ungrab_on(rbind->reg, binding, rbind->bindmap, TRUE);
86 void rbind_binding_removed(const WRegBindingInfo *rbind,
87 const WBinding *binding,
88 const WBindmap *bindmap)
90 if(binding->area==0 && rbind->reg->flags®ION_BINDINGS_ARE_GRABBED)
91 do_binding_grab_on_ungrab_on(rbind->reg, binding, rbind->bindmap, FALSE);
101 static WRegBindingInfo *find_rbind(WRegion *reg, WBindmap *bindmap,
104 WRegBindingInfo *rbind;
106 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
107 if(rbind->bindmap==bindmap && rbind->owner==owner)
121 static WRegBindingInfo *region_do_add_bindmap_owned(WRegion *reg,
126 WRegBindingInfo *rbind;
131 rbind=ALLOC(WRegBindingInfo);
136 rbind->bindmap=bindmap;
141 LINK_ITEM(bindmap->rbind_list, rbind, bm_next, bm_prev);
143 if(region_xwindow(reg)!=None && !(reg->flags®ION_GRAB_ON_PARENT))
144 grab_ungrabbed_bindings(reg, bindmap);
146 /* Link to reg's rbind list*/ {
147 WRegBindingInfo *b=reg->bindings;
149 LINK_ITEM_FIRST(b, rbind, next, prev);
151 LINK_ITEM_LAST(b, rbind, next, prev);
160 bool region_add_bindmap(WRegion *reg, WBindmap *bindmap)
162 if(find_rbind(reg, bindmap, NULL)!=NULL)
164 return (region_do_add_bindmap_owned(reg, bindmap, NULL, TRUE)!=NULL);
168 static void remove_rbind(WRegion *reg, WRegBindingInfo *rbind)
170 UNLINK_ITEM(rbind->bindmap->rbind_list, rbind, bm_next, bm_prev);
172 /* Unlink from reg's rbind list*/ {
173 WRegBindingInfo *b=reg->bindings;
174 UNLINK_ITEM(b, rbind, next, prev);
178 if(region_xwindow(reg)!=None && !(reg->flags®ION_GRAB_ON_PARENT))
179 ungrab_freed_bindings(reg, rbind->bindmap);
185 void region_remove_bindmap(WRegion *reg, WBindmap *bindmap)
187 WRegBindingInfo *rbind=find_rbind(reg, bindmap, NULL);
189 remove_rbind(reg, rbind);
193 void region_remove_bindings(WRegion *reg)
195 WRegBindingInfo *rbind;
197 while((rbind=(WRegBindingInfo*)reg->bindings)!=NULL)
198 remove_rbind(reg, rbind);
202 WBinding *region_lookup_keybinding(WRegion *reg, const XKeyEvent *ev,
203 const WSubmapState *sc,
204 WRegion **binding_owner_ret)
206 WRegBindingInfo *rbind=NULL;
207 WBinding *binding=NULL;
208 const WSubmapState *s=NULL;
209 WBindmap *bindmap=NULL;
212 *binding_owner_ret=reg;
214 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
215 bindmap=rbind->bindmap;
217 for(s=sc; s!=NULL && bindmap!=NULL; s=s->next){
218 binding=bindmap_lookup_binding(bindmap, BINDING_KEYPRESS, s->state, s->key);
225 bindmap=binding->submap;
229 /* There may be no next iteration so we must reset binding here
230 * because we have not found a proper binding.
236 binding=bindmap_lookup_binding(bindmap, BINDING_KEYPRESS, ev->state, ev->keycode);
242 if(binding!=NULL && rbind->owner!=NULL)
243 *binding_owner_ret=rbind->owner;
249 WBinding *region_lookup_binding(WRegion *reg, int act, uint state,
252 WRegBindingInfo *rbind;
253 WBinding *binding=NULL;
255 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next){
256 if(rbind->owner!=NULL)
258 binding=bindmap_lookup_binding_area(rbind->bindmap, act, state, kcb, area);
273 static void add_bindings(WRegion *reg, WRegion *r2)
275 WRegion *rx=REGION_MANAGER(r2);
276 WRegBindingInfo *rbind, *rb2;
277 WBinding *binding=NULL;
279 if(rx!=NULL && REGION_PARENT_REG(rx)==reg){
280 /* The recursion is here to get the bindmaps correctly ordered. */
281 add_bindings(reg, rx);
284 if(r2->flags®ION_GRAB_ON_PARENT){
285 for(rb2=(WRegBindingInfo*)r2->bindings; rb2!=NULL; rb2=rb2->next){
286 rbind=find_rbind(reg, rb2->bindmap, r2);
288 rbind=region_do_add_bindmap_owned(reg, rb2->bindmap,
298 void region_do_update_owned_grabs(WRegion *reg)
300 WRegBindingInfo *rbind, *rb2;
302 reg->flags&=~REGION_BINDING_UPDATE_SCHEDULED;
305 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rbind->next)
309 if(reg->active_sub!=NULL)
310 add_bindings(reg, reg->active_sub);
312 /* remove old grabs */
313 for(rbind=(WRegBindingInfo*)reg->bindings; rbind!=NULL; rbind=rb2){
315 if(rbind->tmp!=1 && rbind->owner!=NULL)
316 remove_rbind(reg, rbind);
320 void region_update_owned_grabs(WRegion *reg)
322 if(reg->flags®ION_BINDING_UPDATE_SCHEDULED
323 || OBJ_IS_BEING_DESTROYED(reg)
324 || ioncore_g.opmode==IONCORE_OPMODE_DEINIT){
328 if(mainloop_defer_action((Obj*)reg,
329 (WDeferredAction*)region_do_update_owned_grabs)){
330 reg->flags|=REGION_BINDING_UPDATE_SCHEDULED;
332 region_do_update_owned_grabs(reg);