diff options
-rw-r--r-- | include/sway/scratchpad.h | 26 | ||||
-rw-r--r-- | include/sway/server.h | 2 | ||||
-rw-r--r-- | include/sway/tree/container.h | 5 | ||||
-rw-r--r-- | sway/commands.c | 3 | ||||
-rw-r--r-- | sway/commands/move.c | 19 | ||||
-rw-r--r-- | sway/commands/scratchpad.c | 37 | ||||
-rw-r--r-- | sway/criteria.c | 8 | ||||
-rw-r--r-- | sway/meson.build | 2 | ||||
-rw-r--r-- | sway/scratchpad.c | 173 | ||||
-rw-r--r-- | sway/server.c | 3 | ||||
-rw-r--r-- | sway/tree/container.c | 8 | ||||
-rw-r--r-- | sway/tree/layout.c | 7 | ||||
-rw-r--r-- | sway/tree/view.c | 2 |
13 files changed, 290 insertions, 5 deletions
diff --git a/include/sway/scratchpad.h b/include/sway/scratchpad.h new file mode 100644 index 00000000..5af5256f --- /dev/null +++ b/include/sway/scratchpad.h | |||
@@ -0,0 +1,26 @@ | |||
1 | #ifndef _SWAY_SCRATCHPAD_H | ||
2 | #define _SWAY_SCRATCHPAD_H | ||
3 | |||
4 | #include "tree/container.h" | ||
5 | |||
6 | /** | ||
7 | * Move a container to the scratchpad. | ||
8 | */ | ||
9 | void scratchpad_add_container(struct sway_container *con); | ||
10 | |||
11 | /** | ||
12 | * Remove a container from the scratchpad. | ||
13 | */ | ||
14 | void scratchpad_remove_container(struct sway_container *con); | ||
15 | |||
16 | /** | ||
17 | * Show or hide the next container on the scratchpad. | ||
18 | */ | ||
19 | void scratchpad_toggle_auto(void); | ||
20 | |||
21 | /** | ||
22 | * Show or hide a specific container on the scratchpad. | ||
23 | */ | ||
24 | void scratchpad_toggle_container(struct sway_container *con); | ||
25 | |||
26 | #endif | ||
diff --git a/include/sway/server.h b/include/sway/server.h index 70bde6d4..6cef2e58 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -48,6 +48,8 @@ struct sway_server { | |||
48 | 48 | ||
49 | list_t *transactions; | 49 | list_t *transactions; |
50 | list_t *dirty_containers; | 50 | list_t *dirty_containers; |
51 | |||
52 | list_t *scratchpad; // struct sway_container | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | struct sway_server server; | 55 | struct sway_server server; |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 59c5b4c7..2a4be18c 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -135,6 +135,11 @@ struct sway_container { | |||
135 | 135 | ||
136 | struct sway_container *parent; | 136 | struct sway_container *parent; |
137 | 137 | ||
138 | // Indicates that the container is a scratchpad container. | ||
139 | // Both hidden and visible scratchpad containers have scratchpad=true. | ||
140 | // Hidden scratchpad containers have a NULL parent. | ||
141 | bool scratchpad; | ||
142 | |||
138 | float alpha; | 143 | float alpha; |
139 | 144 | ||
140 | struct wlr_texture *title_focused; | 145 | struct wlr_texture *title_focused; |
diff --git a/sway/commands.c b/sway/commands.c index f40f0e9d..fdae1961 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -149,6 +149,7 @@ static struct cmd_handler command_handlers[] = { | |||
149 | { "reload", cmd_reload }, | 149 | { "reload", cmd_reload }, |
150 | { "rename", cmd_rename }, | 150 | { "rename", cmd_rename }, |
151 | { "resize", cmd_resize }, | 151 | { "resize", cmd_resize }, |
152 | { "scratchpad", cmd_scratchpad }, | ||
152 | { "split", cmd_split }, | 153 | { "split", cmd_split }, |
153 | { "splith", cmd_splith }, | 154 | { "splith", cmd_splith }, |
154 | { "splitt", cmd_splitt }, | 155 | { "splitt", cmd_splitt }, |
@@ -326,7 +327,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | |||
326 | } while(head); | 327 | } while(head); |
327 | cleanup: | 328 | cleanup: |
328 | free(exec); | 329 | free(exec); |
329 | free(views); | 330 | list_free(views); |
330 | if (!results) { | 331 | if (!results) { |
331 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | 332 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); |
332 | } | 333 | } |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 6ec050a8..1940043d 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "sway/input/cursor.h" | 9 | #include "sway/input/cursor.h" |
10 | #include "sway/input/seat.h" | 10 | #include "sway/input/seat.h" |
11 | #include "sway/output.h" | 11 | #include "sway/output.h" |
12 | #include "sway/scratchpad.h" | ||
12 | #include "sway/tree/arrange.h" | 13 | #include "sway/tree/arrange.h" |
13 | #include "sway/tree/container.h" | 14 | #include "sway/tree/container.h" |
14 | #include "sway/tree/layout.h" | 15 | #include "sway/tree/layout.h" |
@@ -296,6 +297,19 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
296 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 297 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
297 | } | 298 | } |
298 | 299 | ||
300 | static struct cmd_results *move_to_scratchpad(struct sway_container *con) { | ||
301 | if (con->type != C_CONTAINER && con->type != C_VIEW) { | ||
302 | return cmd_results_new(CMD_INVALID, "move", | ||
303 | "Only views and containers can be moved to the scratchpad"); | ||
304 | } | ||
305 | if (con->scratchpad) { | ||
306 | return cmd_results_new(CMD_INVALID, "move", | ||
307 | "Container is already in the scratchpad"); | ||
308 | } | ||
309 | scratchpad_add_container(con); | ||
310 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
311 | } | ||
312 | |||
299 | struct cmd_results *cmd_move(int argc, char **argv) { | 313 | struct cmd_results *cmd_move(int argc, char **argv) { |
300 | struct cmd_results *error = NULL; | 314 | struct cmd_results *error = NULL; |
301 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { | 315 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { |
@@ -317,10 +331,9 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
317 | } else if (strcasecmp(argv[0], "workspace") == 0) { | 331 | } else if (strcasecmp(argv[0], "workspace") == 0) { |
318 | return cmd_move_workspace(current, argc, argv); | 332 | return cmd_move_workspace(current, argc, argv); |
319 | } else if (strcasecmp(argv[0], "scratchpad") == 0 | 333 | } else if (strcasecmp(argv[0], "scratchpad") == 0 |
320 | || (strcasecmp(argv[0], "to") == 0 | 334 | || (strcasecmp(argv[0], "to") == 0 && argc == 2 |
321 | && strcasecmp(argv[1], "scratchpad") == 0)) { | 335 | && strcasecmp(argv[1], "scratchpad") == 0)) { |
322 | // TODO: scratchpad | 336 | return move_to_scratchpad(current); |
323 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | ||
324 | } else if (strcasecmp(argv[0], "position") == 0) { | 337 | } else if (strcasecmp(argv[0], "position") == 0) { |
325 | return move_to_position(current, argc, argv); | 338 | return move_to_position(current, argc, argv); |
326 | } else if (strcasecmp(argv[0], "absolute") == 0) { | 339 | } else if (strcasecmp(argv[0], "absolute") == 0) { |
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c new file mode 100644 index 00000000..8a529cb4 --- /dev/null +++ b/sway/commands/scratchpad.c | |||
@@ -0,0 +1,37 @@ | |||
1 | #include "log.h" | ||
2 | #include "sway/commands.h" | ||
3 | #include "sway/config.h" | ||
4 | #include "sway/scratchpad.h" | ||
5 | #include "sway/server.h" | ||
6 | #include "sway/tree/container.h" | ||
7 | |||
8 | struct cmd_results *cmd_scratchpad(int argc, char **argv) { | ||
9 | struct cmd_results *error = NULL; | ||
10 | if ((error = checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1))) { | ||
11 | return error; | ||
12 | } | ||
13 | if (strcmp(argv[0], "show") != 0) { | ||
14 | return cmd_results_new(CMD_INVALID, "scratchpad", | ||
15 | "Expected 'scratchpad show'"); | ||
16 | } | ||
17 | if (!server.scratchpad->length) { | ||
18 | return cmd_results_new(CMD_INVALID, "scratchpad", | ||
19 | "Scratchpad is empty"); | ||
20 | } | ||
21 | |||
22 | if (config->handler_context.using_criteria) { | ||
23 | // If using criteria, this command is executed for every container which | ||
24 | // matches the criteria. If this container isn't in the scratchpad, | ||
25 | // we'll just silently return a success. | ||
26 | struct sway_container *con = config->handler_context.current_container; | ||
27 | wlr_log(WLR_INFO, "cmd_scratchpad(%s)", con->name); | ||
28 | if (!con->scratchpad) { | ||
29 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
30 | } | ||
31 | scratchpad_toggle_container(con); | ||
32 | } else { | ||
33 | scratchpad_toggle_auto(); | ||
34 | } | ||
35 | |||
36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
37 | } | ||
diff --git a/sway/criteria.c b/sway/criteria.c index e2b248de..6af97d5b 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -225,6 +225,14 @@ list_t *criteria_get_views(struct criteria *criteria) { | |||
225 | }; | 225 | }; |
226 | container_for_each_descendant_dfs(&root_container, | 226 | container_for_each_descendant_dfs(&root_container, |
227 | criteria_get_views_iterator, &data); | 227 | criteria_get_views_iterator, &data); |
228 | |||
229 | // Scratchpad items which are hidden are not in the tree. | ||
230 | for (int i = 0; i < server.scratchpad->length; ++i) { | ||
231 | struct sway_container *con = server.scratchpad->items[i]; | ||
232 | if (!con->parent) { | ||
233 | criteria_get_views_iterator(con, &data); | ||
234 | } | ||
235 | } | ||
228 | return matches; | 236 | return matches; |
229 | } | 237 | } |
230 | 238 | ||
diff --git a/sway/meson.build b/sway/meson.build index f4fdc8ea..30c848e2 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -7,6 +7,7 @@ sway_sources = files( | |||
7 | 'debug-tree.c', | 7 | 'debug-tree.c', |
8 | 'ipc-json.c', | 8 | 'ipc-json.c', |
9 | 'ipc-server.c', | 9 | 'ipc-server.c', |
10 | 'scratchpad.c', | ||
10 | 'security.c', | 11 | 'security.c', |
11 | 12 | ||
12 | 'desktop/desktop.c', | 13 | 'desktop/desktop.c', |
@@ -67,6 +68,7 @@ sway_sources = files( | |||
67 | 'commands/reload.c', | 68 | 'commands/reload.c', |
68 | 'commands/rename.c', | 69 | 'commands/rename.c', |
69 | 'commands/resize.c', | 70 | 'commands/resize.c', |
71 | 'commands/scratchpad.c', | ||
70 | 'commands/seat.c', | 72 | 'commands/seat.c', |
71 | 'commands/seat/attach.c', | 73 | 'commands/seat/attach.c', |
72 | 'commands/seat/cursor.c', | 74 | 'commands/seat/cursor.c', |
diff --git a/sway/scratchpad.c b/sway/scratchpad.c new file mode 100644 index 00000000..e1f931a4 --- /dev/null +++ b/sway/scratchpad.c | |||
@@ -0,0 +1,173 @@ | |||
1 | #define _XOPEN_SOURCE 700 | ||
2 | #include <stdlib.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdbool.h> | ||
5 | #include "sway/scratchpad.h" | ||
6 | #include "sway/input/seat.h" | ||
7 | #include "sway/tree/arrange.h" | ||
8 | #include "sway/tree/container.h" | ||
9 | #include "sway/tree/view.h" | ||
10 | #include "sway/tree/workspace.h" | ||
11 | #include "list.h" | ||
12 | #include "log.h" | ||
13 | |||
14 | void scratchpad_add_container(struct sway_container *con) { | ||
15 | if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) { | ||
16 | return; | ||
17 | } | ||
18 | con->scratchpad = true; | ||
19 | list_add(server.scratchpad, con); | ||
20 | |||
21 | struct sway_container *parent = con->parent; | ||
22 | container_set_floating(con, true); | ||
23 | container_remove_child(con); | ||
24 | arrange_windows(parent); | ||
25 | |||
26 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
27 | seat_set_focus(seat, seat_get_focus_inactive(seat, parent)); | ||
28 | } | ||
29 | |||
30 | void scratchpad_remove_container(struct sway_container *con) { | ||
31 | if (!sway_assert(con->scratchpad, "Container is not in scratchpad")) { | ||
32 | return; | ||
33 | } | ||
34 | con->scratchpad = false; | ||
35 | for (int i = 0; i < server.scratchpad->length; ++i) { | ||
36 | if (server.scratchpad->items[i] == con) { | ||
37 | list_del(server.scratchpad, i); | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * Show a single scratchpad container. | ||
45 | * The container might be visible on another workspace already. | ||
46 | */ | ||
47 | static void scratchpad_show(struct sway_container *con) { | ||
48 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
49 | struct sway_container *ws = seat_get_focus(seat); | ||
50 | if (ws->type != C_WORKSPACE) { | ||
51 | ws = container_parent(ws, C_WORKSPACE); | ||
52 | } | ||
53 | |||
54 | // If the current con or any of its parents are in fullscreen mode, we | ||
55 | // first need to disable it before showing the scratchpad con. | ||
56 | if (ws->sway_workspace->fullscreen) { | ||
57 | view_set_fullscreen(ws->sway_workspace->fullscreen, false); | ||
58 | } | ||
59 | |||
60 | // Show the container | ||
61 | if (con->parent) { | ||
62 | container_remove_child(con); | ||
63 | } | ||
64 | container_add_child(ws->sway_workspace->floating, con); | ||
65 | |||
66 | // Make sure the container's center point overlaps this workspace | ||
67 | double center_lx = con->x + con->width / 2; | ||
68 | double center_ly = con->y + con->height / 2; | ||
69 | |||
70 | struct wlr_box workspace_box; | ||
71 | container_get_box(ws, &workspace_box); | ||
72 | if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { | ||
73 | // Maybe resize it | ||
74 | if (con->width > ws->width || con->height > ws->height) { | ||
75 | // TODO: Do this properly once we can float C_CONTAINERs | ||
76 | if (con->type == C_VIEW) { | ||
77 | view_init_floating(con->sway_view); | ||
78 | arrange_windows(con); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | // Center it | ||
83 | double new_lx = ws->x + (ws->width - con->width) / 2; | ||
84 | double new_ly = ws->y + (ws->height - con->height) / 2; | ||
85 | container_floating_move_to(con, new_lx, new_ly); | ||
86 | } | ||
87 | |||
88 | seat_set_focus(seat, con); | ||
89 | |||
90 | container_set_dirty(con->parent); | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * Hide a single scratchpad container. | ||
95 | * The container might not be the focused container (eg. when using criteria). | ||
96 | */ | ||
97 | static void scratchpad_hide(struct sway_container *con) { | ||
98 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
99 | struct sway_container *focus = seat_get_focus(seat); | ||
100 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | ||
101 | |||
102 | container_remove_child(con); | ||
103 | arrange_windows(ws); | ||
104 | if (con == focus) { | ||
105 | seat_set_focus(seat, seat_get_focus_inactive(seat, ws)); | ||
106 | } | ||
107 | list_move_to_end(server.scratchpad, con); | ||
108 | } | ||
109 | |||
110 | void scratchpad_toggle_auto(void) { | ||
111 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
112 | struct sway_container *focus = seat_get_focus(seat); | ||
113 | struct sway_container *ws = focus->type == C_WORKSPACE ? | ||
114 | focus : container_parent(focus, C_WORKSPACE); | ||
115 | |||
116 | // Check if the currently focused window is a scratchpad window and should | ||
117 | // be hidden again. | ||
118 | if (focus->scratchpad) { | ||
119 | wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", | ||
120 | focus->name); | ||
121 | scratchpad_hide(focus); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | // Check if there is an unfocused scratchpad window on the current workspace | ||
126 | // and focus it. | ||
127 | for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) { | ||
128 | struct sway_container *floater = | ||
129 | ws->sway_workspace->floating->children->items[i]; | ||
130 | if (floater->scratchpad && focus != floater) { | ||
131 | wlr_log(WLR_DEBUG, | ||
132 | "Focusing other scratchpad window (%s) in this workspace", | ||
133 | floater->name); | ||
134 | scratchpad_show(floater); | ||
135 | return; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | // Check if there is a visible scratchpad window on another workspace. | ||
140 | // In this case we move it to the current workspace. | ||
141 | for (int i = 0; i < server.scratchpad->length; ++i) { | ||
142 | struct sway_container *con = server.scratchpad->items[i]; | ||
143 | if (con->parent) { | ||
144 | wlr_log(WLR_DEBUG, | ||
145 | "Moving a visible scratchpad window (%s) to this workspace", | ||
146 | con->name); | ||
147 | scratchpad_show(con); | ||
148 | return; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | // Take the container at the bottom of the scratchpad list | ||
153 | if (!sway_assert(server.scratchpad->length, "Scratchpad is empty")) { | ||
154 | return; | ||
155 | } | ||
156 | struct sway_container *con = server.scratchpad->items[0]; | ||
157 | wlr_log(WLR_DEBUG, "Showing %s from list", con->name); | ||
158 | scratchpad_show(con); | ||
159 | } | ||
160 | |||
161 | void scratchpad_toggle_container(struct sway_container *con) { | ||
162 | if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) { | ||
163 | return; | ||
164 | } | ||
165 | |||
166 | // Check if it matches a currently visible scratchpad window and hide it. | ||
167 | if (con->parent) { | ||
168 | scratchpad_hide(con); | ||
169 | return; | ||
170 | } | ||
171 | |||
172 | scratchpad_show(con); | ||
173 | } | ||
diff --git a/sway/server.c b/sway/server.c index 89dfbf8c..916e6b71 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -126,6 +126,8 @@ bool server_init(struct sway_server *server) { | |||
126 | server->dirty_containers = create_list(); | 126 | server->dirty_containers = create_list(); |
127 | server->transactions = create_list(); | 127 | server->transactions = create_list(); |
128 | 128 | ||
129 | server->scratchpad = create_list(); | ||
130 | |||
129 | input_manager = input_manager_create(server); | 131 | input_manager = input_manager_create(server); |
130 | return true; | 132 | return true; |
131 | } | 133 | } |
@@ -135,6 +137,7 @@ void server_fini(struct sway_server *server) { | |||
135 | wl_display_destroy(server->wl_display); | 137 | wl_display_destroy(server->wl_display); |
136 | list_free(server->dirty_containers); | 138 | list_free(server->dirty_containers); |
137 | list_free(server->transactions); | 139 | list_free(server->transactions); |
140 | list_free(server->scratchpad); | ||
138 | } | 141 | } |
139 | 142 | ||
140 | bool server_start_backend(struct sway_server *server) { | 143 | bool server_start_backend(struct sway_server *server) { |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 42c1d024..4f743c40 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "sway/input/seat.h" | 17 | #include "sway/input/seat.h" |
18 | #include "sway/ipc-server.h" | 18 | #include "sway/ipc-server.h" |
19 | #include "sway/output.h" | 19 | #include "sway/output.h" |
20 | #include "sway/scratchpad.h" | ||
20 | #include "sway/server.h" | 21 | #include "sway/server.h" |
21 | #include "sway/tree/arrange.h" | 22 | #include "sway/tree/arrange.h" |
22 | #include "sway/tree/layout.h" | 23 | #include "sway/tree/layout.h" |
@@ -328,6 +329,10 @@ static struct sway_container *container_destroy_noreaping( | |||
328 | con->destroying = true; | 329 | con->destroying = true; |
329 | container_set_dirty(con); | 330 | container_set_dirty(con); |
330 | 331 | ||
332 | if (con->scratchpad) { | ||
333 | scratchpad_remove_container(con); | ||
334 | } | ||
335 | |||
331 | if (!con->parent) { | 336 | if (!con->parent) { |
332 | return NULL; | 337 | return NULL; |
333 | } | 338 | } |
@@ -955,6 +960,9 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
955 | container_reap_empty_recursive(workspace); | 960 | container_reap_empty_recursive(workspace); |
956 | } else { | 961 | } else { |
957 | // Returning to tiled | 962 | // Returning to tiled |
963 | if (container->scratchpad) { | ||
964 | scratchpad_remove_container(container); | ||
965 | } | ||
958 | container_remove_child(container); | 966 | container_remove_child(container); |
959 | container_add_child(workspace, container); | 967 | container_add_child(workspace, container); |
960 | container->width = container->parent->width; | 968 | container->width = container->parent->width; |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 533906fa..af37611f 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -135,6 +135,10 @@ void container_add_child(struct sway_container *parent, | |||
135 | list_add(parent->children, child); | 135 | list_add(parent->children, child); |
136 | child->parent = parent; | 136 | child->parent = parent; |
137 | container_handle_fullscreen_reparent(child, old_parent); | 137 | container_handle_fullscreen_reparent(child, old_parent); |
138 | if (old_parent) { | ||
139 | container_set_dirty(old_parent); | ||
140 | } | ||
141 | container_set_dirty(child); | ||
138 | } | 142 | } |
139 | 143 | ||
140 | struct sway_container *container_remove_child(struct sway_container *child) { | 144 | struct sway_container *container_remove_child(struct sway_container *child) { |
@@ -153,6 +157,9 @@ struct sway_container *container_remove_child(struct sway_container *child) { | |||
153 | child->parent = NULL; | 157 | child->parent = NULL; |
154 | container_notify_subtree_changed(parent); | 158 | container_notify_subtree_changed(parent); |
155 | 159 | ||
160 | container_set_dirty(parent); | ||
161 | container_set_dirty(child); | ||
162 | |||
156 | return parent; | 163 | return parent; |
157 | } | 164 | } |
158 | 165 | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index 89150a69..9d88d7aa 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -1065,7 +1065,7 @@ void view_update_marks_textures(struct sway_view *view) { | |||
1065 | } | 1065 | } |
1066 | 1066 | ||
1067 | bool view_is_visible(struct sway_view *view) { | 1067 | bool view_is_visible(struct sway_view *view) { |
1068 | if (!view->swayc || view->swayc->destroying) { | 1068 | if (!view->swayc || view->swayc->destroying || !view->swayc->parent) { |
1069 | return false; | 1069 | return false; |
1070 | } | 1070 | } |
1071 | struct sway_container *workspace = | 1071 | struct sway_container *workspace = |