Put keybindings in binary searchable arrays.
This patch sorts keybindings in arrays by keycode or keysym to speed up look up using binary searches. This is a preliminary work to enable more powerful keybindings stuff, where keybindings can be cascaded or why not, attached to specific clients. Interstingly enough, this patch saves 100ko of initial memory (Heap) usage here. The underlying idea is that we should be able to define keybindings_t as trees of keybindings_t which would then define key sequences. The OO approach kind of make sense in fact, since you create a base keybinding (e.g. reacting on Mod4-w) and then you will probably (with appropriate apis) be able to populate new submaps from that point more or less dynamically. And if you have two keybindings on Mod4-w, then adding them will replace the previous one. This means that you can fake per-client bindings with e.g.: k_default = keybindings.new({"Mod4"}, "w", something); k_mplayer = keybindings.new({"Mod4"}, "w", something_else); k_default:add() and in your focus hook: if /* code for testing if it's mplayer */ then k_mplayer:add() else k_default:add() end This would not work before, it does now. It will take way more sense with submaps of course. Signed-off-by: Pierre Habouzit <madcoder@debian.org>
This commit is contained in:
parent
8c1aec2e96
commit
4c288c006b
13
event.c
13
event.c
|
@ -33,6 +33,7 @@
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "titlebar.h"
|
#include "titlebar.h"
|
||||||
|
#include "keybinding.h"
|
||||||
#include "keygrabber.h"
|
#include "keygrabber.h"
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
#include "systray.h"
|
#include "systray.h"
|
||||||
|
@ -390,8 +391,6 @@ event_handle_keypress(void *data __attribute__ ((unused)),
|
||||||
xcb_connection_t *connection __attribute__ ((unused)),
|
xcb_connection_t *connection __attribute__ ((unused)),
|
||||||
xcb_key_press_event_t *ev)
|
xcb_key_press_event_t *ev)
|
||||||
{
|
{
|
||||||
xcb_keysym_t keysym;
|
|
||||||
|
|
||||||
if(globalconf.keygrabber != LUA_REFNIL)
|
if(globalconf.keygrabber != LUA_REFNIL)
|
||||||
{
|
{
|
||||||
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.keygrabber);
|
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.keygrabber);
|
||||||
|
@ -409,16 +408,10 @@ event_handle_keypress(void *data __attribute__ ((unused)),
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
keysym = xcb_key_symbols_get_keysym(globalconf.keysyms, ev->detail, 0);
|
keybinding_t *k = keybinding_find(&globalconf.keys, ev);
|
||||||
|
if (k && k->fct)
|
||||||
for(int i = 0; i < globalconf.keys.len; i++)
|
|
||||||
{
|
|
||||||
keybinding_t *k = globalconf.keys.tab[i];
|
|
||||||
if(((k->keycode && ev->detail == k->keycode) || (k->keysym && keysym == k->keysym))
|
|
||||||
&& k->fct && CLEANMASK(k->mod) == CLEANMASK(ev->state))
|
|
||||||
luaA_dofunction(globalconf.L, k->fct, 0);
|
luaA_dofunction(globalconf.L, k->fct, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
154
keybinding.c
154
keybinding.c
|
@ -2,6 +2,7 @@
|
||||||
* keybinding.c - Key bindings configuration management
|
* keybinding.c - Key bindings configuration management
|
||||||
*
|
*
|
||||||
* Copyright © 2008 Julien Danjou <julien@danjou.info>
|
* Copyright © 2008 Julien Danjou <julien@danjou.info>
|
||||||
|
* Copyright © 2008 Pierre Habouzit <madcoder@debian.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -22,7 +23,8 @@
|
||||||
/* XStringToKeysym() */
|
/* XStringToKeysym() */
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#include "structs.h"
|
#include "keybinding.h"
|
||||||
|
#include "event.h"
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
|
@ -31,27 +33,140 @@ extern awesome_t globalconf;
|
||||||
DO_LUA_NEW(static, keybinding_t, keybinding, "keybinding", keybinding_ref)
|
DO_LUA_NEW(static, keybinding_t, keybinding, "keybinding", keybinding_ref)
|
||||||
DO_LUA_GC(keybinding_t, keybinding, "keybinding", keybinding_unref)
|
DO_LUA_GC(keybinding_t, keybinding, "keybinding", keybinding_unref)
|
||||||
|
|
||||||
|
void keybinding_idx_wipe(keybinding_idx_t *idx)
|
||||||
|
{
|
||||||
|
keybinding_array_wipe(&idx->by_code);
|
||||||
|
keybinding_array_wipe(&idx->by_sym);
|
||||||
|
}
|
||||||
|
|
||||||
void keybinding_delete(keybinding_t **kbp)
|
void keybinding_delete(keybinding_t **kbp)
|
||||||
{
|
{
|
||||||
p_delete(kbp);
|
p_delete(kbp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
keybinding_ev_cmp(xcb_keysym_t keysym, xcb_keycode_t keycode,
|
||||||
|
unsigned long mod, const keybinding_t *k)
|
||||||
|
{
|
||||||
|
if (k->keysym) {
|
||||||
|
if (k->keysym != keysym)
|
||||||
|
return k->keysym > keysym ? 1 : -1;
|
||||||
|
}
|
||||||
|
if (k->keycode) {
|
||||||
|
if (k->keycode != keycode)
|
||||||
|
return k->keycode > keycode ? 1 : -1;
|
||||||
|
}
|
||||||
|
return k->mod == mod ? 0 : (k->mod > mod ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
keybinding_cmp(const keybinding_t *k1, const keybinding_t *k2)
|
||||||
|
{
|
||||||
|
assert ((k1->keysym && k2->keysym) || (k1->keycode && k2->keycode));
|
||||||
|
assert ((!k1->keysym && !k2->keysym) || (!k1->keycode && !k2->keycode));
|
||||||
|
|
||||||
|
if (k1->keysym != k2->keysym)
|
||||||
|
return k2->keysym > k1->keysym ? 1 : -1;
|
||||||
|
if (k1->keycode != k2->keycode)
|
||||||
|
return k2->keycode > k1->keycode ? 1 : -1;
|
||||||
|
return k1->mod == k2->mod ? 0 : (k2->mod > k1->mod ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
keybinding_register_root(keybinding_t *k)
|
||||||
|
{
|
||||||
|
keybinding_idx_t *idx = &globalconf.keys;
|
||||||
|
keybinding_array_t *arr = k->keysym ? &idx->by_sym : &idx->by_code;
|
||||||
|
int l = 0, r = arr->len;
|
||||||
|
|
||||||
|
keybinding_ref(&k);
|
||||||
|
|
||||||
|
while (l < r) {
|
||||||
|
int i = (r + l) / 2;
|
||||||
|
switch (keybinding_cmp(k, arr->tab[i])) {
|
||||||
|
case -1: /* k < arr->tab[i] */
|
||||||
|
r = i;
|
||||||
|
break;
|
||||||
|
case 0: /* k == arr->tab[i] */
|
||||||
|
keybinding_unref(&arr->tab[i]);
|
||||||
|
arr->tab[i] = k;
|
||||||
|
return;
|
||||||
|
case 1: /* k > arr->tab[i] */
|
||||||
|
l = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keybinding_array_splice(arr, r, 0, &k, 1);
|
||||||
|
window_root_grabkey(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
keybinding_unregister_root(keybinding_t **k)
|
||||||
|
{
|
||||||
|
keybinding_idx_t *idx = &globalconf.keys;
|
||||||
|
keybinding_array_t *arr = (*k)->keysym ? &idx->by_sym : &idx->by_code;
|
||||||
|
int l = 0, r = arr->len;
|
||||||
|
|
||||||
|
while (l < r) {
|
||||||
|
int i = (r + l) / 2;
|
||||||
|
switch (keybinding_cmp(*k, arr->tab[i])) {
|
||||||
|
case -1: /* k < arr->tab[i] */
|
||||||
|
r = i;
|
||||||
|
break;
|
||||||
|
case 0: /* k == arr->tab[i] */
|
||||||
|
keybinding_array_take(arr, i);
|
||||||
|
window_root_ungrabkey(*k);
|
||||||
|
keybinding_unref(k);
|
||||||
|
return;
|
||||||
|
case 1: /* k > arr->tab[i] */
|
||||||
|
l = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keybinding_t *
|
||||||
|
keybinding_find(const keybinding_idx_t *idx, const xcb_key_press_event_t *ev)
|
||||||
|
{
|
||||||
|
const keybinding_array_t *arr = &idx->by_sym;
|
||||||
|
int l, r, mod = CLEANMASK(ev->state);
|
||||||
|
xcb_keysym_t keysym;
|
||||||
|
|
||||||
|
keysym = xcb_key_symbols_get_keysym(globalconf.keysyms, ev->detail, 0);
|
||||||
|
|
||||||
|
again:
|
||||||
|
l = 0;
|
||||||
|
r = arr->len;
|
||||||
|
while (l < r) {
|
||||||
|
int i = (r + l) / 2;
|
||||||
|
switch (keybinding_ev_cmp(keysym, ev->detail, mod, arr->tab[i])) {
|
||||||
|
case -1: /* ev < arr->tab[i] */
|
||||||
|
r = i;
|
||||||
|
break;
|
||||||
|
case 0: /* ev == arr->tab[i] */
|
||||||
|
return arr->tab[i];
|
||||||
|
case 1: /* ev > arr->tab[i] */
|
||||||
|
l = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arr != &idx->by_code) {
|
||||||
|
arr = &idx->by_code;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
__luaA_keystore(keybinding_t *key, const char *str)
|
__luaA_keystore(keybinding_t *key, const char *str)
|
||||||
{
|
{
|
||||||
xcb_keycode_t kc;
|
|
||||||
int ikc;
|
|
||||||
|
|
||||||
if(!a_strlen(str))
|
if(!a_strlen(str))
|
||||||
return;
|
return;
|
||||||
else if(a_strncmp(str, "#", 1))
|
else if(*str != '#')
|
||||||
key->keysym = XStringToKeysym(str);
|
key->keysym = XStringToKeysym(str);
|
||||||
else
|
else
|
||||||
{
|
key->keycode = atoi(str + 1);
|
||||||
ikc = atoi(str + 1);
|
|
||||||
memcpy(&kc, &ikc, sizeof(KeyCode));
|
|
||||||
key->keycode = kc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Define a global key binding. This key binding will always be available.
|
/** Define a global key binding. This key binding will always be available.
|
||||||
|
@ -103,14 +218,7 @@ luaA_keybinding_add(lua_State *L)
|
||||||
{
|
{
|
||||||
keybinding_t **k = luaA_checkudata(L, 1, "keybinding");
|
keybinding_t **k = luaA_checkudata(L, 1, "keybinding");
|
||||||
|
|
||||||
/* Check that the keybinding has not been already added. */
|
keybinding_register_root(*k);
|
||||||
for(int i = 0; i < globalconf.keys.len; i++)
|
|
||||||
if(globalconf.keys.tab[i] == *k)
|
|
||||||
luaL_error(L, "keybinding already added");
|
|
||||||
|
|
||||||
keybinding_array_append(&globalconf.keys, keybinding_ref(k));
|
|
||||||
window_root_grabkey(*k);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,15 +232,7 @@ static int
|
||||||
luaA_keybinding_remove(lua_State *L)
|
luaA_keybinding_remove(lua_State *L)
|
||||||
{
|
{
|
||||||
keybinding_t **k = luaA_checkudata(L, 1, "keybinding");
|
keybinding_t **k = luaA_checkudata(L, 1, "keybinding");
|
||||||
|
keybinding_unregister_root(k);
|
||||||
for(int i = 0; i < globalconf.keys.len; i++)
|
|
||||||
if(globalconf.keys.tab[i] == *k)
|
|
||||||
{
|
|
||||||
keybinding_array_take(&globalconf.keys, i);
|
|
||||||
window_root_ungrabkey(*k);
|
|
||||||
keybinding_unref(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* keybinding.h - Keybinding helpers
|
||||||
|
*
|
||||||
|
* Copyright © 2008 Pierre Habouzit <madcoder@debian.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AWESOME_KEYBINDING_H
|
||||||
|
#define AWESOME_KEYBINDING_H
|
||||||
|
|
||||||
|
#include "structs.h"
|
||||||
|
|
||||||
|
void keybinding_delete(keybinding_t **);
|
||||||
|
DO_RCNT(keybinding_t, keybinding, keybinding_delete)
|
||||||
|
ARRAY_FUNCS(keybinding_t *, keybinding, keybinding_unref)
|
||||||
|
|
||||||
|
void keybinding_idx_wipe(keybinding_idx_t *);
|
||||||
|
|
||||||
|
void keybinding_register_root(keybinding_t *);
|
||||||
|
void keybinding_unregiste_rootr(keybinding_t **);
|
||||||
|
keybinding_t *keybinding_find(const keybinding_idx_t *,
|
||||||
|
const xcb_key_press_event_t *);
|
||||||
|
|
||||||
|
#endif
|
12
structs.h
12
structs.h
|
@ -207,6 +207,12 @@ DO_RCNT(titlebar_t, titlebar, titlebar_delete)
|
||||||
|
|
||||||
/** Keys bindings */
|
/** Keys bindings */
|
||||||
ARRAY_TYPE(struct keybinding_t *, keybinding);
|
ARRAY_TYPE(struct keybinding_t *, keybinding);
|
||||||
|
|
||||||
|
typedef struct keybinding_idx_t {
|
||||||
|
keybinding_array_t by_code;
|
||||||
|
keybinding_array_t by_sym;
|
||||||
|
} keybinding_idx_t;
|
||||||
|
|
||||||
struct keybinding_t
|
struct keybinding_t
|
||||||
{
|
{
|
||||||
/** Ref count */
|
/** Ref count */
|
||||||
|
@ -221,10 +227,6 @@ struct keybinding_t
|
||||||
luaA_function fct;
|
luaA_function fct;
|
||||||
};
|
};
|
||||||
|
|
||||||
void keybinding_delete(keybinding_t **);
|
|
||||||
DO_RCNT(keybinding_t, keybinding, keybinding_delete)
|
|
||||||
ARRAY_FUNCS(keybinding_t *, keybinding, keybinding_unref)
|
|
||||||
|
|
||||||
/** Status bar */
|
/** Status bar */
|
||||||
struct statusbar_t
|
struct statusbar_t
|
||||||
{
|
{
|
||||||
|
@ -399,7 +401,7 @@ struct awesome_t
|
||||||
/** Screens info */
|
/** Screens info */
|
||||||
screens_info_t *screens_info;
|
screens_info_t *screens_info;
|
||||||
/** Keys bindings list */
|
/** Keys bindings list */
|
||||||
keybinding_array_t keys;
|
keybinding_idx_t keys;
|
||||||
/** Mouse bindings list */
|
/** Mouse bindings list */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue