2 * ion/ioncore/binding.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
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_any(const WBinding *a, const WBinding *b)
100 int r=compare_bindings(a, b);
111 bool init_bindmap(WBindmap *bindmap)
113 bindmap->rbind_list=NULL;
114 bindmap->areamap=NULL;
115 bindmap->nbindings=0;
116 bindmap->bindings=make_rb();
117 if(bindmap->bindings==NULL){
125 WBindmap *create_bindmap()
127 WBindmap *bindmap=ALLOC(WBindmap);
134 if(!init_bindmap(bindmap)){
143 void binding_deinit(WBinding *binding)
145 if(binding->submap!=NULL){
146 bindmap_destroy(binding->submap);
147 binding->submap=NULL;
150 binding->func=extl_unref_fn(binding->func);
154 static void do_destroy_binding(WBinding *binding)
156 assert(binding!=NULL);
157 binding_deinit(binding);
162 static void bindmap_deinit(WBindmap *bindmap)
167 while(bindmap->rbind_list!=NULL){
168 region_remove_bindmap(bindmap->rbind_list->reg,
172 if(bindmap->bindings==NULL)
175 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
176 do_destroy_binding((WBinding*)rb_val(node));
177 bindmap->nbindings--;
180 assert(bindmap->nbindings==0);
182 rb_free_tree(bindmap->bindings);
183 bindmap->bindings=NULL;
187 void bindmap_destroy(WBindmap *bindmap)
189 bindmap_deinit(bindmap);
194 static void free_map(Rb_node map)
199 FOR_ALL_BINDINGS(b, node, map)
206 void bindmap_refresh(WBindmap *bindmap)
208 WRegBindingInfo *rbind;
209 Rb_node newtree, node;
212 if(bindmap->bindings==NULL)
222 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
232 if(b->act==BINDING_KEYPRESS){
233 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
234 rbind_binding_removed(rbind, b, bindmap);
235 b2->kcb=XKeysymToKeycode(ioncore_g.dpy, b->ksb);
238 if(!rb_insertg(newtree, b2, b2, (Rb_compfn*)compare_bindings)){
246 free_map(bindmap->bindings);
247 bindmap->bindings=newtree;
249 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
250 if(b->act!=BINDING_KEYPRESS)
252 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
253 rbind_binding_added(rbind, b, bindmap);
255 bindmap_refresh(b->submap);
260 bool bindmap_add_binding(WBindmap *bindmap, const WBinding *b)
262 WRegBindingInfo *rbind=NULL;
263 WBinding *binding=NULL;
267 /* Handle adding the binding */
268 binding=ALLOC(WBinding);
275 memcpy(binding, b, sizeof(*b));
277 node=rb_find_gkey_n(bindmap->bindings, binding,
278 (Rb_compfn*)compare_bindings, &found);
281 if(!rb_insert_a(node, binding, binding)){
285 do_destroy_binding((WBinding*)rb_val(node));
286 rb_delete_node(node);
287 bindmap->nbindings--;
289 if(!rb_insertg(bindmap->bindings, binding, binding,
290 (Rb_compfn*)compare_bindings)){
296 bindmap->nbindings++;
298 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
299 rbind_binding_added(rbind, binding, bindmap);
305 bool bindmap_remove_binding(WBindmap *bindmap, const WBinding *b)
307 WRegBindingInfo *rbind=NULL;
308 WBinding *binding=NULL;
312 if(bindmap->bindings==NULL)
315 node=rb_find_gkey_n(bindmap->bindings, b, (Rb_compfn*)compare_bindings,
321 binding=(WBinding*)rb_val(node);
323 for(rbind=bindmap->rbind_list; rbind!=NULL; rbind=rbind->bm_next)
324 rbind_binding_removed(rbind, binding, bindmap);
326 do_destroy_binding(binding);
327 rb_delete_node(node);
329 bindmap->nbindings--;
335 void ioncore_init_bindings()
337 modmap=XGetModifierMapping(ioncore_g.dpy);
339 assert(modmap!=NULL);
341 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
347 void ioncore_update_modmap()
349 XModifierKeymap *nm=XGetModifierMapping(ioncore_g.dpy);
352 XFreeModifiermap(modmap);
361 void binding_grab_on(const WBinding *binding, Window win)
363 if(binding->act==BINDING_KEYPRESS && binding->kcb!=0){
364 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
365 XGrabKey(ioncore_g.dpy, binding->kcb, binding->state, win,
366 True, GrabModeAsync, GrabModeAsync);
368 evil_grab_key(ioncore_g.dpy, binding->kcb, binding->state, win,
369 True, GrabModeAsync, GrabModeAsync);
373 if(binding->act!=BINDING_BUTTONPRESS &&
374 binding->act!=BINDING_BUTTONCLICK &&
375 binding->act!=BINDING_BUTTONDBLCLICK &&
376 binding->act!=BINDING_BUTTONMOTION)
379 if(binding->state==0 || binding->area!=0)
382 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
383 XGrabButton(ioncore_g.dpy, binding->kcb, binding->state, win,
384 True, IONCORE_EVENTMASK_PTRGRAB, GrabModeAsync, GrabModeAsync,
387 evil_grab_button(ioncore_g.dpy, binding->kcb, binding->state, win,
388 True, IONCORE_EVENTMASK_PTRGRAB, GrabModeAsync, GrabModeAsync,
394 void binding_ungrab_on(const WBinding *binding, Window win)
396 if(binding->act==BINDING_KEYPRESS && binding->kcb!=0){
397 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
398 XUngrabKey(ioncore_g.dpy, binding->kcb, binding->state, win);
400 evil_ungrab_key(ioncore_g.dpy, binding->kcb, binding->state, win);
404 if(binding->act!=BINDING_BUTTONPRESS &&
405 binding->act!=BINDING_BUTTONCLICK &&
406 binding->act!=BINDING_BUTTONDBLCLICK &&
407 binding->act!=BINDING_BUTTONMOTION)
410 if(binding->state==0 || binding->area!=0)
413 #ifndef CF_HACK_IGNORE_EVIL_LOCKS
414 XUngrabButton(ioncore_g.dpy, binding->kcb, binding->state, win);
416 evil_ungrab_button(ioncore_g.dpy, binding->kcb, binding->state, win);
424 static WBinding *search_binding(WBindmap *bindmap, WBinding *binding)
429 if(bindmap->bindings==NULL)
432 node=rb_find_gkey_n(bindmap->bindings, binding,
433 (Rb_compfn*)compare_bindings, &found);
438 return (WBinding*)rb_val(node);
442 static WBinding *search_binding_any(WBindmap *bindmap, WBinding *binding)
447 if(bindmap->bindings==NULL)
450 node=rb_find_gkey_n(bindmap->bindings, binding,
451 (Rb_compfn*)compare_bindings_any, &found);
456 return (WBinding*)rb_val(node);
460 static WBinding *do_bindmap_lookup_binding(WBindmap *bindmap,
464 WBinding *binding, tmp;
466 if(bindmap->nbindings==0)
469 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
470 state&=~evilignoremask;
472 state&=KNOWN_MODIFIERS_MASK;
479 binding=search_binding(bindmap, &tmp);
481 if(BINDING_IS_PSEUDO(act)){
482 /* No use trying anything else */
487 tmp.state=AnyModifier;
488 binding=search_binding(bindmap, &tmp);
493 tmp.ksb=(act==BINDING_KEYPRESS ? AnyKey : AnyButton);
495 binding=search_binding_any(bindmap, &tmp);
498 tmp.state=AnyModifier;
499 binding=search_binding_any(bindmap, &tmp);
508 WBinding *bindmap_lookup_binding(WBindmap *bindmap,
509 int act, uint state, uint kcb)
511 return do_bindmap_lookup_binding(bindmap, act, state, kcb, 0);
515 WBinding *bindmap_lookup_binding_area(WBindmap *bindmap,
516 int act, uint state, uint kcb, int area)
520 binding=do_bindmap_lookup_binding(bindmap, act, state, kcb, area);
523 binding=do_bindmap_lookup_binding(bindmap, act, state, kcb, 0);
530 * A dirty hack to deal with (==ignore) evil locking modifier keys.
534 int ioncore_unmod(int state, int keycode)
538 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
539 state&=~evilignoremask;
541 state&=KNOWN_MODIFIERS_MASK;
543 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
544 if(modmap->modifiermap[j]==keycode)
545 return state&~modmasks[j/modmap->max_keypermod];
552 int ioncore_modstate()
558 XQueryKeymap(ioncore_g.dpy, keys);
560 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
561 int a=(modmap->modifiermap[j]&7);
562 int b=(modmap->modifiermap[j]>>3);
565 state|=modmasks[j/modmap->max_keypermod];
569 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
570 state&=~evilignoremask;
572 state&=KNOWN_MODIFIERS_MASK;
578 bool ioncore_ismod(int keycode)
582 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
583 if(modmap->modifiermap[j]==keycode)
591 #ifdef CF_HACK_IGNORE_EVIL_LOCKS
593 static void lookup_evil_locks()
595 uint keycodes[N_LOOKUPEVIL];
598 for(i=0; i<N_LOOKUPEVIL; i++)
599 keycodes[i]=XKeysymToKeycode(ioncore_g.dpy, evillocks[i]);
601 for(j=0; j<N_MODS*modmap->max_keypermod; j++){
602 for(i=0; i<N_LOOKUPEVIL; i++){
603 if(keycodes[i]==None)
605 if(modmap->modifiermap[j]==keycodes[i]){
606 evillockmasks[i]=modmasks[j/modmap->max_keypermod];
607 evilignoremask|=evillockmasks[i];
614 static void evil_grab_key(Display *display, uint keycode, uint modifiers,
615 Window grab_window, bool owner_events,
616 int pointer_mode, int keyboard_mode)
621 XGrabKey(display, keycode, modifiers, grab_window, owner_events,
622 pointer_mode, keyboard_mode);
624 if(modifiers==AnyModifier)
627 for(i=0; i<N_EVILLOCKS; i++){
628 if(evillockmasks[i]==0)
631 for(j=i; j<N_EVILLOCKS; j++){
632 if(evillockmasks[j]==0)
634 mods|=evillockmasks[j];
635 XGrabKey(display, keycode, mods,
636 grab_window, owner_events, pointer_mode, keyboard_mode);
639 XGrabKey(display, keycode,
640 modifiers|evillockmasks[i]|evillockmasks[j],
641 grab_window, owner_events, pointer_mode, keyboard_mode);
647 static void evil_grab_button(Display *display, uint button, uint modifiers,
648 Window grab_window, bool owner_events,
649 uint event_mask, int pointer_mode,
650 int keyboard_mode, Window confine_to,
656 XGrabButton(display, button, modifiers,
657 grab_window, owner_events, event_mask, pointer_mode,
658 keyboard_mode, confine_to, cursor);
660 if(modifiers==AnyModifier)
663 for(i=0; i<N_EVILLOCKS; i++){
664 if(evillockmasks[i]==0)
667 for(j=i; j<N_EVILLOCKS; j++){
668 if(evillockmasks[j]==0)
670 mods|=evillockmasks[j];
671 XGrabButton(display, button, mods,
672 grab_window, owner_events, event_mask, pointer_mode,
673 keyboard_mode, confine_to, cursor);
676 XGrabButton(display, button,
677 modifiers|evillockmasks[i]|evillockmasks[j],
678 grab_window, owner_events, event_mask, pointer_mode,
679 keyboard_mode, confine_to, cursor);
685 static void evil_ungrab_key(Display *display, uint keycode, uint modifiers,
691 XUngrabKey(display, keycode, modifiers, grab_window);
693 if(modifiers==AnyModifier)
696 for(i=0; i<N_EVILLOCKS; i++){
697 if(evillockmasks[i]==0)
700 for(j=i; j<N_EVILLOCKS; j++){
701 if(evillockmasks[j]==0)
703 mods|=evillockmasks[j];
704 XUngrabKey(display, keycode, mods, grab_window);
707 XUngrabKey(display, keycode,
708 modifiers|evillockmasks[i]|evillockmasks[j],
715 static void evil_ungrab_button(Display *display, uint button, uint modifiers,
721 XUngrabButton(display, button, modifiers, grab_window);
723 if(modifiers==AnyModifier)
726 for(i=0; i<N_EVILLOCKS; i++){
727 if(evillockmasks[i]==0)
730 for(j=i; j<N_EVILLOCKS; j++){
731 if(evillockmasks[j]==0)
733 mods|=evillockmasks[j];
734 XUngrabButton(display, button, mods, grab_window);
737 XUngrabButton(display, button,
738 modifiers|evillockmasks[i]|evillockmasks[j],
745 #endif /* CF_HACK_IGNORE_EVIL_LOCKS */