aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-03-30 11:58:17 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2018-03-30 13:49:34 -0400
commit49379dd0fc0758f89d7f4fa4fb5b08c7f4c26ae6 (patch)
treeb67a66382125811fde75e5c3dff37d7081860c78 /sway
parentMerge pull request #1664 from swaywm/xwayland-add-to-focused (diff)
downloadsway-49379dd0fc0758f89d7f4fa4fb5b08c7f4c26ae6.tar.gz
sway-49379dd0fc0758f89d7f4fa4fb5b08c7f4c26ae6.tar.zst
sway-49379dd0fc0758f89d7f4fa4fb5b08c7f4c26ae6.zip
Fix workspace deletion edge cases
Diffstat (limited to 'sway')
-rw-r--r--sway/desktop/xdg_shell_v6.c3
-rw-r--r--sway/desktop/xwayland.c20
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/container.c101
-rw-r--r--sway/tree/layout.c58
-rw-r--r--sway/tree/output.c36
-rw-r--r--sway/tree/view.c11
-rw-r--r--sway/tree/workspace.c56
8 files changed, 140 insertions, 146 deletions
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
92void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { 91void 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
122static void handle_unmap_notify(struct wl_listener *listener, void *data) { 117static 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/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..778108b4 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
21static list_t *bfs_queue; 21static 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
61void container_destroy(struct sway_container *cont) { 61struct 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 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
89struct sway_container *container_output_create( 91struct 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
205struct 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
238struct 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
277struct 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
294struct sway_container *container_set_layout(struct sway_container *container, 207struct 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..32e6a77c 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,40 @@ 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 && 105struct 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 container_workspace_destroy(container);
114 }
115 break;
116 } else if (container->type == C_CONTAINER) {
117 struct sway_container *parent = container->parent;
118 container_destroy(container);
119 container = parent;
120 } else {
121 container = container->parent;
122 }
123 }
124 return container;
110} 125}
111 126
112struct sway_container *container_remove_child(struct sway_container *child) { 127struct sway_container *container_remove_child(struct sway_container *child) {
113 int i;
114 struct sway_container *parent = child->parent; 128 struct sway_container *parent = child->parent;
115 for (i = 0; i < parent->children->length; ++i) { 129 for (int i = 0; i < parent->children->length; ++i) {
116 if (parent->children->items[i] == child) { 130 if (parent->children->items[i] == child) {
117 list_del(parent->children, i); 131 list_del(parent->children, i);
118 break; 132 break;
119 } 133 }
120 } 134 }
121 child->parent = NULL; 135 child->parent = NULL;
122 return parent; 136 return container_reap_empty(parent);
123}
124
125struct 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} 137}
137 138
138void container_move_to(struct sway_container* container, 139void container_move_to(struct sway_container* container,
@@ -145,16 +146,9 @@ void container_move_to(struct sway_container* container,
145 container->width = container->height = 0; 146 container->width = container->height = 0;
146 struct sway_container *new_parent = 147 struct sway_container *new_parent =
147 container_add_sibling(destination, container); 148 container_add_sibling(destination, container);
148 if (destination->type == C_WORKSPACE) { 149 if (old_parent) {
149 // If the workspace only has one child after adding one, it 150 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 } 151 }
156 old_parent = container_reap_empty(old_parent);
157 arrange_windows(old_parent, -1, -1);
158 arrange_windows(new_parent, -1, -1); 152 arrange_windows(new_parent, -1, -1);
159} 153}
160 154
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
6struct 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
7const char *view_get_title(struct sway_view *view) { 8const 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
99struct 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
211struct 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
389bool 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}