client: implements per-client key bindings

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2009-01-05 16:59:20 +01:00
parent bf44ae1e03
commit d9c868b627
7 changed files with 335 additions and 210 deletions

View File

@ -168,7 +168,6 @@ root.buttons({
-- }}} -- }}}
-- {{{ Key bindings -- {{{ Key bindings
-- Bind keyboard digits -- Bind keyboard digits
-- Compute the maximum number of digit we need, limited to 9 -- Compute the maximum number of digit we need, limited to 9
keynumber = 0 keynumber = 0
@ -176,120 +175,135 @@ for s = 1, screen.count() do
keynumber = math.min(9, math.max(#tags[s], keynumber)); keynumber = math.min(9, math.max(#tags[s], keynumber));
end end
globalkeys = {}
clientkeys = {}
for i = 1, keynumber do for i = 1, keynumber do
key({ modkey }, i, table.insert(globalkeys,
function () key({ modkey }, i,
local screen = mouse.screen function ()
if tags[screen][i] then local screen = mouse.screen
awful.tag.viewonly(tags[screen][i]) if tags[screen][i] then
end awful.tag.viewonly(tags[screen][i])
end):add() end
key({ modkey, "Control" }, i, end))
function () table.insert(globalkeys,
local screen = mouse.screen key({ modkey, "Control" }, i,
if tags[screen][i] then function ()
tags[screen][i].selected = not tags[screen][i].selected local screen = mouse.screen
end if tags[screen][i] then
end):add() tags[screen][i].selected = not tags[screen][i].selected
key({ modkey, "Shift" }, i, end
function () end))
if client.focus and tags[client.focus.screen][i] then table.insert(globalkeys,
awful.client.movetotag(tags[client.focus.screen][i]) key({ modkey, "Shift" }, i,
end function ()
end):add() if client.focus and tags[client.focus.screen][i] then
key({ modkey, "Control", "Shift" }, i, awful.client.movetotag(tags[client.focus.screen][i])
function () end
if client.focus and tags[client.focus.screen][i] then end))
awful.client.toggletag(tags[client.focus.screen][i]) table.insert(globalkeys,
end key({ modkey, "Control", "Shift" }, i,
end):add() function ()
if client.focus and tags[client.focus.screen][i] then
awful.client.toggletag(tags[client.focus.screen][i])
end
end))
end end
key({ modkey }, "Left", awful.tag.viewprev):add() table.insert(globalkeys, key({ modkey }, "Left", awful.tag.viewprev))
key({ modkey }, "Right", awful.tag.viewnext):add() table.insert(globalkeys, key({ modkey }, "Right", awful.tag.viewnext))
key({ modkey }, "Escape", awful.tag.history.restore):add() 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 -- 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 () table.insert(globalkeys, key({ modkey, "Control" }, "r", function ()
mypromptbox[mouse.screen].text = mypromptbox[mouse.screen].text =
awful.util.escape(awful.util.restart()) awful.util.escape(awful.util.restart())
end):add() end))
key({ modkey, "Shift" }, "q", awesome.quit):add() table.insert(globalkeys, key({ modkey, "Shift" }, "q", awesome.quit))
-- Client manipulation -- Client manipulation
key({ modkey }, "m", function () if client.focus then client.focus.maximized_horizontal = not client.focus.maximized_horizontal table.insert(clientkeys, key({ modkey }, "m", function (c) c.maximized_horizontal = not c.maximized_horizontal
client.focus.maximized_vertical = not client.focus.maximized_vertical end end):add() c.maximized_vertical = not c.maximized_vertical end))
key({ modkey }, "f", function () if client.focus then client.focus.fullscreen = not client.focus.fullscreen end end):add() table.insert(clientkeys, key({ modkey }, "f", function (c) c.fullscreen = not c.fullscreen end))
key({ modkey, "Shift" }, "c", function () if client.focus then client.focus:kill() end end):add() table.insert(clientkeys, key({ modkey, "Shift" }, "c", function (c) c:kill() end))
key({ modkey }, "j", function () awful.client.focus.byidx(1); if client.focus then client.focus:raise() end end):add() table.insert(clientkeys, key({ modkey, "Control" }, "space", awful.client.floating.toggle))
key({ modkey }, "k", function () awful.client.focus.byidx(-1); if client.focus then client.focus:raise() end end):add() table.insert(clientkeys, key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end))
key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx(1) end):add() table.insert(clientkeys, key({ modkey }, "o", awful.client.movetoscreen))
key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx(-1) end):add() table.insert(clientkeys, key({ modkey, "Shift" }, "r", function (c) c:redraw() end))
key({ modkey, "Control" }, "j", function () awful.screen.focus(1) end):add() table.insert(clientkeys, key({ modkey, "Ctrl" }, "i", function (c)
key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end):add() local s = c.screen
key({ modkey, "Control" }, "space", awful.client.floating.toggle):add() if mypromptbox[s].text then
key({ modkey, "Control" }, "Return", function () if client.focus then client.focus:swap(awful.client.getmaster()) end end):add() mypromptbox[s].text = nil
key({ modkey }, "o", awful.client.movetoscreen):add() else
key({ modkey }, "Tab", function () awful.client.focus.history.previous(); if client.focus then client.focus:raise() end end):add() mypromptbox[s].text = nil
key({ modkey }, "u", awful.client.urgent.jumpto):add() if c.class then
key({ modkey, "Shift" }, "r", function () if client.focus then client.focus:redraw() end end):add() 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 -- Layout manipulation
key({ modkey }, "l", function () awful.tag.incmwfact(0.05) end):add() table.insert(globalkeys, key({ modkey }, "l", function () awful.tag.incmwfact(0.05) end))
key({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add() table.insert(globalkeys, key({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end))
key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add() table.insert(globalkeys, key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end))
key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add() table.insert(globalkeys, key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end))
key({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add() table.insert(globalkeys, key({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end))
key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end):add() table.insert(globalkeys, key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end))
key({ modkey }, "space", function () awful.layout.inc(layouts, 1) end):add() table.insert(globalkeys, key({ modkey }, "space", function () awful.layout.inc(layouts, 1) end))
key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add() table.insert(globalkeys, key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end))
-- Prompt -- Prompt
key({ modkey }, "F1", function () table.insert(globalkeys, key({ modkey }, "F1", function ()
awful.prompt.run({ prompt = "Run: " }, mypromptbox[mouse.screen], awful.prompt.run({ prompt = "Run: " },
awful.util.spawn, awful.completion.bash, mypromptbox[mouse.screen],
awful.util.getdir("cache") .. "/history") awful.util.spawn, awful.completion.bash,
end):add() awful.util.getdir("cache") .. "/history")
key({ modkey }, "F4", function () end))
awful.prompt.run({ prompt = "Run Lua code: " }, mypromptbox[mouse.screen], table.insert(globalkeys, key({ modkey }, "F4", function ()
awful.util.eval, awful.prompt.bash, awful.prompt.run({ prompt = "Run Lua code: " },
awful.util.getdir("cache") .. "/history_eval") mypromptbox[mouse.screen],
end):add() awful.util.eval, awful.prompt.bash,
awful.util.getdir("cache") .. "/history_eval")
key({ modkey, "Ctrl" }, "i", function () end))
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()
-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them -- 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 for i = 1, keynumber do
key({ modkey, "Shift" }, "F" .. i, table.insert(globalkeys, key({ modkey, "Shift" }, "F" .. i,
function () function ()
local screen = mouse.screen local screen = mouse.screen
if tags[screen][i] then if tags[screen][i] then
for k, c in pairs(awful.client.getmarked()) do for k, c in pairs(awful.client.getmarked()) do
awful.client.movetotag(tags[screen][i], c) awful.client.movetotag(tags[screen][i], c)
end end
end end
end):add() end))
end end
-- Set keys
root.keys(globalkeys)
-- }}} -- }}}
-- {{{ Hooks -- {{{ 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. -- Do this after tag mapping, so you don't see it on the wrong tag for a split second.
client.focus = c client.focus = c
-- Set key bindings
c:keys(clientkeys)
-- Set the windows at the slave, -- Set the windows at the slave,
-- i.e. put it at the end of others instead of setting it master. -- i.e. put it at the end of others instead of setting it master.
-- awful.client.setslave(c) -- awful.client.setslave(c)

View File

@ -1897,6 +1897,30 @@ luaA_client_buttons(lua_State *L)
return luaA_button_array_get(L, buttons); 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. /** Send fake events to a client.
* \param L The Lua VM state. * \param L The Lua VM state.
* \return The number of element pushed on stack. * \return The number of element pushed on stack.
@ -2045,6 +2069,7 @@ const struct luaL_reg awesome_client_meta[] =
{ "isvisible", luaA_client_isvisible }, { "isvisible", luaA_client_isvisible },
{ "geometry", luaA_client_geometry }, { "geometry", luaA_client_geometry },
{ "buttons", luaA_client_buttons }, { "buttons", luaA_client_buttons },
{ "keys", luaA_client_keys },
{ "tags", luaA_client_tags }, { "tags", luaA_client_tags },
{ "kill", luaA_client_kill }, { "kill", luaA_client_kill },
{ "swap", luaA_client_swap }, { "swap", luaA_client_swap },

57
event.c
View File

@ -542,6 +542,8 @@ event_handle_key(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)
{ {
client_t *c;
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);
@ -557,9 +559,32 @@ event_handle_key(void *data __attribute__ ((unused)),
} }
lua_pop(globalconf.L, 1); /* pop returned value or function if not called */ 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 else
{ {
keyb_t *k = key_find(ev); keyb_t *k = key_find(&globalconf.keys, ev);
if(k) if(k)
switch(ev->response_type) switch(ev->response_type)
@ -746,9 +771,6 @@ event_handle_mappingnotify(void *data,
if(ev->request == XCB_MAPPING_MODIFIER if(ev->request == XCB_MAPPING_MODIFIER
|| ev->request == XCB_MAPPING_KEYBOARD) || 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 */ /* Send the request to get the NumLock, ShiftLock and CapsLock masks */
xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection); xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection);
@ -761,23 +783,22 @@ event_handle_mappingnotify(void *data,
globalconf.keysyms, &globalconf.numlockmask, globalconf.keysyms, &globalconf.numlockmask,
&globalconf.shiftlockmask, &globalconf.capslockmask); &globalconf.shiftlockmask, &globalconf.capslockmask);
do int nscreen = xcb_setup_roots_length(xcb_get_setup(connection));
{
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);
/* regrab everything */ /* regrab everything */
key_array_t *arr = &globalconf.keys.by_sym; for(int phys_screen = 0; phys_screen < nscreen; phys_screen++)
for(int i = 0; i < arr->len; i++) {
window_root_grabkey(arr->tab[i]); 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(client_t *c = globalconf.clients; c; c = c->next)
for(int i = 0; i < arr->len; i++) {
window_root_grabkey(arr->tab[i]); xcb_ungrab_key(connection, XCB_GRAB_ANY, c->win, XCB_BUTTON_MASK_ANY);
window_grabkeys(c->win, &c->keys);
}
} }
return 0; return 0;

181
key.c
View File

@ -40,6 +40,20 @@ ARRAY_FUNCS(keyb_t *, key, key_unref)
DO_LUA_NEW(static, keyb_t, key, "key", key_ref) DO_LUA_NEW(static, keyb_t, key, "key", key_ref)
DO_LUA_GC(keyb_t, key, "key", key_unref) 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 static int
key_ev_cmp(xcb_keysym_t keysym, xcb_keycode_t keycode, key_ev_cmp(xcb_keysym_t keysym, xcb_keycode_t keycode,
unsigned long mod, const keyb_t *k) 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); 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. * \param k The key.
*/ */
void static void
window_root_grabkey(keyb_t *k) 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; xcb_keycode_t kc;
if((kc = k->keycode) if((kc = k->keycode)
|| (k->keysym || (k->keysym
&& (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym)))) && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym))))
do {
{ xcb_grab_key(globalconf.connection, true, win,
s = xutil_screen_get(globalconf.connection, phys_screen); k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(globalconf.connection, true, s->root, xcb_grab_key(globalconf.connection, true, win,
k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(globalconf.connection, true, s->root, xcb_grab_key(globalconf.connection, true, win,
k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(globalconf.connection, true, s->root, xcb_grab_key(globalconf.connection, true, win,
k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC,
xcb_grab_key(globalconf.connection, true, s->root, XCB_GRAB_MODE_ASYNC);
k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, }
XCB_GRAB_MODE_ASYNC);
phys_screen++;
} while(phys_screen < nscreen);
} }
/** Ungrab key on the root windows. void
* \param k The key. window_grabkeys(xcb_window_t win, keybindings_t *keys)
*/
static void
window_root_ungrabkey(keyb_t *k)
{ {
int phys_screen = 0; for(int i = 0; i < keys->by_code.len; i++)
int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); window_grabkey(win, keys->by_code.tab[i]);
xcb_screen_t *s;
xcb_keycode_t kc;
if((kc = k->keycode) for(int i = 0; i < keys->by_sym.len; i++)
|| (k->keysym && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym)))) window_grabkey(win, keys->by_sym.tab[i]);
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);
} }
static void 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; int l = 0, r = arr->len;
key_ref(&k); key_ref(&k);
@ -151,31 +142,6 @@ key_register_root(keyb_t *k)
} }
key_array_splice(arr, r, 0, &k, 1); 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. /** Return the keysym from keycode.
@ -256,9 +222,9 @@ key_getkeysym(xcb_keycode_t detail, uint16_t state)
keyb_t * 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); int l, r, mod = XUTIL_MASK_CLEAN(ev->state);
xcb_keysym_t keysym; xcb_keysym_t keysym;
@ -283,9 +249,9 @@ key_find(const xcb_key_press_event_t *ev)
break; break;
} }
} }
if (arr != &globalconf.keys.by_code) if(arr != &keys->by_code)
{ {
arr = &globalconf.keys.by_code; arr = &keys->by_code;
goto again; goto again;
} }
return NULL; return NULL;
@ -360,6 +326,55 @@ luaA_key_new(lua_State *L)
return luaA_key_userdata_new(L, k); 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. /** Add a global key binding. This key binding will always be available.
* \param L The Lua VM state. * \param L The Lua VM state.
* *
@ -369,8 +384,19 @@ luaA_key_new(lua_State *L)
static int static int
luaA_key_add(lua_State *L) luaA_key_add(lua_State *L)
{ {
luaA_deprecate(L, "root.keys");
keyb_t **k = luaA_checkudata(L, 1, "key"); 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; return 0;
} }
@ -383,8 +409,7 @@ luaA_key_add(lua_State *L)
static int static int
luaA_key_remove(lua_State *L) luaA_key_remove(lua_State *L)
{ {
keyb_t **k = luaA_checkudata(L, 1, "key"); luaA_deprecate(L, "root.keys");
key_unregister_root(k);
return 0; return 0;
} }

15
key.h
View File

@ -44,9 +44,20 @@ typedef struct keyb_t
ARRAY_TYPE(keyb_t *, key) 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); 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 *); int luaA_key_new(lua_State *);

42
luaa.c
View File

@ -84,24 +84,51 @@ static ev_io csio = { .fd = -1 };
#define XDG_CONFIG_HOME_DEFAULT "/.config" #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. * This binding will be available when you'll click on root window.
* \param L The Lua VM state. * \param L The Lua VM state.
* \return The number of element pushed on stack. * \return The number of element pushed on stack.
* \luastack * \luastack
* \lvalue A client. * \lvalue A client.
* \lparam An array of mouse button bindings objects, or nothing. * \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 static int
luaA_root_buttons(lua_State *L) luaA_root_buttons(lua_State *L)
{ {
button_array_t *buttons = &globalconf.buttons;
if(lua_gettop(L) == 1) 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). /** Get or set global mouse bindings (DEPRECATED).
@ -111,7 +138,7 @@ luaA_root_buttons(lua_State *L)
* \luastack * \luastack
* \lvalue A client. * \lvalue A client.
* \lparam An array of mouse button bindings objects, or nothing. * \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 static int
luaA_buttons(lua_State *L) luaA_buttons(lua_State *L)
@ -808,6 +835,7 @@ luaA_init(void)
static const struct luaL_reg root_lib[] = static const struct luaL_reg root_lib[] =
{ {
{ "buttons", luaA_root_buttons }, { "buttons", luaA_root_buttons },
{ "keys", luaA_root_keys },
{ NULL, NULL } { NULL, NULL }
}; };

View File

@ -218,6 +218,8 @@ struct client_t
wibox_t *titlebar; wibox_t *titlebar;
/** Button bindings */ /** Button bindings */
button_array_t buttons; button_array_t buttons;
/** Key bindings */
keybindings_t keys;
/** Icon */ /** Icon */
image_t *icon; image_t *icon;
/** Size hints */ /** Size hints */
@ -290,13 +292,9 @@ struct awesome_t
int nscreen; int nscreen;
/** True if xinerama is active */ /** True if xinerama is active */
bool xinerama_is_active; bool xinerama_is_active;
/** Key bindings */ /** Root window key bindings */
struct keybindings_t keys;
{ /** Root window mouse bindings */
key_array_t by_code;
key_array_t by_sym;
} keys;
/** Mouse bindings list */
button_array_t buttons; button_array_t buttons;
/** Numlock mask */ /** Numlock mask */
unsigned int numlockmask; unsigned int numlockmask;