summaryrefslogtreecommitdiffstats
path: root/sway/tree/container.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r--sway/tree/container.c273
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
53static void notify_new_container(struct sway_container *container) { 53void 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
79static struct sway_container *_container_destroy(struct sway_container *cont) { 79static 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
112struct sway_container *container_destroy(struct sway_container *cont) { 111static 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
119struct 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 || 148static 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
190static void container_root_finish(struct sway_container *con) {
191 wlr_log(L_ERROR, "TODO: destroy the root container");
192}
193
194static 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) { 230struct 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
282static 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
187struct sway_container *container_workspace_create( 288struct 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
211struct sway_container *container_view_create(struct sway_container *sibling, 305struct 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
238struct 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
251void container_descendants(struct sway_container *root, 332void 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) {