diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-05-19 22:54:50 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-05-21 20:16:56 +1000 |
commit | c08f9bf257c38c92a75988d89fba2d4de6bb2aea (patch) | |
tree | 76ea44c5548301ff4892c44838b783eeeb569c62 /sway/tree/container.c | |
parent | Merge pull request #2011 from RyanDwyer/fix-hide-edge-border-bottom (diff) | |
download | sway-c08f9bf257c38c92a75988d89fba2d4de6bb2aea.tar.gz sway-c08f9bf257c38c92a75988d89fba2d4de6bb2aea.tar.zst sway-c08f9bf257c38c92a75988d89fba2d4de6bb2aea.zip |
Implement tabbed layout
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 267 |
1 files changed, 195 insertions, 72 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index feaf7647..76a21c19 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -452,80 +452,139 @@ struct sway_container *container_parent(struct sway_container *container, | |||
452 | return container; | 452 | return container; |
453 | } | 453 | } |
454 | 454 | ||
455 | struct sway_container *container_at(struct sway_container *parent, | 455 | static struct sway_container *container_at_view(struct sway_container *swayc, |
456 | double lx, double ly, | 456 | double ox, double oy, |
457 | struct wlr_surface **surface, double *sx, double *sy) { | 457 | struct wlr_surface **surface, double *sx, double *sy) { |
458 | list_t *queue = get_bfs_queue(); | 458 | struct sway_view *sview = swayc->sway_view; |
459 | if (!queue) { | 459 | double view_sx = ox - sview->x; |
460 | double view_sy = oy - sview->y; | ||
461 | |||
462 | double _sx, _sy; | ||
463 | struct wlr_surface *_surface = NULL; | ||
464 | switch (sview->type) { | ||
465 | case SWAY_VIEW_XWAYLAND: | ||
466 | _surface = wlr_surface_surface_at(sview->surface, | ||
467 | view_sx, view_sy, &_sx, &_sy); | ||
468 | break; | ||
469 | case SWAY_VIEW_XDG_SHELL_V6: | ||
470 | // the top left corner of the sway container is the | ||
471 | // coordinate of the top left corner of the window geometry | ||
472 | view_sx += sview->wlr_xdg_surface_v6->geometry.x; | ||
473 | view_sy += sview->wlr_xdg_surface_v6->geometry.y; | ||
474 | |||
475 | _surface = wlr_xdg_surface_v6_surface_at( | ||
476 | sview->wlr_xdg_surface_v6, | ||
477 | view_sx, view_sy, &_sx, &_sy); | ||
478 | break; | ||
479 | case SWAY_VIEW_XDG_SHELL: | ||
480 | // the top left corner of the sway container is the | ||
481 | // coordinate of the top left corner of the window geometry | ||
482 | view_sx += sview->wlr_xdg_surface->geometry.x; | ||
483 | view_sy += sview->wlr_xdg_surface->geometry.y; | ||
484 | |||
485 | _surface = wlr_xdg_surface_surface_at( | ||
486 | sview->wlr_xdg_surface, | ||
487 | view_sx, view_sy, &_sx, &_sy); | ||
488 | break; | ||
489 | } | ||
490 | if (_surface) { | ||
491 | *sx = _sx; | ||
492 | *sy = _sy; | ||
493 | *surface = _surface; | ||
494 | } | ||
495 | return swayc; | ||
496 | } | ||
497 | |||
498 | /** | ||
499 | * container_at for a container with layout L_TABBED. | ||
500 | */ | ||
501 | static struct sway_container *container_at_tabbed(struct sway_container *parent, | ||
502 | double ox, double oy, | ||
503 | struct wlr_surface **surface, double *sx, double *sy) { | ||
504 | if (oy < parent->y || oy > parent->y + parent->height) { | ||
460 | return NULL; | 505 | return NULL; |
461 | } | 506 | } |
507 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
462 | 508 | ||
463 | list_add(queue, parent); | 509 | // Tab titles |
510 | int title_height = config->border_thickness * 2 + config->font_height; | ||
511 | if (oy < parent->y + title_height) { | ||
512 | int tab_width = parent->width / parent->children->length; | ||
513 | int child_index = (ox - parent->x) / tab_width; | ||
514 | if (child_index >= parent->children->length) { | ||
515 | child_index = parent->children->length - 1; | ||
516 | } | ||
517 | struct sway_container *child = parent->children->items[child_index]; | ||
518 | return seat_get_focus_inactive(seat, child); | ||
519 | } | ||
464 | 520 | ||
465 | struct sway_container *swayc = NULL; | 521 | // Surfaces |
466 | while (queue->length) { | 522 | struct sway_container *current = seat_get_focus_inactive(seat, parent); |
467 | swayc = queue->items[0]; | 523 | while (current->parent != parent) { |
468 | list_del(queue, 0); | 524 | current = current->parent; |
469 | if (swayc->type == C_VIEW) { | 525 | } |
470 | struct sway_view *sview = swayc->sway_view; | 526 | |
471 | struct sway_container *soutput = container_parent(swayc, C_OUTPUT); | 527 | return container_at(current, ox, oy, surface, sx, sy); |
472 | struct wlr_box *output_box = | 528 | } |
473 | wlr_output_layout_get_box( | 529 | |
474 | root_container.sway_root->output_layout, | 530 | /** |
475 | soutput->sway_output->wlr_output); | 531 | * container_at for a container with layout L_STACKED. |
476 | double ox = lx - output_box->x; | 532 | */ |
477 | double oy = ly - output_box->y; | 533 | static struct sway_container *container_at_stacked( |
478 | double view_sx = ox - sview->x; | 534 | struct sway_container *parent, double ox, double oy, |
479 | double view_sy = oy - sview->y; | 535 | struct wlr_surface **surface, double *sx, double *sy) { |
480 | 536 | // TODO | |
481 | double _sx, _sy; | 537 | return NULL; |
482 | struct wlr_surface *_surface; | 538 | } |
483 | switch (sview->type) { | 539 | |
484 | case SWAY_VIEW_XWAYLAND: | 540 | /** |
485 | _surface = wlr_surface_surface_at(sview->surface, | 541 | * container_at for a container with layout L_HORIZ or L_VERT. |
486 | view_sx, view_sy, &_sx, &_sy); | 542 | */ |
487 | break; | 543 | static struct sway_container *container_at_linear(struct sway_container *parent, |
488 | case SWAY_VIEW_XDG_SHELL_V6: | 544 | double ox, double oy, |
489 | // the top left corner of the sway container is the | 545 | struct wlr_surface **surface, double *sx, double *sy) { |
490 | // coordinate of the top left corner of the window geometry | 546 | for (int i = 0; i < parent->children->length; ++i) { |
491 | view_sx += sview->wlr_xdg_surface_v6->geometry.x; | 547 | struct sway_container *child = parent->children->items[i]; |
492 | view_sy += sview->wlr_xdg_surface_v6->geometry.y; | 548 | struct wlr_box box = { |
493 | 549 | .x = child->x, | |
494 | _surface = wlr_xdg_surface_v6_surface_at( | 550 | .y = child->y, |
495 | sview->wlr_xdg_surface_v6, | 551 | .width = child->width, |
496 | view_sx, view_sy, &_sx, &_sy); | 552 | .height = child->height, |
497 | break; | 553 | }; |
498 | case SWAY_VIEW_XDG_SHELL: | 554 | if (wlr_box_contains_point(&box, ox, oy)) { |
499 | // the top left corner of the sway container is the | 555 | return container_at(child, ox, oy, surface, sx, sy); |
500 | // coordinate of the top left corner of the window geometry | ||
501 | view_sx += sview->wlr_xdg_surface->geometry.x; | ||
502 | view_sy += sview->wlr_xdg_surface->geometry.y; | ||
503 | |||
504 | _surface = wlr_xdg_surface_surface_at( | ||
505 | sview->wlr_xdg_surface, | ||
506 | view_sx, view_sy, &_sx, &_sy); | ||
507 | break; | ||
508 | } | ||
509 | if (_surface) { | ||
510 | *sx = _sx; | ||
511 | *sy = _sy; | ||
512 | *surface = _surface; | ||
513 | return swayc; | ||
514 | } | ||
515 | // Check the view's decorations | ||
516 | struct wlr_box swayc_box = { | ||
517 | .x = swayc->x, | ||
518 | .y = swayc->y, | ||
519 | .width = swayc->width, | ||
520 | .height = swayc->height, | ||
521 | }; | ||
522 | if (wlr_box_contains_point(&swayc_box, ox, oy)) { | ||
523 | return swayc; | ||
524 | } | ||
525 | } else { | ||
526 | list_cat(queue, swayc->children); | ||
527 | } | 556 | } |
528 | } | 557 | } |
558 | return NULL; | ||
559 | } | ||
560 | |||
561 | struct sway_container *container_at(struct sway_container *parent, | ||
562 | double ox, double oy, | ||
563 | struct wlr_surface **surface, double *sx, double *sy) { | ||
564 | if (!sway_assert(parent->type >= C_WORKSPACE, | ||
565 | "Expected workspace or deeper")) { | ||
566 | return NULL; | ||
567 | } | ||
568 | if (parent->type == C_VIEW) { | ||
569 | return container_at_view(parent, ox, oy, surface, sx, sy); | ||
570 | } | ||
571 | if (!parent->children->length) { | ||
572 | return NULL; | ||
573 | } | ||
574 | |||
575 | switch (parent->layout) { | ||
576 | case L_HORIZ: | ||
577 | case L_VERT: | ||
578 | return container_at_linear(parent, ox, oy, surface, sx, sy); | ||
579 | case L_TABBED: | ||
580 | return container_at_tabbed(parent, ox, oy, surface, sx, sy); | ||
581 | case L_STACKED: | ||
582 | return container_at_stacked(parent, ox, oy, surface, sx, sy); | ||
583 | case L_FLOATING: | ||
584 | return NULL; // TODO | ||
585 | case L_NONE: | ||
586 | return NULL; | ||
587 | } | ||
529 | 588 | ||
530 | return NULL; | 589 | return NULL; |
531 | } | 590 | } |
@@ -699,18 +758,82 @@ void container_calculate_title_height(struct sway_container *container) { | |||
699 | container->title_height = height; | 758 | container->title_height = height; |
700 | } | 759 | } |
701 | 760 | ||
761 | /** | ||
762 | * Calculate and return the length of the concatenated child titles. | ||
763 | * An example concatenated title is: V[Terminal, Firefox] | ||
764 | * If buffer is not NULL, also populate the buffer with the concatenated title. | ||
765 | */ | ||
766 | static size_t concatenate_child_titles(struct sway_container *parent, | ||
767 | char *buffer) { | ||
768 | size_t len = 2; // V[ | ||
769 | if (buffer) { | ||
770 | switch (parent->layout) { | ||
771 | case L_VERT: | ||
772 | strcpy(buffer, "V["); | ||
773 | break; | ||
774 | case L_HORIZ: | ||
775 | strcpy(buffer, "H["); | ||
776 | break; | ||
777 | case L_TABBED: | ||
778 | strcpy(buffer, "T["); | ||
779 | break; | ||
780 | case L_STACKED: | ||
781 | strcpy(buffer, "S["); | ||
782 | break; | ||
783 | case L_FLOATING: | ||
784 | strcpy(buffer, "F["); | ||
785 | break; | ||
786 | case L_NONE: | ||
787 | strcpy(buffer, "?["); | ||
788 | break; | ||
789 | } | ||
790 | } | ||
791 | |||
792 | for (int i = 0; i < parent->children->length; ++i) { | ||
793 | if (i != 0) { | ||
794 | len += 2; | ||
795 | if (buffer) { | ||
796 | strcat(buffer, ", "); | ||
797 | } | ||
798 | } | ||
799 | struct sway_container *child = parent->children->items[i]; | ||
800 | if (child->name) { | ||
801 | len += strlen(child->name); | ||
802 | if (buffer) { | ||
803 | strcat(buffer, child->name); | ||
804 | } | ||
805 | } else { | ||
806 | len += 6; | ||
807 | if (buffer) { | ||
808 | strcat(buffer, "(null)"); | ||
809 | } | ||
810 | } | ||
811 | } | ||
812 | |||
813 | len += 1; | ||
814 | if (buffer) { | ||
815 | strcat(buffer, "]"); | ||
816 | } | ||
817 | return len; | ||
818 | } | ||
819 | |||
702 | void container_notify_child_title_changed(struct sway_container *container) { | 820 | void container_notify_child_title_changed(struct sway_container *container) { |
703 | if (!container || container->type != C_CONTAINER) { | 821 | if (!container || container->type != C_CONTAINER) { |
704 | return; | 822 | return; |
705 | } | 823 | } |
706 | if (container->layout != L_TABBED && container->layout != L_STACKED) { | ||
707 | return; | ||
708 | } | ||
709 | if (container->formatted_title) { | 824 | if (container->formatted_title) { |
710 | free(container->formatted_title); | 825 | free(container->formatted_title); |
711 | } | 826 | } |
712 | // TODO: iterate children and concatenate their titles | 827 | |
713 | container->formatted_title = strdup(""); | 828 | size_t len = concatenate_child_titles(container, NULL); |
829 | char *buffer = calloc(len + 1, sizeof(char)); | ||
830 | if (!sway_assert(buffer, "Unable to allocate title string")) { | ||
831 | return; | ||
832 | } | ||
833 | concatenate_child_titles(container, buffer); | ||
834 | |||
835 | container->name = buffer; | ||
836 | container->formatted_title = buffer; | ||
714 | container_calculate_title_height(container); | 837 | container_calculate_title_height(container); |
715 | container_update_title_textures(container); | 838 | container_update_title_textures(container); |
716 | container_notify_child_title_changed(container->parent); | 839 | container_notify_child_title_changed(container->parent); |