diff options
author | Ryan Dwyer <RyanDwyer@users.noreply.github.com> | 2018-08-25 13:06:04 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-25 13:06:04 +1000 |
commit | 4b9ad9c2382db9b2a9a224e9ebc60b6298843aa9 (patch) | |
tree | f1ed7e866d4e34f5ef9b8f72ec8095369619aaa7 /sway | |
parent | commands: implement move absolute (diff) | |
parent | Merge pull request #2499 from RyanDwyer/refactor-destroy-functions (diff) | |
download | sway-4b9ad9c2382db9b2a9a224e9ebc60b6298843aa9.tar.gz sway-4b9ad9c2382db9b2a9a224e9ebc60b6298843aa9.tar.zst sway-4b9ad9c2382db9b2a9a224e9ebc60b6298843aa9.zip |
Merge branch 'master' into commands
Diffstat (limited to 'sway')
-rw-r--r-- | sway/commands/move.c | 2 | ||||
-rw-r--r-- | sway/commands/resize.c | 9 | ||||
-rw-r--r-- | sway/config/output.c | 4 | ||||
-rw-r--r-- | sway/desktop/output.c | 4 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 17 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 2 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 2 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 2 | ||||
-rw-r--r-- | sway/input/seat.c | 23 | ||||
-rw-r--r-- | sway/ipc-json.c | 11 | ||||
-rw-r--r-- | sway/tree/arrange.c | 20 | ||||
-rw-r--r-- | sway/tree/container.c | 285 | ||||
-rw-r--r-- | sway/tree/layout.c | 10 | ||||
-rw-r--r-- | sway/tree/output.c | 108 | ||||
-rw-r--r-- | sway/tree/root.c | 2 | ||||
-rw-r--r-- | sway/tree/view.c | 10 | ||||
-rw-r--r-- | sway/tree/workspace.c | 64 |
17 files changed, 288 insertions, 287 deletions
diff --git a/sway/commands/move.c b/sway/commands/move.c index b256584b..087423de 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -247,7 +247,7 @@ static void workspace_move_to_output(struct sway_container *workspace, | |||
247 | } | 247 | } |
248 | 248 | ||
249 | // Try to remove an empty workspace from the destination output. | 249 | // Try to remove an empty workspace from the destination output. |
250 | container_reap_empty_recursive(new_output_focus); | 250 | container_reap_empty(new_output_focus); |
251 | 251 | ||
252 | output_sort_workspaces(output); | 252 | output_sort_workspaces(output); |
253 | seat_set_focus(seat, output); | 253 | seat_set_focus(seat, output); |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 0f3005f4..ea1e36ff 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <stdlib.h> | 5 | #include <stdlib.h> |
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <strings.h> | 7 | #include <strings.h> |
8 | #include <wlr/util/edges.h> | ||
8 | #include <wlr/util/log.h> | 9 | #include <wlr/util/log.h> |
9 | #include "sway/commands.h" | 10 | #include "sway/commands.h" |
10 | #include "sway/tree/arrange.h" | 11 | #include "sway/tree/arrange.h" |
@@ -250,10 +251,10 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
250 | } | 251 | } |
251 | } | 252 | } |
252 | 253 | ||
253 | enum resize_edge minor_edge = axis == RESIZE_AXIS_HORIZONTAL ? | 254 | enum wlr_edges minor_edge = axis == RESIZE_AXIS_HORIZONTAL ? |
254 | RESIZE_EDGE_LEFT : RESIZE_EDGE_TOP; | 255 | WLR_EDGE_LEFT : WLR_EDGE_TOP; |
255 | enum resize_edge major_edge = axis == RESIZE_AXIS_HORIZONTAL ? | 256 | enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? |
256 | RESIZE_EDGE_RIGHT : RESIZE_EDGE_BOTTOM; | 257 | WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; |
257 | 258 | ||
258 | for (int i = 0; i < parent->parent->children->length; i++) { | 259 | for (int i = 0; i < parent->parent->children->length; i++) { |
259 | struct sway_container *sibling = parent->parent->children->items[i]; | 260 | struct sway_container *sibling = parent->parent->children->items[i]; |
diff --git a/sway/config/output.c b/sway/config/output.c index 1d8cb3ef..7f9b1007 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -181,13 +181,11 @@ void apply_output_config(struct output_config *oc, struct sway_container *output | |||
181 | struct wlr_output *wlr_output = output->sway_output->wlr_output; | 181 | struct wlr_output *wlr_output = output->sway_output->wlr_output; |
182 | 182 | ||
183 | if (oc && oc->enabled == 0) { | 183 | if (oc && oc->enabled == 0) { |
184 | struct sway_output *sway_output = output->sway_output; | ||
185 | if (output->sway_output->bg_pid != 0) { | 184 | if (output->sway_output->bg_pid != 0) { |
186 | terminate_swaybg(output->sway_output->bg_pid); | 185 | terminate_swaybg(output->sway_output->bg_pid); |
187 | output->sway_output->bg_pid = 0; | 186 | output->sway_output->bg_pid = 0; |
188 | } | 187 | } |
189 | container_destroy(output); | 188 | output_begin_destroy(output); |
190 | sway_output->swayc = NULL; | ||
191 | wlr_output_layout_remove(root_container.sway_root->output_layout, | 189 | wlr_output_layout_remove(root_container.sway_root->output_layout, |
192 | wlr_output); | 190 | wlr_output); |
193 | return; | 191 | return; |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3d8bbff5..401d3c44 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -498,7 +498,7 @@ void output_damage_whole_container(struct sway_output *output, | |||
498 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { | 498 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { |
499 | struct sway_output *output = | 499 | struct sway_output *output = |
500 | wl_container_of(listener, output, damage_destroy); | 500 | wl_container_of(listener, output, damage_destroy); |
501 | container_destroy(output->swayc); | 501 | output_begin_destroy(output->swayc); |
502 | } | 502 | } |
503 | 503 | ||
504 | static void handle_destroy(struct wl_listener *listener, void *data) { | 504 | static void handle_destroy(struct wl_listener *listener, void *data) { |
@@ -506,7 +506,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
506 | wl_signal_emit(&output->events.destroy, output); | 506 | wl_signal_emit(&output->events.destroy, output); |
507 | 507 | ||
508 | if (output->swayc) { | 508 | if (output->swayc) { |
509 | container_destroy(output->swayc); | 509 | output_begin_destroy(output->swayc); |
510 | } | 510 | } |
511 | 511 | ||
512 | wl_list_remove(&output->link); | 512 | wl_list_remove(&output->link); |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index f82e5ef2..c18529fb 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -54,7 +54,22 @@ static void transaction_destroy(struct sway_transaction *transaction) { | |||
54 | con->instruction = NULL; | 54 | con->instruction = NULL; |
55 | } | 55 | } |
56 | if (con->destroying && con->ntxnrefs == 0) { | 56 | if (con->destroying && con->ntxnrefs == 0) { |
57 | container_free(con); | 57 | switch (con->type) { |
58 | case C_ROOT: | ||
59 | break; | ||
60 | case C_OUTPUT: | ||
61 | output_destroy(con); | ||
62 | break; | ||
63 | case C_WORKSPACE: | ||
64 | workspace_destroy(con); | ||
65 | break; | ||
66 | case C_CONTAINER: | ||
67 | case C_VIEW: | ||
68 | container_destroy(con); | ||
69 | break; | ||
70 | case C_TYPES: | ||
71 | break; | ||
72 | } | ||
58 | } | 73 | } |
59 | free(instruction); | 74 | free(instruction); |
60 | } | 75 | } |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index aae129bd..f5aaa575 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -448,7 +448,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
448 | wl_list_remove(&xdg_shell_view->map.link); | 448 | wl_list_remove(&xdg_shell_view->map.link); |
449 | wl_list_remove(&xdg_shell_view->unmap.link); | 449 | wl_list_remove(&xdg_shell_view->unmap.link); |
450 | view->wlr_xdg_surface = NULL; | 450 | view->wlr_xdg_surface = NULL; |
451 | view_destroy(view); | 451 | view_begin_destroy(view); |
452 | } | 452 | } |
453 | 453 | ||
454 | struct sway_view *view_from_wlr_xdg_surface( | 454 | struct sway_view *view_from_wlr_xdg_surface( |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 277c53a3..f623b77b 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -441,7 +441,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
441 | wl_list_remove(&xdg_shell_v6_view->map.link); | 441 | wl_list_remove(&xdg_shell_v6_view->map.link); |
442 | wl_list_remove(&xdg_shell_v6_view->unmap.link); | 442 | wl_list_remove(&xdg_shell_v6_view->unmap.link); |
443 | view->wlr_xdg_surface_v6 = NULL; | 443 | view->wlr_xdg_surface_v6 = NULL; |
444 | view_destroy(view); | 444 | view_begin_destroy(view); |
445 | } | 445 | } |
446 | 446 | ||
447 | struct sway_view *view_from_wlr_xdg_surface_v6( | 447 | struct sway_view *view_from_wlr_xdg_surface_v6( |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index ce7235e4..6fcc850d 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -341,7 +341,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
341 | wl_list_remove(&xwayland_view->set_hints.link); | 341 | wl_list_remove(&xwayland_view->set_hints.link); |
342 | wl_list_remove(&xwayland_view->map.link); | 342 | wl_list_remove(&xwayland_view->map.link); |
343 | wl_list_remove(&xwayland_view->unmap.link); | 343 | wl_list_remove(&xwayland_view->unmap.link); |
344 | view_destroy(&xwayland_view->view); | 344 | view_begin_destroy(&xwayland_view->view); |
345 | } | 345 | } |
346 | 346 | ||
347 | static void handle_unmap(struct wl_listener *listener, void *data) { | 347 | static void handle_unmap(struct wl_listener *listener, void *data) { |
diff --git a/sway/input/seat.c b/sway/input/seat.c index caee37a6..997d7815 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -694,13 +694,11 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
694 | 694 | ||
695 | // clean up unfocused empty workspace on new output | 695 | // clean up unfocused empty workspace on new output |
696 | if (new_output_last_ws) { | 696 | if (new_output_last_ws) { |
697 | if (!workspace_is_visible(new_output_last_ws) | 697 | workspace_consider_destroy(new_output_last_ws); |
698 | && workspace_is_empty(new_output_last_ws)) { | 698 | if (new_output_last_ws->destroying && |
699 | if (last_workspace == new_output_last_ws) { | 699 | last_workspace == new_output_last_ws) { |
700 | last_focus = NULL; | 700 | last_focus = NULL; |
701 | last_workspace = NULL; | 701 | last_workspace = NULL; |
702 | } | ||
703 | container_destroy(new_output_last_ws); | ||
704 | } | 702 | } |
705 | } | 703 | } |
706 | 704 | ||
@@ -716,12 +714,9 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
716 | if (notify && last_workspace != new_workspace) { | 714 | if (notify && last_workspace != new_workspace) { |
717 | ipc_event_workspace(last_workspace, new_workspace, "focus"); | 715 | ipc_event_workspace(last_workspace, new_workspace, "focus"); |
718 | } | 716 | } |
719 | if (!workspace_is_visible(last_workspace) | 717 | workspace_consider_destroy(last_workspace); |
720 | && workspace_is_empty(last_workspace)) { | 718 | if (last_workspace->destroying && last_workspace == last_focus) { |
721 | if (last_workspace == last_focus) { | 719 | last_focus = NULL; |
722 | last_focus = NULL; | ||
723 | } | ||
724 | container_destroy(last_workspace); | ||
725 | } | 720 | } |
726 | } | 721 | } |
727 | 722 | ||
@@ -984,7 +979,7 @@ void seat_begin_resize_floating(struct sway_seat *seat, | |||
984 | seat->op_resize_preserve_ratio = keyboard && | 979 | seat->op_resize_preserve_ratio = keyboard && |
985 | (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); | 980 | (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); |
986 | seat->op_resize_edge = edge == WLR_EDGE_NONE ? | 981 | seat->op_resize_edge = edge == WLR_EDGE_NONE ? |
987 | RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT : edge; | 982 | WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; |
988 | seat->op_button = button; | 983 | seat->op_button = button; |
989 | seat->op_ref_lx = seat->cursor->cursor->x; | 984 | seat->op_ref_lx = seat->cursor->cursor->x; |
990 | seat->op_ref_ly = seat->cursor->cursor->y; | 985 | seat->op_ref_ly = seat->cursor->cursor->y; |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index f40af043..06cb7e11 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/config.h" | 5 | #include "sway/config.h" |
6 | #include "sway/ipc-json.h" | 6 | #include "sway/ipc-json.h" |
7 | #include "sway/tree/container.h" | 7 | #include "sway/tree/container.h" |
8 | #include "sway/tree/view.h" | ||
8 | #include "sway/tree/workspace.h" | 9 | #include "sway/tree/workspace.h" |
9 | #include "sway/output.h" | 10 | #include "sway/output.h" |
10 | #include "sway/input/input-manager.h" | 11 | #include "sway/input/input-manager.h" |
@@ -192,6 +193,16 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
192 | c->name ? json_object_new_string(c->name) : NULL); | 193 | c->name ? json_object_new_string(c->name) : NULL); |
193 | json_object_object_add(object, "type", json_object_new_string("con")); | 194 | json_object_object_add(object, "type", json_object_new_string("con")); |
194 | 195 | ||
196 | if (c->type == C_VIEW) { | ||
197 | const char *app_id = view_get_app_id(c->sway_view); | ||
198 | json_object_object_add(object, "app_id", | ||
199 | app_id ? json_object_new_string(app_id) : NULL); | ||
200 | |||
201 | const char *class = view_get_class(c->sway_view); | ||
202 | json_object_object_add(object, "class", | ||
203 | class ? json_object_new_string(class) : NULL); | ||
204 | } | ||
205 | |||
195 | if (c->parent) { | 206 | if (c->parent) { |
196 | json_object_object_add(object, "layout", | 207 | json_object_object_add(object, "layout", |
197 | json_object_new_string(ipc_json_layout_description(c->layout))); | 208 | json_object_new_string(ipc_json_layout_description(c->layout))); |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index cf4a5d9a..a4b058f3 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -206,10 +206,30 @@ static void arrange_workspace(struct sway_container *workspace) { | |||
206 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", | 206 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", |
207 | area->width, area->height, area->x, area->y); | 207 | area->width, area->height, area->x, area->y); |
208 | remove_gaps(workspace); | 208 | remove_gaps(workspace); |
209 | |||
210 | double prev_x = workspace->x; | ||
211 | double prev_y = workspace->y; | ||
209 | workspace->width = area->width; | 212 | workspace->width = area->width; |
210 | workspace->height = area->height; | 213 | workspace->height = area->height; |
211 | workspace->x = output->x + area->x; | 214 | workspace->x = output->x + area->x; |
212 | workspace->y = output->y + area->y; | 215 | workspace->y = output->y + area->y; |
216 | |||
217 | // Adjust any floating containers | ||
218 | double diff_x = workspace->x - prev_x; | ||
219 | double diff_y = workspace->y - prev_y; | ||
220 | for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) { | ||
221 | struct sway_container *floater = | ||
222 | workspace->sway_workspace->floating->items[i]; | ||
223 | container_floating_translate(floater, diff_x, diff_y); | ||
224 | double center_x = floater->x + floater->width / 2; | ||
225 | double center_y = floater->y + floater->height / 2; | ||
226 | struct wlr_box workspace_box; | ||
227 | container_get_box(workspace, &workspace_box); | ||
228 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { | ||
229 | container_floating_move_to_center(floater); | ||
230 | } | ||
231 | } | ||
232 | |||
213 | add_gaps(workspace); | 233 | add_gaps(workspace); |
214 | container_set_dirty(workspace); | 234 | container_set_dirty(workspace); |
215 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, | 235 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 6ea0cc94..6da6212c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -104,209 +104,52 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
104 | return c; | 104 | return c; |
105 | } | 105 | } |
106 | 106 | ||
107 | static void container_workspace_free(struct sway_workspace *ws) { | 107 | void container_destroy(struct sway_container *con) { |
108 | list_foreach(ws->output_priority, free); | 108 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, |
109 | list_free(ws->output_priority); | 109 | "Expected a container or view")) { |
110 | list_free(ws->floating); | 110 | return; |
111 | free(ws); | 111 | } |
112 | } | 112 | if (!sway_assert(con->destroying, |
113 | |||
114 | void container_free(struct sway_container *cont) { | ||
115 | if (!sway_assert(cont->destroying, | ||
116 | "Tried to free container which wasn't marked as destroying")) { | 113 | "Tried to free container which wasn't marked as destroying")) { |
117 | return; | 114 | return; |
118 | } | 115 | } |
119 | if (!sway_assert(cont->ntxnrefs == 0, "Tried to free container " | 116 | if (!sway_assert(con->ntxnrefs == 0, "Tried to free container " |
120 | "which is still referenced by transactions")) { | 117 | "which is still referenced by transactions")) { |
121 | return; | 118 | return; |
122 | } | 119 | } |
123 | free(cont->name); | 120 | free(con->name); |
124 | free(cont->formatted_title); | 121 | free(con->formatted_title); |
125 | wlr_texture_destroy(cont->title_focused); | 122 | wlr_texture_destroy(con->title_focused); |
126 | wlr_texture_destroy(cont->title_focused_inactive); | 123 | wlr_texture_destroy(con->title_focused_inactive); |
127 | wlr_texture_destroy(cont->title_unfocused); | 124 | wlr_texture_destroy(con->title_unfocused); |
128 | wlr_texture_destroy(cont->title_urgent); | 125 | wlr_texture_destroy(con->title_urgent); |
129 | list_free(cont->children); | 126 | list_free(con->children); |
130 | list_free(cont->current.children); | 127 | list_free(con->current.children); |
131 | list_free(cont->outputs); | 128 | list_free(con->outputs); |
132 | |||
133 | switch (cont->type) { | ||
134 | case C_ROOT: | ||
135 | break; | ||
136 | case C_OUTPUT: | ||
137 | break; | ||
138 | case C_WORKSPACE: | ||
139 | container_workspace_free(cont->sway_workspace); | ||
140 | break; | ||
141 | case C_CONTAINER: | ||
142 | break; | ||
143 | case C_VIEW: | ||
144 | { | ||
145 | struct sway_view *view = cont->sway_view; | ||
146 | view->swayc = NULL; | ||
147 | free(view->title_format); | ||
148 | view->title_format = NULL; | ||
149 | |||
150 | if (view->destroying) { | ||
151 | view_free(view); | ||
152 | } | ||
153 | } | ||
154 | break; | ||
155 | case C_TYPES: | ||
156 | sway_assert(false, "Didn't expect to see C_TYPES here"); | ||
157 | break; | ||
158 | } | ||
159 | |||
160 | free(cont); | ||
161 | } | ||
162 | |||
163 | static struct sway_container *container_destroy_noreaping( | ||
164 | struct sway_container *con); | ||
165 | |||
166 | static struct sway_container *container_workspace_destroy( | ||
167 | struct sway_container *workspace) { | ||
168 | if (!sway_assert(workspace, "cannot destroy null workspace")) { | ||
169 | return NULL; | ||
170 | } | ||
171 | |||
172 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | ||
173 | |||
174 | // If we're destroying the output, it will be NULL here. Return the root so | ||
175 | // that it doesn't appear that the workspace has refused to be destoyed, | ||
176 | // which would leave it in a broken state with no parent. | ||
177 | if (output == NULL) { | ||
178 | return &root_container; | ||
179 | } | ||
180 | |||
181 | // Do not destroy this if it's the last workspace on this output | ||
182 | if (output->children->length == 1) { | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | wlr_log(WLR_DEBUG, "destroying workspace '%s'", workspace->name); | ||
187 | |||
188 | if (!workspace_is_empty(workspace)) { | ||
189 | // Move children to a different workspace on this output | ||
190 | struct sway_container *new_workspace = NULL; | ||
191 | for (int i = 0; i < output->children->length; i++) { | ||
192 | if (output->children->items[i] != workspace) { | ||
193 | new_workspace = output->children->items[i]; | ||
194 | break; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | wlr_log(WLR_DEBUG, "moving children to different workspace '%s' -> '%s'", | ||
199 | workspace->name, new_workspace->name); | ||
200 | for (int i = 0; i < workspace->children->length; i++) { | ||
201 | container_move_to(workspace->children->items[i], new_workspace); | ||
202 | } | ||
203 | list_t *floating = workspace->sway_workspace->floating; | ||
204 | for (int i = 0; i < floating->length; i++) { | ||
205 | struct sway_container *floater = floating->items[i]; | ||
206 | container_remove_child(floater); | ||
207 | workspace_add_floating(new_workspace, floater); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | return output; | ||
212 | } | ||
213 | |||
214 | static void untrack_output(struct sway_container *con, void *data) { | ||
215 | struct sway_output *output = data; | ||
216 | int index = list_find(con->outputs, output); | ||
217 | if (index != -1) { | ||
218 | list_del(con->outputs, index); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static struct sway_container *container_output_destroy( | ||
223 | struct sway_container *output) { | ||
224 | if (!sway_assert(output, "cannot destroy null output")) { | ||
225 | return NULL; | ||
226 | } | ||
227 | |||
228 | if (output->children->length > 0) { | ||
229 | // TODO save workspaces when there are no outputs. | ||
230 | // TODO also check if there will ever be no outputs except for exiting | ||
231 | // program | ||
232 | if (root_container.children->length > 1) { | ||
233 | // Move workspace from this output to another output | ||
234 | struct sway_container *fallback_output = | ||
235 | root_container.children->items[0]; | ||
236 | if (fallback_output == output) { | ||
237 | fallback_output = root_container.children->items[1]; | ||
238 | } | ||
239 | |||
240 | while (output->children->length) { | ||
241 | struct sway_container *workspace = output->children->items[0]; | ||
242 | |||
243 | struct sway_container *new_output = | ||
244 | workspace_output_get_highest_available(workspace, output); | ||
245 | if (!new_output) { | ||
246 | new_output = fallback_output; | ||
247 | workspace_output_add_priority(workspace, new_output); | ||
248 | } | ||
249 | 129 | ||
250 | container_remove_child(workspace); | 130 | if (con->type == C_VIEW) { |
251 | if (!workspace_is_empty(workspace)) { | 131 | struct sway_view *view = con->sway_view; |
252 | container_add_child(new_output, workspace); | 132 | view->swayc = NULL; |
253 | ipc_event_workspace(NULL, workspace, "move"); | 133 | free(view->title_format); |
254 | } else { | 134 | view->title_format = NULL; |
255 | container_destroy(workspace); | ||
256 | } | ||
257 | 135 | ||
258 | output_sort_workspaces(new_output); | 136 | if (view->destroying) { |
259 | } | 137 | view_destroy(view); |
260 | } | 138 | } |
261 | } | 139 | } |
262 | 140 | ||
263 | root_for_each_container(untrack_output, output->sway_output); | 141 | free(con); |
264 | |||
265 | wl_list_remove(&output->sway_output->mode.link); | ||
266 | wl_list_remove(&output->sway_output->transform.link); | ||
267 | wl_list_remove(&output->sway_output->scale.link); | ||
268 | |||
269 | wl_list_remove(&output->sway_output->damage_destroy.link); | ||
270 | wl_list_remove(&output->sway_output->damage_frame.link); | ||
271 | |||
272 | output->sway_output->swayc = NULL; | ||
273 | output->sway_output = NULL; | ||
274 | |||
275 | wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | ||
276 | |||
277 | return &root_container; | ||
278 | } | 142 | } |
279 | 143 | ||
280 | /** | 144 | void container_begin_destroy(struct sway_container *con) { |
281 | * Implement the actual destroy logic, without reaping. | 145 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, |
282 | */ | 146 | "Expected a container or view")) { |
283 | static struct sway_container *container_destroy_noreaping( | 147 | return; |
284 | struct sway_container *con) { | ||
285 | if (con == NULL) { | ||
286 | return NULL; | ||
287 | } | ||
288 | if (con->destroying) { | ||
289 | return NULL; | ||
290 | } | 148 | } |
291 | 149 | ||
292 | wl_signal_emit(&con->events.destroy, con); | 150 | wl_signal_emit(&con->events.destroy, con); |
293 | |||
294 | // emit IPC event | ||
295 | if (con->type == C_VIEW) { | 151 | if (con->type == C_VIEW) { |
296 | ipc_event_window(con, "close"); | 152 | ipc_event_window(con, "close"); |
297 | } else if (con->type == C_WORKSPACE) { | ||
298 | ipc_event_workspace(NULL, con, "empty"); | ||
299 | } | ||
300 | |||
301 | // The below functions move their children to somewhere else. | ||
302 | if (con->type == C_OUTPUT) { | ||
303 | container_output_destroy(con); | ||
304 | } else if (con->type == C_WORKSPACE) { | ||
305 | // Workspaces will refuse to be destroyed if they're the last workspace | ||
306 | // on their output. | ||
307 | if (!container_workspace_destroy(con)) { | ||
308 | return NULL; | ||
309 | } | ||
310 | } | 153 | } |
311 | 154 | ||
312 | container_end_mouse_operation(con); | 155 | container_end_mouse_operation(con); |
@@ -318,51 +161,22 @@ static struct sway_container *container_destroy_noreaping( | |||
318 | root_scratchpad_remove_container(con); | 161 | root_scratchpad_remove_container(con); |
319 | } | 162 | } |
320 | 163 | ||
321 | if (!con->parent) { | 164 | if (con->parent) { |
322 | return NULL; | 165 | container_remove_child(con); |
323 | } | ||
324 | |||
325 | return container_remove_child(con); | ||
326 | } | ||
327 | |||
328 | bool container_reap_empty(struct sway_container *con) { | ||
329 | switch (con->type) { | ||
330 | case C_ROOT: | ||
331 | case C_OUTPUT: | ||
332 | // dont reap these | ||
333 | break; | ||
334 | case C_WORKSPACE: | ||
335 | if (!workspace_is_visible(con) && workspace_is_empty(con)) { | ||
336 | wlr_log(WLR_DEBUG, "Destroying workspace via reaper"); | ||
337 | container_destroy_noreaping(con); | ||
338 | return true; | ||
339 | } | ||
340 | break; | ||
341 | case C_CONTAINER: | ||
342 | if (con->children->length == 0) { | ||
343 | container_destroy_noreaping(con); | ||
344 | return true; | ||
345 | } | ||
346 | case C_VIEW: | ||
347 | break; | ||
348 | case C_TYPES: | ||
349 | sway_assert(false, "container_reap_empty called on an invalid " | ||
350 | "container"); | ||
351 | break; | ||
352 | } | 166 | } |
353 | |||
354 | return false; | ||
355 | } | 167 | } |
356 | 168 | ||
357 | struct sway_container *container_reap_empty_recursive( | 169 | struct sway_container *container_reap_empty(struct sway_container *con) { |
358 | struct sway_container *con) { | 170 | while (con && con->type == C_CONTAINER) { |
359 | while (con) { | ||
360 | struct sway_container *next = con->parent; | 171 | struct sway_container *next = con->parent; |
361 | if (!container_reap_empty(con)) { | 172 | if (con->children->length == 0) { |
362 | break; | 173 | container_begin_destroy(con); |
363 | } | 174 | } |
364 | con = next; | 175 | con = next; |
365 | } | 176 | } |
177 | if (con && con->type == C_WORKSPACE) { | ||
178 | workspace_consider_destroy(con); | ||
179 | } | ||
366 | return con; | 180 | return con; |
367 | } | 181 | } |
368 | 182 | ||
@@ -371,34 +185,12 @@ struct sway_container *container_flatten(struct sway_container *container) { | |||
371 | struct sway_container *child = container->children->items[0]; | 185 | struct sway_container *child = container->children->items[0]; |
372 | struct sway_container *parent = container->parent; | 186 | struct sway_container *parent = container->parent; |
373 | container_replace_child(container, child); | 187 | container_replace_child(container, child); |
374 | container_destroy_noreaping(container); | 188 | container_begin_destroy(container); |
375 | container = parent; | 189 | container = parent; |
376 | } | 190 | } |
377 | return container; | 191 | return container; |
378 | } | 192 | } |
379 | 193 | ||
380 | /** | ||
381 | * container_destroy() is the first step in destroying a container. We'll emit | ||
382 | * events, detach it from the tree and mark it as destroying. The container will | ||
383 | * remain in memory until it's no longer used by a transaction, then it will be | ||
384 | * freed via container_free(). | ||
385 | * | ||
386 | * This function just wraps container_destroy_noreaping(), then does reaping. | ||
387 | */ | ||
388 | struct sway_container *container_destroy(struct sway_container *con) { | ||
389 | if (con->is_fullscreen) { | ||
390 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | ||
391 | ws->sway_workspace->fullscreen = NULL; | ||
392 | } | ||
393 | struct sway_container *parent = container_destroy_noreaping(con); | ||
394 | |||
395 | if (!parent) { | ||
396 | return NULL; | ||
397 | } | ||
398 | |||
399 | return container_reap_empty_recursive(parent); | ||
400 | } | ||
401 | |||
402 | static void container_close_func(struct sway_container *container, void *data) { | 194 | static void container_close_func(struct sway_container *container, void *data) { |
403 | if (container->type == C_VIEW) { | 195 | if (container->type == C_VIEW) { |
404 | view_close(container->sway_view); | 196 | view_close(container->sway_view); |
@@ -1201,6 +993,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { | |||
1201 | container_set_fullscreen(workspace->sway_workspace->fullscreen, false); | 993 | container_set_fullscreen(workspace->sway_workspace->fullscreen, false); |
1202 | } | 994 | } |
1203 | 995 | ||
996 | set_fullscreen_iterator(container, &enable); | ||
1204 | container_for_each_child(container, set_fullscreen_iterator, &enable); | 997 | container_for_each_child(container, set_fullscreen_iterator, &enable); |
1205 | 998 | ||
1206 | container->is_fullscreen = enable; | 999 | container->is_fullscreen = enable; |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ee7d7418..12e7342b 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -302,7 +302,7 @@ static void workspace_rejigger(struct sway_container *ws, | |||
302 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 302 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; |
303 | 303 | ||
304 | container_flatten(ws); | 304 | container_flatten(ws); |
305 | container_reap_empty_recursive(original_parent); | 305 | container_reap_empty(original_parent); |
306 | container_create_notify(new_parent); | 306 | container_create_notify(new_parent); |
307 | } | 307 | } |
308 | 308 | ||
@@ -325,7 +325,7 @@ static void move_out_of_tabs_stacks(struct sway_container *container, | |||
325 | container_insert_child(new_parent->parent, container, offs < 0 ? 0 : 1); | 325 | container_insert_child(new_parent->parent, container, offs < 0 ? 0 : 1); |
326 | } else { | 326 | } else { |
327 | container_insert_child(new_parent, container, offs < 0 ? 0 : 1); | 327 | container_insert_child(new_parent, container, offs < 0 ? 0 : 1); |
328 | container_reap_empty_recursive(new_parent->parent); | 328 | container_reap_empty(new_parent->parent); |
329 | container_flatten(new_parent->parent); | 329 | container_flatten(new_parent->parent); |
330 | } | 330 | } |
331 | container_create_notify(new_parent); | 331 | container_create_notify(new_parent); |
@@ -876,13 +876,13 @@ struct sway_container *container_split(struct sway_container *child, | |||
876 | } | 876 | } |
877 | 877 | ||
878 | void container_recursive_resize(struct sway_container *container, | 878 | void container_recursive_resize(struct sway_container *container, |
879 | double amount, enum resize_edge edge) { | 879 | double amount, enum wlr_edges edge) { |
880 | bool layout_match = true; | 880 | bool layout_match = true; |
881 | wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount); | 881 | wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount); |
882 | if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { | 882 | if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) { |
883 | container->width += amount; | 883 | container->width += amount; |
884 | layout_match = container->layout == L_HORIZ; | 884 | layout_match = container->layout == L_HORIZ; |
885 | } else if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { | 885 | } else if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) { |
886 | container->height += amount; | 886 | container->height += amount; |
887 | layout_match = container->layout == L_VERT; | 887 | layout_match = container->layout == L_VERT; |
888 | } | 888 | } |
diff --git a/sway/tree/output.c b/sway/tree/output.c index 6da63064..80636c11 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "log.h" | 10 | #include "log.h" |
11 | 11 | ||
12 | static void restore_workspaces(struct sway_container *output) { | 12 | static void restore_workspaces(struct sway_container *output) { |
13 | // Workspace output priority | ||
13 | for (int i = 0; i < root_container.children->length; i++) { | 14 | for (int i = 0; i < root_container.children->length; i++) { |
14 | struct sway_container *other = root_container.children->items[i]; | 15 | struct sway_container *other = root_container.children->items[i]; |
15 | if (other == output) { | 16 | if (other == output) { |
@@ -29,6 +30,15 @@ static void restore_workspaces(struct sway_container *output) { | |||
29 | } | 30 | } |
30 | } | 31 | } |
31 | 32 | ||
33 | // Saved workspaces | ||
34 | list_t *saved = root_container.sway_root->saved_workspaces; | ||
35 | for (int i = 0; i < saved->length; ++i) { | ||
36 | struct sway_container *ws = saved->items[i]; | ||
37 | container_add_child(output, ws); | ||
38 | ipc_event_workspace(NULL, ws, "move"); | ||
39 | } | ||
40 | saved->length = 0; | ||
41 | |||
32 | output_sort_workspaces(output); | 42 | output_sort_workspaces(output); |
33 | } | 43 | } |
34 | 44 | ||
@@ -68,7 +78,7 @@ struct sway_container *output_create( | |||
68 | output->sway_output = sway_output; | 78 | output->sway_output = sway_output; |
69 | output->name = strdup(name); | 79 | output->name = strdup(name); |
70 | if (output->name == NULL) { | 80 | if (output->name == NULL) { |
71 | container_destroy(output); | 81 | output_begin_destroy(output); |
72 | return NULL; | 82 | return NULL; |
73 | } | 83 | } |
74 | 84 | ||
@@ -103,6 +113,102 @@ struct sway_container *output_create( | |||
103 | return output; | 113 | return output; |
104 | } | 114 | } |
105 | 115 | ||
116 | static void output_evacuate(struct sway_container *output) { | ||
117 | if (!output->children->length) { | ||
118 | return; | ||
119 | } | ||
120 | struct sway_container *fallback_output = NULL; | ||
121 | if (root_container.children->length > 1) { | ||
122 | fallback_output = root_container.children->items[0]; | ||
123 | if (fallback_output == output) { | ||
124 | fallback_output = root_container.children->items[1]; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | while (output->children->length) { | ||
129 | struct sway_container *workspace = output->children->items[0]; | ||
130 | |||
131 | struct sway_container *new_output = | ||
132 | workspace_output_get_highest_available(workspace, output); | ||
133 | if (!new_output) { | ||
134 | new_output = fallback_output; | ||
135 | } | ||
136 | |||
137 | container_remove_child(workspace); | ||
138 | |||
139 | if (new_output) { | ||
140 | workspace_output_add_priority(workspace, new_output); | ||
141 | container_add_child(new_output, workspace); | ||
142 | output_sort_workspaces(new_output); | ||
143 | ipc_event_workspace(NULL, workspace, "move"); | ||
144 | } else { | ||
145 | list_add(root_container.sway_root->saved_workspaces, workspace); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | void output_destroy(struct sway_container *output) { | ||
151 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
152 | return; | ||
153 | } | ||
154 | if (!sway_assert(output->destroying, | ||
155 | "Tried to free output which wasn't marked as destroying")) { | ||
156 | return; | ||
157 | } | ||
158 | if (!sway_assert(output->ntxnrefs == 0, "Tried to free output " | ||
159 | "which is still referenced by transactions")) { | ||
160 | return; | ||
161 | } | ||
162 | free(output->name); | ||
163 | free(output->formatted_title); | ||
164 | wlr_texture_destroy(output->title_focused); | ||
165 | wlr_texture_destroy(output->title_focused_inactive); | ||
166 | wlr_texture_destroy(output->title_unfocused); | ||
167 | wlr_texture_destroy(output->title_urgent); | ||
168 | list_free(output->children); | ||
169 | list_free(output->current.children); | ||
170 | list_free(output->outputs); | ||
171 | free(output); | ||
172 | |||
173 | // NOTE: We don't actually destroy the sway_output here | ||
174 | } | ||
175 | |||
176 | static void untrack_output(struct sway_container *con, void *data) { | ||
177 | struct sway_output *output = data; | ||
178 | int index = list_find(con->outputs, output); | ||
179 | if (index != -1) { | ||
180 | list_del(con->outputs, index); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | void output_begin_destroy(struct sway_container *output) { | ||
185 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
186 | return; | ||
187 | } | ||
188 | wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | ||
189 | wl_signal_emit(&output->events.destroy, output); | ||
190 | |||
191 | output_evacuate(output); | ||
192 | |||
193 | output->destroying = true; | ||
194 | container_set_dirty(output); | ||
195 | |||
196 | root_for_each_container(untrack_output, output->sway_output); | ||
197 | |||
198 | wl_list_remove(&output->sway_output->mode.link); | ||
199 | wl_list_remove(&output->sway_output->transform.link); | ||
200 | wl_list_remove(&output->sway_output->scale.link); | ||
201 | wl_list_remove(&output->sway_output->damage_destroy.link); | ||
202 | wl_list_remove(&output->sway_output->damage_frame.link); | ||
203 | |||
204 | output->sway_output->swayc = NULL; | ||
205 | output->sway_output = NULL; | ||
206 | |||
207 | if (output->parent) { | ||
208 | container_remove_child(output); | ||
209 | } | ||
210 | } | ||
211 | |||
106 | void output_for_each_workspace(struct sway_container *output, | 212 | void output_for_each_workspace(struct sway_container *output, |
107 | void (*f)(struct sway_container *con, void *data), void *data) { | 213 | void (*f)(struct sway_container *con, void *data), void *data) { |
108 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 214 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { |
diff --git a/sway/tree/root.c b/sway/tree/root.c index c27ff2c3..5602f0a0 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c | |||
@@ -39,6 +39,7 @@ void root_create(void) { | |||
39 | wl_list_init(&root_container.sway_root->drag_icons); | 39 | wl_list_init(&root_container.sway_root->drag_icons); |
40 | wl_signal_init(&root_container.sway_root->events.new_container); | 40 | wl_signal_init(&root_container.sway_root->events.new_container); |
41 | root_container.sway_root->scratchpad = create_list(); | 41 | root_container.sway_root->scratchpad = create_list(); |
42 | root_container.sway_root->saved_workspaces = create_list(); | ||
42 | 43 | ||
43 | root_container.sway_root->output_layout_change.notify = | 44 | root_container.sway_root->output_layout_change.notify = |
44 | output_layout_handle_change; | 45 | output_layout_handle_change; |
@@ -50,6 +51,7 @@ void root_destroy(void) { | |||
50 | // sway_root | 51 | // sway_root |
51 | wl_list_remove(&root_container.sway_root->output_layout_change.link); | 52 | wl_list_remove(&root_container.sway_root->output_layout_change.link); |
52 | list_free(root_container.sway_root->scratchpad); | 53 | list_free(root_container.sway_root->scratchpad); |
54 | list_free(root_container.sway_root->saved_workspaces); | ||
53 | wlr_output_layout_destroy(root_container.sway_root->output_layout); | 55 | wlr_output_layout_destroy(root_container.sway_root->output_layout); |
54 | free(root_container.sway_root); | 56 | free(root_container.sway_root); |
55 | 57 | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index 7bf7325a..ba4a880f 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -35,7 +35,7 @@ void view_init(struct sway_view *view, enum sway_view_type type, | |||
35 | wl_signal_init(&view->events.unmap); | 35 | wl_signal_init(&view->events.unmap); |
36 | } | 36 | } |
37 | 37 | ||
38 | void view_free(struct sway_view *view) { | 38 | void view_destroy(struct sway_view *view) { |
39 | if (!sway_assert(view->surface == NULL, "Tried to free mapped view")) { | 39 | if (!sway_assert(view->surface == NULL, "Tried to free mapped view")) { |
40 | return; | 40 | return; |
41 | } | 41 | } |
@@ -75,14 +75,14 @@ void view_free(struct sway_view *view) { | |||
75 | * destroying flag will make the view get freed when the transaction is | 75 | * destroying flag will make the view get freed when the transaction is |
76 | * finished. | 76 | * finished. |
77 | */ | 77 | */ |
78 | void view_destroy(struct sway_view *view) { | 78 | void view_begin_destroy(struct sway_view *view) { |
79 | if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { | 79 | if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { |
80 | return; | 80 | return; |
81 | } | 81 | } |
82 | view->destroying = true; | 82 | view->destroying = true; |
83 | 83 | ||
84 | if (!view->swayc) { | 84 | if (!view->swayc) { |
85 | view_free(view); | 85 | view_destroy(view); |
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
@@ -560,7 +560,9 @@ void view_unmap(struct sway_view *view) { | |||
560 | } | 560 | } |
561 | 561 | ||
562 | bool was_fullscreen = view->swayc->is_fullscreen; | 562 | bool was_fullscreen = view->swayc->is_fullscreen; |
563 | struct sway_container *surviving_ancestor = container_destroy(view->swayc); | 563 | struct sway_container *parent = view->swayc->parent; |
564 | container_begin_destroy(view->swayc); | ||
565 | struct sway_container *surviving_ancestor = container_reap_empty(parent); | ||
564 | 566 | ||
565 | // If the workspace wasn't reaped | 567 | // If the workspace wasn't reaped |
566 | if (surviving_ancestor && surviving_ancestor->type >= C_WORKSPACE) { | 568 | if (surviving_ancestor && surviving_ancestor->type >= C_WORKSPACE) { |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 292f2c9a..93c4b3d3 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -79,6 +79,65 @@ struct sway_container *workspace_create(struct sway_container *output, | |||
79 | return workspace; | 79 | return workspace; |
80 | } | 80 | } |
81 | 81 | ||
82 | void workspace_destroy(struct sway_container *workspace) { | ||
83 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | ||
84 | return; | ||
85 | } | ||
86 | if (!sway_assert(workspace->destroying, | ||
87 | "Tried to free workspace which wasn't marked as destroying")) { | ||
88 | return; | ||
89 | } | ||
90 | if (!sway_assert(workspace->ntxnrefs == 0, "Tried to free workspace " | ||
91 | "which is still referenced by transactions")) { | ||
92 | return; | ||
93 | } | ||
94 | // sway_workspace | ||
95 | struct sway_workspace *ws = workspace->sway_workspace; | ||
96 | list_foreach(ws->output_priority, free); | ||
97 | list_free(ws->output_priority); | ||
98 | list_free(ws->floating); | ||
99 | free(ws); | ||
100 | |||
101 | // swayc | ||
102 | free(workspace->name); | ||
103 | free(workspace->formatted_title); | ||
104 | wlr_texture_destroy(workspace->title_focused); | ||
105 | wlr_texture_destroy(workspace->title_focused_inactive); | ||
106 | wlr_texture_destroy(workspace->title_unfocused); | ||
107 | wlr_texture_destroy(workspace->title_urgent); | ||
108 | list_free(workspace->children); | ||
109 | list_free(workspace->current.children); | ||
110 | list_free(workspace->outputs); | ||
111 | free(workspace); | ||
112 | } | ||
113 | |||
114 | void workspace_begin_destroy(struct sway_container *workspace) { | ||
115 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | ||
116 | return; | ||
117 | } | ||
118 | wlr_log(WLR_DEBUG, "Destroying workspace '%s'", workspace->name); | ||
119 | wl_signal_emit(&workspace->events.destroy, workspace); | ||
120 | ipc_event_workspace(NULL, workspace, "empty"); // intentional | ||
121 | |||
122 | workspace->destroying = true; | ||
123 | container_set_dirty(workspace); | ||
124 | |||
125 | if (workspace->parent) { | ||
126 | container_remove_child(workspace); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | void workspace_consider_destroy(struct sway_container *ws) { | ||
131 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
132 | return; | ||
133 | } | ||
134 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
135 | if (ws->children->length == 0 && ws->sway_workspace->floating->length == 0 | ||
136 | && seat_get_active_child(seat, ws->parent) != ws) { | ||
137 | workspace_begin_destroy(ws); | ||
138 | } | ||
139 | } | ||
140 | |||
82 | char *prev_workspace_name = NULL; | 141 | char *prev_workspace_name = NULL; |
83 | 142 | ||
84 | void next_name_map(struct sway_container *ws, void *data) { | 143 | void next_name_map(struct sway_container *ws, void *data) { |
@@ -205,6 +264,7 @@ char *workspace_next_name(const char *output_name) { | |||
205 | && workspace_by_name(wso->workspace) == NULL) { | 264 | && workspace_by_name(wso->workspace) == NULL) { |
206 | free(target); | 265 | free(target); |
207 | target = strdup(wso->workspace); | 266 | target = strdup(wso->workspace); |
267 | break; | ||
208 | } | 268 | } |
209 | } | 269 | } |
210 | if (target != NULL) { | 270 | if (target != NULL) { |
@@ -420,9 +480,7 @@ bool workspace_switch(struct sway_container *workspace, | |||
420 | // no op. We therefore need to send the IPC event and clean up the old | 480 | // no op. We therefore need to send the IPC event and clean up the old |
421 | // workspace here. | 481 | // workspace here. |
422 | ipc_event_workspace(active_ws, workspace, "focus"); | 482 | ipc_event_workspace(active_ws, workspace, "focus"); |
423 | if (!workspace_is_visible(active_ws) && workspace_is_empty(active_ws)) { | 483 | workspace_consider_destroy(active_ws); |
424 | container_destroy(active_ws); | ||
425 | } | ||
426 | } | 484 | } |
427 | seat_set_focus(seat, next); | 485 | seat_set_focus(seat, next); |
428 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | 486 | struct sway_container *output = container_parent(workspace, C_OUTPUT); |