From ce1936bc65d01502e3a5f8681bb039cb95e82e0c Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 25 Nov 2017 10:59:49 -0500 Subject: Arrange windows on desktop --- sway/tree/layout.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) (limited to 'sway/tree/layout.c') diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 5a70c570..3d6b404d 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -1,10 +1,14 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include +#include #include #include "sway/container.h" +#include "sway/output.h" +#include "sway/view.h" #include "list.h" #include "log.h" @@ -70,3 +74,204 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { void sort_workspaces(swayc_t *output) { list_stable_sort(output->children, sort_workspace_cmp_qsort); } + +static void apply_horiz_layout(swayc_t *container, const double x, + const double y, const double width, + const double height, const int start, + const int end); + +static void apply_vert_layout(swayc_t *container, const double x, + const double y, const double width, + const double height, const int start, + const int end); + +void arrange_windows(swayc_t *container, double width, double height) { + int i; + if (width == -1 || height == -1) { + width = container->width; + height = container->height; + } + // pixels are indivisible. if we don't round the pixels, then the view + // calculations will be off (e.g. 50.5 + 50.5 = 101, but in reality it's + // 50 + 50 = 100). doing it here cascades properly to all width/height/x/y. + width = floor(width); + height = floor(height); + + sway_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, + container->name, container->width, container->height, container->x, + container->y); + + double x = 0, y = 0; + switch (container->type) { + case C_ROOT: + // TODO: wlr_output_layout probably + for (i = 0; i < container->children->length; ++i) { + swayc_t *output = container->children->items[i]; + sway_log(L_DEBUG, "Arranging output '%s' at %f,%f", + output->name, output->x, output->y); + arrange_windows(output, -1, -1); + } + return; + case C_OUTPUT: + { + int _width, _height; + wlr_output_effective_resolution( + container->sway_output->wlr_output, &_width, &_height); + width = container->width = _width; + height = container->height = _height; + } + // arrange all workspaces: + for (i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + arrange_windows(child, -1, -1); + } + return; + case C_WORKSPACE: + { + swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); + width = output->width, height = output->height; + container->x = x; + container->y = y; + width = container->width; + height = container->height; + sway_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", + container->name, container->x, container->y); + } + // children are properly handled below + break; + case C_VIEW: + { + container->width = width; + container->height = height; + container->sway_view->iface.set_dimensions(container->sway_view, + container->width, container->height); + sway_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", + container->width, container->height, + container->x, container->y); + } + return; + default: + container->width = width; + container->height = height; + x = container->x; + y = container->y; + break; + } + + switch (container->layout) { + case L_HORIZ: + apply_horiz_layout(container, x, y, width, height, 0, + container->children->length); + break; + case L_VERT: + apply_vert_layout(container, x, y, width, height, 0, + container->children->length); + break; + default: + sway_log(L_DEBUG, "TODO: arrange layout type %d", container->layout); + apply_horiz_layout(container, x, y, width, height, 0, + container->children->length); + break; + } +} + +static void apply_horiz_layout(swayc_t *container, + const double x, const double y, + const double width, const double height, + const int start, const int end) { + double scale = 0; + // Calculate total width + for (int i = start; i < end; ++i) { + double *old_width = &((swayc_t *)container->children->items[i])->width; + if (*old_width <= 0) { + if (end - start > 1) { + *old_width = width / (end - start - 1); + } else { + *old_width = width; + } + } + scale += *old_width; + } + scale = width / scale; + + // Resize windows + double child_x = x; + if (scale > 0.1) { + sway_log(L_DEBUG, "Arranging %p horizontally", container); + for (int i = start; i < end; ++i) { + swayc_t *child = container->children->items[i]; + sway_log(L_DEBUG, + "Calculating arrangement for %p:%d (will scale %f by %f)", + child, child->type, width, scale); + child->x = child_x; + child->y = y; + + if (i == end - 1) { + double remaining_width = x + width - child_x; + arrange_windows(child, remaining_width, height); + } else { + arrange_windows(child, child->width * scale, height); + } + child_x += child->width; + } + + // update focused view border last because it may + // depend on the title bar geometry of its siblings. + /* TODO WLR + if (focused && container->children->length > 1) { + update_container_border(focused); + } + */ + } +} + +void apply_vert_layout(swayc_t *container, + const double x, const double y, + const double width, const double height, const int start, + const int end) { + int i; + double scale = 0; + // Calculate total height + for (i = start; i < end; ++i) { + double *old_height = &((swayc_t *)container->children->items[i])->height; + if (*old_height <= 0) { + if (end - start > 1) { + *old_height = height / (end - start - 1); + } else { + *old_height = height; + } + } + scale += *old_height; + } + scale = height / scale; + + // Resize + double child_y = y; + if (scale > 0.1) { + sway_log(L_DEBUG, "Arranging %p vertically", container); + for (i = start; i < end; ++i) { + swayc_t *child = container->children->items[i]; + sway_log(L_DEBUG, + "Calculating arrangement for %p:%d (will scale %f by %f)", + child, child->type, height, scale); + child->x = x; + child->y = child_y; + + if (i == end - 1) { + double remaining_height = y + height - child_y; + arrange_windows(child, width, remaining_height); + } else { + arrange_windows(child, width, child->height * scale); + } + child_y += child->height; + } + + // update focused view border last because it may + // depend on the title bar geometry of its siblings. + /* TODO WLR + if (focused && container->children->length > 1) { + update_container_border(focused); + } + */ + } +} -- cgit v1.2.3-54-g00ecf