Merge pull request #2638 from psychon/selection_watch
Add selection watcher objects
This commit is contained in:
commit
a5e8cde34e
|
@ -28,6 +28,7 @@ read_globals = {
|
||||||
"mousegrabber",
|
"mousegrabber",
|
||||||
"root",
|
"root",
|
||||||
"selection",
|
"selection",
|
||||||
|
"selection_watcher",
|
||||||
"tag",
|
"tag",
|
||||||
"window",
|
"window",
|
||||||
"table.unpack",
|
"table.unpack",
|
||||||
|
|
|
@ -37,7 +37,7 @@ install:
|
||||||
|
|
||||||
# Install build dependencies.
|
# Install build dependencies.
|
||||||
# See also `apt-cache showsrc awesome | grep -E '^(Version|Build-Depends)'`.
|
# See also `apt-cache showsrc awesome | grep -E '^(Version|Build-Depends)'`.
|
||||||
- sudo apt-get install -y libcairo2-dev gir1.2-gtk-3.0 libpango1.0-dev libxcb-xtest0-dev libxcb-icccm4-dev libxcb-randr0-dev libxcb-keysyms1-dev libxcb-xinerama0-dev libdbus-1-dev libxdg-basedir-dev libstartup-notification0-dev imagemagick libxcb1-dev libxcb-shape0-dev libxcb-util0-dev libx11-xcb-dev libxcb-cursor-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev
|
- sudo apt-get install -y libcairo2-dev gir1.2-gtk-3.0 libpango1.0-dev libxcb-xtest0-dev libxcb-icccm4-dev libxcb-randr0-dev libxcb-keysyms1-dev libxcb-xinerama0-dev libdbus-1-dev libxdg-basedir-dev libstartup-notification0-dev imagemagick libxcb1-dev libxcb-shape0-dev libxcb-util0-dev libx11-xcb-dev libxcb-cursor-dev libxcb-xkb-dev libxcb-xfixes0-dev libxkbcommon-dev libxkbcommon-x11-dev
|
||||||
- sudo gem install asciidoctor
|
- sudo gem install asciidoctor
|
||||||
|
|
||||||
# Deps for tests.
|
# Deps for tests.
|
||||||
|
|
|
@ -88,6 +88,7 @@ set(AWE_SRCS
|
||||||
${BUILD_DIR}/objects/drawin.c
|
${BUILD_DIR}/objects/drawin.c
|
||||||
${BUILD_DIR}/objects/key.c
|
${BUILD_DIR}/objects/key.c
|
||||||
${BUILD_DIR}/objects/screen.c
|
${BUILD_DIR}/objects/screen.c
|
||||||
|
${BUILD_DIR}/objects/selection_watcher.c
|
||||||
${BUILD_DIR}/objects/tag.c
|
${BUILD_DIR}/objects/tag.c
|
||||||
${BUILD_DIR}/objects/window.c)
|
${BUILD_DIR}/objects/window.c)
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include <xcb/xinerama.h>
|
#include <xcb/xinerama.h>
|
||||||
#include <xcb/xtest.h>
|
#include <xcb/xtest.h>
|
||||||
#include <xcb/shape.h>
|
#include <xcb/shape.h>
|
||||||
|
#include <xcb/xfixes.h>
|
||||||
|
|
||||||
#include <glib-unix.h>
|
#include <glib-unix.h>
|
||||||
|
|
||||||
|
@ -733,6 +734,7 @@ main(int argc, char **argv)
|
||||||
xcb_prefetch_extension_data(globalconf.connection, &xcb_randr_id);
|
xcb_prefetch_extension_data(globalconf.connection, &xcb_randr_id);
|
||||||
xcb_prefetch_extension_data(globalconf.connection, &xcb_xinerama_id);
|
xcb_prefetch_extension_data(globalconf.connection, &xcb_xinerama_id);
|
||||||
xcb_prefetch_extension_data(globalconf.connection, &xcb_shape_id);
|
xcb_prefetch_extension_data(globalconf.connection, &xcb_shape_id);
|
||||||
|
xcb_prefetch_extension_data(globalconf.connection, &xcb_xfixes_id);
|
||||||
|
|
||||||
if (xcb_cursor_context_new(globalconf.connection, globalconf.screen, &globalconf.cursor_ctx) < 0)
|
if (xcb_cursor_context_new(globalconf.connection, globalconf.screen, &globalconf.cursor_ctx) < 0)
|
||||||
fatal("Failed to initialize xcb-cursor");
|
fatal("Failed to initialize xcb-cursor");
|
||||||
|
@ -794,6 +796,13 @@ main(int argc, char **argv)
|
||||||
p_delete(&reply);
|
p_delete(&reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for xfixes extension */
|
||||||
|
query = xcb_get_extension_data(globalconf.connection, &xcb_xfixes_id);
|
||||||
|
globalconf.have_xfixes = query && query->present;
|
||||||
|
if (globalconf.have_xfixes)
|
||||||
|
xcb_discard_reply(globalconf.connection,
|
||||||
|
xcb_xfixes_query_version(globalconf.connection, 1, 0).sequence);
|
||||||
|
|
||||||
event_init();
|
event_init();
|
||||||
|
|
||||||
/* Allocate the key symbols */
|
/* Allocate the key symbols */
|
||||||
|
|
|
@ -141,6 +141,7 @@ set(AWESOME_DEPENDENCIES
|
||||||
xcb-keysyms>=0.3.4
|
xcb-keysyms>=0.3.4
|
||||||
xcb-icccm
|
xcb-icccm
|
||||||
xcb-icccm>=0.3.8
|
xcb-icccm>=0.3.8
|
||||||
|
xcb-xfixes
|
||||||
# NOTE: it's not clear what version is required, but 1.10 works at least.
|
# NOTE: it's not clear what version is required, but 1.10 works at least.
|
||||||
# See https://github.com/awesomeWM/awesome/pull/149#issuecomment-94208356.
|
# See https://github.com/awesomeWM/awesome/pull/149#issuecomment-94208356.
|
||||||
xcb-xkb
|
xcb-xkb
|
||||||
|
|
|
@ -68,6 +68,7 @@ environment):
|
||||||
- [libxcb-util >= 0.3.8](https://xcb.freedesktop.org/)
|
- [libxcb-util >= 0.3.8](https://xcb.freedesktop.org/)
|
||||||
- [libxcb-keysyms >= 0.3.4](https://xcb.freedesktop.org/)
|
- [libxcb-keysyms >= 0.3.4](https://xcb.freedesktop.org/)
|
||||||
- [libxcb-icccm >= 0.3.8](https://xcb.freedesktop.org/)
|
- [libxcb-icccm >= 0.3.8](https://xcb.freedesktop.org/)
|
||||||
|
- [libxcb-xfixes](https://xcb.freedesktop.org/)
|
||||||
- [xcb-util-xrm >= 1.0](https://github.com/Airblader/xcb-util-xrm)
|
- [xcb-util-xrm >= 1.0](https://github.com/Airblader/xcb-util-xrm)
|
||||||
- [libxkbcommon](http://xkbcommon.org/) with X11 support enabled
|
- [libxkbcommon](http://xkbcommon.org/) with X11 support enabled
|
||||||
- [libstartup-notification >=
|
- [libstartup-notification >=
|
||||||
|
|
7
event.c
7
event.c
|
@ -24,6 +24,7 @@
|
||||||
#include "property.h"
|
#include "property.h"
|
||||||
#include "objects/tag.h"
|
#include "objects/tag.h"
|
||||||
#include "objects/drawin.h"
|
#include "objects/drawin.h"
|
||||||
|
#include "objects/selection_watcher.h"
|
||||||
#include "xwindow.h"
|
#include "xwindow.h"
|
||||||
#include "ewmh.h"
|
#include "ewmh.h"
|
||||||
#include "objects/client.h"
|
#include "objects/client.h"
|
||||||
|
@ -43,6 +44,7 @@
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
#include <xcb/xcb_event.h>
|
#include <xcb/xcb_event.h>
|
||||||
#include <xcb/xkb.h>
|
#include <xcb/xkb.h>
|
||||||
|
#include <xcb/xfixes.h>
|
||||||
|
|
||||||
#define DO_EVENT_HOOK_CALLBACK(type, xcbtype, xcbeventprefix, arraytype, match) \
|
#define DO_EVENT_HOOK_CALLBACK(type, xcbtype, xcbeventprefix, arraytype, match) \
|
||||||
static void \
|
static void \
|
||||||
|
@ -1116,6 +1118,7 @@ void event_handle(xcb_generic_event_t *event)
|
||||||
EXTENSION_EVENT(randr, XCB_RANDR_NOTIFY, event_handle_randr_output_change_notify);
|
EXTENSION_EVENT(randr, XCB_RANDR_NOTIFY, event_handle_randr_output_change_notify);
|
||||||
EXTENSION_EVENT(shape, XCB_SHAPE_NOTIFY, event_handle_shape_notify);
|
EXTENSION_EVENT(shape, XCB_SHAPE_NOTIFY, event_handle_shape_notify);
|
||||||
EXTENSION_EVENT(xkb, 0, event_handle_xkb_notify);
|
EXTENSION_EVENT(xkb, 0, event_handle_xkb_notify);
|
||||||
|
EXTENSION_EVENT(xfixes, XCB_XFIXES_SELECTION_NOTIFY, event_handle_xfixes_selection_notify);
|
||||||
#undef EXTENSION_EVENT
|
#undef EXTENSION_EVENT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,6 +1137,10 @@ void event_init(void)
|
||||||
reply = xcb_get_extension_data(globalconf.connection, &xcb_xkb_id);
|
reply = xcb_get_extension_data(globalconf.connection, &xcb_xkb_id);
|
||||||
if (reply && reply->present)
|
if (reply && reply->present)
|
||||||
globalconf.event_base_xkb = reply->first_event;
|
globalconf.event_base_xkb = reply->first_event;
|
||||||
|
|
||||||
|
reply = xcb_get_extension_data(globalconf.connection, &xcb_xfixes_id);
|
||||||
|
if (reply && reply->present)
|
||||||
|
globalconf.event_base_xfixes = reply->first_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -110,9 +110,12 @@ typedef struct
|
||||||
bool have_input_shape;
|
bool have_input_shape;
|
||||||
/** Check for XKB extension */
|
/** Check for XKB extension */
|
||||||
bool have_xkb;
|
bool have_xkb;
|
||||||
|
/** Check for XFixes extension */
|
||||||
|
bool have_xfixes;
|
||||||
uint8_t event_base_shape;
|
uint8_t event_base_shape;
|
||||||
uint8_t event_base_xkb;
|
uint8_t event_base_xkb;
|
||||||
uint8_t event_base_randr;
|
uint8_t event_base_randr;
|
||||||
|
uint8_t event_base_xfixes;
|
||||||
/** Clients list */
|
/** Clients list */
|
||||||
client_array_t clients;
|
client_array_t clients;
|
||||||
/** Embedded windows */
|
/** Embedded windows */
|
||||||
|
|
4
luaa.c
4
luaa.c
|
@ -49,6 +49,7 @@
|
||||||
#include "objects/drawable.h"
|
#include "objects/drawable.h"
|
||||||
#include "objects/drawin.h"
|
#include "objects/drawin.h"
|
||||||
#include "objects/screen.h"
|
#include "objects/screen.h"
|
||||||
|
#include "objects/selection_watcher.h"
|
||||||
#include "objects/tag.h"
|
#include "objects/tag.h"
|
||||||
#include "property.h"
|
#include "property.h"
|
||||||
#include "selection.h"
|
#include "selection.h"
|
||||||
|
@ -1035,6 +1036,9 @@ luaA_init(xdgHandle* xdg, string_array_t *searchpath)
|
||||||
/* Export keys */
|
/* Export keys */
|
||||||
key_class_setup(L);
|
key_class_setup(L);
|
||||||
|
|
||||||
|
/* Export selection watcher */
|
||||||
|
selection_watcher_class_setup(L);
|
||||||
|
|
||||||
/* add Lua search paths */
|
/* add Lua search paths */
|
||||||
lua_getglobal(L, "package");
|
lua_getglobal(L, "package");
|
||||||
if (LUA_TTABLE != lua_type(L, 1))
|
if (LUA_TTABLE != lua_type(L, 1))
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* selection_watcher.h - selection change watcher
|
||||||
|
*
|
||||||
|
* Copyright © 2019 Uli Schlachter <psychon@znc.in>
|
||||||
|
*
|
||||||
|
* 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 "objects/selection_watcher.h"
|
||||||
|
#include "common/luaobject.h"
|
||||||
|
#include "globalconf.h"
|
||||||
|
|
||||||
|
#include <xcb/xfixes.h>
|
||||||
|
|
||||||
|
#define REGISTRY_WATCHER_TABLE_INDEX "awesome_selection_watchers"
|
||||||
|
|
||||||
|
typedef struct selection_watcher_t
|
||||||
|
{
|
||||||
|
LUA_OBJECT_HEADER
|
||||||
|
/** Is this watcher currently active and watching? Used as reference with luaL_ref */
|
||||||
|
int active_ref;
|
||||||
|
/** Atom identifying the selection to watch */
|
||||||
|
xcb_atom_t selection;
|
||||||
|
/** Window used for watching */
|
||||||
|
xcb_window_t window;
|
||||||
|
} selection_watcher_t;
|
||||||
|
|
||||||
|
static lua_class_t selection_watcher_class;
|
||||||
|
LUA_OBJECT_FUNCS(selection_watcher_class, selection_watcher_t, selection_watcher)
|
||||||
|
|
||||||
|
void
|
||||||
|
event_handle_xfixes_selection_notify(xcb_generic_event_t *ev)
|
||||||
|
{
|
||||||
|
xcb_xfixes_selection_notify_event_t *e = (void *) ev;
|
||||||
|
lua_State *L = globalconf_get_lua_State();
|
||||||
|
|
||||||
|
/* Iterate over all active selection watchers */
|
||||||
|
lua_pushliteral(L, REGISTRY_WATCHER_TABLE_INDEX);
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, -2) != 0) {
|
||||||
|
if (lua_type(L, -1) == LUA_TUSERDATA) {
|
||||||
|
selection_watcher_t *selection = lua_touserdata(L, -1);
|
||||||
|
|
||||||
|
if (selection->selection == e->selection && selection->window == e->window) {
|
||||||
|
lua_pushboolean(L, e->owner != XCB_NONE);
|
||||||
|
luaA_object_emit_signal(L, -2, "selection_changed", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Remove the watcher */
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
/* Remove watcher table */
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a new selection watcher object.
|
||||||
|
* \param L The Lua VM state.
|
||||||
|
* \return The number of elements pushed on the stack.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
luaA_selection_watcher_new(lua_State *L)
|
||||||
|
{
|
||||||
|
size_t name_length;
|
||||||
|
const char *name;
|
||||||
|
xcb_intern_atom_reply_t *reply;
|
||||||
|
selection_watcher_t *selection;
|
||||||
|
|
||||||
|
name = luaL_checklstring(L, 2, &name_length);
|
||||||
|
selection = (void *) selection_watcher_class.allocator(L);
|
||||||
|
selection->active_ref = LUA_NOREF;
|
||||||
|
selection->window = XCB_NONE;
|
||||||
|
|
||||||
|
/* Get the atom identifying the selection to watch */
|
||||||
|
reply = xcb_intern_atom_reply(globalconf.connection,
|
||||||
|
xcb_intern_atom_unchecked(globalconf.connection, false, name_length, name),
|
||||||
|
NULL);
|
||||||
|
if (reply) {
|
||||||
|
selection->selection = reply->atom;
|
||||||
|
p_delete(&reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
luaA_selection_watcher_set_active(lua_State *L, selection_watcher_t *selection)
|
||||||
|
{
|
||||||
|
bool b = luaA_checkboolean(L, -1);
|
||||||
|
bool is_active = selection->active_ref != LUA_NOREF;
|
||||||
|
if(b != is_active)
|
||||||
|
{
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
/* Selection becomes active */
|
||||||
|
|
||||||
|
/* Create a window for it */
|
||||||
|
if (selection->window == XCB_NONE)
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Start watching for selection changes */
|
||||||
|
if (globalconf.have_xfixes)
|
||||||
|
{
|
||||||
|
xcb_xfixes_select_selection_input(globalconf.connection, selection->window, selection->selection,
|
||||||
|
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
|
||||||
|
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
|
||||||
|
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
|
||||||
|
} else {
|
||||||
|
luaA_warn(L, "X11 server does not support the XFixes extension; cannot watch selections");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reference the selection watcher. For this, first get the tracking
|
||||||
|
* table out of the registry. */
|
||||||
|
lua_pushliteral(L, REGISTRY_WATCHER_TABLE_INDEX);
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
/* Then actually get the reference */
|
||||||
|
lua_pushvalue(L, -3 - 1);
|
||||||
|
selection->active_ref = luaL_ref(L, -2);
|
||||||
|
|
||||||
|
/* And pop the tracking table again */
|
||||||
|
lua_pop(L, 1);
|
||||||
|
} else {
|
||||||
|
/* Stop watching and destroy the window */
|
||||||
|
if (globalconf.have_xfixes)
|
||||||
|
xcb_xfixes_select_selection_input(globalconf.connection, selection->window, selection->selection, 0);
|
||||||
|
xcb_destroy_window(globalconf.connection, selection->window);
|
||||||
|
|
||||||
|
/* Unreference the selection object */
|
||||||
|
lua_pushliteral(L, REGISTRY_WATCHER_TABLE_INDEX);
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||||
|
luaL_unref(L, -1, selection->active_ref);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
selection->active_ref = LUA_NOREF;
|
||||||
|
}
|
||||||
|
luaA_object_emit_signal(L, -3, "property::active", 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
luaA_selection_watcher_get_active(lua_State *L, selection_watcher_t *selection)
|
||||||
|
{
|
||||||
|
lua_pushboolean(L, selection->active_ref != LUA_NOREF);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
selection_watcher_class_setup(lua_State *L)
|
||||||
|
{
|
||||||
|
static const struct luaL_Reg selection_watcher_methods[] =
|
||||||
|
{
|
||||||
|
LUA_CLASS_METHODS(selection_watcher)
|
||||||
|
{ "__call", luaA_selection_watcher_new },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct luaL_Reg selection_watcher_meta[] = {
|
||||||
|
LUA_OBJECT_META(selection_watcher)
|
||||||
|
LUA_CLASS_META
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Reference a table in the registry that tracks active watchers. This code
|
||||||
|
* does debug.getregistry()[REGISTRY_WATCHER_TABLE_INDEX] = {}
|
||||||
|
*/
|
||||||
|
lua_pushliteral(L, REGISTRY_WATCHER_TABLE_INDEX);
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
luaA_class_setup(L, &selection_watcher_class, "selection_watcher", NULL,
|
||||||
|
(lua_class_allocator_t) selection_watcher_new, NULL, NULL,
|
||||||
|
luaA_class_index_miss_property, luaA_class_newindex_miss_property,
|
||||||
|
selection_watcher_methods, selection_watcher_meta);
|
||||||
|
luaA_class_add_property(&selection_watcher_class, "active",
|
||||||
|
(lua_class_propfunc_t) luaA_selection_watcher_set_active,
|
||||||
|
(lua_class_propfunc_t) luaA_selection_watcher_get_active,
|
||||||
|
(lua_class_propfunc_t) luaA_selection_watcher_set_active);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* selection_watcher.h - selection change watcher header
|
||||||
|
*
|
||||||
|
* Copyright © 2019 Uli Schlachter <psychon@znc.in>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AWESOME_OBJECTS_SELECTION_WATCHER_H
|
||||||
|
#define AWESOME_OBJECTS_SELECTION_WATCHER_H
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
void selection_watcher_class_setup(lua_State*);
|
||||||
|
void event_handle_xfixes_selection_notify(xcb_generic_event_t*);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,120 @@
|
||||||
|
-- Test the selection watcher API
|
||||||
|
|
||||||
|
local runner = require("_runner")
|
||||||
|
local spawn = require("awful.spawn")
|
||||||
|
|
||||||
|
local header = [[
|
||||||
|
local lgi = require("lgi")
|
||||||
|
local Gdk = lgi.Gdk
|
||||||
|
local Gtk = lgi.Gtk
|
||||||
|
local GLib = lgi.GLib
|
||||||
|
local clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||||
|
clipboard:set_text("This is an experiment", -1)
|
||||||
|
]]
|
||||||
|
|
||||||
|
local acquire_and_clear_clipboard = header .. [[
|
||||||
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Gtk.main_quit)
|
||||||
|
Gtk.main()
|
||||||
|
]]
|
||||||
|
|
||||||
|
local acquire_clipboard = header .. [[
|
||||||
|
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 60, Gtk.main_quit)
|
||||||
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, function()
|
||||||
|
print("initialisation done")
|
||||||
|
io.stdout:flush()
|
||||||
|
end)
|
||||||
|
Gtk.main()
|
||||||
|
]]
|
||||||
|
|
||||||
|
local had_error = false
|
||||||
|
local owned_clipboard_changes, unowned_clipboard_changes = 0, 0
|
||||||
|
|
||||||
|
local clipboard_watcher = selection_watcher("CLIPBOARD")
|
||||||
|
local clipboard_watcher_inactive = selection_watcher("CLIPBOARD")
|
||||||
|
local primary_watcher = selection_watcher("PRIMARY")
|
||||||
|
|
||||||
|
clipboard_watcher:connect_signal("selection_changed", function(_, owned)
|
||||||
|
if owned then
|
||||||
|
owned_clipboard_changes = owned_clipboard_changes + 1
|
||||||
|
else
|
||||||
|
unowned_clipboard_changes = unowned_clipboard_changes + 1
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
clipboard_watcher_inactive:connect_signal("selection_changed", function()
|
||||||
|
had_error = true
|
||||||
|
error("Unexpected signal on inactive CLIPBOARD watcher")
|
||||||
|
end)
|
||||||
|
primary_watcher:connect_signal("selection_changed", function()
|
||||||
|
had_error = true
|
||||||
|
error("Unexpected signal on PRIMARY watcher")
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function check_state(owned, unowned)
|
||||||
|
assert(not had_error, "there was an error")
|
||||||
|
assert(owned_clipboard_changes == owned,
|
||||||
|
string.format("expected %d owned changes, but got %d", owned, owned_clipboard_changes))
|
||||||
|
assert(unowned_clipboard_changes == unowned,
|
||||||
|
string.format("expected %d unowned changes, but got %d", unowned, unowned_clipboard_changes))
|
||||||
|
end
|
||||||
|
|
||||||
|
local continue = false
|
||||||
|
runner.run_steps{
|
||||||
|
-- Clear the clipboard to get to a known state
|
||||||
|
function()
|
||||||
|
check_state(0, 0)
|
||||||
|
spawn.with_line_callback({ "lua", "-e", acquire_and_clear_clipboard },
|
||||||
|
{ exit = function() continue = true end })
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
function()
|
||||||
|
-- Wait for the clipboard to be cleared
|
||||||
|
check_state(0, 0)
|
||||||
|
if not continue then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Activate the watchers
|
||||||
|
clipboard_watcher.active = true
|
||||||
|
primary_watcher.active = true
|
||||||
|
awesome.sync()
|
||||||
|
|
||||||
|
-- Set the clipboard
|
||||||
|
continue = false
|
||||||
|
spawn.with_line_callback({ "lua", "-e", acquire_clipboard },
|
||||||
|
{ stdout = function(line)
|
||||||
|
assert(line == "initialisation done",
|
||||||
|
"Unexpected line: " .. line)
|
||||||
|
continue = true
|
||||||
|
end })
|
||||||
|
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
function()
|
||||||
|
-- Wait for the clipboard to be set
|
||||||
|
if not continue then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
check_state(1, 0)
|
||||||
|
|
||||||
|
-- Now clear the clipboard again
|
||||||
|
continue = false
|
||||||
|
spawn.with_line_callback({ "lua", "-e", acquire_and_clear_clipboard },
|
||||||
|
{ exit = function() continue = true end })
|
||||||
|
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
function()
|
||||||
|
-- Wait for the clipboard to be set
|
||||||
|
if not continue then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
check_state(2, 1)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
Loading…
Reference in New Issue