diff options
Diffstat (limited to 'sway/tree/layout.c')
-rw-r--r-- | sway/tree/layout.c | 97 |
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 | ||
23 | static void output_layout_handle_change(struct wl_listener *listener, | 23 | static 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 | ||
28 | void layout_init(void) { | 29 | void 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 | ||
128 | void container_add_child(struct sway_container *parent, | 130 | void 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 | ||
139 | struct sway_container *container_remove_child(struct sway_container *child) { | 145 | struct 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 | ||
221 | static bool sway_dir_to_wlr(enum movement_direction dir, | 249 | static 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 | ||
545 | enum sway_container_layout container_get_default_layout( | 576 | enum 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, | |||
888 | void container_recursive_resize(struct sway_container *container, | 919 | void 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; |