Add support for motif wm hints

This makes motif wm hints available on clients as c.motif_wm_hints.
Actually interpreting all the values is up to Lua. The definition of the
necessary properties is taken from motif.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2018-08-03 19:19:43 +02:00
parent 15a508f022
commit d76143f97b
5 changed files with 212 additions and 0 deletions

View File

@ -64,3 +64,4 @@ XSEL_DATA
WM_TAKE_FOCUS
AWESOME_CLIENT_ORDER
_XKB_RULES_NAMES
_MOTIF_WM_HINTS

View File

@ -646,6 +646,43 @@
* @see size_hints_honor
*/
/**
* The motif WM hints of the client.
*
* This is nil if the client has no motif hints. Otherwise, this is a table that
* contains the present properties. Note that awesome provides these properties
* as-is and does not interpret them for you. For example, if the function table
* only has "resize" set to true, this means that the window requests to be only
* resizable, but asks for the other functions not to be able. If however both
* "resize" and "all" are set, this means that all but the resize function
* should be enabled.
*
* **Signal:**
*
* * *property::motif\_wm\_hints*
*
* @property motif_wm_hints
* @param table
* @tfield[opt] table table.functions
* @tfield[opt] boolean table.functions.all
* @tfield[opt] boolean table.functions.resize
* @tfield[opt] boolean table.functions.move
* @tfield[opt] boolean table.functions.minimize
* @tfield[opt] boolean table.functions.maximize
* @tfield[opt] boolean table.functions.close
* @tfield[opt] table table.decorations
* @tfield[opt] boolean table.decorations.all
* @tfield[opt] boolean table.decorations.border
* @tfield[opt] boolean table.decorations.resizeh
* @tfield[opt] boolean table.decorations.title
* @tfield[opt] boolean table.decorations.menu
* @tfield[opt] boolean table.decorations.minimize
* @tfield[opt] boolean table.decorations.maximize
* @tfield[opt] string table.input_mode
* @tfield[opt] table table.status
* @tfield[opt] boolean table.status.tearoff_window
*/
/**
* Set the client sticky, i.e. available on all tags.
*
@ -978,6 +1015,17 @@ DO_CLIENT_SET_STRING_PROPERTY(role)
DO_CLIENT_SET_STRING_PROPERTY(machine)
#undef DO_CLIENT_SET_STRING_PROPERTY
void
client_set_motif_wm_hints(lua_State *L, int cidx, motif_wm_hints_t hints)
{
client_t *c = luaA_checkudata(L, cidx, &client_class);
if (memcmp(&c->motif_wm_hints, &hints, sizeof(c->motif_wm_hints)) == 0)
return;
memcpy(&c->motif_wm_hints, &hints, sizeof(c->motif_wm_hints));
luaA_object_emit_signal(L, cidx, "property::motif_wm_hints", 0);
}
void
client_find_transient_for(client_t *c)
{
@ -1416,6 +1464,7 @@ client_update_properties(lua_State *L, int cidx, client_t *c)
xcb_get_property_cookie_t net_wm_icon_name = property_get_net_wm_icon_name(c);
xcb_get_property_cookie_t wm_class = property_get_wm_class(c);
xcb_get_property_cookie_t wm_protocols = property_get_wm_protocols(c);
xcb_get_property_cookie_t motif_wm_hints = property_get_motif_wm_hints(c);
xcb_get_property_cookie_t opacity = xwindow_get_opacity_unchecked(c->window);
/* update strut */
@ -1436,6 +1485,7 @@ client_update_properties(lua_State *L, int cidx, client_t *c)
property_update_net_wm_icon_name(c, net_wm_icon_name);
property_update_wm_class(c, wm_class);
property_update_wm_protocols(c, wm_protocols);
property_update_motif_wm_hints(c, motif_wm_hints);
window_set_opacity(L, cidx, xwindow_get_opacity_from_cookie(opacity));
}
@ -3156,6 +3206,78 @@ LUA_OBJECT_EXPORT_PROPERTY(client, client_t, maximized_vertical, lua_pushboolean
LUA_OBJECT_EXPORT_PROPERTY(client, client_t, maximized, lua_pushboolean)
LUA_OBJECT_EXPORT_PROPERTY(client, client_t, startup_id, lua_pushstring)
static int
luaA_client_get_motif_wm_hints(lua_State *L, client_t *c)
{
if (!(c->motif_wm_hints.hints & MWM_HINTS_AWESOME_SET))
return 0;
lua_newtable(L);
#define HANDLE_BIT(field, flag, name) do { \
lua_pushboolean(L, c->motif_wm_hints.field & flag); \
lua_setfield(L, -2, name); \
} while (0)
if (c->motif_wm_hints.hints & MWM_HINTS_FUNCTIONS)
{
lua_newtable(L);
HANDLE_BIT(functions, MWM_FUNC_ALL, "all");
HANDLE_BIT(functions, MWM_FUNC_RESIZE, "resize");
HANDLE_BIT(functions, MWM_FUNC_MOVE, "move");
HANDLE_BIT(functions, MWM_FUNC_MINIMIZE, "minimize");
HANDLE_BIT(functions, MWM_FUNC_MAXIMIZE, "maximize");
HANDLE_BIT(functions, MWM_FUNC_CLOSE, "close");
lua_setfield(L, -2, "functions");
}
if (c->motif_wm_hints.hints & MWM_HINTS_DECORATIONS)
{
lua_newtable(L);
HANDLE_BIT(decorations, MWM_DECOR_ALL, "all");
HANDLE_BIT(decorations, MWM_DECOR_BORDER, "border");
HANDLE_BIT(decorations, MWM_DECOR_RESIZEH, "resizeh");
HANDLE_BIT(decorations, MWM_DECOR_TITLE, "title");
HANDLE_BIT(decorations, MWM_DECOR_MENU, "menu");
HANDLE_BIT(decorations, MWM_DECOR_MINIMIZE, "minimize");
HANDLE_BIT(decorations, MWM_DECOR_MAXIMIZE, "maximize");
lua_setfield(L, -2, "decorations");
}
if (c->motif_wm_hints.hints & MWM_HINTS_INPUT_MODE)
{
switch (c->motif_wm_hints.input_mode) {
case MWM_INPUT_MODELESS:
lua_pushliteral(L, "modeless");
break;
case MWM_INPUT_PRIMARY_APPLICATION_MODAL:
lua_pushliteral(L, "primary_application_modal");
break;
case MWM_INPUT_SYSTEM_MODAL:
lua_pushliteral(L, "system_modal");
break;
case MWM_INPUT_FULL_APPLICATION_MODAL:
lua_pushliteral(L, "full_application_modal");
break;
default:
lua_pushfstring(L, "unknown (%d)", (int) c->motif_wm_hints.input_mode);
break;
}
lua_setfield(L, -2, "input_mode");
}
if (c->motif_wm_hints.hints & MWM_HINTS_STATUS)
{
lua_newtable(L);
HANDLE_BIT(status, MWM_TEAROFF_WINDOW, "tearoff_window");
lua_setfield(L, -2, "status");
}
#undef HANDLE_BIT
return 1;
}
static int
luaA_client_get_content(lua_State *L, client_t *c)
{
@ -3721,6 +3843,10 @@ client_class_setup(lua_State *L)
(lua_class_propfunc_t) luaA_client_set_modal,
(lua_class_propfunc_t) luaA_client_get_modal,
(lua_class_propfunc_t) luaA_client_set_modal);
luaA_class_add_property(&client_class, "motif_wm_hints",
NULL,
(lua_class_propfunc_t) luaA_client_get_motif_wm_hints,
NULL);
luaA_class_add_property(&client_class, "group_window",
NULL,
(lua_class_propfunc_t) luaA_client_get_group_window,

View File

@ -47,6 +47,48 @@ typedef enum {
CLIENT_TITLEBAR_COUNT = 4
} client_titlebar_t;
/* Special bit we invented to "fake" unset hints */
#define MWM_HINTS_AWESOME_SET (1L << 15)
/* The following is taken from MwmUtil.h and slightly adapted, which is
* copyright (c) 1987-2012, The Open Group.
* It is licensed under GPLv2 or later.
*/
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
#define MWM_HINTS_INPUT_MODE (1L << 2)
#define MWM_HINTS_STATUS (1L << 3)
#define MWM_FUNC_ALL (1L << 0)
#define MWM_FUNC_RESIZE (1L << 1)
#define MWM_FUNC_MOVE (1L << 2)
#define MWM_FUNC_MINIMIZE (1L << 3)
#define MWM_FUNC_MAXIMIZE (1L << 4)
#define MWM_FUNC_CLOSE (1L << 5)
#define MWM_DECOR_ALL (1L << 0)
#define MWM_DECOR_BORDER (1L << 1)
#define MWM_DECOR_RESIZEH (1L << 2)
#define MWM_DECOR_TITLE (1L << 3)
#define MWM_DECOR_MENU (1L << 4)
#define MWM_DECOR_MINIMIZE (1L << 5)
#define MWM_DECOR_MAXIMIZE (1L << 6)
#define MWM_INPUT_MODELESS 0
#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
#define MWM_INPUT_SYSTEM_MODAL 2
#define MWM_INPUT_FULL_APPLICATION_MODAL 3
#define MWM_TEAROFF_WINDOW (1L<<0)
typedef struct {
uint32_t hints;
uint32_t functions;
uint32_t decorations;
int32_t input_mode;
uint32_t status;
} motif_wm_hints_t;
/** client_t type */
struct client_t
{
@ -143,6 +185,8 @@ struct client_t
/** The drawable for this bar. */
drawable_t *drawable;
} titlebar[CLIENT_TITLEBAR_COUNT];
/** Motif WM hints, with an additional MWM_HINTS_AWESOME_SET bit */
motif_wm_hints_t motif_wm_hints;
};
ARRAY_FUNCS(client_t *, client, DO_NOTHING)
@ -190,6 +234,7 @@ void client_set_group_window(lua_State *, int, xcb_window_t);
void client_set_icons(client_t *, cairo_surface_array_t);
void client_set_icon_from_pixmaps(client_t *, xcb_pixmap_t, xcb_pixmap_t);
void client_set_skip_taskbar(lua_State *, int, bool);
void client_set_motif_wm_hints(lua_State *, int, motif_wm_hints_t);
void client_focus(client_t *);
bool client_focus_update(client_t *);
bool client_hasproto(client_t *, xcb_atom_t);

