summaryrefslogtreecommitdiffstats
path: root/sway/tree/workspace.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/workspace.c')
-rw-r--r--sway/tree/workspace.c493
1 files changed, 238 insertions, 255 deletions
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 1957d94f..38ee478e 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -12,128 +12,105 @@
12#include "sway/output.h" 12#include "sway/output.h"
13#include "sway/tree/arrange.h" 13#include "sway/tree/arrange.h"
14#include "sway/tree/container.h" 14#include "sway/tree/container.h"
15#include "sway/tree/node.h"
15#include "sway/tree/view.h" 16#include "sway/tree/view.h"
16#include "sway/tree/workspace.h" 17#include "sway/tree/workspace.h"
17#include "list.h" 18#include "list.h"
18#include "log.h" 19#include "log.h"
19#include "util.h" 20#include "util.h"
20 21
21struct sway_container *workspace_get_initial_output(const char *name) { 22struct sway_output *workspace_get_initial_output(const char *name) {
22 struct sway_container *parent;
23 // Search for workspace<->output pair 23 // Search for workspace<->output pair
24 int e = config->workspace_outputs->length;
25 for (int i = 0; i < config->workspace_outputs->length; ++i) { 24 for (int i = 0; i < config->workspace_outputs->length; ++i) {
26 struct workspace_output *wso = config->workspace_outputs->items[i]; 25 struct workspace_output *wso = config->workspace_outputs->items[i];
27 if (strcasecmp(wso->workspace, name) == 0) { 26 if (strcasecmp(wso->workspace, name) == 0) {
28 // Find output to use if it exists 27 // Find output to use if it exists
29 e = root_container.children->length; 28 struct sway_output *output = output_by_name(wso->output);
30 for (i = 0; i < e; ++i) { 29 if (output) {
31 parent = root_container.children->items[i]; 30 return output;
32 if (strcmp(parent->name, wso->output) == 0) {
33 return parent;
34 }
35 } 31 }
36 break; 32 break;
37 } 33 }
38 } 34 }
39 // Otherwise put it on the focused output 35 // Otherwise put it on the focused output
40 struct sway_seat *seat = input_manager_current_seat(input_manager); 36 struct sway_seat *seat = input_manager_current_seat(input_manager);
41 struct sway_container *focus = 37 struct sway_workspace *focus = seat_get_focused_workspace(seat);
42 seat_get_focus_inactive(seat, &root_container); 38 return focus->output;
43 parent = focus;
44 parent = container_parent(parent, C_OUTPUT);
45 return parent;
46} 39}
47 40
48struct sway_container *workspace_create(struct sway_container *output, 41struct sway_workspace *workspace_create(struct sway_output *output,
49 const char *name) { 42 const char *name) {
50 if (output == NULL) { 43 if (output == NULL) {
51 output = workspace_get_initial_output(name); 44 output = workspace_get_initial_output(name);
52 } 45 }
53 46
54 wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); 47 wlr_log(WLR_DEBUG, "Adding workspace %s for output %s", name,
55 struct sway_container *workspace = container_create(C_WORKSPACE); 48 output->wlr_output->name);
56
57 workspace->x = output->x;
58 workspace->y = output->y;
59 workspace->width = output->width;
60 workspace->height = output->height;
61 workspace->name = !name ? NULL : strdup(name);
62 workspace->prev_split_layout = L_NONE;
63 workspace->layout = container_get_default_layout(output);
64 49
65 struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); 50 struct sway_workspace *ws = calloc(1, sizeof(struct sway_workspace));
66 if (!swayws) { 51 if (!ws) {
52 wlr_log(WLR_ERROR, "Unable to allocate sway_workspace");
67 return NULL; 53 return NULL;
68 } 54 }
69 swayws->swayc = workspace; 55 node_init(&ws->node, N_WORKSPACE, ws);
70 swayws->floating = create_list(); 56 ws->x = output->wlr_output->lx;
71 swayws->output_priority = create_list(); 57 ws->y = output->wlr_output->ly;
72 workspace->sway_workspace = swayws; 58 ws->width = output->wlr_output->width;
73 workspace_output_add_priority(workspace, output); 59 ws->height = output->wlr_output->height;
74 60 ws->name = name ? strdup(name) : NULL;
75 container_add_child(output, workspace); 61 ws->prev_split_layout = L_NONE;
62 ws->layout = output_get_default_layout(output);
63 ws->floating = create_list();
64 ws->tiling = create_list();
65 ws->output_priority = create_list();
66 workspace_output_add_priority(ws, output);
67
68 output_add_workspace(output, ws);
76 output_sort_workspaces(output); 69 output_sort_workspaces(output);
77 container_create_notify(workspace);
78 70
79 return workspace; 71 ipc_event_workspace(NULL, ws, "init");
72 wl_signal_emit(&root->events.new_node, &ws->node);
73
74 return ws;
80} 75}
81 76
82void workspace_destroy(struct sway_container *workspace) { 77void workspace_destroy(struct sway_workspace *workspace) {
83 if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { 78 if (!sway_assert(workspace->node.destroying,
84 return;
85 }
86 if (!sway_assert(workspace->destroying,
87 "Tried to free workspace which wasn't marked as destroying")) { 79 "Tried to free workspace which wasn't marked as destroying")) {
88 return; 80 return;
89 } 81 }
90 if (!sway_assert(workspace->ntxnrefs == 0, "Tried to free workspace " 82 if (!sway_assert(workspace->node.ntxnrefs == 0, "Tried to free workspace "
91 "which is still referenced by transactions")) { 83 "which is still referenced by transactions")) {
92 return; 84 return;
93 } 85 }
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 86
101 // swayc
102 free(workspace->name); 87 free(workspace->name);
103 free(workspace->formatted_title); 88 free(workspace->representation);
104 wlr_texture_destroy(workspace->title_focused); 89 list_foreach(workspace->output_priority, free);
105 wlr_texture_destroy(workspace->title_focused_inactive); 90 list_free(workspace->output_priority);
106 wlr_texture_destroy(workspace->title_unfocused); 91 list_free(workspace->floating);
107 wlr_texture_destroy(workspace->title_urgent); 92 list_free(workspace->tiling);
108 list_free(workspace->children); 93 list_free(workspace->current.floating);
109 list_free(workspace->current.children); 94 list_free(workspace->current.tiling);
110 list_free(workspace->outputs);
111 free(workspace); 95 free(workspace);
112} 96}
113 97
114void workspace_begin_destroy(struct sway_container *workspace) { 98void workspace_begin_destroy(struct sway_workspace *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); 99 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 100 ipc_event_workspace(NULL, workspace, "empty"); // intentional
101 wl_signal_emit(&workspace->node.events.destroy, &workspace->node);
121 102
122 workspace->destroying = true; 103 if (workspace->output) {
123 container_set_dirty(workspace); 104 workspace_detach(workspace);
124
125 if (workspace->parent) {
126 container_remove_child(workspace);
127 } 105 }
106
107 workspace->node.destroying = true;
108 node_set_dirty(&workspace->node);
128} 109}
129 110
130void workspace_consider_destroy(struct sway_container *ws) { 111void workspace_consider_destroy(struct sway_workspace *ws) {
131 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { 112 if (ws->tiling->length == 0 && ws->floating->length == 0
132 return; 113 && output_get_active_workspace(ws->output) != ws) {
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); 114 workspace_begin_destroy(ws);
138 } 115 }
139} 116}
@@ -272,59 +249,49 @@ char *workspace_next_name(const char *output_name) {
272 } 249 }
273 // As a fall back, get the current number of active workspaces 250 // As a fall back, get the current number of active workspaces
274 // and return that + 1 for the next workspace's name 251 // and return that + 1 for the next workspace's name
275 int ws_num = root_container.children->length; 252 int ws_num = root->outputs->length;
276 int l = snprintf(NULL, 0, "%d", ws_num); 253 int l = snprintf(NULL, 0, "%d", ws_num);
277 char *name = malloc(l + 1); 254 char *name = malloc(l + 1);
278 if (!sway_assert(name, "Cloud not allocate workspace name")) { 255 if (!sway_assert(name, "Could not allocate workspace name")) {
279 return NULL; 256 return NULL;
280 } 257 }
281 sprintf(name, "%d", ws_num++); 258 sprintf(name, "%d", ws_num++);
282 return name; 259 return name;
283} 260}
284 261
285static bool _workspace_by_number(struct sway_container *view, void *data) { 262static bool _workspace_by_number(struct sway_workspace *ws, void *data) {
286 if (view->type != C_WORKSPACE) {
287 return false;
288 }
289 char *name = data; 263 char *name = data;
290 char *view_name = view->name; 264 char *ws_name = ws->name;
291 while (isdigit(*name)) { 265 while (isdigit(*name)) {
292 if (*name++ != *view_name++) { 266 if (*name++ != *ws_name++) {
293 return false; 267 return false;
294 } 268 }
295 } 269 }
296 return !isdigit(*view_name); 270 return !isdigit(*ws_name);
297} 271}
298 272
299struct sway_container *workspace_by_number(const char* name) { 273struct sway_workspace *workspace_by_number(const char* name) {
300 return root_find_workspace(_workspace_by_number, (void *) name); 274 return root_find_workspace(_workspace_by_number, (void *) name);
301} 275}
302 276
303static bool _workspace_by_name(struct sway_container *view, void *data) { 277static bool _workspace_by_name(struct sway_workspace *ws, void *data) {
304 return (view->type == C_WORKSPACE) && 278 return strcasecmp(ws->name, data) == 0;
305 (strcasecmp(view->name, (char *) data) == 0);
306} 279}
307 280
308struct sway_container *workspace_by_name(const char *name) { 281struct sway_workspace *workspace_by_name(const char *name) {
309 struct sway_seat *seat = input_manager_current_seat(input_manager); 282 struct sway_seat *seat = input_manager_current_seat(input_manager);
310 struct sway_container *current_workspace = NULL, *current_output = NULL; 283 struct sway_workspace *current = seat_get_focused_workspace(seat);
311 struct sway_container *focus = seat_get_focus(seat);
312 if (focus) {
313 current_workspace = focus->type == C_WORKSPACE ?
314 focus : container_parent(focus, C_WORKSPACE);
315 current_output = container_parent(focus, C_OUTPUT);
316 }
317 284
318 if (strcmp(name, "prev") == 0) { 285 if (strcmp(name, "prev") == 0) {
319 return workspace_prev(current_workspace); 286 return workspace_prev(current);
320 } else if (strcmp(name, "prev_on_output") == 0) { 287 } else if (strcmp(name, "prev_on_output") == 0) {
321 return workspace_output_prev(current_output); 288 return workspace_output_prev(current);
322 } else if (strcmp(name, "next") == 0) { 289 } else if (strcmp(name, "next") == 0) {
323 return workspace_next(current_workspace); 290 return workspace_next(current);
324 } else if (strcmp(name, "next_on_output") == 0) { 291 } else if (strcmp(name, "next_on_output") == 0) {
325 return workspace_output_next(current_output); 292 return workspace_output_next(current);
326 } else if (strcmp(name, "current") == 0) { 293 } else if (strcmp(name, "current") == 0) {
327 return current_workspace; 294 return current;
328 } else if (strcasecmp(name, "back_and_forth") == 0) { 295 } else if (strcasecmp(name, "back_and_forth") == 0) {
329 return prev_workspace_name ? 296 return prev_workspace_name ?
330 root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) 297 root_find_workspace(_workspace_by_name, (void*)prev_workspace_name)
@@ -339,97 +306,68 @@ struct sway_container *workspace_by_name(const char *name) {
339 * the end and beginning. If next is false, the previous workspace is returned, 306 * the end and beginning. If next is false, the previous workspace is returned,
340 * otherwise the next one is returned. 307 * otherwise the next one is returned.
341 */ 308 */
342static struct sway_container *workspace_output_prev_next_impl( 309static struct sway_workspace *workspace_output_prev_next_impl(
343 struct sway_container *output, int dir) { 310 struct sway_output *output, int dir) {
344 if (!output) {
345 return NULL;
346 }
347 if (!sway_assert(output->type == C_OUTPUT,
348 "Argument must be an output, is %d", output->type)) {
349 return NULL;
350 }
351
352 struct sway_seat *seat = input_manager_current_seat(input_manager); 311 struct sway_seat *seat = input_manager_current_seat(input_manager);
353 struct sway_container *focus = seat_get_focus_inactive(seat, output); 312 struct sway_workspace *workspace = seat_get_focused_workspace(seat);
354 struct sway_container *workspace = (focus->type == C_WORKSPACE ?
355 focus :
356 container_parent(focus, C_WORKSPACE));
357 313
358 int index = list_find(output->children, workspace); 314 int index = list_find(output->workspaces, workspace);
359 size_t new_index = wrap(index + dir, output->children->length); 315 size_t new_index = wrap(index + dir, output->workspaces->length);
360 return output->children->items[new_index]; 316 return output->workspaces->items[new_index];
361} 317}
362 318
363/** 319/**
364 * Get the previous or next workspace. If the first/last workspace on an output 320 * Get the previous or next workspace. If the first/last workspace on an output
365 * is active, proceed to the previous/next output's previous/next workspace. 321 * is active, proceed to the previous/next output's previous/next workspace.
366 */ 322 */
367static struct sway_container *workspace_prev_next_impl( 323static struct sway_workspace *workspace_prev_next_impl(
368 struct sway_container *workspace, int dir) { 324 struct sway_workspace *workspace, int dir) {
369 if (!workspace) { 325 struct sway_output *output = workspace->output;
370 return NULL; 326 int index = list_find(output->workspaces, workspace);
371 }
372 if (!sway_assert(workspace->type == C_WORKSPACE,
373 "Argument must be a workspace, is %d", workspace->type)) {
374 return NULL;
375 }
376
377 struct sway_container *output = workspace->parent;
378 int index = list_find(output->children, workspace);
379 int new_index = index + dir; 327 int new_index = index + dir;
380 328
381 if (new_index >= 0 && new_index < output->children->length) { 329 if (new_index >= 0 && new_index < output->workspaces->length) {
382 return output->children->items[index + dir]; 330 return output->workspaces->items[new_index];
383 } 331 }
384 332
385 // Look on a different output 333 // Look on a different output
386 int output_index = list_find(root_container.children, output); 334 int output_index = list_find(root->outputs, output);
387 new_index = wrap(output_index + dir, root_container.children->length); 335 new_index = wrap(output_index + dir, root->outputs->length);
388 output = root_container.children->items[new_index]; 336 output = root->outputs->items[new_index];
389 337
390 if (dir == 1) { 338 if (dir == 1) {
391 return output->children->items[0]; 339 return output->workspaces->items[0];
392 } else { 340 } else {
393 return output->children->items[output->children->length - 1]; 341 return output->workspaces->items[output->workspaces->length - 1];
394 } 342 }
395} 343}
396 344
397struct sway_container *workspace_output_next(struct sway_container *current) { 345struct sway_workspace *workspace_output_next(struct sway_workspace *current) {
398 return workspace_output_prev_next_impl(current, 1); 346 return workspace_output_prev_next_impl(current->output, 1);
399} 347}
400 348
401struct sway_container *workspace_next(struct sway_container *current) { 349struct sway_workspace *workspace_next(struct sway_workspace *current) {
402 return workspace_prev_next_impl(current, 1); 350 return workspace_prev_next_impl(current, 1);
403} 351}
404 352
405struct sway_container *workspace_output_prev(struct sway_container *current) { 353struct sway_workspace *workspace_output_prev(struct sway_workspace *current) {
406 return workspace_output_prev_next_impl(current, -1); 354 return workspace_output_prev_next_impl(current->output, -1);
407} 355}
408 356
409struct sway_container *workspace_prev(struct sway_container *current) { 357struct sway_workspace *workspace_prev(struct sway_workspace *current) {
410 return workspace_prev_next_impl(current, -1); 358 return workspace_prev_next_impl(current, -1);
411} 359}
412 360
413bool workspace_switch(struct sway_container *workspace, 361bool workspace_switch(struct sway_workspace *workspace,
414 bool no_auto_back_and_forth) { 362 bool no_auto_back_and_forth) {
415 if (!workspace) {
416 return false;
417 }
418 struct sway_seat *seat = input_manager_current_seat(input_manager); 363 struct sway_seat *seat = input_manager_current_seat(input_manager);
419 struct sway_container *focus = 364 struct sway_node *focus = seat_get_focus_inactive(seat, &root->node);
420 seat_get_focus_inactive(seat, &root_container); 365 struct sway_workspace *active_ws = seat_get_focused_workspace(seat);
421 if (!seat || !focus) {
422 return false;
423 }
424 struct sway_container *active_ws = focus;
425 if (active_ws->type != C_WORKSPACE) {
426 active_ws = container_parent(focus, C_WORKSPACE);
427 }
428 366
429 if (!no_auto_back_and_forth && config->auto_back_and_forth 367 if (!no_auto_back_and_forth && config->auto_back_and_forth
430 && active_ws == workspace 368 && active_ws == workspace
431 && prev_workspace_name) { 369 && prev_workspace_name) {
432 struct sway_container *new_ws = workspace_by_name(prev_workspace_name); 370 struct sway_workspace *new_ws = workspace_by_name(prev_workspace_name);
433 workspace = new_ws ? 371 workspace = new_ws ?
434 new_ws : 372 new_ws :
435 workspace_create(NULL, prev_workspace_name); 373 workspace_create(NULL, prev_workspace_name);
@@ -447,21 +385,21 @@ bool workspace_switch(struct sway_container *workspace,
447 } 385 }
448 386
449 // Move sticky containers to new workspace 387 // Move sticky containers to new workspace
450 struct sway_container *next_output = workspace->parent; 388 struct sway_output *next_output = workspace->output;
451 struct sway_container *next_output_prev_ws = 389 struct sway_workspace *next_output_prev_ws =
452 seat_get_active_child(seat, next_output); 390 output_get_active_workspace(next_output);
453 list_t *floating = next_output_prev_ws->sway_workspace->floating;
454 bool has_sticky = false; 391 bool has_sticky = false;
455 if (workspace != next_output_prev_ws) { 392 if (workspace != next_output_prev_ws) {
456 for (int i = 0; i < floating->length; ++i) { 393 for (int i = 0; i < next_output_prev_ws->floating->length; ++i) {
457 struct sway_container *floater = floating->items[i]; 394 struct sway_container *floater =
395 next_output_prev_ws->floating->items[i];
458 if (floater->is_sticky) { 396 if (floater->is_sticky) {
459 has_sticky = true; 397 has_sticky = true;
460 container_remove_child(floater); 398 container_detach(floater);
461 workspace_add_floating(workspace, floater); 399 workspace_add_floating(workspace, floater);
462 if (floater == focus) { 400 if (&floater->node == focus) {
463 seat_set_focus(seat, NULL); 401 seat_set_focus(seat, NULL);
464 seat_set_focus(seat, floater); 402 seat_set_focus(seat, &floater->node);
465 } 403 }
466 --i; 404 --i;
467 } 405 }
@@ -470,9 +408,9 @@ bool workspace_switch(struct sway_container *workspace,
470 408
471 wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", 409 wlr_log(WLR_DEBUG, "Switching to workspace %p:%s",
472 workspace, workspace->name); 410 workspace, workspace->name);
473 struct sway_container *next = seat_get_focus_inactive(seat, workspace); 411 struct sway_node *next = seat_get_focus_inactive(seat, &workspace->node);
474 if (next == NULL) { 412 if (next == NULL) {
475 next = workspace; 413 next = &workspace->node;
476 } 414 }
477 if (has_sticky) { 415 if (has_sticky) {
478 // If there's a sticky container, we might be setting focus to the same 416 // If there's a sticky container, we might be setting focus to the same
@@ -483,35 +421,24 @@ bool workspace_switch(struct sway_container *workspace,
483 workspace_consider_destroy(active_ws); 421 workspace_consider_destroy(active_ws);
484 } 422 }
485 seat_set_focus(seat, next); 423 seat_set_focus(seat, next);
486 struct sway_container *output = container_parent(workspace, C_OUTPUT); 424 arrange_workspace(workspace);
487 arrange_windows(output);
488 return true; 425 return true;
489} 426}
490 427
491bool workspace_is_visible(struct sway_container *ws) { 428bool workspace_is_visible(struct sway_workspace *ws) {
492 if (ws->destroying) { 429 if (ws->node.destroying) {
493 return false; 430 return false;
494 } 431 }
495 struct sway_container *output = container_parent(ws, C_OUTPUT); 432 return output_get_active_workspace(ws->output) == ws;
496 struct sway_seat *seat = input_manager_current_seat(input_manager);
497 struct sway_container *focus = seat_get_focus_inactive(seat, output);
498 if (focus->type != C_WORKSPACE) {
499 focus = container_parent(focus, C_WORKSPACE);
500 }
501 return focus == ws;
502} 433}
503 434
504bool workspace_is_empty(struct sway_container *ws) { 435bool workspace_is_empty(struct sway_workspace *ws) {
505 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { 436 if (ws->tiling->length) {
506 return false;
507 }
508 if (ws->children->length) {
509 return false; 437 return false;
510 } 438 }
511 // Sticky views are not considered to be part of this workspace 439 // Sticky views are not considered to be part of this workspace
512 list_t *floating = ws->sway_workspace->floating; 440 for (int i = 0; i < ws->floating->length; ++i) {
513 for (int i = 0; i < floating->length; ++i) { 441 struct sway_container *floater = ws->floating->items[i];
514 struct sway_container *floater = floating->items[i];
515 if (!floater->is_sticky) { 442 if (!floater->is_sticky) {
516 return false; 443 return false;
517 } 444 }
@@ -523,20 +450,19 @@ static int find_output(const void *id1, const void *id2) {
523 return strcmp(id1, id2) ? 0 : 1; 450 return strcmp(id1, id2) ? 0 : 1;
524} 451}
525 452
526void workspace_output_raise_priority(struct sway_container *workspace, 453void workspace_output_raise_priority(struct sway_workspace *ws,
527 struct sway_container *old_output, struct sway_container *output) { 454 struct sway_output *old_output, struct sway_output *output) {
528 struct sway_workspace *ws = workspace->sway_workspace;
529
530 int old_index = list_seq_find(ws->output_priority, find_output, 455 int old_index = list_seq_find(ws->output_priority, find_output,
531 old_output->name); 456 old_output->wlr_output->name);
532 if (old_index < 0) { 457 if (old_index < 0) {
533 return; 458 return;
534 } 459 }
535 460
536 int new_index = list_seq_find(ws->output_priority, find_output, 461 int new_index = list_seq_find(ws->output_priority, find_output,
537 output->name); 462 output->wlr_output->name);
538 if (new_index < 0) { 463 if (new_index < 0) {
539 list_insert(ws->output_priority, old_index, strdup(output->name)); 464 list_insert(ws->output_priority, old_index,
465 strdup(output->wlr_output->name));
540 } else if (new_index > old_index) { 466 } else if (new_index > old_index) {
541 char *name = ws->output_priority->items[new_index]; 467 char *name = ws->output_priority->items[new_index];
542 list_del(ws->output_priority, new_index); 468 list_del(ws->output_priority, new_index);
@@ -544,29 +470,24 @@ void workspace_output_raise_priority(struct sway_container *workspace,
544 } 470 }
545} 471}
546 472
547void workspace_output_add_priority(struct sway_container *workspace, 473void workspace_output_add_priority(struct sway_workspace *workspace,
548 struct sway_container *output) { 474 struct sway_output *output) {
549 int index = list_seq_find(workspace->sway_workspace->output_priority, 475 int index = list_seq_find(workspace->output_priority,
550 find_output, output->name); 476 find_output, output->wlr_output->name);
551 if (index < 0) { 477 if (index < 0) {
552 list_add(workspace->sway_workspace->output_priority, 478 list_add(workspace->output_priority, strdup(output->wlr_output->name));
553 strdup(output->name));
554 } 479 }
555} 480}
556 481
557static bool _output_by_name(struct sway_container *output, void *data) { 482struct sway_output *workspace_output_get_highest_available(
558 return output->type == C_OUTPUT && strcasecmp(output->name, data) == 0; 483 struct sway_workspace *ws, struct sway_output *exclude) {
559} 484 for (int i = 0; i < ws->output_priority->length; i++) {
560 485 char *name = ws->output_priority->items[i];
561struct sway_container *workspace_output_get_highest_available( 486 if (exclude && strcasecmp(name, exclude->wlr_output->name) == 0) {
562 struct sway_container *ws, struct sway_container *exclude) {
563 for (int i = 0; i < ws->sway_workspace->output_priority->length; i++) {
564 char *name = ws->sway_workspace->output_priority->items[i];
565 if (exclude && strcasecmp(name, exclude->name) == 0) {
566 continue; 487 continue;
567 } 488 }
568 489
569 struct sway_container *output = root_find_output(_output_by_name, name); 490 struct sway_output *output = output_by_name(name);
570 if (output) { 491 if (output) {
571 return output; 492 return output;
572 } 493 }
@@ -576,49 +497,42 @@ struct sway_container *workspace_output_get_highest_available(
576} 497}
577 498
578static bool find_urgent_iterator(struct sway_container *con, void *data) { 499static bool find_urgent_iterator(struct sway_container *con, void *data) {
579 return con->type == C_VIEW && view_is_urgent(con->sway_view); 500 return con->view && view_is_urgent(con->view);
580} 501}
581 502
582void workspace_detect_urgent(struct sway_container *workspace) { 503void workspace_detect_urgent(struct sway_workspace *workspace) {
583 bool new_urgent = (bool)workspace_find_container(workspace, 504 bool new_urgent = (bool)workspace_find_container(workspace,
584 find_urgent_iterator, NULL); 505 find_urgent_iterator, NULL);
585 506
586 if (workspace->sway_workspace->urgent != new_urgent) { 507 if (workspace->urgent != new_urgent) {
587 workspace->sway_workspace->urgent = new_urgent; 508 workspace->urgent = new_urgent;
588 ipc_event_workspace(NULL, workspace, "urgent"); 509 ipc_event_workspace(NULL, workspace, "urgent");
589 container_damage_whole(workspace); 510 output_damage_whole(workspace->output);
590 } 511 }
591} 512}
592 513
593void workspace_for_each_container(struct sway_container *ws, 514void workspace_for_each_container(struct sway_workspace *ws,
594 void (*f)(struct sway_container *con, void *data), void *data) { 515 void (*f)(struct sway_container *con, void *data), void *data) {
595 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
596 return;
597 }
598 // Tiling 516 // Tiling
599 for (int i = 0; i < ws->children->length; ++i) { 517 for (int i = 0; i < ws->tiling->length; ++i) {
600 struct sway_container *container = ws->children->items[i]; 518 struct sway_container *container = ws->tiling->items[i];
601 f(container, data); 519 f(container, data);
602 container_for_each_child(container, f, data); 520 container_for_each_child(container, f, data);
603 } 521 }
604 // Floating 522 // Floating
605 for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { 523 for (int i = 0; i < ws->floating->length; ++i) {
606 struct sway_container *container = 524 struct sway_container *container = ws->floating->items[i];
607 ws->sway_workspace->floating->items[i];
608 f(container, data); 525 f(container, data);
609 container_for_each_child(container, f, data); 526 container_for_each_child(container, f, data);
610 } 527 }
611} 528}
612 529
613struct sway_container *workspace_find_container(struct sway_container *ws, 530struct sway_container *workspace_find_container(struct sway_workspace *ws,
614 bool (*test)(struct sway_container *con, void *data), void *data) { 531 bool (*test)(struct sway_container *con, void *data), void *data) {
615 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
616 return NULL;
617 }
618 struct sway_container *result = NULL; 532 struct sway_container *result = NULL;
619 // Tiling 533 // Tiling
620 for (int i = 0; i < ws->children->length; ++i) { 534 for (int i = 0; i < ws->tiling->length; ++i) {
621 struct sway_container *child = ws->children->items[i]; 535 struct sway_container *child = ws->tiling->items[i];
622 if (test(child, data)) { 536 if (test(child, data)) {
623 return child; 537 return child;
624 } 538 }
@@ -627,8 +541,8 @@ struct sway_container *workspace_find_container(struct sway_container *ws,
627 } 541 }
628 } 542 }
629 // Floating 543 // Floating
630 for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { 544 for (int i = 0; i < ws->floating->length; ++i) {
631 struct sway_container *child = ws->sway_workspace->floating->items[i]; 545 struct sway_container *child = ws->floating->items[i];
632 if (test(child, data)) { 546 if (test(child, data)) {
633 return child; 547 return child;
634 } 548 }
@@ -639,37 +553,76 @@ struct sway_container *workspace_find_container(struct sway_container *ws,
639 return NULL; 553 return NULL;
640} 554}
641 555
642struct sway_container *workspace_wrap_children(struct sway_container *ws) { 556struct sway_container *workspace_wrap_children(struct sway_workspace *ws) {
643 struct sway_container *middle = container_create(C_CONTAINER); 557 struct sway_container *middle = container_create(NULL);
644 middle->layout = ws->layout; 558 middle->layout = ws->layout;
645 while (ws->children->length) { 559 while (ws->tiling->length) {
646 struct sway_container *child = ws->children->items[0]; 560 struct sway_container *child = ws->tiling->items[0];
647 container_remove_child(child); 561 container_detach(child);
648 container_add_child(middle, child); 562 container_add_child(middle, child);
649 } 563 }
650 container_add_child(ws, middle); 564 workspace_add_tiling(ws, middle);
651 return middle; 565 return middle;
652} 566}
653 567
654void workspace_add_floating(struct sway_container *workspace, 568void workspace_detach(struct sway_workspace *workspace) {
655 struct sway_container *con) { 569 struct sway_output *output = workspace->output;
656 if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { 570 int index = list_find(output->workspaces, workspace);
657 return; 571 if (index != -1) {
572 list_del(output->workspaces, index);
658 } 573 }
659 if (!sway_assert(con->parent == NULL, "Expected an orphan container")) { 574 workspace->output = NULL;
660 return; 575
576 node_set_dirty(&workspace->node);
577 node_set_dirty(&output->node);
578}
579
580static void set_workspace(struct sway_container *container, void *data) {
581 container->workspace = container->parent->workspace;
582}
583
584void workspace_add_tiling(struct sway_workspace *workspace,
585 struct sway_container *con) {
586 if (con->workspace) {
587 container_detach(con);
661 } 588 }
589 list_add(workspace->tiling, con);
590 con->workspace = workspace;
591 container_for_each_child(con, set_workspace, NULL);
592 container_handle_fullscreen_reparent(con);
593 workspace_update_representation(workspace);
594 node_set_dirty(&workspace->node);
595 node_set_dirty(&con->node);
596}
662 597
663 list_add(workspace->sway_workspace->floating, con); 598void workspace_add_floating(struct sway_workspace *workspace,
664 con->parent = workspace; 599 struct sway_container *con) {
665 container_set_dirty(workspace); 600 if (con->workspace) {
666 container_set_dirty(con); 601 container_detach(con);
602 }
603 list_add(workspace->floating, con);
604 con->workspace = workspace;
605 container_for_each_child(con, set_workspace, NULL);
606 container_handle_fullscreen_reparent(con);
607 node_set_dirty(&workspace->node);
608 node_set_dirty(&con->node);
667} 609}
668 610
669void workspace_remove_gaps(struct sway_container *ws) { 611void workspace_insert_tiling(struct sway_workspace *workspace,
670 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { 612 struct sway_container *con, int index) {
671 return; 613 if (con->workspace) {
614 container_detach(con);
672 } 615 }
616 list_insert(workspace->tiling, index, con);
617 con->workspace = workspace;
618 container_for_each_child(con, set_workspace, NULL);
619 container_handle_fullscreen_reparent(con);
620 workspace_update_representation(workspace);
621 node_set_dirty(&workspace->node);
622 node_set_dirty(&con->node);
623}
624
625void workspace_remove_gaps(struct sway_workspace *ws) {
673 if (ws->current_gaps == 0) { 626 if (ws->current_gaps == 0) {
674 return; 627 return;
675 } 628 }
@@ -681,15 +634,12 @@ void workspace_remove_gaps(struct sway_container *ws) {
681 ws->current_gaps = 0; 634 ws->current_gaps = 0;
682} 635}
683 636
684void workspace_add_gaps(struct sway_container *ws) { 637void workspace_add_gaps(struct sway_workspace *ws) {
685 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
686 return;
687 }
688 if (ws->current_gaps > 0) { 638 if (ws->current_gaps > 0) {
689 return; 639 return;
690 } 640 }
691 bool should_apply = 641 bool should_apply =
692 config->edge_gaps || (config->smart_gaps && ws->children->length > 1); 642 config->edge_gaps || (config->smart_gaps && ws->tiling->length > 1);
693 if (!should_apply) { 643 if (!should_apply) {
694 return; 644 return;
695 } 645 }
@@ -708,3 +658,36 @@ void workspace_add_gaps(struct sway_container *ws) {
708 ws->width -= 2 * ws->current_gaps; 658 ws->width -= 2 * ws->current_gaps;
709 ws->height -= 2 * ws->current_gaps; 659 ws->height -= 2 * ws->current_gaps;
710} 660}
661
662struct sway_container *workspace_split(struct sway_workspace *workspace,
663 enum sway_container_layout layout) {
664 if (workspace->tiling->length == 0) {
665 workspace->prev_split_layout = workspace->layout;
666 workspace->layout = layout;
667 return NULL;
668 }
669
670 enum sway_container_layout old_layout = workspace->layout;
671 struct sway_container *middle = workspace_wrap_children(workspace);
672 workspace->layout = layout;
673 middle->layout = old_layout;
674
675 return middle;
676}
677
678void workspace_update_representation(struct sway_workspace *ws) {
679 size_t len = container_build_representation(ws->layout, ws->tiling, NULL);
680 free(ws->representation);
681 ws->representation = calloc(len + 1, sizeof(char));
682 if (!sway_assert(ws->representation, "Unable to allocate title string")) {
683 return;
684 }
685 container_build_representation(ws->layout, ws->tiling, ws->representation);
686}
687
688void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box) {
689 box->x = workspace->x;
690 box->y = workspace->y;
691 box->width = workspace->width;
692 box->height = workspace->height;
693}