Extend tiling/floating criteria with optional auto/user values (#4006)

The default `tiling` and `floating` behavior is preserved and matches
both cases.

Adds a new handler to `remanage_window` on A_I3_FLOATING_WINDOW change.

Mainly in order to `run_assignments`, this makes `for_window [floating]`
directives to work for windows which where initially opened as tiling.
Now, when floating is enabled, `for_window` will trigger correctly. Same
applies to `for_window [tiling]`.

The obvious solution of `run_assignments` after
`floating_{enable,disable}` doesn't work because `run_assignments`
modifies the parser state in src/assignments.c:51.

Fixes #3588

Co-Authored-By: Michael Stapelberg <michael@stapelberg.de>
This commit is contained in:
Orestis Floros
2020-04-12 13:49:08 +02:00
committed by GitHub
parent e7191af8b3
commit ae757c6848
9 changed files with 216 additions and 26 deletions

View File

@ -842,6 +842,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
DLOG("The window was requested to be visible on all workspaces, making it sticky and floating.\n");
floating_enable(con, false);
con->floating = FLOATING_AUTO_ON;
con->sticky = true;
ewmh_update_sticky(con->window->id, true);
@ -1156,6 +1157,25 @@ static bool handle_strut_partial_change(Con *con, xcb_get_property_reply_t *prop
return true;
}
/*
* Handles the _I3_FLOATING_WINDOW property to properly run assignments for
* floating window changes.
*
* This is needed to correctly run the assignments after changes in floating
* windows which are triggered by user commands (floating enable | disable). In
* that case, we can't call run_assignments because it will modify the parser
* state when it needs to parse the user-specified action, breaking the parser
* state for the original command.
*
*/
static bool handle_i3_floating(Con *con, xcb_get_property_reply_t *prop) {
DLOG("floating change for con %p\n", con);
remanage_window(con);
return true;
}
/* Returns false if the event could not be processed (e.g. the window could not
* be found), true otherwise */
typedef bool (*cb_property_handler_t)(Con *con, xcb_get_property_reply_t *property);
@ -1177,6 +1197,7 @@ static struct property_handler_t property_handlers[] = {
{0, 128, handle_class_change},
{0, UINT_MAX, handle_strut_partial_change},
{0, UINT_MAX, handle_window_type},
{0, UINT_MAX, handle_i3_floating},
{0, 5 * sizeof(uint64_t), handle_motif_hints_change}};
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
@ -1198,7 +1219,8 @@ void property_handlers_init(void) {
property_handlers[7].atom = XCB_ATOM_WM_CLASS;
property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
property_handlers[9].atom = A__NET_WM_WINDOW_TYPE;
property_handlers[10].atom = A__MOTIF_WM_HINTS;
property_handlers[10].atom = A_I3_FLOATING_WINDOW;
property_handlers[11].atom = A__MOTIF_WM_HINTS;
}
static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {

View File

@ -538,6 +538,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
bool automatic_border = (motif_border_style == BS_NORMAL);
floating_enable(nc, automatic_border);
nc->floating = FLOATING_AUTO_ON;
}
/* explicitly set the border width to the default */

View File

@ -215,15 +215,43 @@ bool match_matches_window(Match *match, i3Window *window) {
}
if (match->window_mode != WM_ANY) {
if ((con = con_by_window_id(window->id)) == NULL)
if ((con = con_by_window_id(window->id)) == NULL) {
return false;
}
const bool floating = (con_inside_floating(con) != NULL);
if ((match->window_mode == WM_TILING && floating) ||
(match->window_mode == WM_FLOATING && !floating)) {
LOG("window_mode does not match\n");
return false;
switch (match->window_mode) {
case WM_TILING_AUTO:
if (con->floating != FLOATING_AUTO_OFF) {
return false;
}
break;
case WM_TILING_USER:
if (con->floating != FLOATING_USER_OFF) {
return false;
}
break;
case WM_TILING:
if (con_inside_floating(con) != NULL) {
return false;
}
break;
case WM_FLOATING_AUTO:
if (con->floating != FLOATING_AUTO_ON) {
return false;
}
break;
case WM_FLOATING_USER:
if (con->floating != FLOATING_USER_ON) {
return false;
}
break;
case WM_FLOATING:
if (con_inside_floating(con) == NULL) {
return false;
}
break;
case WM_ANY:
assert(false);
}
LOG("window_mode matches\n");
@ -367,10 +395,38 @@ void match_parse_property(Match *match, const char *ctype, const char *cvalue) {
return;
}
if (strcmp(ctype, "tiling_from") == 0 &&
cvalue != NULL &&
strcmp(cvalue, "auto") == 0) {
match->window_mode = WM_TILING_AUTO;
return;
}
if (strcmp(ctype, "tiling_from") == 0 &&
cvalue != NULL &&
strcmp(cvalue, "user") == 0) {
match->window_mode = WM_TILING_USER;
return;
}
if (strcmp(ctype, "floating") == 0) {
match->window_mode = WM_FLOATING;
return;
}
if (strcmp(ctype, "floating_from") == 0 &&
cvalue != NULL &&
strcmp(cvalue, "auto") == 0) {
match->window_mode = WM_FLOATING_AUTO;
return;
}
if (strcmp(ctype, "floating_from") == 0 &&
cvalue != NULL &&
strcmp(cvalue, "user") == 0) {
match->window_mode = WM_FLOATING_USER;
return;
}
ELOG("Unknown criterion: %s\n", ctype);
}