diff --git a/objects/selection_transfer.c b/objects/selection_transfer.c index 040aea61f..a5574c7a6 100644 --- a/objects/selection_transfer.c +++ b/objects/selection_transfer.c @@ -21,13 +21,29 @@ #include "objects/selection_transfer.h" #include "common/luaobject.h" +#include "common/atoms.h" #include "globalconf.h" #define REGISTRY_TRANSFER_TABLE_INDEX "awesome_selection_transfers" +enum transfer_state { + TRANSFER_WAIT_FOR_DATA, + TRANSFER_DONE +}; + typedef struct selection_transfer_t { LUA_OBJECT_HEADER + /** Reference in the special table to this object */ + int ref; + /* Information from the xcb_selection_request_event_t */ + xcb_window_t requestor; + xcb_atom_t selection; + xcb_atom_t target; + xcb_atom_t property; + xcb_timestamp_t time; + /* Current state of the transfer */ + enum transfer_state state; } selection_transfer_t; static lua_class_t selection_transfer_class; @@ -58,22 +74,69 @@ selection_transfer_reject(xcb_window_t requestor, xcb_atom_t selection, selection_transfer_notify(requestor, selection, target, XCB_NONE, time); } -#include "common/atoms.h" /* TODO remove */ +static void +transfer_done(lua_State *L, selection_transfer_t *transfer) +{ + transfer->state = TRANSFER_DONE; + + lua_pushliteral(L, REGISTRY_TRANSFER_TABLE_INDEX); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, transfer->ref); + transfer->ref = LUA_NOREF; + lua_pop(L, 1); +} + void selection_transfer_begin(lua_State *L, int ud, xcb_window_t requestor, xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t time) { - /* TODO implement this */ - xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, - requestor, property, UTF8_STRING, 8, 5, "Test\n"); - selection_transfer_notify(requestor, selection, target, property, time); + ud = luaA_absindex(L, ud); + + /* Allocate a transfer object */ + selection_transfer_t *transfer = (void *) selection_transfer_class.allocator(L); + transfer->requestor = requestor; + transfer->selection = selection; + transfer->target = target; + transfer->property = property; + transfer->time = time; + transfer->state = TRANSFER_WAIT_FOR_DATA; + + /* Save the object in the registry */ + lua_pushliteral(L, REGISTRY_TRANSFER_TABLE_INDEX); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, -2); + transfer->ref = luaL_ref(L, -2); + lua_pop(L, 1); + + /* Get the atom name */ + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(globalconf.connection, + xcb_get_atom_name_unchecked(globalconf.connection, target), NULL); + if (reply) { + lua_pushlstring(L, xcb_get_atom_name_name(reply), + xcb_get_atom_name_name_length(reply)); + p_delete(&reply); + } else + lua_pushnil(L); + + /* Emit the request signal with target and transfer object */ + lua_pushvalue(L, -2); + luaA_object_emit_signal(L, ud, "request", 2); + + /* Reject the transfer if Lua did not do anything */ + if (transfer->state == TRANSFER_WAIT_FOR_DATA) { + selection_transfer_reject(requestor, selection, target, time); + transfer_done(L, transfer); + } + + /* Remove the transfer object from the stack */ + lua_pop(L, 1); } static bool -selection_transfer_checker(selection_transfer_t *selection) +selection_transfer_checker(selection_transfer_t *transfer) { - return true; + return transfer->state != TRANSFER_DONE; } void