From 3b895d84ed12ba3437f6bb8da7c9b6051db48cbc Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 12 Aug 2008 13:23:10 +0200 Subject: [PATCH] mouse: rework mouse buttons API, support release events Signed-off-by: Julien Danjou --- awesomerc.lua.in | 48 ++++++++++++--------- client.c | 55 ++++++++++-------------- common/swindow.c | 9 ++-- event.c | 68 ++++++++++++++++++------------ keybinding.c | 2 +- layout.c | 2 +- lib/awful.lua.in | 11 +++-- lua.c | 46 +++++++++++--------- lua.h | 6 ++- mouse.c | 102 +++++++++++++++++++++++++++++++++++++++------ mouse.h | 7 +++- structs.h | 27 ++++++------ widget.c | 62 +++++++++++---------------- widgets/taglist.c | 33 ++++++++------- widgets/tasklist.c | 26 +++++++----- window.c | 26 ++++++------ window.h | 3 +- 17 files changed, 317 insertions(+), 216 deletions(-) diff --git a/awesomerc.lua.in b/awesomerc.lua.in index d8906f76b..d1d05eff7 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -94,19 +94,23 @@ end -- {{{ Statusbar -- Create a taglist widget mytaglist = widget({ type = "taglist", name = "mytaglist" }) -mytaglist:mouse_add(mouse({}, 1, function (object, tag) awful.tag.viewonly(tag) end)) -mytaglist:mouse_add(mouse({ modkey }, 1, function (object, tag) awful.client.movetotag(tag) end)) -mytaglist:mouse_add(mouse({}, 3, function (object, tag) tag.selected = not tag.selected end)) -mytaglist:mouse_add(mouse({ modkey }, 3, function (object, tag) awful.client.toggletag(tag) end)) -mytaglist:mouse_add(mouse({ }, 4, awful.tag.viewnext)) -mytaglist:mouse_add(mouse({ }, 5, awful.tag.viewprev)) +mytaglist:buttons({ + button({ }, 1, function (object, tag) awful.tag.viewonly(tag) end), + button({ modkey }, 1, function (object, tag) awful.client.movetotag(tag) end), + button({ }, 3, function (object, tag) tag.selected = not tag.selected end), + button({ modkey }, 3, function (object, tag) awful.client.toggletag(tag) end), + button({ }, 4, awful.tag.viewnext), + button({ }, 5, awful.tag.viewprev) +}) mytaglist.label = awful.widget.taglist.label.all -- Create a tasklist widget mytasklist = widget({ type = "tasklist", name = "mytasklist" }) -mytasklist:mouse_add(mouse({ }, 1, function (object, c) client.focus = c; c:raise() end)) -mytasklist:mouse_add(mouse({ }, 4, function () awful.client.focusbyidx(1) end)) -mytasklist:mouse_add(mouse({ }, 5, function () awful.client.focusbyidx(-1) end)) +mytasklist:buttons({ + button({ }, 1, function (object, c) client.focus = c; c:raise() end), + button({ }, 4, function () awful.client.focusbyidx(1) end), + button({ }, 5, function () awful.client.focusbyidx(-1) end) +}) mytasklist.label = awful.widget.tasklist.label.currenttags -- Create a textbox widget @@ -127,10 +131,12 @@ mysystray = widget({ type = "systray", name = "mysystray", align = "right" }) mylayoutbox = {} for s = 1, screen.count() do mylayoutbox[s] = widget({ type = "textbox", name = "mylayoutbox", align = "right" }) - mylayoutbox[s]:mouse_add(mouse({ }, 1, function () awful.layout.inc(layouts, 1) end)) - mylayoutbox[s]:mouse_add(mouse({ }, 3, function () awful.layout.inc(layouts, -1) end)) - mylayoutbox[s]:mouse_add(mouse({ }, 4, function () awful.layout.inc(layouts, 1) end)) - mylayoutbox[s]:mouse_add(mouse({ }, 5, function () awful.layout.inc(layouts, -1) end)) + mylayoutbox[s]:buttons({ + button({ }, 1, function () awful.layout.inc(layouts, 1) end), + button({ }, 3, function () awful.layout.inc(layouts, -1) end), + button({ }, 4, function () awful.layout.inc(layouts, 1) end), + button({ }, 5, function () awful.layout.inc(layouts, -1) end) + }) mylayoutbox[s].text = "" end @@ -154,9 +160,11 @@ end -- }}} -- {{{ Mouse bindings -awesome.mouse_add(mouse({ }, 3, function () awful.spawn(terminal) end)) -awesome.mouse_add(mouse({ }, 4, awful.tag.viewnext)) -awesome.mouse_add(mouse({ }, 5, awful.tag.viewprev)) +awesome.buttons({ + button({ }, 3, function () awful.spawn(terminal) end), + button({ }, 4, awful.tag.viewnext), + button({ }, 5, awful.tag.viewprev) +}) -- }}} -- {{{ Key bindings @@ -365,9 +373,11 @@ function hook_manage(c) awful.titlebar.add(c, { modkey = modkey }) end -- Add mouse bindings - c:mouse_add(mouse({ }, 1, function (c) client.focus = c; c:raise() end)) - c:mouse_add(mouse({ modkey }, 1, function (c) c:mouse_move() end)) - c:mouse_add(mouse({ modkey }, 3, function (c) c:mouse_resize() end)) + c:buttons({ + button({ }, 1, function (c) client.focus = c; c:raise() end), + button({ modkey }, 1, function (c) c:mouse_move() end), + button({ modkey }, 3, function (c) c:mouse_resize() end) + }) -- New client may not receive focus -- if they're not focusable, so set border anyway. c.border_width = beautiful.border_width diff --git a/client.c b/client.c index 0bd7a27b6..81a77da56 100644 --- a/client.c +++ b/client.c @@ -871,38 +871,6 @@ luaA_client_get(lua_State *L) return 1; } -/** Add mouse bindings over clients's window. - * \param L The Lua VM state. - * \luastack - * \lvalue A client. - * \lparam A button binding. - */ -static int -luaA_client_mouse_add(lua_State *L) -{ - client_t **c = luaA_checkudata(L, 1, "client"); - button_t **b = luaA_checkudata(L, 2, "mouse"); - button_list_push(&(*c)->buttons, *b); - button_ref(b); - return 0; -} - -/** Remove mouse bindings over clients's window. - * \param L The Lua VM state. - * \luastack - * \lvalue A client. - * \lparam A button binding. - */ -static int -luaA_client_mouse_remove(lua_State *L) -{ - client_t **c = luaA_checkudata(L, 1, "client"); - button_t **b = luaA_checkudata(L, 1, "mouse"); - button_list_detach(&(*c)->buttons, *b); - button_unref(b); - return 0; -} - /** Get only visible clients for a screen. * \param L The Lua VM state. * \luastack @@ -1406,6 +1374,26 @@ luaA_client_index(lua_State *L) return 1; } +/** Get or set mouse buttons 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 mouse button bindings objects, or nothing. + * \return The array of mouse button bindings objects of this client. + */ +static int +luaA_client_buttons(lua_State *L) +{ + client_t **client = luaA_checkudata(L, 1, "client"); + button_array_t *buttons = &(*client)->buttons; + + if(lua_gettop(L) == 2) + luaA_button_array_set(L, 2, buttons); + + return luaA_button_array_get(L, buttons); +} + /* Client module. * \param L The Lua VM state. * \return The number of pushed elements. @@ -1467,6 +1455,7 @@ const struct luaL_reg awesome_client_methods[] = const struct luaL_reg awesome_client_meta[] = { { "coords", luaA_client_coords }, + { "buttons", luaA_client_buttons }, { "tags", luaA_client_tags }, { "kill", luaA_client_kill }, { "swap", luaA_client_swap }, @@ -1476,8 +1465,6 @@ const struct luaL_reg awesome_client_meta[] = { "mouse_resize", luaA_client_mouse_resize }, { "mouse_move", luaA_client_mouse_move }, { "unmanage", luaA_client_unmanage }, - { "mouse_add", luaA_client_mouse_add }, - { "mouse_remove", luaA_client_mouse_remove }, { "__index", luaA_client_index }, { "__newindex", luaA_client_newindex }, { "__eq", luaA_client_eq }, diff --git a/common/swindow.c b/common/swindow.c index bcd40050f..7ed5984f4 100644 --- a/common/swindow.c +++ b/common/swindow.c @@ -57,10 +57,11 @@ simplewindow_new(xcb_connection_t *conn, int phys_screen, int x, int y, create_win_val[0] = XCB_BACK_PIXMAP_PARENT_RELATIVE; create_win_val[1] = 1; - create_win_val[2] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW | - XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE; + create_win_val[2] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT + | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW + | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY + | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE + | XCB_EVENT_MASK_EXPOSURE; sw->window = xcb_generate_id(conn); xcb_create_window(conn, s->root_depth, sw->window, s->root, x, y, w, h, diff --git a/event.c b/event.c index 27c44fa80..7bbeda990 100644 --- a/event.c +++ b/event.c @@ -42,41 +42,47 @@ extern awesome_t globalconf; -/** Handle mouse button press. +/** Handle mouse button events. * \param c The client on which the event happened or NULL. - * \param button Button number - * \param state Modkeys state - * \param buttons Buttons list to check for + * \param type Event type, press or release. + * \param button Button number. + * \param state Modkeys state. + * \param buttons Buttons array to check for. */ static void -event_handle_mouse_button_press(client_t *c, - unsigned int button, - unsigned int state, - button_t *buttons) +event_handle_mouse_button(client_t *c, + uint8_t type, + xcb_button_t button, + uint16_t state, + button_array_t *buttons) { - button_t *b; - - for(b = buttons; b; b = b->next) - if(button == b->button && XUTIL_MASK_CLEAN(state) == b->mod && b->fct) + for(int i = 0; i < buttons->len; i++) + if(button == buttons->tab[i]->button + && XUTIL_MASK_CLEAN(state) == buttons->tab[i]->mod) { if(c) { luaA_client_userdata_new(globalconf.L, c); - luaA_dofunction(globalconf.L, b->fct, 1, 0); + luaA_dofunction(globalconf.L, + type == XCB_BUTTON_PRESS ? + buttons->tab[i]->press : buttons->tab[i]->release, + 1, 0); } else - luaA_dofunction(globalconf.L, b->fct, 0, 0); + luaA_dofunction(globalconf.L, + type == XCB_BUTTON_PRESS ? + buttons->tab[i]->press : buttons->tab[i]->release, + 0, 0); } } /** The button press event handler. - * \param data currently unused. + * \param data The type of mouse event. * \param connection The connection to the X server. * \param ev The event. */ static int -event_handle_buttonpress(void *data __attribute__ ((unused)), - xcb_connection_t *connection, xcb_button_press_event_t *ev) +event_handle_button(void *data, xcb_connection_t *connection, xcb_button_press_event_t *ev) { int screen, tmp; const int nb_screen = xcb_setup_roots_length(xcb_get_setup(connection)); @@ -84,6 +90,12 @@ event_handle_buttonpress(void *data __attribute__ ((unused)), widget_node_t *w; statusbar_t *statusbar; + /* ev->state is + * button status (8 bits) + modifiers status (8 bits) + * we don't care for button status that we get, especially on release, so + * drop them */ + ev->state &= 0x00ff; + for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) for(statusbar = globalconf.screens[screen].statusbar; statusbar; statusbar = statusbar->next) if(statusbar->sw @@ -117,8 +129,8 @@ event_handle_buttonpress(void *data __attribute__ ((unused)), if(ev->event_x >= w->area.x && ev->event_x < w->area.x + w->area.width && ev->event_y >= w->area.y && ev->event_y < w->area.y + w->area.height) { - w->widget->button_press(w, ev, statusbar->screen, - statusbar, AWESOME_TYPE_STATUSBAR); + w->widget->button(w, ev, statusbar->screen, + statusbar, AWESOME_TYPE_STATUSBAR); return 0; } /* return if no widget match */ @@ -148,8 +160,8 @@ event_handle_buttonpress(void *data __attribute__ ((unused)), if(ev->event_x >= w->area.x && ev->event_x < w->area.x + w->area.width && ev->event_y >= w->area.y && ev->event_y < w->area.y + w->area.height) { - w->widget->button_press(w, ev, c->screen, - c->titlebar, AWESOME_TYPE_TITLEBAR); + w->widget->button(w, ev, c->screen, + c->titlebar, AWESOME_TYPE_TITLEBAR); return 0; } /* return if no widget match */ @@ -158,15 +170,16 @@ event_handle_buttonpress(void *data __attribute__ ((unused)), if((c = client_getbywin(ev->event))) { - event_handle_mouse_button_press(c, ev->detail, ev->state, c->buttons); - xcb_allow_events(globalconf.connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME); + event_handle_mouse_button(c, ev->response_type, ev->detail, ev->state, &c->buttons); + xcb_allow_events(globalconf.connection, + XCB_ALLOW_REPLAY_POINTER, + XCB_CURRENT_TIME); } else for(screen = 0; screen < nb_screen; screen++) if(xutil_screen_get(connection, screen)->root == ev->event) { - event_handle_mouse_button_press(NULL, ev->detail, ev->state, - globalconf.buttons.root); + event_handle_mouse_button(NULL, ev->response_type, ev->detail, ev->state, &globalconf.buttons); return 0; } @@ -339,7 +352,7 @@ event_handle_enternotify(void *data __attribute__ ((unused)), if((c = client_getbytitlebarwin(ev->event)) || (c = client_getbywin(ev->event))) { - window_buttons_grab(c->win, ev->root, c->buttons); + window_buttons_grab(c->win, ev->root, &c->buttons); /* The idea behind saving pointer_x and pointer_y is Bob Marley powered. * this will allow us top drop some EnterNotify events and thus not giving * focus to windows appering under the cursor without a cursor move */ @@ -686,7 +699,8 @@ void a_xcb_set_event_handlers(void) { const xcb_query_extension_reply_t *randr_query; - xcb_event_set_button_press_handler(&globalconf.evenths, event_handle_buttonpress, NULL); + xcb_event_set_button_press_handler(&globalconf.evenths, event_handle_button, NULL); + xcb_event_set_button_release_handler(&globalconf.evenths, event_handle_button, NULL); xcb_event_set_configure_request_handler(&globalconf.evenths, event_handle_configurerequest, NULL); xcb_event_set_configure_notify_handler(&globalconf.evenths, event_handle_configurenotify, NULL); xcb_event_set_destroy_notify_handler(&globalconf.evenths, event_handle_destroynotify, NULL); diff --git a/keybinding.c b/keybinding.c index 770df8d91..ec88a2b09 100644 --- a/keybinding.c +++ b/keybinding.c @@ -343,7 +343,7 @@ luaA_keybinding_new(lua_State *L) /* get the last arg as function */ k = p_new(keybinding_t, 1); luaA_keystore(k, key, len); - luaA_registerfct(L, &k->fct); + luaA_registerfct(L, 4, &k->fct); len = lua_objlen(L, 2); for(i = 1; i <= len; i++) diff --git a/layout.c b/layout.c index 9850cc735..3037ffa59 100644 --- a/layout.c +++ b/layout.c @@ -60,7 +60,7 @@ arrange(int screen) if(qp_r->child == XCB_NONE || qp_r->root == qp_r->child) window_root_buttons_grab(qp_r->root); else if ((c = client_getbywin(qp_r->child))) - window_buttons_grab(c->win, qp_r->root, c->buttons); + window_buttons_grab(c->win, qp_r->root, &c->buttons); globalconf.pointer_x = qp_r->root_x; globalconf.pointer_y = qp_r->root_y; diff --git a/lib/awful.lua.in b/lib/awful.lua.in index fab592f37..d6c8b6edd 100644 --- a/lib/awful.lua.in +++ b/lib/awful.lua.in @@ -23,6 +23,7 @@ local capi = screen = screen, client = client, mouse = mouse, + button = button, titlebar = titlebar, widget = widget, hooks = hooks, @@ -1497,12 +1498,16 @@ function titlebar.add(c, args) local tb = capi.titlebar(targs) local title = capi.widget({ type = "textbox", name = "title", align = "flex" }) - title:mouse_add(capi.mouse({ }, 1, function (t) t.client:mouse_move() end)) - title:mouse_add(capi.mouse({ args.modkey }, 3, function (t) t.client:mouse_resize() end)) + local bts = + { + capi.button({ }, 1, function (t) t.client:mouse_move() end), + capi.button({ args.modkey }, 3, function (t) t.client:mouse_resize() end) + } + title:button_press(bts) if theme.titlebar_close_button == "true" then local close_button = capi.widget({ type = "textbox", name = "close", align = "right" }) - close_button:mouse_add(capi.mouse({ }, 1, function (t) t.client:kill() end)) + close_button:button_press({ capi.button({ }, 1, function (t) t.client:kill() end) }) tb:widgets({ capi.widget({ type = "appicon", name = "appicon", align = "left" }), diff --git a/lua.c b/lua.c index 94009c7bc..1061e27b6 100644 --- a/lua.c +++ b/lua.c @@ -46,6 +46,7 @@ #include "client.h" #include "screen.h" #include "event.h" +#include "mouse.h" #include "layouts/tile.h" #include "common/socket.h" #include "common/buffer.h" @@ -53,6 +54,8 @@ extern awesome_t globalconf; extern const struct luaL_reg awesome_keygrabber_lib[]; +extern const struct luaL_reg awesome_button_methods[]; +extern const struct luaL_reg awesome_button_meta[]; extern const struct luaL_reg awesome_mouse_methods[]; extern const struct luaL_reg awesome_mouse_meta[]; extern const struct luaL_reg awesome_screen_methods[]; @@ -74,22 +77,24 @@ static struct sockaddr_un *addr; static ev_io csio = { .fd = -1 }; struct ev_io csio2 = { .fd = -1 }; -/** Add a global mouse binding. This binding will be available when you'll - * click on root window. +/** 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 - * \lparam A mouse button binding. + * \lvalue A client. + * \lparam An array of mouse button bindings objects, or nothing. + * \return The array of mouse button bindings objects of this client. */ static int -luaA_mouse_add(lua_State *L) +luaA_buttons(lua_State *L) { - button_t **button = luaA_checkudata(L, 1, "mouse"); + button_array_t *buttons = &globalconf.buttons; - button_list_push(&globalconf.buttons.root, *button); - button_ref(button); + if(lua_gettop(L) == 1) + luaA_button_array_set(L, 1, buttons); - return 0; + return luaA_button_array_get(L, buttons); } /** Quit awesome. @@ -139,7 +144,7 @@ luaA_restart(lua_State *L __attribute__ ((unused))) static int luaA_hooks_focus(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.focus); + return luaA_registerfct(L, 1, &globalconf.hooks.focus); } /** Set the function called each time a client loses focus. This function is @@ -152,7 +157,7 @@ luaA_hooks_focus(lua_State *L) static int luaA_hooks_unfocus(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.unfocus); + return luaA_registerfct(L, 1, &globalconf.hooks.unfocus); } /** Set the function called each time a new client appears. This function is @@ -165,7 +170,7 @@ luaA_hooks_unfocus(lua_State *L) static int luaA_hooks_manage(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.manage); + return luaA_registerfct(L, 1, &globalconf.hooks.manage); } /** Set the function called each time a client goes away. This function is @@ -178,7 +183,7 @@ luaA_hooks_manage(lua_State *L) static int luaA_hooks_unmanage(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.unmanage); + return luaA_registerfct(L, 1, &globalconf.hooks.unmanage); } /** Set the function called each time the mouse enter a new window. This @@ -191,7 +196,7 @@ luaA_hooks_unmanage(lua_State *L) static int luaA_hooks_mouseover(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.mouseover); + return luaA_registerfct(L, 1, &globalconf.hooks.mouseover); } /** Set the function called on each screen arrange. This function is called @@ -204,7 +209,7 @@ luaA_hooks_mouseover(lua_State *L) static int luaA_hooks_arrange(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.arrange); + return luaA_registerfct(L, 1, &globalconf.hooks.arrange); } /** Set the function called on each title update. This function is called with @@ -217,7 +222,7 @@ luaA_hooks_arrange(lua_State *L) static int luaA_hooks_titleupdate(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.titleupdate); + return luaA_registerfct(L, 1, &globalconf.hooks.titleupdate); } /** Set the function called when a client get urgency flag. This function is called with @@ -230,7 +235,7 @@ luaA_hooks_titleupdate(lua_State *L) static int luaA_hooks_urgent(lua_State *L) { - return luaA_registerfct(L, &globalconf.hooks.urgent); + return luaA_registerfct(L, 1, &globalconf.hooks.urgent); } /** Set the function to be called every N seconds. @@ -246,7 +251,7 @@ luaA_hooks_timer(lua_State *L) globalconf.timer.repeat = luaL_checknumber(L, 1); if(lua_gettop(L) == 2 && !lua_isnil(L, 2)) - luaA_registerfct(L, &globalconf.hooks.timer); + luaA_registerfct(L, 2, &globalconf.hooks.timer); ev_timer_again(globalconf.loop, &globalconf.timer); return 0; @@ -543,7 +548,7 @@ luaA_init(void) { "exec", luaA_exec }, { "spawn", luaA_spawn }, { "restart", luaA_restart }, - { "mouse_add", luaA_mouse_add }, + { "buttons", luaA_buttons }, { "font_set", luaA_font_set }, { "colors_set", luaA_colors_set }, { NULL, NULL } @@ -586,6 +591,9 @@ luaA_init(void) /* Export mouse */ luaA_openlib(L, "mouse", awesome_mouse_methods, awesome_mouse_meta); + /* Export button */ + luaA_openlib(L, "button", awesome_button_methods, awesome_button_meta); + /* Export tag */ luaA_openlib(L, "tag", awesome_tag_methods, awesome_tag_meta); diff --git a/lua.h b/lua.h index ea24a8f74..576e858ae 100644 --- a/lua.h +++ b/lua.h @@ -202,15 +202,17 @@ luaA_usemetatable(lua_State *L, int idxobj, int idxfield) /** Register a function. * \param L The Lua stack. + * \param idx Index of the function in the stack. * \param fct A luaA_ref address: it will be filled with the luaA_ref * registered. If the adresse point to an already registered function, it will * be unregistered. * \return Always 0. */ static inline int -luaA_registerfct(lua_State *L, luaA_ref *fct) +luaA_registerfct(lua_State *L, int idx, luaA_ref *fct) { - luaA_checkfunction(L, -1); + luaA_checkfunction(L, idx); + lua_pushvalue(L, idx); if(*fct != LUA_REFNIL) luaL_unref(L, LUA_REGISTRYINDEX, *fct); *fct = luaL_ref(L, LUA_REGISTRYINDEX); diff --git a/mouse.c b/mouse.c index 8915675ed..a4f3535f8 100644 --- a/mouse.c +++ b/mouse.c @@ -37,9 +37,9 @@ extern awesome_t globalconf; -DO_LUA_NEW(static, button_t, mouse, "mouse", button_ref) -DO_LUA_GC(button_t, mouse, "mouse", button_unref) -DO_LUA_EQ(button_t, mouse, "mouse") +DO_LUA_NEW(extern, button_t, button, "button", button_ref) +DO_LUA_GC(button_t, button, "button", button_unref) +DO_LUA_EQ(button_t, button, "button") /** Define corners. */ typedef enum @@ -1063,10 +1063,11 @@ luaA_client_mouse_move(lua_State *L) * \lparam A table with modifiers keys. * \lparam A mouse button number. * \lparam A function to execute on click events. + * \lparam A function to execute on release events. * \lreturn A mouse button binding. */ static int -luaA_mouse_new(lua_State *L) +luaA_button_new(lua_State *L) { int i, len; button_t *button; @@ -1074,12 +1075,24 @@ luaA_mouse_new(lua_State *L) luaA_checktable(L, 2); /* arg 3 is mouse button */ i = luaL_checknumber(L, 3); - /* arg 4 is cmd to run */ - luaA_checkfunction(L, 4); + /* arg 4 and 5 are callback functions */ + if(!lua_isnil(L, 4)) + luaA_checkfunction(L, 4); + if(lua_gettop(L) == 5 && !lua_isnil(L, 5)) + luaA_checkfunction(L, 5); button = p_new(button_t, 1); button->button = xutil_button_fromint(i); - button->fct = luaL_ref(L, LUA_REGISTRYINDEX); + + if(lua_isnil(L, 4)) + button->press = LUA_REFNIL; + else + luaA_registerfct(L, 4, &button->press); + + if(lua_gettop(L) == 5 && !lua_isnil(L, 5)) + luaA_registerfct(L, 5, &button->release); + else + button->release = LUA_REFNIL; len = lua_objlen(L, 2); for(i = 1; i <= len; i++) @@ -1088,10 +1101,78 @@ luaA_mouse_new(lua_State *L) button->mod |= xutil_key_mask_fromstr(luaL_checkstring(L, -1)); } - return luaA_mouse_userdata_new(L, button); + return luaA_button_userdata_new(L, button); } -/** Mouse object. +/** Return a formated string for a button. + * \param L The Lua VM state. + * \luastack + * \lvalue A button. + * \lreturn A string. + */ +static int +luaA_button_tostring(lua_State *L) +{ + button_t **p = luaA_checkudata(L, 1, "button"); + lua_pushfstring(L, "[button udata(%p)]", *p); + return 1; +} + +/** Set a button array with a Lua table. + * \param L The Lua VM state. + * \param idx The index of the Lua table. + * \param buttons The array button to fill. + */ +void +luaA_button_array_set(lua_State *L, int idx, button_array_t *buttons) +{ + button_t **b; + + luaA_checktable(L, idx); + button_array_wipe(buttons); + button_array_init(buttons); + lua_pushnil(L); + while(lua_next(L, idx)) + { + b = luaA_checkudata(L, -1, "button"); + button_array_append(buttons, *b); + button_ref(b); + lua_pop(L, 1); + } + lua_pop(L, 1); +} + +/** Push an array of button as an Lua table onto the stack. + * \param L The Lua VM state. + * \param buttons The button array to push. + * \return The number of elements pushed on stack. + */ +int +luaA_button_array_get(lua_State *L, button_array_t *buttons) +{ + luaA_otable_new(L); + for(int i = 0; i < buttons->len; i++) + { + luaA_button_userdata_new(L, buttons->tab[i]); + lua_rawseti(L, -2, i + 1); + } + return 1; +} + +const struct luaL_reg awesome_button_methods[] = +{ + { "__call", luaA_button_new }, + { NULL, NULL } +}; +const struct luaL_reg awesome_button_meta[] = +{ + { "__gc", luaA_button_gc }, + { "__eq", luaA_button_eq }, + { "__tostring", luaA_button_tostring }, + { NULL, NULL } +}; + +/** Mouse library. * \param L The Lua VM state. * \return The number of elements pushed on stack. * \luastack @@ -1229,7 +1310,6 @@ luaA_mouse_coords(lua_State *L) const struct luaL_reg awesome_mouse_methods[] = { - { "__call", luaA_mouse_new }, { "__index", luaA_mouse_index }, { "__newindex", luaA_mouse_newindex }, { "coords", luaA_mouse_coords }, @@ -1237,8 +1317,6 @@ const struct luaL_reg awesome_mouse_methods[] = }; const struct luaL_reg awesome_mouse_meta[] = { - { "__gc", luaA_mouse_gc }, - { "__eq", luaA_mouse_eq }, { NULL, NULL } }; diff --git a/mouse.h b/mouse.h index 360f16bbd..0954e7785 100644 --- a/mouse.h +++ b/mouse.h @@ -22,10 +22,15 @@ #ifndef AWESOME_MOUSE_H #define AWESOME_MOUSE_H -#include +#include "structs.h" int luaA_client_mouse_resize(lua_State *); int luaA_client_mouse_move(lua_State *); +int luaA_button_userdata_new(lua_State *, button_t *); + +int luaA_button_array_get(lua_State *, button_array_t *); +void luaA_button_array_set(lua_State *, int idx, button_array_t *); + #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/structs.h b/structs.h index 82829c276..f766fd63f 100644 --- a/structs.h +++ b/structs.h @@ -77,14 +77,14 @@ struct button_t unsigned long mod; /** Mouse button number */ unsigned int button; - /** Lua function to execute. */ - luaA_ref fct; - /** Next and previous buttons */ - button_t *prev, *next; + /** Lua function to execute on press. */ + luaA_ref press; + /** Lua function to execute on release. */ + luaA_ref release; }; -DO_SLIST(button_t, button, p_delete) DO_RCNT(button_t, button, p_delete) +DO_ARRAY(button_t *, button, button_unref) /** Widget */ struct widget_t @@ -105,14 +105,14 @@ struct widget_t int (*index)(lua_State *, awesome_token_t); /** Newindex function */ int (*newindex)(lua_State *, awesome_token_t); - /** ButtonPressedEvent handler */ - void (*button_press)(widget_node_t *, xcb_button_press_event_t *, int, void *, awesome_type_t); + /** Button event handler */ + void (*button)(widget_node_t *, xcb_button_press_event_t *, int, void *, awesome_type_t); /** Alignement */ alignment_t align; /** Misc private data */ void *data; /** Button bindings */ - button_t *buttons; + button_array_t buttons; /** Cache flags */ int cache_flags; /** True if the widget is visible */ @@ -127,7 +127,7 @@ widget_delete(widget_t **widget) { if((*widget)->destructor) (*widget)->destructor(*widget); - button_list_wipe(&(*widget)->buttons); + button_array_wipe(&(*widget)->buttons); p_delete(&(*widget)->name); p_delete(widget); } @@ -300,7 +300,7 @@ struct client_t /** Titlebar */ titlebar_t *titlebar; /** Button bindings */ - button_t *buttons; + button_array_t buttons; /** Floating window placement algo */ floating_placement_t *floating_placement; /** Icon */ @@ -312,7 +312,7 @@ struct client_t static void client_delete(client_t **c) { - button_list_wipe(&(*c)->buttons); + button_array_wipe(&(*c)->buttons); p_delete(&(*c)->icon_path); p_delete(&(*c)->name); p_delete(c); @@ -407,10 +407,7 @@ struct awesome_t /** Screens info */ screens_info_t *screens_info; /** Mouse bindings list */ - struct - { - button_t *root; - } buttons; + button_array_t buttons; /** Numlock mask */ unsigned int numlockmask; /** Numlock mask */ diff --git a/widget.c b/widget.c index 9cfe04967..4d71d35d2 100644 --- a/widget.c +++ b/widget.c @@ -24,6 +24,7 @@ #include #include +#include "mouse.h" #include "widget.h" #include "titlebar.h" #include "common/atoms.h" @@ -63,19 +64,23 @@ widget_calculate_offset(int barwidth, int widgetwidth, int offset, int alignment * \param type The object type. */ static void -widget_common_button_press(widget_node_t *w, - xcb_button_press_event_t *ev, - int screen __attribute__ ((unused)), - void *p, - awesome_type_t type) +widget_common_button(widget_node_t *w, + xcb_button_press_event_t *ev, + int screen __attribute__ ((unused)), + void *p, + awesome_type_t type) { - button_t *b; + button_array_t *b = &w->widget->buttons; - for(b = w->widget->buttons; b; b = b->next) - if(ev->detail == b->button && XUTIL_MASK_CLEAN(ev->state) == b->mod && b->fct) + for(int i = 0; i < b->len; i++) + if(ev->detail == b->tab[i]->button + && XUTIL_MASK_CLEAN(ev->state) == b->tab[i]->mod) { luaA_pushpointer(globalconf.L, p, type); - luaA_dofunction(globalconf.L, b->fct, 1, 0); + luaA_dofunction(globalconf.L, + ev->response_type == XCB_BUTTON_PRESS ? + b->tab[i]->press : b->tab[i]->release, + 1, 0); } } @@ -193,7 +198,7 @@ void widget_common_new(widget_t *widget) { widget->align = AlignLeft; - widget->button_press = widget_common_button_press; + widget->button = widget_common_button; } /** Invalidate widgets which should be refresh upon @@ -292,42 +297,24 @@ luaA_widget_new(lua_State *L) return luaA_widget_userdata_new(L, w); } -/** Add a mouse button bindings to a widget. +/** Get or set mouse buttons bindings to a widget. * \param L The Lua VM state. * * \luastack * \lvalue A widget. - * \lparam A mouse button bindings object. + * \lparam An array of mouse button bindings objects, or nothing. + * \return The array of mouse button bindings objects of this widget. */ static int -luaA_widget_mouse_add(lua_State *L) +luaA_widget_buttons(lua_State *L) { widget_t **widget = luaA_checkudata(L, 1, "widget"); - button_t **b = luaA_checkudata(L, 2, "mouse"); + button_array_t *buttons = &(*widget)->buttons; - button_list_push(&(*widget)->buttons, *b); - button_ref(b); + if(lua_gettop(L) == 2) + luaA_button_array_set(L, 2, buttons); - return 0; -} - -/** Remove a mouse button bindings from a widget. - * \param L The Lua VM state. - * - * \luastack - * \lvalue A widget. - * \lparam A mouse button bindings object. - */ -static int -luaA_widget_mouse_remove(lua_State *L) -{ - widget_t **widget = luaA_checkudata(L, 1, "widget"); - button_t **b = luaA_checkudata(L, 2, "mouse"); - - button_list_detach(&(*widget)->buttons, *b); - button_unref(b); - - return 0; + return luaA_button_array_get(L, buttons); } /** Convert a widget into a printable string. @@ -469,8 +456,7 @@ const struct luaL_reg awesome_widget_methods[] = }; const struct luaL_reg awesome_widget_meta[] = { - { "mouse_add", luaA_widget_mouse_add }, - { "mouse_remove", luaA_widget_mouse_remove }, + { "buttons", luaA_widget_buttons }, { "__index", luaA_widget_index }, { "__newindex", luaA_widget_newindex }, { "__gc", luaA_widget_gc }, diff --git a/widgets/taglist.c b/widgets/taglist.c index b0940bf66..726c31641 100644 --- a/widgets/taglist.c +++ b/widgets/taglist.c @@ -159,36 +159,41 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, /** Handle button click on tasklist. * \param w The widget node. * \param ev The button press event. + * \param btype The button press event type. * \param screen The screen where the click was. * \param object The object we're onto. * \param type The type object. */ static void -taglist_button_press(widget_node_t *w, - xcb_button_press_event_t *ev, - int screen, - void *object, - awesome_type_t type) +taglist_button(widget_node_t *w, + xcb_button_press_event_t *ev, + int screen, + void *object, + awesome_type_t type) { tag_array_t *tags = &globalconf.screens[screen].tags; - button_t *b; taglist_data_t *data = w->widget->data; taglist_drawn_area_t *tda; + button_array_t *barr = &w->widget->buttons; /* Find the good drawn area list */ if((tda = taglist_drawn_area_getbyobj(data->drawn_area, object))) - for(b = w->widget->buttons; b; b = b->next) - if(ev->detail == b->button && XUTIL_MASK_CLEAN(ev->state) == b->mod && b->fct) - for(int i = 0; i < MIN(tags->len, tda->areas.len); i++) + for(int i = 0; i < barr->len; i++) + if(ev->detail == barr->tab[i]->button + && XUTIL_MASK_CLEAN(ev->state) == barr->tab[i]->mod) + for(int j = 0; i < MIN(tags->len, tda->areas.len); j++) { - tag_t *tag = tags->tab[i]; - area_t *area = &tda->areas.tab[i]; + tag_t *tag = tags->tab[j]; + area_t *area = &tda->areas.tab[j]; if(ev->event_x >= AREA_LEFT(*area) && ev->event_x < AREA_RIGHT(*area)) { luaA_pushpointer(globalconf.L, object, type); luaA_tag_userdata_new(globalconf.L, tag); - luaA_dofunction(globalconf.L, b->fct, 2, 0); + luaA_dofunction(globalconf.L, + ev->response_type == XCB_BUTTON_PRESS ? + barr->tab[i]->press : barr->tab[i]->release, + 2, 0); return; } } @@ -232,7 +237,7 @@ luaA_taglist_newindex(lua_State *L, awesome_token_t token) switch(token) { case A_TK_LABEL: - luaA_registerfct(L, &d->label); + luaA_registerfct(L, 3, &d->label); break; default: return 0; @@ -288,7 +293,7 @@ taglist_new(alignment_t align) w->newindex = luaA_taglist_newindex; w->align = align; w->draw = taglist_draw; - w->button_press = taglist_button_press; + w->button = taglist_button; w->destructor = taglist_destructor; w->detach = taglist_detach; diff --git a/widgets/tasklist.c b/widgets/tasklist.c index 2ce321d8b..1568a9d9f 100644 --- a/widgets/tasklist.c +++ b/widgets/tasklist.c @@ -287,16 +287,16 @@ tasklist_draw(draw_context_t *ctx, int screen, * \param type The type object. */ static void -tasklist_button_press(widget_node_t *w, - xcb_button_press_event_t *ev, - int screen, - void *object, - awesome_type_t type) +tasklist_button(widget_node_t *w, + xcb_button_press_event_t *ev, + int screen, + void *object, + awesome_type_t type) { - button_t *b; tasklist_data_t *d = w->widget->data; int ci = 0; tasklist_object_data_t *odata; + button_array_t *barr = &w->widget->buttons; odata = tasklist_object_data_getbyobj(d->objects_data, object); @@ -308,12 +308,16 @@ tasklist_button_press(widget_node_t *w, else ci = odata->client_labels.len - 1 - (ev->event_x - w->area.x) / odata->box_width; - for(b = w->widget->buttons; b; b = b->next) - if(ev->detail == b->button && XUTIL_MASK_CLEAN(ev->state) == b->mod && b->fct) + for(int i = 0; i < barr->len; i++) + if(ev->detail == barr->tab[i]->button + && XUTIL_MASK_CLEAN(ev->state) == barr->tab[i]->mod) { luaA_pushpointer(globalconf.L, object, type); luaA_client_userdata_new(globalconf.L, odata->client_labels.tab[ci].client); - luaA_dofunction(globalconf.L, b->fct, 2, 0); + luaA_dofunction(globalconf.L, + ev->response_type == XCB_BUTTON_PRESS ? + barr->tab[i]->press : barr->tab[i]->release, + 2, 0); } } @@ -365,7 +369,7 @@ luaA_tasklist_newindex(lua_State *L, awesome_token_t token) d->show_icons = luaA_checkboolean(L, 3); break; case A_TK_LABEL: - luaA_registerfct(L, &d->label); + luaA_registerfct(L, 3, &d->label); break; case A_TK_INVERT: d->invert = luaA_checkboolean(L, 3); @@ -420,7 +424,7 @@ tasklist_new(alignment_t align __attribute__ ((unused))) w = p_new(widget_t, 1); widget_common_new(w); w->draw = tasklist_draw; - w->button_press = tasklist_button_press; + w->button = tasklist_button; w->align = AlignFlex; w->index = luaA_tasklist_index; w->newindex = luaA_tasklist_newindex; diff --git a/window.c b/window.c index af15ba11e..af6352a9c 100644 --- a/window.c +++ b/window.c @@ -105,24 +105,22 @@ window_configure(xcb_window_t win, area_t geometry, int border) * \param buttons The buttons to grab. */ void -window_buttons_grab(xcb_window_t win, xcb_window_t root, button_t *buttons) +window_buttons_grab(xcb_window_t win, xcb_window_t root, button_array_t *buttons) { - button_t *b; - - for(b = buttons; b; b = b->next) + for(int i = 0; i < buttons->len; i++) { xcb_grab_button(globalconf.connection, false, win, BUTTONMASK, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, - b->button, b->mod); + buttons->tab[i]->button, buttons->tab[i]->mod); xcb_grab_button(globalconf.connection, false, win, BUTTONMASK, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, - b->button, b->mod | XCB_MOD_MASK_LOCK); + buttons->tab[i]->button, buttons->tab[i]->mod | XCB_MOD_MASK_LOCK); xcb_grab_button(globalconf.connection, false, win, BUTTONMASK, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, - b->button, b->mod | globalconf.numlockmask); + buttons->tab[i]->button, buttons->tab[i]->mod | globalconf.numlockmask); xcb_grab_button(globalconf.connection, false, win, BUTTONMASK, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, - b->button, b->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK); + buttons->tab[i]->button, buttons->tab[i]->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK); } xcb_ungrab_button(globalconf.connection, XCB_BUTTON_INDEX_ANY, root, XCB_BUTTON_MASK_ANY); @@ -134,22 +132,22 @@ window_buttons_grab(xcb_window_t win, xcb_window_t root, button_t *buttons) void window_root_buttons_grab(xcb_window_t root) { - button_t *b; + button_array_t *barr = &globalconf.buttons; - for(b = globalconf.buttons.root; b; b = b->next) + for(int i = 0; i < barr->len; i++) { xcb_grab_button(globalconf.connection, false, root, BUTTONMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE, - b->button, b->mod); + barr->tab[i]->button, barr->tab[i]->mod); xcb_grab_button(globalconf.connection, false, root, BUTTONMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE, - b->button, b->mod | XCB_MOD_MASK_LOCK); + barr->tab[i]->button, barr->tab[i]->mod | XCB_MOD_MASK_LOCK); xcb_grab_button(globalconf.connection, false, root, BUTTONMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE, - b->button, b->mod | globalconf.numlockmask); + barr->tab[i]->button, barr->tab[i]->mod | globalconf.numlockmask); xcb_grab_button(globalconf.connection, false, root, BUTTONMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE, - b->button, b->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK); + barr->tab[i]->button, barr->tab[i]->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK); } } diff --git a/window.h b/window.h index a2a34ef55..f14bd4435 100644 --- a/window.h +++ b/window.h @@ -28,10 +28,11 @@ void window_state_set(xcb_window_t, long); xcb_get_property_cookie_t window_state_get_unchecked(xcb_window_t); long window_state_get_reply(xcb_get_property_cookie_t); void window_configure(xcb_window_t, area_t, int); -void window_buttons_grab(xcb_window_t, xcb_window_t, button_t *); +void window_buttons_grab(xcb_window_t, xcb_window_t, button_array_t *); void window_root_buttons_grab(xcb_window_t); double window_opacity_get(xcb_window_t); void window_opacity_set(xcb_window_t, double); +void window_grabbuttons(xcb_window_t, xcb_window_t, button_array_t *); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80