aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/layout.c')
-rw-r--r--sway/tree/layout.c97
1 files changed, 64 insertions, 33 deletions
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 14631ad4..a2be0ef3 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -22,7 +22,8 @@ struct sway_container root_container;
22 22
23static void output_layout_handle_change(struct wl_listener *listener, 23static void output_layout_handle_change(struct wl_listener *listener,
24 void *data) { 24 void *data) {
25 arrange_and_commit(&root_container); 25 arrange_windows(&root_container);
26 transaction_commit_dirty();
26} 27}
27 28
28void layout_init(void) { 29void layout_init(void) {
@@ -41,6 +42,7 @@ void layout_init(void) {
41 wl_list_init(&root_container.sway_root->xwayland_unmanaged); 42 wl_list_init(&root_container.sway_root->xwayland_unmanaged);
42 wl_list_init(&root_container.sway_root->drag_icons); 43 wl_list_init(&root_container.sway_root->drag_icons);
43 wl_signal_init(&root_container.sway_root->events.new_container); 44 wl_signal_init(&root_container.sway_root->events.new_container);
45 root_container.sway_root->scratchpad = create_list();
44 46
45 root_container.sway_root->output_layout_change.notify = 47 root_container.sway_root->output_layout_change.notify =
46 output_layout_handle_change; 48 output_layout_handle_change;
@@ -101,7 +103,7 @@ void container_insert_child(struct sway_container *parent,
101 if (old_parent) { 103 if (old_parent) {
102 container_remove_child(child); 104 container_remove_child(child);
103 } 105 }
104 wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i); 106 wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i);
105 list_insert(parent->children, i, child); 107 list_insert(parent->children, i, child);
106 child->parent = parent; 108 child->parent = parent;
107 container_handle_fullscreen_reparent(child, old_parent); 109 container_handle_fullscreen_reparent(child, old_parent);
@@ -127,13 +129,17 @@ struct sway_container *container_add_sibling(struct sway_container *fixed,
127 129
128void container_add_child(struct sway_container *parent, 130void container_add_child(struct sway_container *parent,
129 struct sway_container *child) { 131 struct sway_container *child) {
130 wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", 132 wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
131 child, child->type, child->width, child->height, 133 child, child->type, child->width, child->height,
132 parent, parent->type, parent->width, parent->height); 134 parent, parent->type, parent->width, parent->height);
133 struct sway_container *old_parent = child->parent; 135 struct sway_container *old_parent = child->parent;
134 list_add(parent->children, child); 136 list_add(parent->children, child);
135 child->parent = parent; 137 child->parent = parent;
136 container_handle_fullscreen_reparent(child, old_parent); 138 container_handle_fullscreen_reparent(child, old_parent);
139 if (old_parent) {
140 container_set_dirty(old_parent);
141 }
142 container_set_dirty(child);
137} 143}
138 144
139struct sway_container *container_remove_child(struct sway_container *child) { 145struct sway_container *container_remove_child(struct sway_container *child) {
@@ -152,6 +158,9 @@ struct sway_container *container_remove_child(struct sway_container *child) {
152 child->parent = NULL; 158 child->parent = NULL;
153 container_notify_subtree_changed(parent); 159 container_notify_subtree_changed(parent);
154 160
161 container_set_dirty(parent);
162 container_set_dirty(child);
163
155 return parent; 164 return parent;
156} 165}
157 166
@@ -168,7 +177,12 @@ void container_move_to(struct sway_container *container,
168 struct sway_container *old_parent = container_remove_child(container); 177 struct sway_container *old_parent = container_remove_child(container);
169 container->width = container->height = 0; 178 container->width = container->height = 0;
170 container->saved_width = container->saved_height = 0; 179 container->saved_width = container->saved_height = 0;
171 struct sway_container *new_parent; 180
181 struct sway_container *new_parent, *new_parent_focus;
182 struct sway_seat *seat = input_manager_get_default_seat(input_manager);
183
184 // Get the focus of the destination before we change it.
185 new_parent_focus = seat_get_focus_inactive(seat, destination);
172 if (destination->type == C_VIEW) { 186 if (destination->type == C_VIEW) {
173 new_parent = container_add_sibling(destination, container); 187 new_parent = container_add_sibling(destination, container);
174 } else { 188 } else {
@@ -176,17 +190,20 @@ void container_move_to(struct sway_container *container,
176 container_add_child(destination, container); 190 container_add_child(destination, container);
177 } 191 }
178 wl_signal_emit(&container->events.reparent, old_parent); 192 wl_signal_emit(&container->events.reparent, old_parent);
193
179 if (container->type == C_WORKSPACE) { 194 if (container->type == C_WORKSPACE) {
180 // If moving a workspace to a new output, maybe create a new workspace 195 // If moving a workspace to a new output, maybe create a new workspace
181 // on the previous output 196 // on the previous output
182 struct sway_seat *seat = input_manager_get_default_seat(input_manager);
183 if (old_parent->children->length == 0) { 197 if (old_parent->children->length == 0) {
184 char *ws_name = workspace_next_name(old_parent->name); 198 char *ws_name = workspace_next_name(old_parent->name);
185 struct sway_container *ws = 199 struct sway_container *ws = workspace_create(old_parent, ws_name);
186 workspace_create(old_parent, ws_name);
187 free(ws_name); 200 free(ws_name);
188 seat_set_focus(seat, ws); 201 seat_set_focus(seat, ws);
189 } 202 }
203
204 // Try to remove an empty workspace from the destination output.
205 container_reap_empty_recursive(new_parent_focus);
206
190 container_sort_workspaces(new_parent); 207 container_sort_workspaces(new_parent);
191 seat_set_focus(seat, new_parent); 208 seat_set_focus(seat, new_parent);
192 workspace_output_raise_priority(container, old_parent, new_parent); 209 workspace_output_raise_priority(container, old_parent, new_parent);
@@ -216,6 +233,17 @@ void container_move_to(struct sway_container *container,
216 } 233 }
217 } 234 }
218 } 235 }
236 // Update workspace urgent state
237 struct sway_container *old_workspace = old_parent;
238 if (old_workspace->type != C_WORKSPACE) {
239 old_workspace = container_parent(old_workspace, C_WORKSPACE);
240 }
241 if (new_workspace != old_workspace) {
242 workspace_detect_urgent(new_workspace);
243 if (old_workspace) {
244 workspace_detect_urgent(old_workspace);
245 }
246 }
219} 247}
220 248
221static bool sway_dir_to_wlr(enum movement_direction dir, 249static bool sway_dir_to_wlr(enum movement_direction dir,
@@ -311,13 +339,13 @@ static void move_out_of_tabs_stacks(struct sway_container *container,
311 int offs) { 339 int offs) {
312 if (container->parent == current->parent 340 if (container->parent == current->parent
313 && current->parent->children->length == 1) { 341 && current->parent->children->length == 1) {
314 wlr_log(L_DEBUG, "Changing layout of %zd", current->parent->id); 342 wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id);
315 current->parent->layout = move_dir == 343 current->parent->layout = move_dir ==
316 MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; 344 MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
317 return; 345 return;
318 } 346 }
319 347
320 wlr_log(L_DEBUG, "Moving out of tab/stack into a split"); 348 wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split");
321 bool is_workspace = current->parent->type == C_WORKSPACE; 349 bool is_workspace = current->parent->type == C_WORKSPACE;
322 struct sway_container *new_parent = container_split(current->parent, 350 struct sway_container *new_parent = container_split(current->parent,
323 move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); 351 move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT);
@@ -362,7 +390,7 @@ void container_move(struct sway_container *container,
362 } 390 }
363 391
364 parent = current->parent; 392 parent = current->parent;
365 wlr_log(L_DEBUG, "Visiting %p %s '%s'", current, 393 wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current,
366 container_type_to_str(current->type), current->name); 394 container_type_to_str(current->type), current->name);
367 395
368 int index = index_child(current); 396 int index = index_child(current);
@@ -380,12 +408,12 @@ void container_move(struct sway_container *container,
380 root_container.sway_root->output_layout, wlr_dir, 408 root_container.sway_root->output_layout, wlr_dir,
381 current->sway_output->wlr_output, ref_lx, ref_ly); 409 current->sway_output->wlr_output, ref_lx, ref_ly);
382 if (!next) { 410 if (!next) {
383 wlr_log(L_DEBUG, "Hit edge of output, nowhere else to go"); 411 wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go");
384 return; 412 return;
385 } 413 }
386 struct sway_output *next_output = next->data; 414 struct sway_output *next_output = next->data;
387 current = next_output->swayc; 415 current = next_output->swayc;
388 wlr_log(L_DEBUG, "Selected next output (%s)", current->name); 416 wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name);
389 // Select workspace and get outta here 417 // Select workspace and get outta here
390 current = seat_get_focus_inactive( 418 current = seat_get_focus_inactive(
391 config->handler_context.seat, current); 419 config->handler_context.seat, current);
@@ -398,20 +426,20 @@ void container_move(struct sway_container *container,
398 case C_WORKSPACE: 426 case C_WORKSPACE:
399 if (!is_parallel(current->layout, move_dir)) { 427 if (!is_parallel(current->layout, move_dir)) {
400 if (current->children->length >= 2) { 428 if (current->children->length >= 2) {
401 wlr_log(L_DEBUG, "Rejiggering the workspace (%d kiddos)", 429 wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)",
402 current->children->length); 430 current->children->length);
403 workspace_rejigger(current, container, move_dir); 431 workspace_rejigger(current, container, move_dir);
404 return; 432 return;
405 } else { 433 } else {
406 wlr_log(L_DEBUG, "Selecting output"); 434 wlr_log(WLR_DEBUG, "Selecting output");
407 current = current->parent; 435 current = current->parent;
408 } 436 }
409 } else if (current->layout == L_TABBED 437 } else if (current->layout == L_TABBED
410 || current->layout == L_STACKED) { 438 || current->layout == L_STACKED) {
411 wlr_log(L_DEBUG, "Rejiggering out of tabs/stacks"); 439 wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks");
412 workspace_rejigger(current, container, move_dir); 440 workspace_rejigger(current, container, move_dir);
413 } else { 441 } else {
414 wlr_log(L_DEBUG, "Selecting output"); 442 wlr_log(WLR_DEBUG, "Selecting output");
415 current = current->parent; 443 current = current->parent;
416 } 444 }
417 break; 445 break;
@@ -427,11 +455,11 @@ void container_move(struct sway_container *container,
427 move_dir, offs); 455 move_dir, offs);
428 return; 456 return;
429 } else { 457 } else {
430 wlr_log(L_DEBUG, "Hit limit, selecting parent"); 458 wlr_log(WLR_DEBUG, "Hit limit, selecting parent");
431 current = current->parent; 459 current = current->parent;
432 } 460 }
433 } else { 461 } else {
434 wlr_log(L_DEBUG, "Hit limit, " 462 wlr_log(WLR_DEBUG, "Hit limit, "
435 "promoting descendant to sibling"); 463 "promoting descendant to sibling");
436 // Special case 464 // Special case
437 container_insert_child(current->parent, container, 465 container_insert_child(current->parent, container,
@@ -441,14 +469,14 @@ void container_move(struct sway_container *container,
441 } 469 }
442 } else { 470 } else {
443 sibling = parent->children->items[index + offs]; 471 sibling = parent->children->items[index + offs];
444 wlr_log(L_DEBUG, "Selecting sibling id:%zd", sibling->id); 472 wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id);
445 } 473 }
446 } else if (parent->layout == L_TABBED 474 } else if (parent->layout == L_TABBED
447 || parent->layout == L_STACKED) { 475 || parent->layout == L_STACKED) {
448 move_out_of_tabs_stacks(container, current, move_dir, offs); 476 move_out_of_tabs_stacks(container, current, move_dir, offs);
449 return; 477 return;
450 } else { 478 } else {
451 wlr_log(L_DEBUG, "Moving up to find a parallel container"); 479 wlr_log(WLR_DEBUG, "Moving up to find a parallel container");
452 current = current->parent; 480 current = current->parent;
453 } 481 }
454 break; 482 break;
@@ -467,11 +495,11 @@ void container_move(struct sway_container *container,
467 switch (sibling->type) { 495 switch (sibling->type) {
468 case C_VIEW: 496 case C_VIEW:
469 if (sibling->parent == container->parent) { 497 if (sibling->parent == container->parent) {
470 wlr_log(L_DEBUG, "Swapping siblings"); 498 wlr_log(WLR_DEBUG, "Swapping siblings");
471 sibling->parent->children->items[index + offs] = container; 499 sibling->parent->children->items[index + offs] = container;
472 sibling->parent->children->items[index] = sibling; 500 sibling->parent->children->items[index] = sibling;
473 } else { 501 } else {
474 wlr_log(L_DEBUG, "Promoting to sibling of cousin"); 502 wlr_log(WLR_DEBUG, "Promoting to sibling of cousin");
475 container_insert_child(sibling->parent, container, 503 container_insert_child(sibling->parent, container,
476 index_child(sibling) + (offs > 0 ? 0 : 1)); 504 index_child(sibling) + (offs > 0 ? 0 : 1));
477 container->width = container->height = 0; 505 container->width = container->height = 0;
@@ -482,31 +510,31 @@ void container_move(struct sway_container *container,
482 case C_CONTAINER: 510 case C_CONTAINER:
483 if (is_parallel(sibling->layout, move_dir)) { 511 if (is_parallel(sibling->layout, move_dir)) {
484 int limit = container_limit(sibling, invert_movement(move_dir)); 512 int limit = container_limit(sibling, invert_movement(move_dir));
485 wlr_log(L_DEBUG, "limit: %d", limit); 513 wlr_log(WLR_DEBUG, "limit: %d", limit);
486 wlr_log(L_DEBUG, 514 wlr_log(WLR_DEBUG,
487 "Reparenting container (parallel) to index %d " 515 "Reparenting container (parallel) to index %d "
488 "(move dir: %d)", limit, move_dir); 516 "(move dir: %d)", limit, move_dir);
489 container_insert_child(sibling, container, limit); 517 container_insert_child(sibling, container, limit);
490 container->width = container->height = 0; 518 container->width = container->height = 0;
491 sibling = NULL; 519 sibling = NULL;
492 } else { 520 } else {
493 wlr_log(L_DEBUG, "Reparenting container (perpendicular)"); 521 wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)");
494 struct sway_container *focus_inactive = seat_get_focus_inactive( 522 struct sway_container *focus_inactive = seat_get_focus_inactive(
495 config->handler_context.seat, sibling); 523 config->handler_context.seat, sibling);
496 if (focus_inactive && focus_inactive != sibling) { 524 if (focus_inactive && focus_inactive != sibling) {
497 while (focus_inactive->parent != sibling) { 525 while (focus_inactive->parent != sibling) {
498 focus_inactive = focus_inactive->parent; 526 focus_inactive = focus_inactive->parent;
499 } 527 }
500 wlr_log(L_DEBUG, "Focus inactive: id:%zd", 528 wlr_log(WLR_DEBUG, "Focus inactive: id:%zd",
501 focus_inactive->id); 529 focus_inactive->id);
502 sibling = focus_inactive; 530 sibling = focus_inactive;
503 continue; 531 continue;
504 } else if (sibling->children->length) { 532 } else if (sibling->children->length) {
505 wlr_log(L_DEBUG, "No focus-inactive, adding arbitrarily"); 533 wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily");
506 container_remove_child(container); 534 container_remove_child(container);
507 container_add_sibling(sibling->children->items[0], container); 535 container_add_sibling(sibling->children->items[0], container);
508 } else { 536 } else {
509 wlr_log(L_DEBUG, "No kiddos, adding container alone"); 537 wlr_log(WLR_DEBUG, "No kiddos, adding container alone");
510 container_remove_child(container); 538 container_remove_child(container);
511 container_add_child(sibling, container); 539 container_add_child(sibling, container);
512 } 540 }
@@ -539,7 +567,10 @@ void container_move(struct sway_container *container,
539 } 567 }
540 if (last_ws && next_ws && last_ws != next_ws) { 568 if (last_ws && next_ws && last_ws != next_ws) {
541 ipc_event_workspace(last_ws, container, "focus"); 569 ipc_event_workspace(last_ws, container, "focus");
570 workspace_detect_urgent(last_ws);
571 workspace_detect_urgent(next_ws);
542 } 572 }
573 container_end_mouse_operation(container);
543} 574}
544 575
545enum sway_container_layout container_get_default_layout( 576enum sway_container_layout container_get_default_layout(
@@ -603,7 +634,7 @@ static struct sway_container *get_swayc_in_output_direction(
603 } 634 }
604 635
605 if (ws == NULL) { 636 if (ws == NULL) {
606 wlr_log(L_ERROR, "got an output without a workspace"); 637 wlr_log(WLR_ERROR, "got an output without a workspace");
607 return NULL; 638 return NULL;
608 } 639 }
609 640
@@ -775,7 +806,7 @@ struct sway_container *container_get_in_direction(
775 } else { 806 } else {
776 struct sway_container *desired_con = 807 struct sway_container *desired_con =
777 parent->children->items[desired]; 808 parent->children->items[desired];
778 wlr_log(L_DEBUG, 809 wlr_log(WLR_DEBUG,
779 "cont %d-%p dir %i sibling %d: %p", idx, 810 "cont %d-%p dir %i sibling %d: %p", idx,
780 container, dir, desired, desired_con); 811 container, dir, desired, desired_con);
781 return seat_get_focus_inactive_view(seat, desired_con); 812 return seat_get_focus_inactive_view(seat, desired_con);
@@ -840,7 +871,7 @@ struct sway_container *container_split(struct sway_container *child,
840 871
841 struct sway_container *cont = container_create(C_CONTAINER); 872 struct sway_container *cont = container_create(C_CONTAINER);
842 873
843 wlr_log(L_DEBUG, "creating container %p around %p", cont, child); 874 wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child);
844 875
845 remove_gaps(child); 876 remove_gaps(child);
846 877
@@ -888,7 +919,7 @@ struct sway_container *container_split(struct sway_container *child,
888void container_recursive_resize(struct sway_container *container, 919void container_recursive_resize(struct sway_container *container,
889 double amount, enum resize_edge edge) { 920 double amount, enum resize_edge edge) {
890 bool layout_match = true; 921 bool layout_match = true;
891 wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); 922 wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount);
892 if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { 923 if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) {
893 container->width += amount; 924 container->width += amount;
894 layout_match = container->layout == L_HORIZ; 925 layout_match = container->layout == L_HORIZ;
@@ -978,7 +1009,7 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
978 return; 1009 return;
979 } 1010 }
980 1011
981 wlr_log(L_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); 1012 wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id);
982 1013
983 int fs1 = con1->type == C_VIEW && con1->sway_view->is_fullscreen; 1014 int fs1 = con1->type == C_VIEW && con1->sway_view->is_fullscreen;
984 int fs2 = con2->type == C_VIEW && con2->sway_view->is_fullscreen; 1015 int fs2 = con2->type == C_VIEW && con2->sway_view->is_fullscreen;