]> git.sur5r.net Git - i3/i3/commitdiff
Make fullscreen windows open on the output which is indicated by their geometry
authorwentasah <sojkam1@fel.cvut.cz>
Wed, 6 Apr 2016 19:19:10 +0000 (21:19 +0200)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Wed, 6 Apr 2016 19:19:10 +0000 (21:19 +0200)
With this change, multi-monitor presentations (e.g. as implemented by
LibreOffice Impress) work out of the box. Previously, one had to move
the presentation windows to the right outputs oneself.

include/con.h
include/randr.h
src/con.c
src/manage.c
src/randr.c
testcases/t/531-fullscreen-on-given-output.t [new file with mode: 0644]

index 5b48120b04ead14df78ff73a0905552a102c6d13..130dd83b250643f4a90a9ebff83f71a5ed5488fa 100644 (file)
@@ -268,6 +268,13 @@ void con_disable_fullscreen(Con *con);
 void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates,
                            bool dont_warp, bool ignore_focus);
 
+/**
+ * Moves the given container to the currently focused container on the
+ * visible workspace on the given output.
+ *
+ */
+void con_move_to_output(Con *con, Output *output);
+
 /**
  * Moves the given container to the given mark.
  *
index 998f0d597e8839237da1885375fec363a898abbc..8d4b4defa42e46919eb24435dba89e83bebd6849 100644 (file)
@@ -79,6 +79,13 @@ Output *get_output_by_name(const char *name);
  */
 Output *get_output_containing(unsigned int x, unsigned int y);
 
+/**
+ * Returns the active output which spans exactly the area specified by
+ * rect or NULL if there is no output like this.
+ *
+ */
+Output *get_output_with_dimensions(Rect rect);
+
 /*
  * In contained_by_output, we check if any active output contains part of the container.
  * We do this by checking if the output rect is intersected by the Rect.
index cd17f9e51e0c035754b3b1580a8b4b276e0c071b..17cdd2d6c42c71ab83d47eab2c6bf0fcb2c600f9 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -1157,6 +1157,19 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
     _con_move_to_con(con, target, true, fix_coordinates, dont_warp, ignore_focus);
 }
 
+/*
+ * Moves the given container to the currently focused container on the
+ * visible workspace on the given output.
+ *
+ */
+void con_move_to_output(Con *con, Output *output) {
+    Con *ws = NULL;
+    GREP_FIRST(ws, output_get_content(output->con), workspace_is_visible(child));
+    assert(ws != NULL);
+    DLOG("Moving con %p to output %s\n", con, output->name);
+    con_move_to_workspace(con, ws, false, false, false);
+}
+
 /*
  * Returns the orientation of the given container (for stacked containers,
  * vertical orientation is used regardless of the actual orientation of the
index 93272f1b7e049a5ead27139372a83ae4345efa26..81a62ab8dab7c9a5a185ac5f2833a834a9b9a4af 100644 (file)
@@ -359,8 +359,16 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
     if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_FULLSCREEN)) {
         /* If this window is already fullscreen (after restarting!), skip
          * toggling fullscreen, that would drop it out of fullscreen mode. */
-        if (fs != nc)
+        if (fs != nc) {
+            Output *output = get_output_with_dimensions((Rect){geom->x, geom->y, geom->width, geom->height});
+            /* If the requested window geometry spans the whole area
+             * of an output, move the window to that output. This is
+             * needed e.g. for LibreOffice Impress multi-monitor
+             * presentations to work out of the box. */
+            if (output != NULL)
+                con_move_to_output(nc, output);
             con_toggle_fullscreen(nc, CF_OUTPUT);
+        }
         fs = NULL;
     }
 
index f0234c5c4bf26fb1863ce41ecda2d5ddc0ecf8c5..6aed40cff4c9114b232520bf16359877d69fe444 100644 (file)
@@ -108,6 +108,27 @@ Output *get_output_containing(unsigned int x, unsigned int y) {
     return NULL;
 }
 
+/*
+ * Returns the active output which spans exactly the area specified by
+ * rect or NULL if there is no output like this.
+ *
+ */
+Output *get_output_with_dimensions(Rect rect) {
+    Output *output;
+    TAILQ_FOREACH(output, &outputs, outputs) {
+        if (!output->active)
+            continue;
+        DLOG("comparing x=%d y=%d %dx%d with x=%d and y=%d %dx%d\n",
+             rect.x, rect.y, rect.width, rect.height,
+             output->rect.x, output->rect.y, output->rect.width, output->rect.height);
+        if (rect.x == output->rect.x && rect.width == output->rect.width &&
+            rect.y == output->rect.y && rect.height == output->rect.height)
+            return output;
+    }
+
+    return NULL;
+}
+
 /*
  * In contained_by_output, we check if any active output contains part of the container.
  * We do this by checking if the output rect is intersected by the Rect.
diff --git a/testcases/t/531-fullscreen-on-given-output.t b/testcases/t/531-fullscreen-on-given-output.t
new file mode 100644 (file)
index 0000000..fd32865
--- /dev/null
@@ -0,0 +1,75 @@
+#!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 that fullscreen windows appear on the output indicated by
+# their geometry
+use i3test i3_autostart => 0;
+use List::Util qw(first);
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+fake-outputs 1024x768+0+0,1024x768+1024+0
+EOT
+
+my $pid = launch_with_config($config);
+
+# Helper functions
+sub fullscreen($) {
+    my ($window) = @_;
+    $window->fullscreen(1);
+}
+
+sub find_window {
+    my ($nodes, $id) = @_;
+
+    foreach (@{$nodes}) {
+       return $_ if ($_->{window} // 0) == $id;
+       my $node = find_window($_->{nodes}, $id);
+       return $node if $node;
+    };
+    return undef;
+}
+
+# Create two fullscreen windows, each on different output
+my $orig_rect1 = X11::XCB::Rect->new(x => 0, y => 0, width => 1024, height => 768);
+my $orig_rect2 = X11::XCB::Rect->new(x => 1024, y => 0, width => 1024, height => 768);
+
+my $win_on_first_output = open_window(rect => $orig_rect1,
+                                     before_map => \&fullscreen);
+
+my $win_on_second_output = open_window(rect => $orig_rect2,
+                                      before_map => \&fullscreen);
+
+sync_with_i3;
+
+# Check that the windows are on the correct output
+is_deeply(scalar $win_on_first_output->rect, $orig_rect1, "first window spans the first output");
+is_deeply(scalar $win_on_second_output->rect, $orig_rect2, "second window spans the sencond output");
+
+# Check that both windows remained fullscreen
+my $tree = i3(get_socket_path())->get_tree->recv;
+
+my $node1 = find_window($tree->{nodes}, $win_on_first_output->{id});
+my $node2 = find_window($tree->{nodes}, $win_on_second_output->{id});
+
+is($node1->{fullscreen_mode}, 1, "first window is fullscreen");
+is($node2->{fullscreen_mode}, 1, "second window is fullscreen");
+
+exit_gracefully($pid);
+
+done_testing;