From 0d2c6fc5d1b3407e5f54e2c124ca12b9a4ce981d Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Thu, 7 Feb 2019 16:37:37 +0100 Subject: [PATCH] Implement INCR transfers Incremental transfers are required to be supported. This commit adds that necessary support to awesomeWM. Signed-off-by: Uli Schlachter --- common/atoms.list | 1 + objects/selection_getter.c | 106 ++++++++++++++++++++++++++++++------- objects/selection_getter.h | 1 + property.c | 4 ++ 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/common/atoms.list b/common/atoms.list index 5c1205b6f..9cf41336e 100644 --- a/common/atoms.list +++ b/common/atoms.list @@ -64,5 +64,6 @@ XSEL_DATA WM_TAKE_FOCUS AWESOME_CLIENT_ORDER AWESOME_SELECTION_ATOM +INCR _XKB_RULES_NAMES _MOTIF_WM_HINTS diff --git a/objects/selection_getter.c b/objects/selection_getter.c index 8d4314910..5d2372306 100644 --- a/objects/selection_getter.c +++ b/objects/selection_getter.c @@ -89,6 +89,22 @@ luaA_selection_getter_new(lua_State *L) return 1; } +static void +selection_transfer_finished(lua_State *L, int ud) +{ + selection_getter_t *selection = lua_touserdata(L, ud); + + /* Unreference the selection object; it's dead */ + lua_pushliteral(L, REGISTRY_GETTER_TABLE_INDEX); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, selection->ref); + lua_pop(L, 1); + + selection->ref = LUA_NOREF; + + luaA_object_emit_signal(L, ud, "data_end", 0); +} + static void selection_handle_selectionnotify(lua_State *L, int ud, xcb_atom_t property) { @@ -99,34 +115,37 @@ selection_handle_selectionnotify(lua_State *L, int ud, xcb_atom_t property) if (property != XCB_NONE) { + xcb_change_window_attributes(globalconf.connection, selection->window, + XCB_CW_EVENT_MASK, (uint32_t[]) { XCB_EVENT_MASK_PROPERTY_CHANGE }); + xcb_get_property_reply_t *property_r = xcb_get_property_reply(globalconf.connection, xcb_get_property(globalconf.connection, true, selection->window, AWESOME_SELECTION_ATOM, XCB_GET_PROPERTY_TYPE_ANY, 0, 0xffffffff), NULL); if (property_r) { + if (property_r->type == INCR) + { + /* This is an incremental transfer. The above GetProperty had + * delete=true. This indicates to the other end that the + * transfer should start now. Right now we only get an estimate + * of the size of the data to be transferred, which we ignore. + */ + p_delete(&property_r); + return; + } lua_pushlstring(L, xcb_get_property_value(property_r), xcb_get_property_value_length(property_r)); luaA_object_emit_signal(L, ud, "data", 1); p_delete(&property_r); } } - luaA_object_emit_signal(L, ud, "data_end", 0); - - /* Now unreference the selection object; it's dead */ - lua_pushliteral(L, REGISTRY_GETTER_TABLE_INDEX); - lua_rawget(L, LUA_REGISTRYINDEX); - luaL_unref(L, -1, selection->ref); - lua_pop(L, 1); - - selection->ref = LUA_NOREF; + selection_transfer_finished(L, ud); } -void -event_handle_selectionnotify(xcb_selection_notify_event_t *ev) +static int +selection_getter_find_by_window(lua_State *L, xcb_window_t window) { - lua_State *L = globalconf_get_lua_State(); - /* Iterate over all active selection getters */ lua_pushliteral(L, REGISTRY_GETTER_TABLE_INDEX); lua_rawget(L, LUA_REGISTRYINDEX); @@ -134,11 +153,11 @@ event_handle_selectionnotify(xcb_selection_notify_event_t *ev) while (lua_next(L, -2) != 0) { if (lua_type(L, -1) == LUA_TUSERDATA) { selection_getter_t *selection = lua_touserdata(L, -1); - if (ev->requestor == selection->window) { - /* Found the right selection */ - selection_handle_selectionnotify(L, -1, ev->property); - lua_pop(L, 2); - break; + if (selection->window == window) { + /* Found the right selection, remove table and key */ + lua_remove(L, -2); + lua_remove(L, -2); + return 1; } } /* Remove the value, leaving only the key */ @@ -146,6 +165,57 @@ event_handle_selectionnotify(xcb_selection_notify_event_t *ev) } /* Remove the getter table */ lua_pop(L, 1); + + return 0; +} + +int +property_handle_awesome_selection_atom(uint8_t state, xcb_window_t window) +{ + lua_State *L = globalconf_get_lua_State(); + + if (state != XCB_PROPERTY_NEW_VALUE) + return 0; + + if (selection_getter_find_by_window(L, window) == 0) + return 0; + + selection_getter_t *selection = lua_touserdata(L, -1); + + xcb_get_property_reply_t *property_r = xcb_get_property_reply(globalconf.connection, + xcb_get_property(globalconf.connection, true, selection->window, AWESOME_SELECTION_ATOM, + XCB_GET_PROPERTY_TYPE_ANY, 0, 0xffffffff), NULL); + + if (property_r) + { + if (property_r->value_len > 0) + { + lua_pushlstring(L, xcb_get_property_value(property_r), xcb_get_property_value_length(property_r)); + luaA_object_emit_signal(L, -2, "data", 1); + } + else + { + /* Transfer finished */ + selection_transfer_finished(L, -1); + } + + p_delete(&property_r); + } + + lua_pop(L, 1); + return 0; +} + +void +event_handle_selectionnotify(xcb_selection_notify_event_t *ev) +{ + lua_State *L = globalconf_get_lua_State(); + + if (selection_getter_find_by_window(L, ev->requestor) == 0) + return; + + selection_handle_selectionnotify(L, -1, ev->property); + lua_pop(L, 1); } void diff --git a/objects/selection_getter.h b/objects/selection_getter.h index 374020996..aa676be71 100644 --- a/objects/selection_getter.h +++ b/objects/selection_getter.h @@ -27,6 +27,7 @@ void selection_getter_class_setup(lua_State*); void event_handle_selectionnotify(xcb_selection_notify_event_t*); +int property_handle_awesome_selection_atom(uint8_t, xcb_window_t); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/property.c b/property.c index 5449b1810..f84a6b529 100644 --- a/property.c +++ b/property.c @@ -25,6 +25,7 @@ #include "ewmh.h" #include "objects/client.h" #include "objects/drawin.h" +#include "objects/selection_getter.h" #include "xwindow.h" #include @@ -524,6 +525,9 @@ property_handle_propertynotify(xcb_property_notify_event_t *ev) /* background change */ HANDLE(_XROOTPMAP_ID, property_handle_xrootpmap_id) + /* selection transfers */ + HANDLE(AWESOME_SELECTION_ATOM, property_handle_awesome_selection_atom) + /* If nothing was found, return */ END;