selection_acquire: Also emit release when X11 selection is lost
Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
e4199dd6b5
commit
869b1b0dff
4
event.c
4
event.c
|
@ -25,6 +25,7 @@
|
||||||
#include "objects/tag.h"
|
#include "objects/tag.h"
|
||||||
#include "objects/selection_getter.h"
|
#include "objects/selection_getter.h"
|
||||||
#include "objects/drawin.h"
|
#include "objects/drawin.h"
|
||||||
|
#include "objects/selection_acquire.h"
|
||||||
#include "objects/selection_watcher.h"
|
#include "objects/selection_watcher.h"
|
||||||
#include "xwindow.h"
|
#include "xwindow.h"
|
||||||
#include "ewmh.h"
|
#include "ewmh.h"
|
||||||
|
@ -1013,7 +1014,8 @@ event_handle_selectionclear(xcb_selection_clear_event_t *ev)
|
||||||
{
|
{
|
||||||
warn("Lost WM_Sn selection, exiting...");
|
warn("Lost WM_Sn selection, exiting...");
|
||||||
g_main_loop_quit(globalconf.loop);
|
g_main_loop_quit(globalconf.loop);
|
||||||
}
|
} else
|
||||||
|
selection_handle_selectionclear(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief awesome xerror function.
|
/** \brief awesome xerror function.
|
||||||
|
|
|
@ -28,17 +28,85 @@
|
||||||
typedef struct selection_acquire_t
|
typedef struct selection_acquire_t
|
||||||
{
|
{
|
||||||
LUA_OBJECT_HEADER
|
LUA_OBJECT_HEADER
|
||||||
|
/** The selection that is being owned. */
|
||||||
|
xcb_atom_t selection;
|
||||||
/** Window used for owning the selection. */
|
/** Window used for owning the selection. */
|
||||||
xcb_window_t window;
|
xcb_window_t window;
|
||||||
/** Timestamp used for acquiring the selection. */
|
/** Timestamp used for acquiring the selection. */
|
||||||
xcb_timestamp_t timestamp;
|
xcb_timestamp_t timestamp;
|
||||||
/** Reference in the special table to this object. */
|
|
||||||
int ref;
|
|
||||||
} selection_acquire_t;
|
} selection_acquire_t;
|
||||||
|
|
||||||
static lua_class_t selection_acquire_class;
|
static lua_class_t selection_acquire_class;
|
||||||
LUA_OBJECT_FUNCS(selection_acquire_class, selection_acquire_t, selection_acquire)
|
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
|
static int
|
||||||
luaA_selection_acquire_new(lua_State *L)
|
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);
|
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 */
|
/* Get the atom identifying the selection */
|
||||||
reply = xcb_intern_atom_reply(globalconf.connection,
|
reply = xcb_intern_atom_reply(globalconf.connection,
|
||||||
xcb_intern_atom_unchecked(globalconf.connection, false, name_length, name),
|
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;
|
name_atom = reply ? reply->atom : XCB_NONE;
|
||||||
p_delete(&reply);
|
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->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);
|
xcb_set_selection_owner(globalconf.connection, selection->window, name_atom, selection->timestamp);
|
||||||
selection_reply = xcb_get_selection_owner_reply(globalconf.connection,
|
selection_reply = xcb_get_selection_owner_reply(globalconf.connection,
|
||||||
xcb_get_selection_owner(globalconf.connection, name_atom),
|
xcb_get_selection_owner(globalconf.connection, name_atom),
|
||||||
|
@ -80,12 +149,24 @@ luaA_selection_acquire_new(lua_State *L)
|
||||||
return 0;
|
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_pushliteral(L, REGISTRY_ACQUIRE_TABLE_INDEX);
|
||||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||||
lua_pushvalue(L, -2);
|
|
||||||
selection->ref = luaL_ref(L, -2);
|
luaA_pushatom(L, name_atom);
|
||||||
lua_pop(L, 1);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -93,18 +174,8 @@ luaA_selection_acquire_new(lua_State *L)
|
||||||
static int
|
static int
|
||||||
luaA_selection_acquire_release(lua_State *L)
|
luaA_selection_acquire_release(lua_State *L)
|
||||||
{
|
{
|
||||||
selection_acquire_t *selection = luaA_checkudata(L, 1, &selection_acquire_class);
|
luaA_checkudata(L, 1, &selection_acquire_class);
|
||||||
|
selection_release(L, 1);
|
||||||
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;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +183,7 @@ luaA_selection_acquire_release(lua_State *L)
|
||||||
static bool
|
static bool
|
||||||
selection_acquire_checker(selection_acquire_t *selection)
|
selection_acquire_checker(selection_acquire_t *selection)
|
||||||
{
|
{
|
||||||
return selection->window != XCB_NONE;
|
return selection->selection != XCB_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -23,8 +23,10 @@
|
||||||
#define AWESOME_OBJECTS_SELECTION_ACQUIRE_H
|
#define AWESOME_OBJECTS_SELECTION_ACQUIRE_H
|
||||||
|
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
void selection_acquire_class_setup(lua_State*);
|
void selection_acquire_class_setup(lua_State*);
|
||||||
|
void selection_handle_selectionclear(xcb_selection_clear_event_t*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue