From 3a4b55886d2691680bd6859ef30d91435b1f46b3 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 02:07:40 +0200 Subject: [PATCH] src/view.c: Convert SnapToEdge to use view_apply_xxx_geometry framework --- include/labwc.h | 1 + src/interactive.c | 1 + src/view.c | 230 +++++++++++++++++++++++++--------------------- 3 files changed, 128 insertions(+), 104 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index be6a629d..7fc0e0a5 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -306,6 +306,7 @@ struct view { bool been_mapped; bool minimized; bool maximized; + uint32_t tiled; /* private, enum view_edge in src/view.c */ struct wlr_output *fullscreen; /* geometry of the wlr_surface contained within the view */ diff --git a/src/interactive.c b/src/interactive.c index 8ade121a..c7dab3dc 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -40,6 +40,7 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) return; } } + view->tiled = 0; /* * This function sets up an interactive move or resize operation, where diff --git a/src/view.c b/src/view.c index e82dd6d3..8c3938fb 100644 --- a/src/view.c +++ b/src/view.c @@ -10,6 +10,89 @@ #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +/** + * All view_apply_xxx_geometry() functions must *not* modify + * any state besides repositioning or resizing the view. + * + * They may be called repeatably during output layout changes. + */ + +enum view_edge { + VIEW_EDGE_INVALID = 0, + + VIEW_EDGE_LEFT, + VIEW_EDGE_RIGHT, + VIEW_EDGE_UP, + VIEW_EDGE_DOWN, + VIEW_EDGE_CENTER, +}; + +static enum view_edge +view_edge_invert(enum view_edge edge) +{ + switch (edge) { + case VIEW_EDGE_LEFT: + return VIEW_EDGE_RIGHT; + case VIEW_EDGE_RIGHT: + return VIEW_EDGE_LEFT; + case VIEW_EDGE_UP: + return VIEW_EDGE_DOWN; + case VIEW_EDGE_DOWN: + return VIEW_EDGE_UP; + case VIEW_EDGE_CENTER: + case VIEW_EDGE_INVALID: + default: + return VIEW_EDGE_INVALID; + } +} + +static struct wlr_box +view_get_edge_snap_box(struct view *view, struct output *output, + enum view_edge edge) +{ + struct wlr_box usable = output_usable_area_in_layout_coords(output); + if (usable.height == output->wlr_output->height + && output->wlr_output->scale != 1) { + usable.height /= output->wlr_output->scale; + } + if (usable.width == output->wlr_output->width + && output->wlr_output->scale != 1) { + usable.width /= output->wlr_output->scale; + } + + int x_offset = edge == VIEW_EDGE_RIGHT + ? (usable.width + rc.gap) / 2 : rc.gap; + int y_offset = edge == VIEW_EDGE_DOWN + ? (usable.height + rc.gap) / 2 : rc.gap; + + int base_width, base_height; + switch (edge) { + case VIEW_EDGE_LEFT: + case VIEW_EDGE_RIGHT: + base_width = (usable.width - 3 * rc.gap) / 2; + base_height = usable.height - 2 * rc.gap; + break; + case VIEW_EDGE_UP: + case VIEW_EDGE_DOWN: + base_width = usable.width - 2 * rc.gap; + base_height = (usable.height - 3 * rc.gap) / 2; + break; + default: + case VIEW_EDGE_CENTER: + base_width = usable.width - 2 * rc.gap; + base_height = usable.height - 2 * rc.gap; + break; + } + struct wlr_box dst = { + .x = x_offset + usable.x + view->margin.left, + .y = y_offset + usable.y + view->margin.top, + .width = base_width - view->margin.left - view->margin.right, + .height = base_height - view->margin.top - view->margin.bottom, + }; + + return dst; +} + void view_set_activated(struct view *view, bool activated) { @@ -185,6 +268,27 @@ view_center(struct view *view) } } +static void +view_apply_tiled_geometry(struct view *view, struct output *output) +{ + assert(view->tiled); + if (!output) { + output = view_output(view); + } + if (!output) { + wlr_log(WLR_ERROR, "Can't tile: no output"); + return; + } + + struct wlr_box dst = view_get_edge_snap_box(view, output, view->tiled); + if (view->w == dst.width && view->h == dst.height) { + /* move horizontally/vertically without changing size */ + view_move(view, dst.x, dst.y); + } else { + view_move_resize(view, dst); + } +} + static void view_apply_fullscreen_geometry(struct view *view, struct wlr_output *wlr_output) { @@ -515,35 +619,6 @@ view_move_to_edge(struct view *view, const char *direction) view_move(view, x, y); } -enum view_edge { - VIEW_EDGE_INVALID, - - VIEW_EDGE_LEFT, - VIEW_EDGE_RIGHT, - VIEW_EDGE_UP, - VIEW_EDGE_DOWN, - VIEW_EDGE_CENTER, -}; - -static enum view_edge -view_edge_invert(enum view_edge edge) -{ - switch (edge) { - case VIEW_EDGE_LEFT: - return VIEW_EDGE_RIGHT; - case VIEW_EDGE_RIGHT: - return VIEW_EDGE_LEFT; - case VIEW_EDGE_UP: - return VIEW_EDGE_DOWN; - case VIEW_EDGE_DOWN: - return VIEW_EDGE_UP; - case VIEW_EDGE_CENTER: - case VIEW_EDGE_INVALID: - default: - return VIEW_EDGE_INVALID; - } -} - static enum view_edge view_edge_parse(const char *direction) { @@ -565,53 +640,6 @@ view_edge_parse(const char *direction) } } -static struct wlr_box -view_get_edge_snap_box(struct view *view, struct output *output, - enum view_edge edge) -{ - struct wlr_box usable = output_usable_area_in_layout_coords(output); - if (usable.height == output->wlr_output->height - && output->wlr_output->scale != 1) { - usable.height /= output->wlr_output->scale; - } - if (usable.width == output->wlr_output->width - && output->wlr_output->scale != 1) { - usable.width /= output->wlr_output->scale; - } - - int x_offset = edge == VIEW_EDGE_RIGHT - ? (usable.width + rc.gap) / 2 : rc.gap; - int y_offset = edge == VIEW_EDGE_DOWN - ? (usable.height + rc.gap) / 2 : rc.gap; - - int base_width, base_height; - switch (edge) { - case VIEW_EDGE_LEFT: - case VIEW_EDGE_RIGHT: - base_width = (usable.width - 3 * rc.gap) / 2; - base_height = usable.height - 2 * rc.gap; - break; - case VIEW_EDGE_UP: - case VIEW_EDGE_DOWN: - base_width = usable.width - 2 * rc.gap; - base_height = (usable.height - 3 * rc.gap) / 2; - break; - default: - case VIEW_EDGE_CENTER: - base_width = usable.width - 2 * rc.gap; - base_height = usable.height - 2 * rc.gap; - break; - } - struct wlr_box dst = { - .x = x_offset + usable.x + view->margin.left, - .y = y_offset + usable.y + view->margin.top, - .width = base_width - view->margin.left - view->margin.right, - .height = base_height - view->margin.top - view->margin.bottom, - }; - - return dst; -} - void view_snap_to_edge(struct view *view, const char *direction) { @@ -630,50 +658,44 @@ view_snap_to_edge(struct view *view, const char *direction) return; } - struct wlr_box dst = view_get_edge_snap_box(view, output, edge); - - if (view->x == dst.x && view->y == dst.y && view->w == dst.width - && view->h == dst.height) { - /* Move over to the next screen if this is already snapped. */ - struct wlr_box usable = - output_usable_area_in_layout_coords(output); + if (view->tiled == edge) { + /* We are already tiled for this edge and thus should switch outputs */ + struct wlr_output *new_output = NULL; + struct wlr_output *current_output = output->wlr_output; + struct wlr_output_layout *layout = view->server->output_layout; switch (edge) { case VIEW_EDGE_LEFT: - dst.x -= (usable.width / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_LEFT, current_output, 1, 0); break; case VIEW_EDGE_RIGHT: - dst.x += (usable.width / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_RIGHT, current_output, 1, 0); break; case VIEW_EDGE_UP: - dst.y -= (usable.height / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_UP, current_output, 0, 1); break; case VIEW_EDGE_DOWN: - dst.y += (usable.height / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_DOWN, current_output, 0, 1); break; default: break; } - - struct wlr_output *new_wlr_output = wlr_output_layout_output_at( - view->server->output_layout, dst.x, dst.y); - struct output *new_output = - output_from_wlr_output(view->server, new_wlr_output); - - if (new_output == output || !new_output - || edge == VIEW_EDGE_CENTER) { + if (new_output && new_output != current_output) { + /* Move to next output */ + edge = view_edge_invert(edge); + output = output_from_wlr_output(view->server, new_output); + } else { + /* No more output to move to */ return; } - - dst = view_get_edge_snap_box(view, new_output, - view_edge_invert(edge)); } - if (view->w == dst.width && view->h == dst.height) { - /* move horizontally/vertically without changing size */ - view_move(view, dst.x, dst.y); - } else { - view_move_resize(view, dst); - } + /* TODO: store old geometry if !maximized && !fullscreen && !tiled */ + view->tiled = edge; + view_apply_tiled_geometry(view, output); } const char *