diff --git a/include/container.h b/include/container.h index fd621490d..35b93802e 100644 --- a/include/container.h +++ b/include/container.h @@ -2,8 +2,8 @@ #define _SWAY_CONTAINER_H #include typedef struct sway_container swayc_t; - #include "layout.h" +#include "focus.h" enum swayc_types{ C_ROOT, @@ -78,10 +78,15 @@ swayc_t *destroy_container(swayc_t *container); // parent swayc_t *destroy_view(swayc_t *view); +// Container info +bool swayc_is_fullscreen(swayc_t *view); + // Container Lookup 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 *swayc_by_direction(swayc_t *container, enum movement_direction dir); 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..10f6ecbfa 100644 --- a/include/layout.h +++ b/include/layout.h @@ -25,8 +25,4 @@ void unfocus_all(swayc_t *container); 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/commands.c b/sway/commands.c index 3ac7f4dd4..f9ff9d911 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -294,36 +294,39 @@ static bool cmd_focus(struct sway_config *config, int argc, char **argv) { } else if (strcasecmp(argv[0], "mode_toggle") == 0) { int i; swayc_t *focused = get_focused_view(active_workspace); - if (focused->is_floating) { - if (active_workspace->children->length > 0) { - for (i = 0;i < active_workspace->floating->length; i++) { - if (active_workspace->floating->items[i] == focused) { - floating_toggled_index = i; - break; + // Dont change focus if fullscreen + if (!swayc_is_fullscreen(focused)) { + if (focused->is_floating) { + if (active_workspace->children->length > 0) { + for (i = 0;i < active_workspace->floating->length; i++) { + if (active_workspace->floating->items[i] == focused) { + floating_toggled_index = i; + break; + } + } + if (active_workspace->children->length > tiled_toggled_index) { + set_focused_container(get_focused_view(active_workspace->children->items[tiled_toggled_index])); + } else { + set_focused_container(get_focused_view(active_workspace->children->items[0])); + tiled_toggled_index = 0; } } - if (active_workspace->children->length > tiled_toggled_index) { - set_focused_container(get_focused_view(active_workspace->children->items[tiled_toggled_index])); - } else { - set_focused_container(get_focused_view(active_workspace->children->items[0])); - tiled_toggled_index = 0; - } - } - } else { - if (active_workspace->floating->length > 0) { - for (i = 0;i < active_workspace->children->length; i++) { - if (active_workspace->children->items[i] == focused) { - tiled_toggled_index = i; - break; + } else { + if (active_workspace->floating->length > 0) { + for (i = 0;i < active_workspace->children->length; i++) { + if (active_workspace->children->items[i] == focused) { + tiled_toggled_index = i; + break; + } + } + if (active_workspace->floating->length > floating_toggled_index) { + swayc_t *floating = active_workspace->floating->items[floating_toggled_index]; + set_focused_container(get_focused_view(floating)); + } else { + swayc_t *floating = active_workspace->floating->items[active_workspace->floating->length - 1]; + set_focused_container(get_focused_view(floating)); + tiled_toggled_index = active_workspace->floating->length - 1; } - } - if (active_workspace->floating->length > floating_toggled_index) { - swayc_t *floating = active_workspace->floating->items[floating_toggled_index]; - set_focused_container(get_focused_view(floating)); - } else { - swayc_t *floating = active_workspace->floating->items[active_workspace->floating->length - 1]; - set_focused_container(get_focused_view(floating)); - tiled_toggled_index = active_workspace->floating->length - 1; } } } @@ -442,6 +445,9 @@ static bool _do_split(struct sway_config *config, int argc, char **argv, int lay } swayc_t *focused = get_focused_container(&root_container); + if (focused->is_floating) { + return true; + } if (focused->type == C_WORKSPACE && focused->children->length <= 1) { /* Case that focus is on an workspace with 0/1 children.change its layout */ sway_log(L_DEBUG, "changing workspace layout"); @@ -505,17 +511,15 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) { return false; } + //get focused view and check current state. swayc_t *container = get_focused_view(&root_container); - bool current = (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) > 0; + bool current = swayc_is_fullscreen(container); wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); - // Resize workspace if going from fullscreen -> notfullscreen - // otherwise just resize container - if (current) { - container = swayc_parent_by_type(container, C_WORKSPACE); + // Resize workspace + container = swayc_parent_by_type(container, C_WORKSPACE); + if (container) { + arrange_windows(container, -1, -1); } - // Only resize container when going into fullscreen - arrange_windows(container, -1, -1); - return true; } diff --git a/sway/container.c b/sway/container.c index 7ccc2e098..f92612164 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,14 +32,16 @@ static void free_swayc(swayc_t *cont) { if (!ASSERT_NONNULL(cont)) { return; } - // TODO does not properly handle containers with children, - // TODO but functions that call this usually check for that + sway_log(L_DEBUG, "destroying container %p, handle:%ld",cont, cont->handle); + if (cont->handle) { + wlc_handle_set_user_data(cont->handle, 0); + } + // Destroy all children if (cont->children) { - if (cont->children->length) { - int i; - for (i = 0; i < cont->children->length; ++i) { - free_swayc(cont->children->items[i]); - } + // children remove themselves from parent, so continue until theres no + // more children + while (cont->children->length) { + free_swayc(cont->children->items[0]); } list_free(cont->children); } @@ -58,7 +66,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 +74,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); @@ -101,9 +107,12 @@ swayc_t *new_output(wlc_handle handle) { // create and initilize default workspace swayc_t *ws = new_workspace(output, ws_name); ws->is_focused = true; + if (!active_workspace) { + active_workspace = ws; + } free(ws_name); - + return output; } @@ -112,13 +121,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(); @@ -128,10 +138,10 @@ swayc_t *new_workspace(swayc_t *output, const char *name) { } swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { - if (!ASSERT_NONNULL(child)) { + if (!ASSERT_NONNULL(child) || child->is_floating) { 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 +187,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 +217,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,19 +249,20 @@ 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; } if (output->children->length == 0) { // TODO move workspaces to other outputs } - sway_log(L_DEBUG, "OUTPUT: Destroying output '%lu'", output->handle); + sway_log(L_DEBUG, "%s:'%lu'", __func__, output->handle); free_swayc(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,12 +285,12 @@ 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; } while (container->children->length == 0 && container->type == C_CONTAINER) { - sway_log(L_DEBUG, "Container: Destroying container '%p'", container); + sway_log(L_DEBUG, "%s: '%p'", __func__, container); swayc_t *parent = container->parent; free_swayc(container); container = parent; @@ -289,11 +298,11 @@ 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; } - sway_log(L_DEBUG, "Destroying view '%p'", view); + sway_log(L_DEBUG, "%s: '%p'", __func__, view); swayc_t *parent = view->parent; free_swayc(view); @@ -303,6 +312,15 @@ swayc_t *destroy_view(swayc_t *view) { } return parent; } +#undef DESTROY_FUNC + +// Container info function + +bool swayc_is_fullscreen(swayc_t *view) { + return view + && view->type == C_VIEW + && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN); +} // Container lookup @@ -332,6 +350,61 @@ 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 *swayc_by_direction(swayc_t *container, enum movement_direction dir) { + swayc_t *parent = container->parent; + + if (dir == MOVE_PARENT) { + if (parent->type == C_OUTPUT) { + return NULL; + } else { + return parent; + } + } + while (true) { + // Test if we can even make a difference here + bool can_move = false; + int diff = 0; + if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { + if (parent->layout == L_HORIZ || parent->type == C_ROOT) { + can_move = true; + diff = dir == MOVE_LEFT ? -1 : 1; + } + } else { + if (parent->layout == L_VERT) { + can_move = true; + diff = dir == MOVE_UP ? -1 : 1; + } + } + if (can_move) { + int i; + for (i = 0; i < parent->children->length; ++i) { + swayc_t *child = parent->children->items[i]; + if (child == container) { + break; + } + } + int desired = i + diff; + if (desired < 0 || desired >= parent->children->length) { + can_move = false; + } else { + return parent->children->items[desired]; + } + } + if (!can_move) { + container = parent; + parent = parent->parent; + if (!parent) { + // Nothing we can do + return NULL; + } + } + } +} + swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { if (!container->children) { return NULL; @@ -398,10 +471,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/focus.c b/sway/focus.c index 5008dbbf0..6b2f8a7dc 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -54,8 +54,8 @@ static void update_focus(swayc_t *c) { } bool move_focus(enum movement_direction direction) { - swayc_t *view = get_swayc_in_direction( - get_focused_container(&root_container), direction); + swayc_t *view = get_focused_container(&root_container); + view = swayc_by_direction(view, direction); if (view) { if (direction == MOVE_PARENT) { set_focused_container(view); @@ -84,10 +84,16 @@ void set_focused_container(swayc_t *c) { return; } sway_log(L_DEBUG, "Setting focus to %p:%ld", c, c->handle); - - // Find previous focused view, and the new focused view, if they are the same return - swayc_t *focused = get_focused_view(&root_container); - swayc_t *workspace = active_workspace; + // Get workspace for c, get that workspaces current focused container. + // if that focsued container is fullscreen dont change focus + swayc_t *workspace = c; + if (workspace->type != C_WORKSPACE) { + workspace = swayc_parent_by_type(c, C_WORKSPACE); + } + swayc_t *focused = get_focused_view(workspace); + if (active_workspace == workspace && swayc_is_fullscreen(focused)) { + return; + } // update container focus from here to root, making necessary changes along // the way @@ -101,13 +107,6 @@ void set_focused_container(swayc_t *c) { p->is_focused = false; } - // if the workspace is the same, and previous focus is fullscreen, dont - // change focus - if (workspace == active_workspace - && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { - return; - } - // get new focused view and set focus to it. p = get_focused_view(c); if (p->type == C_VIEW && !(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) { @@ -137,6 +136,15 @@ void set_focused_container_for(swayc_t *a, swayc_t *c) { return; } } + + // Get workspace for c, get that workspaces current focused container. + // if that focsued container is fullscreen dont change focus + swayc_t *workspace = swayc_parent_by_type(c, C_WORKSPACE); + swayc_t *focused = get_focused_view(workspace); + if (swayc_is_fullscreen(focused)) { + return; + } + // Check if we changing a parent container that will see chnage bool effective = true; while (find != &root_container) { diff --git a/sway/handlers.c b/sway/handlers.c index 79628fe5c..7ba55cba6 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 @@ -420,10 +420,7 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct } } if (config->focus_follows_mouse && prev_handle != handle) { - // Dont change focus if fullscreen - swayc_t *focused = get_focused_view(view); - if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) - && !(pointer_state.l_held || pointer_state.r_held)) { + if (!(pointer_state.l_held || pointer_state.r_held)) { set_focused_container(container_under_pointer()); } } @@ -451,7 +448,7 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) { swayc_t *focused = get_focused_container(&root_container); // dont change focus if fullscreen - if (focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { + if (swayc_is_fullscreen(focused)) { return false; } if (state == WLC_BUTTON_STATE_PRESSED) { @@ -516,7 +513,6 @@ static void handle_wlc_ready(void) { config->active = true; } - struct wlc_interface interface = { .output = { .created = handle_output_created, @@ -544,3 +540,4 @@ struct wlc_interface interface = { .ready = handle_wlc_ready } }; + diff --git a/sway/layout.c b/sway/layout.c index 8c011fdb5..33acbe6ac 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -15,9 +15,11 @@ void init_layout(void) { root_container.type = C_ROOT; root_container.layout = L_NONE; root_container.children = create_list(); - root_container.handle = -1; + root_container.handle = 0; } +// Children of container functions + static int index_child(swayc_t *parent, swayc_t *child) { int i; for (i = 0; i < parent->children->length; ++i) { @@ -35,7 +37,8 @@ void add_child(swayc_t *parent, swayc_t *child) { child->parent = parent; // set focus for this container if (parent->children->length == 1) { - set_focused_container_for(parent, child); + parent->focused = child; + set_focused_container_for(parent, get_focused_view(parent)); } } @@ -46,7 +49,7 @@ void add_floating(swayc_t *ws, swayc_t *child) { child->parent = ws; child->is_floating = true; if (!ws->focused) { - set_focused_container_for(ws, child); + ws->focused = child; } } @@ -71,7 +74,7 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) { new_child->parent = child->parent; if (child->parent->focused == child) { - set_focused_container_for(child->parent, new_child); + child->parent->focused = new_child; } child->parent = NULL; return parent; @@ -100,267 +103,274 @@ swayc_t *remove_child(swayc_t *child) { // Set focused to new container if (parent->focused == child) { if (parent->children->length > 0) { - set_focused_container_for(parent, parent->children->items[i?i-1:0]); + parent->focused = parent->children->items[i?i-1:0]; } else { parent->focused = NULL; } } + child->parent = NULL; return parent; } - -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 = { +// Fitting functions +#define FIT_FUNC __attribute__((nonnull)) static void +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; + } + 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; } - - // 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); - } - } - } - } - } - layout_log(&root_container, 0); } -swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) { - if (parent->children == NULL) { - return NULL; +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); } - - // 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; - - if (dir == MOVE_PARENT) { - if (parent->type == C_OUTPUT) { - return NULL; - } else { - return parent; - } +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); } - while (true) { - // Test if we can even make a difference here - bool can_move = false; - int diff = 0; - if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { - if (parent->layout == L_HORIZ || parent->type == C_ROOT) { - can_move = true; - diff = dir == MOVE_LEFT ? -1 : 1; - } - } else { - if (parent->layout == L_VERT) { - can_move = true; - diff = dir == MOVE_UP ? -1 : 1; - } +} + +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; + } + + // 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); + sway_log(L_DEBUG,"putting %ld below %ld", 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; } - if (can_move) { - int i; - for (i = 0; i < parent->children->length; ++i) { - swayc_t *child = parent->children->items[i]; - if (child == container) { - break; - } - } - int desired = i + diff; - if (desired < 0 || desired >= parent->children->length) { - can_move = false; + // Update current top, send it below previous bottom, and set new bottom + top = order_children(*child, bottom); + wlc_view_send_below(top, bottom); + sway_log(L_DEBUG,"putting %ld below %ld", bottom, top); + 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->floating->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; + // Send focused view to front or back if fullscreen depending on tofront + if (!focused->is_floating && swayc_is_fullscreen(focused)) { + if (tofront) { + wlc_view_bring_to_front(focused->handle); + sway_log(L_DEBUG,"bring %ld to front (fullscreen)", focused->handle); + // we dont want to bring floating windows above fullscreen + // window + tofront = false; } else { - return parent->children->items[desired]; + wlc_view_send_to_back(focused->handle); } } - if (!can_move) { - container = parent; - parent = parent->parent; - if (!parent) { - // Nothing we can do - return NULL; + for (i = 0; i < len; ++i, ++child) { + if (tofront) { + wlc_view_bring_to_front((*child)->handle); + sway_log(L_DEBUG,"bring %ld to front (floating)", focused->handle); + } else { + wlc_view_send_to_back((*child)->handle); + sway_log(L_DEBUG,"sending %ld to back (floating)", focused->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; +} + 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) { diff --git a/sway/workspace.c b/sway/workspace.c index d436da8e2..ce626de4a 100644 --- a/sway/workspace.c +++ b/sway/workspace.c @@ -182,5 +182,5 @@ void workspace_switch(swayc_t *workspace) { } sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); set_focused_container(get_focused_view(workspace)); - arrange_windows(workspace, -1, -1); + arrange_windows(workspace->parent, -1, -1); }