summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-04-04 00:26:31 -0400
committerLibravatar GitHub <noreply@github.com>2018-04-04 00:26:31 -0400
commitdee71871d7a37cfa1e53f3f1f60e6e93d21beda4 (patch)
tree1565ba1fede2da35b170353f895c34205216dc38
parentMerge pull request #1722 from swaywm/swaybar-hidpi (diff)
parentfix double free (diff)
downloadsway-dee71871d7a37cfa1e53f3f1f60e6e93d21beda4.tar.gz
sway-dee71871d7a37cfa1e53f3f1f60e6e93d21beda4.tar.zst
sway-dee71871d7a37cfa1e53f3f1f60e6e93d21beda4.zip
Merge pull request #1702 from acrisci/split-containers2
properly close container containers
-rw-r--r--include/sway/tree/container.h22
-rw-r--r--include/sway/tree/layout.h17
-rw-r--r--include/sway/tree/output.h0
-rw-r--r--include/sway/tree/workspace.h2
-rw-r--r--sway/commands/kill.c17
-rw-r--r--sway/commands/layout.c3
-rw-r--r--sway/commands/move.c2
-rw-r--r--sway/commands/workspace.c6
-rw-r--r--sway/config/output.c5
-rw-r--r--sway/desktop/output.c17
-rw-r--r--sway/input/seat.c2
-rw-r--r--sway/meson.build2
-rw-r--r--sway/tree/container.c273
-rw-r--r--sway/tree/layout.c56
-rw-r--r--sway/tree/output.c96
-rw-r--r--sway/tree/view.c17
-rw-r--r--sway/tree/workspace.c124
17 files changed, 358 insertions, 303 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 464f80c4..277165ea 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -91,13 +91,11 @@ struct sway_container {
91 } events; 91 } events;
92}; 92};
93 93
94// TODO make private and use the container-specific create functions
95struct sway_container *container_create(enum sway_container_type type); 94struct sway_container *container_create(enum sway_container_type type);
96 95
97const char *container_type_to_str(enum sway_container_type type); 96const char *container_type_to_str(enum sway_container_type type);
98 97
99// TODO only one container create function and pass the type? 98struct sway_container *output_create(
100struct sway_container *container_output_create(
101 struct sway_output *sway_output); 99 struct sway_output *sway_output);
102 100
103/** 101/**
@@ -110,35 +108,26 @@ struct sway_container *container_container_create();
110 * Create a new output. Outputs are children of the root container and have no 108 * Create a new output. Outputs are children of the root container and have no
111 * order in the tree structure. 109 * order in the tree structure.
112 */ 110 */
113struct sway_container *container_output_create(struct sway_output *sway_output); 111struct sway_container *output_create(struct sway_output *sway_output);
114 112
115/** 113/**
116 * Create a new workspace container. Workspaces are children of an output 114 * Create a new workspace container. Workspaces are children of an output
117 * container and are ordered alphabetically by name. 115 * container and are ordered alphabetically by name.
118 */ 116 */
119struct sway_container *container_workspace_create(struct sway_container *output, const char *name); 117struct sway_container *workspace_create(struct sway_container *output, const char *name);
120 118
121/* 119/*
122 * Create a new view container. A view can be a child of a workspace container 120 * Create a new view container. A view can be a child of a workspace container
123 * or a container container and are rendered in the order and structure of 121 * or a container container and are rendered in the order and structure of
124 * how they are attached to the tree. 122 * how they are attached to the tree.
125 */ 123 */
126// TODO view containers should be created in a detached state.
127struct sway_container *container_view_create( 124struct sway_container *container_view_create(
128 struct sway_container *sibling, struct sway_view *sway_view); 125 struct sway_container *sibling, struct sway_view *sway_view);
129 126
130// TODO don't return the parent on destroy
131struct sway_container *container_destroy(struct sway_container *container); 127struct sway_container *container_destroy(struct sway_container *container);
132 128
133struct sway_container *container_workspace_destroy(struct sway_container *container); 129struct sway_container *container_close(struct sway_container *container);
134struct sway_container *container_output_destroy(struct sway_container *container);
135struct sway_container *container_view_destroy(struct sway_container *container);
136 130
137// TODO move to layout.c
138struct sway_container *container_set_layout(struct sway_container *container,
139 enum sway_container_layout layout);
140
141// TODO rename to container_descendants_for_each()
142void container_descendants(struct sway_container *root, 131void container_descendants(struct sway_container *root,
143 enum sway_container_type type, 132 enum sway_container_type type,
144 void (*func)(struct sway_container *item, void *data), void *data); 133 void (*func)(struct sway_container *item, void *data), void *data);
@@ -153,7 +142,6 @@ struct sway_container *container_find(struct sway_container *container,
153/** 142/**
154 * Finds a parent container with the given struct sway_containerype. 143 * Finds a parent container with the given struct sway_containerype.
155 */ 144 */
156// TODO rename to container_parent_of_type()
157struct sway_container *container_parent(struct sway_container *container, 145struct sway_container *container_parent(struct sway_container *container,
158 enum sway_container_type type); 146 enum sway_container_type type);
159 147
@@ -190,4 +178,6 @@ bool container_has_anscestor(struct sway_container *container,
190bool container_has_child(struct sway_container *con, 178bool container_has_child(struct sway_container *con,
191 struct sway_container *child); 179 struct sway_container *child);
192 180
181void container_create_notify(struct sway_container *container);
182
193#endif 183#endif
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h
index 8badb244..784dcc9b 100644
--- a/include/sway/tree/layout.h
+++ b/include/sway/tree/layout.h
@@ -29,42 +29,37 @@ struct sway_root {
29 29
30void layout_init(void); 30void layout_init(void);
31 31
32// TODO move to tree.h
33void container_add_child(struct sway_container *parent, 32void container_add_child(struct sway_container *parent,
34 struct sway_container *child); 33 struct sway_container *child);
35 34
36// TODO move to tree.h
37struct sway_container *container_add_sibling(struct sway_container *parent, 35struct sway_container *container_add_sibling(struct sway_container *parent,
38 struct sway_container *child); 36 struct sway_container *child);
39 37
40// TODO move to tree.h
41struct sway_container *container_remove_child(struct sway_container *child); 38struct sway_container *container_remove_child(struct sway_container *child);
42 39
43// TODO PRIVATE in tree.h 40struct sway_container *container_replace_child(struct sway_container *child,
44struct sway_container *container_reap_empty(struct sway_container *container); 41 struct sway_container *new_child);
42
43struct sway_container *container_set_layout(struct sway_container *container,
44 enum sway_container_layout layout);
45 45
46// TODO move to tree.h
47void container_move_to(struct sway_container* container, 46void container_move_to(struct sway_container* container,
48 struct sway_container* destination); 47 struct sway_container* destination);
49 48
50void container_move(struct sway_container *container, 49void container_move(struct sway_container *container,
51 enum movement_direction dir, int move_amt); 50 enum movement_direction dir, int move_amt);
52 51
53// TODO move to output.c
54enum sway_container_layout container_get_default_layout( 52enum sway_container_layout container_get_default_layout(
55 struct sway_container *output); 53 struct sway_container *con);
56 54
57// TODO move to output.c
58void container_sort_workspaces(struct sway_container *output); 55void container_sort_workspaces(struct sway_container *output);
59 56
60void arrange_windows(struct sway_container *container, 57void arrange_windows(struct sway_container *container,
61 double width, double height); 58 double width, double height);
62 59
63// TODO move to container.h
64struct sway_container *container_get_in_direction(struct sway_container 60struct sway_container *container_get_in_direction(struct sway_container
65 *container, struct sway_seat *seat, enum movement_direction dir); 61 *container, struct sway_seat *seat, enum movement_direction dir);
66 62
67// TODO move to tree.h
68struct sway_container *container_split(struct sway_container *child, 63struct sway_container *container_split(struct sway_container *child,
69 enum sway_container_layout layout); 64 enum sway_container_layout layout);
70 65
diff --git a/include/sway/tree/output.h b/include/sway/tree/output.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/include/sway/tree/output.h
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index 4e4c3450..8d49fefb 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -7,8 +7,6 @@ extern char *prev_workspace_name;
7 7
8char *workspace_next_name(const char *output_name); 8char *workspace_next_name(const char *output_name);
9 9
10struct sway_container *workspace_create(const char *name);
11
12bool workspace_switch(struct sway_container *workspace); 10bool workspace_switch(struct sway_container *workspace);
13 11
14struct sway_container *workspace_by_number(const char* name); 12struct sway_container *workspace_by_number(const char* name);
diff --git a/sway/commands/kill.c b/sway/commands/kill.c
index 46d6e98e..f3fa52f1 100644
--- a/sway/commands/kill.c
+++ b/sway/commands/kill.c
@@ -10,22 +10,7 @@ struct cmd_results *cmd_kill(int argc, char **argv) {
10 struct sway_container *con = 10 struct sway_container *con =
11 config->handler_context.current_container; 11 config->handler_context.current_container;
12 12
13 switch (con->type) { 13 container_close(con);
14 case C_ROOT:
15 case C_OUTPUT:
16 case C_WORKSPACE:
17 case C_TYPES:
18 return cmd_results_new(CMD_INVALID, NULL,
19 "Can only kill views and containers with this command");
20 break;
21 case C_CONTAINER:
22 con = container_destroy(con);
23 arrange_windows(con, -1, -1);
24 break;
25 case C_VIEW:
26 view_close(con->sway_view);
27 break;
28 }
29 14
30 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 15 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
31} 16}
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index ebab2a48..4c49a627 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -28,8 +28,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
28 if (strcasecmp(argv[0], "default") == 0) { 28 if (strcasecmp(argv[0], "default") == 0) {
29 container_set_layout(parent, parent->prev_layout); 29 container_set_layout(parent, parent->prev_layout);
30 if (parent->layout == L_NONE) { 30 if (parent->layout == L_NONE) {
31 struct sway_container *output = container_parent(parent, C_OUTPUT); 31 container_set_layout(parent, container_get_default_layout(parent));
32 container_set_layout(parent, container_get_default_layout(output));
33 } 32 }
34 } else { 33 } else {
35 if (parent->layout != L_TABBED && parent->layout != L_STACKED) { 34 if (parent->layout != L_TABBED && parent->layout != L_STACKED) {
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 644c622b..c954ab94 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -74,7 +74,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
74 ws = workspace_by_name(ws_name); 74 ws = workspace_by_name(ws_name);
75 } 75 }
76 if (!ws) { 76 if (!ws) {
77 ws = workspace_create(ws_name ? ws_name : num_name); 77 ws = workspace_create(NULL, ws_name ? ws_name : num_name);
78 } 78 }
79 free(ws_name); 79 free(ws_name);
80 struct sway_container *old_parent = current->parent; 80 struct sway_container *old_parent = current->parent;
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index aa4096f7..958b3222 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -61,7 +61,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
61 if (strcasecmp(argv[0], "number") == 0) { 61 if (strcasecmp(argv[0], "number") == 0) {
62 if (!(ws = workspace_by_number(argv[1]))) { 62 if (!(ws = workspace_by_number(argv[1]))) {
63 char *name = join_args(argv + 1, argc - 1); 63 char *name = join_args(argv + 1, argc - 1);
64 ws = workspace_create(name); 64 ws = workspace_create(NULL, name);
65 free(name); 65 free(name);
66 } 66 }
67 } else if (strcasecmp(argv[0], "next") == 0) { 67 } else if (strcasecmp(argv[0], "next") == 0) {
@@ -80,12 +80,12 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
80 ws = old_workspace; 80 ws = old_workspace;
81 } else if (prev_workspace_name 81 } else if (prev_workspace_name
82 && !(ws = workspace_by_name(prev_workspace_name))) { 82 && !(ws = workspace_by_name(prev_workspace_name))) {
83 ws = workspace_create(prev_workspace_name); 83 ws = workspace_create(NULL, prev_workspace_name);
84 } 84 }
85 } else { 85 } else {
86 char *name = join_args(argv, argc); 86 char *name = join_args(argv, argc);
87 if (!(ws = workspace_by_name(name))) { 87 if (!(ws = workspace_by_name(name))) {
88 ws = workspace_create(name); 88 ws = workspace_create(NULL, name);
89 } 89 }
90 free(name); 90 free(name);
91 } 91 }
diff --git a/sway/config/output.c b/sway/config/output.c
index 6d832cbc..1c298d37 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -128,8 +128,9 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
128 struct wlr_output *wlr_output = output->sway_output->wlr_output; 128 struct wlr_output *wlr_output = output->sway_output->wlr_output;
129 129
130 if (oc && oc->enabled == 0) { 130 if (oc && oc->enabled == 0) {
131 container_output_destroy(output); 131 container_destroy(output);
132 wlr_output_layout_remove(output_layout, wlr_output); 132 wlr_output_layout_remove(root_container.sway_root->output_layout,
133 wlr_output);
133 return; 134 return;
134 } 135 }
135 136
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 4b407f41..8a4fb4a2 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -2,6 +2,7 @@
2#include <assert.h> 2#include <assert.h>
3#include <stdlib.h> 3#include <stdlib.h>
4#include <time.h> 4#include <time.h>
5#include <strings.h>
5#include <wayland-server.h> 6#include <wayland-server.h>
6#include <wlr/render/wlr_renderer.h> 7#include <wlr/render/wlr_renderer.h>
7#include <wlr/types/wlr_box.h> 8#include <wlr/types/wlr_box.h>
@@ -21,6 +22,16 @@
21#include "sway/tree/layout.h" 22#include "sway/tree/layout.h"
22#include "sway/tree/view.h" 23#include "sway/tree/view.h"
23 24
25struct sway_container *output_by_name(const char *name) {
26 for (int i = 0; i < root_container.children->length; ++i) {
27 struct sway_container *output = root_container.children->items[i];
28 if (strcasecmp(output->name, name) == 0) {
29 return output;
30 }
31 }
32 return NULL;
33}
34
24/** 35/**
25 * Rotate a child's position relative to a parent. The parent size is (pw, ph), 36 * Rotate a child's position relative to a parent. The parent size is (pw, ph),
26 * the child position is (*sx, *sy) and its size is (sw, sh). 37 * the child position is (*sx, *sy) and its size is (sw, sh).
@@ -334,12 +345,12 @@ void output_damage_whole_view(struct sway_output *output,
334static void damage_handle_destroy(struct wl_listener *listener, void *data) { 345static void damage_handle_destroy(struct wl_listener *listener, void *data) {
335 struct sway_output *output = 346 struct sway_output *output =
336 wl_container_of(listener, output, damage_destroy); 347 wl_container_of(listener, output, damage_destroy);
337 container_output_destroy(output->swayc); 348 container_destroy(output->swayc);
338} 349}
339 350
340static void handle_destroy(struct wl_listener *listener, void *data) { 351static void handle_destroy(struct wl_listener *listener, void *data) {
341 struct sway_output *output = wl_container_of(listener, output, destroy); 352 struct sway_output *output = wl_container_of(listener, output, destroy);
342 container_output_destroy(output->swayc); 353 container_destroy(output->swayc);
343} 354}
344 355
345static void handle_mode(struct wl_listener *listener, void *data) { 356static void handle_mode(struct wl_listener *listener, void *data) {
@@ -381,7 +392,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
381 392
382 output->damage = wlr_output_damage_create(wlr_output); 393 output->damage = wlr_output_damage_create(wlr_output);
383 394
384 output->swayc = container_output_create(output); 395 output->swayc = output_create(output);
385 if (!output->swayc) { 396 if (!output->swayc) {
386 free(output); 397 free(output);
387 return; 398 return;
diff --git a/sway/input/seat.c b/sway/input/seat.c
index cf519a82..4a99e9eb 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -384,7 +384,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
384 if (last_ws) { 384 if (last_ws) {
385 ipc_event_workspace(last_ws, container, "focus"); 385 ipc_event_workspace(last_ws, container, "focus");
386 if (last_ws->children->length == 0) { 386 if (last_ws->children->length == 0) {
387 container_workspace_destroy(last_ws); 387 container_destroy(last_ws);
388 } 388 }
389 } 389 }
390 struct sway_container *last_output = last_focus; 390 struct sway_container *last_output = last_focus;
diff --git a/sway/meson.build b/sway/meson.build
index a6a633a0..91aab0a0 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -86,9 +86,9 @@ sway_sources = files(
86 'security.c', 86 'security.c',
87 'tree/container.c', 87 'tree/container.c',
88 'tree/layout.c', 88 'tree/layout.c',
89 'tree/output.c',
90 'tree/view.c', 89 'tree/view.c',
91 'tree/workspace.c', 90 'tree/workspace.c',
91 'tree/output.c',
92) 92)
93 93
94sway_deps = [ 94sway_deps = [
diff --git a/sway/tree/container.c b/sway/tree/container.c
index c686401c..eaf4c117 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -1,4 +1,5 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h>
2#include <stdint.h> 3#include <stdint.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <string.h> 5#include <string.h>
@@ -6,7 +7,6 @@
6#include <wayland-server.h> 7#include <wayland-server.h>
7#include <wlr/types/wlr_output_layout.h> 8#include <wlr/types/wlr_output_layout.h>
8#include <wlr/types/wlr_wl_shell.h> 9#include <wlr/types/wlr_wl_shell.h>
9#include "log.h"
10#include "sway/config.h" 10#include "sway/config.h"
11#include "sway/input/input-manager.h" 11#include "sway/input/input-manager.h"
12#include "sway/input/seat.h" 12#include "sway/input/seat.h"
@@ -50,7 +50,7 @@ const char *container_type_to_str(enum sway_container_type type) {
50 } 50 }
51} 51}
52 52
53static void notify_new_container(struct sway_container *container) { 53void container_create_notify(struct sway_container *container) {
54 wl_signal_emit(&root_container.sway_root->events.new_container, container); 54 wl_signal_emit(&root_container.sway_root->events.new_container, container);
55 ipc_event_window(container, "new"); 55 ipc_event_window(container, "new");
56} 56}
@@ -76,21 +76,21 @@ struct sway_container *container_create(enum sway_container_type type) {
76 return c; 76 return c;
77} 77}
78 78
79static struct sway_container *_container_destroy(struct sway_container *cont) { 79static void _container_destroy(struct sway_container *cont) {
80 if (cont == NULL) { 80 if (cont == NULL) {
81 return NULL; 81 return;
82 } 82 }
83 83
84 wl_signal_emit(&cont->events.destroy, cont); 84 wl_signal_emit(&cont->events.destroy, cont);
85 85
86 struct sway_container *parent = cont->parent; 86 struct sway_container *parent = cont->parent;
87 if (cont->children != NULL) { 87 if (cont->children != NULL && cont->children->length) {
88 // remove children until there are no more, container_destroy calls 88 // remove children until there are no more, container_destroy calls
89 // container_remove_child, which removes child from this container 89 // container_remove_child, which removes child from this container
90 while (cont->children != NULL && cont->children->length != 0) { 90 while (cont->children != NULL) {
91 struct sway_container *child = cont->children->items[0]; 91 struct sway_container *child = cont->children->items[0];
92 container_remove_child(child); 92 container_remove_child(child);
93 container_destroy(child); 93 _container_destroy(child);
94 } 94 }
95 } 95 }
96 if (cont->marks) { 96 if (cont->marks) {
@@ -106,106 +106,200 @@ static struct sway_container *_container_destroy(struct sway_container *cont) {
106 list_free(cont->children); 106 list_free(cont->children);
107 cont->children = NULL; 107 cont->children = NULL;
108 free(cont); 108 free(cont);
109 return parent;
110} 109}
111 110
112struct sway_container *container_destroy(struct sway_container *cont) { 111static struct sway_container *container_output_destroy(
113 struct sway_container *parent = _container_destroy(cont); 112 struct sway_container *output) {
114 parent = container_reap_empty(parent); 113 if (!sway_assert(output, "cannot destroy null output")) {
115 arrange_windows(&root_container, -1, -1); 114 return NULL;
116 return parent; 115 }
117} 116
117 if (output->children->length > 0) {
118 // TODO save workspaces when there are no outputs.
119 // TODO also check if there will ever be no outputs except for exiting
120 // program
121 if (root_container.children->length > 1) {
122 int p = root_container.children->items[0] == output;
123 // Move workspace from this output to another output
124 while (output->children->length) {
125 struct sway_container *child = output->children->items[0];
126 container_remove_child(child);
127 container_add_child(root_container.children->items[p], child);
128 }
129 container_sort_workspaces(root_container.children->items[p]);
130 arrange_windows(root_container.children->items[p],
131 -1, -1);
132 }
133 }
118 134
119struct sway_container *container_output_create( 135 wl_list_remove(&output->sway_output->destroy.link);
120 struct sway_output *sway_output) { 136 wl_list_remove(&output->sway_output->mode.link);
121 struct wlr_box size; 137 wl_list_remove(&output->sway_output->transform.link);
122 wlr_output_effective_resolution(sway_output->wlr_output, &size.width, 138 wl_list_remove(&output->sway_output->scale.link);
123 &size.height);
124 139
125 const char *name = sway_output->wlr_output->name; 140 wl_list_remove(&output->sway_output->damage_destroy.link);
126 char identifier[128]; 141 wl_list_remove(&output->sway_output->damage_frame.link);
127 output_get_identifier(identifier, sizeof(identifier), sway_output);
128 142
129 struct output_config *oc = NULL, *all = NULL; 143 wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
130 for (int i = 0; i < config->output_configs->length; ++i) { 144 _container_destroy(output);
131 struct output_config *cur = config->output_configs->items[i]; 145 return &root_container;
146}
132 147
133 if (strcasecmp(name, cur->name) == 0 || 148static struct sway_container *container_workspace_destroy(
134 strcasecmp(identifier, cur->name) == 0) { 149 struct sway_container *workspace) {
135 wlr_log(L_DEBUG, "Matched output config for %s", name); 150 if (!sway_assert(workspace, "cannot destroy null workspace")) {
136 oc = cur; 151 return NULL;
137 } 152 }
138 if (strcasecmp("*", cur->name) == 0) { 153
139 wlr_log(L_DEBUG, "Matched wildcard output config for %s", name); 154 // Do not destroy this if it's the last workspace on this output
140 all = cur; 155 struct sway_container *output = container_parent(workspace, C_OUTPUT);
156 if (output && output->children->length == 1) {
157 return NULL;
158 }
159
160 struct sway_container *parent = workspace->parent;
161 if (workspace->children->length == 0) {
162 // destroy the WS if there are no children (TODO check for floating)
163 wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
164 ipc_event_workspace(workspace, NULL, "empty");
165 } else {
166 // Move children to a different workspace on this output
167 struct sway_container *new_workspace = NULL;
168 // TODO move floating
169 for (int i = 0; i < output->children->length; i++) {
170 if (output->children->items[i] != workspace) {
171 new_workspace = output->children->items[i];
172 break;
173 }
141 } 174 }
142 175
143 if (oc && all) { 176 wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'",
144 break; 177 workspace->name, new_workspace->name);
178 for (int i = 0; i < workspace->children->length; i++) {
179 container_move_to(workspace->children->items[i], new_workspace);
145 } 180 }
146 } 181 }
147 if (!oc) {
148 oc = all;
149 }
150 182
151 if (oc && !oc->enabled) { 183 _container_destroy(workspace);
152 return NULL; 184
185 output_damage_whole(output->sway_output);
186
187 return parent;
188}
189
190static void container_root_finish(struct sway_container *con) {
191 wlr_log(L_ERROR, "TODO: destroy the root container");
192}
193
194static bool container_reap_empty(struct sway_container *con) {
195 switch (con->type) {
196 case C_ROOT:
197 case C_OUTPUT:
198 // dont reap these
199 break;
200 case C_WORKSPACE:
201 if (!workspace_is_visible(con) && con->children->length == 0) {
202 container_workspace_destroy(con);
203 return true;
204 }
205 break;
206 case C_CONTAINER:
207 if (con->children->length == 0) {
208 _container_destroy(con);
209 return true;
210 } else if (con->children->length == 1) {
211 struct sway_container *child = con->children->items[0];
212 if (child->type == C_CONTAINER) {
213 container_remove_child(child);
214 container_replace_child(con, child);
215 _container_destroy(con);
216 return true;
217 }
218 }
219 case C_VIEW:
220 break;
221 case C_TYPES:
222 sway_assert(false, "container_reap_empty called on an invalid "
223 "container");
224 break;
153 } 225 }
154 226
155 struct sway_container *output = container_create(C_OUTPUT); 227 return false;
156 output->sway_output = sway_output; 228}
157 output->name = strdup(name); 229
158 if (output->name == NULL) { 230struct sway_container *container_destroy(struct sway_container *con) {
159 container_destroy(output); 231 if (con == NULL) {
160 return NULL; 232 return NULL;
161 } 233 }
162 234
163 // Insert the child before applying config so that the container coordinates 235 struct sway_container *parent = con->parent;
164 // get updated 236
165 container_add_child(&root_container, output); 237 switch (con->type) {
166 apply_output_config(oc, output); 238 case C_ROOT:
239 container_root_finish(con);
240 break;
241 case C_OUTPUT:
242 // dont try to reap the root after this
243 container_output_destroy(con);
244 break;
245 case C_WORKSPACE:
246 // dont try to reap the output after this
247 container_workspace_destroy(con);
248 break;
249 case C_CONTAINER:
250 if (con->children->length) {
251 for (int i = 0; i < con->children->length; ++i) {
252 struct sway_container *child = con->children->items[0];
253 container_remove_child(child);
254 container_add_child(parent, child);
255 }
256 }
257 _container_destroy(con);
258 break;
259 case C_VIEW:
260 _container_destroy(con);
261 break;
262 case C_TYPES:
263 wlr_log(L_ERROR, "container_destroy called on an invalid "
264 "container");
265 break;
266 }
167 267
168 load_swaybars(); 268 struct sway_container *tmp = parent;
269 while (parent) {
270 tmp = parent->parent;
169 271
170 // Create workspace 272 if (!container_reap_empty(parent)) {
171 char *ws_name = workspace_next_name(output->name); 273 break;
172 wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
173 struct sway_container *ws = container_workspace_create(output, ws_name);
174 // Set each seat's focus if not already set
175 struct sway_seat *seat = NULL;
176 wl_list_for_each(seat, &input_manager->seats, link) {
177 if (!seat->has_focus) {
178 seat_set_focus(seat, ws);
179 } 274 }
275
276 parent = tmp;
180 } 277 }
181 278
182 free(ws_name); 279 return tmp;
183 notify_new_container(output); 280}
184 return output; 281
282static void container_close_func(struct sway_container *container, void *data) {
283 if (container->type == C_VIEW) {
284 view_close(container->sway_view);
285 }
185} 286}
186 287
187struct sway_container *container_workspace_create( 288struct sway_container *container_close(struct sway_container *con) {
188 struct sway_container *output, const char *name) { 289 if (!sway_assert(con != NULL,
189 if (!sway_assert(output, 290 "container_close called with a NULL container")) {
190 "container_workspace_create called with null output")) {
191 return NULL; 291 return NULL;
192 } 292 }
193 wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name); 293
194 struct sway_container *workspace = container_create(C_WORKSPACE); 294 struct sway_container *parent = con->parent;
195 295
196 workspace->x = output->x; 296 if (con->type == C_VIEW) {
197 workspace->y = output->y; 297 view_close(con->sway_view);
198 workspace->width = output->width; 298 } else {
199 workspace->height = output->height; 299 container_for_each_descendant_dfs(con, container_close_func, NULL);
200 workspace->name = !name ? NULL : strdup(name); 300 }
201 workspace->prev_layout = L_NONE; 301
202 workspace->layout = container_get_default_layout(output); 302 return parent;
203 workspace->workspace_layout = container_get_default_layout(output);
204
205 container_add_child(output, workspace);
206 container_sort_workspaces(output);
207 notify_new_container(workspace);
208 return workspace;
209} 303}
210 304
211struct sway_container *container_view_create(struct sway_container *sibling, 305struct sway_container *container_view_create(struct sway_container *sibling,
@@ -231,23 +325,10 @@ struct sway_container *container_view_create(struct sway_container *sibling,
231 // Regular case, create as sibling of current container 325 // Regular case, create as sibling of current container
232 container_add_sibling(sibling, swayc); 326 container_add_sibling(sibling, swayc);
233 } 327 }
234 notify_new_container(swayc); 328 container_create_notify(swayc);
235 return swayc; 329 return swayc;
236} 330}
237 331
238struct sway_container *container_set_layout(struct sway_container *container,
239 enum sway_container_layout layout) {
240 if (container->type == C_WORKSPACE) {
241 container->workspace_layout = layout;
242 if (layout == L_HORIZ || layout == L_VERT) {
243 container->layout = layout;
244 }
245 } else {
246 container->layout = layout;
247 }
248 return container;
249}
250
251void container_descendants(struct sway_container *root, 332void container_descendants(struct sway_container *root,
252 enum sway_container_type type, 333 enum sway_container_type type,
253 void (*func)(struct sway_container *item, void *data), void *data) { 334 void (*func)(struct sway_container *item, void *data), void *data) {
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 617350d9..5abdbc32 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -1,5 +1,4 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h>
3#include <ctype.h> 2#include <ctype.h>
4#include <math.h> 3#include <math.h>
5#include <stdbool.h> 4#include <stdbool.h>
@@ -52,6 +51,19 @@ static void output_layout_handle_change(struct wl_listener *listener,
52 arrange_windows(&root_container, -1, -1); 51 arrange_windows(&root_container, -1, -1);
53} 52}
54 53
54struct sway_container *container_set_layout(struct sway_container *container,
55 enum sway_container_layout layout) {
56 if (container->type == C_WORKSPACE) {
57 container->workspace_layout = layout;
58 if (layout == L_HORIZ || layout == L_VERT) {
59 container->layout = layout;
60 }
61 } else {
62 container->layout = layout;
63 }
64 return container;
65}
66
55void layout_init(void) { 67void layout_init(void) {
56 root_container.id = 0; // normally assigned in new_swayc() 68 root_container.id = 0; // normally assigned in new_swayc()
57 root_container.type = C_ROOT; 69 root_container.type = C_ROOT;
@@ -107,32 +119,6 @@ void container_add_child(struct sway_container *parent,
107 child->parent = parent; 119 child->parent = parent;
108} 120}
109 121
110struct sway_container *container_reap_empty(struct sway_container *container) {
111 if (container == NULL) {
112 return NULL;
113 }
114 wlr_log(L_DEBUG, "Reaping %p %s '%s'", container,
115 container_type_to_str(container->type), container->name);
116 while (container->type != C_ROOT && container->type != C_OUTPUT
117 && container->children->length == 0) {
118 if (container->type == C_WORKSPACE) {
119 if (!workspace_is_visible(container)) {
120 struct sway_container *parent = container->parent;
121 container_workspace_destroy(container);
122 return parent;
123 }
124 return container;
125 } else if (container->type == C_CONTAINER) {
126 struct sway_container *parent = container->parent;
127 container_destroy(container);
128 container = parent;
129 } else {
130 container = container->parent;
131 }
132 }
133 return container;
134}
135
136struct sway_container *container_remove_child(struct sway_container *child) { 122struct sway_container *container_remove_child(struct sway_container *child) {
137 struct sway_container *parent = child->parent; 123 struct sway_container *parent = child->parent;
138 for (int i = 0; i < parent->children->length; ++i) { 124 for (int i = 0; i < parent->children->length; ++i) {
@@ -167,7 +153,7 @@ void container_move_to(struct sway_container *container,
167 if (old_parent->children->length == 0) { 153 if (old_parent->children->length == 0) {
168 char *ws_name = workspace_next_name(old_parent->name); 154 char *ws_name = workspace_next_name(old_parent->name);
169 struct sway_container *ws = 155 struct sway_container *ws =
170 container_workspace_create(old_parent, ws_name); 156 workspace_create(old_parent, ws_name);
171 free(ws_name); 157 free(ws_name);
172 seat_set_focus(seat, ws); 158 seat_set_focus(seat, ws);
173 } 159 }
@@ -186,12 +172,22 @@ void container_move(struct sway_container *container,
186} 172}
187 173
188enum sway_container_layout container_get_default_layout( 174enum sway_container_layout container_get_default_layout(
189 struct sway_container *output) { 175 struct sway_container *con) {
176 if (con->type != C_OUTPUT) {
177 con = container_parent(con, C_OUTPUT);
178 }
179
180 if (!sway_assert(con != NULL,
181 "container_get_default_layout must be called on an attached"
182 " container below the root container")) {
183 return 0;
184 }
185
190 if (config->default_layout != L_NONE) { 186 if (config->default_layout != L_NONE) {
191 return config->default_layout; 187 return config->default_layout;
192 } else if (config->default_orientation != L_NONE) { 188 } else if (config->default_orientation != L_NONE) {
193 return config->default_orientation; 189 return config->default_orientation;
194 } else if (output->width >= output->height) { 190 } else if (con->width >= con->height) {
195 return L_HORIZ; 191 return L_HORIZ;
196 } else { 192 } else {
197 return L_VERT; 193 return L_VERT;
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 0509db23..6c7044a2 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -1,51 +1,73 @@
1#define _POSIX_C_SOURCE 200809L
2#include <string.h>
1#include <strings.h> 3#include <strings.h>
2#include "sway/tree/container.h"
3#include "sway/tree/layout.h"
4#include "sway/output.h" 4#include "sway/output.h"
5#include "sway/tree/output.h"
6#include "sway/tree/workspace.h"
5#include "log.h" 7#include "log.h"
6 8
7struct sway_container *container_output_destroy(struct sway_container *output) { 9struct sway_container *output_create(
8 if (!sway_assert(output, "cannot destroy null output")) { 10 struct sway_output *sway_output) {
9 return NULL; 11 struct wlr_box size;
10 } 12 wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
13 &size.height);
14
15 const char *name = sway_output->wlr_output->name;
16 char identifier[128];
17 output_get_identifier(identifier, sizeof(identifier), sway_output);
18
19 struct output_config *oc = NULL, *all = NULL;
20 for (int i = 0; i < config->output_configs->length; ++i) {
21 struct output_config *cur = config->output_configs->items[i];
11 22
12 if (output->children->length > 0) { 23 if (strcasecmp(name, cur->name) == 0 ||
13 // TODO save workspaces when there are no outputs. 24 strcasecmp(identifier, cur->name) == 0) {
14 // TODO also check if there will ever be no outputs except for exiting 25 wlr_log(L_DEBUG, "Matched output config for %s", name);
15 // program 26 oc = cur;
16 if (root_container.children->length > 1) {
17 int p = root_container.children->items[0] == output;
18 // Move workspace from this output to another output
19 while (output->children->length) {
20 struct sway_container *child = output->children->items[0];
21 container_remove_child(child);
22 container_add_child(root_container.children->items[p], child);
23 }
24 container_sort_workspaces(root_container.children->items[p]);
25 arrange_windows(root_container.children->items[p],
26 -1, -1);
27 } 27 }
28 if (strcasecmp("*", cur->name) == 0) {
29 wlr_log(L_DEBUG, "Matched wildcard output config for %s", name);
30 all = cur;
31 }
32
33 if (oc && all) {
34 break;
35 }
36 }
37 if (!oc) {
38 oc = all;
28 } 39 }
29 40
30 wl_list_remove(&output->sway_output->destroy.link); 41 if (oc && !oc->enabled) {
31 wl_list_remove(&output->sway_output->mode.link); 42 return NULL;
32 wl_list_remove(&output->sway_output->transform.link); 43 }
33 wl_list_remove(&output->sway_output->scale.link);
34 44
35 wl_list_remove(&output->sway_output->damage_destroy.link); 45 struct sway_container *output = container_create(C_OUTPUT);
36 wl_list_remove(&output->sway_output->damage_frame.link); 46 output->sway_output = sway_output;
47 output->name = strdup(name);
48 if (output->name == NULL) {
49 container_destroy(output);
50 return NULL;
51 }
37 52
38 wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); 53 apply_output_config(oc, output);
39 container_destroy(output); 54 container_add_child(&root_container, output);
40 return &root_container; 55 load_swaybars();
41}
42 56
43struct sway_container *output_by_name(const char *name) { 57 // Create workspace
44 for (int i = 0; i < root_container.children->length; ++i) { 58 char *ws_name = workspace_next_name(output->name);
45 struct sway_container *output = root_container.children->items[i]; 59 wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
46 if (strcasecmp(output->name, name) == 0){ 60 struct sway_container *ws = workspace_create(output, ws_name);
47 return output; 61 // Set each seat's focus if not already set
62 struct sway_seat *seat = NULL;
63 wl_list_for_each(seat, &input_manager->seats, link) {
64 if (!seat->has_focus) {
65 seat_set_focus(seat, ws);
48 } 66 }
49 } 67 }
50 return NULL; 68
69 free(ws_name);
70 container_create_notify(output);
71 return output;
51} 72}
73
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 09c804e4..aa010a40 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -27,8 +27,7 @@ void view_destroy(struct sway_view *view) {
27 view_unmap(view); 27 view_unmap(view);
28 } 28 }
29 29
30 container_view_destroy(view->swayc); 30 container_destroy(view->swayc);
31 free(view);
32} 31}
33 32
34const char *view_get_title(struct sway_view *view) { 33const char *view_get_title(struct sway_view *view) {
@@ -78,16 +77,6 @@ void view_close(struct sway_view *view) {
78 } 77 }
79} 78}
80 79
81struct sway_container *container_view_destroy(struct sway_container *view) {
82 if (!view) {
83 return NULL;
84 }
85 wlr_log(L_DEBUG, "Destroying view '%s'", view->name);
86 struct sway_container *parent = container_destroy(view);
87 arrange_windows(parent, -1, -1);
88 return parent;
89}
90
91void view_damage_whole(struct sway_view *view) { 80void view_damage_whole(struct sway_view *view) {
92 for (int i = 0; i < root_container.children->length; ++i) { 81 for (int i = 0; i < root_container.children->length; ++i) {
93 struct sway_container *cont = root_container.children->items[i]; 82 struct sway_container *cont = root_container.children->items[i];
@@ -160,10 +149,12 @@ void view_unmap(struct sway_view *view) {
160 149
161 view_damage_whole(view); 150 view_damage_whole(view);
162 151
163 container_view_destroy(view->swayc); 152 struct sway_container *parent = container_destroy(view->swayc);
164 153
165 view->swayc = NULL; 154 view->swayc = NULL;
166 view->surface = NULL; 155 view->surface = NULL;
156
157 arrange_windows(parent, -1, -1);
167} 158}
168 159
169void view_update_position(struct sway_view *view, double ox, double oy) { 160void view_update_position(struct sway_view *view, double ox, double oy) {
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 8077de2e..316f01e4 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -14,6 +14,58 @@
14#include "log.h" 14#include "log.h"
15#include "util.h" 15#include "util.h"
16 16
17static struct sway_container *get_workspace_initial_output(const char *name) {
18 struct sway_container *parent;
19 // Search for workspace<->output pair
20 int e = config->workspace_outputs->length;
21 for (int i = 0; i < config->workspace_outputs->length; ++i) {
22 struct workspace_output *wso = config->workspace_outputs->items[i];
23 if (strcasecmp(wso->workspace, name) == 0) {
24 // Find output to use if it exists
25 e = root_container.children->length;
26 for (i = 0; i < e; ++i) {
27 parent = root_container.children->items[i];
28 if (strcmp(parent->name, wso->output) == 0) {
29 return parent;
30 }
31 }
32 break;
33 }
34 }
35 // Otherwise put it on the focused output
36 struct sway_seat *seat = input_manager_current_seat(input_manager);
37 struct sway_container *focus =
38 seat_get_focus_inactive(seat, &root_container);
39 parent = focus;
40 parent = container_parent(parent, C_OUTPUT);
41 return parent;
42}
43
44struct sway_container *workspace_create(struct sway_container *output,
45 const char *name) {
46 if (output == NULL) {
47 output = get_workspace_initial_output(name);
48 }
49
50 wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name);
51 struct sway_container *workspace = container_create(C_WORKSPACE);
52
53 workspace->x = output->x;
54 workspace->y = output->y;
55 workspace->width = output->width;
56 workspace->height = output->height;
57 workspace->name = !name ? NULL : strdup(name);
58 workspace->prev_layout = L_NONE;
59 workspace->layout = container_get_default_layout(output);
60 workspace->workspace_layout = workspace->layout;
61
62 container_add_child(output, workspace);
63 container_sort_workspaces(output);
64 container_create_notify(workspace);
65
66 return workspace;
67}
68
17char *prev_workspace_name = NULL; 69char *prev_workspace_name = NULL;
18struct workspace_by_number_data { 70struct workspace_by_number_data {
19 int len; 71 int len;
@@ -197,74 +249,6 @@ struct sway_container *workspace_by_name(const char *name) {
197 } 249 }
198} 250}
199 251
200struct sway_container *workspace_create(const char *name) {
201 struct sway_container *parent;
202 // Search for workspace<->output pair
203 int i, e = config->workspace_outputs->length;
204 for (i = 0; i < e; ++i) {
205 struct workspace_output *wso = config->workspace_outputs->items[i];
206 if (strcasecmp(wso->workspace, name) == 0) {
207 // Find output to use if it exists
208 e = root_container.children->length;
209 for (i = 0; i < e; ++i) {
210 parent = root_container.children->items[i];
211 if (strcmp(parent->name, wso->output) == 0) {
212 return container_workspace_create(parent, name);
213 }
214 }
215 break;
216 }
217 }
218 // Otherwise create a new one
219 struct sway_seat *seat = input_manager_current_seat(input_manager);
220 struct sway_container *focus =
221 seat_get_focus_inactive(seat, &root_container);
222 parent = focus;
223 parent = container_parent(parent, C_OUTPUT);
224 struct sway_container *new_ws = container_workspace_create(parent, name);
225 ipc_event_workspace(NULL, new_ws, "init");
226 return new_ws;
227}
228
229struct sway_container *container_workspace_destroy(
230 struct sway_container *workspace) {
231 if (!sway_assert(workspace, "cannot destroy null workspace")) {
232 return NULL;
233 }
234
235 // Do not destroy this if it's the last workspace on this output
236 struct sway_container *output = container_parent(workspace, C_OUTPUT);
237 if (output && output->children->length == 1) {
238 return NULL;
239 }
240
241 struct sway_container *parent = workspace->parent;
242 if (workspace->children->length == 0) {
243 // destroy the WS if there are no children (TODO check for floating)
244 wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
245 ipc_event_workspace(workspace, NULL, "empty");
246 } else {
247 // Move children to a different workspace on this output
248 struct sway_container *new_workspace = NULL;
249 // TODO move floating
250 for (int i = 0; i < output->children->length; i++) {
251 if (output->children->items[i] != workspace) {
252 new_workspace = output->children->items[i];
253 break;
254 }
255 }
256
257 wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'",
258 workspace->name, new_workspace->name);
259 for (int i = 0; i < workspace->children->length; i++) {
260 container_move_to(workspace->children->items[i], new_workspace);
261 }
262 }
263
264 container_destroy(workspace);
265 return parent;
266}
267
268/** 252/**
269 * Get the previous or next workspace on the specified output. Wraps around at 253 * Get the previous or next workspace on the specified output. Wraps around at
270 * the end and beginning. If next is false, the previous workspace is returned, 254 * the end and beginning. If next is false, the previous workspace is returned,
@@ -376,7 +360,9 @@ bool workspace_switch(struct sway_container *workspace) {
376 && active_ws == workspace 360 && active_ws == workspace
377 && prev_workspace_name) { 361 && prev_workspace_name) {
378 struct sway_container *new_ws = workspace_by_name(prev_workspace_name); 362 struct sway_container *new_ws = workspace_by_name(prev_workspace_name);
379 workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); 363 workspace = new_ws ?
364 new_ws :
365 workspace_create(NULL, prev_workspace_name);
380 } 366 }
381 367
382 if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name) 368 if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name)