aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/workspace.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/workspace.c')
-rw-r--r--sway/tree/workspace.c174
1 files changed, 93 insertions, 81 deletions
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 921b7d19..40d33435 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -48,14 +48,16 @@ struct sway_output *workspace_get_initial_output(const char *name) {
48 if (focus && focus->type == N_WORKSPACE) { 48 if (focus && focus->type == N_WORKSPACE) {
49 return focus->sway_workspace->output; 49 return focus->sway_workspace->output;
50 } else if (focus && focus->type == N_CONTAINER) { 50 } else if (focus && focus->type == N_CONTAINER) {
51 return focus->sway_container->workspace->output; 51 return focus->sway_container->pending.workspace->output;
52 } 52 }
53 // Fallback to the first output or noop output for headless 53 // Fallback to the first output or the headless output
54 return root->outputs->length ? root->outputs->items[0] : root->noop_output; 54 return root->outputs->length ? root->outputs->items[0] : root->fallback_output;
55} 55}
56 56
57struct sway_workspace *workspace_create(struct sway_output *output, 57struct sway_workspace *workspace_create(struct sway_output *output,
58 const char *name) { 58 const char *name) {
59 sway_assert(name, "NULL name given to workspace_create");
60
59 if (output == NULL) { 61 if (output == NULL) {
60 output = workspace_get_initial_output(name); 62 output = workspace_get_initial_output(name);
61 } 63 }
@@ -69,7 +71,19 @@ struct sway_workspace *workspace_create(struct sway_output *output,
69 return NULL; 71 return NULL;
70 } 72 }
71 node_init(&ws->node, N_WORKSPACE, ws); 73 node_init(&ws->node, N_WORKSPACE, ws);
72 ws->name = name ? strdup(name) : NULL; 74
75 bool failed = false;
76 ws->layers.tiling = alloc_scene_tree(root->staging, &failed);
77 ws->layers.fullscreen = alloc_scene_tree(root->staging, &failed);
78
79 if (failed) {
80 wlr_scene_node_destroy(&ws->layers.tiling->node);
81 wlr_scene_node_destroy(&ws->layers.fullscreen->node);
82 free(ws);
83 return NULL;
84 }
85
86 ws->name = strdup(name);
73 ws->prev_split_layout = L_NONE; 87 ws->prev_split_layout = L_NONE;
74 ws->layout = output_get_default_layout(output); 88 ws->layout = output_get_default_layout(output);
75 ws->floating = create_list(); 89 ws->floating = create_list();
@@ -114,7 +128,7 @@ struct sway_workspace *workspace_create(struct sway_output *output,
114 output_sort_workspaces(output); 128 output_sort_workspaces(output);
115 129
116 ipc_event_workspace(NULL, ws, "init"); 130 ipc_event_workspace(NULL, ws, "init");
117 wl_signal_emit(&root->events.new_node, &ws->node); 131 wl_signal_emit_mutable(&root->events.new_node, &ws->node);
118 132
119 return ws; 133 return ws;
120} 134}
@@ -129,6 +143,11 @@ void workspace_destroy(struct sway_workspace *workspace) {
129 return; 143 return;
130 } 144 }
131 145
146 scene_node_disown_children(workspace->layers.tiling);
147 scene_node_disown_children(workspace->layers.fullscreen);
148 wlr_scene_node_destroy(&workspace->layers.tiling->node);
149 wlr_scene_node_destroy(&workspace->layers.fullscreen->node);
150
132 free(workspace->name); 151 free(workspace->name);
133 free(workspace->representation); 152 free(workspace->representation);
134 list_free_items_and_destroy(workspace->output_priority); 153 list_free_items_and_destroy(workspace->output_priority);
@@ -142,7 +161,7 @@ void workspace_destroy(struct sway_workspace *workspace) {
142void workspace_begin_destroy(struct sway_workspace *workspace) { 161void workspace_begin_destroy(struct sway_workspace *workspace) {
143 sway_log(SWAY_DEBUG, "Destroying workspace '%s'", workspace->name); 162 sway_log(SWAY_DEBUG, "Destroying workspace '%s'", workspace->name);
144 ipc_event_workspace(NULL, workspace, "empty"); // intentional 163 ipc_event_workspace(NULL, workspace, "empty"); // intentional
145 wl_signal_emit(&workspace->node.events.destroy, &workspace->node); 164 wl_signal_emit_mutable(&workspace->node.events.destroy, &workspace->node);
146 165
147 if (workspace->output) { 166 if (workspace->output) {
148 workspace_detach(workspace); 167 workspace_detach(workspace);
@@ -174,22 +193,16 @@ void workspace_consider_destroy(struct sway_workspace *ws) {
174static bool workspace_valid_on_output(const char *output_name, 193static bool workspace_valid_on_output(const char *output_name,
175 const char *ws_name) { 194 const char *ws_name) {
176 struct workspace_config *wsc = workspace_find_config(ws_name); 195 struct workspace_config *wsc = workspace_find_config(ws_name);
177 char identifier[128];
178 struct sway_output *output = output_by_name_or_id(output_name); 196 struct sway_output *output = output_by_name_or_id(output_name);
179 if (!output) { 197 if (!output) {
180 return false; 198 return false;
181 } 199 }
182 output_name = output->wlr_output->name;
183 output_get_identifier(identifier, sizeof(identifier), output);
184
185 if (!wsc) { 200 if (!wsc) {
186 return true; 201 return true;
187 } 202 }
188 203
189 for (int i = 0; i < wsc->outputs->length; i++) { 204 for (int i = 0; i < wsc->outputs->length; i++) {
190 if (strcmp(wsc->outputs->items[i], "*") == 0 || 205 if (output_match_name_or_id(output, wsc->outputs->items[i])) {
191 strcmp(wsc->outputs->items[i], output_name) == 0 ||
192 strcmp(wsc->outputs->items[i], identifier) == 0) {
193 return true; 206 return true;
194 } 207 }
195 } 208 }
@@ -222,10 +235,8 @@ static void workspace_name_from_binding(const struct sway_binding * binding,
222 // not a command about workspaces 235 // not a command about workspaces
223 if (strcmp(_target, "next") == 0 || 236 if (strcmp(_target, "next") == 0 ||
224 strcmp(_target, "prev") == 0 || 237 strcmp(_target, "prev") == 0 ||
225 strncmp(_target, "next_on_output", 238 strcmp(_target, "next_on_output") == 0 ||
226 strlen("next_on_output")) == 0 || 239 strcmp(_target, "prev_on_output") == 0 ||
227 strncmp(_target, "prev_on_output",
228 strlen("next_on_output")) == 0 ||
229 strcmp(_target, "number") == 0 || 240 strcmp(_target, "number") == 0 ||
230 strcmp(_target, "back_and_forth") == 0 || 241 strcmp(_target, "back_and_forth") == 0 ||
231 strcmp(_target, "current") == 0) { 242 strcmp(_target, "current") == 0) {
@@ -286,13 +297,10 @@ char *workspace_next_name(const char *output_name) {
286 // assignments primarily, falling back to bindings and numbers. 297 // assignments primarily, falling back to bindings and numbers.
287 struct sway_mode *mode = config->current_mode; 298 struct sway_mode *mode = config->current_mode;
288 299
289 char identifier[128];
290 struct sway_output *output = output_by_name_or_id(output_name); 300 struct sway_output *output = output_by_name_or_id(output_name);
291 if (!output) { 301 if (!output) {
292 return NULL; 302 return NULL;
293 } 303 }
294 output_name = output->wlr_output->name;
295 output_get_identifier(identifier, sizeof(identifier), output);
296 304
297 int order = INT_MAX; 305 int order = INT_MAX;
298 char *target = NULL; 306 char *target = NULL;
@@ -312,9 +320,7 @@ char *workspace_next_name(const char *output_name) {
312 } 320 }
313 bool found = false; 321 bool found = false;
314 for (int j = 0; j < wsc->outputs->length; ++j) { 322 for (int j = 0; j < wsc->outputs->length; ++j) {
315 if (strcmp(wsc->outputs->items[j], "*") == 0 || 323 if (output_match_name_or_id(output, wsc->outputs->items[j])) {
316 strcmp(wsc->outputs->items[j], output_name) == 0 ||
317 strcmp(wsc->outputs->items[j], identifier) == 0) {
318 found = true; 324 found = true;
319 free(target); 325 free(target);
320 target = strdup(wsc->workspace); 326 target = strdup(wsc->workspace);
@@ -363,11 +369,11 @@ struct sway_workspace *workspace_by_name(const char *name) {
363 if (current && strcmp(name, "prev") == 0) { 369 if (current && strcmp(name, "prev") == 0) {
364 return workspace_prev(current); 370 return workspace_prev(current);
365 } else if (current && strcmp(name, "prev_on_output") == 0) { 371 } else if (current && strcmp(name, "prev_on_output") == 0) {
366 return workspace_output_prev(current, false); 372 return workspace_output_prev(current);
367 } else if (current && strcmp(name, "next") == 0) { 373 } else if (current && strcmp(name, "next") == 0) {
368 return workspace_next(current); 374 return workspace_next(current);
369 } else if (current && strcmp(name, "next_on_output") == 0) { 375 } else if (current && strcmp(name, "next_on_output") == 0) {
370 return workspace_output_next(current, false); 376 return workspace_output_next(current);
371 } else if (strcmp(name, "current") == 0) { 377 } else if (strcmp(name, "current") == 0) {
372 return current; 378 return current;
373 } else if (strcasecmp(name, "back_and_forth") == 0) { 379 } else if (strcasecmp(name, "back_and_forth") == 0) {
@@ -530,7 +536,7 @@ struct sway_workspace *workspace_next(struct sway_workspace *workspace) {
530 * otherwise the next one is returned. 536 * otherwise the next one is returned.
531 */ 537 */
532static struct sway_workspace *workspace_output_prev_next_impl( 538static struct sway_workspace *workspace_output_prev_next_impl(
533 struct sway_output *output, int dir, bool create) { 539 struct sway_output *output, int dir) {
534 struct sway_seat *seat = input_manager_current_seat(); 540 struct sway_seat *seat = input_manager_current_seat();
535 struct sway_workspace *workspace = seat_get_focused_workspace(seat); 541 struct sway_workspace *workspace = seat_get_focused_workspace(seat);
536 if (!workspace) { 542 if (!workspace) {
@@ -540,46 +546,43 @@ static struct sway_workspace *workspace_output_prev_next_impl(
540 } 546 }
541 547
542 int index = list_find(output->workspaces, workspace); 548 int index = list_find(output->workspaces, workspace);
543 if (!workspace_is_empty(workspace) && create &&
544 (index + dir < 0 || index + dir == output->workspaces->length)) {
545 struct sway_output *output = workspace->output;
546 char *next = workspace_next_name(output->wlr_output->name);
547 workspace_create(output, next);
548 free(next);
549 }
550 size_t new_index = wrap(index + dir, output->workspaces->length); 549 size_t new_index = wrap(index + dir, output->workspaces->length);
551 return output->workspaces->items[new_index]; 550 return output->workspaces->items[new_index];
552} 551}
553 552
554struct sway_workspace *workspace_output_next( 553
555 struct sway_workspace *current, bool create) { 554struct sway_workspace *workspace_output_next(struct sway_workspace *current) {
556 return workspace_output_prev_next_impl(current->output, 1, create); 555 return workspace_output_prev_next_impl(current->output, 1);
557} 556}
558 557
559struct sway_workspace *workspace_output_prev( 558struct sway_workspace *workspace_output_prev(struct sway_workspace *current) {
560 struct sway_workspace *current, bool create) { 559 return workspace_output_prev_next_impl(current->output, -1);
561 return workspace_output_prev_next_impl(current->output, -1, create);
562} 560}
563 561
564bool workspace_switch(struct sway_workspace *workspace, 562struct sway_workspace *workspace_auto_back_and_forth(
565 bool no_auto_back_and_forth) { 563 struct sway_workspace *workspace) {
566 struct sway_seat *seat = input_manager_current_seat(); 564 struct sway_seat *seat = input_manager_current_seat();
567 struct sway_workspace *active_ws = NULL; 565 struct sway_workspace *active_ws = NULL;
568 struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); 566 struct sway_node *focus = seat_get_focus_inactive(seat, &root->node);
569 if (focus && focus->type == N_WORKSPACE) { 567 if (focus && focus->type == N_WORKSPACE) {
570 active_ws = focus->sway_workspace; 568 active_ws = focus->sway_workspace;
571 } else if (focus && focus->type == N_CONTAINER) { 569 } else if (focus && focus->type == N_CONTAINER) {
572 active_ws = focus->sway_container->workspace; 570 active_ws = focus->sway_container->pending.workspace;
573 } 571 }
574 572
575 if (!no_auto_back_and_forth && config->auto_back_and_forth && active_ws 573 if (config->auto_back_and_forth && active_ws && active_ws == workspace &&
576 && active_ws == workspace && seat->prev_workspace_name) { 574 seat->prev_workspace_name) {
577 struct sway_workspace *new_ws = 575 struct sway_workspace *new_ws =
578 workspace_by_name(seat->prev_workspace_name); 576 workspace_by_name(seat->prev_workspace_name);
579 workspace = new_ws ? 577 workspace = new_ws ?
580 new_ws : 578 new_ws :
581 workspace_create(NULL, seat->prev_workspace_name); 579 workspace_create(NULL, seat->prev_workspace_name);
582 } 580 }
581 return workspace;
582}
583
584bool workspace_switch(struct sway_workspace *workspace) {
585 struct sway_seat *seat = input_manager_current_seat();
583 586
584 sway_log(SWAY_DEBUG, "Switching to workspace %p:%s", 587 sway_log(SWAY_DEBUG, "Switching to workspace %p:%s",
585 workspace, workspace->name); 588 workspace, workspace->name);
@@ -657,15 +660,9 @@ void workspace_output_add_priority(struct sway_workspace *workspace,
657 660
658struct sway_output *workspace_output_get_highest_available( 661struct sway_output *workspace_output_get_highest_available(
659 struct sway_workspace *ws, struct sway_output *exclude) { 662 struct sway_workspace *ws, struct sway_output *exclude) {
660 char exclude_id[128] = {'\0'};
661 if (exclude) {
662 output_get_identifier(exclude_id, sizeof(exclude_id), exclude);
663 }
664
665 for (int i = 0; i < ws->output_priority->length; i++) { 663 for (int i = 0; i < ws->output_priority->length; i++) {
666 char *name = ws->output_priority->items[i]; 664 const char *name = ws->output_priority->items[i];
667 if (exclude && (strcmp(name, exclude->wlr_output->name) == 0 665 if (exclude && output_match_name_or_id(exclude, name)) {
668 || strcmp(name, exclude_id) == 0)) {
669 continue; 666 continue;
670 } 667 }
671 668
@@ -689,7 +686,6 @@ void workspace_detect_urgent(struct sway_workspace *workspace) {
689 if (workspace->urgent != new_urgent) { 686 if (workspace->urgent != new_urgent) {
690 workspace->urgent = new_urgent; 687 workspace->urgent = new_urgent;
691 ipc_event_workspace(NULL, workspace, "urgent"); 688 ipc_event_workspace(NULL, workspace, "urgent");
692 output_damage_whole(workspace->output);
693 } 689 }
694} 690}
695 691
@@ -736,13 +732,13 @@ struct sway_container *workspace_find_container(struct sway_workspace *ws,
736} 732}
737 733
738static void set_workspace(struct sway_container *container, void *data) { 734static void set_workspace(struct sway_container *container, void *data) {
739 container->workspace = container->parent->workspace; 735 container->pending.workspace = container->pending.parent->pending.workspace;
740} 736}
741 737
742static void workspace_attach_tiling(struct sway_workspace *ws, 738static void workspace_attach_tiling(struct sway_workspace *ws,
743 struct sway_container *con) { 739 struct sway_container *con) {
744 list_add(ws->tiling, con); 740 list_add(ws->tiling, con);
745 con->workspace = ws; 741 con->pending.workspace = ws;
746 container_for_each_child(con, set_workspace, NULL); 742 container_for_each_child(con, set_workspace, NULL);
747 container_handle_fullscreen_reparent(con); 743 container_handle_fullscreen_reparent(con);
748 workspace_update_representation(ws); 744 workspace_update_representation(ws);
@@ -753,7 +749,7 @@ static void workspace_attach_tiling(struct sway_workspace *ws,
753struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { 749struct sway_container *workspace_wrap_children(struct sway_workspace *ws) {
754 struct sway_container *fs = ws->fullscreen; 750 struct sway_container *fs = ws->fullscreen;
755 struct sway_container *middle = container_create(NULL); 751 struct sway_container *middle = container_create(NULL);
756 middle->layout = ws->layout; 752 middle->pending.layout = ws->layout;
757 while (ws->tiling->length) { 753 while (ws->tiling->length) {
758 struct sway_container *child = ws->tiling->items[0]; 754 struct sway_container *child = ws->tiling->items[0];
759 container_detach(child); 755 container_detach(child);
@@ -771,9 +767,9 @@ void workspace_unwrap_children(struct sway_workspace *ws,
771 return; 767 return;
772 } 768 }
773 769
774 ws->layout = wrap->layout; 770 ws->layout = wrap->pending.layout;
775 while (wrap->children->length) { 771 while (wrap->pending.children->length) {
776 struct sway_container *child = wrap->children->items[0]; 772 struct sway_container *child = wrap->pending.children->items[0];
777 container_detach(child); 773 container_detach(child);
778 workspace_add_tiling(ws, child); 774 workspace_add_tiling(ws, child);
779 } 775 }
@@ -793,14 +789,18 @@ void workspace_detach(struct sway_workspace *workspace) {
793 789
794struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, 790struct sway_container *workspace_add_tiling(struct sway_workspace *workspace,
795 struct sway_container *con) { 791 struct sway_container *con) {
796 if (con->workspace) { 792 if (con->pending.workspace) {
793 struct sway_container *old_parent = con->pending.parent;
797 container_detach(con); 794 container_detach(con);
795 if (old_parent) {
796 container_reap_empty(old_parent);
797 }
798 } 798 }
799 if (config->default_layout != L_NONE) { 799 if (config->default_layout != L_NONE) {
800 con = container_split(con, config->default_layout); 800 con = container_split(con, config->default_layout);
801 } 801 }
802 list_add(workspace->tiling, con); 802 list_add(workspace->tiling, con);
803 con->workspace = workspace; 803 con->pending.workspace = workspace;
804 container_for_each_child(con, set_workspace, NULL); 804 container_for_each_child(con, set_workspace, NULL);
805 container_handle_fullscreen_reparent(con); 805 container_handle_fullscreen_reparent(con);
806 workspace_update_representation(workspace); 806 workspace_update_representation(workspace);
@@ -811,11 +811,11 @@ struct sway_container *workspace_add_tiling(struct sway_workspace *workspace,
811 811
812void workspace_add_floating(struct sway_workspace *workspace, 812void workspace_add_floating(struct sway_workspace *workspace,
813 struct sway_container *con) { 813 struct sway_container *con) {
814 if (con->workspace) { 814 if (con->pending.workspace) {
815 container_detach(con); 815 container_detach(con);
816 } 816 }
817 list_add(workspace->floating, con); 817 list_add(workspace->floating, con);
818 con->workspace = workspace; 818 con->pending.workspace = workspace;
819 container_for_each_child(con, set_workspace, NULL); 819 container_for_each_child(con, set_workspace, NULL);
820 container_handle_fullscreen_reparent(con); 820 container_handle_fullscreen_reparent(con);
821 node_set_dirty(&workspace->node); 821 node_set_dirty(&workspace->node);
@@ -825,7 +825,7 @@ void workspace_add_floating(struct sway_workspace *workspace,
825void workspace_insert_tiling_direct(struct sway_workspace *workspace, 825void workspace_insert_tiling_direct(struct sway_workspace *workspace,
826 struct sway_container *con, int index) { 826 struct sway_container *con, int index) {
827 list_insert(workspace->tiling, index, con); 827 list_insert(workspace->tiling, index, con);
828 con->workspace = workspace; 828 con->pending.workspace = workspace;
829 container_for_each_child(con, set_workspace, NULL); 829 container_for_each_child(con, set_workspace, NULL);
830 container_handle_fullscreen_reparent(con); 830 container_handle_fullscreen_reparent(con);
831 workspace_update_representation(workspace); 831 workspace_update_representation(workspace);
@@ -835,7 +835,7 @@ void workspace_insert_tiling_direct(struct sway_workspace *workspace,
835 835
836struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, 836struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace,
837 struct sway_container *con, int index) { 837 struct sway_container *con, int index) {
838 if (con->workspace) { 838 if (con->pending.workspace) {
839 container_detach(con); 839 container_detach(con);
840 } 840 }
841 if (config->default_layout != L_NONE) { 841 if (config->default_layout != L_NONE) {
@@ -845,24 +845,36 @@ struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace,
845 return con; 845 return con;
846} 846}
847 847
848bool workspace_has_single_visible_container(struct sway_workspace *ws) {
849 struct sway_seat *seat = input_manager_get_default_seat();
850 struct sway_container *focus =
851 seat_get_focus_inactive_tiling(seat, ws);
852 if (focus && !focus->view) {
853 focus = seat_get_focus_inactive_view(seat, &focus->node);
854 }
855 return (focus && focus->view && view_ancestor_is_only_visible(focus->view));
856}
857
848void workspace_add_gaps(struct sway_workspace *ws) { 858void workspace_add_gaps(struct sway_workspace *ws) {
849 if (config->smart_gaps) { 859 if (config->smart_gaps == SMART_GAPS_ON
850 struct sway_seat *seat = input_manager_get_default_seat(); 860 && workspace_has_single_visible_container(ws)) {
851 struct sway_container *focus = 861 ws->current_gaps.top = 0;
852 seat_get_focus_inactive_tiling(seat, ws); 862 ws->current_gaps.right = 0;
853 if (focus && !focus->view) { 863 ws->current_gaps.bottom = 0;
854 focus = seat_get_focus_inactive_view(seat, &focus->node); 864 ws->current_gaps.left = 0;
855 } 865 return;
856 if (focus && focus->view && view_ancestor_is_only_visible(focus->view)) { 866 }
857 ws->current_gaps.top = 0; 867
858 ws->current_gaps.right = 0; 868 if (config->smart_gaps == SMART_GAPS_INVERSE_OUTER
859 ws->current_gaps.bottom = 0; 869 && !workspace_has_single_visible_container(ws)) {
860 ws->current_gaps.left = 0; 870 ws->current_gaps.top = 0;
861 return; 871 ws->current_gaps.right = 0;
862 } 872 ws->current_gaps.bottom = 0;
873 ws->current_gaps.left = 0;
874 } else {
875 ws->current_gaps = ws->gaps_outer;
863 } 876 }
864 877
865 ws->current_gaps = ws->gaps_outer;
866 // Add inner gaps and make sure we don't turn out negative 878 // Add inner gaps and make sure we don't turn out negative
867 ws->current_gaps.top = fmax(0, ws->current_gaps.top + ws->gaps_inner); 879 ws->current_gaps.top = fmax(0, ws->current_gaps.top + ws->gaps_inner);
868 ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner); 880 ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner);
@@ -905,7 +917,7 @@ struct sway_container *workspace_split(struct sway_workspace *workspace,
905 enum sway_container_layout old_layout = workspace->layout; 917 enum sway_container_layout old_layout = workspace->layout;
906 struct sway_container *middle = workspace_wrap_children(workspace); 918 struct sway_container *middle = workspace_wrap_children(workspace);
907 workspace->layout = layout; 919 workspace->layout = layout;
908 middle->layout = old_layout; 920 middle->pending.layout = old_layout;
909 921
910 struct sway_seat *seat; 922 struct sway_seat *seat;
911 wl_list_for_each(seat, &server.input->seats, link) { 923 wl_list_for_each(seat, &server.input->seats, link) {