diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 9dfd171f..648a74c4 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 5a044aa8..8692e92d 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 96332e5c..2d666d95 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 731862a9..6c0556b2 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 62219bb1..d931c4dc 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 fa27ec36..b92c7099 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");