From c242657c3b7bae8af853527b588e3d6fec6d087f Mon Sep 17 00:00:00 2001 From: Gregor Best Date: Fri, 2 Jan 2009 20:11:21 +0100 Subject: [PATCH] awesome: add selection() for getting the primary X selection Signed-off-by: Gregor Best Signed-off-by: Julien Danjou --- CMakeLists.txt | 1 + common/atoms.list | 1 + luaa.c | 5 ++ selection.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 selection.c diff --git a/CMakeLists.txt b/CMakeLists.txt index cb09cc4b..a6054922 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ set(AWE_SRCS ${SOURCE_DIR}/mouse.c ${SOURCE_DIR}/screen.c ${SOURCE_DIR}/stack.c + ${SOURCE_DIR}/selection.c ${SOURCE_DIR}/wibox.c ${SOURCE_DIR}/systray.c ${SOURCE_DIR}/tag.c diff --git a/common/atoms.list b/common/atoms.list index f7205e18..f426fade 100644 --- a/common/atoms.list +++ b/common/atoms.list @@ -54,3 +54,4 @@ _NET_SYSTEM_TRAY_ORIENTATION WM_CHANGE_STATE WM_WINDOW_ROLE WM_CLIENT_LEADER +XSEL_DATA diff --git a/luaa.c b/luaa.c index 6e6a379c..f4788054 100644 --- a/luaa.c +++ b/luaa.c @@ -76,6 +76,8 @@ extern const struct luaL_reg awesome_wibox_meta[]; extern const struct luaL_reg awesome_key_methods[]; extern const struct luaL_reg awesome_key_meta[]; extern const struct luaL_reg awesome_keybinding_methods[]; +extern const struct luaL_reg awesome_selection_methods[]; +extern const struct luaL_reg awesome_selection_meta[]; static struct sockaddr_un *addr; static ev_io csio = { .fd = -1 }; @@ -840,6 +842,9 @@ luaA_init(void) luaA_openlib(L, "key", awesome_key_methods, awesome_key_meta); luaA_openlib(L, "keybinding", awesome_keybinding_methods, awesome_key_meta); + /* Export selection */ + luaA_openlib(L, "selection", awesome_selection_methods, awesome_selection_meta); + lua_pushliteral(L, "AWESOME_VERSION"); lua_pushstring(L, AWESOME_VERSION); lua_settable(L, LUA_GLOBALSINDEX); diff --git a/selection.c b/selection.c new file mode 100644 index 00000000..2d7ff763 --- /dev/null +++ b/selection.c @@ -0,0 +1,129 @@ +/* + * selection.c - Selection handling + * + * Copyright © 2009 Julien Danjou + * Copyright © 2009 Gregor Best + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include + +#include "structs.h" +#include "event.h" +#include "common/atoms.h" + +extern awesome_t globalconf; + +static xcb_window_t selection_window = XCB_NONE; + +/** Get the current X selection buffer. + * \param L The Lua VM state. + * \return The number of elements pushed on stack. + * \luastack + * \lreturn A string with the current X selection buffer. + */ +static int +luaA_selection_get(lua_State *L) +{ + if(selection_window == XCB_NONE) + { + xcb_screen_t *screen = xutil_screen_get(globalconf.connection, globalconf.default_screen); + uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; + uint32_t values[] = { screen->black_pixel, 1, XCB_EVENT_MASK_PROPERTY_CHANGE }; + + selection_window = xcb_generate_id(globalconf.connection); + + xcb_create_window(globalconf.connection, screen->root_depth, selection_window, screen->root, + 0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT, screen->root_visual, + mask, values); + } + + xcb_convert_selection(globalconf.connection, selection_window, + PRIMARY, UTF8_STRING, XSEL_DATA, XCB_CURRENT_TIME); + xcb_flush(globalconf.connection); + + xcb_generic_event_t *event; + + while(true) + { + event = xcb_wait_for_event(globalconf.connection); + + if(!event) + return 0; + + if(XCB_EVENT_RESPONSE_TYPE(event) != XCB_SELECTION_NOTIFY) + { + /* \todo Eventually, this may be rewritten with adding a static + * buffer, then a event handler for XCB_SELECTION_NOTIFY, then call + * xcb_event_poll_for_event_loop() and awesome_refresh(), + * then check if some static buffer has been filled with data. + * If yes, that'd be the xsel data, otherwise, re-loop. + * Anyway that's still brokes the socket or D-Bus, so maybe using + * ev_loop() would be even better. + */ + xcb_event_handle(&globalconf.evenths, event); + p_delete(&event); + awesome_refresh(globalconf.connection); + continue; + } + + xcb_selection_notify_event_t *event_notify = + (xcb_selection_notify_event_t *) event; + + if(event_notify->selection == PRIMARY + && event_notify->property != XCB_NONE) + { + xcb_get_text_property_reply_t prop; + xcb_get_property_cookie_t cookie = + xcb_get_text_property(globalconf.connection, + event_notify->requestor, + event_notify->property); + + if(xcb_get_text_property_reply(globalconf.connection, + cookie, &prop, NULL)) + { + lua_pushlstring(L, prop.name, prop.name_len); + + xcb_get_text_property_reply_wipe(&prop); + + xcb_delete_property(globalconf.connection, + event_notify->requestor, + event_notify->property); + + p_delete(&event); + + return 1; + } + else + break; + } + } + + p_delete(&event); + return 0; +} + +const struct luaL_reg awesome_selection_methods[] = +{ + { "__call", luaA_selection_get }, + { NULL, NULL } +}; + +const struct luaL_reg awesome_selection_meta[] = +{ + { NULL, NULL } +};