View File

@ -91,6 +91,7 @@ HANDLE_PROPERTY(wm_hints)
HANDLE_PROPERTY(wm_class)
HANDLE_PROPERTY(net_wm_icon)
HANDLE_PROPERTY(net_wm_pid)
HANDLE_PROPERTY(motif_wm_hints)
#undef HANDLE_PROPERTY
@ -304,6 +305,41 @@ property_update_net_wm_pid(client_t *c, xcb_get_property_cookie_t cookie)
p_delete(&reply);
}
xcb_get_property_cookie_t
property_get_motif_wm_hints(client_t *c)
{
return xcb_get_property_unchecked(globalconf.connection, false, c->window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 0L, 5L);
}
void
property_update_motif_wm_hints(client_t *c, xcb_get_property_cookie_t cookie)
{
motif_wm_hints_t hints;
xcb_get_property_reply_t *reply;
lua_State *L = globalconf_get_lua_State();
/* Clear the hints */
p_clear(&hints, 1);
reply = xcb_get_property_reply(globalconf.connection, cookie, NULL);
if(reply && reply->value_len == 5)
{
uint32_t *rdata = xcb_get_property_value(reply);
if(rdata)
{
memcpy(&hints, rdata, sizeof(hints));
hints.hints |= MWM_HINTS_AWESOME_SET;
}
}
p_delete(&reply);
luaA_object_push(L, c);
client_set_motif_wm_hints(L, -1, hints);
lua_pop(L, 1);
}
xcb_get_property_cookie_t
property_get_wm_protocols(client_t *c)
{
@ -478,6 +514,9 @@ property_handle_propertynotify(xcb_property_notify_event_t *ev)
HANDLE(_NET_WM_PID, property_handle_net_wm_pid)
HANDLE(_NET_WM_WINDOW_OPACITY, property_handle_net_wm_opacity)
/* MOTIF hints */
HANDLE(_MOTIF_WM_HINTS, property_handle_motif_wm_hints)
/* background change */
HANDLE(_XROOTPMAP_ID, property_handle_xrootpmap_id)

View File

@ -42,6 +42,7 @@ PROPERTY(wm_class);
PROPERTY(wm_protocols);
PROPERTY(net_wm_pid);
PROPERTY(net_wm_icon);
PROPERTY(motif_wm_hints);
#undef PROPERTY