From b93f0686110274a29ea012476f2c0d17968fb1c1 Mon Sep 17 00:00:00 2001 From: taiyu Date: Thu, 20 Aug 2015 16:12:35 -0700 Subject: [PATCH] proper view ordering --- include/container.h | 1 + include/layout.h | 1 - sway/container.c | 48 +++-- sway/handlers.c | 12 +- sway/layout.c | 413 ++++++++++++++++++++++++-------------------- sway/log.c | 3 +- 6 files changed, 269 insertions(+), 209 deletions(-) diff --git a/include/container.h b/include/container.h index fd621490d..66d8d81d5 100644 --- a/include/container.h +++ b/include/container.h @@ -82,6 +82,7 @@ swayc_t *destroy_view(swayc_t *view); swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); +swayc_t *swayc_by_handle(wlc_handle handle); swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); diff --git a/include/layout.h b/include/layout.h index 75e72d2fe..5d1f11acd 100644 --- a/include/layout.h +++ b/include/layout.h @@ -26,7 +26,6 @@ void focus_view(swayc_t *view); void focus_view_for(swayc_t *ancestor, swayc_t *container); swayc_t *get_focused_container(swayc_t *parent); -swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent); swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir); #endif diff --git a/sway/container.c b/sway/container.c index 7ccc2e098..054e1e49d 100644 --- a/sway/container.c +++ b/sway/container.c @@ -11,11 +11,17 @@ #define ASSERT_NONNULL(PTR) \ sway_assert (PTR, "%s: " #PTR "must be non-null", __func__) -static swayc_t *new_swayc(enum swayc_types type) { +static swayc_t *new_swayc(enum swayc_types type, wlc_handle handle) { swayc_t *c = calloc(1, sizeof(swayc_t)); - c->handle = -1; + if (handle > 0) { + c->handle = handle; + wlc_handle_set_user_data(handle, c); + } else { + c->handle = 0; + } c->layout = L_NONE; c->type = type; + c->gaps = 0; if (type != C_VIEW) { c->children = create_list(); } @@ -26,6 +32,9 @@ static void free_swayc(swayc_t *cont) { if (!ASSERT_NONNULL(cont)) { return; } + if (cont->handle > 0) { + wlc_handle_set_user_data(cont->handle, 0); + } // TODO does not properly handle containers with children, // TODO but functions that call this usually check for that if (cont->children) { @@ -58,7 +67,7 @@ static void free_swayc(swayc_t *cont) { // New containers static bool workspace_test(swayc_t *view, void *name) { - return strcasecmp(view->name, (char *)name) == 0; + return strcasecmp(view->name, name) == 0; } swayc_t *new_output(wlc_handle handle) { @@ -66,12 +75,10 @@ swayc_t *new_output(wlc_handle handle) { const char *name = wlc_output_get_name(handle); sway_log(L_DEBUG, "Added output %lu:%s", handle, name); - swayc_t *output = new_swayc(C_OUTPUT); + swayc_t *output = new_swayc(C_OUTPUT, handle); output->width = size->w; output->height = size->h; - output->handle = handle; output->name = name ? strdup(name) : NULL; - output->gaps = config->gaps_outer + config->gaps_inner / 2; add_child(&root_container, output); @@ -112,13 +119,14 @@ swayc_t *new_workspace(swayc_t *output, const char *name) { return NULL; } sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle); - swayc_t *workspace = new_swayc(C_WORKSPACE); + swayc_t *workspace = new_swayc(C_WORKSPACE, 0); workspace->layout = L_HORIZ; // TODO: default layout workspace->x = output->x; workspace->y = output->y; workspace->width = output->width; workspace->height = output->height; + workspace->gaps = config->gaps_outer; workspace->name = strdup(name); workspace->visible = true; workspace->floating = create_list(); @@ -131,7 +139,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { if (!ASSERT_NONNULL(child)) { return NULL; } - swayc_t *cont = new_swayc(C_CONTAINER); + swayc_t *cont = new_swayc(C_CONTAINER, 0); sway_log(L_DEBUG, "creating container %p around %p", cont, child); @@ -177,11 +185,10 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { return NULL; } const char *title = wlc_view_get_title(handle); - swayc_t *view = new_swayc(C_VIEW); + swayc_t *view = new_swayc(C_VIEW, handle); sway_log(L_DEBUG, "Adding new view %lu:%s to container %p %d", handle, title, sibling, sibling ? sibling->type : 0); // Setup values - view->handle = handle; view->name = title ? strdup(title) : NULL; view->visible = true; view->is_focused = true; @@ -208,11 +215,10 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { swayc_t *new_floating_view(wlc_handle handle) { const char *title = wlc_view_get_title(handle); - swayc_t *view = new_swayc(C_VIEW); + swayc_t *view = new_swayc(C_VIEW, handle); sway_log(L_DEBUG, "Adding new view %lu:%x:%s as a floating view", handle, wlc_view_get_type(handle), title); // Setup values - view->handle = handle; view->name = title ? strdup(title) : NULL; view->visible = true; @@ -241,7 +247,8 @@ swayc_t *new_floating_view(wlc_handle handle) { // Destroy container -swayc_t *destroy_output(swayc_t *output) { +#define DESTROY_FUNC __attribute__((nonnull)) swayc_t * +DESTROY_FUNC destroy_output(swayc_t *output) { if (!ASSERT_NONNULL(output)) { return NULL; } @@ -253,7 +260,7 @@ swayc_t *destroy_output(swayc_t *output) { return &root_container; } -swayc_t *destroy_workspace(swayc_t *workspace) { +DESTROY_FUNC destroy_workspace(swayc_t *workspace) { if (!ASSERT_NONNULL(workspace)) { return NULL; } @@ -276,7 +283,7 @@ swayc_t *destroy_workspace(swayc_t *workspace) { return NULL; } -swayc_t *destroy_container(swayc_t *container) { +DESTROY_FUNC destroy_container(swayc_t *container) { if (!ASSERT_NONNULL(container)) { return NULL; } @@ -289,7 +296,7 @@ swayc_t *destroy_container(swayc_t *container) { return container; } -swayc_t *destroy_view(swayc_t *view) { +DESTROY_FUNC destroy_view(swayc_t *view) { if (!ASSERT_NONNULL(view)) { return NULL; } @@ -303,6 +310,7 @@ swayc_t *destroy_view(swayc_t *view) { } return parent; } +#undef DESTROY_FUNC // Container lookup @@ -332,6 +340,11 @@ swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts layout) { return container; } +swayc_t *swayc_by_handle(wlc_handle handle) { + return wlc_handle_get_user_data(handle); +} + + swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { if (!container->children) { return NULL; @@ -398,10 +411,11 @@ void reset_gaps(swayc_t *view, void *data) { if (!ASSERT_NONNULL(view)) { return; } - if (view->type == C_OUTPUT) { + if (view->type == C_WORKSPACE) { view->gaps = config->gaps_outer; } if (view->type == C_VIEW) { view->gaps = config->gaps_inner; } } + diff --git a/sway/handlers.c b/sway/handlers.c index 79628fe5c..85c500be5 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -113,7 +113,7 @@ static void handle_output_destroyed(wlc_handle output) { static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); - swayc_t *c = get_swayc_for_handle(output, &root_container); + swayc_t *c = swayc_by_handle(output); if (!c) return; c->width = to->w; c->height = to->h; @@ -121,7 +121,7 @@ static void handle_output_resolution_change(wlc_handle output, const struct wlc_ } static void handle_output_focused(wlc_handle output, bool focus) { - swayc_t *c = get_swayc_for_handle(output, &root_container); + swayc_t *c = swayc_by_handle(output); // if for some reason this output doesnt exist, create it. if (!c) { handle_output_created(output); @@ -139,7 +139,7 @@ static bool handle_view_created(wlc_handle handle) { // Get parent container, to add view in if (parent) { - focused = get_swayc_for_handle(parent, &root_container); + focused = swayc_by_handle(parent); } if (!focused || focused->type == C_OUTPUT) { focused = get_focused_container(&root_container); @@ -196,7 +196,7 @@ static bool handle_view_created(wlc_handle handle) { static void handle_view_destroyed(wlc_handle handle) { sway_log(L_DEBUG, "Destroying window %lu", handle); - swayc_t *view = get_swayc_for_handle(handle, &root_container); + swayc_t *view = swayc_by_handle(handle); switch (wlc_view_get_type(handle)) { // regular view created regularly @@ -230,7 +230,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo // If the view is floating, then apply the geometry. // Otherwise save the desired width/height for the view. // This will not do anything for the time being as WLC improperly sends geometry requests - swayc_t *view = get_swayc_for_handle(handle, &root_container); + swayc_t *view = swayc_by_handle(handle); if (view) { view->desired_width = geometry->size.w; view->desired_height = geometry->size.h; @@ -246,7 +246,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo } static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { - swayc_t *c = get_swayc_for_handle(view, &root_container); + swayc_t *c = swayc_by_handle(view); switch (state) { case WLC_BIT_FULLSCREEN: // i3 just lets it become fullscreen diff --git a/sway/layout.c b/sway/layout.c index 8c011fdb5..3cd716e95 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -18,6 +18,8 @@ void init_layout(void) { root_container.handle = -1; } +// Children of container functions + static int index_child(swayc_t *parent, swayc_t *child) { int i; for (i = 0; i < parent->children->length; ++i) { @@ -108,211 +110,254 @@ swayc_t *remove_child(swayc_t *child) { return parent; } +// Fitting functions +#define FIT_FUNC __attribute__((nonnull)) static void -void arrange_windows(swayc_t *container, int width, int height) { - int i; - if (width == -1 || height == -1) { - sway_log(L_DEBUG, "Arranging layout for %p", container); - width = container->width; - height = container->height; - } - - int x = 0, y = 0; - switch (container->type) { - case C_ROOT: - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - sway_log(L_DEBUG, "Arranging output at %d", x); - child->x = x; - child->y = y; - arrange_windows(child, -1, -1); - // Removed for now because wlc works with relative positions - // Addition can be reconsidered once wlc positions are changed - // x += child->width; - } - return; - case C_OUTPUT: - container->width = width; - container->height = height; - // These lines make x/y negative and result in stuff glitching out - // Their addition can be reconsidered once wlc positions are changed - // x -= container->x; - // y -= container->y; - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - child->x = x + container->gaps; - child->y = y + container->gaps; - child->width = width - container->gaps * 2; - child->height = height - container->gaps * 2; - sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y); - arrange_windows(child, -1, -1); - } - return; - case C_VIEW: - { - struct wlc_geometry geometry = { +FIT_FUNC _fit_view(swayc_t *view) { + sway_log(L_DEBUG, "%s:%p: (%dx%d@%dx%d)", __func__, view, + view->width, view->height, view->x, view->y); + struct wlc_geometry geo; + if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { + swayc_t *op = swayc_parent_by_type(view, C_OUTPUT); + geo = (struct wlc_geometry){ + .origin = { .x = 0, .y = 0 }, + .size = { .w = op->width, .h = op->height } + }; + } else { + if (view->is_floating) { + geo = (struct wlc_geometry){ .origin = { - .x = container->x + container->gaps / 2, - .y = container->y + container->gaps / 2 + .x = view->x, + .y = view->y, }, - .size = { - .w = width - container->gaps, - .h = height - container->gaps + .size = { + .w = view->width, + .h = view->height, } }; - if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { - swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT); - geometry.origin.x = 0; - geometry.origin.y = 0; - geometry.size.w = parent->width; - geometry.size.h = parent->height; - wlc_view_set_geometry(container->handle, 0, &geometry); - wlc_view_bring_to_front(container->handle); - } else { - wlc_view_set_geometry(container->handle, 0, &geometry); - container->width = width; - container->height = height; + } else { + geo = (struct wlc_geometry){ + .origin = { + .x = view->x + view->gaps / 2, + .y = view->y + view->gaps / 2, + }, + .size = { + .w = view->width - view->gaps, + .h = view->height - view->gaps + } + }; + } + } + wlc_view_set_geometry(view->handle, 0, &geo); +} + +FIT_FUNC _fit_container(swayc_t *container) { + sway_log(L_DEBUG, "%s:%p: (%dx%d@%dx%d)", __func__, container, + container->width, container->height, container->x, container->y); + swayc_t **child = (swayc_t **)container->children->items; + int i, len = container->children->length; + // geometry + int x = container->x; + int y = container->y; + int w = container->width; + int h = container->height; + // scaling + double s = 0; + switch (container->layout) { + default: + case L_HORIZ: + // Find scaling amount required to fit children in parent + for (i = 0; i < len; ++i, ++child) { + int *prev_w = &(*child)->width; + if (*prev_w <= 0) { + *prev_w = w / (len > 1 ? len - 1 : 1); } - sway_log(L_DEBUG, "Set view to %d x %d @ %d, %d", geometry.size.w, geometry.size.h, - geometry.origin.x, geometry.origin.y); + s += *prev_w; + } + sway_log(L_DEBUG,"s:%f",s); + if (s < 0.001) { + return; + } + s = w / s; + child = (swayc_t **)container->children->items; + for (i = 0; i < len; ++i, ++child) { + // Set geometry + (*child)->x = x; + (*child)->y = y; + // Scale width to fit in container + (*child)->width *= s; + (*child)->height = h; + // Increment x offset + x += (*child)->width; + // Recursibly resize children, depending on its type + ((*child)->type == C_VIEW ? _fit_view : _fit_container)(*child); } return; - default: - container->width = width; - container->height = height; - break; - } - x = y = 0; - double scale = 0; - switch (container->layout) { - case L_HORIZ: - default: - // Calculate total width - for (i = 0; i < container->children->length; ++i) { - int *old_width = &((swayc_t *)container->children->items[i])->width; - if (*old_width <= 0) { - if (container->children->length > 1) { - *old_width = width / (container->children->length - 1); - } else { - *old_width = width; - } - } - scale += *old_width; - } - // Resize windows - if (scale > 0.1) { - scale = width / scale; - sway_log(L_DEBUG, "Arranging %p horizontally", container); - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, width, scale); - child->x = x + container->x; - child->y = y + container->y; - arrange_windows(child, child->width * scale, height); - x += child->width; - } - } - break; case L_VERT: - // Calculate total height - for (i = 0; i < container->children->length; ++i) { - int *old_height = &((swayc_t *)container->children->items[i])->height; - if (*old_height <= 0) { - if (container->children->length > 1) { - *old_height = height / (container->children->length - 1); - } else { - *old_height = height; - } + // Find scaling amount required to fit children in parent + for (i = 0; i < len; ++i, ++child) { + int *prev_h = &(*child)->height; + if (*prev_h <= 0) { + *prev_h = h / (len > 1 ? len - 1 : 1); } - scale += *old_height; + s += *prev_h; } - // Resize - if (scale > 0.1) { - scale = height / scale; - sway_log(L_DEBUG, "Arranging %p vertically", container); - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %d by %f)", child, child->type, height, scale); - child->x = x + container->x; - child->y = y + container->y; - arrange_windows(child, width, child->height * scale); - y += child->height; - } + if (s < 0.001) { + return; } - break; + s = h / s; + child = (swayc_t **)container->children->items; + for (i = 0; i < len; ++i, ++child) { + // Set geometry + (*child)->x = x; + (*child)->y = y; + // Scale height to fit in container + (*child)->height *= s; + (*child)->width = w; + // Increment y offset + y += (*child)->height; + // Recursibly resize children, depending on its type + ((*child)->type == C_VIEW ? _fit_view : _fit_container)(*child); + } + return; + } +} + +FIT_FUNC _fit_workspace(swayc_t *workspace) { + workspace->x += workspace->gaps; + workspace->y += workspace->gaps; + workspace->width -= workspace->gaps * 2; + workspace->height -= workspace->gaps * 2; + sway_log(L_DEBUG, "%s:%p: (%dx%d@%dx%d)", __func__, workspace, + workspace->width, workspace->height, workspace->x,workspace->y); + // workspace is treated same as container for tiling + _fit_container(workspace); + // Handle floating containers + swayc_t **child = (swayc_t **)workspace->floating->items; + int i, len = workspace->floating->length; + for (i = 0; i < len; ++i, ++child) { + // Fit floating depending on view + ((*child)->type == C_VIEW ? _fit_view : _fit_container)(*child); + } +} + +FIT_FUNC _fit_output(swayc_t *output) { + sway_log(L_DEBUG, "%s:%p: (%dx%d@%dx%d)", __func__, output, output->width, + output->height, output->x,output->y); + swayc_t **child = (swayc_t **)output->children->items; + int i, len = output->children->length; + int x = output->x; + int y = output->y; + int w = output->width; + int h = output->height; + for (i = 0; i < len; ++i, ++child) { + // Set geometry with gaps + (*child)->x = x; + (*child)->y = y; + (*child)->width = w; + (*child)->height = h; + // recursivly fit children + _fit_workspace(*child); + } +} + +FIT_FUNC _fit_root(swayc_t *root) { + sway_log(L_DEBUG, "%s:%p: (%dx%d@%dx%d)", __func__, root, root->width, + root->height, root->x,root->y); + swayc_t **child = (swayc_t **)root->children->items; + int i, len = root->children->length; + for (i = 0; i < len; ++i, ++child) { + (*child)->x = 0; + (*child)->y = 0; + _fit_output(*child); + } +} + +FIT_FUNC fit_children_in(swayc_t *swayc) { + switch (swayc->type) { + case C_ROOT: _fit_root(swayc); return; + case C_WORKSPACE: swayc = swayc->parent; + case C_OUTPUT: _fit_output(swayc); return; + case C_VIEW: swayc = swayc->parent; + case C_CONTAINER: _fit_container(swayc); return; + default: sway_assert(false, "%s: invalid type", __func__); + } +} +#undef FIT_FUNC + +__attribute__((nonnull)) static wlc_handle order_children(swayc_t *swayc, wlc_handle top) { + // return handle + if (swayc->type == C_VIEW) { + return swayc->handle; + } + // return if no focus + if (swayc->focused == NULL) { + return 0; } - // Arrage floating layouts for workspaces last - if (container->type == C_WORKSPACE) { - for (i = 0; i < container->floating->length; ++i) { - swayc_t *view = container->floating->items[i]; - if (view->type == C_VIEW) { - // Set the geometry - struct wlc_geometry geometry = { - .origin = { - .x = view->x, - .y = view->y - }, - .size = { - .w = view->width, - .h = view->height - } - }; - if (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN) { - swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT); - geometry.origin.x = 0; - geometry.origin.y = 0; - geometry.size.w = parent->width; - geometry.size.h = parent->height; - wlc_view_set_geometry(view->handle, 0, &geometry); - wlc_view_bring_to_front(view->handle); - } else { - wlc_view_set_geometry(view->handle, 0, &geometry); - // Bring the views to the front in order of the list, the list - // will be kept up to date so that more recently focused views - // have higher indexes - // This is conditional on there not being a fullscreen view in the workspace - if (!container->focused - || !(wlc_view_get_state(container->focused->handle) & WLC_BIT_FULLSCREEN)) { - wlc_view_bring_to_front(view->handle); - } - } + // TODO fix floating implementation. + // Recurse and get handle of focused container + wlc_handle bottom = order_children(swayc->focused, top); + + // TODO Used properly in workspace case + wlc_handle topmost = bottom; + (void) topmost; + + // Put handle below current top, or if there is no top, set it as bottom + if (top) { + wlc_view_send_below(bottom, top); + } else { + top = bottom; + } + + // recurse for all children with the current bottom handle as their top. + int i, len = swayc->children->length; + swayc_t **child = (swayc_t **)swayc->children->items; + for (i = 0; i < len; ++i, ++child) { + // Skip over the focused child + if (*child == swayc->focused) { + continue; + } + // Update current top, send it below previous bottom, and set new bottom + top = order_children(*child, bottom); + wlc_view_send_below(top, bottom); + bottom = top; + } + + // TODO fix floating implementation. + // If we are at a workspace, put floating containers above topmost + if (swayc->type == C_WORKSPACE) { + // TODO using the same hacky implementation as before. + // send floating windows to front + len = swayc->children->length; + child = (swayc_t **)swayc->floating->items; + + // chekc whether to send floating windows to the back or front + swayc_t *focused = get_focused_view(swayc); + bool tofront = swayc->parent->focused == swayc || (focused->type == C_VIEW + && (wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)); + for (i = 0; i < len; ++i) { + if (tofront) { + wlc_view_bring_to_front((*child)->handle); + } else { + wlc_view_send_to_back((*child)->handle); } } } + // Return the bottom of this, which shall be the top of others, + return bottom; +} + +// Arrange layout + +void arrange_windows(swayc_t *container, int width, int height) { + fit_children_in(container); + order_children(container, 0); layout_log(&root_container, 0); + return; } -swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) { - if (parent->children == NULL) { - return NULL; - } - - // Search for floating workspaces - int i; - if (parent->type == C_WORKSPACE) { - for (i = 0; i < parent->floating->length; ++i) { - swayc_t *child = parent->floating->items[i]; - if (child->handle == handle) { - return child; - } - } - } - - for (i = 0; i < parent->children->length; ++i) { - swayc_t *child = parent->children->items[i]; - if (child->handle == handle) { - return child; - } else { - swayc_t *res; - if ((res = get_swayc_for_handle(handle, child))) { - return res; - } - } - } - return NULL; -} swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) { swayc_t *parent = container->parent; diff --git a/sway/log.c b/sway/log.c index 6e01421bc..5fe32f07c 100644 --- a/sway/log.c +++ b/sway/log.c @@ -16,7 +16,7 @@ static const char *verbosity_colors[] = { "", // L_SILENT "\x1B[1;31m", // L_ERROR "\x1B[1;34m", // L_INFO - "\x1B[1;30m", // L_DEBUG + "\x1B[1;32m", // L_DEBUG }; void init_log(int verbosity) { @@ -151,6 +151,7 @@ static void container_log(const swayc_t *c) { void layout_log(const swayc_t *c, int depth) { int i, d; int e = c->children ? c->children->length : 0; + if (L_DEBUG > v) return; container_log(c); if (e) { for (i = 0; i < e; ++i) {