From 52420cc24d61db8d22cf0d391f1f84b37bf087d5 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 16 Apr 2018 20:36:40 +1000 Subject: [PATCH 01/17] Implement fullscreen. --- include/sway/ipc-server.h | 1 + include/sway/tree/container.h | 4 ++++ include/sway/tree/view.h | 9 ++++++++ sway/commands.c | 1 + sway/commands/fullscreen.c | 40 +++++++++++++++++++++++++++++++++++ sway/desktop/output.c | 24 ++++++++++++++------- sway/desktop/xdg_shell_v6.c | 26 +++++++++++++++++++++++ sway/desktop/xwayland.c | 34 +++++++++++++++++++++++++++++ sway/input/seat.c | 14 ++++++++++++ sway/meson.build | 1 + sway/tree/layout.c | 18 ++++++++++++++++ sway/tree/view.c | 40 +++++++++++++++++++++++++++++++++++ 12 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 sway/commands/fullscreen.c diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index c3389fe85..dd16a175e 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -1,6 +1,7 @@ #ifndef _SWAY_IPC_SERVER_H #define _SWAY_IPC_SERVER_H #include +#include "sway/config.h" #include "sway/tree/container.h" #include "ipc.h" diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 2a8b8abaf..22bd72403 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -72,9 +72,13 @@ struct sway_container { // For C_OUTPUT, this is the output position in layout coordinates // For other types, this is the position in output-local coordinates double x, y; + double saved_x, saved_y; // does not include borders or gaps. double width, height; + // For C_WORKSPACE only + struct sway_view *fullscreen; + list_t *children; struct sway_container *parent; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index b51c54b53..73d5f6c7c 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -28,6 +28,7 @@ struct sway_view_impl { void (*configure)(struct sway_view *view, double ox, double oy, int width, int height); void (*set_activated)(struct sway_view *view, bool activated); + void (*set_fullscreen)(struct sway_view *view, bool fullscreen); void (*for_each_surface)(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data); void (*close)(struct sway_view *view); @@ -41,6 +42,8 @@ struct sway_view { struct sway_container *swayc; // NULL for unmanaged views struct wlr_surface *surface; // NULL for unmapped views int width, height; + int saved_width, saved_height; + bool is_fullscreen; union { struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; @@ -63,6 +66,7 @@ struct sway_xdg_shell_v6_view { struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; + struct wl_listener request_fullscreen; struct wl_listener new_popup; struct wl_listener map; struct wl_listener unmap; @@ -79,6 +83,7 @@ struct sway_xwayland_view { struct wl_listener request_resize; struct wl_listener request_maximize; struct wl_listener request_configure; + struct wl_listener request_fullscreen; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; @@ -93,6 +98,7 @@ struct sway_xwayland_unmanaged { int lx, ly; struct wl_listener request_configure; + struct wl_listener request_fullscreen; struct wl_listener commit; struct wl_listener map; struct wl_listener unmap; @@ -106,6 +112,7 @@ struct sway_wl_shell_view { struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; + struct wl_listener request_fullscreen; struct wl_listener destroy; int pending_width, pending_height; @@ -155,6 +162,8 @@ void view_configure(struct sway_view *view, double ox, double oy, int width, void view_set_activated(struct sway_view *view, bool activated); +void view_set_fullscreen(struct sway_view *view, bool fullscreen); + void view_close(struct sway_view *view); void view_damage(struct sway_view *view, bool whole); diff --git a/sway/commands.c b/sway/commands.c index 99f425245..8ddc033be 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -99,6 +99,7 @@ static struct cmd_handler handlers[] = { { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "focus_follows_mouse", cmd_focus_follows_mouse }, + { "fullscreen", cmd_fullscreen }, { "include", cmd_include }, { "input", cmd_input }, { "mode", cmd_mode }, diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c new file mode 100644 index 000000000..3e256282c --- /dev/null +++ b/sway/commands/fullscreen.c @@ -0,0 +1,40 @@ +#include +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" +#include "sway/tree/layout.h" + +// fullscreen toggle|enable|disable +struct cmd_results *cmd_fullscreen(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can only be used when sway is running."); + if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 1))) { + return error; + } + struct sway_container *container = + config->handler_context.current_container; + if (container->type != C_VIEW) { + return cmd_results_new(CMD_INVALID, "fullscreen", + "Only views can fullscreen"); + } + struct sway_view *view = container->sway_view; + bool wants_fullscreen; + + if (strcmp(argv[0], "enable") == 0) { + wants_fullscreen = true; + } else if (strcmp(argv[0], "disable") == 0) { + wants_fullscreen = false; + } else if (strcmp(argv[0], "toggle") == 0) { + wants_fullscreen = !view->is_fullscreen; + } else { + return cmd_results_new(CMD_INVALID, "fullscreen", + "Expected 'fullscreen '"); + } + + view_set_fullscreen(view, wants_fullscreen); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1b3143d0c..b86f20e8d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -273,17 +273,25 @@ static void render_output(struct sway_output *output, struct timespec *when, float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; wlr_renderer_clear(renderer, clear_color); - render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - struct sway_container *workspace = output_get_active_workspace(output); - render_container(output, workspace); - render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); + if (workspace->fullscreen) { + wlr_output_set_fullscreen_surface(wlr_output, + workspace->fullscreen->surface); + } else { + wlr_output_set_fullscreen_surface(wlr_output, NULL); + render_layer(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - // TODO: consider revising this when fullscreen windows are supported - render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + render_container(output, workspace); + + render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); + + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + render_layer(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + } renderer_end: if (root_container.sway_root->debug_tree) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index e4703040c..133b60c34 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -118,6 +118,14 @@ static void set_activated(struct sway_view *view, bool activated) { } } +static void set_fullscreen(struct sway_view *view, bool fullscreen) { + if (xdg_shell_v6_view_from_view(view) == NULL) { + return; + } + struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6; + wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen); +} + static void for_each_surface(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data) { if (xdg_shell_v6_view_from_view(view) == NULL) { @@ -146,6 +154,7 @@ static void destroy(struct sway_view *view) { wl_list_remove(&xdg_shell_v6_view->destroy.link); wl_list_remove(&xdg_shell_v6_view->map.link); wl_list_remove(&xdg_shell_v6_view->unmap.link); + wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link); free(xdg_shell_v6_view); } @@ -153,6 +162,7 @@ static const struct sway_view_impl view_impl = { .get_prop = get_prop, .configure = configure, .set_activated = set_activated, + .set_fullscreen = set_fullscreen, .for_each_surface = for_each_surface, .close = _close, .destroy = destroy, @@ -210,6 +220,18 @@ static void handle_destroy(struct wl_listener *listener, void *data) { view_destroy(&xdg_shell_v6_view->view); } +static void handle_request_fullscreen(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, request_fullscreen); + struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data; + + if (xdg_shell_v6_view->view.wlr_xdg_surface_v6->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + return; + } + + view_set_fullscreen(&xdg_shell_v6_view->view, e->fullscreen); +} + void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, xdg_shell_v6_surface); @@ -246,4 +268,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { xdg_shell_v6_view->destroy.notify = handle_destroy; wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_v6_view->destroy); + + xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen; + wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, + &xdg_shell_v6_view->request_fullscreen); } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 69166af07..716d88823 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -25,6 +25,15 @@ static void unmanaged_handle_request_configure(struct wl_listener *listener, ev->width, ev->height); } +static void unmanaged_handle_request_fullscreen(struct wl_listener *listener, + void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, request_fullscreen); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + view_set_fullscreen(view, xsurface->fullscreen); +} + static void unmanaged_handle_commit(struct wl_listener *listener, void *data) { struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, commit); @@ -106,6 +115,9 @@ static struct sway_xwayland_unmanaged *create_unmanaged( wl_signal_add(&xsurface->events.request_configure, &surface->request_configure); surface->request_configure.notify = unmanaged_handle_request_configure; + wl_signal_add(&xsurface->events.request_fullscreen, + &surface->request_fullscreen); + surface->request_fullscreen.notify = unmanaged_handle_request_fullscreen; wl_signal_add(&xsurface->events.map, &surface->map); surface->map.notify = unmanaged_handle_map; wl_signal_add(&xsurface->events.unmap, &surface->unmap); @@ -179,6 +191,14 @@ static void set_activated(struct sway_view *view, bool activated) { wlr_xwayland_surface_activate(surface, activated); } +static void set_fullscreen(struct sway_view *view, bool fullscreen) { + if (xwayland_view_from_view(view) == NULL) { + return; + } + struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; + wlr_xwayland_surface_set_fullscreen(surface, fullscreen); +} + static void _close(struct sway_view *view) { if (xwayland_view_from_view(view) == NULL) { return; @@ -193,6 +213,7 @@ static void destroy(struct sway_view *view) { } wl_list_remove(&xwayland_view->destroy.link); wl_list_remove(&xwayland_view->request_configure.link); + wl_list_remove(&xwayland_view->request_fullscreen.link); wl_list_remove(&xwayland_view->map.link); wl_list_remove(&xwayland_view->unmap.link); free(xwayland_view); @@ -202,6 +223,7 @@ static const struct sway_view_impl view_impl = { .get_prop = get_prop, .configure = configure, .set_activated = set_activated, + .set_fullscreen = set_fullscreen, .close = _close, .destroy = destroy, }; @@ -263,6 +285,14 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { ev->width, ev->height); } +static void handle_request_fullscreen(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, request_fullscreen); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + view_set_fullscreen(view, xsurface->fullscreen); +} + void handle_xwayland_surface(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, xwayland_surface); @@ -298,6 +328,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { &xwayland_view->request_configure); xwayland_view->request_configure.notify = handle_request_configure; + wl_signal_add(&xsurface->events.request_fullscreen, + &xwayland_view->request_fullscreen); + xwayland_view->request_fullscreen.notify = handle_request_fullscreen; + wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); xwayland_view->unmap.notify = handle_unmap; diff --git a/sway/input/seat.c b/sway/input/seat.c index 09927a1a1..f60c43b5d 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -448,6 +448,20 @@ void seat_set_focus_warp(struct sway_seat *seat, return; } + struct sway_container *last_workspace = last_focus; + if (last_workspace && last_workspace->type != C_WORKSPACE) { + last_workspace = container_parent(last_workspace, C_WORKSPACE); + } + struct sway_container *new_workspace = container; + if (new_workspace && new_workspace->type != C_WORKSPACE) { + new_workspace = container_parent(new_workspace, C_WORKSPACE); + } + + if (last_workspace == new_workspace && last_workspace->fullscreen + && !container->sway_view->is_fullscreen) { + return; + } + struct sway_container *last_output = last_focus; if (last_output && last_output->type != C_OUTPUT) { last_output = container_parent(last_output, C_OUTPUT); diff --git a/sway/meson.build b/sway/meson.build index 9e55e335f..0bbb8da15 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -34,6 +34,7 @@ sway_sources = files( 'commands/exec_always.c', 'commands/focus.c', 'commands/focus_follows_mouse.c', + 'commands/fullscreen.c', 'commands/kill.c', 'commands/opacity.c', 'commands/include.c', diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 0b6378223..ae6db4549 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -137,6 +137,21 @@ void container_move_to(struct sway_container *container, || container_has_anscestor(container, destination)) { return; } + + if (container->sway_view->is_fullscreen) { + struct sway_container *old_workspace = container; + if (old_workspace->type != C_WORKSPACE) { + old_workspace = container_parent(old_workspace, C_WORKSPACE); + } + struct sway_container *new_workspace = destination; + if (new_workspace->type != C_WORKSPACE) { + new_workspace = container_parent(new_workspace, C_WORKSPACE); + } + if (old_workspace != new_workspace) { + view_set_fullscreen(container->sway_view, false); + } + } + struct sway_container *old_parent = container_remove_child(container); container->width = container->height = 0; struct sway_container *new_parent; @@ -557,6 +572,9 @@ void arrange_windows(struct sway_container *container, return; case C_WORKSPACE: { + if (container->fullscreen) { + return; + } struct sway_container *output = container_parent(container, C_OUTPUT); struct wlr_box *area = &output->sway_output->usable_area; diff --git a/sway/tree/view.c b/sway/tree/view.c index 99b447209..b958233b4 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -2,6 +2,7 @@ #include #include #include "log.h" +#include "sway/ipc-server.h" #include "sway/output.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" @@ -73,7 +74,46 @@ void view_set_activated(struct sway_view *view, bool activated) { } } +void view_set_fullscreen(struct sway_view *view, bool fullscreen) { + if (view->is_fullscreen == fullscreen) { + return; + } + + struct sway_container *container = container_parent(view->swayc, C_OUTPUT); + struct sway_output *output = container->sway_output; + struct sway_container *workspace = container_parent(view->swayc, C_WORKSPACE); + + if (view->impl->set_fullscreen) { + view->impl->set_fullscreen(view, fullscreen); + } + + if (fullscreen) { + view->swayc->saved_x = view->swayc->x; + view->swayc->saved_y = view->swayc->y; + view->saved_width = view->width; + view->saved_height = view->height; + view_configure(view, 0, 0, output->wlr_output->width, output->wlr_output->height); + workspace->fullscreen = view; + } else { + view_configure(view, view->swayc->saved_x, view->swayc->saved_y, + view->saved_width, view->saved_height); + workspace->fullscreen = NULL; + } + + view->is_fullscreen = fullscreen; + output_damage_whole(output); + + arrange_windows(workspace, -1, -1); + + ipc_event_window(view->swayc, "fullscreen_mode"); +} + void view_close(struct sway_view *view) { + if (view->is_fullscreen) { + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + ws->fullscreen = NULL; + } + if (view->impl->close) { view->impl->close(view); } From bfd5834f4c1046c234ceaae212e65e045cd51460 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 17 Apr 2018 08:11:50 +1000 Subject: [PATCH 02/17] Feedback for fullscreen. --- include/sway/tree/container.h | 1 - include/sway/tree/view.h | 1 - sway/commands/fullscreen.c | 14 ++++---------- sway/desktop/output.c | 6 ++---- sway/desktop/xwayland.c | 12 ------------ sway/tree/layout.c | 2 +- sway/tree/view.c | 18 ++++++------------ 7 files changed, 13 insertions(+), 41 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 22bd72403..0283584b0 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -72,7 +72,6 @@ struct sway_container { // For C_OUTPUT, this is the output position in layout coordinates // For other types, this is the position in output-local coordinates double x, y; - double saved_x, saved_y; // does not include borders or gaps. double width, height; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 73d5f6c7c..9dfd171f1 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -42,7 +42,6 @@ struct sway_view { struct sway_container *swayc; // NULL for unmanaged views struct wlr_surface *surface; // NULL for unmapped views int width, height; - int saved_width, saved_height; bool is_fullscreen; union { diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 3e256282c..5a044aa85 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c @@ -8,12 +8,6 @@ // fullscreen toggle|enable|disable struct cmd_results *cmd_fullscreen(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can only be used when sway is running."); - if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 1))) { - return error; - } struct sway_container *container = config->handler_context.current_container; if (container->type != C_VIEW) { @@ -23,15 +17,15 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { struct sway_view *view = container->sway_view; bool wants_fullscreen; - if (strcmp(argv[0], "enable") == 0) { + if (argc == 0 || strcmp(argv[0], "toggle") == 0) { + wants_fullscreen = !view->is_fullscreen; + } else if (strcmp(argv[0], "enable") == 0) { wants_fullscreen = true; } else if (strcmp(argv[0], "disable") == 0) { wants_fullscreen = false; - } else if (strcmp(argv[0], "toggle") == 0) { - wants_fullscreen = !view->is_fullscreen; } else { return cmd_results_new(CMD_INVALID, "fullscreen", - "Expected 'fullscreen '"); + "Expected 'fullscreen' or fullscreen '"); } view_set_fullscreen(view, wants_fullscreen); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index b86f20e8d..dc2f63802 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -287,11 +287,9 @@ static void render_output(struct sway_output *output, struct timespec *when, render_container(output, workspace); render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); - - render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); } + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); renderer_end: if (root_container.sway_root->debug_tree) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 716d88823..963c5a0ed 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -25,15 +25,6 @@ static void unmanaged_handle_request_configure(struct wl_listener *listener, ev->width, ev->height); } -static void unmanaged_handle_request_fullscreen(struct wl_listener *listener, - void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, request_fullscreen); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - view_set_fullscreen(view, xsurface->fullscreen); -} - static void unmanaged_handle_commit(struct wl_listener *listener, void *data) { struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, commit); @@ -115,9 +106,6 @@ static struct sway_xwayland_unmanaged *create_unmanaged( wl_signal_add(&xsurface->events.request_configure, &surface->request_configure); surface->request_configure.notify = unmanaged_handle_request_configure; - wl_signal_add(&xsurface->events.request_fullscreen, - &surface->request_fullscreen); - surface->request_fullscreen.notify = unmanaged_handle_request_fullscreen; wl_signal_add(&xsurface->events.map, &surface->map); surface->map.notify = unmanaged_handle_map; wl_signal_add(&xsurface->events.unmap, &surface->unmap); diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ae6db4549..ad097f2e4 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -138,7 +138,7 @@ void container_move_to(struct sway_container *container, return; } - if (container->sway_view->is_fullscreen) { + if (container->type == C_VIEW && container->sway_view->is_fullscreen) { struct sway_container *old_workspace = container; if (old_workspace->type != C_WORKSPACE) { old_workspace = container_parent(old_workspace, C_WORKSPACE); diff --git a/sway/tree/view.c b/sway/tree/view.c index b958233b4..10285ad03 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -79,32 +79,26 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) { return; } - struct sway_container *container = container_parent(view->swayc, C_OUTPUT); - struct sway_output *output = container->sway_output; struct sway_container *workspace = container_parent(view->swayc, C_WORKSPACE); + struct sway_container *container = container_parent(workspace, C_OUTPUT); + struct sway_output *output = container->sway_output; if (view->impl->set_fullscreen) { view->impl->set_fullscreen(view, fullscreen); } + view->is_fullscreen = fullscreen; + if (fullscreen) { - view->swayc->saved_x = view->swayc->x; - view->swayc->saved_y = view->swayc->y; - view->saved_width = view->width; - view->saved_height = view->height; - view_configure(view, 0, 0, output->wlr_output->width, output->wlr_output->height); workspace->fullscreen = view; + view_configure(view, 0, 0, output->wlr_output->width, output->wlr_output->height); } else { - view_configure(view, view->swayc->saved_x, view->swayc->saved_y, - view->saved_width, view->saved_height); workspace->fullscreen = NULL; + arrange_windows(workspace, -1, -1); } - view->is_fullscreen = fullscreen; output_damage_whole(output); - arrange_windows(workspace, -1, -1); - ipc_event_window(view->swayc, "fullscreen_mode"); } From c685ef081f090d1e15428f55426e02f2274312d0 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 17 Apr 2018 09:31:34 +1000 Subject: [PATCH 03/17] Create sway_workspace struct. --- include/sway/tree/container.h | 5 ++--- include/sway/tree/workspace.h | 7 +++++++ sway/desktop/output.c | 5 +++-- sway/input/seat.c | 4 +++- sway/tree/container.c | 1 + sway/tree/layout.c | 18 +----------------- sway/tree/view.c | 7 ++++--- sway/tree/workspace.c | 7 +++++++ 8 files changed, 28 insertions(+), 26 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 0283584b0..6efda72fd 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -45,6 +45,7 @@ enum sway_container_border { struct sway_root; struct sway_output; +struct sway_workspace; struct sway_view; struct sway_container { @@ -52,6 +53,7 @@ struct sway_container { // TODO: Encapsulate state for other node types as well like C_CONTAINER struct sway_root *sway_root; struct sway_output *sway_output; + struct sway_workspace *sway_workspace; struct sway_view *sway_view; }; @@ -75,9 +77,6 @@ struct sway_container { // does not include borders or gaps. double width, height; - // For C_WORKSPACE only - struct sway_view *fullscreen; - list_t *children; struct sway_container *parent; diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 8d49fefba..35e1df3b3 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -3,6 +3,13 @@ #include "sway/tree/container.h" +struct sway_view; + +struct sway_workspace { + struct sway_container *swayc; + struct sway_view *fullscreen; +}; + extern char *prev_workspace_name; char *workspace_next_name(const char *output_name); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index dc2f63802..74919ccd9 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -22,6 +22,7 @@ #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" struct sway_container *output_by_name(const char *name) { for (int i = 0; i < root_container.children->length; ++i) { @@ -275,9 +276,9 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_container *workspace = output_get_active_workspace(output); - if (workspace->fullscreen) { + if (workspace->sway_workspace->fullscreen) { wlr_output_set_fullscreen_surface(wlr_output, - workspace->fullscreen->surface); + workspace->sway_workspace->fullscreen->surface); } else { wlr_output_set_fullscreen_surface(wlr_output, NULL); render_layer(output, diff --git a/sway/input/seat.c b/sway/input/seat.c index f60c43b5d..23b7ef768 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -18,6 +18,7 @@ #include "sway/output.h" #include "sway/tree/container.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "log.h" static void seat_device_destroy(struct sway_seat_device *seat_device) { @@ -457,7 +458,8 @@ void seat_set_focus_warp(struct sway_seat *seat, new_workspace = container_parent(new_workspace, C_WORKSPACE); } - if (last_workspace == new_workspace && last_workspace->fullscreen + if (last_workspace == new_workspace + && last_workspace->sway_workspace->fullscreen && !container->sway_view->is_fullscreen) { return; } diff --git a/sway/tree/container.c b/sway/tree/container.c index c00674939..f14e9b9a9 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -197,6 +197,7 @@ static struct sway_container *container_workspace_destroy( } } + free(workspace->sway_workspace); _container_destroy(workspace); output_damage_whole(output->sway_output); diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ad097f2e4..62219bb10 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -572,7 +572,7 @@ void arrange_windows(struct sway_container *container, return; case C_WORKSPACE: { - if (container->fullscreen) { + if (container->sway_workspace->fullscreen) { return; } struct sway_container *output = @@ -847,22 +847,6 @@ struct sway_container *container_get_in_direction( } } - // TODO WLR fullscreen - /* - if (container->type == C_VIEW && swayc_is_fullscreen(container)) { - wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output"); - container = container_parent(container, C_OUTPUT); - get_layout_center_position(container, &abs_pos); - struct sway_container *output = - swayc_adjacent_output(container, dir, &abs_pos, true); - return get_swayc_in_output_direction(output, dir); - } - if (container->type == C_WORKSPACE && container->fullscreen) { - sway_log(L_DEBUG, "Moving to fullscreen view"); - return container->fullscreen; - } - */ - struct sway_container *wrap_candidate = NULL; while (true) { bool can_move = false; diff --git a/sway/tree/view.c b/sway/tree/view.c index 10285ad03..e7a267ec5 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -7,6 +7,7 @@ #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" void view_init(struct sway_view *view, enum sway_view_type type, const struct sway_view_impl *impl) { @@ -90,10 +91,10 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) { view->is_fullscreen = fullscreen; if (fullscreen) { - workspace->fullscreen = view; + workspace->sway_workspace->fullscreen = view; view_configure(view, 0, 0, output->wlr_output->width, output->wlr_output->height); } else { - workspace->fullscreen = NULL; + workspace->sway_workspace->fullscreen = NULL; arrange_windows(workspace, -1, -1); } @@ -105,7 +106,7 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) { void view_close(struct sway_view *view) { if (view->is_fullscreen) { struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - ws->fullscreen = NULL; + ws->sway_workspace->fullscreen = NULL; } if (view->impl->close) { diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 316f01e4e..7f3c1903a 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -59,6 +59,13 @@ struct sway_container *workspace_create(struct sway_container *output, workspace->layout = container_get_default_layout(output); workspace->workspace_layout = workspace->layout; + struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); + if (!swayws) { + return NULL; + } + swayws->swayc = workspace; + workspace->sway_workspace = swayws; + container_add_child(output, workspace); container_sort_workspaces(output); container_create_notify(workspace); From a44d016e2b24a3454551c27f9252b4c419968760 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 17 Apr 2018 10:58:42 +1000 Subject: [PATCH 04/17] Don't damage views if they're hidden by a fullscreen view. --- sway/desktop/output.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 74919ccd9..361a92d0f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -469,6 +469,12 @@ void output_damage_view(struct sway_output *output, struct sway_view *view, return; } + struct sway_container *workspace = container_parent(view->swayc, + C_WORKSPACE); + if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { + return; + } + struct damage_data data = { .output = output, .whole = whole, From 143b528f71ea71393368815eecebf900ff45cf9d Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 17 Apr 2018 11:04:57 +1000 Subject: [PATCH 05/17] Handle fullscreen flag when mapping a surface. --- sway/desktop/wl_shell.c | 4 ++++ sway/desktop/xdg_shell_v6.c | 4 ++++ sway/desktop/xwayland.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index b63c220c6..96332e5c9 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -128,4 +128,8 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { wl_signal_add(&shell_surface->events.destroy, &wl_shell_view->destroy); view_map(&wl_shell_view->view, shell_surface->surface); + + if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN) { + view_set_fullscreen(&wl_shell_view->view, true); + } } diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 133b60c34..731862a95 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -212,6 +212,10 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_v6_view->new_popup.notify = handle_new_popup; wl_signal_add(&xdg_surface->events.new_popup, &xdg_shell_v6_view->new_popup); + + if (xdg_surface->toplevel->current.fullscreen) { + view_set_fullscreen(view, true); + } } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 963c5a0ed..46eaa84ce 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -248,6 +248,10 @@ static void handle_map(struct wl_listener *listener, void *data) { // Put it back into the tree wlr_xwayland_surface_set_maximized(xsurface, true); view_map(view, xsurface->surface); + + if (xsurface->fullscreen) { + view_set_fullscreen(view, true); + } } static void handle_destroy(struct wl_listener *listener, void *data) { From cc4da245a8e4a746ebd379ca8dd6cc3b33ded8e4 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 17 Apr 2018 11:06:03 +1000 Subject: [PATCH 06/17] Fix views unmapping their own fullscreen windows. --- sway/tree/view.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index e7a267ec5..fa27ec36b 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -104,11 +104,6 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) { } void view_close(struct sway_view *view) { - if (view->is_fullscreen) { - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - ws->sway_workspace->fullscreen = NULL; - } - if (view->impl->close) { view->impl->close(view); } @@ -232,6 +227,11 @@ void view_unmap(struct sway_view *view) { wl_signal_emit(&view->events.unmap, view); + if (view->is_fullscreen) { + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + ws->sway_workspace->fullscreen = NULL; + } + view_damage(view, true); wl_list_remove(&view->surface_new_subsurface.link); From 72beae209b03815e39d0aaa11348fa17c8a7bca9 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 18 Apr 2018 00:10:32 +1000 Subject: [PATCH 07/17] Fullscreen fixes. --- include/sway/tree/view.h | 1 + sway/commands/fullscreen.c | 7 +- sway/desktop/wl_shell.c | 31 ++++++++ sway/desktop/xdg_shell_v6.c | 4 +- sway/tree/layout.c | 136 +++++++++++++++++++++++++++++------- sway/tree/view.c | 20 +++++- 6 files changed, 170 insertions(+), 29 deletions(-) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 9dfd171f1..648a74c44 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -112,6 +112,7 @@ struct sway_wl_shell_view { struct wl_listener request_resize; struct wl_listener request_maximize; struct wl_listener request_fullscreen; + struct wl_listener set_state; struct wl_listener destroy; int pending_width, pending_height; diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 5a044aa85..8692e92d8 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c @@ -6,8 +6,11 @@ #include "sway/tree/view.h" #include "sway/tree/layout.h" -// fullscreen toggle|enable|disable struct cmd_results *cmd_fullscreen(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) { + return error; + } struct sway_container *container = config->handler_context.current_container; if (container->type != C_VIEW) { @@ -25,7 +28,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { wants_fullscreen = false; } else { return cmd_results_new(CMD_INVALID, "fullscreen", - "Expected 'fullscreen' or fullscreen '"); + "Expected 'fullscreen' or 'fullscreen '"); } view_set_fullscreen(view, wants_fullscreen); diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index 96332e5c9..2d666d95a 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -61,14 +61,21 @@ static void destroy(struct sway_view *view) { } wl_list_remove(&wl_shell_view->commit.link); wl_list_remove(&wl_shell_view->destroy.link); + wl_list_remove(&wl_shell_view->request_fullscreen.link); + wl_list_remove(&wl_shell_view->set_state.link); free(wl_shell_view); } +static void set_fullscreen(struct sway_view *view, bool fullscreen) { + // TODO +} + static const struct sway_view_impl view_impl = { .get_prop = get_prop, .configure = configure, .close = _close, .destroy = destroy, + .set_fullscreen = set_fullscreen, }; static void handle_commit(struct wl_listener *listener, void *data) { @@ -88,6 +95,23 @@ static void handle_destroy(struct wl_listener *listener, void *data) { view_destroy(&wl_shell_view->view); } +static void handle_request_fullscreen(struct wl_listener *listener, void *data) { + struct sway_wl_shell_view *wl_shell_view = + wl_container_of(listener, wl_shell_view, request_fullscreen); + view_set_fullscreen(&wl_shell_view->view, true); +} + +static void handle_set_state(struct wl_listener *listener, void *data) { + struct sway_wl_shell_view *wl_shell_view = + wl_container_of(listener, wl_shell_view, set_state); + struct sway_view *view = &wl_shell_view->view; + struct wlr_wl_shell_surface *surface = view->wlr_wl_shell_surface; + if (view->is_fullscreen && + surface->state != WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN) { + view_set_fullscreen(view, false); + } +} + void handle_wl_shell_surface(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, wl_shell_surface); @@ -127,6 +151,13 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { wl_shell_view->destroy.notify = handle_destroy; wl_signal_add(&shell_surface->events.destroy, &wl_shell_view->destroy); + wl_shell_view->request_fullscreen.notify = handle_request_fullscreen; + wl_signal_add(&shell_surface->events.request_fullscreen, + &wl_shell_view->request_fullscreen); + + wl_shell_view->set_state.notify = handle_set_state; + wl_signal_add(&shell_surface->events.set_state, &wl_shell_view->set_state); + view_map(&wl_shell_view->view, shell_surface->surface); if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 731862a95..6c0556b20 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -229,7 +229,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) wl_container_of(listener, xdg_shell_v6_view, request_fullscreen); struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data; - if (xdg_shell_v6_view->view.wlr_xdg_surface_v6->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + if (!sway_assert(xdg_shell_v6_view->view.wlr_xdg_surface_v6->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, + "xdg_shell_v6 requested fullscreen of surface with role %i", + xdg_shell_v6_view->view.wlr_xdg_surface_v6->role)) { return; } diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 62219bb10..d931c4dcf 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -82,6 +82,37 @@ static int index_child(const struct sway_container *child) { return i; } +static void container_handle_fullscreen_reparent(struct sway_container *viewcon, + struct sway_container *old_parent) { + if (viewcon->type != C_VIEW || !viewcon->sway_view->is_fullscreen) { + return; + } + struct sway_view *view = viewcon->sway_view; + struct sway_container *old_workspace = old_parent; + if (old_workspace && old_workspace->type != C_WORKSPACE) { + old_workspace = container_parent(old_workspace, C_WORKSPACE); + } + struct sway_container *new_workspace = container_parent(view->swayc, + C_WORKSPACE); + if (old_workspace == new_workspace) { + return; + } + // Unmark the old workspace as fullscreen + if (old_workspace) { + old_workspace->sway_workspace->fullscreen = NULL; + } + + // Mark the new workspace as fullscreen + if (new_workspace->sway_workspace->fullscreen) { + view_set_fullscreen(new_workspace->sway_workspace->fullscreen, false); + } + new_workspace->sway_workspace->fullscreen = view; + // Resize view to new output dimensions + struct sway_output *output = new_workspace->parent->sway_output; + view_configure(view, 0, 0, + output->wlr_output->width, output->wlr_output->height); +} + void container_insert_child(struct sway_container *parent, struct sway_container *child, int i) { struct sway_container *old_parent = child->parent; @@ -91,6 +122,7 @@ void container_insert_child(struct sway_container *parent, wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i); list_insert(parent->children, i, child); child->parent = parent; + container_handle_fullscreen_reparent(child, old_parent); wl_signal_emit(&child->events.reparent, old_parent); } @@ -106,6 +138,7 @@ struct sway_container *container_add_sibling(struct sway_container *fixed, int i = index_child(fixed); list_insert(parent->children, i + 1, active); active->parent = parent; + container_handle_fullscreen_reparent(active, old_parent); wl_signal_emit(&active->events.reparent, old_parent); return active->parent; } @@ -115,11 +148,18 @@ void container_add_child(struct sway_container *parent, wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, child->width, child->height, parent, parent->type, parent->width, parent->height); + struct sway_container *old_parent = child->parent; list_add(parent->children, child); + container_handle_fullscreen_reparent(child, old_parent); child->parent = parent; } struct sway_container *container_remove_child(struct sway_container *child) { + if (child->type == C_VIEW && child->sway_view->is_fullscreen) { + struct sway_container *workspace = container_parent(child, C_WORKSPACE); + workspace->sway_workspace->fullscreen = NULL; + } + struct sway_container *parent = child->parent; for (int i = 0; i < parent->children->length; ++i) { if (parent->children->items[i] == child) { @@ -137,21 +177,6 @@ void container_move_to(struct sway_container *container, || container_has_anscestor(container, destination)) { return; } - - if (container->type == C_VIEW && container->sway_view->is_fullscreen) { - struct sway_container *old_workspace = container; - if (old_workspace->type != C_WORKSPACE) { - old_workspace = container_parent(old_workspace, C_WORKSPACE); - } - struct sway_container *new_workspace = destination; - if (new_workspace->type != C_WORKSPACE) { - new_workspace = container_parent(new_workspace, C_WORKSPACE); - } - if (old_workspace != new_workspace) { - view_set_fullscreen(container->sway_view, false); - } - } - struct sway_container *old_parent = container_remove_child(container); container->width = container->height = 0; struct sway_container *new_parent; @@ -179,6 +204,26 @@ void container_move_to(struct sway_container *container, arrange_windows(old_parent, -1, -1); } arrange_windows(new_parent, -1, -1); + // If view was moved to a fullscreen workspace, refocus the fullscreen view + struct sway_container *new_workspace = container; + if (new_workspace->type != C_WORKSPACE) { + new_workspace = container_parent(new_workspace, C_WORKSPACE); + } + if (new_workspace->sway_workspace->fullscreen) { + struct sway_seat *seat; + struct sway_container *focus, *focus_ws; + wl_list_for_each(seat, &input_manager->seats, link) { + focus = seat_get_focus(seat); + focus_ws = focus; + if (focus_ws->type != C_WORKSPACE) { + focus_ws = container_parent(focus_ws, C_WORKSPACE); + } + seat_set_focus(seat, new_workspace->sway_workspace->fullscreen->swayc); + if (focus_ws != new_workspace) { + seat_set_focus(seat, focus); + } + } + } } static bool sway_dir_to_wlr(enum movement_direction dir, @@ -283,6 +328,11 @@ void container_move(struct sway_container *container, struct sway_container *current = container; struct sway_container *parent = current->parent; + // If moving a fullscreen view, only consider outputs + if (container->type == C_VIEW && container->sway_view->is_fullscreen) { + current = container_parent(container, C_OUTPUT); + } + if (parent != container_flatten(parent)) { // Special case: we were the last one in this container, so flatten it // and leave @@ -546,6 +596,14 @@ void arrange_windows(struct sway_container *container, container->name, container->width, container->height, container->x, container->y); + if (container->type == C_WORKSPACE + && container->sway_workspace->fullscreen) { + struct wlr_output *wlr_output + = container->parent->sway_output->wlr_output; + view_configure(container->sway_workspace->fullscreen, 0, 0, + wlr_output->width, wlr_output->height); + } + double x = 0, y = 0; switch (container->type) { case C_ROOT: @@ -831,19 +889,27 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { return NULL; } -struct sway_container *container_get_in_direction( +static struct sway_container *container_get_in_direction_naive( struct sway_container *container, struct sway_seat *seat, enum movement_direction dir) { - if (dir == MOVE_CHILD) { - return seat_get_focus_inactive(seat, container); - } - struct sway_container *parent = container->parent; - if (dir == MOVE_PARENT) { - if (parent->type == C_OUTPUT) { + + if (container->type == C_VIEW && container->sway_view->is_fullscreen) { + if (dir == MOVE_PARENT || dir == MOVE_CHILD) { return NULL; - } else { - return parent; + } + container = container_parent(container, C_OUTPUT); + parent = container->parent; + } else { + if (dir == MOVE_CHILD) { + return seat_get_focus_inactive(seat, container); + } + if (dir == MOVE_PARENT) { + if (parent->type == C_OUTPUT) { + return NULL; + } else { + return parent; + } } } @@ -932,6 +998,28 @@ struct sway_container *container_get_in_direction( } } +struct sway_container *container_get_in_direction( + struct sway_container *container, struct sway_seat *seat, + enum movement_direction dir) { + struct sway_container *result = container_get_in_direction_naive(container, + seat, dir); + if (!result) { + return NULL; + } + struct sway_container *old_workspace = container; + if (old_workspace->type != C_WORKSPACE) { + old_workspace = container_parent(old_workspace, C_WORKSPACE); + } + struct sway_container *new_workspace = result; + if (new_workspace->type != C_WORKSPACE) { + new_workspace = container_parent(new_workspace, C_WORKSPACE); + } + if (old_workspace != new_workspace && new_workspace->sway_workspace->fullscreen) { + result = new_workspace->sway_workspace->fullscreen->swayc; + } + return result; +} + struct sway_container *container_replace_child(struct sway_container *child, struct sway_container *new_child) { struct sway_container *parent = child->parent; diff --git a/sway/tree/view.c b/sway/tree/view.c index fa27ec36b..b92c70996 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -91,13 +91,29 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) { view->is_fullscreen = fullscreen; if (fullscreen) { + if (workspace->sway_workspace->fullscreen) { + view_set_fullscreen(workspace->sway_workspace->fullscreen, false); + } workspace->sway_workspace->fullscreen = view; - view_configure(view, 0, 0, output->wlr_output->width, output->wlr_output->height); + + struct sway_seat *seat; + struct sway_container *focus, *focus_ws; + wl_list_for_each(seat, &input_manager->seats, link) { + focus = seat_get_focus(seat); + focus_ws = focus; + if (focus_ws->type != C_WORKSPACE) { + focus_ws = container_parent(focus_ws, C_WORKSPACE); + } + seat_set_focus(seat, view->swayc); + if (focus_ws != workspace) { + seat_set_focus(seat, focus); + } + } } else { workspace->sway_workspace->fullscreen = NULL; - arrange_windows(workspace, -1, -1); } + arrange_windows(workspace, -1, -1); output_damage_whole(output); ipc_event_window(view->swayc, "fullscreen_mode"); From 35ccdd67a89280c1d906ed914d67918cfb382e1f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 18 Apr 2018 08:35:28 +1000 Subject: [PATCH 08/17] More fullscreen fixes. * Render fullscreen views without wlr function, which makes popups and lockscreen work. * Don't allow input events to surfaces behind fullscreen views. * Use correct output dimensions (for rotated outputs). --- sway/desktop/output.c | 10 ++++++---- sway/input/cursor.c | 8 ++++++++ sway/tree/layout.c | 4 +--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 361a92d0f..a5f2f71f2 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -229,7 +229,11 @@ static void render_container_iterator(struct sway_container *con, static void render_container(struct sway_output *output, struct sway_container *con) { - container_descendants(con, C_VIEW, render_container_iterator, output); + if (con->type == C_VIEW) { // Happens if a view is fullscreened + render_container_iterator(con, output); + } else { + container_descendants(con, C_VIEW, render_container_iterator, output); + } } static struct sway_container *output_get_active_workspace( @@ -277,10 +281,8 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_container *workspace = output_get_active_workspace(output); if (workspace->sway_workspace->fullscreen) { - wlr_output_set_fullscreen_surface(wlr_output, - workspace->sway_workspace->fullscreen->surface); + render_container(output, workspace->sway_workspace->fullscreen->swayc); } else { - wlr_output_set_fullscreen_surface(wlr_output, NULL); render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 15a61cbf8..6d14c12c7 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -12,6 +12,7 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "wlr-layer-shell-unstable-v1-protocol.h" static struct wlr_surface *layer_surface_at(struct sway_output *output, @@ -89,6 +90,13 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor, return ws; } + if (ws->sway_workspace->fullscreen) { + *sx = ox; + *sy = oy; + *surface = ws->sway_workspace->fullscreen->surface; + return ws->sway_workspace->fullscreen->swayc; + } + struct sway_container *c; if ((c = container_at(ws, cursor->cursor->x, cursor->cursor->y, surface, sx, sy))) { diff --git a/sway/tree/layout.c b/sway/tree/layout.c index d931c4dcf..56d4e1d28 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -598,10 +598,8 @@ void arrange_windows(struct sway_container *container, if (container->type == C_WORKSPACE && container->sway_workspace->fullscreen) { - struct wlr_output *wlr_output - = container->parent->sway_output->wlr_output; view_configure(container->sway_workspace->fullscreen, 0, 0, - wlr_output->width, wlr_output->height); + container->parent->width, container->parent->height); } double x = 0, y = 0; From 8d06b222f048e5a27c4c5b0bc46ceaab7639502f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 18 Apr 2018 13:06:10 +1000 Subject: [PATCH 09/17] Fullscreen rendering and input fixes. * Render background when using fullscreen, because transparency. * Check that fullscreen surface allows input. * Don't look for surfaces in top layer if there's a fullscreen view. --- sway/desktop/output.c | 4 ++-- sway/input/cursor.c | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a5f2f71f2..299b57f1a 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -280,11 +280,11 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_container *workspace = output_get_active_workspace(output); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + if (workspace->sway_workspace->fullscreen) { render_container(output, workspace->sway_workspace->fullscreen->swayc); } else { - render_layer(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); render_container(output, workspace); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 6d14c12c7..a19f0752a 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -84,19 +84,22 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor, ox, oy, sx, sy))) { return ws; } + if (ws->sway_workspace->fullscreen) { + struct wlr_surface *wlr_surface = ws->sway_workspace->fullscreen->surface; + if (wlr_surface_point_accepts_input(wlr_surface, ox, oy)) { + *sx = ox; + *sy = oy; + *surface = wlr_surface; + return ws->sway_workspace->fullscreen->swayc; + } + return NULL; + } if ((*surface = layer_surface_at(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], ox, oy, sx, sy))) { return ws; } - if (ws->sway_workspace->fullscreen) { - *sx = ox; - *sy = oy; - *surface = ws->sway_workspace->fullscreen->surface; - return ws->sway_workspace->fullscreen->swayc; - } - struct sway_container *c; if ((c = container_at(ws, cursor->cursor->x, cursor->cursor->y, surface, sx, sy))) { From 2acfbc519ef7940b620abef0de64ae79d1f50782 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 19 Apr 2018 12:47:34 +1000 Subject: [PATCH 10/17] xdg_shell_v6: Use client_pending state instead of current It appears client_pending is the state that should be used here. --- sway/desktop/xdg_shell_v6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 6c0556b20..87e346664 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -213,7 +213,7 @@ static void handle_map(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_surface->events.new_popup, &xdg_shell_v6_view->new_popup); - if (xdg_surface->toplevel->current.fullscreen) { + if (xdg_surface->toplevel->client_pending.fullscreen) { view_set_fullscreen(view, true); } } From 7e38cc2e05f4a14a9e4043951b6fcc033cbb41c2 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 19 Apr 2018 12:50:53 +1000 Subject: [PATCH 11/17] arrange_windows(): Calculate workspace properties when fullscreen --- sway/tree/layout.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 56d4e1d28..96d0c567e 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -596,12 +596,6 @@ void arrange_windows(struct sway_container *container, container->name, container->width, container->height, container->x, container->y); - if (container->type == C_WORKSPACE - && container->sway_workspace->fullscreen) { - view_configure(container->sway_workspace->fullscreen, 0, 0, - container->parent->width, container->parent->height); - } - double x = 0, y = 0; switch (container->type) { case C_ROOT: @@ -628,9 +622,6 @@ void arrange_windows(struct sway_container *container, return; case C_WORKSPACE: { - if (container->sway_workspace->fullscreen) { - return; - } struct sway_container *output = container_parent(container, C_OUTPUT); struct wlr_box *area = &output->sway_output->usable_area; @@ -642,6 +633,11 @@ void arrange_windows(struct sway_container *container, container->y = y = area->y; wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", container->name, container->x, container->y); + if (container->sway_workspace->fullscreen) { + view_configure(container->sway_workspace->fullscreen, 0, 0, + output->width, output->height); + return; + } } // children are properly handled below break; From 45a2fad0dead2e00a41eedd3b524aacd29f00335 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 19 Apr 2018 12:53:02 +1000 Subject: [PATCH 12/17] container_get_in_direction(): Don't split this function --- sway/tree/layout.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 96d0c567e..7ffc24844 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -883,7 +883,7 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { return NULL; } -static struct sway_container *container_get_in_direction_naive( +struct sway_container *container_get_in_direction( struct sway_container *container, struct sway_seat *seat, enum movement_direction dir) { struct sway_container *parent = container->parent; @@ -936,6 +936,14 @@ static struct sway_container *container_get_in_direction_naive( if (next == NULL) { return NULL; } + struct sway_container *next_workspace = next; + if (next_workspace->type != C_WORKSPACE) { + next_workspace = container_parent(next_workspace, C_WORKSPACE); + } + sway_assert(next_workspace, "Next container has no workspace"); + if (next_workspace->sway_workspace->fullscreen) { + return next_workspace->sway_workspace->fullscreen->swayc; + } if (next->children && next->children->length) { // TODO consider floating children as well return seat_get_focus_inactive_view(seat, next); @@ -992,28 +1000,6 @@ static struct sway_container *container_get_in_direction_naive( } } -struct sway_container *container_get_in_direction( - struct sway_container *container, struct sway_seat *seat, - enum movement_direction dir) { - struct sway_container *result = container_get_in_direction_naive(container, - seat, dir); - if (!result) { - return NULL; - } - struct sway_container *old_workspace = container; - if (old_workspace->type != C_WORKSPACE) { - old_workspace = container_parent(old_workspace, C_WORKSPACE); - } - struct sway_container *new_workspace = result; - if (new_workspace->type != C_WORKSPACE) { - new_workspace = container_parent(new_workspace, C_WORKSPACE); - } - if (old_workspace != new_workspace && new_workspace->sway_workspace->fullscreen) { - result = new_workspace->sway_workspace->fullscreen->swayc; - } - return result; -} - struct sway_container *container_replace_child(struct sway_container *child, struct sway_container *new_child) { struct sway_container *parent = child->parent; From 9715e38ca82f891afdb824d02b7f19a2587e24c1 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 19 Apr 2018 13:01:43 +1000 Subject: [PATCH 13/17] render_output(): When fullscreen, clear to black and don't render background --- sway/desktop/output.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 299b57f1a..1ab9324de 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -275,16 +275,18 @@ static void render_output(struct sway_output *output, struct timespec *when, wlr_output_transformed_resolution(wlr_output, &width, &height); pixman_region32_union_rect(damage, damage, 0, 0, width, height); - float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; - wlr_renderer_clear(renderer, clear_color); - struct sway_container *workspace = output_get_active_workspace(output); - render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - if (workspace->sway_workspace->fullscreen) { + float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + wlr_renderer_clear(renderer, clear_color); render_container(output, workspace->sway_workspace->fullscreen->swayc); } else { + float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; + wlr_renderer_clear(renderer, clear_color); + + render_layer(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); render_container(output, workspace); From 777800e37ab84de9deb64586d8155a9eb600b4c2 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 19 Apr 2018 09:15:21 -0400 Subject: [PATCH 14/17] Fix qutebrowser crash on context menu dismissal --- sway/input/seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/input/seat.c b/sway/input/seat.c index 23b7ef768..8bba7d8fc 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -458,7 +458,7 @@ void seat_set_focus_warp(struct sway_seat *seat, new_workspace = container_parent(new_workspace, C_WORKSPACE); } - if (last_workspace == new_workspace + if (last_workspace && last_workspace == new_workspace && last_workspace->sway_workspace->fullscreen && !container->sway_view->is_fullscreen) { return; From bd67342bdc82d53bbe492e9ac515600d4a649bc9 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 20 Apr 2018 08:08:34 +1000 Subject: [PATCH 15/17] Don't render top layer when fullscreen. --- sway/desktop/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1ab9324de..4a1b0c847 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -292,8 +292,8 @@ static void render_output(struct sway_output *output, struct timespec *when, render_container(output, workspace); render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); } - render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); renderer_end: From 76837b91325c4bbb2fd631a30a26f125493ca631 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 20 Apr 2018 08:10:58 +1000 Subject: [PATCH 16/17] Ignore xdg_shell_v6 request_fullscreen if not mapped --- sway/desktop/xdg_shell_v6.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 87e346664..fdfb93460 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -234,6 +234,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) xdg_shell_v6_view->view.wlr_xdg_surface_v6->role)) { return; } + if (!xdg_shell_v6_view->view.wlr_xdg_surface_v6->mapped) { + return; + } view_set_fullscreen(&xdg_shell_v6_view->view, e->fullscreen); } From 6afccd07d95582a72e36b49454266ab0cebec7c0 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 20 Apr 2018 08:12:03 +1000 Subject: [PATCH 17/17] Add TODO about rendering fullscreen views smaller than the output --- sway/desktop/output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 4a1b0c847..8d25caaec 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -280,6 +280,7 @@ static void render_output(struct sway_output *output, struct timespec *when, if (workspace->sway_workspace->fullscreen) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; wlr_renderer_clear(renderer, clear_color); + // TODO: handle views smaller than the output render_container(output, workspace->sway_workspace->fullscreen->swayc); } else { float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};