diff options
author | Tony Crisci <tony@dubstepdish.com> | 2018-03-30 15:47:53 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-30 15:47:53 -0400 |
commit | 7eca02301ba309fa909ba9b12cb335f8f944f1ee (patch) | |
tree | 8616074124e558fb6787be9cb3336d61663d9a86 | |
parent | Merge pull request #1664 from swaywm/xwayland-add-to-focused (diff) | |
parent | Fix segfault when reaping invisible workspaces (diff) | |
download | sway-7eca02301ba309fa909ba9b12cb335f8f944f1ee.tar.gz sway-7eca02301ba309fa909ba9b12cb335f8f944f1ee.tar.zst sway-7eca02301ba309fa909ba9b12cb335f8f944f1ee.zip |
Merge pull request #1662 from swaywm/workspace-delete-fixes
Fix workspace deletion edge cases
-rw-r--r-- | include/sway/tree/container.h | 2 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 2 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 2 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 3 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 20 | ||||
-rw-r--r-- | sway/ipc-json.c | 69 | ||||
-rw-r--r-- | sway/ipc-server.c | 8 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/container.c | 103 | ||||
-rw-r--r-- | sway/tree/layout.c | 60 | ||||
-rw-r--r-- | sway/tree/output.c | 36 | ||||
-rw-r--r-- | sway/tree/view.c | 11 | ||||
-rw-r--r-- | sway/tree/workspace.c | 56 |
13 files changed, 203 insertions, 170 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 24e8468e..6aa66da0 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -104,7 +104,7 @@ struct sway_container *container_workspace_destroy( | |||
104 | 104 | ||
105 | struct sway_container *container_view_destroy(struct sway_container *view); | 105 | struct sway_container *container_view_destroy(struct sway_container *view); |
106 | 106 | ||
107 | void container_destroy(struct sway_container *cont); | 107 | struct sway_container *container_destroy(struct sway_container *cont); |
108 | 108 | ||
109 | struct sway_container *container_set_layout(struct sway_container *container, | 109 | struct sway_container *container_set_layout(struct sway_container *container, |
110 | enum sway_container_layout layout); | 110 | enum sway_container_layout layout); |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 8239366b..0a904c4b 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h | |||
@@ -39,6 +39,8 @@ struct sway_container *container_add_sibling(struct sway_container *parent, | |||
39 | 39 | ||
40 | struct sway_container *container_remove_child(struct sway_container *child); | 40 | struct sway_container *container_remove_child(struct sway_container *child); |
41 | 41 | ||
42 | struct sway_container *container_reap_empty(struct sway_container *container); | ||
43 | |||
42 | void container_move_to(struct sway_container* container, | 44 | void container_move_to(struct sway_container* container, |
43 | struct sway_container* destination); | 45 | struct sway_container* destination); |
44 | 46 | ||
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index d73b29c1..4e4c3450 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -23,4 +23,6 @@ struct sway_container *workspace_output_prev(struct sway_container *current); | |||
23 | 23 | ||
24 | struct sway_container *workspace_prev(struct sway_container *current); | 24 | struct sway_container *workspace_prev(struct sway_container *current); |
25 | 25 | ||
26 | bool workspace_is_visible(struct sway_container *ws); | ||
27 | |||
26 | #endif | 28 | #endif |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 25c0cbca..01f38d16 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -83,10 +83,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
83 | wl_container_of(listener, sway_xdg_surface, destroy); | 83 | wl_container_of(listener, sway_xdg_surface, destroy); |
84 | wl_list_remove(&sway_xdg_surface->commit.link); | 84 | wl_list_remove(&sway_xdg_surface->commit.link); |
85 | wl_list_remove(&sway_xdg_surface->destroy.link); | 85 | wl_list_remove(&sway_xdg_surface->destroy.link); |
86 | struct sway_container *parent = container_view_destroy(sway_xdg_surface->view->swayc); | 86 | container_view_destroy(sway_xdg_surface->view->swayc); |
87 | free(sway_xdg_surface->view); | 87 | free(sway_xdg_surface->view); |
88 | free(sway_xdg_surface); | 88 | free(sway_xdg_surface); |
89 | arrange_windows(parent, -1, -1); | ||
90 | } | 89 | } |
91 | 90 | ||
92 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | 91 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 3e08b20e..357c8883 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -109,29 +109,17 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
109 | wl_list_remove(&sway_surface->destroy.link); | 109 | wl_list_remove(&sway_surface->destroy.link); |
110 | wl_list_remove(&sway_surface->request_configure.link); | 110 | wl_list_remove(&sway_surface->request_configure.link); |
111 | wl_list_remove(&sway_surface->view->unmanaged_view_link); | 111 | wl_list_remove(&sway_surface->view->unmanaged_view_link); |
112 | 112 | container_view_destroy(sway_surface->view->swayc); | |
113 | struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); | 113 | sway_surface->view->swayc = NULL; |
114 | if (parent) { | 114 | sway_surface->view->surface = NULL; |
115 | arrange_windows(parent, -1, -1); | ||
116 | } | ||
117 | |||
118 | free(sway_surface->view); | ||
119 | free(sway_surface); | ||
120 | } | 115 | } |
121 | 116 | ||
122 | static void handle_unmap_notify(struct wl_listener *listener, void *data) { | 117 | static void handle_unmap_notify(struct wl_listener *listener, void *data) { |
123 | struct sway_xwayland_surface *sway_surface = | 118 | struct sway_xwayland_surface *sway_surface = |
124 | wl_container_of(listener, sway_surface, unmap_notify); | 119 | wl_container_of(listener, sway_surface, unmap_notify); |
125 | |||
126 | wl_list_remove(&sway_surface->view->unmanaged_view_link); | 120 | wl_list_remove(&sway_surface->view->unmanaged_view_link); |
127 | wl_list_init(&sway_surface->view->unmanaged_view_link); | 121 | wl_list_init(&sway_surface->view->unmanaged_view_link); |
128 | 122 | container_view_destroy(sway_surface->view->swayc); | |
129 | // take it out of the tree | ||
130 | struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); | ||
131 | if (parent) { | ||
132 | arrange_windows(parent, -1, -1); | ||
133 | } | ||
134 | |||
135 | sway_surface->view->swayc = NULL; | 123 | sway_surface->view->swayc = NULL; |
136 | sway_surface->view->surface = NULL; | 124 | sway_surface->view->surface = NULL; |
137 | } | 125 | } |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index eab6399f..7c5f7304 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -66,19 +66,42 @@ static const char *ipc_json_get_output_transform(enum wl_output_transform transf | |||
66 | 66 | ||
67 | static void ipc_json_describe_output(struct sway_container *container, json_object *object) { | 67 | static void ipc_json_describe_output(struct sway_container *container, json_object *object) { |
68 | struct wlr_output *wlr_output = container->sway_output->wlr_output; | 68 | struct wlr_output *wlr_output = container->sway_output->wlr_output; |
69 | json_object_object_add(object, "type", json_object_new_string("output")); | 69 | json_object_object_add(object, "type", |
70 | json_object_object_add(object, "active", json_object_new_boolean(true)); | 70 | json_object_new_string("output")); |
71 | json_object_object_add(object, "primary", json_object_new_boolean(false)); | 71 | json_object_object_add(object, "active", |
72 | json_object_object_add(object, "layout", json_object_new_string("output")); | 72 | json_object_new_boolean(true)); |
73 | json_object_object_add(object, "make", json_object_new_string(wlr_output->make)); | 73 | json_object_object_add(object, "primary", |
74 | json_object_object_add(object, "model", json_object_new_string(wlr_output->model)); | 74 | json_object_new_boolean(false)); |
75 | json_object_object_add(object, "serial", json_object_new_string(wlr_output->serial)); | 75 | json_object_object_add(object, "layout", |
76 | json_object_object_add(object, "scale", json_object_new_double(wlr_output->scale)); | 76 | json_object_new_string("output")); |
77 | json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh)); | 77 | json_object_object_add(object, "make", |
78 | json_object_new_string(wlr_output->make)); | ||
79 | json_object_object_add(object, "model", | ||
80 | json_object_new_string(wlr_output->model)); | ||
81 | json_object_object_add(object, "serial", | ||
82 | json_object_new_string(wlr_output->serial)); | ||
83 | json_object_object_add(object, "scale", | ||
84 | json_object_new_double(wlr_output->scale)); | ||
85 | json_object_object_add(object, "refresh", | ||
86 | json_object_new_int(wlr_output->refresh)); | ||
78 | json_object_object_add(object, "transform", | 87 | json_object_object_add(object, "transform", |
79 | json_object_new_string(ipc_json_get_output_transform(wlr_output->transform))); | 88 | json_object_new_string( |
80 | // TODO WLR need to set "current_workspace" to the currently focused | 89 | ipc_json_get_output_transform(wlr_output->transform))); |
81 | // workspace in a way that makes sense with multiseat | 90 | |
91 | struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager); | ||
92 | const char *ws = NULL; | ||
93 | if (seat) { | ||
94 | struct sway_container *focus = | ||
95 | sway_seat_get_focus_inactive(seat, container); | ||
96 | if (focus && focus->type != C_WORKSPACE) { | ||
97 | focus = container_parent(focus, C_WORKSPACE); | ||
98 | } | ||
99 | if (focus) { | ||
100 | ws = focus->name; | ||
101 | } | ||
102 | } | ||
103 | json_object_object_add(object, "current_workspace", | ||
104 | json_object_new_string(ws)); | ||
82 | 105 | ||
83 | json_object *modes_array = json_object_new_array(); | 106 | json_object *modes_array = json_object_new_array(); |
84 | struct wlr_output_mode *mode; | 107 | struct wlr_output_mode *mode; |
@@ -95,16 +118,20 @@ static void ipc_json_describe_output(struct sway_container *container, json_obje | |||
95 | json_object_object_add(object, "modes", modes_array); | 118 | json_object_object_add(object, "modes", modes_array); |
96 | } | 119 | } |
97 | 120 | ||
98 | static void ipc_json_describe_workspace(struct sway_container *workspace, json_object *object) { | 121 | static void ipc_json_describe_workspace(struct sway_container *workspace, |
99 | int num = (isdigit(workspace->name[0])) ? atoi(workspace->name) : -1; | 122 | json_object *object) { |
123 | int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1; | ||
100 | 124 | ||
101 | json_object_object_add(object, "num", json_object_new_int(num)); | 125 | json_object_object_add(object, "num", json_object_new_int(num)); |
102 | json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); | 126 | json_object_object_add(object, "output", workspace->parent ? |
127 | json_object_new_string(workspace->parent->name) : NULL); | ||
103 | json_object_object_add(object, "type", json_object_new_string("workspace")); | 128 | json_object_object_add(object, "type", json_object_new_string("workspace")); |
129 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
104 | } | 130 | } |
105 | 131 | ||
106 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { | 132 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { |
107 | json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); | 133 | json_object_object_add(object, "name", |
134 | c->name ? json_object_new_string(c->name) : NULL); | ||
108 | } | 135 | } |
109 | 136 | ||
110 | json_object *ipc_json_describe_container(struct sway_container *c) { | 137 | json_object *ipc_json_describe_container(struct sway_container *c) { |
@@ -118,28 +145,26 @@ json_object *ipc_json_describe_container(struct sway_container *c) { | |||
118 | json_object *object = json_object_new_object(); | 145 | json_object *object = json_object_new_object(); |
119 | 146 | ||
120 | json_object_object_add(object, "id", json_object_new_int((int)c->id)); | 147 | json_object_object_add(object, "id", json_object_new_int((int)c->id)); |
121 | json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); | 148 | json_object_object_add(object, "name", |
149 | c->name ? json_object_new_string(c->name) : NULL); | ||
122 | json_object_object_add(object, "rect", ipc_json_create_rect(c)); | 150 | json_object_object_add(object, "rect", ipc_json_create_rect(c)); |
123 | json_object_object_add(object, "focused", json_object_new_boolean(focused)); | 151 | json_object_object_add(object, "focused", |
152 | json_object_new_boolean(focused)); | ||
124 | 153 | ||
125 | switch (c->type) { | 154 | switch (c->type) { |
126 | case C_ROOT: | 155 | case C_ROOT: |
127 | ipc_json_describe_root(c, object); | 156 | ipc_json_describe_root(c, object); |
128 | break; | 157 | break; |
129 | |||
130 | case C_OUTPUT: | 158 | case C_OUTPUT: |
131 | ipc_json_describe_output(c, object); | 159 | ipc_json_describe_output(c, object); |
132 | break; | 160 | break; |
133 | |||
134 | case C_CONTAINER: | 161 | case C_CONTAINER: |
135 | case C_VIEW: | 162 | case C_VIEW: |
136 | ipc_json_describe_view(c, object); | 163 | ipc_json_describe_view(c, object); |
137 | break; | 164 | break; |
138 | |||
139 | case C_WORKSPACE: | 165 | case C_WORKSPACE: |
140 | ipc_json_describe_workspace(c, object); | 166 | ipc_json_describe_workspace(c, object); |
141 | break; | 167 | break; |
142 | |||
143 | case C_TYPES: | 168 | case C_TYPES: |
144 | default: | 169 | default: |
145 | break; | 170 | break; |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 394161af..f1854bcc 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -398,6 +398,14 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace, | |||
398 | json_object_object_add(workspace_json, "focused", | 398 | json_object_object_add(workspace_json, "focused", |
399 | json_object_new_boolean(focused)); | 399 | json_object_new_boolean(focused)); |
400 | json_object_array_add((json_object *)data, workspace_json); | 400 | json_object_array_add((json_object *)data, workspace_json); |
401 | |||
402 | focused_ws = sway_seat_get_focus_inactive(seat, workspace->parent); | ||
403 | if (focused_ws->type != C_WORKSPACE) { | ||
404 | focused_ws = container_parent(focused_ws, C_WORKSPACE); | ||
405 | } | ||
406 | bool visible = workspace == focused_ws; | ||
407 | json_object_object_add(workspace_json, "visible", | ||
408 | json_object_new_boolean(visible)); | ||
401 | } | 409 | } |
402 | 410 | ||
403 | void ipc_client_handle_command(struct ipc_client *client) { | 411 | void ipc_client_handle_command(struct ipc_client *client) { |
diff --git a/sway/meson.build b/sway/meson.build index 9c5e4a00..e8a192f0 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -82,6 +82,7 @@ sway_sources = files( | |||
82 | 'security.c', | 82 | 'security.c', |
83 | 'tree/container.c', | 83 | 'tree/container.c', |
84 | 'tree/layout.c', | 84 | 'tree/layout.c', |
85 | 'tree/output.c', | ||
85 | 'tree/view.c', | 86 | 'tree/view.c', |
86 | 'tree/workspace.c', | 87 | 'tree/workspace.c', |
87 | ) | 88 | ) |
diff --git a/sway/tree/container.c b/sway/tree/container.c index ed39a154..c3cf6c64 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -10,12 +10,12 @@ | |||
10 | #include "sway/tree/container.h" | 10 | #include "sway/tree/container.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" |
13 | #include "sway/tree/layout.h" | 13 | #include "sway/ipc-server.h" |
14 | #include "sway/output.h" | 14 | #include "sway/output.h" |
15 | #include "sway/server.h" | 15 | #include "sway/server.h" |
16 | #include "sway/tree/layout.h" | ||
16 | #include "sway/tree/view.h" | 17 | #include "sway/tree/view.h" |
17 | #include "sway/tree/workspace.h" | 18 | #include "sway/tree/workspace.h" |
18 | #include "sway/ipc-server.h" | ||
19 | #include "log.h" | 19 | #include "log.h" |
20 | 20 | ||
21 | static list_t *bfs_queue; | 21 | static list_t *bfs_queue; |
@@ -58,13 +58,14 @@ static struct sway_container *container_create(enum sway_container_type type) { | |||
58 | return c; | 58 | return c; |
59 | } | 59 | } |
60 | 60 | ||
61 | void container_destroy(struct sway_container *cont) { | 61 | struct sway_container *container_destroy(struct sway_container *cont) { |
62 | if (cont == NULL) { | 62 | if (cont == NULL) { |
63 | return; | 63 | return NULL; |
64 | } | 64 | } |
65 | 65 | ||
66 | wl_signal_emit(&cont->events.destroy, cont); | 66 | wl_signal_emit(&cont->events.destroy, cont); |
67 | 67 | ||
68 | struct sway_container *parent = cont->parent; | ||
68 | if (cont->children) { | 69 | if (cont->children) { |
69 | // remove children until there are no more, container_destroy calls | 70 | // remove children until there are no more, container_destroy calls |
70 | // container_remove_child, which removes child from this container | 71 | // container_remove_child, which removes child from this container |
@@ -77,13 +78,14 @@ void container_destroy(struct sway_container *cont) { | |||
77 | list_foreach(cont->marks, free); | 78 | list_foreach(cont->marks, free); |
78 | list_free(cont->marks); | 79 | list_free(cont->marks); |
79 | } | 80 | } |
80 | if (cont->parent) { | 81 | if (parent) { |
81 | container_remove_child(cont); | 82 | parent = container_remove_child(cont); |
82 | } | 83 | } |
83 | if (cont->name) { | 84 | if (cont->name) { |
84 | free(cont->name); | 85 | free(cont->name); |
85 | } | 86 | } |
86 | free(cont); | 87 | free(cont); |
88 | return parent; | ||
87 | } | 89 | } |
88 | 90 | ||
89 | struct sway_container *container_output_create( | 91 | struct sway_container *container_output_create( |
@@ -202,95 +204,6 @@ struct sway_container *container_view_create(struct sway_container *sibling, | |||
202 | return swayc; | 204 | return swayc; |
203 | } | 205 | } |
204 | 206 | ||
205 | struct sway_container *container_output_destroy(struct sway_container *output) { | ||
206 | if (!sway_assert(output, "cannot destroy null output")) { | ||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | if (output->children->length > 0) { | ||
211 | // TODO save workspaces when there are no outputs. | ||
212 | // TODO also check if there will ever be no outputs except for exiting | ||
213 | // program | ||
214 | if (root_container.children->length > 1) { | ||
215 | int p = root_container.children->items[0] == output; | ||
216 | // Move workspace from this output to another output | ||
217 | while (output->children->length) { | ||
218 | struct sway_container *child = output->children->items[0]; | ||
219 | container_remove_child(child); | ||
220 | container_add_child(root_container.children->items[p], child); | ||
221 | } | ||
222 | container_sort_workspaces(root_container.children->items[p]); | ||
223 | arrange_windows(root_container.children->items[p], | ||
224 | -1, -1); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | wl_list_remove(&output->sway_output->frame.link); | ||
229 | wl_list_remove(&output->sway_output->destroy.link); | ||
230 | wl_list_remove(&output->sway_output->mode.link); | ||
231 | |||
232 | wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | ||
233 | container_destroy(output); | ||
234 | |||
235 | return &root_container; | ||
236 | } | ||
237 | |||
238 | struct sway_container *container_workspace_destroy( | ||
239 | struct sway_container *workspace) { | ||
240 | if (!sway_assert(workspace, "cannot destroy null workspace")) { | ||
241 | return NULL; | ||
242 | } | ||
243 | |||
244 | // Do not destroy this if it's the last workspace on this output | ||
245 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | ||
246 | if (output && output->children->length == 1) { | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | struct sway_container *parent = workspace->parent; | ||
251 | if (workspace->children->length == 0) { | ||
252 | // destroy the WS if there are no children (TODO check for floating) | ||
253 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); | ||
254 | ipc_event_workspace(workspace, NULL, "empty"); | ||
255 | } else { | ||
256 | // Move children to a different workspace on this output | ||
257 | struct sway_container *new_workspace = NULL; | ||
258 | // TODO move floating | ||
259 | for (int i = 0; i < output->children->length; i++) { | ||
260 | if (output->children->items[i] != workspace) { | ||
261 | new_workspace = output->children->items[i]; | ||
262 | break; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", | ||
267 | workspace->name, new_workspace->name); | ||
268 | for (int i = 0; i < workspace->children->length; i++) { | ||
269 | container_move_to(workspace->children->items[i], new_workspace); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | container_destroy(workspace); | ||
274 | return parent; | ||
275 | } | ||
276 | |||
277 | struct sway_container *container_view_destroy(struct sway_container *view) { | ||
278 | if (!view) { | ||
279 | return NULL; | ||
280 | } | ||
281 | wlr_log(L_DEBUG, "Destroying view '%s'", view->name); | ||
282 | struct sway_container *parent = view->parent; | ||
283 | container_destroy(view); | ||
284 | |||
285 | // TODO WLR: Destroy empty containers | ||
286 | /* | ||
287 | if (parent && parent->type == C_CONTAINER) { | ||
288 | return destroy_container(parent); | ||
289 | } | ||
290 | */ | ||
291 | return parent; | ||
292 | } | ||
293 | |||
294 | struct sway_container *container_set_layout(struct sway_container *container, | 207 | struct sway_container *container_set_layout(struct sway_container *container, |
295 | enum sway_container_layout layout) { | 208 | enum sway_container_layout layout) { |
296 | if (container->type == C_WORKSPACE) { | 209 | if (container->type == C_WORKSPACE) { |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 73c4849b..588ceb2d 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "sway/tree/container.h" | 9 | #include "sway/tree/container.h" |
10 | #include "sway/tree/layout.h" | 10 | #include "sway/tree/layout.h" |
11 | #include "sway/output.h" | 11 | #include "sway/output.h" |
12 | #include "sway/tree/workspace.h" | ||
12 | #include "sway/tree/view.h" | 13 | #include "sway/tree/view.h" |
13 | #include "sway/input/seat.h" | 14 | #include "sway/input/seat.h" |
14 | #include "sway/ipc-server.h" | 15 | #include "sway/ipc-server.h" |
@@ -99,40 +100,42 @@ void container_add_child(struct sway_container *parent, | |||
99 | parent, parent->type, parent->width, parent->height); | 100 | parent, parent->type, parent->width, parent->height); |
100 | list_add(parent->children, child); | 101 | list_add(parent->children, child); |
101 | child->parent = parent; | 102 | child->parent = parent; |
102 | // set focus for this container | 103 | } |
103 | /* TODO WLR | 104 | |
104 | if (parent->type == C_WORKSPACE && child->type == C_VIEW && | 105 | struct sway_container *container_reap_empty(struct sway_container *container) { |
105 | (parent->workspace_layout == L_TABBED || parent->workspace_layout == | 106 | if (!sway_assert(container, "reaping null container")) { |
106 | L_STACKED)) { | 107 | return NULL; |
107 | child = new_container(child, parent->workspace_layout); | ||
108 | } | 108 | } |
109 | */ | 109 | wlr_log(L_DEBUG, "reaping %p %s", container, container->name); |
110 | while (container->children->length == 0) { | ||
111 | if (container->type == C_WORKSPACE) { | ||
112 | if (!workspace_is_visible(container)) { | ||
113 | struct sway_container *parent = container->parent; | ||
114 | container_workspace_destroy(container); | ||
115 | return parent; | ||
116 | } | ||
117 | return container; | ||
118 | } else if (container->type == C_CONTAINER) { | ||
119 | struct sway_container *parent = container->parent; | ||
120 | container_destroy(container); | ||
121 | container = parent; | ||
122 | } else { | ||
123 | container = container->parent; | ||
124 | } | ||
125 | } | ||
126 | return container; | ||
110 | } | 127 | } |
111 | 128 | ||
112 | struct sway_container *container_remove_child(struct sway_container *child) { | 129 | struct sway_container *container_remove_child(struct sway_container *child) { |
113 | int i; | ||
114 | struct sway_container *parent = child->parent; | 130 | struct sway_container *parent = child->parent; |
115 | for (i = 0; i < parent->children->length; ++i) { | 131 | for (int i = 0; i < parent->children->length; ++i) { |
116 | if (parent->children->items[i] == child) { | 132 | if (parent->children->items[i] == child) { |
117 | list_del(parent->children, i); | 133 | list_del(parent->children, i); |
118 | break; | 134 | break; |
119 | } | 135 | } |
120 | } | 136 | } |
121 | child->parent = NULL; | 137 | child->parent = NULL; |
122 | return parent; | 138 | return container_reap_empty(parent); |
123 | } | ||
124 | |||
125 | struct sway_container *container_reap_empty(struct sway_container *container) { | ||
126 | if (!sway_assert(container, "reaping null container")) { | ||
127 | return NULL; | ||
128 | } | ||
129 | while (container->children->length == 0 && container->type == C_CONTAINER) { | ||
130 | wlr_log(L_DEBUG, "Container: Destroying container '%p'", container); | ||
131 | struct sway_container *parent = container->parent; | ||
132 | container_destroy(container); | ||
133 | container = parent; | ||
134 | } | ||
135 | return container; | ||
136 | } | 139 | } |
137 | 140 | ||
138 | void container_move_to(struct sway_container* container, | 141 | void container_move_to(struct sway_container* container, |
@@ -145,16 +148,9 @@ void container_move_to(struct sway_container* container, | |||
145 | container->width = container->height = 0; | 148 | container->width = container->height = 0; |
146 | struct sway_container *new_parent = | 149 | struct sway_container *new_parent = |
147 | container_add_sibling(destination, container); | 150 | container_add_sibling(destination, container); |
148 | if (destination->type == C_WORKSPACE) { | 151 | if (old_parent) { |
149 | // If the workspace only has one child after adding one, it | 152 | arrange_windows(old_parent, -1, -1); |
150 | // means that the workspace was just initialized. | ||
151 | // TODO: Consider floating views in this test | ||
152 | if (destination->children->length == 1) { | ||
153 | ipc_event_workspace(NULL, destination, "init"); | ||
154 | } | ||
155 | } | 153 | } |
156 | old_parent = container_reap_empty(old_parent); | ||
157 | arrange_windows(old_parent, -1, -1); | ||
158 | arrange_windows(new_parent, -1, -1); | 154 | arrange_windows(new_parent, -1, -1); |
159 | } | 155 | } |
160 | 156 | ||
diff --git a/sway/tree/output.c b/sway/tree/output.c new file mode 100644 index 00000000..2246cb11 --- /dev/null +++ b/sway/tree/output.c | |||
@@ -0,0 +1,36 @@ | |||
1 | #include "sway/tree/container.h" | ||
2 | #include "sway/tree/layout.h" | ||
3 | #include "sway/output.h" | ||
4 | #include "log.h" | ||
5 | |||
6 | struct sway_container *container_output_destroy(struct sway_container *output) { | ||
7 | if (!sway_assert(output, "cannot destroy null output")) { | ||
8 | return NULL; | ||
9 | } | ||
10 | |||
11 | if (output->children->length > 0) { | ||
12 | // TODO save workspaces when there are no outputs. | ||
13 | // TODO also check if there will ever be no outputs except for exiting | ||
14 | // program | ||
15 | if (root_container.children->length > 1) { | ||
16 | int p = root_container.children->items[0] == output; | ||
17 | // Move workspace from this output to another output | ||
18 | while (output->children->length) { | ||
19 | struct sway_container *child = output->children->items[0]; | ||
20 | container_remove_child(child); | ||
21 | container_add_child(root_container.children->items[p], child); | ||
22 | } | ||
23 | container_sort_workspaces(root_container.children->items[p]); | ||
24 | arrange_windows(root_container.children->items[p], | ||
25 | -1, -1); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | wl_list_remove(&output->sway_output->frame.link); | ||
30 | wl_list_remove(&output->sway_output->destroy.link); | ||
31 | wl_list_remove(&output->sway_output->mode.link); | ||
32 | |||
33 | wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | ||
34 | container_destroy(output); | ||
35 | return &root_container; | ||
36 | } | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index d5325c31..480ff693 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/tree/container.h" | 3 | #include "sway/tree/container.h" |
4 | #include "sway/tree/layout.h" | 4 | #include "sway/tree/layout.h" |
5 | #include "sway/tree/view.h" | 5 | #include "sway/tree/view.h" |
6 | #include "log.h" | ||
6 | 7 | ||
7 | const char *view_get_title(struct sway_view *view) { | 8 | const char *view_get_title(struct sway_view *view) { |
8 | if (view->iface.get_prop) { | 9 | if (view->iface.get_prop) { |
@@ -94,3 +95,13 @@ void view_update_outputs(struct sway_view *view, const struct wlr_box *before) { | |||
94 | } | 95 | } |
95 | } | 96 | } |
96 | } | 97 | } |
98 | |||
99 | struct sway_container *container_view_destroy(struct sway_container *view) { | ||
100 | if (!view) { | ||
101 | return NULL; | ||
102 | } | ||
103 | wlr_log(L_DEBUG, "Destroying view '%s'", view->name); | ||
104 | struct sway_container *parent = container_destroy(view); | ||
105 | arrange_windows(parent, -1, -1); | ||
106 | return parent; | ||
107 | } | ||
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 5800ea09..c629f1f1 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -6,9 +6,10 @@ | |||
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <strings.h> | 7 | #include <strings.h> |
8 | #include "stringop.h" | 8 | #include "stringop.h" |
9 | #include "sway/tree/container.h" | ||
10 | #include "sway/input/input-manager.h" | 9 | #include "sway/input/input-manager.h" |
11 | #include "sway/input/seat.h" | 10 | #include "sway/input/seat.h" |
11 | #include "sway/ipc-server.h" | ||
12 | #include "sway/tree/container.h" | ||
12 | #include "sway/tree/workspace.h" | 13 | #include "sway/tree/workspace.h" |
13 | #include "log.h" | 14 | #include "log.h" |
14 | #include "util.h" | 15 | #include "util.h" |
@@ -202,7 +203,48 @@ struct sway_container *workspace_create(const char *name) { | |||
202 | sway_seat_get_focus_inactive(seat, &root_container); | 203 | sway_seat_get_focus_inactive(seat, &root_container); |
203 | parent = focus; | 204 | parent = focus; |
204 | parent = container_parent(parent, C_OUTPUT); | 205 | parent = container_parent(parent, C_OUTPUT); |
205 | return container_workspace_create(parent, name); | 206 | struct sway_container *new_ws = container_workspace_create(parent, name); |
207 | ipc_event_workspace(NULL, new_ws, "init"); | ||
208 | return new_ws; | ||
209 | } | ||
210 | |||
211 | struct sway_container *container_workspace_destroy( | ||
212 | struct sway_container *workspace) { | ||
213 | if (!sway_assert(workspace, "cannot destroy null workspace")) { | ||
214 | return NULL; | ||
215 | } | ||
216 | |||
217 | // Do not destroy this if it's the last workspace on this output | ||
218 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | ||
219 | if (output && output->children->length == 1) { | ||
220 | return NULL; | ||
221 | } | ||
222 | |||
223 | struct sway_container *parent = workspace->parent; | ||
224 | if (workspace->children->length == 0) { | ||
225 | // destroy the WS if there are no children (TODO check for floating) | ||
226 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); | ||
227 | ipc_event_workspace(workspace, NULL, "empty"); | ||
228 | } else { | ||
229 | // Move children to a different workspace on this output | ||
230 | struct sway_container *new_workspace = NULL; | ||
231 | // TODO move floating | ||
232 | for (int i = 0; i < output->children->length; i++) { | ||
233 | if (output->children->items[i] != workspace) { | ||
234 | new_workspace = output->children->items[i]; | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", | ||
240 | workspace->name, new_workspace->name); | ||
241 | for (int i = 0; i < workspace->children->length; i++) { | ||
242 | container_move_to(workspace->children->items[i], new_workspace); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | container_destroy(workspace); | ||
247 | return parent; | ||
206 | } | 248 | } |
207 | 249 | ||
208 | /** | 250 | /** |
@@ -343,3 +385,13 @@ bool workspace_switch(struct sway_container *workspace) { | |||
343 | arrange_windows(output, -1, -1); | 385 | arrange_windows(output, -1, -1); |
344 | return true; | 386 | return true; |
345 | } | 387 | } |
388 | |||
389 | bool workspace_is_visible(struct sway_container *ws) { | ||
390 | struct sway_container *output = container_parent(ws, C_OUTPUT); | ||
391 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
392 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, output); | ||
393 | if (focus->type != C_WORKSPACE) { | ||
394 | focus = container_parent(focus, C_WORKSPACE); | ||
395 | } | ||
396 | return focus == ws; | ||
397 | } | ||