From 08cfba2192f5770d975c5fe70789a81aaee4dc7e Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 26 Jul 2018 18:36:46 +1000 Subject: Allow containers to float Things worth noting: * When a fullscreen view unmaps, the check to unset fullscreen on the workspace has been moved out of view_unmap and into container_destroy, because containers can be fullscreen too * The calls to `container_reap_empty_recursive(workspace)` have been removed from `container_set_floating`. That function reaps upwards so it wouldn't do anything. I'm probably the one who originally added it... * My fix (b14bd1b0b1536039e4f46fe94515c7c44e7afc61) for the tabbed child crash has a side effect where when you close a floating container, focus is not given to the tiled container again. I've removed my fix and removed the call to `send_cursor_motion` from `seat_set_focus_warp`. We should consider calling it from somewhere earlier in the call stack. --- sway/tree/container.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 5 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 6ebf2653..566432b1 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -407,6 +407,10 @@ struct sway_container *container_flatten(struct sway_container *container) { * This function just wraps container_destroy_noreaping(), then does reaping. */ struct sway_container *container_destroy(struct sway_container *con) { + if (con->is_fullscreen) { + struct sway_container *ws = container_parent(con, C_WORKSPACE); + ws->sway_workspace->fullscreen = NULL; + } struct sway_container *parent = container_destroy_noreaping(con); if (!parent) { @@ -945,23 +949,81 @@ size_t container_titlebar_height() { return config->font_height + TITLEBAR_V_PADDING * 2; } +void container_init_floating(struct sway_container *con) { + if (!sway_assert(con->type == C_VIEW || con->type == C_CONTAINER, + "Expected a view or container")) { + return; + } + struct sway_container *ws = container_parent(con, C_WORKSPACE); + int min_width, min_height; + int max_width, max_height; + + if (config->floating_minimum_width == -1) { // no minimum + min_width = 0; + } else if (config->floating_minimum_width == 0) { // automatic + min_width = 75; + } else { + min_width = config->floating_minimum_width; + } + + if (config->floating_minimum_height == -1) { // no minimum + min_height = 0; + } else if (config->floating_minimum_height == 0) { // automatic + min_height = 50; + } else { + min_height = config->floating_minimum_height; + } + + if (config->floating_maximum_width == -1) { // no maximum + max_width = INT_MAX; + } else if (config->floating_maximum_width == 0) { // automatic + max_width = ws->width * 0.6666; + } else { + max_width = config->floating_maximum_width; + } + + if (config->floating_maximum_height == -1) { // no maximum + max_height = INT_MAX; + } else if (config->floating_maximum_height == 0) { // automatic + max_height = ws->height * 0.6666; + } else { + max_height = config->floating_maximum_height; + } + + if (con->type == C_CONTAINER) { + con->width = max_width; + con->height = max_height; + con->x = ws->x + (ws->width - con->width) / 2; + con->y = ws->y + (ws->height - con->height) / 2; + } else { + struct sway_view *view = con->sway_view; + view->width = fmax(min_width, fmin(view->natural_width, max_width)); + view->height = fmax(min_height, fmin(view->natural_height, max_height)); + view->x = ws->x + (ws->width - view->width) / 2; + view->y = ws->y + (ws->height - view->height) / 2; + + // If the view's border is B_NONE then these properties are ignored. + view->border_top = view->border_bottom = true; + view->border_left = view->border_right = true; + + container_set_geometry_from_floating_view(view->swayc); + } +} + void container_set_floating(struct sway_container *container, bool enable) { if (container_is_floating(container) == enable) { return; } struct sway_container *workspace = container_parent(container, C_WORKSPACE); - struct sway_seat *seat = input_manager_current_seat(input_manager); if (enable) { container_remove_child(container); container_add_child(workspace->sway_workspace->floating, container); + container_init_floating(container); if (container->type == C_VIEW) { - view_init_floating(container->sway_view); view_set_tiled(container->sway_view, false); } - seat_set_focus(seat, seat_get_focus_inactive(seat, container)); - container_reap_empty_recursive(workspace); } else { // Returning to tiled if (container->scratchpad) { @@ -975,7 +1037,6 @@ void container_set_floating(struct sway_container *container, bool enable) { view_set_tiled(container->sway_view, true); } container->is_sticky = false; - container_reap_empty_recursive(workspace->sway_workspace->floating); } container_end_mouse_operation(container); @@ -1195,6 +1256,17 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { ipc_event_window(container, "fullscreen_mode"); } +bool container_is_floating_or_child(struct sway_container *container) { + do { + if (container->parent && container->parent->layout == L_FLOATING) { + return true; + } + container = container->parent; + } while (container && container->type != C_WORKSPACE); + + return false; +} + bool container_is_fullscreen_or_child(struct sway_container *container) { do { if (container->is_fullscreen) { -- cgit v1.2.3 From da2a87f6c71bfe90a4d77542bfc7ed22899f67be Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 26 Jul 2018 22:58:42 +1000 Subject: When unfloating, return container to previously focused tiled container This introduces seat_get_focus_inactive_tiling and updates `focus mode_toggle` to use it instead, because the previous method wasn't guaranteed to return a tiling view. --- include/sway/input/seat.h | 3 +++ sway/commands/focus.c | 14 ++++++++------ sway/input/seat.c | 23 +++++++++++++++++------ sway/tree/container.c | 5 ++++- 4 files changed, 32 insertions(+), 13 deletions(-) (limited to 'sway/tree/container.c') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index ab25788f..07febe2c 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -124,6 +124,9 @@ struct sway_container *seat_get_focus(struct sway_seat *seat); struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container); +struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, + struct sway_container *container); + /** * Descend into the focus stack to find the focus-inactive view. Useful for * container placement when they change position in the tree. diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 9cd8bfae..ce3d032f 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -35,14 +35,16 @@ static struct cmd_results *focus_mode(struct sway_container *con, struct sway_seat *seat, bool floating) { struct sway_container *ws = con->type == C_WORKSPACE ? con : container_parent(con, C_WORKSPACE); - struct sway_container *new_focus = ws; + struct sway_container *new_focus = NULL; if (floating) { - new_focus = ws->sway_workspace->floating; - if (new_focus->children->length == 0) { - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } + new_focus = seat_get_focus_inactive(seat, ws->sway_workspace->floating); + } else { + new_focus = seat_get_focus_inactive_tiling(seat, ws); + } + if (!new_focus) { + new_focus = ws; } - seat_set_focus(seat, seat_get_active_child(seat, new_focus)); + seat_set_focus(seat, new_focus); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/input/seat.c b/sway/input/seat.c index 877a93c6..18d5591d 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -124,12 +124,14 @@ static void seat_send_focus(struct sway_container *con, } static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, - struct sway_container *container, enum sway_container_type type) { + struct sway_container *container, enum sway_container_type type, + bool only_tiling) { if (container->type == C_VIEW) { return container; } - struct sway_container *floating = container->type == C_WORKSPACE ? + struct sway_container *floating = + container->type == C_WORKSPACE && !only_tiling ? container->sway_workspace->floating : NULL; if (container->children->length == 0 && (!floating || floating->children->length == 0)) { @@ -143,6 +145,10 @@ static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, } if (container_has_child(container, current->container)) { + if (only_tiling && + container_is_floating_or_child(current->container)) { + continue; + } return current->container; } if (floating && container_has_child(floating, current->container)) { @@ -169,7 +175,7 @@ void seat_focus_inactive_children_for_each(struct sway_seat *seat, struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, struct sway_container *container) { - return seat_get_focus_by_type(seat, container, C_VIEW); + return seat_get_focus_by_type(seat, container, C_VIEW, false); } static void handle_seat_container_destroy(struct wl_listener *listener, @@ -191,7 +197,7 @@ static void handle_seat_container_destroy(struct wl_listener *listener, if (set_focus) { struct sway_container *next_focus = NULL; while (next_focus == NULL) { - next_focus = seat_get_focus_by_type(seat, parent, C_VIEW); + next_focus = seat_get_focus_by_type(seat, parent, C_VIEW, false); if (next_focus == NULL && parent->type == C_WORKSPACE) { next_focus = parent; @@ -648,7 +654,7 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_container *new_output_last_ws = NULL; if (last_output && new_output && last_output != new_output) { new_output_last_ws = - seat_get_focus_by_type(seat, new_output, C_WORKSPACE); + seat_get_focus_by_type(seat, new_output, C_WORKSPACE, false); } if (container && container->parent) { @@ -853,7 +859,12 @@ void seat_set_exclusive_client(struct sway_seat *seat, struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) { - return seat_get_focus_by_type(seat, container, C_TYPES); + return seat_get_focus_by_type(seat, container, C_TYPES, false); +} + +struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, + struct sway_container *container) { + return seat_get_focus_by_type(seat, container, C_TYPES, true); } struct sway_container *seat_get_active_child(struct sway_seat *seat, diff --git a/sway/tree/container.c b/sway/tree/container.c index 566432b1..b8ff87e1 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1015,6 +1015,7 @@ void container_set_floating(struct sway_container *container, bool enable) { return; } + struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *workspace = container_parent(container, C_WORKSPACE); if (enable) { @@ -1029,8 +1030,10 @@ void container_set_floating(struct sway_container *container, bool enable) { if (container->scratchpad) { scratchpad_remove_container(container); } + struct sway_container *sibling = + seat_get_focus_inactive_tiling(seat, workspace); container_remove_child(container); - container_add_child(workspace, container); + container_add_child(sibling, container); container->width = container->parent->width; container->height = container->parent->height; if (container->type == C_VIEW) { -- cgit v1.2.3 From 538e083f61c363ef1127636d8fac1b7e4872e4c4 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 27 Jul 2018 09:10:10 +1000 Subject: Fix focus mode_toggle from a child of a floating container Also fixes a crash when unfloating a window. It needs to add it back to the tiling tree as a sibling rather than a child, because the reference container might be a view. --- sway/commands/focus.c | 11 ++++++++++- sway/tree/container.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/commands/focus.c b/sway/commands/focus.c index ce3d032f..76d3f1dc 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -35,6 +35,15 @@ static struct cmd_results *focus_mode(struct sway_container *con, struct sway_seat *seat, bool floating) { struct sway_container *ws = con->type == C_WORKSPACE ? con : container_parent(con, C_WORKSPACE); + + // If the container is in a floating split container, + // operate on the split container instead of the child. + if (container_is_floating_or_child(con)) { + while (con->parent->layout != L_FLOATING) { + con = con->parent; + } + } + struct sway_container *new_focus = NULL; if (floating) { new_focus = seat_get_focus_inactive(seat, ws->sway_workspace->floating); @@ -99,7 +108,7 @@ struct cmd_results *cmd_focus(int argc, char **argv) { } else if (strcmp(argv[0], "tiling") == 0) { return focus_mode(con, seat, false); } else if (strcmp(argv[0], "mode_toggle") == 0) { - return focus_mode(con, seat, !container_is_floating(con)); + return focus_mode(con, seat, !container_is_floating_or_child(con)); } if (strcmp(argv[0], "output") == 0) { diff --git a/sway/tree/container.c b/sway/tree/container.c index b8ff87e1..71babe5c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1033,7 +1033,7 @@ void container_set_floating(struct sway_container *container, bool enable) { struct sway_container *sibling = seat_get_focus_inactive_tiling(seat, workspace); container_remove_child(container); - container_add_child(sibling, container); + container_add_sibling(sibling, container); container->width = container->parent->width; container->height = container->parent->height; if (container->type == C_VIEW) { -- cgit v1.2.3 From debb8e85b2808e4b5e8ff79a702ffc48efc36389 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 27 Jul 2018 13:46:01 +1000 Subject: Fix crash when unfloating child of container into empty workspace --- sway/tree/container.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 71babe5c..2332d81f 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1030,10 +1030,13 @@ void container_set_floating(struct sway_container *container, bool enable) { if (container->scratchpad) { scratchpad_remove_container(container); } - struct sway_container *sibling = - seat_get_focus_inactive_tiling(seat, workspace); container_remove_child(container); - container_add_sibling(sibling, container); + struct sway_container *reference = + seat_get_focus_inactive_tiling(seat, workspace); + if (reference->type == C_VIEW) { + reference = reference->parent; + } + container_add_child(reference, container); container->width = container->parent->width; container->height = container->parent->height; if (container->type == C_VIEW) { -- cgit v1.2.3