xmacro(WM_STATE)
xmacro(WM_CLIENT_LEADER)
xmacro(WM_TAKE_FOCUS)
+xmacro(WM_WINDOW_ROLE)
xmacro(I3_SOCKET_PATH)
xmacro(I3_CONFIG_PATH)
* application supports _NET_WM_NAME, in COMPOUND_TEXT otherwise). */
char *name_x;
+ /** The WM_WINDOW_ROLE of this window (for example, the pidgin buddy window
+ * sets "buddy list"). Useful to match specific windows in assignments or
+ * for_window. */
+ char *role;
+
/** Flag to force re-rendering the decoration upon changes */
bool name_x_changed;
struct regex *class;
struct regex *instance;
struct regex *mark;
+ struct regex *role;
enum {
M_DONTCHECK = -1,
M_NODOCK = 0,
*/
void window_update_strut_partial(i3Window *win, xcb_get_property_reply_t *prop);
+/**
+ * Updates the WM_WINDOW_ROLE
+ *
+ */
+void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
+
#endif
class { yy_push_state(WANT_QSTRING); return TOK_CLASS; }
instance { yy_push_state(WANT_QSTRING); return TOK_INSTANCE; }
+window_role { yy_push_state(WANT_QSTRING); return TOK_WINDOW_ROLE; }
id { yy_push_state(WANT_QSTRING); return TOK_ID; }
con_id { yy_push_state(WANT_QSTRING); return TOK_CON_ID; }
con_mark { yy_push_state(WANT_QSTRING); return TOK_MARK; }
%token TOK_MARK "mark"
%token TOK_CLASS "class"
%token TOK_INSTANCE "instance"
+%token TOK_WINDOW_ROLE "window_role"
%token TOK_ID "id"
%token TOK_CON_ID "con_id"
%token TOK_TITLE "title"
current_match.instance = regex_new($3);
free($3);
}
+ | TOK_WINDOW_ROLE '=' STR
+ {
+ printf("criteria: window_role = %s\n", $3);
+ current_match.role = regex_new($3);
+ free($3);
+ }
| TOK_CON_ID '=' STR
{
printf("criteria: id = %s\n", $3);
class { BEGIN(WANT_QSTRING); return TOK_CLASS; }
instance { BEGIN(WANT_QSTRING); return TOK_INSTANCE; }
+window_role { BEGIN(WANT_QSTRING); return TOK_WINDOW_ROLE; }
id { BEGIN(WANT_QSTRING); return TOK_ID; }
con_id { BEGIN(WANT_QSTRING); return TOK_CON_ID; }
con_mark { BEGIN(WANT_QSTRING); return TOK_MARK; }
%token TOK_CLASS "class"
%token TOK_INSTANCE "instance"
+%token TOK_WINDOW_ROLE "window_role"
%token TOK_ID "id"
%token TOK_CON_ID "con_id"
%token TOK_TITLE "title"
current_match.instance = regex_new($3);
free($3);
}
+ | TOK_WINDOW_ROLE '=' STR
+ {
+ printf("criteria: window_role = %s\n", $3);
+ current_match.role = regex_new($3);
+ free($3);
+ }
| TOK_CON_ID '=' STR
{
printf("criteria: id = %s\n", $3);
return true;
}
+/*
+ * Called when a window changes its WM_WINDOW_ROLE.
+ *
+ */
+static bool handle_windowrole_change(void *data, xcb_connection_t *conn, uint8_t state,
+ xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
+ Con *con;
+ if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
+ return false;
+
+ window_update_role(con->window, prop, false);
+
+ return true;
+}
+
#if 0
/*
* Updates the client’s WM_CLASS property
{ 0, 128, handle_windowname_change_legacy },
{ 0, UINT_MAX, handle_normal_hints },
{ 0, UINT_MAX, handle_clientleader_change },
- { 0, UINT_MAX, handle_transient_for }
+ { 0, UINT_MAX, handle_transient_for },
+ { 0, 128, handle_windowrole_change }
};
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
property_handlers[3].atom = XCB_ATOM_WM_NORMAL_HINTS;
property_handlers[4].atom = A_WM_CLIENT_LEADER;
property_handlers[5].atom = XCB_ATOM_WM_TRANSIENT_FOR;
+ property_handlers[6].atom = A_WM_WINDOW_ROLE;
}
static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
utf8_title_cookie, title_cookie,
- class_cookie, leader_cookie, transient_cookie;
+ class_cookie, leader_cookie, transient_cookie,
+ role_cookie;
geomc = xcb_get_geometry(conn, d);
transient_cookie = GET_PROPERTY(XCB_ATOM_WM_TRANSIENT_FOR, UINT32_MAX);
title_cookie = GET_PROPERTY(XCB_ATOM_WM_NAME, 128);
class_cookie = GET_PROPERTY(XCB_ATOM_WM_CLASS, 128);
+ role_cookie = GET_PROPERTY(A_WM_WINDOW_ROLE, 128);
/* TODO: also get wm_normal_hints here. implement after we got rid of xcb-event */
DLOG("reparenting!\n");
window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL));
window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL));
+ window_update_role(cwindow, xcb_get_property_reply(conn, role_cookie, NULL), true);
/* check if the window needs WM_TAKE_FOCUS */
cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS);
match->application == NULL &&
match->class == NULL &&
match->instance == NULL &&
+ match->role == NULL &&
match->id == XCB_NONE &&
match->con_id == NULL &&
match->dock == -1 &&
DUPLICATE_REGEX(application);
DUPLICATE_REGEX(class);
DUPLICATE_REGEX(instance);
+ DUPLICATE_REGEX(role);
}
/*
}
}
+ if (match->role != NULL) {
+ if (window->role != NULL &&
+ regex_matches(match->role, window->role)) {
+ LOG("window_role matches (%s)\n", window->role);
+ } else {
+ LOG("window_role does not match\n");
+ return false;
+ }
+ }
+
if (match->dock != -1) {
LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
regex_free(match->class);
regex_free(match->instance);
regex_free(match->mark);
+ regex_free(match->role);
/* Second step: free the regex helper struct itself */
FREE(match->title);
FREE(match->class);
FREE(match->instance);
FREE(match->mark);
+ FREE(match->role);
}
free(prop);
}
+
+/*
+ * Updates the WM_WINDOW_ROLE
+ *
+ */
+void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt) {
+ if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
+ DLOG("prop == NULL\n");
+ FREE(prop);
+ return;
+ }
+
+ char *new_role;
+ if (asprintf(&new_role, "%.*s", xcb_get_property_value_length(prop),
+ (char*)xcb_get_property_value(prop)) == -1) {
+ perror("asprintf()");
+ DLOG("Could not get WM_WINDOW_ROLE\n");
+ free(prop);
+ return;
+ }
+ FREE(win->role);
+ win->role = new_role;
+ LOG("WM_WINDOW_ROLE changed to \"%s\"\n", win->role);
+
+ if (before_mgmt) {
+ free(prop);
+ return;
+ }
+
+ run_assignments(win);
+
+ free(prop);
+}