From 04489ff4209dc073027419d90961367cfb998fe8 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Fri, 3 Aug 2018 23:06:01 +1000
Subject: 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 <wlr/types/wlr_output_layout.h>
 #include <wlr/render/wlr_texture.h>
 #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 <wayland-server-core.h>
+#include <wayland-util.h>
+#include <wlr/types/wlr_output_layout.h>
+#include <wlr/render/wlr_texture.h>
+#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 <stdlib.h>
-#include <stdio.h>
-#include <stdbool.h>
-#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 <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wlr/types/wlr_output_layout.h>
+#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);
+}
-- 
cgit v1.2.3