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 */