From 20aa8ee67dc528299dbc8735220a1c081c7ff9f6 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 25 Jan 2019 08:29:21 +1000 Subject: [PATCH] Implement fullscreen global --- include/sway/tree/container.h | 18 +++- include/sway/tree/root.h | 2 + sway/commands/focus.c | 26 ++--- sway/commands/fullscreen.c | 34 +++++-- sway/commands/move.c | 44 +++++---- sway/commands/split.c | 6 +- sway/commands/swap.c | 27 ++++-- sway/commands/workspace.c | 5 + sway/desktop/output.c | 30 ++++-- sway/desktop/render.c | 10 +- sway/desktop/transaction.c | 2 +- sway/desktop/xdg_shell.c | 2 +- sway/desktop/xdg_shell_v6.c | 2 +- sway/desktop/xwayland.c | 2 +- sway/input/cursor.c | 12 ++- sway/input/seat.c | 12 +++ sway/ipc-json.c | 4 +- sway/sway.5.scd | 5 +- sway/tree/arrange.c | 16 +++- sway/tree/container.c | 174 ++++++++++++++++++++++++---------- sway/tree/root.c | 5 +- sway/tree/view.c | 26 +++-- 22 files changed, 332 insertions(+), 132 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 9a432cb2..f0d0b3ce 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -25,6 +25,12 @@ enum sway_container_border { B_CSD, }; +enum sway_fullscreen_mode { + FULLSCREEN_NONE, + FULLSCREEN_WORKSPACE, + FULLSCREEN_GLOBAL, +}; + struct sway_root; struct sway_output; struct sway_workspace; @@ -38,7 +44,7 @@ struct sway_container_state { double x, y; double width, height; - bool is_fullscreen; + enum sway_fullscreen_mode fullscreen_mode; struct sway_workspace *workspace; struct sway_container *parent; @@ -85,7 +91,7 @@ struct sway_container { double content_x, content_y; int content_width, content_height; - bool is_fullscreen; + enum sway_fullscreen_mode fullscreen_mode; enum sway_container_border border; @@ -249,7 +255,13 @@ bool container_has_urgent_child(struct sway_container *container); */ void container_end_mouse_operation(struct sway_container *container); -void container_set_fullscreen(struct sway_container *container, bool enable); +void container_set_fullscreen(struct sway_container *con, + enum sway_fullscreen_mode mode); + +/** + * Convenience function. + */ +void container_fullscreen_disable(struct sway_container *con); /** * Return true if the container is floating, or a child of a floating split diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index 8f4deaa7..9ff45eb5 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -35,6 +35,8 @@ struct sway_root { // For when there's no connected outputs struct sway_output *noop_output; + struct sway_container *fullscreen_global; + struct { struct wl_signal new_node; } events; diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 0622f2e8..87fe6cf3 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -89,19 +89,23 @@ static struct sway_node *get_node_in_output_direction( static struct sway_node *node_get_in_direction(struct sway_container *container, struct sway_seat *seat, enum wlr_direction dir) { - if (container->is_fullscreen) { - // Fullscreen container with a direction - go straight to outputs - struct sway_output *output = container->workspace->output; - struct sway_output *new_output = output_get_in_direction(output, dir); - if (!new_output) { - return NULL; - } - return get_node_in_output_direction(new_output, dir); - } - struct sway_container *wrap_candidate = NULL; struct sway_container *current = container; while (current) { + if (current->fullscreen_mode == FULLSCREEN_WORKSPACE) { + // Fullscreen container with a direction - go straight to outputs + struct sway_output *output = current->workspace->output; + struct sway_output *new_output = + output_get_in_direction(output, dir); + if (!new_output) { + return NULL; + } + return get_node_in_output_direction(new_output, dir); + } + if (current->fullscreen_mode == FULLSCREEN_GLOBAL) { + return NULL; + } + bool can_move = false; int desired; int idx = container_sibling_index(current); @@ -227,7 +231,7 @@ static struct cmd_results *focus_output(struct sway_seat *seat, static struct cmd_results *focus_parent(void) { struct sway_seat *seat = config->handler_context.seat; struct sway_container *con = config->handler_context.container; - if (!con || con->is_fullscreen) { + if (!con || con->fullscreen_mode) { return cmd_results_new(CMD_SUCCESS, NULL); } struct sway_node *parent = node_get_parent(&con->node); diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 920b9bd0..52248ce4 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c @@ -1,3 +1,4 @@ +#include #include "log.h" #include "sway/commands.h" #include "sway/config.h" @@ -7,9 +8,10 @@ #include "sway/tree/workspace.h" #include "util.h" +// fullscreen [enable|disable|toggle] [global] struct cmd_results *cmd_fullscreen(int argc, char **argv) { struct cmd_results *error = NULL; - if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_MOST, 1))) { + if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_MOST, 2))) { return error; } if (!root->outputs->length) { @@ -23,20 +25,38 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, "Can't fullscreen an empty workspace"); } - if (node->type == N_WORKSPACE) { + + bool is_fullscreen = container && + container->fullscreen_mode != FULLSCREEN_NONE; + bool global = false; + bool enable = !is_fullscreen; + + if (argc >= 1) { + if (strcasecmp(argv[0], "global") == 0) { + global = true; + } else { + enable = parse_boolean(argv[0], is_fullscreen); + } + } + + if (argc >= 2) { + global = strcasecmp(argv[1], "global") == 0; + } + + if (enable && node->type == N_WORKSPACE) { // Wrap the workspace's children in a container so we can fullscreen it container = workspace_wrap_children(workspace); workspace->layout = L_HORIZ; seat_set_focus_container(config->handler_context.seat, container); } - bool enable = !container->is_fullscreen; - if (argc) { - enable = parse_boolean(argv[0], container->is_fullscreen); + enum sway_fullscreen_mode mode = FULLSCREEN_NONE; + if (enable) { + mode = global ? FULLSCREEN_GLOBAL : FULLSCREEN_WORKSPACE; } - container_set_fullscreen(container, enable); - arrange_workspace(workspace); + container_set_fullscreen(container, mode); + arrange_root(); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/move.c b/sway/commands/move.c index acb5f44f..aa06b168 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -191,7 +191,7 @@ static void container_move_to_workspace(struct sway_container *container, workspace_add_floating(workspace, container); container_handle_fullscreen_reparent(container); // If changing output, center it within the workspace - if (old_output != workspace->output && !container->is_fullscreen) { + if (old_output != workspace->output && !container->fullscreen_mode) { container_floating_move_to_center(container); } } else { @@ -276,7 +276,7 @@ static void workspace_rejigger(struct sway_workspace *ws, static bool container_move_in_direction(struct sway_container *container, enum wlr_direction move_dir) { // If moving a fullscreen view, only consider outputs - if (container->is_fullscreen) { + if (container->fullscreen_mode == FULLSCREEN_WORKSPACE) { struct sway_output *new_output = output_get_in_direction(container->workspace->output, move_dir); if (!new_output) { @@ -286,6 +286,9 @@ static bool container_move_in_direction(struct sway_container *container, container_move_to_workspace(container, ws); return true; } + if (container->fullscreen_mode == FULLSCREEN_GLOBAL) { + return false; + } // If container is in a split container by itself, move out of the split if (container->parent) { @@ -309,13 +312,19 @@ static bool container_move_in_direction(struct sway_container *container, int index = list_find(siblings, current); int desired = index + offs; + // Don't allow containers to move out of their + // fullscreen or floating parent + if (current->fullscreen_mode || container_is_floating(current)) { + return false; + } + if (is_parallel(layout, move_dir)) { if (desired == -1 || desired == siblings->length) { if (current->parent == container->parent) { current = current->parent; continue; } else { - // Special case + // Reparenting if (current->parent) { container_insert_child(current->parent, container, index + (offs < 0 ? 0 : 1)); @@ -334,13 +343,6 @@ static bool container_move_in_direction(struct sway_container *container, } current = current->parent; - - // Don't allow containers to move out of their - // fullscreen or floating parent - if (current && - (current->is_fullscreen || container_is_floating(current))) { - return false; - } } // Maybe rejigger the workspace @@ -563,10 +565,14 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { } // arrange windows - if (old_ws && !old_ws->node.destroying) { - arrange_workspace(old_ws); + if (root->fullscreen_global) { + arrange_root(); + } else { + if (old_ws && !old_ws->node.destroying) { + arrange_workspace(old_ws); + } + arrange_node(node_get_parent(destination)); } - arrange_node(node_get_parent(destination)); return cmd_results_new(CMD_SUCCESS, NULL); } @@ -658,7 +664,7 @@ static struct cmd_results *cmd_move_in_direction( "Cannot move a hidden scratchpad container"); } if (container_is_floating(container)) { - if (container->is_fullscreen) { + if (container->fullscreen_mode) { return cmd_results_new(CMD_FAILURE, "Cannot move fullscreen floating container"); } @@ -690,9 +696,13 @@ static struct cmd_results *cmd_move_in_direction( struct sway_workspace *new_ws = container->workspace; - arrange_workspace(old_ws); - if (new_ws != old_ws) { - arrange_workspace(new_ws); + if (root->fullscreen_global) { + arrange_root(); + } else { + arrange_workspace(old_ws); + if (new_ws != old_ws) { + arrange_workspace(new_ws); + } } if (container->view) { diff --git a/sway/commands/split.c b/sway/commands/split.c index 06b7df5e..b7ab7b79 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c @@ -26,7 +26,11 @@ static struct cmd_results *do_split(int layout) { container_flatten(con->parent->parent); } - arrange_workspace(ws); + if (root->fullscreen_global) { + arrange_root(); + } else { + arrange_workspace(ws); + } return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/swap.c b/sway/commands/swap.c index 0d8d1116..0e2c2d10 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -77,6 +77,11 @@ static void swap_focus(struct sway_container *con1, } else { seat_set_focus_container(seat, focus); } + + if (root->fullscreen_global) { + seat_set_focus(seat, + seat_get_focus_inactive(seat, &root->fullscreen_global->node)); + } } static void container_swap(struct sway_container *con1, @@ -98,13 +103,13 @@ static void container_swap(struct sway_container *con1, sway_log(SWAY_DEBUG, "Swapping containers %zu and %zu", con1->node.id, con2->node.id); - bool fs1 = con1->is_fullscreen; - bool fs2 = con2->is_fullscreen; + enum sway_fullscreen_mode fs1 = con1->fullscreen_mode; + enum sway_fullscreen_mode fs2 = con2->fullscreen_mode; if (fs1) { - container_set_fullscreen(con1, false); + container_fullscreen_disable(con1); } if (fs2) { - container_set_fullscreen(con2, false); + container_fullscreen_disable(con2); } struct sway_seat *seat = config->handler_context.seat; @@ -136,10 +141,10 @@ static void container_swap(struct sway_container *con1, } if (fs1) { - container_set_fullscreen(con2, true); + container_set_fullscreen(con2, fs1); } if (fs2) { - container_set_fullscreen(con1, true); + container_set_fullscreen(con1, fs2); } } @@ -220,9 +225,13 @@ struct cmd_results *cmd_swap(int argc, char **argv) { container_swap(current, other); - arrange_node(node_get_parent(¤t->node)); - if (node_get_parent(&other->node) != node_get_parent(¤t->node)) { - arrange_node(node_get_parent(&other->node)); + if (root->fullscreen_global) { + arrange_root(); + } else { + arrange_node(node_get_parent(¤t->node)); + if (node_get_parent(&other->node) != node_get_parent(¤t->node)) { + arrange_node(node_get_parent(&other->node)); + } } return cmd_results_new(CMD_SUCCESS, NULL); diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 6bfca506..c5d6435a 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -168,6 +168,11 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { "Can't run this command while there's no outputs connected."); } + if (root->fullscreen_global) { + return cmd_results_new(CMD_FAILURE, "workspace", + "Can't switch workspaces while fullscreen global"); + } + bool no_auto_back_and_forth = false; while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { no_auto_back_and_forth = true; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index f18a118f..b5f164cb 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -251,17 +251,27 @@ static void output_for_each_surface(struct sway_output *output, }; struct sway_workspace *workspace = output_get_active_workspace(output); - if (workspace->current.fullscreen) { - for_each_surface_container_iterator( - workspace->current.fullscreen, &data); - container_for_each_child(workspace->current.fullscreen, + struct sway_container *fullscreen_con = root->fullscreen_global; + if (fullscreen_con && fullscreen_con->scratchpad && + !fullscreen_con->workspace) { + fullscreen_con = NULL; + } + if (!fullscreen_con) { + fullscreen_con = workspace->current.fullscreen; + } + if (fullscreen_con) { + for_each_surface_container_iterator(fullscreen_con, &data); + container_for_each_child(fullscreen_con, for_each_surface_container_iterator, &data); - for (int i = 0; i < workspace->current.floating->length; ++i) { - struct sway_container *floater = - workspace->current.floating->items[i]; - if (container_is_transient_for(floater, - workspace->current.fullscreen)) { - for_each_surface_container_iterator(floater, &data); + + // TODO: Show transient containers for fullscreen global + if (fullscreen_con == workspace->current.fullscreen) { + for (int i = 0; i < workspace->current.floating->length; ++i) { + struct sway_container *floater = + workspace->current.floating->items[i]; + if (container_is_transient_for(floater, fullscreen_con)) { + for_each_surface_container_iterator(floater, &data); + } } } #if HAVE_XWAYLAND diff --git a/sway/desktop/render.c b/sway/desktop/render.c index a38c6a07..fa27500e 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -985,7 +985,15 @@ void output_render(struct sway_output *output, struct timespec *when, goto render_overlay; } - struct sway_container *fullscreen_con = workspace->current.fullscreen; + struct sway_container *fullscreen_con = root->fullscreen_global; + if (fullscreen_con && fullscreen_con->scratchpad && + !fullscreen_con->workspace) { + fullscreen_con = NULL; + } + if (!fullscreen_con) { + fullscreen_con = workspace->current.fullscreen; + } + if (fullscreen_con) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 55cf1c5e..b06ac9cc 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -134,7 +134,7 @@ static void copy_container_state(struct sway_container *container, state->y = container->y; state->width = container->width; state->height = container->height; - state->is_fullscreen = container->is_fullscreen; + state->fullscreen_mode = container->fullscreen_mode; state->parent = container->parent; state->workspace = container->workspace; state->border = container->border; diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index e2c614b3..007b0a94 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -349,7 +349,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) container_set_fullscreen(view->container, e->fullscreen); - arrange_workspace(view->container->workspace); + arrange_root(); transaction_commit_dirty(); } diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index f11c00b1..386e350e 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -342,7 +342,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) container_set_fullscreen(view->container, e->fullscreen); - arrange_workspace(view->container->workspace); + arrange_root(); transaction_commit_dirty(); } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 4ea661f8..d9e1b0a9 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -453,7 +453,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) } container_set_fullscreen(view->container, xsurface->fullscreen); - arrange_workspace(view->container->workspace); + arrange_root(); transaction_commit_dirty(); } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index bf9bf2da..4b2d99e6 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -90,6 +90,16 @@ struct sway_node *node_at_coords( double ox = lx, oy = ly; wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy); + if (root->fullscreen_global) { + // Try fullscreen container + struct sway_container *con = tiling_container_at( + &root->fullscreen_global->node, lx, ly, surface, sx, sy); + if (con) { + return &con->node; + } + return NULL; + } + // find the focused workspace on the output for this seat struct sway_workspace *ws = output_get_active_workspace(output); @@ -659,7 +669,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, // Handle moving a tiling container if (config->tiling_drag && (mod_pressed || on_titlebar) && state == WLR_BUTTON_PRESSED && !is_floating_or_child && - cont && !cont->is_fullscreen) { + cont && cont->fullscreen_mode == FULLSCREEN_NONE) { struct sway_container *focus = seat_get_focused_container(seat); bool focused = focus == cont || container_has_ancestor(focus, cont); if (on_titlebar && !focused) { diff --git a/sway/input/seat.c b/sway/input/seat.c index fd5eda2d..f216810b 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -753,6 +753,18 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { return; } } + // Deny setting focus to a workspace node when using fullscreen global + if (root->fullscreen_global && !container && new_workspace) { + return; + } + // Deny setting focus to a view which is hidden by a fullscreen global + if (root->fullscreen_global && container != root->fullscreen_global && + !container_has_ancestor(container, root->fullscreen_global)) { + // Unless it's a transient container + if (!container_is_transient_for(container, root->fullscreen_global)) { + return; + } + } struct sway_output *new_output = new_workspace->output; diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 778bf773..87d2c1ec 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -425,7 +425,9 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o view_is_urgent(c->view) : container_has_urgent_child(c); json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky)); - json_object_object_add(object, "fullscreen_mode", json_object_new_int(c->is_fullscreen)); + + json_object_object_add(object, "fullscreen_mode", + json_object_new_int(c->fullscreen_mode)); struct sway_node *parent = node_get_parent(&c->node); struct wlr_box parent_box = {0, 0, 0, 0}; diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 06bc0dbf..c2539804 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -134,9 +134,10 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). *focus* mode\_toggle Moves focus between the floating and tiled layers. -*fullscreen* [enable|disable|toggle] +*fullscreen* [enable|disable|toggle] [global] Makes focused view fullscreen, non-fullscreen, or the opposite of what it - is now. If no argument is given, it does the same as _toggle_. + is now. If no argument is given, it does the same as _toggle_. If _global_ + is specified, the view will be fullscreen across all outputs. *gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current set|plus|minus diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index f78d95a4..da372aa4 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -261,9 +261,19 @@ void arrange_root(void) { root->y = layout_box->y; root->width = layout_box->width; root->height = layout_box->height; - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - arrange_output(output); + + if (root->fullscreen_global) { + struct sway_container *fs = root->fullscreen_global; + fs->x = root->x; + fs->y = root->y; + fs->width = root->width; + fs->height = root->height; + arrange_container(fs); + } else { + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + arrange_output(output); + } } } diff --git a/sway/tree/container.c b/sway/tree/container.c index 0c0684c0..d8ad3bc0 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -92,7 +92,7 @@ void container_begin_destroy(struct sway_container *con) { } // The workspace must have the fullscreen pointer cleared so that the // seat code can find an appropriate new focus. - if (con->is_fullscreen && con->workspace) { + if (con->fullscreen_mode == FULLSCREEN_WORKSPACE && con->workspace) { con->workspace->fullscreen = NULL; } wl_signal_emit(&con->node.events.destroy, &con->node); @@ -106,6 +106,10 @@ void container_begin_destroy(struct sway_container *con) { root_scratchpad_remove_container(con); } + if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { + container_fullscreen_disable(con); + } + if (con->parent || con->workspace) { container_detach(con); } @@ -840,15 +844,15 @@ void container_floating_move_to_center(struct sway_container *con) { return; } struct sway_workspace *ws = con->workspace; - bool full = con->is_fullscreen; - if (full) { - container_set_fullscreen(con, false); + enum sway_fullscreen_mode fullscreen_mode = con->fullscreen_mode; + if (fullscreen_mode) { + container_fullscreen_disable(con); } double new_lx = ws->x + (ws->width - con->width) / 2; double new_ly = ws->y + (ws->height - con->height) / 2; container_floating_translate(con, new_lx - con->x, new_ly - con->y); - if (full) { - container_set_fullscreen(con, true); + if (fullscreen_mode) { + container_set_fullscreen(con, fullscreen_mode); } } @@ -877,59 +881,125 @@ static void set_fullscreen_iterator(struct sway_container *con, void *data) { } } -void container_set_fullscreen(struct sway_container *container, bool enable) { - if (container->is_fullscreen == enable) { +static void container_fullscreen_workspace(struct sway_container *con) { + if (!sway_assert(con->fullscreen_mode == FULLSCREEN_NONE, + "Expected a non-fullscreen container")) { return; } + bool enable = true; + set_fullscreen_iterator(con, &enable); + container_for_each_child(con, set_fullscreen_iterator, &enable); - struct sway_workspace *workspace = container->workspace; - if (enable && workspace->fullscreen) { - container_set_fullscreen(workspace->fullscreen, false); + con->workspace->fullscreen = con; + con->saved_x = con->x; + con->saved_y = con->y; + con->saved_width = con->width; + con->saved_height = con->height; + + struct sway_seat *seat; + struct sway_workspace *focus_ws; + wl_list_for_each(seat, &server.input->seats, link) { + focus_ws = seat_get_focused_workspace(seat); + if (focus_ws == con->workspace) { + seat_set_focus_container(seat, con); + } } - set_fullscreen_iterator(container, &enable); - container_for_each_child(container, set_fullscreen_iterator, &enable); + con->fullscreen_mode = FULLSCREEN_WORKSPACE; + container_end_mouse_operation(con); + ipc_event_window(con, "fullscreen_mode"); +} + +static void container_fullscreen_global(struct sway_container *con) { + if (!sway_assert(con->fullscreen_mode == FULLSCREEN_NONE, + "Expected a non-fullscreen container")) { + return; + } + bool enable = true; + set_fullscreen_iterator(con, &enable); + container_for_each_child(con, set_fullscreen_iterator, &enable); - container->is_fullscreen = enable; + root->fullscreen_global = con; + con->saved_x = con->x; + con->saved_y = con->y; + con->saved_width = con->width; + con->saved_height = con->height; - if (enable) { - workspace->fullscreen = container; - container->saved_x = container->x; - container->saved_y = container->y; - container->saved_width = container->width; - container->saved_height = container->height; - - struct sway_seat *seat; - struct sway_workspace *focus_ws; - wl_list_for_each(seat, &server.input->seats, link) { - focus_ws = seat_get_focused_workspace(seat); - if (focus_ws) { - if (focus_ws == workspace) { - seat_set_focus_container(seat, container); - } - } + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + struct sway_container *focus = seat_get_focused_container(seat); + if (focus && focus != con) { + seat_set_focus_container(seat, con); } - } else { - workspace->fullscreen = NULL; - if (container_is_floating(container)) { - container->x = container->saved_x; - container->y = container->saved_y; - container->width = container->saved_width; - container->height = container->saved_height; - struct sway_output *output = - container_floating_find_output(container); - if (workspace->output != output) { - container_floating_move_to_center(container); + } + + con->fullscreen_mode = FULLSCREEN_GLOBAL; + container_end_mouse_operation(con); + ipc_event_window(con, "fullscreen_mode"); +} + +void container_fullscreen_disable(struct sway_container *con) { + if (!sway_assert(con->fullscreen_mode != FULLSCREEN_NONE, + "Expected a fullscreen container")) { + return; + } + bool enable = false; + set_fullscreen_iterator(con, &enable); + container_for_each_child(con, set_fullscreen_iterator, &enable); + + if (container_is_floating(con)) { + con->x = con->saved_x; + con->y = con->saved_y; + } + con->width = con->saved_width; + con->height = con->saved_height; + + if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { + con->workspace->fullscreen = NULL; + if (container_is_floating(con)) { + struct sway_output *output = container_floating_find_output(con); + if (con->workspace->output != output) { + container_floating_move_to_center(con); } - } else { - container->width = container->saved_width; - container->height = container->saved_height; } + } else { + root->fullscreen_global = NULL; } - container_end_mouse_operation(container); + con->fullscreen_mode = FULLSCREEN_NONE; + container_end_mouse_operation(con); + ipc_event_window(con, "fullscreen_mode"); +} + +void container_set_fullscreen(struct sway_container *con, + enum sway_fullscreen_mode mode) { + if (con->fullscreen_mode == mode) { + return; + } - ipc_event_window(container, "fullscreen_mode"); + switch (mode) { + case FULLSCREEN_NONE: + container_fullscreen_disable(con); + break; + case FULLSCREEN_WORKSPACE: + if (root->fullscreen_global) { + container_fullscreen_disable(root->fullscreen_global); + } + if (con->workspace->fullscreen) { + container_fullscreen_disable(con->workspace->fullscreen); + } + container_fullscreen_workspace(con); + break; + case FULLSCREEN_GLOBAL: + if (root->fullscreen_global) { + container_fullscreen_disable(root->fullscreen_global); + } + if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { + container_fullscreen_disable(con); + } + container_fullscreen_global(con); + break; + } } bool container_is_floating_or_child(struct sway_container *container) { @@ -941,7 +1011,7 @@ bool container_is_floating_or_child(struct sway_container *container) { bool container_is_fullscreen_or_child(struct sway_container *container) { do { - if (container->is_fullscreen) { + if (container->fullscreen_mode) { return true; } container = container->parent; @@ -1111,12 +1181,12 @@ list_t *container_get_current_siblings(struct sway_container *container) { } void container_handle_fullscreen_reparent(struct sway_container *con) { - if (!con->is_fullscreen || !con->workspace || + if (con->fullscreen_mode != FULLSCREEN_WORKSPACE || !con->workspace || con->workspace->fullscreen == con) { return; } if (con->workspace->fullscreen) { - container_set_fullscreen(con->workspace->fullscreen, false); + container_fullscreen_disable(con->workspace->fullscreen); } con->workspace->fullscreen = con; @@ -1171,9 +1241,12 @@ void container_add_child(struct sway_container *parent, } void container_detach(struct sway_container *child) { - if (child->is_fullscreen) { + if (child->fullscreen_mode == FULLSCREEN_WORKSPACE) { child->workspace->fullscreen = NULL; } + if (child->fullscreen_mode == FULLSCREEN_GLOBAL) { + root->fullscreen_global = NULL; + } struct sway_container *old_parent = child->parent; struct sway_workspace *old_workspace = child->workspace; @@ -1387,4 +1460,3 @@ void container_raise_floating(struct sway_container *con) { node_set_dirty(&floater->workspace->node); } } - diff --git a/sway/tree/root.c b/sway/tree/root.c index 99cf91a7..476e47a3 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -101,7 +101,10 @@ void root_scratchpad_show(struct sway_container *con) { // If the current con or any of its parents are in fullscreen mode, we // first need to disable it before showing the scratchpad con. if (new_ws->fullscreen) { - container_set_fullscreen(new_ws->fullscreen, false); + container_fullscreen_disable(new_ws->fullscreen); + } + if (root->fullscreen_global) { + container_fullscreen_disable(root->fullscreen_global); } // Show the container diff --git a/sway/tree/view.c b/sway/tree/view.c index 8795e04f..561c6ef1 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -203,12 +203,18 @@ void view_autoconfigure(struct sway_view *view) { } struct sway_output *output = con->workspace->output; - if (con->is_fullscreen) { + if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { con->content_x = output->lx; con->content_y = output->ly; con->content_width = output->width; con->content_height = output->height; return; + } else if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { + con->content_x = root->x; + con->content_y = root->y; + con->content_width = root->width; + con->content_height = root->height; + return; } struct sway_workspace *ws = view->container->workspace; @@ -648,7 +654,10 @@ void view_unmap(struct sway_view *view) { workspace_consider_destroy(ws); } - if (ws && !ws->node.destroying) { + if (root->fullscreen_global) { + // Container may have been a child of the root fullscreen container + arrange_root(); + } else if (ws && !ws->node.destroying) { arrange_workspace(ws); workspace_detect_urgent(ws); } @@ -1008,14 +1017,11 @@ bool view_is_visible(struct sway_view *view) { con = con->parent; } // Check view isn't hidden by another fullscreen view - if (workspace->fullscreen && - !container_is_fullscreen_or_child(view->container)) { - // However, if we're transient for the fullscreen view and we allow - // "popups" during fullscreen then it might be visible - if (!container_is_transient_for(view->container, - workspace->fullscreen)) { - return false; - } + struct sway_container *fs = root->fullscreen_global ? + root->fullscreen_global : workspace->fullscreen; + if (fs && !container_is_fullscreen_or_child(view->container) && + !container_is_transient_for(view->container, fs)) { + return false; } return true; }