aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Alexander Orzechowski <alex@ozal.ski>2024-01-18 10:01:12 -0500
committerLibravatar Kirill Primak <vyivel@eclair.cafe>2024-01-18 18:36:54 +0300
commit2e53de80bb0f4c93e74ae050fa07e78f18e909d9 (patch)
tree155e4ee92c60445d61e7e516e15d48fc1d68a3fa
parentcontainer: Don't track outputs (diff)
downloadsway-2e53de80bb0f4c93e74ae050fa07e78f18e909d9.tar.gz
sway-2e53de80bb0f4c93e74ae050fa07e78f18e909d9.tar.zst
sway-2e53de80bb0f4c93e74ae050fa07e78f18e909d9.zip
scene_graph: Arrange scene graph on transaction apply
-rw-r--r--sway/desktop/transaction.c430
1 files changed, 428 insertions, 2 deletions
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index ba9d0648..0755c8a0 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -5,6 +5,7 @@
5#include <time.h> 5#include <time.h>
6#include <wlr/types/wlr_buffer.h> 6#include <wlr/types/wlr_buffer.h>
7#include "sway/config.h" 7#include "sway/config.h"
8#include "sway/scene_descriptor.h"
8#include "sway/desktop/idle_inhibit_v1.h" 9#include "sway/desktop/idle_inhibit_v1.h"
9#include "sway/desktop/transaction.h" 10#include "sway/desktop/transaction.h"
10#include "sway/input/cursor.h" 11#include "sway/input/cursor.h"
@@ -252,6 +253,431 @@ static void apply_container_state(struct sway_container *container,
252 } 253 }
253} 254}
254 255
256static void arrange_title_bar(struct sway_container *con,
257 int x, int y, int width, int height) {
258 container_update(con);
259
260 bool has_title_bar = height > 0;
261 wlr_scene_node_set_enabled(&con->title_bar.tree->node, has_title_bar);
262 if (!has_title_bar) {
263 return;
264 }
265
266 wlr_scene_node_set_position(&con->title_bar.tree->node, x, y);
267
268 con->title_width = width;
269 container_arrange_title_bar(con);
270}
271
272static void disable_container(struct sway_container *con) {
273 if (con->view) {
274 wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree);
275 } else {
276 for (int i = 0; i < con->current.children->length; i++) {
277 struct sway_container *child = con->current.children->items[i];
278
279 wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree);
280
281 disable_container(child);
282 }
283 }
284}
285
286static void arrange_container(struct sway_container *con,
287 int width, int height, bool title_bar, int gaps);
288
289static void arrange_children(enum sway_container_layout layout, list_t *children,
290 struct sway_container *active, struct wlr_scene_tree *content,
291 int width, int height, int gaps) {
292 int title_bar_height = container_titlebar_height();
293
294 if (layout == L_TABBED) {
295 struct sway_container *first = children->length == 1 ?
296 ((struct sway_container *)children->items[0]) : NULL;
297 if (config->hide_lone_tab && first && first->view &&
298 first->current.border != B_NORMAL) {
299 title_bar_height = 0;
300 }
301
302 double w = (double) width / children->length;
303 int title_offset = 0;
304 for (int i = 0; i < children->length; i++) {
305 struct sway_container *child = children->items[i];
306 bool activated = child == active;
307 int next_title_offset = round(w * i + w);
308
309 arrange_title_bar(child, title_offset, -title_bar_height,
310 next_title_offset - title_offset, title_bar_height);
311 wlr_scene_node_set_enabled(&child->border.tree->node, activated);
312 wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
313 wlr_scene_node_reparent(&child->scene_tree->node, content);
314
315 if (activated) {
316 arrange_container(child, width, height - title_bar_height,
317 false, 0);
318 } else {
319 disable_container(child);
320 }
321
322 title_offset = next_title_offset;
323 }
324 } else if (layout == L_STACKED) {
325 struct sway_container *first = children->length == 1 ?
326 ((struct sway_container *)children->items[0]) : NULL;
327 if (config->hide_lone_tab && first && first->view &&
328 first->current.border != B_NORMAL) {
329 title_bar_height = 0;
330 }
331
332 int title_height = title_bar_height * children->length;
333
334 int y = 0;
335 for (int i = 0; i < children->length; i++) {
336 struct sway_container *child = children->items[i];
337 bool activated = child == active;
338
339 arrange_title_bar(child, 0, y - title_height, width, title_bar_height);
340 wlr_scene_node_set_enabled(&child->border.tree->node, activated);
341 wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
342 wlr_scene_node_reparent(&child->scene_tree->node, content);
343
344 if (activated) {
345 arrange_container(child, width, height - title_height,
346 false, 0);
347 } else {
348 disable_container(child);
349 }
350
351 y += title_bar_height;
352 }
353 } else if (layout == L_VERT) {
354 int off = 0;
355 for (int i = 0; i < children->length; i++) {
356 struct sway_container *child = children->items[i];
357 int cheight = child->current.height;
358
359 wlr_scene_node_set_enabled(&child->border.tree->node, true);
360 wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
361 wlr_scene_node_reparent(&child->scene_tree->node, content);
362 arrange_container(child, width, cheight, true, gaps);
363 off += cheight + gaps;
364 }
365 } else if (layout == L_HORIZ) {
366 int off = 0;
367 for (int i = 0; i < children->length; i++) {
368 struct sway_container *child = children->items[i];
369 int cwidth = child->current.width;
370
371 wlr_scene_node_set_enabled(&child->border.tree->node, true);
372 wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
373 wlr_scene_node_reparent(&child->scene_tree->node, content);
374 arrange_container(child, cwidth, height, true, gaps);
375 off += cwidth + gaps;
376 }
377 } else {
378 sway_assert(false, "unreachable");
379 }
380}
381
382static void arrange_container(struct sway_container *con,
383 int width, int height, bool title_bar, int gaps) {
384 // this container might have previously been in the scratchpad,
385 // make sure it's enabled for viewing
386 wlr_scene_node_set_enabled(&con->scene_tree->node, true);
387
388 if (con->view) {
389 int border_top = container_titlebar_height();
390 int border_width = con->current.border_thickness;
391
392 if (title_bar && con->current.border != B_NORMAL) {
393 wlr_scene_node_set_enabled(&con->title_bar.tree->node, false);
394 wlr_scene_node_set_enabled(&con->border.top->node, true);
395 } else {
396 wlr_scene_node_set_enabled(&con->border.top->node, false);
397 }
398
399 if (con->current.border == B_NORMAL) {
400 if (title_bar) {
401 arrange_title_bar(con, 0, 0, width, border_top);
402 } else {
403 border_top = 0;
404 // should be handled by the parent container
405 }
406 } else if (con->current.border == B_PIXEL) {
407 container_update(con);
408 border_top = title_bar && con->current.border_top ? border_width : 0;
409 } else if (con->current.border == B_NONE) {
410 container_update(con);
411 border_top = 0;
412 border_width = 0;
413 } else if (con->current.border == B_CSD) {
414 border_top = 0;
415 border_width = 0;
416 } else {
417 sway_assert(false, "unreachable");
418 }
419
420 int border_bottom = con->current.border_bottom ? border_width : 0;
421 int border_left = con->current.border_left ? border_width : 0;
422 int border_right = con->current.border_right ? border_width : 0;
423
424 wlr_scene_rect_set_size(con->border.top, width, border_top);
425 wlr_scene_rect_set_size(con->border.bottom, width, border_bottom);
426 wlr_scene_rect_set_size(con->border.left,
427 border_left, height - border_top - border_bottom);
428 wlr_scene_rect_set_size(con->border.right,
429 border_right, height - border_top - border_bottom);
430
431 wlr_scene_node_set_position(&con->border.top->node, 0, 0);
432 wlr_scene_node_set_position(&con->border.bottom->node,
433 0, height - border_bottom);
434 wlr_scene_node_set_position(&con->border.left->node,
435 0, border_top);
436 wlr_scene_node_set_position(&con->border.right->node,
437 width - border_right, border_top);
438
439 // make sure to reparent, it's possible that the client just came out of
440 // fullscreen mode where the parent of the surface is not the container
441 wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree);
442 wlr_scene_node_set_position(&con->view->scene_tree->node,
443 border_left, border_top);
444 } else {
445 // make sure to disable the title bar if the parent is not managing it
446 if (title_bar) {
447 wlr_scene_node_set_enabled(&con->title_bar.tree->node, false);
448 }
449
450 arrange_children(con->current.layout, con->current.children,
451 con->current.focused_inactive_child, con->content_tree,
452 width, height, gaps);
453 }
454}
455
456static int container_get_gaps(struct sway_container *con) {
457 struct sway_workspace *ws = con->current.workspace;
458 struct sway_container *temp = con;
459 while (temp) {
460 enum sway_container_layout layout;
461 if (temp->current.parent) {
462 layout = temp->current.parent->current.layout;
463 } else {
464 layout = ws->current.layout;
465 }
466 if (layout == L_TABBED || layout == L_STACKED) {
467 return 0;
468 }
469 temp = temp->pending.parent;
470 }
471 return ws->gaps_inner;
472}
473
474static void arrange_fullscreen(struct wlr_scene_tree *tree,
475 struct sway_container *fs, struct sway_workspace *ws,
476 int width, int height) {
477 struct wlr_scene_node *fs_node;
478 if (fs->view) {
479 fs_node = &fs->view->scene_tree->node;
480
481 // if we only care about the view, disable any decorations
482 wlr_scene_node_set_enabled(&fs->scene_tree->node, false);
483 } else {
484 fs_node = &fs->scene_tree->node;
485 arrange_container(fs, width, height, true, container_get_gaps(fs));
486 }
487
488 wlr_scene_node_reparent(fs_node, tree);
489 wlr_scene_node_lower_to_bottom(fs_node);
490 wlr_scene_node_set_position(fs_node, 0, 0);
491}
492
493static void arrange_workspace_floating(struct sway_workspace *ws) {
494 for (int i = 0; i < ws->current.floating->length; i++) {
495 struct sway_container *floater = ws->current.floating->items[i];
496 struct wlr_scene_tree *layer = root->layers.floating;
497
498 if (floater->current.fullscreen_mode != FULLSCREEN_NONE) {
499 continue;
500 }
501
502 if (root->fullscreen_global) {
503 if (container_is_transient_for(floater, root->fullscreen_global)) {
504 layer = root->layers.fullscreen_global;
505 }
506 } else {
507 for (int i = 0; i < root->outputs->length; i++) {
508 struct sway_output *output = root->outputs->items[i];
509 struct sway_workspace *active = output->current.active_workspace;
510
511 if (active && active->fullscreen &&
512 container_is_transient_for(floater, active->fullscreen)) {
513 layer = root->layers.fullscreen;
514 }
515 }
516 }
517
518 wlr_scene_node_reparent(&floater->scene_tree->node, layer);
519 wlr_scene_node_set_position(&floater->scene_tree->node,
520 floater->current.x, floater->current.y);
521 wlr_scene_node_set_enabled(&floater->scene_tree->node, true);
522
523 arrange_container(floater, floater->current.width, floater->current.height,
524 true, ws->gaps_inner);
525 }
526}
527
528static void arrange_workspace_tiling(struct sway_workspace *ws,
529 int width, int height) {
530 arrange_children(ws->current.layout, ws->current.tiling,
531 ws->current.focused_inactive_child, ws->layers.tiling,
532 width, height, ws->gaps_inner);
533}
534
535static void disable_workspace(struct sway_workspace *ws) {
536 // if any containers were just moved to a disabled workspace it will
537 // have the parent of the old workspace. Move the workspace so that it won't
538 // be shown.
539 for (int i = 0; i < ws->current.tiling->length; i++) {
540 struct sway_container *child = ws->current.tiling->items[i];
541
542 wlr_scene_node_reparent(&child->scene_tree->node, ws->layers.tiling);
543 disable_container(child);
544 }
545
546 for (int i = 0; i < ws->current.floating->length; i++) {
547 struct sway_container *floater = ws->current.floating->items[i];
548 wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating);
549 disable_container(floater);
550 wlr_scene_node_set_enabled(&floater->scene_tree->node, false);
551 }
552}
553
554static void arrange_output(struct sway_output *output, int width, int height) {
555 for (int i = 0; i < output->current.workspaces->length; i++) {
556 struct sway_workspace *child = output->current.workspaces->items[i];
557
558 bool activated = output->current.active_workspace == child;
559
560 wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
561 wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
562
563 for (int i = 0; i < child->current.floating->length; i++) {
564 struct sway_container *floater = child->current.floating->items[i];
565 wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating);
566 wlr_scene_node_set_enabled(&floater->scene_tree->node, activated);
567 }
568
569 if (activated) {
570 struct sway_container *fs = child->current.fullscreen;
571 wlr_scene_node_set_enabled(&child->layers.tiling->node, !fs);
572 wlr_scene_node_set_enabled(&child->layers.fullscreen->node, fs);
573
574 arrange_workspace_floating(child);
575
576 wlr_scene_node_set_enabled(&output->layers.shell_background->node, !fs);
577 wlr_scene_node_set_enabled(&output->layers.shell_bottom->node, !fs);
578 wlr_scene_node_set_enabled(&output->layers.fullscreen->node, fs);
579
580 if (fs) {
581 wlr_scene_rect_set_size(output->fullscreen_background, width, height);
582
583 arrange_fullscreen(child->layers.fullscreen, fs, child,
584 width, height);
585 } else {
586 struct wlr_box *area = &output->usable_area;
587 struct side_gaps *gaps = &child->current_gaps;
588
589 wlr_scene_node_set_position(&child->layers.tiling->node,
590 gaps->left + area->x, gaps->top + area->y);
591
592 arrange_workspace_tiling(child,
593 area->width - gaps->left - gaps->right,
594 area->height - gaps->top - gaps->bottom);
595 }
596 } else {
597 wlr_scene_node_set_enabled(&child->layers.tiling->node, false);
598 wlr_scene_node_set_enabled(&child->layers.fullscreen->node, false);
599
600 disable_workspace(child);
601 }
602 }
603}
604
605static void arrange_popup(struct wlr_scene_tree *popup) {
606 struct wlr_scene_node *node;
607 wl_list_for_each(node, &popup->children, link) {
608 struct sway_xdg_popup *popup = scene_descriptor_try_get(node,
609 SWAY_SCENE_DESC_POPUP);
610
611 // the popup layer may have popups from layer_shell surfaces, in this
612 // case those don't have a scene descriptor, so lets skip those here.
613 if (popup) {
614 struct wlr_scene_tree *tree = popup->view->content_tree;
615
616 int lx, ly;
617 wlr_scene_node_coords(&tree->node, &lx, &ly);
618 wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly);
619 }
620 }
621}
622
623static void arrange_root(struct sway_root *root) {
624 struct sway_container *fs = root->fullscreen_global;
625
626 wlr_scene_node_set_enabled(&root->layers.shell_background->node, !fs);
627 wlr_scene_node_set_enabled(&root->layers.shell_bottom->node, !fs);
628 wlr_scene_node_set_enabled(&root->layers.tiling->node, !fs);
629 wlr_scene_node_set_enabled(&root->layers.floating->node, !fs);
630 wlr_scene_node_set_enabled(&root->layers.shell_top->node, !fs);
631 wlr_scene_node_set_enabled(&root->layers.fullscreen->node, !fs);
632
633 // hide all contents in the scratchpad
634 for (int i = 0; i < root->scratchpad->length; i++) {
635 struct sway_container *con = root->scratchpad->items[i];
636
637 wlr_scene_node_set_enabled(&con->scene_tree->node, false);
638 }
639
640 if (fs) {
641 for (int i = 0; i < root->outputs->length; i++) {
642 struct sway_output *output = root->outputs->items[i];
643 struct sway_workspace *ws = output->current.active_workspace;
644
645 if (ws) {
646 arrange_workspace_floating(ws);
647 }
648 }
649
650 arrange_fullscreen(root->layers.fullscreen_global, fs, NULL,
651 root->width, root->height);
652 } else {
653 for (int i = 0; i < root->outputs->length; i++) {
654 struct sway_output *output = root->outputs->items[i];
655
656 wlr_scene_output_set_position(output->scene_output, output->lx, output->ly);
657
658 wlr_scene_node_reparent(&output->layers.shell_background->node, root->layers.shell_background);
659 wlr_scene_node_reparent(&output->layers.shell_bottom->node, root->layers.shell_bottom);
660 wlr_scene_node_reparent(&output->layers.tiling->node, root->layers.tiling);
661 wlr_scene_node_reparent(&output->layers.shell_top->node, root->layers.shell_top);
662 wlr_scene_node_reparent(&output->layers.shell_overlay->node, root->layers.shell_overlay);
663 wlr_scene_node_reparent(&output->layers.fullscreen->node, root->layers.fullscreen);
664 wlr_scene_node_reparent(&output->layers.session_lock->node, root->layers.session_lock);
665
666 wlr_scene_node_set_position(&output->layers.shell_background->node, output->lx, output->ly);
667 wlr_scene_node_set_position(&output->layers.shell_bottom->node, output->lx, output->ly);
668 wlr_scene_node_set_position(&output->layers.tiling->node, output->lx, output->ly);
669 wlr_scene_node_set_position(&output->layers.fullscreen->node, output->lx, output->ly);
670 wlr_scene_node_set_position(&output->layers.shell_top->node, output->lx, output->ly);
671 wlr_scene_node_set_position(&output->layers.shell_overlay->node, output->lx, output->ly);
672 wlr_scene_node_set_position(&output->layers.session_lock->node, output->lx, output->ly);
673
674 arrange_output(output, output->width, output->height);
675 }
676 }
677
678 arrange_popup(root->layers.popup);
679}
680
255/** 681/**
256 * Apply a transaction to the "current" state of the tree. 682 * Apply a transaction to the "current" state of the tree.
257 */ 683 */
@@ -291,8 +717,6 @@ static void transaction_apply(struct sway_transaction *transaction) {
291 717
292 node->instruction = NULL; 718 node->instruction = NULL;
293 } 719 }
294
295 cursor_rebase_all();
296} 720}
297 721
298static void transaction_commit_pending(void); 722static void transaction_commit_pending(void);
@@ -305,6 +729,8 @@ static void transaction_progress(void) {
305 return; 729 return;
306 } 730 }
307 transaction_apply(server.queued_transaction); 731 transaction_apply(server.queued_transaction);
732 arrange_root(root);
733 cursor_rebase_all();
308 transaction_destroy(server.queued_transaction); 734 transaction_destroy(server.queued_transaction);
309 server.queued_transaction = NULL; 735 server.queued_transaction = NULL;
310 736