diff options
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 336 |
1 files changed, 264 insertions, 72 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index e47338e7..9cf18f61 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -73,6 +73,44 @@ static void container_close_notify(struct sway_container *container) { | |||
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
76 | static void container_update_textures_recursive(struct sway_container *con) { | ||
77 | container_update_title_textures(con); | ||
78 | |||
79 | if (con->type == C_VIEW) { | ||
80 | view_update_marks_textures(con->sway_view); | ||
81 | } else { | ||
82 | for (int i = 0; i < con->children->length; ++i) { | ||
83 | struct sway_container *child = con->children->items[i]; | ||
84 | container_update_textures_recursive(child); | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static void handle_reparent(struct wl_listener *listener, | ||
90 | void *data) { | ||
91 | struct sway_container *container = | ||
92 | wl_container_of(listener, container, reparent); | ||
93 | struct sway_container *old_parent = data; | ||
94 | |||
95 | struct sway_container *old_output = old_parent; | ||
96 | if (old_output != NULL && old_output->type != C_OUTPUT) { | ||
97 | old_output = container_parent(old_output, C_OUTPUT); | ||
98 | } | ||
99 | |||
100 | struct sway_container *new_output = container->parent; | ||
101 | if (new_output != NULL && new_output->type != C_OUTPUT) { | ||
102 | new_output = container_parent(new_output, C_OUTPUT); | ||
103 | } | ||
104 | |||
105 | if (old_output && new_output) { | ||
106 | float old_scale = old_output->sway_output->wlr_output->scale; | ||
107 | float new_scale = new_output->sway_output->wlr_output->scale; | ||
108 | if (old_scale != new_scale) { | ||
109 | container_update_textures_recursive(container); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
76 | struct sway_container *container_create(enum sway_container_type type) { | 114 | struct sway_container *container_create(enum sway_container_type type) { |
77 | // next id starts at 1 because 0 is assigned to root_container in layout.c | 115 | // next id starts at 1 because 0 is assigned to root_container in layout.c |
78 | static size_t next_id = 1; | 116 | static size_t next_id = 1; |
@@ -92,6 +130,9 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
92 | wl_signal_init(&c->events.destroy); | 130 | wl_signal_init(&c->events.destroy); |
93 | wl_signal_init(&c->events.reparent); | 131 | wl_signal_init(&c->events.reparent); |
94 | 132 | ||
133 | wl_signal_add(&c->events.reparent, &c->reparent); | ||
134 | c->reparent.notify = handle_reparent; | ||
135 | |||
95 | return c; | 136 | return c; |
96 | } | 137 | } |
97 | 138 | ||
@@ -411,80 +452,154 @@ struct sway_container *container_parent(struct sway_container *container, | |||
411 | return container; | 452 | return container; |
412 | } | 453 | } |
413 | 454 | ||
414 | struct sway_container *container_at(struct sway_container *parent, | 455 | static struct sway_container *container_at_view(struct sway_container *swayc, |
415 | double lx, double ly, | 456 | double ox, double oy, |
416 | struct wlr_surface **surface, double *sx, double *sy) { | 457 | struct wlr_surface **surface, double *sx, double *sy) { |
417 | list_t *queue = get_bfs_queue(); | 458 | if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { |
418 | if (!queue) { | ||
419 | return NULL; | 459 | return NULL; |
420 | } | 460 | } |
461 | struct sway_view *sview = swayc->sway_view; | ||
462 | double view_sx = ox - sview->x; | ||
463 | double view_sy = oy - sview->y; | ||
421 | 464 | ||
422 | list_add(queue, parent); | 465 | double _sx, _sy; |
466 | struct wlr_surface *_surface = NULL; | ||
467 | switch (sview->type) { | ||
468 | case SWAY_VIEW_XWAYLAND: | ||
469 | _surface = wlr_surface_surface_at(sview->surface, | ||
470 | view_sx, view_sy, &_sx, &_sy); | ||
471 | break; | ||
472 | case SWAY_VIEW_XDG_SHELL_V6: | ||
473 | // the top left corner of the sway container is the | ||
474 | // coordinate of the top left corner of the window geometry | ||
475 | view_sx += sview->wlr_xdg_surface_v6->geometry.x; | ||
476 | view_sy += sview->wlr_xdg_surface_v6->geometry.y; | ||
477 | |||
478 | _surface = wlr_xdg_surface_v6_surface_at( | ||
479 | sview->wlr_xdg_surface_v6, | ||
480 | view_sx, view_sy, &_sx, &_sy); | ||
481 | break; | ||
482 | case SWAY_VIEW_XDG_SHELL: | ||
483 | // the top left corner of the sway container is the | ||
484 | // coordinate of the top left corner of the window geometry | ||
485 | view_sx += sview->wlr_xdg_surface->geometry.x; | ||
486 | view_sy += sview->wlr_xdg_surface->geometry.y; | ||
487 | |||
488 | _surface = wlr_xdg_surface_surface_at( | ||
489 | sview->wlr_xdg_surface, | ||
490 | view_sx, view_sy, &_sx, &_sy); | ||
491 | break; | ||
492 | } | ||
493 | if (_surface) { | ||
494 | *sx = _sx; | ||
495 | *sy = _sy; | ||
496 | *surface = _surface; | ||
497 | } | ||
498 | return swayc; | ||
499 | } | ||
423 | 500 | ||
424 | struct sway_container *swayc = NULL; | 501 | /** |
425 | while (queue->length) { | 502 | * container_at for a container with layout L_TABBED. |
426 | swayc = queue->items[0]; | 503 | */ |
427 | list_del(queue, 0); | 504 | static struct sway_container *container_at_tabbed(struct sway_container *parent, |
428 | if (swayc->type == C_VIEW) { | 505 | double ox, double oy, |
429 | struct sway_view *sview = swayc->sway_view; | 506 | struct wlr_surface **surface, double *sx, double *sy) { |
430 | struct sway_container *soutput = container_parent(swayc, C_OUTPUT); | 507 | if (oy < parent->y || oy > parent->y + parent->height) { |
431 | struct wlr_box *output_box = | 508 | return NULL; |
432 | wlr_output_layout_get_box( | 509 | } |
433 | root_container.sway_root->output_layout, | 510 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
434 | soutput->sway_output->wlr_output); | 511 | |
435 | double ox = lx - output_box->x; | 512 | // Tab titles |
436 | double oy = ly - output_box->y; | 513 | int title_height = container_titlebar_height(); |
437 | double view_sx = ox - sview->x; | 514 | if (oy < parent->y + title_height) { |
438 | double view_sy = oy - sview->y; | 515 | int tab_width = parent->width / parent->children->length; |
439 | 516 | int child_index = (ox - parent->x) / tab_width; | |
440 | double _sx, _sy; | 517 | if (child_index >= parent->children->length) { |
441 | struct wlr_surface *_surface; | 518 | child_index = parent->children->length - 1; |
442 | switch (sview->type) { | 519 | } |
443 | case SWAY_VIEW_XWAYLAND: | 520 | struct sway_container *child = parent->children->items[child_index]; |
444 | _surface = wlr_surface_surface_at(sview->surface, | 521 | return seat_get_focus_inactive(seat, child); |
445 | view_sx, view_sy, &_sx, &_sy); | 522 | } |
446 | break; | 523 | |
447 | case SWAY_VIEW_XDG_SHELL_V6: | 524 | // Surfaces |
448 | // the top left corner of the sway container is the | 525 | struct sway_container *current = seat_get_active_child(seat, parent); |
449 | // coordinate of the top left corner of the window geometry | 526 | |
450 | view_sx += sview->wlr_xdg_surface_v6->geometry.x; | 527 | return container_at(current, ox, oy, surface, sx, sy); |
451 | view_sy += sview->wlr_xdg_surface_v6->geometry.y; | 528 | } |
452 | 529 | ||
453 | _surface = wlr_xdg_surface_v6_surface_at( | 530 | /** |
454 | sview->wlr_xdg_surface_v6, | 531 | * container_at for a container with layout L_STACKED. |
455 | view_sx, view_sy, &_sx, &_sy); | 532 | */ |
456 | break; | 533 | static struct sway_container *container_at_stacked( |
457 | case SWAY_VIEW_XDG_SHELL: | 534 | struct sway_container *parent, double ox, double oy, |
458 | // the top left corner of the sway container is the | 535 | struct wlr_surface **surface, double *sx, double *sy) { |
459 | // coordinate of the top left corner of the window geometry | 536 | if (oy < parent->y || oy > parent->y + parent->height) { |
460 | view_sx += sview->wlr_xdg_surface->geometry.x; | 537 | return NULL; |
461 | view_sy += sview->wlr_xdg_surface->geometry.y; | 538 | } |
462 | 539 | struct sway_seat *seat = input_manager_current_seat(input_manager); | |
463 | _surface = wlr_xdg_surface_surface_at( | 540 | |
464 | sview->wlr_xdg_surface, | 541 | // Title bars |
465 | view_sx, view_sy, &_sx, &_sy); | 542 | int title_height = container_titlebar_height(); |
466 | break; | 543 | int child_index = (oy - parent->y) / title_height; |
467 | } | 544 | if (child_index < parent->children->length) { |
468 | if (_surface) { | 545 | struct sway_container *child = parent->children->items[child_index]; |
469 | *sx = _sx; | 546 | return seat_get_focus_inactive(seat, child); |
470 | *sy = _sy; | 547 | } |
471 | *surface = _surface; | 548 | |
472 | return swayc; | 549 | // Surfaces |
473 | } | 550 | struct sway_container *current = seat_get_active_child(seat, parent); |
474 | // Check the view's decorations | 551 | |
475 | struct wlr_box swayc_box = { | 552 | return container_at(current, ox, oy, surface, sx, sy); |
476 | .x = swayc->x, | 553 | } |
477 | .y = swayc->y, | 554 | |
478 | .width = swayc->width, | 555 | /** |
479 | .height = swayc->height, | 556 | * container_at for a container with layout L_HORIZ or L_VERT. |
480 | }; | 557 | */ |
481 | if (wlr_box_contains_point(&swayc_box, ox, oy)) { | 558 | static struct sway_container *container_at_linear(struct sway_container *parent, |
482 | return swayc; | 559 | double ox, double oy, |
483 | } | 560 | struct wlr_surface **surface, double *sx, double *sy) { |
484 | } else { | 561 | for (int i = 0; i < parent->children->length; ++i) { |
485 | list_cat(queue, swayc->children); | 562 | struct sway_container *child = parent->children->items[i]; |
563 | struct wlr_box box = { | ||
564 | .x = child->x, | ||
565 | .y = child->y, | ||
566 | .width = child->width, | ||
567 | .height = child->height, | ||
568 | }; | ||
569 | if (wlr_box_contains_point(&box, ox, oy)) { | ||
570 | return container_at(child, ox, oy, surface, sx, sy); | ||
486 | } | 571 | } |
487 | } | 572 | } |
573 | return NULL; | ||
574 | } | ||
575 | |||
576 | struct sway_container *container_at(struct sway_container *parent, | ||
577 | double ox, double oy, | ||
578 | struct wlr_surface **surface, double *sx, double *sy) { | ||
579 | if (!sway_assert(parent->type >= C_WORKSPACE, | ||
580 | "Expected workspace or deeper")) { | ||
581 | return NULL; | ||
582 | } | ||
583 | if (parent->type == C_VIEW) { | ||
584 | return container_at_view(parent, ox, oy, surface, sx, sy); | ||
585 | } | ||
586 | if (!parent->children->length) { | ||
587 | return NULL; | ||
588 | } | ||
589 | |||
590 | switch (parent->layout) { | ||
591 | case L_HORIZ: | ||
592 | case L_VERT: | ||
593 | return container_at_linear(parent, ox, oy, surface, sx, sy); | ||
594 | case L_TABBED: | ||
595 | return container_at_tabbed(parent, ox, oy, surface, sx, sy); | ||
596 | case L_STACKED: | ||
597 | return container_at_stacked(parent, ox, oy, surface, sx, sy); | ||
598 | case L_FLOATING: | ||
599 | return NULL; // TODO | ||
600 | case L_NONE: | ||
601 | return NULL; | ||
602 | } | ||
488 | 603 | ||
489 | return NULL; | 604 | return NULL; |
490 | } | 605 | } |
@@ -658,19 +773,96 @@ void container_calculate_title_height(struct sway_container *container) { | |||
658 | container->title_height = height; | 773 | container->title_height = height; |
659 | } | 774 | } |
660 | 775 | ||
776 | /** | ||
777 | * Calculate and return the length of the concatenated child titles. | ||
778 | * An example concatenated title is: V[Terminal, Firefox] | ||
779 | * If buffer is not NULL, also populate the buffer with the concatenated title. | ||
780 | */ | ||
781 | static size_t concatenate_child_titles(struct sway_container *parent, | ||
782 | char *buffer) { | ||
783 | size_t len = 2; // V[ | ||
784 | if (buffer) { | ||
785 | switch (parent->layout) { | ||
786 | case L_VERT: | ||
787 | strcpy(buffer, "V["); | ||
788 | break; | ||
789 | case L_HORIZ: | ||
790 | strcpy(buffer, "H["); | ||
791 | break; | ||
792 | case L_TABBED: | ||
793 | strcpy(buffer, "T["); | ||
794 | break; | ||
795 | case L_STACKED: | ||
796 | strcpy(buffer, "S["); | ||
797 | break; | ||
798 | case L_FLOATING: | ||
799 | strcpy(buffer, "F["); | ||
800 | break; | ||
801 | case L_NONE: | ||
802 | strcpy(buffer, "D["); | ||
803 | break; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | for (int i = 0; i < parent->children->length; ++i) { | ||
808 | if (i != 0) { | ||
809 | len += 1; | ||
810 | if (buffer) { | ||
811 | strcat(buffer, " "); | ||
812 | } | ||
813 | } | ||
814 | struct sway_container *child = parent->children->items[i]; | ||
815 | const char *identifier = NULL; | ||
816 | if (child->type == C_VIEW) { | ||
817 | identifier = view_get_class(child->sway_view); | ||
818 | if (!identifier) { | ||
819 | identifier = view_get_app_id(child->sway_view); | ||
820 | } | ||
821 | } else { | ||
822 | identifier = child->name; | ||
823 | } | ||
824 | if (identifier) { | ||
825 | len += strlen(identifier); | ||
826 | if (buffer) { | ||
827 | strcat(buffer, identifier); | ||
828 | } | ||
829 | } else { | ||
830 | len += 6; | ||
831 | if (buffer) { | ||
832 | strcat(buffer, "(null)"); | ||
833 | } | ||
834 | } | ||
835 | } | ||
836 | |||
837 | len += 1; | ||
838 | if (buffer) { | ||
839 | strcat(buffer, "]"); | ||
840 | } | ||
841 | return len; | ||
842 | } | ||
843 | |||
661 | void container_notify_child_title_changed(struct sway_container *container) { | 844 | void container_notify_child_title_changed(struct sway_container *container) { |
662 | if (!container || container->type != C_CONTAINER) { | 845 | if (!container || container->type != C_CONTAINER) { |
663 | return; | 846 | return; |
664 | } | 847 | } |
665 | if (container->layout != L_TABBED && container->layout != L_STACKED) { | ||
666 | return; | ||
667 | } | ||
668 | if (container->formatted_title) { | 848 | if (container->formatted_title) { |
669 | free(container->formatted_title); | 849 | free(container->formatted_title); |
670 | } | 850 | } |
671 | // TODO: iterate children and concatenate their titles | 851 | |
672 | container->formatted_title = strdup(""); | 852 | size_t len = concatenate_child_titles(container, NULL); |
853 | char *buffer = calloc(len + 1, sizeof(char)); | ||
854 | if (!sway_assert(buffer, "Unable to allocate title string")) { | ||
855 | return; | ||
856 | } | ||
857 | concatenate_child_titles(container, buffer); | ||
858 | |||
859 | container->name = buffer; | ||
860 | container->formatted_title = buffer; | ||
673 | container_calculate_title_height(container); | 861 | container_calculate_title_height(container); |
674 | container_update_title_textures(container); | 862 | container_update_title_textures(container); |
675 | container_notify_child_title_changed(container->parent); | 863 | container_notify_child_title_changed(container->parent); |
676 | } | 864 | } |
865 | |||
866 | size_t container_titlebar_height() { | ||
867 | return config->font_height + TITLEBAR_V_PADDING * 2; | ||
868 | } | ||