2 * keybinding.c - Key bindings configuration management
4 * Copyright © 2008 Julien Danjou <julien@danjou.info>
5 * Copyright © 2008 Pierre Habouzit <madcoder@debian.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 /* XStringToKeysym() */
27 #include "common/refcount.h"
28 #include "common/array.h"
29 #include "keybinding.h"
31 ARRAY_TYPE(keybinding_t
*, keybinding
)
33 extern awesome_t globalconf
;
36 keybinding_array_t by_code
;
37 keybinding_array_t by_sym
;
40 static void keybinding_delete(keybinding_t
**kbp
)
42 luaL_unref(globalconf
.L
, LUA_REGISTRYINDEX
, (*kbp
)->fct
);
46 DO_RCNT(keybinding_t
, keybinding
, keybinding_delete
)
47 ARRAY_FUNCS(keybinding_t
*, keybinding
, keybinding_unref
)
48 DO_LUA_NEW(static, keybinding_t
, keybinding
, "keybinding", keybinding_ref
)
49 DO_LUA_GC(keybinding_t
, keybinding
, "keybinding", keybinding_unref
)
52 keybinding_ev_cmp(xcb_keysym_t keysym
, xcb_keycode_t keycode
,
53 unsigned long mod
, const keybinding_t
*k
)
56 if (k
->keysym
!= keysym
)
57 return k
->keysym
> keysym
? 1 : -1;
60 if (k
->keycode
!= keycode
)
61 return k
->keycode
> keycode
? 1 : -1;
63 return k
->mod
== mod
? 0 : (k
->mod
> mod
? 1 : -1);
67 keybinding_cmp(const keybinding_t
*k1
, const keybinding_t
*k2
)
69 assert ((k1
->keysym
&& k2
->keysym
) || (k1
->keycode
&& k2
->keycode
));
70 assert ((!k1
->keysym
&& !k2
->keysym
) || (!k1
->keycode
&& !k2
->keycode
));
72 if (k1
->keysym
!= k2
->keysym
)
73 return k2
->keysym
> k1
->keysym
? 1 : -1;
74 if (k1
->keycode
!= k2
->keycode
)
75 return k2
->keycode
> k1
->keycode
? 1 : -1;
76 return k1
->mod
== k2
->mod
? 0 : (k2
->mod
> k1
->mod
? 1 : -1);
79 /** Grab key on the root windows.
80 * \param k The keybinding.
83 window_root_grabkey(keybinding_t
*k
)
85 int phys_screen
= globalconf
.default_screen
;
90 || (k
->keysym
&& (kc
= xcb_key_symbols_get_keycode(globalconf
.keysyms
, k
->keysym
))))
93 s
= xutil_screen_get(globalconf
.connection
, phys_screen
);
94 xcb_grab_key(globalconf
.connection
, true, s
->root
,
95 k
->mod
, kc
, XCB_GRAB_MODE_ASYNC
, XCB_GRAB_MODE_ASYNC
);
96 xcb_grab_key(globalconf
.connection
, true, s
->root
,
97 k
->mod
| XCB_MOD_MASK_LOCK
, kc
, XCB_GRAB_MODE_ASYNC
, XCB_GRAB_MODE_ASYNC
);
98 xcb_grab_key(globalconf
.connection
, true, s
->root
,
99 k
->mod
| globalconf
.numlockmask
, kc
, XCB_GRAB_MODE_ASYNC
, XCB_GRAB_MODE_ASYNC
);
100 xcb_grab_key(globalconf
.connection
, true, s
->root
,
101 k
->mod
| globalconf
.numlockmask
| XCB_MOD_MASK_LOCK
, kc
, XCB_GRAB_MODE_ASYNC
,
102 XCB_GRAB_MODE_ASYNC
);
104 } while(!globalconf
.screens_info
->xinerama_is_active
105 && phys_screen
< globalconf
.screens_info
->nscreen
);
108 /** Ungrab key on the root windows.
109 * \param k The keybinding.
112 window_root_ungrabkey(keybinding_t
*k
)
114 int phys_screen
= globalconf
.default_screen
;
119 || (k
->keysym
&& (kc
= xcb_key_symbols_get_keycode(globalconf
.keysyms
, k
->keysym
))))
122 s
= xutil_screen_get(globalconf
.connection
, phys_screen
);
123 xcb_ungrab_key(globalconf
.connection
, kc
, s
->root
,
125 xcb_ungrab_key(globalconf
.connection
, kc
, s
->root
,
126 k
->mod
| XCB_MOD_MASK_LOCK
);
127 xcb_ungrab_key(globalconf
.connection
, kc
, s
->root
,
128 k
->mod
| globalconf
.numlockmask
);
129 xcb_ungrab_key(globalconf
.connection
, kc
, s
->root
,
130 k
->mod
| globalconf
.numlockmask
| XCB_MOD_MASK_LOCK
);
132 } while(!globalconf
.screens_info
->xinerama_is_active
133 && phys_screen
< globalconf
.screens_info
->nscreen
);
137 keybinding_register_root(keybinding_t
*k
)
139 keybinding_array_t
*arr
= k
->keysym
? &keys_g
.by_sym
: &keys_g
.by_code
;
140 int l
= 0, r
= arr
->len
;
146 switch (keybinding_cmp(k
, arr
->tab
[i
])) {
147 case -1: /* k < arr->tab[i] */
150 case 0: /* k == arr->tab[i] */
151 keybinding_unref(&arr
->tab
[i
]);
154 case 1: /* k > arr->tab[i] */
160 keybinding_array_splice(arr
, r
, 0, &k
, 1);
161 window_root_grabkey(k
);
165 keybinding_unregister_root(keybinding_t
**k
)
167 keybinding_array_t
*arr
= (*k
)->keysym
? &keys_g
.by_sym
: &keys_g
.by_code
;
168 int l
= 0, r
= arr
->len
;
172 switch (keybinding_cmp(*k
, arr
->tab
[i
])) {
173 case -1: /* k < arr->tab[i] */
176 case 0: /* k == arr->tab[i] */
177 keybinding_array_take(arr
, i
);
178 window_root_ungrabkey(*k
);
181 case 1: /* k > arr->tab[i] */
189 keybinding_find(const xcb_key_press_event_t
*ev
)
191 const keybinding_array_t
*arr
= &keys_g
.by_sym
;
192 int l
, r
, mod
= XUTIL_MASK_CLEAN(ev
->state
);
195 keysym
= xcb_key_symbols_get_keysym(globalconf
.keysyms
, ev
->detail
, 0);
202 switch (keybinding_ev_cmp(keysym
, ev
->detail
, mod
, arr
->tab
[i
])) {
203 case -1: /* ev < arr->tab[i] */
206 case 0: /* ev == arr->tab[i] */
208 case 1: /* ev > arr->tab[i] */
213 if (arr
!= &keys_g
.by_code
) {
214 arr
= &keys_g
.by_code
;
221 __luaA_keystore(keybinding_t
*key
, const char *str
)
226 key
->keysym
= XStringToKeysym(str
);
228 key
->keycode
= atoi(str
+ 1);
231 /** Define a global key binding. This key binding will always be available.
232 * \param L The Lua VM state.
235 * \lparam A table with modifier keys.
236 * \lparam A key name.
237 * \lparam A function to execute.
238 * \lreturn The keybinding.
241 luaA_keybinding_new(lua_State
*L
)
247 /* arg 2 is key mod table */
248 luaA_checktable(L
, 2);
250 key
= luaL_checkstring(L
, 3);
251 /* arg 4 is cmd to run */
252 luaA_checkfunction(L
, 4);
254 /* get the last arg as function */
255 k
= p_new(keybinding_t
, 1);
256 __luaA_keystore(k
, key
);
257 k
->fct
= luaL_ref(L
, LUA_REGISTRYINDEX
);
259 len
= lua_objlen(L
, 2);
260 for(i
= 1; i
<= len
; i
++)
262 lua_rawgeti(L
, 2, i
);
263 k
->mod
|= xutil_key_mask_fromstr(luaL_checkstring(L
, -1));
266 return luaA_keybinding_userdata_new(L
, k
);
269 /** Add a global key binding. This key binding will always be available.
270 * \param L The Lua VM state.
273 * \lvalue A keybinding.
276 luaA_keybinding_add(lua_State
*L
)
278 keybinding_t
**k
= luaA_checkudata(L
, 1, "keybinding");
280 keybinding_register_root(*k
);
284 /** Remove a global key binding.
285 * \param L The Lua VM state.
288 * \lvalue A keybinding.
291 luaA_keybinding_remove(lua_State
*L
)
293 keybinding_t
**k
= luaA_checkudata(L
, 1, "keybinding");
294 keybinding_unregister_root(k
);
298 /** Convert a keybinding to a printable string.
302 luaA_keybinding_tostring(lua_State
*L
)
304 keybinding_t
**p
= luaA_checkudata(L
, 1, "keybinding");
305 lua_pushfstring(L
, "[keybinding udata(%p)]", *p
);
309 const struct luaL_reg awesome_keybinding_methods
[] =
311 { "__call", luaA_keybinding_new
},
314 const struct luaL_reg awesome_keybinding_meta
[] =
316 {"add", luaA_keybinding_add
},
317 {"remove", luaA_keybinding_remove
},
318 {"__tostring", luaA_keybinding_tostring
},
319 {"__gc", luaA_keybinding_gc
},