diff options
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 273 |
1 files changed, 177 insertions, 96 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index c686401c..eaf4c117 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | ||
2 | #include <stdint.h> | 3 | #include <stdint.h> |
3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
4 | #include <string.h> | 5 | #include <string.h> |
@@ -6,7 +7,6 @@ | |||
6 | #include <wayland-server.h> | 7 | #include <wayland-server.h> |
7 | #include <wlr/types/wlr_output_layout.h> | 8 | #include <wlr/types/wlr_output_layout.h> |
8 | #include <wlr/types/wlr_wl_shell.h> | 9 | #include <wlr/types/wlr_wl_shell.h> |
9 | #include "log.h" | ||
10 | #include "sway/config.h" | 10 | #include "sway/config.h" |
11 | #include "sway/input/input-manager.h" | 11 | #include "sway/input/input-manager.h" |
12 | #include "sway/input/seat.h" | 12 | #include "sway/input/seat.h" |
@@ -50,7 +50,7 @@ const char *container_type_to_str(enum sway_container_type type) { | |||
50 | } | 50 | } |
51 | } | 51 | } |
52 | 52 | ||
53 | static void notify_new_container(struct sway_container *container) { | 53 | void container_create_notify(struct sway_container *container) { |
54 | wl_signal_emit(&root_container.sway_root->events.new_container, container); | 54 | wl_signal_emit(&root_container.sway_root->events.new_container, container); |
55 | ipc_event_window(container, "new"); | 55 | ipc_event_window(container, "new"); |
56 | } | 56 | } |
@@ -76,21 +76,21 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
76 | return c; | 76 | return c; |
77 | } | 77 | } |
78 | 78 | ||
79 | static struct sway_container *_container_destroy(struct sway_container *cont) { | 79 | static void _container_destroy(struct sway_container *cont) { |
80 | if (cont == NULL) { | 80 | if (cont == NULL) { |
81 | return NULL; | 81 | return; |
82 | } | 82 | } |
83 | 83 | ||
84 | wl_signal_emit(&cont->events.destroy, cont); | 84 | wl_signal_emit(&cont->events.destroy, cont); |
85 | 85 | ||
86 | struct sway_container *parent = cont->parent; | 86 | struct sway_container *parent = cont->parent; |
87 | if (cont->children != NULL) { | 87 | if (cont->children != NULL && cont->children->length) { |
88 | // remove children until there are no more, container_destroy calls | 88 | // remove children until there are no more, container_destroy calls |
89 | // container_remove_child, which removes child from this container | 89 | // container_remove_child, which removes child from this container |
90 | while (cont->children != NULL && cont->children->length != 0) { | 90 | while (cont->children != NULL) { |
91 | struct sway_container *child = cont->children->items[0]; | 91 | struct sway_container *child = cont->children->items[0]; |
92 | container_remove_child(child); | 92 | container_remove_child(child); |
93 | container_destroy(child); | 93 | _container_destroy(child); |
94 | } | 94 | } |
95 | } | 95 | } |
96 | if (cont->marks) { | 96 | if (cont->marks) { |
@@ -106,106 +106,200 @@ static struct sway_container *_container_destroy(struct sway_container *cont) { | |||
106 | list_free(cont->children); | 106 | list_free(cont->children); |
107 | cont->children = NULL; | 107 | cont->children = NULL; |
108 | free(cont); | 108 | free(cont); |
109 | return parent; | ||
110 | } | 109 | } |
111 | 110 | ||
112 | struct sway_container *container_destroy(struct sway_container *cont) { | 111 | static struct sway_container *container_output_destroy( |
113 | struct sway_container *parent = _container_destroy(cont); | 112 | struct sway_container *output) { |
114 | parent = container_reap_empty(parent); | 113 | if (!sway_assert(output, "cannot destroy null output")) { |
115 | arrange_windows(&root_container, -1, -1); | 114 | return NULL; |
116 | return parent; | 115 | } |
117 | } | 116 | |
117 | if (output->children->length > 0) { | ||
118 | // TODO save workspaces when there are no outputs. | ||
119 | // TODO also check if there will ever be no outputs except for exiting | ||
120 | // program | ||
121 | if (root_container.children->length > 1) { | ||
122 | int p = root_container.children->items[0] == output; | ||
123 | // Move workspace from this output to another output | ||
124 | while (output->children->length) { | ||
125 | struct sway_container *child = output->children->items[0]; | ||
126 | container_remove_child(child); | ||
127 | container_add_child(root_container.children->items[p], child); | ||
128 | } | ||
129 | container_sort_workspaces(root_container.children->items[p]); | ||
130 | arrange_windows(root_container.children->items[p], | ||
131 | -1, -1); | ||
132 | } | ||
133 | } | ||
118 | 134 | ||
119 | struct sway_container *container_output_create( | 135 | wl_list_remove(&output->sway_output->destroy.link); |
120 | struct sway_output *sway_output) { | 136 | wl_list_remove(&output->sway_output->mode.link); |
121 | struct wlr_box size; | 137 | wl_list_remove(&output->sway_output->transform.link); |
122 | wlr_output_effective_resolution(sway_output->wlr_output, &size.width, | 138 | wl_list_remove(&output->sway_output->scale.link); |
123 | &size.height); | ||
124 | 139 | ||
125 | const char *name = sway_output->wlr_output->name; | 140 | wl_list_remove(&output->sway_output->damage_destroy.link); |
126 | char identifier[128]; | 141 | wl_list_remove(&output->sway_output->damage_frame.link); |
127 | output_get_identifier(identifier, sizeof(identifier), sway_output); | ||
128 | 142 | ||
129 | struct output_config *oc = NULL, *all = NULL; | 143 | wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); |
130 | for (int i = 0; i < config->output_configs->length; ++i) { | 144 | _container_destroy(output); |
131 | struct output_config *cur = config->output_configs->items[i]; | 145 | return &root_container; |
146 | } | ||
132 | 147 | ||
133 | if (strcasecmp(name, cur->name) == 0 || | 148 | static struct sway_container *container_workspace_destroy( |
134 | strcasecmp(identifier, cur->name) == 0) { | 149 | struct sway_container *workspace) { |
135 | wlr_log(L_DEBUG, "Matched output config for %s", name); | 150 | if (!sway_assert(workspace, "cannot destroy null workspace")) { |
136 | oc = cur; | 151 | return NULL; |
137 | } | 152 | } |
138 | if (strcasecmp("*", cur->name) == 0) { | 153 | |
139 | wlr_log(L_DEBUG, "Matched wildcard output config for %s", name); | 154 | // Do not destroy this if it's the last workspace on this output |
140 | all = cur; | 155 | struct sway_container *output = container_parent(workspace, C_OUTPUT); |
156 | if (output && output->children->length == 1) { | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | struct sway_container *parent = workspace->parent; | ||
161 | if (workspace->children->length == 0) { | ||
162 | // destroy the WS if there are no children (TODO check for floating) | ||
163 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); | ||
164 | ipc_event_workspace(workspace, NULL, "empty"); | ||
165 | } else { | ||
166 | // Move children to a different workspace on this output | ||
167 | struct sway_container *new_workspace = NULL; | ||
168 | // TODO move floating | ||
169 | for (int i = 0; i < output->children->length; i++) { | ||
170 | if (output->children->items[i] != workspace) { | ||
171 | new_workspace = output->children->items[i]; | ||
172 | break; | ||
173 | } | ||
141 | } | 174 | } |
142 | 175 | ||
143 | if (oc && all) { | 176 | wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", |
144 | break; | 177 | workspace->name, new_workspace->name); |
178 | for (int i = 0; i < workspace->children->length; i++) { | ||
179 | container_move_to(workspace->children->items[i], new_workspace); | ||
145 | } | 180 | } |
146 | } | 181 | } |
147 | if (!oc) { | ||
148 | oc = all; | ||
149 | } | ||
150 | 182 | ||
151 | if (oc && !oc->enabled) { | 183 | _container_destroy(workspace); |
152 | return NULL; | 184 | |
185 | output_damage_whole(output->sway_output); | ||
186 | |||
187 | return parent; | ||
188 | } | ||
189 | |||
190 | static void container_root_finish(struct sway_container *con) { | ||
191 | wlr_log(L_ERROR, "TODO: destroy the root container"); | ||
192 | } | ||
193 | |||
194 | static bool container_reap_empty(struct sway_container *con) { | ||
195 | switch (con->type) { | ||
196 | case C_ROOT: | ||
197 | case C_OUTPUT: | ||
198 | // dont reap these | ||
199 | break; | ||
200 | case C_WORKSPACE: | ||
201 | if (!workspace_is_visible(con) && con->children->length == 0) { | ||
202 | container_workspace_destroy(con); | ||
203 | return true; | ||
204 | } | ||
205 | break; | ||
206 | case C_CONTAINER: | ||
207 | if (con->children->length == 0) { | ||
208 | _container_destroy(con); | ||
209 | return true; | ||
210 | } else if (con->children->length == 1) { | ||
211 | struct sway_container *child = con->children->items[0]; | ||
212 | if (child->type == C_CONTAINER) { | ||
213 | container_remove_child(child); | ||
214 | container_replace_child(con, child); | ||
215 | _container_destroy(con); | ||
216 | return true; | ||
217 | } | ||
218 | } | ||
219 | case C_VIEW: | ||
220 | break; | ||
221 | case C_TYPES: | ||
222 | sway_assert(false, "container_reap_empty called on an invalid " | ||
223 | "container"); | ||
224 | break; | ||
153 | } | 225 | } |
154 | 226 | ||
155 | struct sway_container *output = container_create(C_OUTPUT); | 227 | return false; |
156 | output->sway_output = sway_output; | 228 | } |
157 | output->name = strdup(name); | 229 | |
158 | if (output->name == NULL) { | 230 | struct sway_container *container_destroy(struct sway_container *con) { |
159 | container_destroy(output); | 231 | if (con == NULL) { |
160 | return NULL; | 232 | return NULL; |
161 | } | 233 | } |
162 | 234 | ||
163 | // Insert the child before applying config so that the container coordinates | 235 | struct sway_container *parent = con->parent; |
164 | // get updated | 236 | |
165 | container_add_child(&root_container, output); | 237 | switch (con->type) { |
166 | apply_output_config(oc, output); | 238 | case C_ROOT: |
239 | container_root_finish(con); | ||
240 | break; | ||
241 | case C_OUTPUT: | ||
242 | // dont try to reap the root after this | ||
243 | container_output_destroy(con); | ||
244 | break; | ||
245 | case C_WORKSPACE: | ||
246 | // dont try to reap the output after this | ||
247 | container_workspace_destroy(con); | ||
248 | break; | ||
249 | case C_CONTAINER: | ||
250 | if (con->children->length) { | ||
251 | for (int i = 0; i < con->children->length; ++i) { | ||
252 | struct sway_container *child = con->children->items[0]; | ||
253 | container_remove_child(child); | ||
254 | container_add_child(parent, child); | ||
255 | } | ||
256 | } | ||
257 | _container_destroy(con); | ||
258 | break; | ||
259 | case C_VIEW: | ||
260 | _container_destroy(con); | ||
261 | break; | ||
262 | case C_TYPES: | ||
263 | wlr_log(L_ERROR, "container_destroy called on an invalid " | ||
264 | "container"); | ||
265 | break; | ||
266 | } | ||
167 | 267 | ||
168 | load_swaybars(); | 268 | struct sway_container *tmp = parent; |
269 | while (parent) { | ||
270 | tmp = parent->parent; | ||
169 | 271 | ||
170 | // Create workspace | 272 | if (!container_reap_empty(parent)) { |
171 | char *ws_name = workspace_next_name(output->name); | 273 | break; |
172 | wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); | ||
173 | struct sway_container *ws = container_workspace_create(output, ws_name); | ||
174 | // Set each seat's focus if not already set | ||
175 | struct sway_seat *seat = NULL; | ||
176 | wl_list_for_each(seat, &input_manager->seats, link) { | ||
177 | if (!seat->has_focus) { | ||
178 | seat_set_focus(seat, ws); | ||
179 | } | 274 | } |
275 | |||
276 | parent = tmp; | ||
180 | } | 277 | } |
181 | 278 | ||
182 | free(ws_name); | 279 | return tmp; |
183 | notify_new_container(output); | 280 | } |
184 | return output; | 281 | |
282 | static void container_close_func(struct sway_container *container, void *data) { | ||
283 | if (container->type == C_VIEW) { | ||
284 | view_close(container->sway_view); | ||
285 | } | ||
185 | } | 286 | } |
186 | 287 | ||
187 | struct sway_container *container_workspace_create( | 288 | struct sway_container *container_close(struct sway_container *con) { |
188 | struct sway_container *output, const char *name) { | 289 | if (!sway_assert(con != NULL, |
189 | if (!sway_assert(output, | 290 | "container_close called with a NULL container")) { |
190 | "container_workspace_create called with null output")) { | ||
191 | return NULL; | 291 | return NULL; |
192 | } | 292 | } |
193 | wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name); | 293 | |
194 | struct sway_container *workspace = container_create(C_WORKSPACE); | 294 | struct sway_container *parent = con->parent; |
195 | 295 | ||
196 | workspace->x = output->x; | 296 | if (con->type == C_VIEW) { |
197 | workspace->y = output->y; | 297 | view_close(con->sway_view); |
198 | workspace->width = output->width; | 298 | } else { |
199 | workspace->height = output->height; | 299 | container_for_each_descendant_dfs(con, container_close_func, NULL); |
200 | workspace->name = !name ? NULL : strdup(name); | 300 | } |
201 | workspace->prev_layout = L_NONE; | 301 | |
202 | workspace->layout = container_get_default_layout(output); | 302 | return parent; |
203 | workspace->workspace_layout = container_get_default_layout(output); | ||
204 | |||
205 | container_add_child(output, workspace); | ||
206 | container_sort_workspaces(output); | ||
207 | notify_new_container(workspace); | ||
208 | return workspace; | ||
209 | } | 303 | } |
210 | 304 | ||
211 | struct sway_container *container_view_create(struct sway_container *sibling, | 305 | struct sway_container *container_view_create(struct sway_container *sibling, |
@@ -231,23 +325,10 @@ struct sway_container *container_view_create(struct sway_container *sibling, | |||
231 | // Regular case, create as sibling of current container | 325 | // Regular case, create as sibling of current container |
232 | container_add_sibling(sibling, swayc); | 326 | container_add_sibling(sibling, swayc); |
233 | } | 327 | } |
234 | notify_new_container(swayc); | 328 | container_create_notify(swayc); |
235 | return swayc; | 329 | return swayc; |
236 | } | 330 | } |
237 | 331 | ||
238 | struct sway_container *container_set_layout(struct sway_container *container, | ||
239 | enum sway_container_layout layout) { | ||
240 | if (container->type == C_WORKSPACE) { | ||
241 | container->workspace_layout = layout; | ||
242 | if (layout == L_HORIZ || layout == L_VERT) { | ||
243 | container->layout = layout; | ||
244 | } | ||
245 | } else { | ||
246 | container->layout = layout; | ||
247 | } | ||
248 | return container; | ||
249 | } | ||
250 | |||
251 | void container_descendants(struct sway_container *root, | 332 | void container_descendants(struct sway_container *root, |
252 | enum sway_container_type type, | 333 | enum sway_container_type type, |
253 | void (*func)(struct sway_container *item, void *data), void *data) { | 334 | void (*func)(struct sway_container *item, void *data), void *data) { |