From d9c868b627ffcb45822a8cdfdf0b85012b420d7e Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 5 Jan 2009 16:59:20 +0100 Subject: [PATCH] client: implements per-client key bindings Signed-off-by: Julien Danjou --- awesomerc.lua.in | 213 +++++++++++++++++++++++++---------------------- client.c | 25 ++++++ event.c | 57 +++++++++---- key.c | 181 +++++++++++++++++++++++----------------- key.h | 15 +++- luaa.c | 42 ++++++++-- structs.h | 12 ++- 7 files changed, 335 insertions(+), 210 deletions(-) diff --git a/awesomerc.lua.in b/awesomerc.lua.in index abab9177..5b605159 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -168,7 +168,6 @@ root.buttons({ -- }}} -- {{{ Key bindings - -- Bind keyboard digits -- Compute the maximum number of digit we need, limited to 9 keynumber = 0 @@ -176,120 +175,135 @@ for s = 1, screen.count() do keynumber = math.min(9, math.max(#tags[s], keynumber)); end +globalkeys = {} +clientkeys = {} + for i = 1, keynumber do - key({ modkey }, i, - function () - local screen = mouse.screen - if tags[screen][i] then - awful.tag.viewonly(tags[screen][i]) - end - end):add() - key({ modkey, "Control" }, i, - function () - local screen = mouse.screen - if tags[screen][i] then - tags[screen][i].selected = not tags[screen][i].selected - end - end):add() - key({ modkey, "Shift" }, i, - function () - if client.focus and tags[client.focus.screen][i] then - awful.client.movetotag(tags[client.focus.screen][i]) - end - end):add() - key({ modkey, "Control", "Shift" }, i, - function () - if client.focus and tags[client.focus.screen][i] then - awful.client.toggletag(tags[client.focus.screen][i]) - end - end):add() + table.insert(globalkeys, + key({ modkey }, i, + function () + local screen = mouse.screen + if tags[screen][i] then + awful.tag.viewonly(tags[screen][i]) + end + end)) + table.insert(globalkeys, + key({ modkey, "Control" }, i, + function () + local screen = mouse.screen + if tags[screen][i] then + tags[screen][i].selected = not tags[screen][i].selected + end + end)) + table.insert(globalkeys, + key({ modkey, "Shift" }, i, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.movetotag(tags[client.focus.screen][i]) + end + end)) + table.insert(globalkeys, + key({ modkey, "Control", "Shift" }, i, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.toggletag(tags[client.focus.screen][i]) + end + end)) end -key({ modkey }, "Left", awful.tag.viewprev):add() -key({ modkey }, "Right", awful.tag.viewnext):add() -key({ modkey }, "Escape", awful.tag.history.restore):add() +table.insert(globalkeys, key({ modkey }, "Left", awful.tag.viewprev)) +table.insert(globalkeys, key({ modkey }, "Right", awful.tag.viewnext)) +table.insert(globalkeys, key({ modkey }, "Escape", awful.tag.history.restore)) + +table.insert(globalkeys, key({ modkey }, "j", function () awful.client.focus.byidx(1); if client.focus then client.focus:raise() end end)) +table.insert(globalkeys, key({ modkey }, "k", function () awful.client.focus.byidx(-1); if client.focus then client.focus:raise() end end)) +table.insert(globalkeys, key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx(1) end)) +table.insert(globalkeys, key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx(-1) end)) + +table.insert(globalkeys, key({ modkey, "Control" }, "j", function () awful.screen.focus(1) end)) +table.insert(globalkeys, key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end)) + +table.insert(globalkeys, key({ modkey }, "Tab", function () awful.client.focus.history.previous(); if client.focus then client.focus:raise() end end)) + +table.insert(globalkeys, key({ modkey }, "u", awful.client.urgent.jumpto)) -- Standard program -key({ modkey }, "Return", function () awful.util.spawn(terminal) end):add() +table.insert(globalkeys, key({ modkey }, "Return", function () awful.util.spawn(terminal) end)) -key({ modkey, "Control" }, "r", function () - mypromptbox[mouse.screen].text = - awful.util.escape(awful.util.restart()) - end):add() -key({ modkey, "Shift" }, "q", awesome.quit):add() +table.insert(globalkeys, key({ modkey, "Control" }, "r", function () + mypromptbox[mouse.screen].text = + awful.util.escape(awful.util.restart()) + end)) +table.insert(globalkeys, key({ modkey, "Shift" }, "q", awesome.quit)) -- Client manipulation -key({ modkey }, "m", function () if client.focus then client.focus.maximized_horizontal = not client.focus.maximized_horizontal - client.focus.maximized_vertical = not client.focus.maximized_vertical end end):add() -key({ modkey }, "f", function () if client.focus then client.focus.fullscreen = not client.focus.fullscreen end end):add() -key({ modkey, "Shift" }, "c", function () if client.focus then client.focus:kill() end end):add() -key({ modkey }, "j", function () awful.client.focus.byidx(1); if client.focus then client.focus:raise() end end):add() -key({ modkey }, "k", function () awful.client.focus.byidx(-1); if client.focus then client.focus:raise() end end):add() -key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx(1) end):add() -key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx(-1) end):add() -key({ modkey, "Control" }, "j", function () awful.screen.focus(1) end):add() -key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end):add() -key({ modkey, "Control" }, "space", awful.client.floating.toggle):add() -key({ modkey, "Control" }, "Return", function () if client.focus then client.focus:swap(awful.client.getmaster()) end end):add() -key({ modkey }, "o", awful.client.movetoscreen):add() -key({ modkey }, "Tab", function () awful.client.focus.history.previous(); if client.focus then client.focus:raise() end end):add() -key({ modkey }, "u", awful.client.urgent.jumpto):add() -key({ modkey, "Shift" }, "r", function () if client.focus then client.focus:redraw() end end):add() +table.insert(clientkeys, key({ modkey }, "m", function (c) c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical end)) +table.insert(clientkeys, key({ modkey }, "f", function (c) c.fullscreen = not c.fullscreen end)) +table.insert(clientkeys, key({ modkey, "Shift" }, "c", function (c) c:kill() end)) +table.insert(clientkeys, key({ modkey, "Control" }, "space", awful.client.floating.toggle)) +table.insert(clientkeys, key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end)) +table.insert(clientkeys, key({ modkey }, "o", awful.client.movetoscreen)) +table.insert(clientkeys, key({ modkey, "Shift" }, "r", function (c) c:redraw() end)) +table.insert(clientkeys, key({ modkey, "Ctrl" }, "i", function (c) + local s = c.screen + if mypromptbox[s].text then + mypromptbox[s].text = nil + else + mypromptbox[s].text = nil + if c.class then + mypromptbox[s].text = "Class: " .. c.class .. " " + end + if c.instance then + mypromptbox[s].text = mypromptbox[s].text .. "Instance: ".. c.instance .. " " + end + if c.role then + mypromptbox[s].text = mypromptbox[s].text .. "Role: ".. crole + end + end + end)) -- Layout manipulation -key({ modkey }, "l", function () awful.tag.incmwfact(0.05) end):add() -key({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add() -key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add() -key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add() -key({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add() -key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end):add() -key({ modkey }, "space", function () awful.layout.inc(layouts, 1) end):add() -key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add() +table.insert(globalkeys, key({ modkey }, "l", function () awful.tag.incmwfact(0.05) end)) +table.insert(globalkeys, key({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end)) +table.insert(globalkeys, key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end)) +table.insert(globalkeys, key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end)) +table.insert(globalkeys, key({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end)) +table.insert(globalkeys, key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end)) +table.insert(globalkeys, key({ modkey }, "space", function () awful.layout.inc(layouts, 1) end)) +table.insert(globalkeys, key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end)) -- Prompt -key({ modkey }, "F1", function () - awful.prompt.run({ prompt = "Run: " }, mypromptbox[mouse.screen], - awful.util.spawn, awful.completion.bash, - awful.util.getdir("cache") .. "/history") - end):add() -key({ modkey }, "F4", function () - awful.prompt.run({ prompt = "Run Lua code: " }, mypromptbox[mouse.screen], - awful.util.eval, awful.prompt.bash, - awful.util.getdir("cache") .. "/history_eval") - end):add() - -key({ modkey, "Ctrl" }, "i", function () - local s = mouse.screen - if mypromptbox[s].text then - mypromptbox[s].text = nil - elseif client.focus then - mypromptbox[s].text = nil - if client.focus.class then - mypromptbox[s].text = "Class: " .. client.focus.class .. " " - end - if client.focus.instance then - mypromptbox[s].text = mypromptbox[s].text .. "Instance: ".. client.focus.instance .. " " - end - if client.focus.role then - mypromptbox[s].text = mypromptbox[s].text .. "Role: ".. client.focus.role - end - end - end):add() +table.insert(globalkeys, key({ modkey }, "F1", function () + awful.prompt.run({ prompt = "Run: " }, + mypromptbox[mouse.screen], + awful.util.spawn, awful.completion.bash, + awful.util.getdir("cache") .. "/history") + end)) +table.insert(globalkeys, key({ modkey }, "F4", function () + awful.prompt.run({ prompt = "Run Lua code: " }, + mypromptbox[mouse.screen], + awful.util.eval, awful.prompt.bash, + awful.util.getdir("cache") .. "/history_eval") + end)) -- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them -key({ modkey }, "t", awful.client.togglemarked):add() +table.insert(clientkeys, key({ modkey }, "t", awful.client.togglemarked)) for i = 1, keynumber do - key({ modkey, "Shift" }, "F" .. i, - function () - local screen = mouse.screen - if tags[screen][i] then - for k, c in pairs(awful.client.getmarked()) do - awful.client.movetotag(tags[screen][i], c) - end - end - end):add() + table.insert(globalkeys, key({ modkey, "Shift" }, "F" .. i, + function () + local screen = mouse.screen + if tags[screen][i] then + for k, c in pairs(awful.client.getmarked()) do + awful.client.movetotag(tags[screen][i], c) + end + end + end)) end + +-- Set keys +root.keys(globalkeys) -- }}} -- {{{ Hooks @@ -374,6 +388,9 @@ awful.hooks.manage.register(function (c, startup) -- Do this after tag mapping, so you don't see it on the wrong tag for a split second. client.focus = c + -- Set key bindings + c:keys(clientkeys) + -- Set the windows at the slave, -- i.e. put it at the end of others instead of setting it master. -- awful.client.setslave(c) diff --git a/client.c b/client.c index 3dd8e614..e75bde75 100644 --- a/client.c +++ b/client.c @@ -1897,6 +1897,30 @@ luaA_client_buttons(lua_State *L) return luaA_button_array_get(L, buttons); } +/** Get or set keys bindings for a client. + * \param L The Lua VM state. + * \return The number of element pushed on stack. + * \luastack + * \lvalue A client. + * \lparam An array of key bindings objects, or nothing. + * \return The array of key bindings objects of this client. + */ +static int +luaA_client_keys(lua_State *L) +{ + client_t **c = luaA_checkudata(L, 1, "client"); + keybindings_t *keys = &(*c)->keys; + + if(lua_gettop(L) == 2) + { + luaA_key_array_set(L, 2, keys); + xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, (*c)->win, XCB_BUTTON_MASK_ANY); + window_grabkeys((*c)->win, keys); + } + + return luaA_key_array_get(L, keys); +} + /** Send fake events to a client. * \param L The Lua VM state. * \return The number of element pushed on stack. @@ -2045,6 +2069,7 @@ const struct luaL_reg awesome_client_meta[] = { "isvisible", luaA_client_isvisible }, { "geometry", luaA_client_geometry }, { "buttons", luaA_client_buttons }, + { "keys", luaA_client_keys }, { "tags", luaA_client_tags }, { "kill", luaA_client_kill }, { "swap", luaA_client_swap }, diff --git a/event.c b/event.c index 8e0e4cbf..ee1035e0 100644 --- a/event.c +++ b/event.c @@ -542,6 +542,8 @@ event_handle_key(void *data __attribute__ ((unused)), xcb_connection_t *connection __attribute__ ((unused)), xcb_key_press_event_t *ev) { + client_t *c; + if(globalconf.keygrabber != LUA_REFNIL) { lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.keygrabber); @@ -557,9 +559,32 @@ event_handle_key(void *data __attribute__ ((unused)), } lua_pop(globalconf.L, 1); /* pop returned value or function if not called */ } + else if((c = client_getbywin(ev->event))) + { + keyb_t *k = key_find(&c->keys, ev); + + if(k) + switch(ev->response_type) + { + case XCB_KEY_PRESS: + if(k->press != LUA_REFNIL) + { + luaA_client_userdata_new(globalconf.L, c); + luaA_dofunction(globalconf.L, k->press, 1, 0); + } + break; + case XCB_KEY_RELEASE: + if(k->release != LUA_REFNIL) + { + luaA_client_userdata_new(globalconf.L, c); + luaA_dofunction(globalconf.L, k->release, 1, 0); + } + break; + } + } else { - keyb_t *k = key_find(ev); + keyb_t *k = key_find(&globalconf.keys, ev); if(k) switch(ev->response_type) @@ -746,9 +771,6 @@ event_handle_mappingnotify(void *data, if(ev->request == XCB_MAPPING_MODIFIER || ev->request == XCB_MAPPING_KEYBOARD) { - int nscreen = xcb_setup_roots_length(xcb_get_setup(connection)); - int phys_screen = 0; - /* Send the request to get the NumLock, ShiftLock and CapsLock masks */ xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection); @@ -761,23 +783,22 @@ event_handle_mappingnotify(void *data, globalconf.keysyms, &globalconf.numlockmask, &globalconf.shiftlockmask, &globalconf.capslockmask); - do - { - xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen); - /* yes XCB_BUTTON_MASK_ANY is also for grab_key even if it's look - * weird */ - xcb_ungrab_key(connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY); - phys_screen++; - } while(phys_screen < nscreen); + int nscreen = xcb_setup_roots_length(xcb_get_setup(connection)); /* regrab everything */ - key_array_t *arr = &globalconf.keys.by_sym; - for(int i = 0; i < arr->len; i++) - window_root_grabkey(arr->tab[i]); + for(int phys_screen = 0; phys_screen < nscreen; phys_screen++) + { + xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen); + /* yes XCB_BUTTON_MASK_ANY is also for grab_key even if it's look weird */ + xcb_ungrab_key(connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY); + window_grabkeys(s->root, &globalconf.keys); + } - arr = &globalconf.keys.by_code; - for(int i = 0; i < arr->len; i++) - window_root_grabkey(arr->tab[i]); + for(client_t *c = globalconf.clients; c; c = c->next) + { + xcb_ungrab_key(connection, XCB_GRAB_ANY, c->win, XCB_BUTTON_MASK_ANY); + window_grabkeys(c->win, &c->keys); + } } return 0; diff --git a/key.c b/key.c index 677e3161..58680564 100644 --- a/key.c +++ b/key.c @@ -40,6 +40,20 @@ ARRAY_FUNCS(keyb_t *, key, key_unref) DO_LUA_NEW(static, keyb_t, key, "key", key_ref) DO_LUA_GC(keyb_t, key, "key", key_unref) +static void +keybindings_init(keybindings_t *kb) +{ + key_array_init(&kb->by_code); + key_array_init(&kb->by_sym); +} + +static void +keybindings_wipe(keybindings_t *kb) +{ + key_array_wipe(&kb->by_code); + key_array_wipe(&kb->by_sym); +} + static int key_ev_cmp(xcb_keysym_t keysym, xcb_keycode_t keycode, unsigned long mod, const keyb_t *k) @@ -68,68 +82,45 @@ key_cmp(const keyb_t *k1, const keyb_t *k2) return k1->mod == k2->mod ? 0 : (k2->mod > k1->mod ? 1 : -1); } -/** Grab key on the root windows. +/** Grab key on a window. + * \param win The window. * \param k The key. */ -void -window_root_grabkey(keyb_t *k) +static void +window_grabkey(xcb_window_t win, keyb_t *k) { - int phys_screen = 0; - int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); - 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 = xutil_screen_get(globalconf.connection, phys_screen); - xcb_grab_key(globalconf.connection, true, s->root, - k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); - xcb_grab_key(globalconf.connection, true, s->root, - k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); - xcb_grab_key(globalconf.connection, true, s->root, - k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); - xcb_grab_key(globalconf.connection, true, s->root, - k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC); - phys_screen++; - } while(phys_screen < nscreen); + { + xcb_grab_key(globalconf.connection, true, win, + k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + xcb_grab_key(globalconf.connection, true, win, + k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + xcb_grab_key(globalconf.connection, true, win, + k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + xcb_grab_key(globalconf.connection, true, win, + k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC); + } } -/** Ungrab key on the root windows. - * \param k The key. - */ -static void -window_root_ungrabkey(keyb_t *k) +void +window_grabkeys(xcb_window_t win, keybindings_t *keys) { - int phys_screen = 0; - int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); - xcb_screen_t *s; - xcb_keycode_t kc; + for(int i = 0; i < keys->by_code.len; i++) + window_grabkey(win, keys->by_code.tab[i]); - if((kc = k->keycode) - || (k->keysym && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym)))) - do - { - s = xutil_screen_get(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(phys_screen < nscreen); + for(int i = 0; i < keys->by_sym.len; i++) + window_grabkey(win, keys->by_sym.tab[i]); } static void -key_register_root(keyb_t *k) +key_register(keybindings_t *keys, keyb_t *k) { - key_array_t *arr = k->keysym ? &globalconf.keys.by_sym : &globalconf.keys.by_code; + key_array_t *arr = k->keysym ? &keys->by_sym : &keys->by_code; int l = 0, r = arr->len; key_ref(&k); @@ -151,31 +142,6 @@ key_register_root(keyb_t *k) } key_array_splice(arr, r, 0, &k, 1); - window_root_grabkey(k); -} - -static void -key_unregister_root(keyb_t **k) -{ - key_array_t *arr = (*k)->keysym ? &globalconf.keys.by_sym : &globalconf.keys.by_code; - int l = 0, r = arr->len; - - while (l < r) { - int i = (r + l) / 2; - switch (key_cmp(*k, arr->tab[i])) { - case -1: /* k < arr->tab[i] */ - r = i; - break; - case 0: /* k == arr->tab[i] */ - key_array_take(arr, i); - window_root_ungrabkey(*k); - key_unref(k); - return; - case 1: /* k > arr->tab[i] */ - l = i + 1; - break; - } - } } /** Return the keysym from keycode. @@ -256,9 +222,9 @@ key_getkeysym(xcb_keycode_t detail, uint16_t state) keyb_t * -key_find(const xcb_key_press_event_t *ev) +key_find(keybindings_t *keys, const xcb_key_press_event_t *ev) { - const key_array_t *arr = &globalconf.keys.by_sym; + const key_array_t *arr = &keys->by_sym; int l, r, mod = XUTIL_MASK_CLEAN(ev->state); xcb_keysym_t keysym; @@ -283,9 +249,9 @@ key_find(const xcb_key_press_event_t *ev) break; } } - if (arr != &globalconf.keys.by_code) + if(arr != &keys->by_code) { - arr = &globalconf.keys.by_code; + arr = &keys->by_code; goto again; } return NULL; @@ -360,6 +326,55 @@ luaA_key_new(lua_State *L) return luaA_key_userdata_new(L, k); } +/** Set a key array with a Lua table. + * \param L The Lua VM state. + * \param idx The index of the Lua table. + * \param keys The array key to fill. + */ +void +luaA_key_array_set(lua_State *L, int idx, keybindings_t *keys) +{ + luaA_checktable(L, idx); + + for(int i = 0; i < keys->by_code.len; i++); + + for(int i = 0; i < keys->by_sym.len; i++); + + keybindings_wipe(keys); + + keybindings_init(keys); + + lua_pushnil(L); + while(lua_next(L, idx)) + { + keyb_t **k = luaA_checkudata(L, -1, "key"); + key_register(keys, *k); + lua_pop(L, 1); + } +} + +/** Push an array of key as an Lua table onto the stack. + * \param L The Lua VM state. + * \param keys The key array to push. + * \return The number of elements pushed on stack. + */ +int +luaA_key_array_get(lua_State *L, keybindings_t *keys) +{ + luaA_otable_new(L); + for(int i = 0; i < keys->by_code.len; i++) + { + luaA_key_userdata_new(L, keys->by_code.tab[i]); + lua_rawseti(L, -2, i + 1); + } + for(int i = 0; i < keys->by_sym.len; i++) + { + luaA_key_userdata_new(L, keys->by_sym.tab[i]); + lua_rawseti(L, -2, i + 1); + } + return 1; +} + /** Add a global key binding. This key binding will always be available. * \param L The Lua VM state. * @@ -369,8 +384,19 @@ luaA_key_new(lua_State *L) static int luaA_key_add(lua_State *L) { + luaA_deprecate(L, "root.keys"); keyb_t **k = luaA_checkudata(L, 1, "key"); - key_register_root(*k); + int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); + + key_register(&globalconf.keys, *k); + + for(int phys_screen = 0; phys_screen < nscreen; phys_screen++) + { + xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen); + xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY); + window_grabkeys(s->root, &globalconf.keys); + } + return 0; } @@ -383,8 +409,7 @@ luaA_key_add(lua_State *L) static int luaA_key_remove(lua_State *L) { - keyb_t **k = luaA_checkudata(L, 1, "key"); - key_unregister_root(k); + luaA_deprecate(L, "root.keys"); return 0; } diff --git a/key.h b/key.h index 8c974529..796872b9 100644 --- a/key.h +++ b/key.h @@ -44,9 +44,20 @@ typedef struct keyb_t ARRAY_TYPE(keyb_t *, key) -keyb_t *key_find(const xcb_key_press_event_t *); +/** Key bindings */ +typedef struct +{ + key_array_t by_code; + key_array_t by_sym; +} keybindings_t; + +keyb_t *key_find(keybindings_t *, const xcb_key_press_event_t *); xcb_keysym_t key_getkeysym(xcb_keycode_t, uint16_t); -void window_root_grabkey(keyb_t *); + +void luaA_key_array_set(lua_State *, int, keybindings_t *); +int luaA_key_array_get(lua_State *, keybindings_t *); + +void window_grabkeys(xcb_window_t, keybindings_t *); int luaA_key_new(lua_State *); diff --git a/luaa.c b/luaa.c index 9add4aa4..025eaf3a 100644 --- a/luaa.c +++ b/luaa.c @@ -84,24 +84,51 @@ static ev_io csio = { .fd = -1 }; #define XDG_CONFIG_HOME_DEFAULT "/.config" -/** Get or +/** Get or set global key bindings. + * This binding will be available when you'll press keys on root window. + * \param L The Lua VM state. + * \return The number of element pushed on stack. + * \luastack + * \lvalue A client. + * \lparam An array of key bindings objects, or nothing. + * \return The array of key bindings objects of this client. + */ +static int +luaA_root_keys(lua_State *L) +{ + if(lua_gettop(L) == 1) + { + luaA_key_array_set(L, 1, &globalconf.keys); + + int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); + + for(int phys_screen = 0; phys_screen < nscreen; phys_screen++) + { + xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen); + xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY); + window_grabkeys(s->root, &globalconf.keys); + } + } + + return luaA_key_array_get(L, &globalconf.keys); +} + +/** Get or set global mouse bindings. * This binding will be available when you'll click on root window. * \param L The Lua VM state. * \return The number of element pushed on stack. * \luastack * \lvalue A client. * \lparam An array of mouse button bindings objects, or nothing. - * \return The array of mouse button bindings objects of this client. + * \return The array of mouse button bindings objects. */ static int luaA_root_buttons(lua_State *L) { - button_array_t *buttons = &globalconf.buttons; - if(lua_gettop(L) == 1) - luaA_button_array_set(L, 1, buttons); + luaA_button_array_set(L, 1, &globalconf.buttons); - return luaA_button_array_get(L, buttons); + return luaA_button_array_get(L, &globalconf.buttons); } /** Get or set global mouse bindings (DEPRECATED). @@ -111,7 +138,7 @@ luaA_root_buttons(lua_State *L) * \luastack * \lvalue A client. * \lparam An array of mouse button bindings objects, or nothing. - * \return The array of mouse button bindings objects of this client. + * \return The array of mouse button bindings objects. */ static int luaA_buttons(lua_State *L) @@ -808,6 +835,7 @@ luaA_init(void) static const struct luaL_reg root_lib[] = { { "buttons", luaA_root_buttons }, + { "keys", luaA_root_keys }, { NULL, NULL } }; diff --git a/structs.h b/structs.h index 8f75b2f2..a0cfc446 100644 --- a/structs.h +++ b/structs.h @@ -218,6 +218,8 @@ struct client_t wibox_t *titlebar; /** Button bindings */ button_array_t buttons; + /** Key bindings */ + keybindings_t keys; /** Icon */ image_t *icon; /** Size hints */ @@ -290,13 +292,9 @@ struct awesome_t int nscreen; /** True if xinerama is active */ bool xinerama_is_active; - /** Key bindings */ - struct - { - key_array_t by_code; - key_array_t by_sym; - } keys; - /** Mouse bindings list */ + /** Root window key bindings */ + keybindings_t keys; + /** Root window mouse bindings */ button_array_t buttons; /** Numlock mask */ unsigned int numlockmask;