2 * ion/ioncore/binding.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * See the included file LICENSE for details.
14 #include <libtu/objp.h>
16 #include <libextl/extl.h>
19 #ifndef CF_NO_LOCK_HACK
20 #define CF_HACK_IGNORE_EVIL_LOCKS
23 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
25 #include <X11/keysymdef.h>
34 static const uint modmasks[N_MODS]={
35 ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask,
39 static XModifierKeymap *modmap=NULL;
41 #define KNOWN_MODIFIERS_MASK (ShiftMask|LockMask|ControlMask|Mod1Mask|\
42 Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
44 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
47 #define N_LOOKUPEVIL 2
49 static uint evillockmasks[N_EVILLOCKS]={
53 static const KeySym evillocks[N_LOOKUPEVIL]={
54 XK_Num_Lock, XK_Scroll_Lock
57 static uint evilignoremask=LockMask;
59 static void lookup_evil_locks();
61 static void evil_grab_key(Display *display, uint keycode, uint modifiers,
62 Window grab_window, bool owner_events,
63 int pointer_mode, int keyboard_mode);
65 static void evil_grab_button(Display *display, uint button, uint modifiers,
66 Window grab_window, bool owner_events,
67 uint event_mask, int pointer_mode,
68 int keyboard_mode, Window confine_to,
71 static void evil_ungrab_key(Display *display, uint keycode, uint modifiers,
74 static void evil_ungrab_button(Display *display, uint button, uint modifiers,
80 #define CVAL(A, B, V) ( A->V < B->V ? -1 : (A->V > B->V ? 1 : 0))
82 static int compare_bindings(const WBinding *a, const WBinding *b)
84 int r=CVAL(a, b, act);
97 /* This is only used for searching AnyKey etc. */
98 static int compare_bindings_ksb(const WBinding *a, const WBinding *b)
100 int r=CVAL(a, b, act);
116 bool init_bindmap(WBindmap *bindmap)
118 bindmap->rbind_list=NULL;
119 bindmap->areamap=NULL;
120 bindmap->nbindings=0;
121 bindmap->bindings=make_rb();
122 if(bindmap->bindings==NULL){
130 WBindmap *create_bindmap()
132 WBindmap *bindmap=ALLOC(WBindmap);
139 if(!init_bindmap(bindmap)){
148 void binding_deinit(WBinding *binding)
150 if(binding->submap!=NULL){
151 bindmap_destroy(binding->submap);
152 binding->submap=NULL;
155 binding->func=extl_unref_fn(binding->func);
159 static void do_destroy_binding(WBinding *binding)
161 assert(binding!=NULL);
162 binding_deinit(binding);
167 static void bindmap_deinit(WBindmap *bindmap)
172 while(bindmap->rbind_list!=NULL){
173 region_remove_bindmap(bindmap->rbind_list->reg,
177 if(bindmap->bindings==NULL)
180 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
181 do_destroy_binding((WBinding*)rb_val(node));
182 bindmap->nbindings--;
185 assert(bindmap->nbindings==0);
187 rb_free_tree(bindmap->bindings);
188 bindmap->bindings=NULL;
192 void bindmap_destroy(WBindmap *bindmap)
194 bindmap_deinit(bindmap);
199 static void free_map(Rb_node map)
204 FOR_ALL_BINDINGS(b, node, map)
211 void bindmap_refresh(WBindmap *bindmap)
213 WRegBindingInfo *rbind;
214 Rb_node newtree, node;
217 if(bindmap->bindings==NULL)
227 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
237 if(b->act==BINDING_KEYPRESS){
238 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
239 rbind_binding_removed(rbind, b, bindmap);
240 b2->kcb=XKeysymToKeycode(ioncore_g.dpy, b->ksb);
243 if(!rb_insertg(newtree, b2, b2, (Rb_compfn*)compare_bindings)){
251 free_map(bindmap->bindings);
252 bindmap->bindings=newtree;
254 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
255 if(b->act!=BINDING_KEYPRESS)
257 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
258 rbind_binding_added(rbind, b, bindmap);
260 bindmap_refresh(b->submap);
265 bool bindmap_add_binding(WBindmap *bindmap, const WBinding *b)
267 WRegBindingInfo *rbind=NULL;
268 WBinding *binding=NULL;
272 /* Handle adding the binding */
273 binding=ALLOC(WBinding);
280 memcpy(binding, b, sizeof(*b));
282 node=rb_find_gkey_n(bindmap->bindings, binding,
283 (Rb_compfn*)compare_bindings, &found);
286 if(!rb_insert_a(node, binding, binding)){
290 do_destroy_binding((WBinding*)rb_val(node));
291 rb_delete_node(node);
292 bindmap->nbindings--;
294 if(!rb_insertg(bindmap->bindings, binding, binding,
295 (Rb_compfn*)compare_bindings)){
301 bindmap->nbindings++;
303 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
304 rbind_binding_added(rbind, binding, bindmap);
310 bool bindmap_remove_binding(WBindmap *bindmap, const WBinding *b)
312 WRegBindingInfo *rbind=NULL;
313 WBinding *binding=NULL;
317 if(bindmap->bindings==NULL)
320 node=rb_find_gkey_n(bindmap->bindings, b, (Rb_compfn*)compare_bindings,
326 binding=(WBinding*)rb_val(node);
328 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
329 rbind_binding_removed(rbind, binding, bindmap);
331 do_destroy_binding(binding);
332 rb_delete_node(node);
334 bindmap->nbindings--;
340 void ioncore_init_bindings()
342 modmap=XGetModifierMapping(ioncore_g.dpy);
344 assert(modmap!=NULL);
346 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
352 void ioncore_update_modmap()
354 XModifierKeymap *nm=XGetModifierMapping(ioncore_g.dpy);
357 XFreeModifiermap(modmap);
366 void binding_grab_on(const WBinding *binding, Window win)
368 if(binding->act==BINDING_KEYPRESS && binding->kcb!=0){
369 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
370 XGrabKey(ioncore_g.dpy, binding->kcb, binding->state, win,
371 True, GrabModeAsync, GrabModeAsync);
373 evil_grab_key(ioncore_g.dpy, binding->kcb, binding->state, win,
374 True, GrabModeAsync, GrabModeAsync);
378 if(binding->act!=BINDING_BUTTONPRESS &&
379 binding->act!=BINDING_BUTTONCLICK &&
380 binding->act!=BINDING_BUTTONDBLCLICK &&
381 binding->act!=BINDING_BUTTONMOTION)
384 if(binding->state==0)
387 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
388 XGrabButton(ioncore_g.dpy, binding->kcb, binding->state, win,
389 True, IONCORE_EVENTMASK_PTRGRAB, GrabModeAsync, GrabModeAsync,
392 evil_grab_button(ioncore_g.dpy, binding->kcb, binding->state, win,
393 True, IONCORE_EVENTMASK_PTRGRAB, GrabModeAsync, GrabModeAsync,
399 void binding_ungrab_on(const WBinding *binding, Window win)
401 if(binding->act==BINDING_KEYPRESS){
402 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
403 XUngrabKey(ioncore_g.dpy, binding->kcb, binding->state, win);
405 evil_ungrab_key(ioncore_g.dpy, binding->kcb, binding->state, win);
409 if(binding->act!=BINDING_BUTTONPRESS &&
410 binding->act!=BINDING_BUTTONCLICK &&
411 binding->act!=BINDING_BUTTONDBLCLICK &&
412 binding->act!=BINDING_BUTTONMOTION)
415 if(binding->state==0)
418 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
419 XUngrabButton(ioncore_g.dpy, binding->kcb, binding->state, win);
421 evil_ungrab_button(ioncore_g.dpy, binding->kcb, binding->state, win);
429 static WBinding *search_binding(WBindmap *bindmap, WBinding *binding)
434 if(bindmap->bindings==NULL)
437 node=rb_find_gkey_n(bindmap->bindings, binding,
438 (Rb_compfn*)compare_bindings, &found);
443 return (WBinding*)rb_val(node);
447 static WBinding *search_binding_ksb(WBindmap *bindmap, WBinding *binding)
452 if(bindmap->bindings==NULL)
455 node=rb_find_gkey_n(bindmap->bindings, binding,
456 (Rb_compfn*)compare_bindings_ksb, &found);
461 return (WBinding*)rb_val(node);
465 static WBinding *do_bindmap_lookup_binding(WBindmap *bindmap,
469 WBinding *binding, tmp;
471 if(bindmap->nbindings==0)
474 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
475 state&=~evilignoremask;
477 state&=KNOWN_MODIFIERS_MASK;
484 binding=search_binding(bindmap, &tmp);
486 if(BINDING_IS_PSEUDO(act)){
487 /* No use trying anything else */
492 tmp.state=AnyModifier;
493 binding=search_binding(bindmap, &tmp);
497 tmp.ksb=(act==BINDING_KEYPRESS ? AnyKey : AnyButton);
499 binding=search_binding_ksb(bindmap, &tmp);
502 tmp.state=AnyModifier;
503 binding=search_binding_ksb(bindmap, &tmp);
512 WBinding *bindmap_lookup_binding(WBindmap *bindmap,
513 int act, uint state, uint kcb)
515 return do_bindmap_lookup_binding(bindmap, act, state, kcb, 0);
519 WBinding *bindmap_lookup_binding_area(WBindmap *bindmap,
520 int act, uint state, uint kcb, int area)
524 binding=do_bindmap_lookup_binding(bindmap, act, state, kcb, area);
527 binding=do_bindmap_lookup_binding(bindmap, act, state, kcb, 0);
534 * A dirty hack to deal with (==ignore) evil locking modifier keys.
538 int ioncore_unmod(int state, int keycode)
542 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
543 state&=~evilignoremask;
546 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
547 if(modmap->modifiermap[j]==keycode)
548 return state&~modmasks[j/modmap->max_keypermod];
555 int ioncore_modstate()
561 XQueryKeymap(ioncore_g.dpy, keys);
563 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
564 int a=(modmap->modifiermap[j]&7);
565 int b=(modmap->modifiermap[j]>>3);
568 state|=modmasks[j/modmap->max_keypermod];
572 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
573 state&=~evilignoremask;
579 bool ioncore_ismod(int keycode)
583 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
584 if(modmap->modifiermap[j]==keycode)
592 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
594 static void lookup_evil_locks()
596 uint keycodes[N_LOOKUPEVIL];
599 for(i=0; i<N_LOOKUPEVIL; i++)
600 keycodes[i]=XKeysymToKeycode(ioncore_g.dpy, evillocks[i]);
602 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
603 for(i=0; i<N_LOOKUPEVIL; i++){
604 if(keycodes[i]==None)
606 if(modmap->modifiermap[j]==keycodes[i]){
607 evillockmasks[i]=modmasks[j/modmap->max_keypermod];
608 evilignoremask|=evillockmasks[i];
615 static void evil_grab_key(Display *display, uint keycode, uint modifiers,
616 Window grab_window, bool owner_events,
617 int pointer_mode, int keyboard_mode)
622 XGrabKey(display, keycode, modifiers, grab_window, owner_events,
623 pointer_mode, keyboard_mode);
625 if(modifiers==AnyModifier)
628 for(i=0; i<N_EVILLOCKS; i++){
629 if(evillockmasks[i]==0)
632 for(j=i; j<N_EVILLOCKS; j++){
633 if(evillockmasks[j]==0)
635 mods|=evillockmasks[j];
636 XGrabKey(display, keycode, mods,
637 grab_window, owner_events, pointer_mode, keyboard_mode);
640 XGrabKey(display, keycode,
641 modifiers|evillockmasks[i]|evillockmasks[j],
642 grab_window, owner_events, pointer_mode, keyboard_mode);
648 static void evil_grab_button(Display *display, uint button, uint modifiers,
649 Window grab_window, bool owner_events,
650 uint event_mask, int pointer_mode,
651 int keyboard_mode, Window confine_to,
657 XGrabButton(display, button, modifiers,
658 grab_window, owner_events, event_mask, pointer_mode,
659 keyboard_mode, confine_to, cursor);
661 if(modifiers==AnyModifier)
664 for(i=0; i<N_EVILLOCKS; i++){
665 if(evillockmasks[i]==0)
668 for(j=i; j<N_EVILLOCKS; j++){
669 if(evillockmasks[j]==0)
671 mods|=evillockmasks[j];
672 XGrabButton(display, button, mods,
673 grab_window, owner_events, event_mask, pointer_mode,
674 keyboard_mode, confine_to, cursor);
677 XGrabButton(display, button,
678 modifiers|evillockmasks[i]|evillockmasks[j],
679 grab_window, owner_events, event_mask, pointer_mode,
680 keyboard_mode, confine_to, cursor);
686 static void evil_ungrab_key(Display *display, uint keycode, uint modifiers,
692 XUngrabKey(display, keycode, modifiers, grab_window);
694 if(modifiers==AnyModifier)
697 for(i=0; i<N_EVILLOCKS; i++){
698 if(evillockmasks[i]==0)
701 for(j=i; j<N_EVILLOCKS; j++){
702 if(evillockmasks[j]==0)
704 mods|=evillockmasks[j];
705 XUngrabKey(display, keycode, mods, grab_window);
708 XUngrabKey(display, keycode,
709 modifiers|evillockmasks[i]|evillockmasks[j],
716 static void evil_ungrab_button(Display *display, uint button, uint modifiers,
722 XUngrabButton(display, button, modifiers, grab_window);
724 if(modifiers==AnyModifier)
727 for(i=0; i<N_EVILLOCKS; i++){
728 if(evillockmasks[i]==0)
731 for(j=i; j<N_EVILLOCKS; j++){
732 if(evillockmasks[j]==0)
734 mods|=evillockmasks[j];
735 XUngrabButton(display, button, mods, grab_window);
738 XUngrabButton(display, button,
739 modifiers|evillockmasks[i]|evillockmasks[j],
746 #endif /* CF_HACK_IGNORE_EVIL_LOCKS */