summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-05-21 19:52:08 -0400
committerLibravatar GitHub <noreply@github.com>2018-05-21 19:52:08 -0400
commit9731d080bea58fee78bd52bb5633cb37ec7edc22 (patch)
tree7fbc2b11fc371cdec7ed1b5cdbeb2224d429cace
parentFix focus follows mouse with no focus (diff)
parentReplace empty argument with void (diff)
downloadsway-9731d080bea58fee78bd52bb5633cb37ec7edc22.tar.gz
sway-9731d080bea58fee78bd52bb5633cb37ec7edc22.tar.zst
sway-9731d080bea58fee78bd52bb5633cb37ec7edc22.zip
Merge pull request #2015 from RyanDwyer/stacked-layout
Implement stacked layout
-rw-r--r--include/sway/tree/container.h11
-rw-r--r--sway/commands/layout.c2
-rw-r--r--sway/desktop/output.c602
-rw-r--r--sway/tree/arrange.c32
-rw-r--r--sway/tree/container.c25
-rw-r--r--sway/tree/view.c15
6 files changed, 340 insertions, 347 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 598a4f3d..493c70e2 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -11,6 +11,12 @@ extern struct sway_container root_container;
11struct sway_view; 11struct sway_view;
12struct sway_seat; 12struct sway_seat;
13 13
14#define TITLEBAR_BORDER_THICKNESS 1
15
16// Padding includes titlebar border
17#define TITLEBAR_H_PADDING 3
18#define TITLEBAR_V_PADDING 4
19
14/** 20/**
15 * Different kinds of containers. 21 * Different kinds of containers.
16 * 22 *
@@ -212,4 +218,9 @@ void container_calculate_title_height(struct sway_container *container);
212 218
213void container_notify_child_title_changed(struct sway_container *container); 219void container_notify_child_title_changed(struct sway_container *container);
214 220
221/**
222 * Return the height of a regular title bar.
223 */
224size_t container_titlebar_height(void);
225
215#endif 226#endif
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 8aa321ae..58728f16 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -41,6 +41,8 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
41 parent->layout = L_VERT; 41 parent->layout = L_VERT;
42 } else if (strcasecmp(argv[0], "tabbed") == 0) { 42 } else if (strcasecmp(argv[0], "tabbed") == 0) {
43 parent->layout = L_TABBED; 43 parent->layout = L_TABBED;
44 } else if (strcasecmp(argv[0], "stacking") == 0) {
45 parent->layout = L_STACKED;
44 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { 46 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
45 if (parent->layout == L_HORIZ) { 47 if (parent->layout == L_HORIZ) {
46 parent->layout = L_VERT; 48 parent->layout = L_VERT;
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 551e96fc..765647fd 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,161 @@ 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 = TITLEBAR_BORDER_THICKNESS;
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) {
404 box.height = 1; 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 + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
424 box.width = width - left_offset - right_offset;
425 box.height = TITLEBAR_BORDER_THICKNESS;
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 + TITLEBAR_BORDER_THICKNESS;
433 box.width = TITLEBAR_BORDER_THICKNESS;
434 box.height =
435 container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
436 scale_box(&box, output_scale);
437 render_rect(output->wlr_output, output_damage, &box, color);
438
439 // Single pixel right edge
440 box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale;
441 render_rect(output->wlr_output, output_damage, &box, color);
442 }
443
444 size_t inner_width = width - TITLEBAR_H_PADDING * 2;
445
408 // Marks 446 // Marks
409 size_t marks_width = 0; 447 size_t marks_width = 0;
410 if (config->show_marks && marks_texture) { 448 if (config->show_marks && marks_texture) {
411 struct wlr_box texture_box; 449 struct wlr_box texture_box;
412 wlr_texture_get_size(marks_texture, 450 wlr_texture_get_size(marks_texture,
413 &texture_box.width, &texture_box.height); 451 &texture_box.width, &texture_box.height);
414 texture_box.x = (inner_x + inner_width) * output_scale - texture_box.width; 452 texture_box.x =
415 texture_box.y = (con->y + view->border_thickness) * output_scale; 453 (x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width;
454 texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
416 455
417 float matrix[9]; 456 float matrix[9];
418 wlr_matrix_project_box(matrix, &texture_box, 457 wlr_matrix_project_box(matrix, &texture_box,
419 WL_OUTPUT_TRANSFORM_NORMAL, 458 WL_OUTPUT_TRANSFORM_NORMAL,
420 0.0, output->wlr_output->transform_matrix); 459 0.0, output->wlr_output->transform_matrix);
421 460
461 if (inner_width * output_scale < texture_box.width) {
462 texture_box.width = inner_width * output_scale;
463 }
422 render_texture(output->wlr_output, output_damage, marks_texture, 464 render_texture(output->wlr_output, output_damage, marks_texture,
423 &texture_box, matrix, con->alpha); 465 &texture_box, matrix, con->alpha);
424 marks_width = texture_box.width; 466 marks_width = texture_box.width;
@@ -430,8 +472,8 @@ static void render_container_simple_border_normal(struct sway_output *output,
430 struct wlr_box texture_box; 472 struct wlr_box texture_box;
431 wlr_texture_get_size(title_texture, 473 wlr_texture_get_size(title_texture,
432 &texture_box.width, &texture_box.height); 474 &texture_box.width, &texture_box.height);
433 texture_box.x = inner_x * output_scale; 475 texture_box.x = (x + TITLEBAR_H_PADDING) * output_scale;
434 texture_box.y = (con->y + view->border_thickness) * output_scale; 476 texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
435 477
436 float matrix[9]; 478 float matrix[9];
437 wlr_matrix_project_box(matrix, &texture_box, 479 wlr_matrix_project_box(matrix, &texture_box,
@@ -446,104 +488,89 @@ static void render_container_simple_border_normal(struct sway_output *output,
446 title_width = texture_box.width; 488 title_width = texture_box.width;
447 } 489 }
448 490
449 // Title background - above the text 491 // Padding above title
450 memcpy(&color, colors->background, sizeof(float) * 4); 492 memcpy(&color, colors->background, sizeof(float) * 4);
451 premultiply_alpha(color, con->alpha); 493 premultiply_alpha(color, con->alpha);
452 box.x = inner_x; 494 box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
453 box.y = con->y + 1; 495 box.y = y + TITLEBAR_BORDER_THICKNESS;
454 box.width = inner_width; 496 box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2;
455 box.height = view->border_thickness - 1; 497 box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS;
456 scale_box(&box, output_scale); 498 scale_box(&box, output_scale);
457 render_rect(output->wlr_output, output_damage, &box, color); 499 render_rect(output->wlr_output, output_damage, &box, color);
458 500
459 // Title background - below the text 501 // Padding below title
460 box.y = (con->y + view->border_thickness + config->font_height) 502 box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale;
461 * output_scale;
462 render_rect(output->wlr_output, output_damage, &box, color); 503 render_rect(output->wlr_output, output_damage, &box, color);
463 504
464 // Title background - filler between title and marks 505 // Filler between title and marks
465 box.width = inner_width * output_scale - title_width - marks_width; 506 box.width = inner_width * output_scale - title_width - marks_width;
466 if (box.width > 0) { 507 if (box.width > 0) {
467 box.x = inner_x * output_scale + title_width; 508 box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width;
468 box.y = (con->y + view->border_thickness) * output_scale; 509 box.y = (y + TITLEBAR_V_PADDING) * output_scale;
469 box.height = config->font_height * output_scale; 510 box.height = config->font_height * output_scale;
470 render_rect(output->wlr_output, output_damage, &box, color); 511 render_rect(output->wlr_output, output_damage, &box, color);
471 } 512 }
472}
473 513
474/** 514 // Padding left of title
475 * Render decorations for a view with "border pixel". 515 left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
476 * 516 box.x = x + left_offset;
477 * Care must be taken not to render over the same pixel multiple times, 517 box.y = y + TITLEBAR_V_PADDING;
478 * otherwise the colors will be incorrect when using opacity. 518 box.width = TITLEBAR_H_PADDING - left_offset;
479 */ 519 box.height = config->font_height;
480static void render_container_simple_border_pixel(struct sway_output *output, 520 scale_box(&box, output_scale);
481 pixman_region32_t *output_damage, struct sway_container *con, 521 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 522
488 if (view->border_left) { 523 // Padding right of marks
489 // Child border - left edge 524 right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
490 memcpy(&color, colors->child_border, sizeof(float) * 4); 525 box.x = x + width - TITLEBAR_H_PADDING;
491 premultiply_alpha(color, con->alpha); 526 box.y = y + TITLEBAR_V_PADDING;
492 box.x = con->x; 527 box.width = TITLEBAR_H_PADDING - right_offset;
493 box.y = con->y + view->border_thickness * view->border_top; 528 box.height = config->font_height;
494 box.width = view->border_thickness; 529 scale_box(&box, output_scale);
495 box.height = con->height - view->border_thickness 530 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 531
501 if (view->border_right) { 532 if (connects_sides) {
502 // Child border - right edge 533 // Left pixel in line with bottom bar
503 if (con->parent->children->length == 1 534 box.x = x;
504 && con->parent->layout == L_HORIZ) { 535 box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
505 memcpy(&color, colors->indicator, sizeof(float) * 4); 536 box.width = view->border_thickness * view->border_left;
506 } else { 537 box.height = TITLEBAR_BORDER_THICKNESS;
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); 538 scale_box(&box, output_scale);
516 render_rect(output->wlr_output, output_damage, &box, color); 539 render_rect(output->wlr_output, output_damage, &box, color);
517 }
518 540
519 if (view->border_top) { 541 // Right pixel in line with bottom bar
520 // Child border - top edge 542 box.x = x + width - view->border_thickness * view->border_right;
521 memcpy(&color, colors->child_border, sizeof(float) * 4); 543 box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
522 premultiply_alpha(color, con->alpha); 544 box.width = view->border_thickness * view->border_right;
523 box.x = con->x; 545 box.height = TITLEBAR_BORDER_THICKNESS;
524 box.y = con->y;
525 box.width = con->width;
526 box.height = view->border_thickness;
527 scale_box(&box, output_scale); 546 scale_box(&box, output_scale);
528 render_rect(output->wlr_output, output_damage, &box, color); 547 render_rect(output->wlr_output, output_damage, &box, color);
529 } 548 }
549}
530 550
531 if (view->border_bottom) { 551/**
532 // Child border - bottom edge 552 * Render the top border line for a view using "border pixel".
533 if (con->parent->children->length == 1 553 */
534 && con->parent->layout == L_VERT) { 554static void render_top_border(struct sway_output *output,
535 memcpy(&color, colors->indicator, sizeof(float) * 4); 555 pixman_region32_t *output_damage, struct sway_container *con,
536 } else { 556 struct border_colors *colors) {
537 memcpy(&color, colors->child_border, sizeof(float) * 4); 557 struct sway_view *view = con->sway_view;
538 } 558 if (!view->border_top) {
539 premultiply_alpha(color, con->alpha); 559 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 } 560 }
561 struct wlr_box box;
562 float color[4];
563 float output_scale = output->wlr_output->scale;
564
565 // Child border - top edge
566 memcpy(&color, colors->child_border, sizeof(float) * 4);
567 premultiply_alpha(color, con->alpha);
568 box.x = con->x;
569 box.y = con->y;
570 box.width = con->width;
571 box.height = view->border_thickness;
572 scale_box(&box, output_scale);
573 render_rect(output->wlr_output, output_damage, &box, color);
547} 574}
548 575
549static void render_container(struct sway_output *output, 576static void render_container(struct sway_output *output,
@@ -565,33 +592,30 @@ static void render_container_simple(struct sway_output *output,
565 struct sway_container *child = con->children->items[i]; 592 struct sway_container *child = con->children->items[i];
566 593
567 if (child->type == C_VIEW) { 594 if (child->type == C_VIEW) {
568 if (child->sway_view->border != B_NONE) { 595 struct border_colors *colors;
569 struct border_colors *colors; 596 struct wlr_texture *title_texture;
570 struct wlr_texture *title_texture; 597 struct wlr_texture *marks_texture;
571 struct wlr_texture *marks_texture; 598 if (focus == child || parent_focused) {
572 if (focus == child || parent_focused) { 599 colors = &config->border_colors.focused;
573 colors = &config->border_colors.focused; 600 title_texture = child->title_focused;
574 title_texture = child->title_focused; 601 marks_texture = child->sway_view->marks_focused;
575 marks_texture = child->sway_view->marks_focused; 602 } else if (seat_get_focus_inactive(seat, con) == child) {
576 } else if (seat_get_focus_inactive(seat, con) == child) { 603 colors = &config->border_colors.focused_inactive;
577 colors = &config->border_colors.focused_inactive; 604 title_texture = child->title_focused_inactive;
578 title_texture = child->title_focused_inactive; 605 marks_texture = child->sway_view->marks_focused_inactive;
579 marks_texture = child->sway_view->marks_focused_inactive; 606 } else {
580 } else { 607 colors = &config->border_colors.unfocused;
581 colors = &config->border_colors.unfocused; 608 title_texture = child->title_unfocused;
582 title_texture = child->title_unfocused; 609 marks_texture = child->sway_view->marks_unfocused;
583 marks_texture = child->sway_view->marks_unfocused; 610 }
584 } 611
585 612 if (child->sway_view->border == B_NORMAL) {
586 if (child->sway_view->border == B_NORMAL) { 613 render_titlebar(output, damage, child, child->x, child->y,
587 render_container_simple_border_normal(output, damage, 614 child->width, colors, title_texture, marks_texture);
588 child, colors, title_texture, marks_texture); 615 } else {
589 } else { 616 render_top_border(output, damage, child, colors);
590 render_container_simple_border_pixel(output, damage, child,
591 colors);
592 }
593 } 617 }
594 render_view(child->sway_view, output, damage); 618 render_view(output, damage, child, colors);
595 } else { 619 } else {
596 render_container(output, damage, child, 620 render_container(output, damage, child,
597 parent_focused || focus == child); 621 parent_focused || focus == child);
@@ -599,154 +623,71 @@ static void render_container_simple(struct sway_output *output,
599 } 623 }
600} 624}
601 625
602static void render_tab(struct sway_output *output, pixman_region32_t *damage, 626/**
603 struct sway_container *parent, int child_index, 627 * Render a container's children using the L_TABBED layout.
604 struct border_colors *colors, struct wlr_texture *title_texture) { 628 */
605 struct sway_container *con = parent->children->items[child_index]; 629static void render_container_tabbed(struct sway_output *output,
606 float output_scale = output->wlr_output->scale; 630 pixman_region32_t *damage, struct sway_container *con,
607 float color[4]; 631 bool parent_focused) {
608 struct wlr_box box; 632 if (!con->children->length) {
609 633 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 } 634 }
635 struct sway_seat *seat = input_manager_current_seat(input_manager);
636 struct sway_container *focus = seat_get_focus(seat);
637 struct sway_container *current = seat_get_active_child(seat, con);
638 struct border_colors *current_colors = NULL;
616 639
617 // Single pixel bar above title 640 // Render tabs
618 memcpy(&color, colors->border, sizeof(float) * 4); 641 for (int i = 0; i < con->children->length; ++i) {
619 premultiply_alpha(color, con->alpha); 642 struct sway_container *child = con->children->items[i];
620 box.x = x; 643 struct border_colors *colors;
621 box.y = parent->y; 644 struct wlr_texture *title_texture;
622 box.width = tab_width; 645 struct wlr_texture *marks_texture;
623 box.height = 1; 646 struct sway_view *view =
624 scale_box(&box, output_scale); 647 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 648
658 int available = (tab_width - config->border_thickness * 2 - 2) 649 if (focus == child || parent_focused) {
659 * output_scale; 650 colors = &config->border_colors.focused;
660 if (texture_box.width > available) { 651 title_texture = child->title_focused;
661 texture_box.width = available; 652 marks_texture = view ? view->marks_focused : NULL;
653 } else if (child == current) {
654 colors = &config->border_colors.focused_inactive;
655 title_texture = child->title_focused_inactive;
656 marks_texture = view ? view->marks_focused : NULL;
657 } else {
658 colors = &config->border_colors.unfocused;
659 title_texture = child->title_unfocused;
660 marks_texture = view ? view->marks_unfocused : NULL;
662 } 661 }
663 render_texture(output->wlr_output, damage, title_texture,
664 &texture_box, matrix, 1.0);
665 title_width = texture_box.width;
666 }
667
668 // Title background - above the text
669 memcpy(&color, colors->background, sizeof(float) * 4);
670 premultiply_alpha(color, con->alpha);
671 box.x = x + 1;
672 box.y = parent->y + 1;
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 662
678 // Title background - below the text 663 int tab_width = con->width / con->children->length;
679 box.y = (parent->y + config->border_thickness + config->font_height) 664 int x = con->x + tab_width * i;
680 * output_scale; 665 // Make last tab use the remaining width of the parent
681 render_rect(output->wlr_output, damage, &box, color); 666 if (i == con->children->length - 1) {
682 667 tab_width = con->width - tab_width * i;
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 } 668 }
721 669
722 if (view->border_right) { 670 render_titlebar(output, damage, child, x, child->y, tab_width, colors,
723 memcpy(&color, colors->child_border, sizeof(float) * 4); 671 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 672
733 if (view->border_bottom) { 673 if (child == current) {
734 memcpy(&color, colors->child_border, sizeof(float) * 4); 674 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 } 675 }
743 } 676 }
677
678 // Render surface and left/right/bottom borders
679 if (current->type == C_VIEW) {
680 render_view(output, damage, current, current_colors);
681 } else {
682 render_container(output, damage, current,
683 parent_focused || current == focus);
684 }
744} 685}
745 686
746/** 687/**
747 * Render a container's children using the L_TABBED layout. 688 * Render a container's children using the L_STACKED layout.
748 */ 689 */
749static void render_container_tabbed(struct sway_output *output, 690static void render_container_stacked(struct sway_output *output,
750 pixman_region32_t *damage, struct sway_container *con, 691 pixman_region32_t *damage, struct sway_container *con,
751 bool parent_focused) { 692 bool parent_focused) {
752 if (!con->children->length) { 693 if (!con->children->length) {
@@ -757,24 +698,32 @@ static void render_container_tabbed(struct sway_output *output,
757 struct sway_container *current = seat_get_active_child(seat, con); 698 struct sway_container *current = seat_get_active_child(seat, con);
758 struct border_colors *current_colors = NULL; 699 struct border_colors *current_colors = NULL;
759 700
760 // Render tabs 701 // Render titles
761 for (int i = 0; i < con->children->length; ++i) { 702 for (int i = 0; i < con->children->length; ++i) {
762 struct sway_container *child = con->children->items[i]; 703 struct sway_container *child = con->children->items[i];
763 struct border_colors *colors; 704 struct border_colors *colors;
764 struct wlr_texture *title_texture; 705 struct wlr_texture *title_texture;
706 struct wlr_texture *marks_texture;
707 struct sway_view *view =
708 child->type == C_VIEW ? child->sway_view : NULL;
765 709
766 if (focus == child || parent_focused) { 710 if (focus == child || parent_focused) {
767 colors = &config->border_colors.focused; 711 colors = &config->border_colors.focused;
768 title_texture = child->title_focused; 712 title_texture = child->title_focused;
713 marks_texture = view ? view->marks_focused : NULL;
769 } else if (child == current) { 714 } else if (child == current) {
770 colors = &config->border_colors.focused_inactive; 715 colors = &config->border_colors.focused_inactive;
771 title_texture = child->title_focused_inactive; 716 title_texture = child->title_focused_inactive;
717 marks_texture = view ? view->marks_focused_inactive : NULL;
772 } else { 718 } else {
773 colors = &config->border_colors.unfocused; 719 colors = &config->border_colors.unfocused;
774 title_texture = child->title_unfocused; 720 title_texture = child->title_unfocused;
721 marks_texture = view ? view->marks_unfocused : NULL;
775 } 722 }
776 723
777 render_tab(output, damage, con, i, colors, title_texture); 724 int y = con->y + container_titlebar_height() * i;
725 render_titlebar(output, damage, child, child->x, y, child->width,
726 colors, title_texture, marks_texture);
778 727
779 if (child == current) { 728 if (child == current) {
780 current_colors = colors; 729 current_colors = colors;
@@ -783,21 +732,13 @@ static void render_container_tabbed(struct sway_output *output,
783 732
784 // Render surface and left/right/bottom borders 733 // Render surface and left/right/bottom borders
785 if (current->type == C_VIEW) { 734 if (current->type == C_VIEW) {
786 render_tab_content(output, damage, current, current_colors); 735 render_view(output, damage, current, current_colors);
787 } else { 736 } else {
788 render_container(output, damage, current, 737 render_container(output, damage, current,
789 parent_focused || current == focus); 738 parent_focused || current == focus);
790 } 739 }
791} 740}
792 741
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, 742static void render_container(struct sway_output *output,
802 pixman_region32_t *damage, struct sway_container *con, 743 pixman_region32_t *damage, struct sway_container *con,
803 bool parent_focused) { 744 bool parent_focused) {
@@ -808,7 +749,7 @@ static void render_container(struct sway_output *output,
808 render_container_simple(output, damage, con, parent_focused); 749 render_container_simple(output, damage, con, parent_focused);
809 break; 750 break;
810 case L_STACKED: 751 case L_STACKED:
811 render_container_stacked(output, damage, con); 752 render_container_stacked(output, damage, con, parent_focused);
812 break; 753 break;
813 case L_TABBED: 754 case L_TABBED:
814 render_container_tabbed(output, damage, con, parent_focused); 755 render_container_tabbed(output, damage, con, parent_focused);
@@ -868,7 +809,8 @@ static void render_output(struct sway_output *output, struct timespec *when,
868 } 809 }
869 810
870 // TODO: handle views smaller than the output 811 // TODO: handle views smaller than the output
871 render_view(workspace->sway_workspace->fullscreen, output, damage); 812 render_view_surfaces(
813 workspace->sway_workspace->fullscreen, output, damage);
872 814
873 if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { 815 if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) {
874 render_unmanaged(output, damage, 816 render_unmanaged(output, damage,
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 8aebc0cc..37f4a066 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -86,12 +86,14 @@ static void apply_horiz_layout(struct sway_container *parent) {
86 if (!num_children) { 86 if (!num_children) {
87 return; 87 return;
88 } 88 }
89 size_t parent_height = parent->height;
90 size_t parent_offset = 0; 89 size_t parent_offset = 0;
91 if (parent->parent->layout == L_TABBED) { 90 if (parent->parent->layout == L_TABBED) {
92 parent_offset = config->border_thickness * 2 + config->font_height; 91 parent_offset = container_titlebar_height();
93 parent_height -= parent_offset; 92 } else if (parent->parent->layout == L_STACKED) {
93 parent_offset =
94 container_titlebar_height() * parent->parent->children->length;
94 } 95 }
96 size_t parent_height = parent->height - parent_offset;
95 97
96 // Calculate total width of children 98 // Calculate total width of children
97 double total_width = 0; 99 double total_width = 0;
@@ -132,12 +134,14 @@ static void apply_vert_layout(struct sway_container *parent) {
132 if (!num_children) { 134 if (!num_children) {
133 return; 135 return;
134 } 136 }
135 size_t parent_height = parent->height;
136 size_t parent_offset = 0; 137 size_t parent_offset = 0;
137 if (parent->parent->layout == L_TABBED) { 138 if (parent->parent->layout == L_TABBED) {
138 parent_offset = config->border_thickness * 2 + config->font_height; 139 parent_offset = container_titlebar_height();
139 parent_height -= parent_offset; 140 } else if (parent->parent->layout == L_STACKED) {
141 parent_offset =
142 container_titlebar_height() * parent->parent->children->length;
140 } 143 }
144 size_t parent_height = parent->height - parent_offset;
141 145
142 // Calculate total height of children 146 // Calculate total height of children
143 double total_height = 0; 147 double total_height = 0;
@@ -186,6 +190,19 @@ static void apply_tabbed_layout(struct sway_container *parent) {
186 } 190 }
187} 191}
188 192
193static void apply_stacked_layout(struct sway_container *parent) {
194 if (!parent->children->length) {
195 return;
196 }
197 for (int i = 0; i < parent->children->length; ++i) {
198 struct sway_container *child = parent->children->items[i];
199 child->x = parent->x;
200 child->y = parent->y;
201 child->width = parent->width;
202 child->height = parent->height;
203 }
204}
205
189void arrange_children_of(struct sway_container *parent) { 206void arrange_children_of(struct sway_container *parent) {
190 if (config->reloading) { 207 if (config->reloading) {
191 return; 208 return;
@@ -219,6 +236,9 @@ void arrange_children_of(struct sway_container *parent) {
219 case L_TABBED: 236 case L_TABBED:
220 apply_tabbed_layout(parent); 237 apply_tabbed_layout(parent);
221 break; 238 break;
239 case L_STACKED:
240 apply_stacked_layout(parent);
241 break;
222 default: 242 default:
223 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout); 243 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
224 apply_horiz_layout(parent); 244 apply_horiz_layout(parent);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 5d88325f..9cf18f61 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -510,7 +510,7 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent,
510 struct sway_seat *seat = input_manager_current_seat(input_manager); 510 struct sway_seat *seat = input_manager_current_seat(input_manager);
511 511
512 // Tab titles 512 // Tab titles
513 int title_height = config->border_thickness * 2 + config->font_height; 513 int title_height = container_titlebar_height();
514 if (oy < parent->y + title_height) { 514 if (oy < parent->y + title_height) {
515 int tab_width = parent->width / parent->children->length; 515 int tab_width = parent->width / parent->children->length;
516 int child_index = (ox - parent->x) / tab_width; 516 int child_index = (ox - parent->x) / tab_width;
@@ -533,8 +533,23 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent,
533static struct sway_container *container_at_stacked( 533static struct sway_container *container_at_stacked(
534 struct sway_container *parent, double ox, double oy, 534 struct sway_container *parent, double ox, double oy,
535 struct wlr_surface **surface, double *sx, double *sy) { 535 struct wlr_surface **surface, double *sx, double *sy) {
536 // TODO 536 if (oy < parent->y || oy > parent->y + parent->height) {
537 return NULL; 537 return NULL;
538 }
539 struct sway_seat *seat = input_manager_current_seat(input_manager);
540
541 // Title bars
542 int title_height = container_titlebar_height();
543 int child_index = (oy - parent->y) / title_height;
544 if (child_index < parent->children->length) {
545 struct sway_container *child = parent->children->items[child_index];
546 return seat_get_focus_inactive(seat, child);
547 }
548
549 // Surfaces
550 struct sway_container *current = seat_get_active_child(seat, parent);
551
552 return container_at(current, ox, oy, surface, sx, sy);
538} 553}
539 554
540/** 555/**
@@ -847,3 +862,7 @@ void container_notify_child_title_changed(struct sway_container *container) {
847 container_update_title_textures(container); 862 container_update_title_textures(container);
848 container_notify_child_title_changed(container->parent); 863 container_notify_child_title_changed(container->parent);
849} 864}
865
866size_t container_titlebar_height() {
867 return config->font_height + TITLEBAR_V_PADDING * 2;
868}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index c013e635..07157818 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -182,11 +182,11 @@ void view_autoconfigure(struct sway_view *view) {
182 // area. We have to offset the surface y by the height of the title bar, and 182 // area. We have to offset the surface y by the height of the title bar, and
183 // disable any top border because we'll always have the title bar. 183 // disable any top border because we'll always have the title bar.
184 if (view->swayc->parent->layout == L_TABBED) { 184 if (view->swayc->parent->layout == L_TABBED) {
185 y_offset = config->border_thickness * 2 + config->font_height; 185 y_offset = container_titlebar_height();
186 view->border_top = 0; 186 view->border_top = 0;
187 } else if (view->swayc->parent->layout == L_STACKED) { 187 } else if (view->swayc->parent->layout == L_STACKED) {
188 y_offset = config->border_thickness * 2 + config->font_height; 188 y_offset = container_titlebar_height()
189 y_offset *= view->swayc->parent->children->length; 189 * view->swayc->parent->children->length;
190 view->border_top = 0; 190 view->border_top = 0;
191 } 191 }
192 192
@@ -208,7 +208,7 @@ void view_autoconfigure(struct sway_view *view) {
208 - view->border_thickness * view->border_bottom; 208 - view->border_thickness * view->border_bottom;
209 break; 209 break;
210 case B_NORMAL: 210 case B_NORMAL:
211 // Height is: border + title height + border + view height + border 211 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
212 x = view->swayc->x + view->border_thickness * view->border_left; 212 x = view->swayc->x + view->border_thickness * view->border_left;
213 width = view->swayc->width 213 width = view->swayc->width
214 - view->border_thickness * view->border_left 214 - view->border_thickness * view->border_left
@@ -218,10 +218,9 @@ void view_autoconfigure(struct sway_view *view) {
218 height = view->swayc->height - y_offset 218 height = view->swayc->height - y_offset
219 - view->border_thickness * view->border_bottom; 219 - view->border_thickness * view->border_bottom;
220 } else { 220 } else {
221 y = view->swayc->y + config->font_height + view->border_thickness * 2 221 y = view->swayc->y + container_titlebar_height();
222 + y_offset; 222 height = view->swayc->height - container_titlebar_height()
223 height = view->swayc->height - config->font_height 223 - view->border_thickness * view->border_bottom;
224 - view->border_thickness * (2 + view->border_bottom);
225 } 224 }
226 break; 225 break;
227 } 226 }