From 69e1a421fc2ccecd93f79c9dd0537671138bb0a9 Mon Sep 17 00:00:00 2001
From: Ian Fan <ianfan0@gmail.com>
Date: Tue, 31 Jul 2018 11:38:34 +0100
Subject: commands: complete move implementation

---
 include/sway/tree/view.h | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'include/sway/tree')

diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 37fd02bc..4a3f01e7 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -315,6 +315,11 @@ void view_update_title(struct sway_view *view, bool force);
  */
 void view_execute_criteria(struct sway_view *view);
 
+/**
+ * Find any view that has the given mark and return it.
+ */
+struct sway_view *view_find_mark(char *mark);
+
 /**
  * Find any view that has the given mark and remove the mark from the view.
  * Returns true if it matched a view.
-- 
cgit v1.2.3


From 356063b6c084a7c2d4e3e654fe48ec79a102294b Mon Sep 17 00:00:00 2001
From: Ian Fan <ianfan0@gmail.com>
Date: Wed, 1 Aug 2018 16:03:37 +0100
Subject: commands: fix layout implementation (also better name for previous
 split layout)

---
 include/sway/tree/container.h |  2 +-
 sway/commands/layout.c        | 43 ++++++++++++++++++++++++++-----------------
 sway/tree/layout.c            |  4 ++--
 sway/tree/workspace.c         |  2 +-
 4 files changed, 30 insertions(+), 21 deletions(-)

(limited to 'include/sway/tree')

diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 44ff9f7d..16a180f8 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -113,7 +113,7 @@ struct sway_container {
 
 	enum sway_container_type type;
 	enum sway_container_layout layout;
-	enum sway_container_layout prev_layout;
+	enum sway_container_layout prev_split_layout;
 
 	bool is_sticky;
 
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index ec170591..f4e4dda9 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -42,19 +42,16 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
 		parent = parent->parent;
 	}
 
-	if (strcasecmp(argv[0], "default") == 0) {
-		parent->layout = parent->prev_layout;
-	} else {
-		if (parent->layout != L_TABBED && parent->layout != L_STACKED) {
-			parent->prev_layout = parent->layout;
-		}
-
-		bool assigned_directly = parse_layout_string(argv[0], &parent->layout);
-		if (!assigned_directly && strcasecmp(argv[0], "toggle") == 0) {
+	enum sway_container_layout prev = parent->layout;
+	bool assigned_directly = parse_layout_string(argv[0], &parent->layout);
+	if (!assigned_directly) {
+		if (strcasecmp(argv[0], "default") == 0) {
+			parent->layout = parent->prev_split_layout;
+		} else if (strcasecmp(argv[0], "toggle") == 0) {
 			if (argc == 1) {
 				parent->layout =
 					parent->layout == L_STACKED ? L_TABBED :
-					parent->layout == L_TABBED ? parent->prev_layout : L_STACKED;
+					parent->layout == L_TABBED ? parent->prev_split_layout : L_STACKED;
 			} else if (argc == 2) {
 				if (strcasecmp(argv[1], "all") == 0) {
 					parent->layout =
@@ -62,17 +59,20 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
 						parent->layout == L_VERT ? L_STACKED :
 						parent->layout == L_STACKED ? L_TABBED : L_HORIZ;
 				} else if (strcasecmp(argv[1], "split") == 0) {
-					parent->layout = parent->layout == L_VERT ? L_HORIZ : L_VERT;
+					parent->layout =
+						parent->layout == L_HORIZ ? L_VERT :
+						parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout;
 				} else {
 					return cmd_results_new(CMD_INVALID, "layout", expected_syntax);
 				}
 			} else {
-				bool valid;
 				enum sway_container_layout parsed_layout;
 				int curr = 1;
 				for (; curr < argc; curr++) {
-					valid = parse_layout_string(argv[curr], &parsed_layout);
-					if (valid && parsed_layout == parent->layout) {
+					bool valid = parse_layout_string(argv[curr], &parsed_layout);
+					if ((valid && parsed_layout == parent->layout) ||
+							(strcmp(argv[curr], "split") == 0 &&
+							(parent->layout == L_VERT || parent->layout == L_HORIZ))) {
 						break;
 					}
 				}
@@ -83,6 +83,11 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
 					}
 					if (parse_layout_string(argv[i], &parent->layout)) {
 						break;
+					} else if (strcmp(argv[i], "split") == 0) {
+						parent->layout =
+							parent->layout == L_HORIZ ? L_VERT :
+							parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout;
+						break;
 					} // invalid layout strings are silently ignored
 				}
 			}
@@ -93,9 +98,13 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
 	if (parent->layout == L_NONE) {
 		parent->layout = container_get_default_layout(parent);
 	}
-
-	container_notify_subtree_changed(parent);
-	arrange_windows(parent);
+	if (prev != parent->layout) {
+		if (prev != L_TABBED && prev != L_STACKED) {
+			parent->prev_split_layout = prev;
+		}
+		container_notify_subtree_changed(parent);
+		arrange_windows(parent);
+	}
 
 	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 }
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 07de9664..28cdc71e 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -859,7 +859,7 @@ struct sway_container *container_split(struct sway_container *child,
 	}
 	if (child->type == C_WORKSPACE && child->children->length == 0) {
 		// Special case: this just behaves like splitt
-		child->prev_layout = child->layout;
+		child->prev_split_layout = child->layout;
 		child->layout = layout;
 		return child;
 	}
@@ -870,7 +870,7 @@ struct sway_container *container_split(struct sway_container *child,
 
 	remove_gaps(child);
 
-	cont->prev_layout = L_NONE;
+	cont->prev_split_layout = L_NONE;
 	cont->width = child->width;
 	cont->height = child->height;
 	cont->x = child->x;
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index cc225e79..250d5ba7 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -59,7 +59,7 @@ struct sway_container *workspace_create(struct sway_container *output,
 	workspace->width = output->width;
 	workspace->height = output->height;
 	workspace->name = !name ? NULL : strdup(name);
-	workspace->prev_layout = L_NONE;
+	workspace->prev_split_layout = L_NONE;
 	workspace->layout = container_get_default_layout(output);
 
 	struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace));
-- 
cgit v1.2.3


From 85ae121caad02265b95ecea66fa864607575eb31 Mon Sep 17 00:00:00 2001
From: Ian Fan <ianfan0@gmail.com>
Date: Sun, 5 Aug 2018 00:05:48 +0100
Subject: commands: complete workspace implementation

Allow optional --no-auto-back-and-forth flag, as well as refactoring some logic
---
 include/sway/tree/workspace.h |  4 +++-
 sway/commands/workspace.c     | 54 ++++++++++++++++++-------------------------
 sway/sway.5.scd               |  5 +++-
 sway/tree/workspace.c         | 42 ++++++++++++++++++++++-----------
 4 files changed, 59 insertions(+), 46 deletions(-)

(limited to 'include/sway/tree')

diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index 3337f2c8..239cbbdb 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -1,6 +1,7 @@
 #ifndef _SWAY_WORKSPACE_H
 #define _SWAY_WORKSPACE_H
 
+#include <stdbool.h>
 #include "sway/tree/container.h"
 
 struct sway_view;
@@ -17,7 +18,8 @@ extern char *prev_workspace_name;
 
 char *workspace_next_name(const char *output_name);
 
-bool workspace_switch(struct sway_container *workspace);
+bool workspace_switch(struct sway_container *workspace,
+		bool no_auto_back_and_forth);
 
 struct sway_container *workspace_by_number(const char* name);
 
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index e8b37182..f32ede1e 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -17,17 +17,6 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
 
 	int output_location = -1;
 
-	struct sway_container *current_container = config->handler_context.current_container;
-	struct sway_container *old_workspace = NULL, *old_output = NULL;
-	if (current_container) {
-		if (current_container->type == C_WORKSPACE) {
-			old_workspace = current_container;
-		} else {
-			old_workspace = container_parent(current_container, C_WORKSPACE);
-		}
-		old_output = container_parent(current_container, C_OUTPUT);
-	}
-
 	for (int i = 0; i < argc; ++i) {
 		if (strcasecmp(argv[i], "output") == 0) {
 			output_location = i;
@@ -57,39 +46,42 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
 		if (config->reading || !config->active) {
 			return cmd_results_new(CMD_DEFER, "workspace", NULL);
 		}
+
+		bool no_auto_back_and_forth = false;
+		while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) {
+			no_auto_back_and_forth = true;
+			if ((error = checkarg(--argc, "workspace", EXPECTED_AT_LEAST, 1))) {
+				return error;
+			}
+			++argv;
+		}
+
+
 		struct sway_container *ws = NULL;
 		if (strcasecmp(argv[0], "number") == 0) {
+			if (argc < 2) {
+				cmd_results_new(CMD_INVALID, "workspace",
+						"Expected workspace number");
+			}
 			if (!(ws = workspace_by_number(argv[1]))) {
 				char *name = join_args(argv + 1, argc - 1);
 				ws = workspace_create(NULL, name);
 				free(name);
 			}
-		} else if (strcasecmp(argv[0], "next") == 0) {
-			ws = workspace_next(old_workspace);
-		} else if (strcasecmp(argv[0], "prev") == 0) {
-			ws = workspace_prev(old_workspace);
-		} else if (strcasecmp(argv[0], "next_on_output") == 0) {
-			ws = workspace_output_next(old_output);
-		} else if (strcasecmp(argv[0], "prev_on_output") == 0) {
-			ws = workspace_output_prev(old_output);
-		} else if (strcasecmp(argv[0], "back_and_forth") == 0) {
-			// if auto_back_and_forth is enabled, workspace_switch will swap
-			// the workspaces. If we created prev_workspace here, workspace_switch
-			// would put us back on original workspace.
-			if (config->auto_back_and_forth) {
-				ws = old_workspace;
-			} else if (prev_workspace_name
-					&& !(ws = workspace_by_name(prev_workspace_name))) {
-				ws = workspace_create(NULL, prev_workspace_name);
-			}
 		} else {
 			char *name = join_args(argv, argc);
 			if (!(ws = workspace_by_name(name))) {
-				ws = workspace_create(NULL, name);
+				if (strcasecmp(argv[0], "back_and_forth") == 0) {
+					if (prev_workspace_name) {
+						ws = workspace_create(NULL, prev_workspace_name);
+					}
+				} else {
+					ws = workspace_create(NULL, name);
+				}
 			}
 			free(name);
 		}
-		workspace_switch(ws);
+		workspace_switch(ws, no_auto_back_and_forth);
 	}
 	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 }
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 8083106b..36ce13df 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -526,7 +526,7 @@ config after the others, or it will be matched instead of the others.
 	state. Using _allow_ or _deny_ controls the window's ability to set itself
 	as urgent. By default, windows are allowed to set their own urgency.
 
-*workspace* [number] <name>
+*workspace* [--no-auto-back-and-forth] [number] <name>
 	Switches to the specified workspace. The string "number" is optional and is
 	used to sort workspaces.
 
@@ -537,6 +537,9 @@ config after the others, or it will be matched instead of the others.
 *workspace* prev\_on\_output|next\_on\_output
 	Switches to the next workspace on the current output.
 
+*workspace* back_and_forth
+	Switches to the previously focused workspace.
+
 *workspace* <name> output <output>
 	Specifies that workspace _name_ should be shown on the specified _output_.
 
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 250d5ba7..5e20429b 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -250,20 +250,35 @@ struct sway_container *workspace_by_name(const char *name) {
 		current_workspace = container_parent(focus, C_WORKSPACE);
 		current_output = container_parent(focus, C_OUTPUT);
 	}
-	if (strcmp(name, "prev") == 0) {
-		return workspace_prev(current_workspace);
-	} else if (strcmp(name, "prev_on_output") == 0) {
-		return workspace_output_prev(current_output);
-	} else if (strcmp(name, "next") == 0) {
-		return workspace_next(current_workspace);
-	} else if (strcmp(name, "next_on_output") == 0) {
-		return workspace_output_next(current_output);
-	} else if (strcmp(name, "current") == 0) {
-		return current_workspace;
+
+	char *name_cpy = strdup(name);
+	char *first_word = strtok(name_cpy, " ");
+	if (first_word == NULL) {
+		first_word = name_cpy;
+	}
+
+	struct sway_container *ws = NULL;
+	if (strcmp(first_word, "prev") == 0) {
+		ws = workspace_prev(current_workspace);
+	} else if (strcmp(first_word, "prev_on_output") == 0) {
+		ws = workspace_output_prev(current_output);
+	} else if (strcmp(first_word, "next") == 0) {
+		ws = workspace_next(current_workspace);
+	} else if (strcmp(first_word, "next_on_output") == 0) {
+		ws = workspace_output_next(current_output);
+	} else if (strcmp(first_word, "current") == 0) {
+		ws = current_workspace;
+	} else if (strcasecmp(first_word, "back_and_forth") == 0) {
+		if (prev_workspace_name) {
+			ws = container_find(&root_container, _workspace_by_name,
+				(void *)prev_workspace_name);
+		}
 	} else {
-		return container_find(&root_container, _workspace_by_name,
+		ws = container_find(&root_container, _workspace_by_name,
 				(void *)name);
 	}
+	free(name_cpy);
+	return ws;
 }
 
 /**
@@ -364,7 +379,8 @@ struct sway_container *workspace_prev(struct sway_container *current) {
 	return workspace_prev_next_impl(current, false);
 }
 
-bool workspace_switch(struct sway_container *workspace) {
+bool workspace_switch(struct sway_container *workspace,
+		bool no_auto_back_and_forth) {
 	if (!workspace) {
 		return false;
 	}
@@ -379,7 +395,7 @@ bool workspace_switch(struct sway_container *workspace) {
 		active_ws = container_parent(focus, C_WORKSPACE);
 	}
 
-	if (config->auto_back_and_forth
+	if (!no_auto_back_and_forth && config->auto_back_and_forth
 			&& active_ws == workspace
 			&& prev_workspace_name) {
 		struct sway_container *new_ws = workspace_by_name(prev_workspace_name);
-- 
cgit v1.2.3


From 9d578e0a0f08e053dfc1982e32d9fda172b0087f Mon Sep 17 00:00:00 2001
From: emersion <contact@emersion.fr>
Date: Sun, 29 Jul 2018 18:31:10 +0100
Subject: Handle views created after decoration mode is sent for xdg-shell

---
 include/sway/decoration.h |  4 ++++
 include/sway/server.h     |  1 +
 include/sway/tree/view.h  |  4 ++++
 sway/decoration.c         | 34 ++++++++++++++++++++++++++++++++--
 sway/desktop/xdg_shell.c  | 19 +++++++++++++++++++
 sway/server.c             |  3 +--
 6 files changed, 61 insertions(+), 4 deletions(-)

(limited to 'include/sway/tree')

diff --git a/include/sway/decoration.h b/include/sway/decoration.h
index c77c04c7..7916746e 100644
--- a/include/sway/decoration.h
+++ b/include/sway/decoration.h
@@ -5,9 +5,13 @@
 
 struct sway_server_decoration {
 	struct wlr_server_decoration *wlr_server_decoration;
+	struct wl_list link;
 
 	struct wl_listener destroy;
 	struct wl_listener mode;
 };
 
+struct sway_server_decoration *decoration_from_surface(
+	struct wlr_surface *surface);
+
 #endif
diff --git a/include/sway/server.h b/include/sway/server.h
index 7e73fb4f..b93584b6 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -52,6 +52,7 @@ struct sway_server {
 
 	struct wlr_server_decoration_manager *server_decoration_manager;
 	struct wl_listener server_decoration;
+	struct wl_list decorations; // sway_server_decoration::link
 
 	bool debug_txn_timings;
 
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 37fd02bc..e91d2a20 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -118,6 +118,8 @@ struct sway_view {
 struct sway_xdg_shell_v6_view {
 	struct sway_view view;
 
+	enum wlr_server_decoration_manager_mode deco_mode;
+
 	struct wl_listener commit;
 	struct wl_listener request_move;
 	struct wl_listener request_resize;
@@ -134,6 +136,8 @@ struct sway_xdg_shell_v6_view {
 struct sway_xdg_shell_view {
 	struct sway_view view;
 
+	enum wlr_server_decoration_manager_mode deco_mode;
+
 	struct wl_listener commit;
 	struct wl_listener request_move;
 	struct wl_listener request_resize;
diff --git a/sway/decoration.c b/sway/decoration.c
index 73b3f45d..0e3e67ac 100644
--- a/sway/decoration.c
+++ b/sway/decoration.c
@@ -9,6 +9,8 @@ static void server_decoration_handle_destroy(struct wl_listener *listener,
 	struct sway_server_decoration *deco =
 		wl_container_of(listener, deco, destroy);
 	wl_list_remove(&deco->destroy.link);
+	wl_list_remove(&deco->mode.link);
+	wl_list_remove(&deco->link);
 	free(deco);
 }
 
@@ -18,9 +20,24 @@ static void server_decoration_handle_mode(struct wl_listener *listener,
 		wl_container_of(listener, deco, mode);
 	struct sway_view *view =
 		view_from_wlr_surface(deco->wlr_server_decoration->surface);
+	if (view == NULL || view->surface != deco->wlr_server_decoration->surface) {
+		return;
+	}
 
-	// TODO
-	wlr_log(WLR_ERROR, "%p %d", view, deco->wlr_server_decoration->mode);
+	switch (view->type) {
+	case SWAY_VIEW_XDG_SHELL_V6:;
+		struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
+			(struct sway_xdg_shell_v6_view *)view;
+		xdg_shell_v6_view->deco_mode = deco->wlr_server_decoration->mode;
+		break;
+	case SWAY_VIEW_XDG_SHELL:;
+		struct sway_xdg_shell_view *xdg_shell_view =
+			(struct sway_xdg_shell_view *)view;
+		xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode;
+		break;
+	default:
+		break;
+	}
 }
 
 void handle_server_decoration(struct wl_listener *listener, void *data) {
@@ -38,4 +55,17 @@ void handle_server_decoration(struct wl_listener *listener, void *data) {
 
 	wl_signal_add(&wlr_deco->events.mode, &deco->mode);
 	deco->mode.notify = server_decoration_handle_mode;
+
+	wl_list_insert(&server.decorations, &deco->link);
+}
+
+struct sway_server_decoration *decoration_from_surface(
+		struct wlr_surface *surface) {
+	struct sway_server_decoration *deco;
+	wl_list_for_each(deco, &server.decorations, link) {
+		if (deco->wlr_server_decoration->surface == surface) {
+			return deco;
+		}
+	}
+	return NULL;
 }
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index b364663d..3b73f99c 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -6,6 +6,7 @@
 #include <wlr/types/wlr_xdg_shell.h>
 #include <wlr/util/edges.h>
 #include "log.h"
+#include "sway/decoration.h"
 #include "sway/input/input-manager.h"
 #include "sway/input/seat.h"
 #include "sway/server.h"
@@ -170,6 +171,15 @@ static bool wants_floating(struct sway_view *view) {
 		|| toplevel->parent;
 }
 
+static bool has_client_side_decorations(struct sway_view *view) {
+	struct sway_xdg_shell_view *xdg_shell_view =
+		xdg_shell_view_from_view(view);
+	if (xdg_shell_view == NULL) {
+		return true;
+	}
+	return xdg_shell_view->deco_mode != WLR_SERVER_DECORATION_MANAGER_MODE_SERVER;
+}
+
 static void for_each_surface(struct sway_view *view,
 		wlr_surface_iterator_func_t iterator, void *user_data) {
 	if (xdg_shell_view_from_view(view) == NULL) {
@@ -226,6 +236,7 @@ static const struct sway_view_impl view_impl = {
 	.set_tiled = set_tiled,
 	.set_fullscreen = set_fullscreen,
 	.wants_floating = wants_floating,
+	.has_client_side_decorations = has_client_side_decorations,
 	.for_each_surface = for_each_surface,
 	.for_each_popup = for_each_popup,
 	.close = _close,
@@ -357,6 +368,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
 		view->natural_height = view->wlr_xdg_surface->surface->current.height;
 	}
 
+	struct sway_server_decoration *deco =
+		decoration_from_surface(xdg_surface->surface);
+	if (deco != NULL) {
+		xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode;
+	} else {
+		xdg_shell_view->deco_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
+	}
+
 	view_map(view, view->wlr_xdg_surface->surface);
 
 	if (xdg_surface->toplevel->client_pending.fullscreen) {
diff --git a/sway/server.c b/sway/server.c
index bf6255bc..e8dc63be 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -19,7 +19,6 @@
 #include <wlr/types/wlr_xcursor_manager.h>
 #include <wlr/types/wlr_xdg_output.h>
 #include <wlr/util/log.h>
-// TODO WLR: make Xwayland optional
 #include "list.h"
 #include "sway/config.h"
 #include "sway/desktop/idle_inhibit_v1.h"
@@ -85,7 +84,6 @@ bool server_init(struct sway_server *server) {
 		&server->xdg_shell_surface);
 	server->xdg_shell_surface.notify = handle_xdg_shell_surface;
 
-	// TODO make xwayland optional
 #ifdef HAVE_XWAYLAND
 	server->xwayland.wlr_xwayland =
 		wlr_xwayland_create(server->wl_display, server->compositor, true);
@@ -117,6 +115,7 @@ bool server_init(struct sway_server *server) {
 	wl_signal_add(&server->server_decoration_manager->events.new_decoration,
 		&server->server_decoration);
 	server->server_decoration.notify = handle_server_decoration;
+	wl_list_init(&server->decorations);
 
 	wlr_linux_dmabuf_v1_create(server->wl_display, renderer);
 	wlr_export_dmabuf_manager_v1_create(server->wl_display);
-- 
cgit v1.2.3