Skip to content
This repository has been archived by the owner on Apr 18, 2023. It is now read-only.

Commit

Permalink
Add "machine" criterion to match WM_CLIENT_MACHINE
Browse files Browse the repository at this point in the history
Closes #3981

Add "%machine" title_format placeholder
Add "machine" to the IPC and layout saving/restoring
  • Loading branch information
xzfc authored and orestisfl committed Jan 28, 2021
1 parent 9212267 commit 32c10a1
Show file tree
Hide file tree
Showing 16 changed files with 86 additions and 10 deletions.
2 changes: 2 additions & 0 deletions RELEASE-NOTES-next
Expand Up @@ -17,6 +17,8 @@ strongly encouraged to upgrade.
• i3bar: use first bar config by default
• i3-dump-log -f now uses UNIX sockets instead of pthreads. The UNIX socket approach
should be more reliable and also more portable.
• Allow for_window to match against WM_CLIENT_MACHINE
• Add %machine placeholder (WM_CLIENT_MACHINE) to title_format

┌────────────────────────────┐
│ Bugfixes │
Expand Down
3 changes: 2 additions & 1 deletion docs/ipc
Expand Up @@ -362,7 +362,8 @@ window (integer)::
X11-related tools display (usually in hex).
window_properties (map)::
This optional field contains all available X11 window properties from the
following list: *title*, *instance*, *class*, *window_role* and *transient_for*.
following list: *title*, *instance*, *class*, *window_role*, *machine*
and *transient_for*.
window_type (string)::
The window type (_NET_WM_WINDOW_TYPE). Possible values are undefined, normal,
dialog, utility, toolbar, splash, menu, dropdown_menu, popup_menu, tooltip and
Expand Down
6 changes: 3 additions & 3 deletions docs/layout-saving
Expand Up @@ -185,9 +185,9 @@ Therefore, if you just start Emacs via dmenu, it will not get swallowed by that
container. Only if you start Emacs with the proper instance name (+emacs24
--name notmuch+), it will get swallowed.

You can match on "class", "instance", "window_role" and "title". All values are
case-sensitive regular expressions (PCRE). Use +xprop(1)+ and click into a
window to see its properties:
You can match on "class", "instance", "window_role", "title" and "machine". All
values are case-sensitive regular expressions (PCRE). Use +xprop(1)+ and click
into a window to see its properties:

--------------------------------------------------------------------------------
$ xprop
Expand Down
13 changes: 10 additions & 3 deletions docs/userguide
Expand Up @@ -1896,6 +1896,10 @@ window_type::
Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are
+normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+,
+popup_menu+, +tooltip+ and +notification+.
machine::
Compares the name of the machine the client window is running on
(WM_CLIENT_MACHINE). Usually, it is equal to the hostname of the local
machine, but it may differ if remote X11 apps are used.
id::
Compares the X11 window ID, which you can get via +xwininfo+ for example.
title::
Expand Down Expand Up @@ -1933,9 +1937,9 @@ tiling_from::
tiling are matched. With "user", only windows that the user made tiling
are matched.

The criteria +class+, +instance+, +role+, +title+, +workspace+ and +mark+ are
actually regular expressions (PCRE). See +pcresyntax(3)+ or +perldoc perlre+ for
information on how to use them.
The criteria +class+, +instance+, +role+, +title+, +workspace+, +machine+ and
+mark+ are actually regular expressions (PCRE). See +pcresyntax(3)+ or +perldoc
perlre+ for information on how to use them.

[[exec]]
=== Executing applications (exec)
Expand Down Expand Up @@ -2584,6 +2588,9 @@ and the following placeholders which will be replaced:
+%instance+::
The X11 window instance (first part of WM_CLASS). This corresponds to the
+instance+ criterion, see <<command_criteria>>.
+%machine+::
The X11 name of the machine (WM_CLIENT_MACHINE). This corresponds to the
+machine+ criterion, see <<command_criteria>>.

