Add awesome.register_xproperty (FS#1212)
This commits adds awesome.register_xproperty(). This allows lua code to register arbitrary X11 properties with awesome which will then watch these properties. Whenever such a property is changed on a client or drawin, we will emit the xproperty::name signal. This also adds window:get_xproperty(name) and window:set_xproperty(name, value) which allows to mess with properties. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
2b1febeabe
commit
62e2dee4ba
|
@ -55,12 +55,14 @@ typedef struct button_t button_t;
|
|||
typedef struct widget_t widget_t;
|
||||
typedef struct client_t client_t;
|
||||
typedef struct tag tag_t;
|
||||
typedef struct xproperty xproperty_t;
|
||||
|
||||
ARRAY_TYPE(button_t *, button)
|
||||
ARRAY_TYPE(tag_t *, tag)
|
||||
ARRAY_TYPE(screen_t, screen)
|
||||
ARRAY_TYPE(client_t *, client)
|
||||
ARRAY_TYPE(drawin_t *, drawin)
|
||||
ARRAY_TYPE(xproperty_t, xproperty)
|
||||
|
||||
/** Main configuration structure */
|
||||
typedef struct
|
||||
|
@ -140,6 +142,8 @@ typedef struct
|
|||
bool need_lazy_banning;
|
||||
/** Tag list */
|
||||
tag_array_t tags;
|
||||
/** List of registered xproperties */
|
||||
xproperty_array_t xproperties;
|
||||
} awesome_t;
|
||||
|
||||
extern awesome_t globalconf;
|
||||
|
|
|
@ -48,19 +48,10 @@ function wibox:set_fg(c)
|
|||
self._drawable:set_fg(c)
|
||||
end
|
||||
|
||||
--- Helper function to make wibox:buttons() work as expected
|
||||
function wibox:buttons(...)
|
||||
return self.drawin:buttons(...)
|
||||
end
|
||||
|
||||
--- Helper function to make wibox:struts() work as expected
|
||||
function wibox:struts(...)
|
||||
return self.drawin:struts(...)
|
||||
end
|
||||
|
||||
--- Helper function to make wibox:geometry() work as expected
|
||||
function wibox:geometry(...)
|
||||
return self.drawin:geometry(...)
|
||||
for _, k in pairs{ "buttons", "struts", "geometry", "get_xproperty", "set_xproperty" } do
|
||||
wibox[k] = function(self, ...)
|
||||
return self.drawin[k](self.drawin, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local function setup_signals(_wibox)
|
||||
|
|
2
luaa.c
2
luaa.c
|
@ -42,6 +42,7 @@
|
|||
#include "objects/drawable.h"
|
||||
#include "screen.h"
|
||||
#include "event.h"
|
||||
#include "property.h"
|
||||
#include "selection.h"
|
||||
#include "systray.h"
|
||||
#include "common/xcursor.h"
|
||||
|
@ -573,6 +574,7 @@ luaA_init(xdgHandle* xdg)
|
|||
{ "emit_signal", luaA_awesome_emit_signal },
|
||||
{ "systray", luaA_systray },
|
||||
{ "load_image", luaA_load_image },
|
||||
{ "register_xproperty", luaA_register_xproperty },
|
||||
{ "__index", luaA_awesome_index },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -37,6 +37,12 @@ module("awesome")
|
|||
-- @name load_image
|
||||
-- @class function
|
||||
|
||||
--- Register a new xproperty.
|
||||
-- @param name The name of the X11 property
|
||||
-- @param type One of "string", "number" or "boolean"
|
||||
-- @name register_xproperty
|
||||
-- @class function
|
||||
|
||||
--- Add a global signal.
|
||||
-- @param name A string with the event name.
|
||||
-- @param func The function to call.
|
||||
|
|
|
@ -111,6 +111,17 @@ module("client")
|
|||
-- @name unmanage
|
||||
-- @class function
|
||||
|
||||
--- Change a xproperty.
|
||||
-- @param name The name of the X11 property
|
||||
-- @param value The new value for the property
|
||||
-- @name set_xproperty
|
||||
-- @class function
|
||||
|
||||
--- Get the value of a xproperty.
|
||||
-- @param name The name of the X11 property
|
||||
-- @name get_xproperty
|
||||
-- @class function
|
||||
|
||||
--- Add a signal.
|
||||
-- @param name A signal name.
|
||||
-- @param func A function to call when the signal is emitted.
|
||||
|
|
|
@ -40,6 +40,17 @@ module("drawin")
|
|||
-- @name geometry
|
||||
-- @class function
|
||||
|
||||
--- Change a xproperty.
|
||||
-- @param name The name of the X11 property
|
||||
-- @param value The new value for the property
|
||||
-- @name set_xproperty
|
||||
-- @class function
|
||||
|
||||
--- Get the value of a xproperty.
|
||||
-- @param name The name of the X11 property
|
||||
-- @name get_xproperty
|
||||
-- @class function
|
||||
|
||||
--- Add a signal.
|
||||
-- @param name A signal name.
|
||||
-- @param func A function to call when the signal is emitted.
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "xwindow.h"
|
||||
#include "ewmh.h"
|
||||
#include "screen.h"
|
||||
#include "property.h"
|
||||
#include "objects/window.h"
|
||||
#include "common/atoms.h"
|
||||
#include "common/luaobject.h"
|
||||
|
@ -296,6 +297,101 @@ luaA_window_set_type(lua_State *L, window_t *w)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static xproperty_t *
|
||||
luaA_find_xproperty(lua_State *L, int idx)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, idx);
|
||||
foreach(prop, globalconf.xproperties)
|
||||
if (A_STREQ(prop->name, name))
|
||||
return prop;
|
||||
luaL_argerror(L, idx, "Unknown xproperty");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Set an xproperty.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_window_set_xproperty(lua_State *L)
|
||||
{
|
||||
window_t *w = luaA_checkudata(L, 1, &window_class);
|
||||
xproperty_t *prop = luaA_find_xproperty(L, 2);
|
||||
xcb_atom_t type;
|
||||
uint8_t format;
|
||||
size_t len;
|
||||
uint32_t number;
|
||||
const void *data;
|
||||
|
||||
if(lua_isnil(L, 3))
|
||||
{
|
||||
xcb_delete_property(globalconf.connection, w->window, prop->atom);
|
||||
} else {
|
||||
if(prop->type == PROP_STRING)
|
||||
{
|
||||
data = luaL_checklstring(L, 3, &len);
|
||||
type = UTF8_STRING;
|
||||
format = 8;
|
||||
} else if(prop->type == PROP_NUMBER || prop->type == PROP_BOOLEAN)
|
||||
{
|
||||
if (prop->type == PROP_NUMBER)
|
||||
number = luaL_checkinteger(L, 3);
|
||||
else
|
||||
number = luaA_checkboolean(L, 3);
|
||||
data = &number;
|
||||
len = 1;
|
||||
type = XCB_ATOM_CARDINAL;
|
||||
format = 32;
|
||||
} else
|
||||
fatal("Got an xproperty with invalid type");
|
||||
|
||||
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, w->window,
|
||||
prop->atom, type, format, len, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Get an xproperty.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static int
|
||||
luaA_window_get_xproperty(lua_State *L)
|
||||
{
|
||||
window_t *w = luaA_checkudata(L, 1, &window_class);
|
||||
xproperty_t *prop = luaA_find_xproperty(L, 2);
|
||||
xcb_atom_t type;
|
||||
void *data;
|
||||
xcb_get_property_reply_t *reply;
|
||||
|
||||
type = prop->type == PROP_STRING ? UTF8_STRING : XCB_ATOM_CARDINAL;
|
||||
reply = xcb_get_property_reply(globalconf.connection,
|
||||
xcb_get_property_unchecked(globalconf.connection, false, w->window,
|
||||
prop->atom, type, 0, 4), NULL);
|
||||
if(!reply)
|
||||
return 0;
|
||||
|
||||
data = xcb_get_property_value(reply);
|
||||
|
||||
if(prop->type == PROP_STRING)
|
||||
lua_pushlstring(L, data, reply->value_len);
|
||||
else
|
||||
{
|
||||
if(reply->value_len <= 0)
|
||||
{
|
||||
p_delete(&reply);
|
||||
return 0;
|
||||
}
|
||||
if(prop->type == PROP_NUMBER)
|
||||
lua_pushinteger(L, *(uint32_t *) data);
|
||||
else
|
||||
lua_pushboolean(L, *(uint32_t *) data);
|
||||
}
|
||||
|
||||
p_delete(&reply);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Translate a window_type_t into the corresponding EWMH atom.
|
||||
* @param type The type to return.
|
||||
* @return The EWMH atom for this type.
|
||||
|
@ -360,6 +456,8 @@ window_class_setup(lua_State *L)
|
|||
{
|
||||
{ "struts", luaA_window_struts },
|
||||
{ "buttons", luaA_window_buttons },
|
||||
{ "set_xproperty", luaA_window_set_xproperty },
|
||||
{ "get_xproperty", luaA_window_get_xproperty },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
95
property.c
95
property.c
|
@ -378,12 +378,41 @@ property_handle_xrootpmap_id(uint8_t state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** The property notify event handler handling xproperties.
|
||||
* \param ev The event.
|
||||
*/
|
||||
static void
|
||||
property_handle_propertynotify_xproperty(xcb_property_notify_event_t *ev)
|
||||
{
|
||||
xproperty_t *prop;
|
||||
xproperty_t lookup = { .atom = ev->atom };
|
||||
buffer_t buf;
|
||||
void *obj;
|
||||
|
||||
prop = xproperty_array_lookup(&globalconf.xproperties, &lookup);
|
||||
if(!prop)
|
||||
/* Property is not registered */
|
||||
return;
|
||||
|
||||
obj = client_getbywin(ev->window);
|
||||
if(!obj)
|
||||
obj = drawin_getbywin(ev->window);
|
||||
if(!obj)
|
||||
return;
|
||||
|
||||
/* Get us the name of the property */
|
||||
buffer_inita(&buf, a_strlen(prop->name) + a_strlen("xproperty::") + 1);
|
||||
buffer_addf(&buf, "xproperty::%s", prop->name);
|
||||
|
||||
/* And emit the right signal */
|
||||
luaA_object_push(globalconf.L, obj);
|
||||
luaA_object_emit_signal(globalconf.L, -1, buf.s, 0);
|
||||
lua_pop(globalconf.L, 1);
|
||||
buffer_wipe(&buf);
|
||||
}
|
||||
|
||||
/** The property notify event handler.
|
||||
* \param data Unused data.
|
||||
* \param connection The connection to the X server.
|
||||
* \param ev The event.
|
||||
* \return Status code, 0 if everything's fine.
|
||||
*/
|
||||
void
|
||||
property_handle_propertynotify(xcb_property_notify_event_t *ev)
|
||||
|
@ -393,6 +422,8 @@ property_handle_propertynotify(xcb_property_notify_event_t *ev)
|
|||
|
||||
globalconf.timestamp = ev->time;
|
||||
|
||||
property_handle_propertynotify_xproperty(ev);
|
||||
|
||||
/* Find the correct event handler */
|
||||
#define HANDLE(atom_, cb) \
|
||||
if (ev->atom == atom_) \
|
||||
|
@ -436,4 +467,62 @@ property_handle_propertynotify(xcb_property_notify_event_t *ev)
|
|||
(*handler)(ev->state, ev->window);
|
||||
}
|
||||
|
||||
/** Register a new xproperty.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
* \luastack
|
||||
* \lparam The name of the X11 property
|
||||
* \lparam One of "string", "number" or "boolean"
|
||||
*/
|
||||
int
|
||||
luaA_register_xproperty(lua_State *L)
|
||||
{
|
||||
const char *name;
|
||||
struct xproperty property;
|
||||
struct xproperty *found;
|
||||
const char *const args[] = { "string", "number", "boolean" };
|
||||
xcb_intern_atom_reply_t *atom_r;
|
||||
int type;
|
||||
|
||||
name = luaL_checkstring(L, 1);
|
||||
type = luaL_checkoption(L, 2, NULL, args);
|
||||
if (type == 0)
|
||||
property.type = PROP_STRING;
|
||||
else if (type == 1)
|
||||
property.type = PROP_NUMBER;
|
||||
else
|
||||
property.type = PROP_BOOLEAN;
|
||||
|
||||
atom_r = xcb_intern_atom_reply(globalconf.connection,
|
||||
xcb_intern_atom_unchecked(globalconf.connection, false,
|
||||
a_strlen(name), name),
|
||||
NULL);
|
||||
if(!atom_r)
|
||||
return 0;
|
||||
|
||||
property.atom = atom_r->atom;
|
||||
p_delete(&atom_r);
|
||||
|
||||
found = xproperty_array_lookup(&globalconf.xproperties, &property);
|
||||
if(found)
|
||||
{
|
||||
/* Property already registered */
|
||||
if(found->type != property.type)
|
||||
return luaL_error(L, "xproperty '%s' already registered with different type", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_t buf;
|
||||
buffer_inita(&buf, a_strlen(name) + a_strlen("xproperty::") + 1);
|
||||
buffer_addf(&buf, "xproperty::%s", name);
|
||||
|
||||
property.name = a_strdup(name);
|
||||
xproperty_array_insert(&globalconf.xproperties, property);
|
||||
signal_add(&window_class.signals, buf.s);
|
||||
buffer_wipe(&buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
23
property.h
23
property.h
|
@ -46,6 +46,29 @@ PROPERTY(net_wm_icon);
|
|||
#undef PROPERTY
|
||||
|
||||
void property_handle_propertynotify(xcb_property_notify_event_t *ev);
|
||||
int luaA_register_xproperty(lua_State *L);
|
||||
|
||||
struct xproperty {
|
||||
xcb_atom_t atom;
|
||||
const char *name;
|
||||
enum {
|
||||
/* UTF8_STRING */
|
||||
PROP_STRING,
|
||||
/* CARDINAL */
|
||||
PROP_NUMBER,
|
||||
/* CARDINAL with values 0 and 1 (or "0 and != 0") */
|
||||
PROP_BOOLEAN
|
||||
} type;
|
||||
};
|
||||
|
||||
static inline int
|
||||
xproperty_cmp(const void *a, const void *b)
|
||||
{
|
||||
const xproperty_t *x = a, *y = b;
|
||||
return x->atom - y->atom;
|
||||
}
|
||||
|
||||
BARRAY_FUNCS(xproperty_t, xproperty, DO_NOTHING, xproperty_cmp)
|
||||
|
||||
#endif
|
||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
Loading…
Reference in New Issue