X-Git-Url: https://git.decadent.org.uk/gitweb/?p=ion3.git;a=blobdiff_plain;f=ioncore%2Fkey.c;h=8675b8ce475f4663fb0b89954d317a498ae90bac;hp=57ada801f313f85d8f3515f6611e638876e62a2c;hb=e3aec18706513a87eaa7839dfdaf7e0fcd0d8d2a;hpb=803afbc1cd633f6c025bcd9537e9b7e9aedadd0d diff --git a/ioncore/key.c b/ioncore/key.c index 57ada80..8675b8c 100644 --- a/ioncore/key.c +++ b/ioncore/key.c @@ -1,16 +1,17 @@ /* * ion/ioncore/key.c * - * Copyright (c) Tuomo Valkonen 1999-2007. + * Copyright (c) Tuomo Valkonen 1999-2009. * - * Ion is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * See the included file LICENSE for details. */ #include + #include +#include +#include + #include "common.h" #include "key.h" #include "binding.h" @@ -19,7 +20,6 @@ #include "cursor.h" #include "grab.h" #include "regbind.h" -#include #include "strings.h" #include "xwindow.h" @@ -97,9 +97,7 @@ void clientwin_quote_next(WClientWin *cwin) static bool waitrelease_handler(WRegion *reg, XEvent *ev) { - if(!ioncore_unmod(ev->xkey.state, ev->xkey.keycode)) - return TRUE; - return FALSE; + return (ioncore_unmod(ev->xkey.state, ev->xkey.keycode)==0); } @@ -120,29 +118,63 @@ static void waitrelease(WRegion *reg) } -static void free_subs(WSubmapState *p) +static void free_sub(WSubmapState *p) { - WSubmapState *next; + /*extl_unref_fn(p->leave); + watch_reset(&p->leave_reg); + */ - while(p!=NULL){ - next=p->next; - free(p); - p=next; + free(p); +} + + +void region_free_submapstat(WRegion *reg) +{ + while(reg->submapstat!=NULL){ + WSubmapState *p=reg->submapstat; + reg->submapstat=p->next; + free_sub(p); } } +WHook *ioncore_submap_ungrab_hook=NULL; + + +static void call_submap_ungrab_hook() +{ + hook_call_v(ioncore_submap_ungrab_hook); +} + + static void clear_subs(WRegion *reg) { - while(reg->submapstat!=NULL){ - WSubmapState *tmp=reg->submapstat; - reg->submapstat=tmp->next; - free(tmp); + region_free_submapstat(reg); + mainloop_defer_action(NULL, (WDeferredAction*)call_submap_ungrab_hook); +/* + while(reg!=NULL && reg->submapstat!=NULL){ + WSubmapState *p=reg->submapstat; + reg->submapstat=p->next; + + if(p->leave!=extl_fn_none() && p->leave_reg.obj!=NULL){ + Watch regw=WATCH_INIT; + + watch_setup(®w, (Obj*)reg, NULL); + + extl_call(p->leave, "o", NULL, p->leave_reg.obj); + + reg=(WRegion*)regw.obj; + + watch_reset(®w); + } + + free_sub(p); } +*/ } -static bool add_sub(WRegion *reg, uint key, uint state) +static WSubmapState *add_sub(WRegion *reg, uint key, uint state) { WSubmapState **p; WSubmapState *s; @@ -159,14 +191,16 @@ static bool add_sub(WRegion *reg, uint key, uint state) s=ALLOC(WSubmapState); if(s==NULL) - return FALSE; + return NULL; s->key=key; s->state=state; + /*s->leave=extl_fn_none(); + watch_init(&s->leave_reg);*/ *p=s; - return TRUE; + return s; } @@ -189,88 +223,159 @@ bool ioncore_current_key(uint *kcb, uint *state, bool *sub) } -/* Return value TRUE = grab needed */ -static bool do_key(WRegion *reg, XKeyEvent *ev) +enum{GRAB_NONE, GRAB_NONE_SUBMAP, GRAB_SUBMAP, GRAB_WAITRELEASE}; + + +static WBinding *lookup_binding_(WRegion *reg, + int act, uint state, uint kcb, + WSubmapState *st, + WRegion **binding_owner, WRegion **subreg) { - WBinding *binding=NULL; - WRegion *oreg=NULL, *binding_owner=NULL, *subreg=NULL; - bool grabbed; + WBinding *binding; - oreg=reg; - grabbed=(oreg->flags®ION_BINDINGS_ARE_GRABBED); + *subreg=NULL; - if(grabbed){ - /* Find the deepest nested active window grabbing this key. */ - while(reg->active_sub!=NULL) - reg=reg->active_sub; + do{ + binding=region_lookup_keybinding(reg, act, state, kcb, st, + binding_owner); - do{ - binding=region_lookup_keybinding(reg, ev, oreg->submapstat, - &binding_owner); + if(binding!=NULL) + break; - if(binding!=NULL) - break; - if(OBJ_IS(reg, WRootWin)) - break; - - subreg=reg; - reg=REGION_PARENT_REG(reg); - }while(reg!=NULL); + if(OBJ_IS(reg, WRootWin)) + break; + + *subreg=reg; + reg=REGION_PARENT_REG(reg); + }while(reg!=NULL); + + return binding; +} + +static WBinding *lookup_binding(WRegion *oreg, + int act, uint state, uint kcb, + WRegion **binding_owner, WRegion **subreg) +{ + WRegion *reg=oreg; + + /* Find the deepest nested active window grabbing this key. */ + while(reg->active_sub!=NULL) + reg=reg->active_sub; + + return lookup_binding_(reg, act, state, kcb, oreg->submapstat, + binding_owner, subreg); +} + + +static void do_call_binding(WBinding *binding, WRegion *reg, WRegion *subreg) +{ + WRegion *mgd=region_managed_within(reg, subreg); + + /* TODO: having to pass both mgd and subreg for some handlers + * to work is ugly and complex. + */ + extl_call(binding->func, "ooo", NULL, reg, mgd, subreg); +} + + +static int do_key(WRegion *oreg, XKeyEvent *ev) +{ + WBinding *binding=NULL; + WRegion *binding_owner=NULL, *subreg=NULL; + bool grabbed=(oreg->flags®ION_BINDINGS_ARE_GRABBED); + int ret=GRAB_NONE; + + if(grabbed){ + binding=lookup_binding(oreg, BINDING_KEYPRESS, ev->state, ev->keycode, + &binding_owner, &subreg); }else{ - binding=region_lookup_keybinding(oreg, ev, oreg->submapstat, + binding=region_lookup_keybinding(oreg, BINDING_KEYPRESS, + ev->state, ev->keycode, + oreg->submapstat, &binding_owner); } if(binding!=NULL){ + bool subs=(oreg->submapstat!=NULL); + WBinding *call=NULL; + if(binding->submap!=NULL){ - if(add_sub(oreg, ev->keycode, ev->state)) - return grabbed; - else - clear_subs(oreg); - }else if(binding_owner!=NULL){ - WRegion *mgd=region_managed_within(binding_owner, subreg); - bool subs=(oreg->submapstat!=NULL); - - clear_subs(oreg); + WSubmapState *s=add_sub(oreg, ev->keycode, ev->state); + if(s!=NULL){ + /*WRegion *own2, *subreg2; + + call=lookup_binding(binding_owner, BINDING_SUBMAP_LEAVE, 0, 0, + oreg->submapstat, &own2, &subreg2); + + if(call!=NULL){ + s->leave=extl_ref_fn(call->func); + watch_setup(&s->leave_reg, (Obj*)own2, NULL); + }*/ + + call=lookup_binding_(binding_owner, BINDING_SUBMAP_ENTER, 0, 0, + oreg->submapstat, + &binding_owner, &subreg); + + ret=(grabbed ? GRAB_SUBMAP : GRAB_NONE_SUBMAP); + } + }else{ + call=binding; if(grabbed) XUngrabKeyboard(ioncore_g.dpy, CurrentTime); + if(ev->state!=0 && !subs && binding->wait) + ret=GRAB_WAITRELEASE; + } + + if(call!=NULL){ current_kcb=ev->keycode; current_state=ev->state; current_submap=subs; - /* TODO: having to pass both mgd and subreg for some handlers - * to work is ugly and complex. - */ - extl_call(binding->func, "ooo", NULL, binding_owner, mgd, subreg); + do_call_binding(call, binding_owner, subreg); current_kcb=0; - - if(ev->state!=0 && !subs && binding->wait) - waitrelease(oreg); } - }else if(oreg->submapstat!=NULL){ - clear_subs(oreg); - }else if(OBJ_IS(oreg, WWindow)){ + }else if(oreg->submapstat==NULL && OBJ_IS(oreg, WWindow)){ insstr((WWindow*)oreg, ev); } - return FALSE; + return ret; } static bool submapgrab_handler(WRegion* reg, XEvent *xev) { XKeyEvent *ev=&xev->xkey; - if(ev->type!=KeyPress) + if(ev->type!=KeyPress){ + if(ioncore_unmod(ev->state, ev->keycode)==0){ + WBinding *binding; + WRegion *binding_owner, *subreg; + + binding=lookup_binding(reg, + BINDING_SUBMAP_RELEASEMOD, 0, 0, + &binding_owner, &subreg); + + if(binding!=NULL) + do_call_binding(binding, binding_owner, subreg); + } return FALSE; + } + if(ioncore_ismod(ev->keycode)) return FALSE; - return !do_key(reg, ev); + if(do_key(reg, ev)!=GRAB_SUBMAP){ + clear_subs(reg); + return TRUE; + }else{ + return FALSE; + } } + + static void submapgrab(WRegion *reg) { ioncore_grab_establish(reg, submapgrab_handler, clear_subs, 0); @@ -283,7 +388,27 @@ void ioncore_do_handle_keypress(XKeyEvent *ev) WRegion *reg=(WRegion*)XWINDOW_REGION_OF(ev->window); if(reg!=NULL){ - if(do_key(reg, ev)) - submapgrab(reg); + Watch w=WATCH_INIT; + int grab; + + /* reg might be destroyed by binding handlers */ + watch_setup(&w, (Obj*)reg, NULL); + + grab=do_key(reg, ev); + + reg=(WRegion*)w.obj; + + if(reg!=NULL){ + if(grab==GRAB_SUBMAP) + submapgrab(reg); + else if(grab==GRAB_WAITRELEASE) + waitrelease(reg); + else if(grab==GRAB_NONE_SUBMAP) + /* nothing */; + else if(grab==GRAB_NONE && reg->submapstat!=NULL) + clear_subs(reg); + } + + watch_reset(&w); } }