diff --git a/include/atoms_rest.xmacro b/include/atoms_rest.xmacro index 12cb63fd..d461dc08 100644 --- a/include/atoms_rest.xmacro +++ b/include/atoms_rest.xmacro @@ -13,6 +13,7 @@ xmacro(I3_CONFIG_PATH) xmacro(I3_SYNC) xmacro(I3_SHMLOG_PATH) xmacro(I3_PID) +xmacro(I3_FLOATING_WINDOW) xmacro(_NET_REQUEST_FRAME_EXTENTS) xmacro(_NET_FRAME_EXTENTS) xmacro(_MOTIF_WM_HINTS) diff --git a/src/floating.c b/src/floating.c index 8ac818ac..231577fd 100644 --- a/src/floating.c +++ b/src/floating.c @@ -29,6 +29,34 @@ static Rect total_outputs_dimensions(void) { return outputs_dimensions; } +/* + * Updates I3_FLOATING_WINDOW by either setting or removing it on the con and + * all its children. + * + */ +static void floating_set_hint_atom(Con *con, bool floating) { + if (!con_is_leaf(con)) { + Con *child; + TAILQ_FOREACH(child, &(con->nodes_head), nodes) { + floating_set_hint_atom(child, floating); + } + } + + if (con->window == NULL) { + return; + } + + if (floating) { + uint32_t val = 1; + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id, + A_I3_FLOATING_WINDOW, XCB_ATOM_CARDINAL, 32, 1, &val); + } else { + xcb_delete_property(conn, con->window->id, A_I3_FLOATING_WINDOW); + } + + xcb_flush(conn); +} + /** * Called when a floating window is created or resized. * This function resizes the window if its size is higher or lower than the @@ -260,19 +288,19 @@ void floating_enable(Con *con, bool automatic) { /* Check if we need to re-assign it to a different workspace because of its * coordinates and exit if that was done successfully. */ if (floating_maybe_reassign_ws(nc)) { - ipc_send_window_event("floating", con); - return; + goto done; } /* Sanitize coordinates: Check if they are on any output */ if (get_output_containing(nc->rect.x, nc->rect.y) != NULL) { - ipc_send_window_event("floating", con); - return; + goto done; } ELOG("No output found at destination coordinates, centering floating window on current ws\n"); floating_center(nc, ws->rect); +done: + floating_set_hint_atom(nc, true); ipc_send_window_event("floating", con); } @@ -318,6 +346,7 @@ void floating_disable(Con *con, bool automatic) { if (set_focus) con_focus(con); + floating_set_hint_atom(con, false); ipc_send_window_event("floating", con); } diff --git a/testcases/t/263-i3-floating-window-atom.t b/testcases/t/263-i3-floating-window-atom.t new file mode 100644 index 00000000..43b69ccb --- /dev/null +++ b/testcases/t/263-i3-floating-window-atom.t @@ -0,0 +1,70 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Tests for our proprietary atom I3_FLOATING_WINDOW to allow +# identifying floating windows. +# Ticket: #2223 +use i3test; +use X11::XCB qw(:all); + +my ($con); + +sub has_i3_floating_window { + sync_with_i3; + + my ($con) = @_; + my $cookie = $x->get_property( + 0, + $con->{id}, + $x->atom(name => 'I3_FLOATING_WINDOW')->id, + $x->atom(name => 'CARDINAL')->id, + 0, + 1 + ); + + my $reply = $x->get_property_reply($cookie->{sequence}); + return 0 if $reply->{length} != 1; + + return unpack("L", $reply->{value}); +} + +############################################################################### +# Toggling floating on a container adds / removes I3_FLOATING_WINDOW. +############################################################################### + +fresh_workspace; + +$con = open_window; +is(has_i3_floating_window($con), 0, 'I3_FLOATING_WINDOW is not set'); + +cmd 'floating enable'; +is(has_i3_floating_window($con), 1, 'I3_FLOATING_WINDOW is set'); + +cmd 'floating disable'; +is(has_i3_floating_window($con), 0, 'I3_FLOATING_WINDOW is not set'); + +############################################################################### +# A window that is floated when managed has I3_FLOATING_WINDOW set. +############################################################################### +# +fresh_workspace; + +$con = open_floating_window; +is(has_i3_floating_window($con), 1, 'I3_FLOATING_WINDOW is set'); + +############################################################################### + +done_testing;