Using the <<for_window>> directive, you can set the title format for any window
based on <<command_criteria>>.
Expand Down
4 changes: 4 additions & 0 deletions include/data.h
Expand Up @@ -414,6 +414,9 @@ struct Window {
* for_window. */
char *role;

/** WM_CLIENT_MACHINE of the window */
char *machine;

/** Flag to force re-rendering the decoration upon changes */
bool name_x_changed;

Expand Down Expand Up @@ -500,6 +503,7 @@ struct Match {
struct regex *mark;
struct regex *window_role;
struct regex *workspace;
struct regex *machine;
xcb_atom_t window_type;
enum {
U_DONTCHECK = -1,
Expand Down
6 changes: 6 additions & 0 deletions include/window.h
Expand Up @@ -95,3 +95,9 @@ void window_update_hints(i3Window *win, xcb_get_property_reply_t *prop, bool *ur
*
*/
void window_update_motif_hints(i3Window *win, xcb_get_property_reply_t *prop, border_style_t *motif_border_style);

/**
* Updates the WM_CLIENT_MACHINE
*
*/
void window_update_machine(i3Window *win, xcb_get_property_reply_t *prop);
1 change: 1 addition & 0 deletions parser-specs/commands.spec
Expand Up @@ -54,6 +54,7 @@ state CRITERIA:
ctype = 'title' -> CRITERION
ctype = 'urgent' -> CRITERION
ctype = 'workspace' -> CRITERION
ctype = 'machine' -> CRITERION
ctype = 'tiling', 'floating'
-> call cmd_criteria_add($ctype, NULL); CRITERIA
']' -> call cmd_criteria_match_windows(); INITIAL
Expand Down
1 change: 1 addition & 0 deletions parser-specs/config.spec
Expand Up @@ -191,6 +191,7 @@ state CRITERIA:
ctype = 'title' -> CRITERION
ctype = 'urgent' -> CRITERION
ctype = 'workspace' -> CRITERION
ctype = 'machine' -> CRITERION
ctype = 'floating_from' -> CRITERION_FROM
ctype = 'tiling_from' -> CRITERION_FROM
ctype = 'tiling', 'floating'
Expand Down
7 changes: 6 additions & 1 deletion src/con.c
Expand Up @@ -2304,20 +2304,25 @@ i3String *con_parse_title_format(Con *con) {
char *title;
char *class;
char *instance;
char *machine;
if (win == NULL) {
title = pango_escape_markup(con_get_tree_representation(con));
class = sstrdup("i3-frame");
instance = sstrdup("i3-frame");
machine = sstrdup("");
} else {
title = pango_escape_markup(sstrdup((win->name == NULL) ? "" : i3string_as_utf8(win->name)));
class = pango_escape_markup(sstrdup((win->class_class == NULL) ? "" : win->class_class));
instance = pango_escape_markup(sstrdup((win->class_instance == NULL) ? "" : win->class_instance));
machine = pango_escape_markup(sstrdup((win->machine == NULL) ? "" : win->machine));
}

placeholder_t placeholders[] = {
{.name = "%title", .value = title},
{.name = "%class", .value = class},
{.name = "%instance", .value = instance}};
{.name = "%instance", .value = instance},
{.name = "%machine", .value = machine},
};
const size_t num = sizeof(placeholders) / sizeof(placeholder_t);

char *formatted_str = format_placeholders(con->title_format, &placeholders[0], num);
Expand Down
14 changes: 13 additions & 1 deletion src/handlers.c
Expand Up @@ -1086,6 +1086,16 @@ static bool handle_class_change(Con *con, xcb_get_property_reply_t *prop) {
return true;
}

/*
* Handles the WM_CLIENT_MACHINE property for assignments and criteria selection.
*
*/
static bool handle_machine_change(Con *con, xcb_get_property_reply_t *prop) {
window_update_machine(con->window, prop);
con = remanage_window(con);
return true;
}

/*
* Handles the _MOTIF_WM_HINTS property of specifing window deocration settings.
*
Expand Down Expand Up @@ -1197,6 +1207,7 @@ static struct property_handler_t property_handlers[] = {
{0, UINT_MAX, handle_strut_partial_change},
{0, UINT_MAX, handle_window_type},
{0, UINT_MAX, handle_i3_floating},
{0, 128, handle_machine_change},
{0, 5 * sizeof(uint64_t), handle_motif_hints_change}};
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))

Expand All @@ -1219,7 +1230,8 @@ void property_handlers_init(void) {
property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
property_handlers[9].atom = A__NET_WM_WINDOW_TYPE;
property_handlers[10].atom = A_I3_FLOATING_WINDOW;
property_handlers[11].atom = A__MOTIF_WM_HINTS;
property_handlers[11].atom = XCB_ATOM_WM_CLIENT_MACHINE;
property_handlers[12].atom = A__MOTIF_WM_HINTS;
}

static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
Expand Down
2 changes: 2 additions & 0 deletions src/ipc.c
Expand Up @@ -557,6 +557,7 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
DUMP_PROPERTY("class", class_class);
DUMP_PROPERTY("instance", class_instance);
DUMP_PROPERTY("window_role", role);
DUMP_PROPERTY("machine", machine);

if (con->window->name != NULL) {
ystr("title");
Expand Down Expand Up @@ -646,6 +647,7 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
DUMP_REGEX(instance);
DUMP_REGEX(window_role);
DUMP_REGEX(title);
DUMP_REGEX(machine);

#undef DUMP_REGEX
y(map_close);
Expand Down
3 changes: 3 additions & 0 deletions src/load_layout.c
Expand Up @@ -285,6 +285,9 @@ static int json_string(void *ctx, const unsigned char *val, size_t len) {
} else if (strcasecmp(last_key, "title") == 0) {
current_swallow->title = regex_new(sval);
swallow_is_empty = false;
} else if (strcasecmp(last_key, "machine") == 0) {
current_swallow->machine = regex_new(sval);
swallow_is_empty = false;
} else {
ELOG("swallow key %s unknown\n", last_key);
}
Expand Down
5 changes: 4 additions & 1 deletion src/manage.c
Expand Up @@ -116,7 +116,8 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
utf8_title_cookie, title_cookie,
class_cookie, leader_cookie, transient_cookie,
role_cookie, startup_id_cookie, wm_hints_cookie,
wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie, wm_desktop_cookie;
wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie, wm_desktop_cookie,
wm_machine_cookie;

geomc = xcb_get_geometry(conn, d);

Expand Down Expand Up @@ -189,6 +190,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
motif_wm_hints_cookie = GET_PROPERTY(A__MOTIF_WM_HINTS, 5 * sizeof(uint64_t));
wm_user_time_cookie = GET_PROPERTY(A__NET_WM_USER_TIME, UINT32_MAX);
wm_desktop_cookie = GET_PROPERTY(A__NET_WM_DESKTOP, UINT32_MAX);
wm_machine_cookie = GET_PROPERTY(XCB_ATOM_WM_CLIENT_MACHINE, UINT32_MAX);

i3Window *cwindow = scalloc(1, sizeof(i3Window));
cwindow->id = window;
Expand All @@ -211,6 +213,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
border_style_t motif_border_style = BS_NORMAL;
window_update_motif_hints(cwindow, xcb_get_property_reply(conn, motif_wm_hints_cookie, NULL), &motif_border_style);
window_update_normal_hints(cwindow, xcb_get_property_reply(conn, wm_normal_hints_cookie, NULL), geom);
window_update_machine(cwindow, xcb_get_property_reply(conn, wm_machine_cookie, NULL));
xcb_get_property_reply_t *type_reply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
xcb_get_property_reply_t *state_reply = xcb_get_property_reply(conn, state_cookie, NULL);

Expand Down
10 changes: 10 additions & 0 deletions src/match.c
Expand Up @@ -47,6 +47,7 @@ bool match_is_empty(Match *match) {
match->instance == NULL &&
match->window_role == NULL &&
match->workspace == NULL &&
match->machine == NULL &&
match->urgent == U_DONTCHECK &&
match->id == XCB_NONE &&
match->window_type == UINT32_MAX &&
Expand Down Expand Up @@ -130,6 +131,8 @@ bool match_matches_window(Match *match, i3Window *window) {
}
}

CHECK_WINDOW_FIELD(machine, machine, str);

Con *con = NULL;
if (match->urgent == U_LATEST) {
/* if the window isn't urgent, no sense in searching */
Expand Down Expand Up @@ -273,6 +276,7 @@ void match_free(Match *match) {
regex_free(match->mark);
regex_free(match->window_role);
regex_free(match->workspace);
regex_free(match->machine);
}

/*
Expand Down Expand Up @@ -390,6 +394,12 @@ void match_parse_property(Match *match, const char *ctype, const char *cvalue) {
return;
}

if (strcmp(ctype, "machine") == 0) {
regex_free(match->machine);
match->machine = regex_new(cvalue);
return;
}

if (strcmp(ctype, "tiling") == 0) {
match->window_mode = WM_TILING;
return;
Expand Down
1 change: 1 addition & 0 deletions src/restore_layout.c
Expand Up @@ -153,6 +153,7 @@ static void update_placeholder_contents(placeholder_state *state) {
APPEND_REGEX(instance);
APPEND_REGEX(window_role);
APPEND_REGEX(title);
APPEND_REGEX(machine);

if (serialized == NULL) {
DLOG("This swallows specification is not serializable?!\n");
Expand Down
18 changes: 18 additions & 0 deletions src/window.c
Expand Up @@ -466,3 +466,21 @@ void window_update_motif_hints(i3Window *win, xcb_get_property_reply_t *prop, bo
#undef MWM_DECOR_BORDER
#undef MWM_DECOR_TITLE
}

/*
* Updates the WM_CLIENT_MACHINE
*
*/
void window_update_machine(i3Window *win, xcb_get_property_reply_t *prop) {
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
DLOG("WM_CLIENT_MACHINE not set.\n");
FREE(prop);
return;
}

FREE(win->machine);
win->machine = sstrndup((char *)xcb_get_property_value(prop), xcb_get_property_value_length(prop));
LOG("WM_CLIENT_MACHINE changed to \"%s\"\n", win->machine);

free(prop);
}

0 comments on commit 32c10a1

Please sign in to comment.