aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/output.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-05-21 22:58:46 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-05-22 08:27:24 +1000
commit664169fbf1c4e07f17a48b2b801dad9cea31ea4c (patch)
treee20b1f39a89abd5a6567f7e9d398f002e9ee5bee /sway/desktop/output.c
parentFix focus follows mouse with no focus (diff)
downloadsway-664169fbf1c4e07f17a48b2b801dad9cea31ea4c.tar.gz
sway-664169fbf1c4e07f17a48b2b801dad9cea31ea4c.tar.zst
sway-664169fbf1c4e07f17a48b2b801dad9cea31ea4c.zip
Implement stacked layout
Diffstat (limited to 'sway/desktop/output.c')
-rw-r--r--sway/desktop/output.c596
1 files changed, 268 insertions, 328 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 551e96fc..3b501a63 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -269,17 +269,6 @@ static void render_unmanaged(struct sway_output *output,
269 render_surface_iterator, &data); 269 render_surface_iterator, &data);
270} 270}
271 271
272static void render_view(struct sway_view *view, struct sway_output *output,
273 pixman_region32_t *damage) {
274 struct render_data data = {
275 .output = output,
276 .damage = damage,
277 .alpha = view->swayc->alpha,
278 };
279 output_view_for_each_surface(
280 view, &data.root_geo, render_surface_iterator, &data);
281}
282
283static void render_rect(struct wlr_output *wlr_output, 272static void render_rect(struct wlr_output *wlr_output,
284 pixman_region32_t *output_damage, const struct wlr_box *_box, 273 pixman_region32_t *output_damage, const struct wlr_box *_box,
285 float color[static 4]) { 274 float color[static 4]) {
@@ -317,108 +306,159 @@ static void premultiply_alpha(float color[4], float opacity) {
317 color[2] *= color[3]; 306 color[2] *= color[3];
318} 307}
319 308
309static void render_view_surfaces(struct sway_view *view,
310 struct sway_output *output, pixman_region32_t *damage) {
311 struct render_data data = {
312 .output = output,
313 .damage = damage,
314 .alpha = view->swayc->alpha,
315 };
316 output_view_for_each_surface(
317 view, &data.root_geo, render_surface_iterator, &data);
318}
319
320/** 320/**
321 * Render decorations for a view with "border normal". 321 * Render a view's surface and left/bottom/right borders.
322 *
323 * Care must be taken not to render over the same pixel multiple times,
324 * otherwise the colors will be incorrect when using opacity.
325 */ 322 */
326static void render_container_simple_border_normal(struct sway_output *output, 323static void render_view(struct sway_output *output, pixman_region32_t *damage,
327 pixman_region32_t *output_damage, 324 struct sway_container *con, struct border_colors *colors) {
328 struct sway_container *con, struct border_colors *colors,
329 struct wlr_texture *title_texture, struct wlr_texture *marks_texture) {
330 struct wlr_box box;
331 float color[4];
332 struct sway_view *view = con->sway_view; 325 struct sway_view *view = con->sway_view;
333 float output_scale = output->wlr_output->scale; 326 render_view_surfaces(view, output, damage);
334 327
335 if (view->border_left) { 328 struct wlr_box box;
336 // Child border - left edge 329 float output_scale = output->wlr_output->scale;
337 memcpy(&color, colors->child_border, sizeof(float) * 4); 330 float color[4];
338 premultiply_alpha(color, con->alpha);
339 box.x = con->x;
340 box.y = con->y + 1;
341 box.width = view->border_thickness;
342 box.height = con->height - 1
343 - view->border_thickness * view->border_bottom;
344 scale_box(&box, output_scale);
345 render_rect(output->wlr_output, output_damage, &box, color);
346 }
347 331
348 if (view->border_right) { 332 if (view->border != B_NONE) {
349 // Child border - right edge 333 if (view->border_left) {
350 if (con->parent->children->length == 1
351 && con->parent->layout == L_HORIZ) {
352 memcpy(&color, colors->indicator, sizeof(float) * 4);
353 } else {
354 memcpy(&color, colors->child_border, sizeof(float) * 4); 334 memcpy(&color, colors->child_border, sizeof(float) * 4);
335 premultiply_alpha(color, con->alpha);
336 box.x = con->x;
337 box.y = view->y;
338 box.width = view->border_thickness;
339 box.height = view->height;
340 scale_box(&box, output_scale);
341 render_rect(output->wlr_output, damage, &box, color);
355 } 342 }
356 premultiply_alpha(color, con->alpha);
357 box.x = con->x + con->width - view->border_thickness;
358 box.y = con->y + 1;
359 box.width = view->border_thickness;
360 box.height = con->height - 1
361 - view->border_thickness * view->border_bottom;
362 scale_box(&box, output_scale);
363 render_rect(output->wlr_output, output_damage, &box, color);
364 }
365 343
366 if (view->border_bottom) { 344 if (view->border_right) {
367 // Child border - bottom edge 345 if (con->parent->children->length == 1
368 if (con->parent->children->length == 1 346 && con->parent->layout == L_HORIZ) {
369 && con->parent->layout == L_VERT) { 347 memcpy(&color, colors->indicator, sizeof(float) * 4);
370 memcpy(&color, colors->indicator, sizeof(float) * 4); 348 } else {
371 } else { 349 memcpy(&color, colors->child_border, sizeof(float) * 4);
372 memcpy(&color, colors->child_border, sizeof(float) * 4); 350 }
351 premultiply_alpha(color, con->alpha);
352 box.x = view->x + view->width;
353 box.y = view->y;
354 box.width = view->border_thickness;
355 box.height = view->height;
356 scale_box(&box, output_scale);
357 render_rect(output->wlr_output, damage, &box, color);
358 }
359
360 if (view->border_bottom) {
361 if (con->parent->children->length == 1
362 && con->parent->layout == L_VERT) {
363 memcpy(&color, colors->indicator, sizeof(float) * 4);
364 } else {
365 memcpy(&color, colors->child_border, sizeof(float) * 4);
366 }
367 premultiply_alpha(color, con->alpha);
368 box.x = con->x;
369 box.y = view->y + view->height;
370 box.width = con->width;
371 box.height = view->border_thickness;
372 scale_box(&box, output_scale);
373 render_rect(output->wlr_output, damage, &box, color);
373 } 374 }
374 premultiply_alpha(color, con->alpha);
375 box.x = con->x;
376 box.y = con->y + con->height - view->border_thickness;
377 box.width = con->width;
378 box.height = view->border_thickness;
379 scale_box(&box, output_scale);
380 render_rect(output->wlr_output, output_damage, &box, color);
381 } 375 }
376}
377
378/**
379 * Render a titlebar.
380 *
381 * Care must be taken not to render over the same pixel multiple times,
382 * otherwise the colors will be incorrect when using opacity.
383 *
384 * The height is: 1px border, 3px padding, font height, 3px padding, 1px border
385 * The left side for L_TABBED is: 1px border, 2px padding, title
386 * The left side for other layouts is: 3px padding, title
387 */
388static void render_titlebar(struct sway_output *output,
389 pixman_region32_t *output_damage, struct sway_container *con,
390 int x, int y, int width,
391 struct border_colors *colors, struct wlr_texture *title_texture,
392 struct wlr_texture *marks_texture) {
393 struct wlr_box box;
394 float color[4];
395 struct sway_view *view = con->type == C_VIEW ? con->sway_view : NULL;
396 float output_scale = output->wlr_output->scale;
397 enum sway_container_layout layout = con->parent->layout;
398 bool is_last_child =
399 con->parent->children->items[con->parent->children->length - 1] == con;
382 400
383 // Single pixel bar above title 401 // Single pixel bar above title
384 memcpy(&color, colors->border, sizeof(float) * 4); 402 memcpy(&color, colors->border, sizeof(float) * 4);
385 premultiply_alpha(color, con->alpha); 403 premultiply_alpha(color, con->alpha);
386 box.x = con->x; 404 box.x = x;
387 box.y = con->y; 405 box.y = y;
388 box.width = con->width; 406 box.width = width;
389 box.height = 1; 407 box.height = 1;
390 scale_box(&box, output_scale); 408 scale_box(&box, output_scale);
391 render_rect(output->wlr_output, output_damage, &box, color); 409 render_rect(output->wlr_output, output_damage, &box, color);
392 410
393 // Setting these makes marks and title easier
394 size_t inner_x = con->x + view->border_thickness * view->border_left;
395 size_t inner_width = con->width - view->border_thickness * view->border_left
396 - view->border_thickness * view->border_right;
397
398 // Single pixel bar below title 411 // Single pixel bar below title
399 memcpy(&color, colors->border, sizeof(float) * 4); 412 size_t left_offset = 0, right_offset = 0;
400 premultiply_alpha(color, con->alpha); 413 bool connects_sides = false;
401 box.x = inner_x; 414 if (layout == L_HORIZ || layout == L_VERT ||
402 box.y = view->y - 1; 415 (layout == L_STACKED && is_last_child)) {
403 box.width = inner_width; 416 if (view) {
417 left_offset = view->border_left * view->border_thickness;
418 right_offset = view->border_right * view->border_thickness;
419 connects_sides = true;
420 }
421 }
422 box.x = x + left_offset;
423 box.y = y + config->font_height + 7;
424 box.width = width - left_offset - right_offset;
404 box.height = 1; 425 box.height = 1;
405 scale_box(&box, output_scale); 426 scale_box(&box, output_scale);
406 render_rect(output->wlr_output, output_damage, &box, color); 427 render_rect(output->wlr_output, output_damage, &box, color);
407 428
429 if (layout == L_TABBED) {
430 // Single pixel left edge
431 box.x = x;
432 box.y = y + 1;
433 box.width = 1;
434 box.height = config->font_height + 6;
435 scale_box(&box, output_scale);
436 render_rect(output->wlr_output, output_damage, &box, color);
437
438 // Single pixel right edge
439 box.x = (x + width - 1) * output_scale;
440 render_rect(output->wlr_output, output_damage, &box, color);
441 }
442
443 size_t inner_width = width - 6;
444
408 // Marks 445 // Marks
409 size_t marks_width = 0; 446 size_t marks_width = 0;
410 if (config->show_marks && marks_texture) { 447 if (config->show_marks && marks_texture) {
411 struct wlr_box texture_box; 448 struct wlr_box texture_box;
412 wlr_texture_get_size(marks_texture, 449 wlr_texture_get_size(marks_texture,
413 &texture_box.width, &texture_box.height); 450 &texture_box.width, &texture_box.height);
414 texture_box.x = (inner_x + inner_width) * output_scale - texture_box.width; 451 texture_box.x = (x + width - 3) * output_scale - texture_box.width;
415 texture_box.y = (con->y + view->border_thickness) * output_scale; 452 texture_box.y = (y + 4) * output_scale;
416 453
417 float matrix[9]; 454 float matrix[9];
418 wlr_matrix_project_box(matrix, &texture_box, 455 wlr_matrix_project_box(matrix, &texture_box,
419 WL_OUTPUT_TRANSFORM_NORMAL, 456 WL_OUTPUT_TRANSFORM_NORMAL,
420 0.0, output->wlr_output->transform_matrix); 457 0.0, output->wlr_output->transform_matrix);
421 458
459 if (inner_width * output_scale < texture_box.width) {
460 texture_box.width = inner_width * output_scale;
461 }
422 render_texture(output->wlr_output, output_damage, marks_texture, 462 render_texture(output->wlr_output, output_damage, marks_texture,
423 &texture_box, matrix, con->alpha); 463 &texture_box, matrix, con->alpha);
424 marks_width = texture_box.width; 464 marks_width = texture_box.width;
@@ -430,8 +470,8 @@ static void render_container_simple_border_normal(struct sway_output *output,
430 struct wlr_box texture_box; 470 struct wlr_box texture_box;
431 wlr_texture_get_size(title_texture, 471 wlr_texture_get_size(title_texture,
432 &texture_box.width, &texture_box.height); 472 &texture_box.width, &texture_box.height);
433 texture_box.x = inner_x * output_scale; 473 texture_box.x = (x + 3) * output_scale;
434 texture_box.y = (con->y + view->border_thickness) * output_scale; 474 texture_box.y = (y + 4) * output_scale;
435 475
436 float matrix[9]; 476 float matrix[9];
437 wlr_matrix_project_box(matrix, &texture_box, 477 wlr_matrix_project_box(matrix, &texture_box,
@@ -446,104 +486,89 @@ static void render_container_simple_border_normal(struct sway_output *output,
446 title_width = texture_box.width; 486 title_width = texture_box.width;
447 } 487 }
448 488
449 // Title background - above the text 489 // Padding above title
450 memcpy(&color, colors->background, sizeof(float) * 4); 490 memcpy(&color, colors->background, sizeof(float) * 4);
451 premultiply_alpha(color, con->alpha); 491 premultiply_alpha(color, con->alpha);
452 box.x = inner_x; 492 box.x = x + (layout == L_TABBED);
453 box.y = con->y + 1; 493 box.y = y + 1;
454 box.width = inner_width; 494 box.width = width - (layout == L_TABBED) * 2;
455 box.height = view->border_thickness - 1; 495 box.height = 3;
456 scale_box(&box, output_scale); 496 scale_box(&box, output_scale);
457 render_rect(output->wlr_output, output_damage, &box, color); 497 render_rect(output->wlr_output, output_damage, &box, color);
458 498
459 // Title background - below the text 499 // Padding below title
460 box.y = (con->y + view->border_thickness + config->font_height) 500 box.y = (y + 4 + config->font_height) * output_scale;
461 * output_scale;
462 render_rect(output->wlr_output, output_damage, &box, color); 501 render_rect(output->wlr_output, output_damage, &box, color);
463 502
464 // Title background - filler between title and marks 503 // Filler between title and marks
465 box.width = inner_width * output_scale - title_width - marks_width; 504 box.width = inner_width * output_scale - title_width - marks_width;
466 if (box.width > 0) { 505 if (box.width > 0) {
467 box.x = inner_x * output_scale + title_width; 506 box.x = (x + 3) * output_scale + title_width;
468 box.y = (con->y + view->border_thickness) * output_scale; 507 box.y = (y + 4) * output_scale;
469 box.height = config->font_height * output_scale; 508 box.height = config->font_height * output_scale;
470 render_rect(output->wlr_output, output_damage, &box, color); 509 render_rect(output->wlr_output, output_damage, &box, color);
471 } 510 }
472}
473 511
474/** 512 // Padding left of title
475 * Render decorations for a view with "border pixel". 513 left_offset = layout == L_TABBED ? 1 : 0;
476 * 514 box.x = x + left_offset;
477 * Care must be taken not to render over the same pixel multiple times, 515 box.y = y + 4;
478 * otherwise the colors will be incorrect when using opacity. 516 box.width = 3 - left_offset;
479 */ 517 box.height = config->font_height;
480static void render_container_simple_border_pixel(struct sway_output *output, 518 scale_box(&box, output_scale);
481 pixman_region32_t *output_damage, struct sway_container *con, 519 render_rect(output->wlr_output, output_damage, &box, color);
482 struct border_colors *colors) {
483 struct wlr_box box;
484 float color[4];
485 struct sway_view *view = con->sway_view;
486 float output_scale = output->wlr_output->scale;
487 520
488 if (view->border_left) { 521 // Padding right of marks
489 // Child border - left edge 522 right_offset = layout == L_TABBED ? 1 : 0;
490 memcpy(&color, colors->child_border, sizeof(float) * 4); 523 box.x = x + width - 3;
491 premultiply_alpha(color, con->alpha); 524 box.y = y + 4;
492 box.x = con->x; 525 box.width = 3 - right_offset;
493 box.y = con->y + view->border_thickness * view->border_top; 526 box.height = config->font_height;
494 box.width = view->border_thickness; 527 scale_box(&box, output_scale);
495 box.height = con->height - view->border_thickness 528 render_rect(output->wlr_output, output_damage, &box, color);
496 * (view->border_top + view->border_bottom);
497 scale_box(&box, output_scale);
498 render_rect(output->wlr_output, output_damage, &box, color);
499 }
500 529
501 if (view->border_right) { 530 if (connects_sides) {
502 // Child border - right edge 531 // Left pixel in line with bottom bar
503 if (con->parent->children->length == 1 532 box.x = x;
504 && con->parent->layout == L_HORIZ) { 533 box.y = y + config->font_height + 7;
505 memcpy(&color, colors->indicator, sizeof(float) * 4); 534 box.width = view->border_thickness * view->border_left;
506 } else { 535 box.height = 1;
507 memcpy(&color, colors->child_border, sizeof(float) * 4);
508 }
509 premultiply_alpha(color, con->alpha);
510 box.x = con->x + con->width - view->border_thickness;
511 box.y = con->y + view->border_thickness * view->border_top;
512 box.width = view->border_thickness;
513 box.height = con->height - view->border_thickness
514 * (view->border_top + view->border_bottom);
515 scale_box(&box, output_scale); 536 scale_box(&box, output_scale);
516 render_rect(output->wlr_output, output_damage, &box, color); 537 render_rect(output->wlr_output, output_damage, &box, color);
517 }
518 538
519 if (view->border_top) { 539 // Right pixel in line with bottom bar
520 // Child border - top edge 540 box.x = x + width - view->border_thickness * view->border_right;
521 memcpy(&color, colors->child_border, sizeof(float) * 4); 541 box.y = y + config->font_height + 7;
522 premultiply_alpha(color, con->alpha); 542 box.width = view->border_thickness * view->border_right;
523 box.x = con->x; 543 box.height = 1;
524 box.y = con->y;
525 box.width = con->width;
526 box.height = view->border_thickness;
527 scale_box(&box, output_scale); 544 scale_box(&box, output_scale);
528 render_rect(output->wlr_output, output_damage, &box, color); 545 render_rect(output->wlr_output, output_damage, &box, color);
529 } 546 }
547}
530 548
531 if (view->border_bottom) { 549/**
532 // Child border - bottom edge 550 * Render the top border line for a view using "border pixel".
533 if (con->parent->children->length == 1 551 */
534 && con->parent->layout == L_VERT) { 552static void render_top_border(struct sway_output *output,
535 memcpy(&color, colors->indicator, sizeof(float) * 4); 553 pixman_region32_t *output_damage, struct sway_container *con,
536 } else { 554 struct border_colors *colors) {
537 memcpy(&color, colors->child_border, sizeof(float) * 4); 555 struct sway_view *view = con->sway_view;
538 } 556 if (!view->border_top) {
539 premultiply_alpha(color, con->alpha); 557 return;
540 box.x = con->x;
541 box.y = con->y + con->height - view->border_thickness;
542 box.width = con->width;
543 box.height = view->border_thickness;
544 scale_box(&box, output_scale);
545 render_rect(output->wlr_output, output_damage, &box, color);
546 } 558 }
559 struct wlr_box box;
560 float color[4];
561 float output_scale = output->wlr_output->scale;
562
563 // Child border - top edge
564 memcpy(&color, colors->child_border, sizeof(float) * 4);
565 premultiply_alpha(color, con->alpha);
566 box.x = con->x;
567 box.y = con->y;
568 box.width = con->width;
569 box.height = view->border_thickness;
570 scale_box(&box, output_scale);
571 render_rect(output->wlr_output, output_damage, &box, color);
547} 572}
548 573
549static void render_container(struct sway_output *output, 574static void render_container(struct sway_output *output,
@@ -565,33 +590,30 @@ static void render_container_simple(struct sway_output *output,
565 struct sway_container *child = con->children->items[i]; 590 struct sway_container *child = con->children->items[i];
566 591
567 if (child->type == C_VIEW) { 592 if (child->type == C_VIEW) {
568 if (child->sway_view->border != B_NONE) { 593 struct border_colors *colors;
569 struct border_colors *colors; 594 struct wlr_texture *title_texture;
570 struct wlr_texture *title_texture; 595 struct wlr_texture *marks_texture;
571 struct wlr_texture *marks_texture; 596 if (focus == child || parent_focused) {
572 if (focus == child || parent_focused) { 597 colors = &config->border_colors.focused;
573 colors = &config->border_colors.focused; 598 title_texture = child->title_focused;
574 title_texture = child->title_focused; 599 marks_texture = child->sway_view->marks_focused;
575 marks_texture = child->sway_view->marks_focused; 600 } else if (seat_get_focus_inactive(seat, con) == child) {
576 } else if (seat_get_focus_inactive(seat, con) == child) { 601 colors = &config->border_colors.focused_inactive;
577 colors = &config->border_colors.focused_inactive; 602 title_texture = child->title_focused_inactive;
578 title_texture = child->title_focused_inactive; 603 marks_texture = child->sway_view->marks_focused_inactive;
579 marks_texture = child->sway_view->marks_focused_inactive; 604 } else {
580 } else { 605 colors = &config->border_colors.unfocused;
581 colors = &config->border_colors.unfocused; 606 title_texture = child->title_unfocused;
582 title_texture = child->title_unfocused; 607 marks_texture = child->sway_view->marks_unfocused;
583 marks_texture = child->sway_view->marks_unfocused; 608 }
584 } 609
585 610 if (child->sway_view->border == B_NORMAL) {
586 if (child->sway_view->border == B_NORMAL) { 611 render_titlebar(output, damage, child, child->x, child->y,
587 render_container_simple_border_normal(output, damage, 612 child->width, colors, title_texture, marks_texture);
588 child, colors, title_texture, marks_texture); 613 } else {
589 } else { 614 render_top_border(output, damage, child, colors);
590 render_container_simple_border_pixel(output, damage, child,
591 colors);
592 }
593 } 615 }
594 render_view(child->sway_view, output, damage); 616 render_view(output, damage, child, colors);
595 } else { 617 } else {
596 render_container(output, damage, child, 618 render_container(output, damage, child,
597 parent_focused || focus == child); 619 parent_focused || focus == child);
@@ -599,154 +621,71 @@ static void render_container_simple(struct sway_output *output,
599 } 621 }
600} 622}
601 623
602static void render_tab(struct sway_output *output, pixman_region32_t *damage, 624/**
603 struct sway_container *parent, int child_index, 625 * Render a container's children using the L_TABBED layout.
604 struct border_colors *colors, struct wlr_texture *title_texture) { 626 */
605 struct sway_container *con = parent->children->items[child_index]; 627static void render_container_tabbed(struct sway_output *output,
606 float output_scale = output->wlr_output->scale; 628 pixman_region32_t *damage, struct sway_container *con,
607 float color[4]; 629 bool parent_focused) {
608 struct wlr_box box; 630 if (!con->children->length) {
609 631 return;
610 int tab_width = parent->width / parent->children->length;
611 int x = parent->x + tab_width * child_index;
612 // Make last tab use the remaining width of the parent
613 if (child_index == parent->children->length - 1) {
614 tab_width = parent->width - tab_width * child_index;
615 } 632 }
633 struct sway_seat *seat = input_manager_current_seat(input_manager);
634 struct sway_container *focus = seat_get_focus(seat);
635 struct sway_container *current = seat_get_active_child(seat, con);
636 struct border_colors *current_colors = NULL;
616 637
617 // Single pixel bar above title 638 // Render tabs
618 memcpy(&color, colors->border, sizeof(float) * 4); 639 for (int i = 0; i < con->children->length; ++i) {
619 premultiply_alpha(color, con->alpha); 640 struct sway_container *child = con->children->items[i];
620 box.x = x; 641 struct border_colors *colors;
621 box.y = parent->y; 642 struct wlr_texture *title_texture;
622 box.width = tab_width; 643 struct wlr_texture *marks_texture;
623 box.height = 1; 644 struct sway_view *view =
624 scale_box(&box, output_scale); 645 child->type == C_VIEW ? child->sway_view : NULL;
625 render_rect(output->wlr_output, damage, &box, color);
626
627 // Single pixel bar below title
628 box.y = (parent->y + config->border_thickness * 2 + config->font_height - 1)
629 * output_scale;
630 render_rect(output->wlr_output, damage, &box, color);
631
632 // Single pixel bar on left
633 box.x = x;
634 box.y = parent->y + 1;
635 box.width = 1;
636 box.height = config->border_thickness * 2 + config->font_height - 2;
637 scale_box(&box, output_scale);
638 render_rect(output->wlr_output, damage, &box, color);
639
640 // Single pixel bar on right
641 box.x = (x + tab_width - 1) * output_scale;
642 render_rect(output->wlr_output, damage, &box, color);
643
644 // Title text
645 size_t title_width = 0;
646 if (title_texture) {
647 struct wlr_box texture_box;
648 wlr_texture_get_size(title_texture,
649 &texture_box.width, &texture_box.height);
650 texture_box.x = (x + 1 + config->border_thickness) * output_scale;
651 texture_box.y = (parent->y + config->border_thickness) * output_scale;
652
653 float matrix[9];
654 wlr_matrix_project_box(matrix, &texture_box,
655 WL_OUTPUT_TRANSFORM_NORMAL,
656 0.0, output->wlr_output->transform_matrix);
657 646
658 int available = (tab_width - config->border_thickness * 2 - 2) 647 if (focus == child || parent_focused) {
659 * output_scale; 648 colors = &config->border_colors.focused;
660 if (texture_box.width > available) { 649 title_texture = child->title_focused;
661 texture_box.width = available; 650 marks_texture = view ? view->marks_focused : NULL;
651 } else if (child == current) {
652 colors = &config->border_colors.focused_inactive;
653 title_texture = child->title_focused_inactive;
654 marks_texture = view ? view->marks_focused : NULL;
655 } else {
656 colors = &config->border_colors.unfocused;
657 title_texture = child->title_unfocused;
658 marks_texture = view ? view->marks_unfocused : NULL;
662 } 659 }
663 render_texture(output->wlr_output, damage, title_texture,
664 &texture_box, matrix, 1.0);
665 title_width = texture_box.width;
666 }
667 660
668 // Title background - above the text 661 int tab_width = con->width / con->children->length;
669 memcpy(&color, colors->background, sizeof(float) * 4); 662 int x = con->x + tab_width * i;
670 premultiply_alpha(color, con->alpha); 663 // Make last tab use the remaining width of the parent
671 box.x = x + 1; 664 if (i == con->children->length - 1) {
672 box.y = parent->y + 1; 665 tab_width = con->width - tab_width * i;
673 box.width = tab_width - 2;
674 box.height = config->border_thickness - 1;
675 scale_box(&box, output_scale);
676 render_rect(output->wlr_output, damage, &box, color);
677
678 // Title background - below the text
679 box.y = (parent->y + config->border_thickness + config->font_height)
680 * output_scale;
681 render_rect(output->wlr_output, damage, &box, color);
682
683 // Title background - left of text
684 box.x = x + 1;
685 box.y = parent->y + config->border_thickness;
686 box.width = config->border_thickness;
687 box.height = config->font_height;
688 scale_box(&box, output_scale);
689 render_rect(output->wlr_output, damage, &box, color);
690
691 // Title background - right of text
692 box.x = (x + 1 + config->border_thickness) * output_scale + title_width;
693 box.y = (parent->y + config->border_thickness) * output_scale;
694 box.width = (tab_width - config->border_thickness - 2) * output_scale
695 - title_width;
696 box.height = config->font_height * output_scale;
697 render_rect(output->wlr_output, damage, &box, color);
698}
699
700static void render_tab_content(struct sway_output *output,
701 pixman_region32_t *damage, struct sway_container *con,
702 struct border_colors *colors) {
703 struct sway_view *view = con->sway_view;
704 render_view(view, output, damage);
705
706 struct wlr_box box;
707 float output_scale = output->wlr_output->scale;
708 float color[4];
709
710 if (view->border != B_NONE) {
711 if (view->border_left) {
712 memcpy(&color, colors->child_border, sizeof(float) * 4);
713 premultiply_alpha(color, con->alpha);
714 box.x = con->x;
715 box.y = con->y + config->border_thickness * 2 + config->font_height;
716 box.width = view->border_thickness;
717 box.height = view->height;
718 scale_box(&box, output_scale);
719 render_rect(output->wlr_output, damage, &box, color);
720 } 666 }
721 667
722 if (view->border_right) { 668 render_titlebar(output, damage, child, x, child->y, tab_width, colors,
723 memcpy(&color, colors->child_border, sizeof(float) * 4); 669 title_texture, marks_texture);
724 premultiply_alpha(color, con->alpha);
725 box.x = view->x + view->width;
726 box.y = con->y + config->border_thickness * 2 + config->font_height;
727 box.width = view->border_thickness;
728 box.height = view->height;
729 scale_box(&box, output_scale);
730 render_rect(output->wlr_output, damage, &box, color);
731 }
732 670
733 if (view->border_bottom) { 671 if (child == current) {
734 memcpy(&color, colors->child_border, sizeof(float) * 4); 672 current_colors = colors;
735 premultiply_alpha(color, con->alpha);
736 box.x = con->x;
737 box.y = view->y + view->height;
738 box.width = con->width;
739 box.height = view->border_thickness;
740 scale_box(&box, output_scale);
741 render_rect(output->wlr_output, damage, &box, color);
742 } 673 }
743 } 674 }
675
676 // Render surface and left/right/bottom borders
677 if (current->type == C_VIEW) {
678 render_view(output, damage, current, current_colors);
679 } else {
680 render_container(output, damage, current,
681 parent_focused || current == focus);
682 }
744} 683}
745 684
746/** 685/**
747 * Render a container's children using the L_TABBED layout. 686 * Render a container's children using the L_STACKED layout.
748 */ 687 */
749static void render_container_tabbed(struct sway_output *output, 688static void render_container_stacked(struct sway_output *output,
750 pixman_region32_t *damage, struct sway_container *con, 689 pixman_region32_t *damage, struct sway_container *con,
751 bool parent_focused) { 690 bool parent_focused) {
752 if (!con->children->length) { 691 if (!con->children->length) {
@@ -757,24 +696,32 @@ static void render_container_tabbed(struct sway_output *output,
757 struct sway_container *current = seat_get_active_child(seat, con); 696 struct sway_container *current = seat_get_active_child(seat, con);
758 struct border_colors *current_colors = NULL; 697 struct border_colors *current_colors = NULL;
759 698
760 // Render tabs 699 // Render titles
761 for (int i = 0; i < con->children->length; ++i) { 700 for (int i = 0; i < con->children->length; ++i) {
762 struct sway_container *child = con->children->items[i]; 701 struct sway_container *child = con->children->items[i];
763 struct border_colors *colors; 702 struct border_colors *colors;
764 struct wlr_texture *title_texture; 703 struct wlr_texture *title_texture;
704 struct wlr_texture *marks_texture;
705 struct sway_view *view =
706 child->type == C_VIEW ? child->sway_view : NULL;
765 707
766 if (focus == child || parent_focused) { 708 if (focus == child || parent_focused) {
767 colors = &config->border_colors.focused; 709 colors = &config->border_colors.focused;
768 title_texture = child->title_focused; 710 title_texture = child->title_focused;
711 marks_texture = view ? view->marks_focused : NULL;
769 } else if (child == current) { 712 } else if (child == current) {
770 colors = &config->border_colors.focused_inactive; 713 colors = &config->border_colors.focused_inactive;
771 title_texture = child->title_focused_inactive; 714 title_texture = child->title_focused_inactive;
715 marks_texture = view ? view->marks_focused_inactive : NULL;
772 } else { 716 } else {
773 colors = &config->border_colors.unfocused; 717 colors = &config->border_colors.unfocused;
774 title_texture = child->title_unfocused; 718 title_texture = child->title_unfocused;
719 marks_texture = view ? view->marks_unfocused : NULL;
775 } 720 }
776 721
777 render_tab(output, damage, con, i, colors, title_texture); 722 int y = con->y + (config->font_height + 8) * i;
723 render_titlebar(output, damage, child, child->x, y, child->width,
724 colors, title_texture, marks_texture);
778 725
779 if (child == current) { 726 if (child == current) {
780 current_colors = colors; 727 current_colors = colors;
@@ -783,21 +730,13 @@ static void render_container_tabbed(struct sway_output *output,
783 730
784 // Render surface and left/right/bottom borders 731 // Render surface and left/right/bottom borders
785 if (current->type == C_VIEW) { 732 if (current->type == C_VIEW) {
786 render_tab_content(output, damage, current, current_colors); 733 render_view(output, damage, current, current_colors);
787 } else { 734 } else {
788 render_container(output, damage, current, 735 render_container(output, damage, current,
789 parent_focused || current == focus); 736 parent_focused || current == focus);
790 } 737 }
791} 738}
792 739
793/**
794 * Render a container's children using the L_STACKED layout.
795 */
796static void render_container_stacked(struct sway_output *output,
797 pixman_region32_t *damage, struct sway_container *con) {
798 // TODO
799}
800
801static void render_container(struct sway_output *output, 740static void render_container(struct sway_output *output,
802 pixman_region32_t *damage, struct sway_container *con, 741 pixman_region32_t *damage, struct sway_container *con,
803 bool parent_focused) { 742 bool parent_focused) {
@@ -808,7 +747,7 @@ static void render_container(struct sway_output *output,
808 render_container_simple(output, damage, con, parent_focused); 747 render_container_simple(output, damage, con, parent_focused);
809 break; 748 break;
810 case L_STACKED: 749 case L_STACKED:
811 render_container_stacked(output, damage, con); 750 render_container_stacked(output, damage, con, parent_focused);
812 break; 751 break;
813 case L_TABBED: 752 case L_TABBED:
814 render_container_tabbed(output, damage, con, parent_focused); 753 render_container_tabbed(output, damage, con, parent_focused);
@@ -868,7 +807,8 @@ static void render_output(struct sway_output *output, struct timespec *when,
868 } 807 }
869 808
870 // TODO: handle views smaller than the output 809 // TODO: handle views smaller than the output
871 render_view(workspace->sway_workspace->fullscreen, output, damage); 810 render_view_surfaces(
811 workspace->sway_workspace->fullscreen, output, damage);
872 812
873 if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { 813 if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) {
874 render_unmanaged(output, damage, 814 render_unmanaged(output, damage,