selection_acquire: Also emit release when X11 selection is lost

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2019-02-10 17:03:00 +01:00
parent e4199dd6b5
commit 869b1b0dff
3 changed files with 103 additions and 28 deletions

View File

@ -25,6 +25,7 @@
#include "objects/tag.h"
#include "objects/selection_getter.h"
#include "objects/drawin.h"
#include "objects/selection_acquire.h"
#include "objects/selection_watcher.h"
#include "xwindow.h"
#include "ewmh.h"
@ -1013,7 +1014,8 @@ event_handle_selectionclear(xcb_selection_clear_event_t *ev)
{
warn("Lost WM_Sn selection, exiting...");
g_main_loop_quit(globalconf.loop);
}
} else
selection_handle_selectionclear(ev);
}
/** \brief awesome xerror function.

View File

@ -28,17 +28,85 @@
typedef struct selection_acquire_t
{
LUA_OBJECT_HEADER
/** The selection that is being owned. */
xcb_atom_t selection;
/** Window used for owning the selection. */
xcb_window_t window;
/** Timestamp used for acquiring the selection. */
xcb_timestamp_t timestamp;
/** Reference in the special table to this object. */
int ref;
} selection_acquire_t;
static lua_class_t selection_acquire_class;
LUA_OBJECT_FUNCS(selection_acquire_class, selection_acquire_t, selection_acquire)
static void
luaA_pushatom(lua_State *L, xcb_atom_t atom)
{
lua_pushnumber(L, atom);
}
static int
selection_acquire_find_by_window(lua_State *L, xcb_window_t window)
{
/* Iterate over all active selection acquire objects */
lua_pushliteral(L, REGISTRY_ACQUIRE_TABLE_INDEX);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
if (lua_type(L, -1) == LUA_TUSERDATA) {
selection_acquire_t *selection = lua_touserdata(L, -1);
if (selection->window == window)
{
/* Remove table and key */
lua_remove(L, -2);
lua_remove(L, -2);
return 1;
}
}
/* Remove the value, leaving only the key */
lua_pop(L, 1);
}
/* Remove the table */
lua_pop(L, 1);
return 0;
}
static void
selection_release(lua_State *L, int ud)
{
selection_acquire_t *selection = luaA_checkudata(L, ud, &selection_acquire_class);
luaA_object_emit_signal(L, ud, "release", 0);
/* Destroy the window, this also releases the selection in X11 */
xcb_destroy_window(globalconf.connection, selection->window);
selection->window = XCB_NONE;
/* Unreference the object, it's now dead */
lua_pushliteral(L, REGISTRY_ACQUIRE_TABLE_INDEX);
lua_rawget(L, LUA_REGISTRYINDEX);
luaA_pushatom(L, selection->selection);
lua_pushnil(L);
lua_rawset(L, -3);
selection->selection = XCB_NONE;
lua_pop(L, 1);
}
void
selection_handle_selectionclear(xcb_selection_clear_event_t *ev)
{
lua_State *L = globalconf_get_lua_State();
if (selection_acquire_find_by_window(L, ev->owner) == 0)
return;
selection_release(L, -1);
lua_pop(L, 1);
}
static int
luaA_selection_acquire_new(lua_State *L)
{
@ -51,13 +119,6 @@ luaA_selection_acquire_new(lua_State *L)
name = luaL_checklstring(L, 2, &name_length);
/* Create a selection object */
selection = (void *) selection_acquire_class.allocator(L);
selection->window = xcb_generate_id(globalconf.connection);
xcb_create_window(globalconf.connection, globalconf.screen->root_depth,
selection->window, globalconf.screen->root, -1, -1, 1, 1, 0,
XCB_COPY_FROM_PARENT, globalconf.screen->root_visual, 0, NULL);
/* Get the atom identifying the selection */
reply = xcb_intern_atom_reply(globalconf.connection,
xcb_intern_atom_unchecked(globalconf.connection, false, name_length, name),
@ -65,8 +126,16 @@ luaA_selection_acquire_new(lua_State *L)
name_atom = reply ? reply->atom : XCB_NONE;
p_delete(&reply);
/* Try to acquire the selection */
/* Create a selection object */
selection = (void *) selection_acquire_class.allocator(L);
selection->selection = name_atom;
selection->timestamp = globalconf.timestamp;
selection->window = xcb_generate_id(globalconf.connection);
xcb_create_window(globalconf.connection, globalconf.screen->root_depth,
selection->window, globalconf.screen->root, -1, -1, 1, 1, 0,
XCB_COPY_FROM_PARENT, globalconf.screen->root_visual, 0, NULL);
/* Try to acquire the selection */
xcb_set_selection_owner(globalconf.connection, selection->window, name_atom, selection->timestamp);
selection_reply = xcb_get_selection_owner_reply(globalconf.connection,
xcb_get_selection_owner(globalconf.connection, name_atom),
@ -80,12 +149,24 @@ luaA_selection_acquire_new(lua_State *L)
return 0;
}
/* Everything worked, register the object in table */
/* Everything worked, register the object in the table */
lua_pushliteral(L, REGISTRY_ACQUIRE_TABLE_INDEX);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushvalue(L, -2);
selection->ref = luaL_ref(L, -2);
lua_pop(L, 1);
luaA_pushatom(L, name_atom);
lua_rawget(L, -2);
if (!lua_isnil(L, -1)) {
/* There is already another selection_acquire object for this selection,
* release it now. X11 does not send us SelectionClear events for our
* own changes to the selection.
*/
selection_release(L, -1);
}
luaA_pushatom(L, name_atom);
lua_pushvalue(L, -4);
lua_rawset(L, -4);
lua_pop(L, 2);
return 1;
}
@ -93,18 +174,8 @@ luaA_selection_acquire_new(lua_State *L)
static int
luaA_selection_acquire_release(lua_State *L)
{
selection_acquire_t *selection = luaA_checkudata(L, 1, &selection_acquire_class);
xcb_destroy_window(globalconf.connection, selection->window);
selection->window = XCB_NONE;
/* Unreference the object, it's now dead */
lua_pushliteral(L, REGISTRY_ACQUIRE_TABLE_INDEX);
lua_rawget(L, LUA_REGISTRYINDEX);
luaL_unref(L, -1, selection->ref);
lua_pop(L, 1);
selection->ref = LUA_NOREF;
luaA_checkudata(L, 1, &selection_acquire_class);
selection_release(L, 1);
return 0;
}
@ -112,7 +183,7 @@ luaA_selection_acquire_release(lua_State *L)
static bool
selection_acquire_checker(selection_acquire_t *selection)
{
return selection->window != XCB_NONE;
return selection->selection != XCB_NONE;
}
void

View File

@ -23,8 +23,10 @@
#define AWESOME_OBJECTS_SELECTION_ACQUIRE_H
#include <lua.h>
#include <xcb/xcb.h>
void selection_acquire_class_setup(lua_State*);
void selection_handle_selectionclear(xcb_selection_clear_event_t*);
#endif