diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-05-21 22:58:46 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-05-22 08:27:24 +1000 |
commit | 664169fbf1c4e07f17a48b2b801dad9cea31ea4c (patch) | |
tree | e20b1f39a89abd5a6567f7e9d398f002e9ee5bee | |
parent | Fix focus follows mouse with no focus (diff) | |
download | sway-664169fbf1c4e07f17a48b2b801dad9cea31ea4c.tar.gz sway-664169fbf1c4e07f17a48b2b801dad9cea31ea4c.tar.zst sway-664169fbf1c4e07f17a48b2b801dad9cea31ea4c.zip |
Implement stacked layout
-rw-r--r-- | sway/commands/layout.c | 2 | ||||
-rw-r--r-- | sway/desktop/output.c | 596 | ||||
-rw-r--r-- | sway/tree/arrange.c | 32 | ||||
-rw-r--r-- | sway/tree/view.c | 15 |
4 files changed, 303 insertions, 342 deletions
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..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 | ||
272 | static 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 | |||
283 | static void render_rect(struct wlr_output *wlr_output, | 272 | static 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 | ||
309 | static 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 | */ |
326 | static void render_container_simple_border_normal(struct sway_output *output, | 323 | static 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 | */ | ||
388 | static 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; |
480 | static 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) { | 552 | static 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 | ||
549 | static void render_container(struct sway_output *output, | 574 | static 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 | ||
602 | static 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]; | 627 | static 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 | |||
700 | static 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 | */ |
749 | static void render_container_tabbed(struct sway_output *output, | 688 | static 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 | */ | ||
796 | static void render_container_stacked(struct sway_output *output, | ||
797 | pixman_region32_t *damage, struct sway_container *con) { | ||
798 | // TODO | ||
799 | } | ||
800 | |||
801 | static void render_container(struct sway_output *output, | 740 | static 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, |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 8aebc0cc..b8e07bca 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 = config->font_height + 8; |
93 | parent_height -= parent_offset; | 92 | } else if (parent->parent->layout == L_STACKED) { |
93 | parent_offset = (config->font_height + 8) | ||
94 | * 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 = config->font_height + 8; |
139 | parent_height -= parent_offset; | 140 | } else if (parent->parent->layout == L_STACKED) { |
141 | parent_offset = (config->font_height + 8) | ||
142 | * 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 | ||
193 | static 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 | |||
189 | void arrange_children_of(struct sway_container *parent) { | 206 | void 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/view.c b/sway/tree/view.c index c013e635..1280dc8d 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 = config->font_height + 8; |
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 = (config->font_height + 8) |
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 + config->font_height + 8; |
222 | + y_offset; | 222 | height = view->swayc->height - config->font_height - 8 |
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 | } |