From 04489ff4209dc073027419d90961367cfb998fe8 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 3 Aug 2018 23:06:01 +1000 Subject: [PATCH] Separate root-related code This creates a root.c and moves bits and pieces from elsewhere into it. * layout_init has been renamed to root_create and moved into root.c * root_destroy has been created and is called on shutdown * scratchpad code has been moved into root.c, because hidden scratchpad containers are stored in the root struct --- include/sway/scratchpad.h | 26 ------ include/sway/tree/layout.h | 23 +---- include/sway/tree/root.h | 57 ++++++++++++ sway/commands/move.c | 5 +- sway/commands/scratchpad.c | 81 ++++++++++++++++- sway/main.c | 3 +- sway/meson.build | 2 +- sway/scratchpad.c | 181 ------------------------------------- sway/tree/arrange.c | 2 - sway/tree/container.c | 6 +- sway/tree/layout.c | 34 ------- sway/tree/root.c | 147 ++++++++++++++++++++++++++++++ 12 files changed, 292 insertions(+), 275 deletions(-) delete mode 100644 include/sway/scratchpad.h create mode 100644 include/sway/tree/root.h delete mode 100644 sway/scratchpad.c create mode 100644 sway/tree/root.c diff --git a/include/sway/scratchpad.h b/include/sway/scratchpad.h deleted file mode 100644 index 5af5256f..00000000 --- a/include/sway/scratchpad.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _SWAY_SCRATCHPAD_H -#define _SWAY_SCRATCHPAD_H - -#include "tree/container.h" - -/** - * Move a container to the scratchpad. - */ -void scratchpad_add_container(struct sway_container *con); - -/** - * Remove a container from the scratchpad. - */ -void scratchpad_remove_container(struct sway_container *con); - -/** - * Show or hide the next container on the scratchpad. - */ -void scratchpad_toggle_auto(void); - -/** - * Show or hide a specific container on the scratchpad. - */ -void scratchpad_toggle_container(struct sway_container *con); - -#endif diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index a4c31bf6..77cd954b 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -3,6 +3,7 @@ #include #include #include "sway/tree/container.h" +#include "sway/tree/root.h" #include "config.h" enum movement_direction { @@ -24,28 +25,6 @@ enum resize_edge { struct sway_container; -struct sway_root { - struct wlr_output_layout *output_layout; - - struct wl_listener output_layout_change; -#ifdef HAVE_XWAYLAND - struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link -#endif - struct wl_list drag_icons; // sway_drag_icon::link - - struct wlr_texture *debug_tree; - - struct wl_list outputs; // sway_output::link - - list_t *scratchpad; // struct sway_container - - struct { - struct wl_signal new_container; - } events; -}; - -void layout_init(void); - void container_add_child(struct sway_container *parent, struct sway_container *child); diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h new file mode 100644 index 00000000..ada3c73f --- /dev/null +++ b/include/sway/tree/root.h @@ -0,0 +1,57 @@ +#ifndef _SWAY_ROOT_H +#define _SWAY_ROOT_H +#include +#include +#include +#include +#include "sway/tree/container.h" +#include "config.h" +#include "list.h" + +extern struct sway_container root_container; + +struct sway_root { + struct wlr_output_layout *output_layout; + + struct wl_listener output_layout_change; +#ifdef HAVE_XWAYLAND + struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link +#endif + struct wl_list drag_icons; // sway_drag_icon::link + + struct wlr_texture *debug_tree; + + struct wl_list outputs; // sway_output::link + + list_t *scratchpad; // struct sway_container + + struct { + struct wl_signal new_container; + } events; +}; + +void root_create(void); + +void root_destroy(void); + +/** + * Move a container to the scratchpad. + */ +void root_scratchpad_add_container(struct sway_container *con); + +/** + * Remove a container from the scratchpad. + */ +void root_scratchpad_remove_container(struct sway_container *con); + +/** + * Show a single scratchpad container. + */ +void root_scratchpad_show(struct sway_container *con); + +/** + * Hide a single scratchpad container. + */ +void root_scratchpad_hide(struct sway_container *con); + +#endif diff --git a/sway/commands/move.c b/sway/commands/move.c index 1e8b76f9..841da4c4 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -9,10 +9,9 @@ #include "sway/input/cursor.h" #include "sway/input/seat.h" #include "sway/output.h" -#include "sway/scratchpad.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" -#include "sway/tree/layout.h" +#include "sway/tree/root.h" #include "sway/tree/workspace.h" #include "stringop.h" #include "list.h" @@ -324,7 +323,7 @@ static struct cmd_results *move_to_scratchpad(struct sway_container *con) { return cmd_results_new(CMD_INVALID, "move", "Container is already in the scratchpad"); } - scratchpad_add_container(con); + root_scratchpad_add_container(con); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index 01a91d65..0e573aeb 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c @@ -1,8 +1,87 @@ #include "log.h" #include "sway/commands.h" #include "sway/config.h" -#include "sway/scratchpad.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" #include "sway/tree/container.h" +#include "sway/tree/root.h" +#include "sway/tree/workspace.h" + +static void scratchpad_toggle_auto(void) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *ws = focus->type == C_WORKSPACE ? + focus : container_parent(focus, C_WORKSPACE); + + // If the focus is in a floating split container, + // operate on the split container instead of the child. + if (container_is_floating_or_child(focus)) { + while (focus->parent->layout != L_FLOATING) { + focus = focus->parent; + } + } + + + // Check if the currently focused window is a scratchpad window and should + // be hidden again. + if (focus->scratchpad) { + wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", + focus->name); + root_scratchpad_hide(focus); + return; + } + + // Check if there is an unfocused scratchpad window on the current workspace + // and focus it. + for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) { + struct sway_container *floater = + ws->sway_workspace->floating->children->items[i]; + if (floater->scratchpad && focus != floater) { + wlr_log(WLR_DEBUG, + "Focusing other scratchpad window (%s) in this workspace", + floater->name); + root_scratchpad_show(floater); + return; + } + } + + // Check if there is a visible scratchpad window on another workspace. + // In this case we move it to the current workspace. + for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { + struct sway_container *con = + root_container.sway_root->scratchpad->items[i]; + if (con->parent) { + wlr_log(WLR_DEBUG, + "Moving a visible scratchpad window (%s) to this workspace", + con->name); + root_scratchpad_show(con); + return; + } + } + + // Take the container at the bottom of the scratchpad list + if (!sway_assert(root_container.sway_root->scratchpad->length, + "Scratchpad is empty")) { + return; + } + struct sway_container *con = root_container.sway_root->scratchpad->items[0]; + wlr_log(WLR_DEBUG, "Showing %s from list", con->name); + root_scratchpad_show(con); +} + +static void scratchpad_toggle_container(struct sway_container *con) { + if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) { + return; + } + + // Check if it matches a currently visible scratchpad window and hide it. + if (con->parent) { + root_scratchpad_hide(con); + return; + } + + root_scratchpad_show(con); +} struct cmd_results *cmd_scratchpad(int argc, char **argv) { struct cmd_results *error = NULL; diff --git a/sway/main.c b/sway/main.c index c02caf42..d433368b 100644 --- a/sway/main.c +++ b/sway/main.c @@ -407,7 +407,7 @@ int main(int argc, char **argv) { wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION); - layout_init(); + root_create(); if (!server_init(&server)) { return 1; @@ -464,6 +464,7 @@ int main(int argc, char **argv) { wlr_log(WLR_INFO, "Shutting down sway"); server_fini(&server); + root_destroy(); if (config) { free_config(config); diff --git a/sway/meson.build b/sway/meson.build index 17406f6b..c18fb6e2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -7,7 +7,6 @@ sway_sources = files( 'debug-tree.c', 'ipc-json.c', 'ipc-server.c', - 'scratchpad.c', 'security.c', 'swaynag.c', @@ -150,6 +149,7 @@ sway_sources = files( 'tree/arrange.c', 'tree/container.c', 'tree/layout.c', + 'tree/root.c', 'tree/view.c', 'tree/workspace.c', 'tree/output.c', diff --git a/sway/scratchpad.c b/sway/scratchpad.c deleted file mode 100644 index b7d6fd99..00000000 --- a/sway/scratchpad.c +++ /dev/null @@ -1,181 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include "sway/scratchpad.h" -#include "sway/input/seat.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "list.h" -#include "log.h" - -void scratchpad_add_container(struct sway_container *con) { - if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) { - return; - } - con->scratchpad = true; - list_add(root_container.sway_root->scratchpad, con); - - struct sway_container *parent = con->parent; - container_set_floating(con, true); - container_remove_child(con); - arrange_windows(parent); - - struct sway_seat *seat = input_manager_current_seat(input_manager); - seat_set_focus(seat, seat_get_focus_inactive(seat, parent)); -} - -void scratchpad_remove_container(struct sway_container *con) { - if (!sway_assert(con->scratchpad, "Container is not in scratchpad")) { - return; - } - con->scratchpad = false; - for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { - if (root_container.sway_root->scratchpad->items[i] == con) { - list_del(root_container.sway_root->scratchpad, i); - break; - } - } -} - -/** - * Show a single scratchpad container. - * The container might be visible on another workspace already. - */ -static void scratchpad_show(struct sway_container *con) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *ws = seat_get_focus(seat); - if (ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } - - // 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 (ws->sway_workspace->fullscreen) { - container_set_fullscreen(ws->sway_workspace->fullscreen, false); - } - - // Show the container - if (con->parent) { - container_remove_child(con); - } - container_add_child(ws->sway_workspace->floating, con); - - // Make sure the container's center point overlaps this workspace - double center_lx = con->x + con->width / 2; - double center_ly = con->y + con->height / 2; - - struct wlr_box workspace_box; - container_get_box(ws, &workspace_box); - if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { - // Maybe resize it - if (con->width > ws->width || con->height > ws->height) { - container_init_floating(con); - } - - // Center it - double new_lx = ws->x + (ws->width - con->width) / 2; - double new_ly = ws->y + (ws->height - con->height) / 2; - container_floating_move_to(con, new_lx, new_ly); - } - - arrange_windows(ws); - seat_set_focus(seat, seat_get_focus_inactive(seat, con)); - - container_set_dirty(con->parent); -} - -/** - * Hide a single scratchpad container. - * The container might not be the focused container (eg. when using criteria). - */ -static void scratchpad_hide(struct sway_container *con) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *ws = container_parent(con, C_WORKSPACE); - - container_remove_child(con); - arrange_windows(ws); - if (con == focus) { - seat_set_focus(seat, seat_get_focus_inactive(seat, ws)); - } - list_move_to_end(root_container.sway_root->scratchpad, con); -} - -void scratchpad_toggle_auto(void) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *ws = focus->type == C_WORKSPACE ? - focus : container_parent(focus, C_WORKSPACE); - - // If the focus is in a floating split container, - // operate on the split container instead of the child. - if (container_is_floating_or_child(focus)) { - while (focus->parent->layout != L_FLOATING) { - focus = focus->parent; - } - } - - - // Check if the currently focused window is a scratchpad window and should - // be hidden again. - if (focus->scratchpad) { - wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", - focus->name); - scratchpad_hide(focus); - return; - } - - // Check if there is an unfocused scratchpad window on the current workspace - // and focus it. - for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) { - struct sway_container *floater = - ws->sway_workspace->floating->children->items[i]; - if (floater->scratchpad && focus != floater) { - wlr_log(WLR_DEBUG, - "Focusing other scratchpad window (%s) in this workspace", - floater->name); - scratchpad_show(floater); - return; - } - } - - // Check if there is a visible scratchpad window on another workspace. - // In this case we move it to the current workspace. - for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { - struct sway_container *con = - root_container.sway_root->scratchpad->items[i]; - if (con->parent) { - wlr_log(WLR_DEBUG, - "Moving a visible scratchpad window (%s) to this workspace", - con->name); - scratchpad_show(con); - return; - } - } - - // Take the container at the bottom of the scratchpad list - if (!sway_assert(root_container.sway_root->scratchpad->length, - "Scratchpad is empty")) { - return; - } - struct sway_container *con = root_container.sway_root->scratchpad->items[0]; - wlr_log(WLR_DEBUG, "Showing %s from list", con->name); - scratchpad_show(con); -} - -void scratchpad_toggle_container(struct sway_container *con) { - if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) { - return; - } - - // Check if it matches a currently visible scratchpad window and hide it. - if (con->parent) { - scratchpad_hide(con); - return; - } - - scratchpad_show(con); -} diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 5452b13c..494a8461 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -14,8 +14,6 @@ #include "list.h" #include "log.h" -struct sway_container root_container; - static void apply_horiz_layout(struct sway_container *parent) { size_t num_children = parent->children->length; if (!num_children) { diff --git a/sway/tree/container.c b/sway/tree/container.c index 4a503652..6da5ac3c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -17,7 +17,6 @@ #include "sway/input/seat.h" #include "sway/ipc-server.h" #include "sway/output.h" -#include "sway/scratchpad.h" #include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/layout.h" @@ -336,7 +335,6 @@ static struct sway_container *container_destroy_noreaping( // Workspaces will refuse to be destroyed if they're the last workspace // on their output. if (!container_workspace_destroy(con)) { - wlr_log(WLR_ERROR, "workspace doesn't want to destroy"); return NULL; } } @@ -347,7 +345,7 @@ static struct sway_container *container_destroy_noreaping( container_set_dirty(con); if (con->scratchpad) { - scratchpad_remove_container(con); + root_scratchpad_remove_container(con); } if (!con->parent) { @@ -1097,7 +1095,7 @@ void container_set_floating(struct sway_container *container, bool enable) { } else { // Returning to tiled if (container->scratchpad) { - scratchpad_remove_container(container); + root_scratchpad_remove_container(container); } container_remove_child(container); struct sway_container *reference = diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 1f82e534..07de9664 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -19,40 +19,6 @@ #include "list.h" #include "log.h" -struct sway_container root_container; - -static void output_layout_handle_change(struct wl_listener *listener, - void *data) { - arrange_windows(&root_container); - transaction_commit_dirty(); -} - -void layout_init(void) { - root_container.id = 0; // normally assigned in new_swayc() - root_container.type = C_ROOT; - root_container.layout = L_NONE; - root_container.name = strdup("root"); - root_container.instructions = create_list(); - root_container.children = create_list(); - root_container.current.children = create_list(); - wl_signal_init(&root_container.events.destroy); - - root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); - root_container.sway_root->output_layout = wlr_output_layout_create(); - wl_list_init(&root_container.sway_root->outputs); -#ifdef HAVE_XWAYLAND - wl_list_init(&root_container.sway_root->xwayland_unmanaged); -#endif - wl_list_init(&root_container.sway_root->drag_icons); - wl_signal_init(&root_container.sway_root->events.new_container); - root_container.sway_root->scratchpad = create_list(); - - root_container.sway_root->output_layout_change.notify = - output_layout_handle_change; - wl_signal_add(&root_container.sway_root->output_layout->events.change, - &root_container.sway_root->output_layout_change); -} - static int index_child(const struct sway_container *child) { struct sway_container *parent = child->parent; for (int i = 0; i < parent->children->length; ++i) { diff --git a/sway/tree/root.c b/sway/tree/root.c new file mode 100644 index 00000000..9f3965be --- /dev/null +++ b/sway/tree/root.c @@ -0,0 +1,147 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include "sway/input/seat.h" +#include "sway/tree/arrange.h" +#include "sway/tree/container.h" +#include "sway/tree/root.h" +#include "sway/tree/workspace.h" +#include "list.h" +#include "log.h" + +struct sway_container root_container; + +static void output_layout_handle_change(struct wl_listener *listener, + void *data) { + arrange_windows(&root_container); + transaction_commit_dirty(); +} + +void root_create(void) { + root_container.id = 0; // normally assigned in new_swayc() + root_container.type = C_ROOT; + root_container.layout = L_NONE; + root_container.name = strdup("root"); + root_container.instructions = create_list(); + root_container.children = create_list(); + root_container.current.children = create_list(); + wl_signal_init(&root_container.events.destroy); + + root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); + root_container.sway_root->output_layout = wlr_output_layout_create(); + wl_list_init(&root_container.sway_root->outputs); +#ifdef HAVE_XWAYLAND + wl_list_init(&root_container.sway_root->xwayland_unmanaged); +#endif + wl_list_init(&root_container.sway_root->drag_icons); + wl_signal_init(&root_container.sway_root->events.new_container); + root_container.sway_root->scratchpad = create_list(); + + root_container.sway_root->output_layout_change.notify = + output_layout_handle_change; + wl_signal_add(&root_container.sway_root->output_layout->events.change, + &root_container.sway_root->output_layout_change); +} + +void root_destroy(void) { + // sway_root + wl_list_remove(&root_container.sway_root->output_layout_change.link); + list_free(root_container.sway_root->scratchpad); + wlr_output_layout_destroy(root_container.sway_root->output_layout); + free(root_container.sway_root); + + // root_container + list_free(root_container.instructions); + list_free(root_container.children); + list_free(root_container.current.children); + free(root_container.name); + + memset(&root_container, 0, sizeof(root_container)); +} + +void root_scratchpad_add_container(struct sway_container *con) { + if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) { + return; + } + con->scratchpad = true; + list_add(root_container.sway_root->scratchpad, con); + + struct sway_container *parent = con->parent; + container_set_floating(con, true); + container_remove_child(con); + arrange_windows(parent); + + struct sway_seat *seat = input_manager_current_seat(input_manager); + seat_set_focus(seat, seat_get_focus_inactive(seat, parent)); +} + +void root_scratchpad_remove_container(struct sway_container *con) { + if (!sway_assert(con->scratchpad, "Container is not in scratchpad")) { + return; + } + con->scratchpad = false; + for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { + if (root_container.sway_root->scratchpad->items[i] == con) { + list_del(root_container.sway_root->scratchpad, i); + break; + } + } +} + +void root_scratchpad_show(struct sway_container *con) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *ws = seat_get_focus(seat); + if (ws->type != C_WORKSPACE) { + ws = container_parent(ws, C_WORKSPACE); + } + + // 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 (ws->sway_workspace->fullscreen) { + container_set_fullscreen(ws->sway_workspace->fullscreen, false); + } + + // Show the container + if (con->parent) { + container_remove_child(con); + } + container_add_child(ws->sway_workspace->floating, con); + + // Make sure the container's center point overlaps this workspace + double center_lx = con->x + con->width / 2; + double center_ly = con->y + con->height / 2; + + struct wlr_box workspace_box; + container_get_box(ws, &workspace_box); + if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { + // Maybe resize it + if (con->width > ws->width || con->height > ws->height) { + container_init_floating(con); + } + + // Center it + double new_lx = ws->x + (ws->width - con->width) / 2; + double new_ly = ws->y + (ws->height - con->height) / 2; + container_floating_move_to(con, new_lx, new_ly); + } + + arrange_windows(ws); + seat_set_focus(seat, seat_get_focus_inactive(seat, con)); + + container_set_dirty(con->parent); +} + +void root_scratchpad_hide(struct sway_container *con) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *ws = container_parent(con, C_WORKSPACE); + + container_remove_child(con); + arrange_windows(ws); + if (con == focus) { + seat_set_focus(seat, seat_get_focus_inactive(seat, ws)); + } + list_move_to_end(root_container.sway_root->scratchpad, con); +}