From b6e31563d0217f3416f903e9b02307baa15a7a02 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Wed, 28 May 2008 12:15:00 +0200 Subject: [PATCH] [lua] Add new keybinding interface Signed-off-by: Julien Danjou --- Makefile.am | 1 + awesomerc.lua.in | 98 ++++++++++++++--------------- keybinding.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++ keybinding.h | 26 ++++++++ lua.c | 67 ++------------------ structs.h | 3 + window.c | 30 ++++++++- window.h | 1 + 8 files changed, 271 insertions(+), 112 deletions(-) create mode 100644 keybinding.c create mode 100644 keybinding.h diff --git a/Makefile.am b/Makefile.am index 65890d2d9..edcc5cca5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -122,6 +122,7 @@ awesome_SOURCES = \ cnode.c cnode.h \ event.c event.h \ layout.c layout.h \ + keybinding.c keybinding.h \ awesome.c \ tag.c tag.h \ lua.c lua.h \ diff --git a/awesomerc.lua.in b/awesomerc.lua.in index b6964f47a..772c21240 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -112,64 +112,64 @@ for s = 1, screen.count() do end for i = 1, keynumber do - awesome.key({ modkey }, i, - function () - local screen = mouse.screen_get() - if tags[screen][i] then - awful.tag.viewonly(tags[screen][i]) - end - end) - awesome.key({ modkey, "Control" }, i, - function () - local screen = mouse.screen_get() - if tags[screen][i] then - tags[i]:view(not tags[screen][i]:isselected()) - end - end) - awesome.key({ modkey, "Shift" }, i, - function () - local screen = mouse.screen_get() - if tags[screen][i] then - awful.client.movetotag(tags[screen][i]) - end - end) - awesome.key({ modkey, "Control", "Shift" }, i, - function () - local screen = mouse.screen_get() - if tags[screen][i] then - awful.client.toggletag(tags[screen][i]) - end - end) + keybinding.new({ modkey }, i, + function () + local screen = mouse.screen_get() + if tags[screen][i] then + awful.tag.viewonly(tags[screen][i]) + end + end):add() + keybinding.new({ modkey, "Control" }, i, + function () + local screen = mouse.screen_get() + if tags[screen][i] then + tags[i]:view(not tags[screen][i]:isselected()) + end + end):add() + keybinding.new({ modkey, "Shift" }, i, + function () + local screen = mouse.screen_get() + if tags[screen][i] then + awful.client.movetotag(tags[screen][i]) + end + end):add() + keybinding.new({ modkey, "Control", "Shift" }, i, + function () + local screen = mouse.screen_get() + if tags[screen][i] then + awful.client.toggletag(tags[screen][i]) + end + end):add() end -awesome.key({ modkey }, "Left", awful.tag.viewprev) -awesome.key({ modkey }, "Right", awful.tag.viewnext) +keybinding.new({ modkey }, "Left", awful.tag.viewprev):add() +keybinding.new({ modkey }, "Right", awful.tag.viewnext):add() -- Standard program -awesome.key({ modkey }, "Return", function () awful.spawn(terminal) end) +keybinding.new({ modkey }, "Return", function () awful.spawn(terminal) end):add() -awesome.key({ modkey, "Control" }, "r", awesome.restart) -awesome.key({ modkey, "Shift" }, "q", awesome.quit) +keybinding.new({ modkey, "Control" }, "r", awesome.restart):add() +keybinding.new({ modkey, "Shift" }, "q", awesome.quit):add() -- Client manipulation -awesome.key({ modkey, "Shift" }, "c", function () client.focus_get():kill() end) -awesome.key({ modkey }, "j", function () awful.client.focus(1); client.focus_get():raise() end) -awesome.key({ modkey }, "k", function () awful.client.focus(-1); client.focus_get():raise() end) -awesome.key({ modkey, "Shift" }, "j", function () awful.client.swap(1) end) -awesome.key({ modkey, "Shift" }, "k", function () awful.client.swap(-1) end) -awesome.key({ modkey, "Control" }, "j", function () awful.screen.focus(1) end) -awesome.key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end) -awesome.key({ modkey, "Control" }, "space", function () awful.client.togglefloating() end) +keybinding.new({ modkey, "Shift" }, "c", function () client.focus_get():kill() end):add() +keybinding.new({ modkey }, "j", function () awful.client.focus(1); client.focus_get():raise() end):add() +keybinding.new({ modkey }, "k", function () awful.client.focus(-1); client.focus_get():raise() end):add() +keybinding.new({ modkey, "Shift" }, "j", function () awful.client.swap(1) end):add() +keybinding.new({ modkey, "Shift" }, "k", function () awful.client.swap(-1) end):add() +keybinding.new({ modkey, "Control" }, "j", function () awful.screen.focus(1) end):add() +keybinding.new({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end):add() +keybinding.new({ modkey, "Control" }, "space", function () awful.client.togglefloating() end):add() -- Layout manipulation -awesome.key({ modkey }, "l", function () awful.tag.incmwfact(0.05) end) -awesome.key({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end) -awesome.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end) -awesome.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end) -awesome.key({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end) -awesome.key({ modkey, "Control" }, "l", function () awful.tag.incncol(1) end) -awesome.key({ modkey }, "space", function () awful.layout.inc(layouts, 1) end) -awesome.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end) +keybinding.new({ modkey }, "l", function () awful.tag.incmwfact(0.05) end):add() +keybinding.new({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add() +keybinding.new({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add() +keybinding.new({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add() +keybinding.new({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add() +keybinding.new({ modkey, "Control" }, "l", function () awful.tag.incncol(1) end):add() +keybinding.new({ modkey }, "space", function () awful.layout.inc(layouts, 1) end):add() +keybinding.new({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add() -- }}} -- {{{ Hooks diff --git a/keybinding.c b/keybinding.c new file mode 100644 index 000000000..9564dfe68 --- /dev/null +++ b/keybinding.c @@ -0,0 +1,157 @@ +/* + * keybinding.c - Key bindings configuration management + * + * Copyright © 2008 Julien Danjou + * + * 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. + * + */ + +/* XStringToKeysym() */ +#include + +#include "structs.h" +#include "lua.h" +#include "window.h" + +extern awesome_t globalconf; + +static void +__luaA_keystore(keybinding_t *key, const char *str) +{ + xcb_keycode_t kc; + int ikc; + + if(!a_strlen(str)) + return; + else if(a_strncmp(str, "#", 1)) + key->keysym = XStringToKeysym(str); + else + { + ikc = atoi(str + 1); + memcpy(&kc, &ikc, sizeof(KeyCode)); + key->keycode = kc; + } +} + +/** Define a global key binding. This key binding will always be available. + * \param A table with modifier keys. + * \param A key name. + * \param A function to execute. + */ +static int +luaA_keybinding_new(lua_State *L) +{ + size_t i, len; + keybinding_t *k, **keyb; + const char *key; + + /* arg 1 is key mod table */ + luaA_checktable(L, 1); + /* arg 2 is key */ + key = luaL_checkstring(L, 2); + /* arg 3 is cmd to run */ + luaA_checkfunction(L, 3); + + /* get the last arg as function */ + k = p_new(keybinding_t, 1); + __luaA_keystore(k, key); + k->fct = luaL_ref(L, LUA_REGISTRYINDEX); + + len = lua_objlen(L, 1); + for(i = 1; i <= len; i++) + { + lua_rawgeti(L, 1, i); + k->mod |= xutil_keymask_fromstr(luaL_checkstring(L, -1)); + } + + keyb = lua_newuserdata(globalconf.L, sizeof(client_t *)); + *keyb = k; + keybinding_ref(keyb); + return luaA_settype(L, "keybinding"); +} + +/** Add a global key binding. This key binding will always be available. + */ +static int +luaA_keybinding_add(lua_State *L) +{ + keybinding_t *key, **k = luaL_checkudata(L, 1, "keybinding"); + + /* Check that the keybinding has not been already added. */ + for(key = globalconf.keys; key; key = key->next) + if(key == *k) + luaL_error(L, "keybinding already added"); + + keybinding_list_push(&globalconf.keys, *k); + + keybinding_ref(k); + + window_root_grabkey(*k); + + return 0; +} + +/** Remove a global key binding. + */ +static int +luaA_keybinding_remove(lua_State *L) +{ + keybinding_t **k = luaL_checkudata(L, 1, "keybinding"); + + keybinding_list_detach(&globalconf.keys, *k); + + keybinding_unref(k); + + window_root_ungrabkey(*k); + + return 0; +} + +/** Handle keybinding garbage collection. + */ +static int +luaA_keybinding_gc(lua_State *L) +{ + keybinding_t **keybinding = luaL_checkudata(L, 1, "keybinding"); + keybinding_unref(keybinding); + return 0; +} + +/** Convert a keybinding to a printable string. + * \return A string. + */ +static int +luaA_keybinding_tostring(lua_State *L) +{ + keybinding_t **p = luaL_checkudata(L, 1, "keybinding"); + lua_pushfstring(L, "[keybinding udata(%p)]", *p); + return 1; +} + +const struct luaL_reg awesome_keybinding_methods[] = +{ + { "new", luaA_keybinding_new }, + { NULL, NULL } +}; +const struct luaL_reg awesome_keybinding_meta[] = +{ + {"add", luaA_keybinding_add }, + {"remove", luaA_keybinding_remove }, + {"__tostring", luaA_keybinding_tostring }, + {"__gc", luaA_keybinding_gc }, + { NULL, NULL }, +}; + diff --git a/keybinding.h b/keybinding.h new file mode 100644 index 000000000..b6d66e302 --- /dev/null +++ b/keybinding.h @@ -0,0 +1,26 @@ +/* + * keybinding.h - Key bindings configuration management header + * + * Copyright © 2008 Julien Danjou + * + * 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 + +#endif +// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/lua.c b/lua.c index ee8c990c3..b6e3152d8 100644 --- a/lua.c +++ b/lua.c @@ -29,15 +29,12 @@ #include #include -/* XStringToKeysym() */ -#include - #include "config.h" #include "structs.h" #include "lua.h" -#include "window.h" #include "tag.h" #include "client.h" +#include "window.h" #include "layouts/tile.h" extern awesome_t globalconf; @@ -56,24 +53,8 @@ extern const struct luaL_reg awesome_widget_methods[]; extern const struct luaL_reg awesome_widget_meta[]; extern const struct luaL_reg awesome_statusbar_methods[]; extern const struct luaL_reg awesome_statusbar_meta[]; - -static void -__luaA_keystore(keybinding_t *key, const char *str) -{ - xcb_keycode_t kc; - int ikc; - - if(!a_strlen(str)) - return; - else if(a_strncmp(str, "#", 1)) - key->keysym = XStringToKeysym(str); - else - { - ikc = atoi(str + 1); - memcpy(&kc, &ikc, sizeof(KeyCode)); - key->keycode = kc; - } -} +extern const struct luaL_reg awesome_keybinding_methods[]; +extern const struct luaL_reg awesome_keybinding_meta[]; /** Define a global mouse binding. This binding will be available wehn you * click on root window. @@ -113,44 +94,6 @@ luaA_mouse(lua_State *L) return 0; } -/** Define a global key binding. This key binding will always be available. - * \param A table with modifier keys. - * \param A key name. - * \param A function to execute. - */ -static int -luaA_key(lua_State *L) -{ - size_t i, len; - keybinding_t *k; - const char *key; - - /* arg 1 is key mod table */ - luaA_checktable(L, 1); - /* arg 2 is key */ - key = luaL_checkstring(L, 2); - /* arg 3 is cmd to run */ - luaA_checkfunction(L, 3); - - /* get the last arg as function */ - k = p_new(keybinding_t, 1); - __luaA_keystore(k, key); - k->fct = luaL_ref(L, LUA_REGISTRYINDEX); - - len = lua_objlen(L, 1); - for(i = 1; i <= len; i++) - { - lua_rawgeti(L, 1, i); - k->mod |= xutil_keymask_fromstr(luaL_checkstring(L, -1)); - } - - keybinding_list_push(&globalconf.keys, k); - - window_root_grabkey(k); - - return 0; -} - /** Set the floating placement algorithm. This will be used to compute the * initial floating position of floating windows. * \param An algorith name, either `none', `smart' or `mouse'. @@ -431,7 +374,6 @@ luaA_parserc(const char *rcfile) { "restart", luaA_restart }, { "floating_placement_set", luaA_floating_placement_set }, { "padding_set", luaA_padding_set }, - { "key", luaA_key }, { "mouse", luaA_mouse }, { "resizehints_set", luaA_resizehints_set }, { "font_set", luaA_font_set }, @@ -488,6 +430,9 @@ luaA_parserc(const char *rcfile) /* Export titlebar */ luaA_openlib(L, "titlebar", awesome_titlebar_methods, awesome_titlebar_meta); + /* Export keys */ + luaA_openlib(L, "keybinding", awesome_keybinding_methods, awesome_keybinding_meta); + lua_pushliteral(L, "AWESOME_VERSION"); lua_pushliteral(L, VERSION); lua_settable(L, LUA_GLOBALSINDEX); diff --git a/structs.h b/structs.h index 222ca97ca..d0a01d491 100644 --- a/structs.h +++ b/structs.h @@ -79,6 +79,8 @@ DO_RCNT(titlebar_t, titlebar, titlebar_delete) typedef struct keybinding_t keybinding_t; struct keybinding_t { + /** Ref count */ + int refcount; /** Key modifier */ unsigned long mod; /** Keysym */ @@ -92,6 +94,7 @@ struct keybinding_t }; DO_SLIST(keybinding_t, keybinding, p_delete) +DO_RCNT(keybinding_t, keybinding, p_delete) /** Mouse buttons bindings */ typedef struct button_t button_t; diff --git a/window.c b/window.c index 5a6b54c02..6c80a0cfe 100644 --- a/window.c +++ b/window.c @@ -209,7 +209,6 @@ window_root_grabkey(keybinding_t *k) if((kc = k->keycode) || (k->keysym && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym)))) - { do { s = xcb_aux_get_screen(globalconf.connection, phys_screen); @@ -225,7 +224,34 @@ window_root_grabkey(keybinding_t *k) phys_screen++; } while(!globalconf.screens_info->xinerama_is_active && phys_screen < globalconf.screens_info->nscreen); - } +} + +/** Ungrab key on the root windows. + * \param k The keybinding. + */ +void +window_root_ungrabkey(keybinding_t *k) +{ + int phys_screen = globalconf.default_screen; + xcb_screen_t *s; + xcb_keycode_t kc; + + if((kc = k->keycode) + || (k->keysym && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym)))) + do + { + s = xcb_aux_get_screen(globalconf.connection, phys_screen); + xcb_ungrab_key(globalconf.connection, kc, s->root, + k->mod); + xcb_ungrab_key(globalconf.connection, kc, s->root, + k->mod | XCB_MOD_MASK_LOCK); + xcb_ungrab_key(globalconf.connection, kc, s->root, + k->mod | globalconf.numlockmask); + xcb_ungrab_key(globalconf.connection, kc, s->root, + k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK); + phys_screen++; + } while(!globalconf.screens_info->xinerama_is_active + && phys_screen < globalconf.screens_info->nscreen); } /** Set shape property on window. diff --git a/window.h b/window.h index f95aeeca6..e2586e8b9 100644 --- a/window.h +++ b/window.h @@ -31,6 +31,7 @@ void window_grabbuttons(xcb_window_t, int); void window_root_grabbutton(button_t *); void window_root_grabbuttons(void); void window_root_grabkey(keybinding_t *); +void window_root_ungrabkey(keybinding_t *); void window_setshape(xcb_window_t, int); void window_settrans(xcb_window_t, double);