summaryrefslogtreecommitdiffstats
path: root/sway/tree/container.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r--sway/tree/container.c336
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
76static 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
89static 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
76struct sway_container *container_create(enum sway_container_type type) { 114struct 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
414struct sway_container *container_at(struct sway_container *parent, 455static 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); 504static 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; 533static 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)) { 558static 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
576struct 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 */
781static 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
661void container_notify_child_title_changed(struct sway_container *container) { 844void 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
866size_t container_titlebar_height() {
867 return config->font_height + TITLEBAR_V_PADDING * 2;
868}