From 0db3b9309bce5eca478781c3b5af3324e5db990b Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Thu, 18 Sep 2025 21:39:30 +0100 Subject: [PATCH 1/4] libsfdo.wrap: update revision to v0.1.4 --- subprojects/libsfdo.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/libsfdo.wrap b/subprojects/libsfdo.wrap index 22df1d6a..d05264db 100644 --- a/subprojects/libsfdo.wrap +++ b/subprojects/libsfdo.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://gitlab.freedesktop.org/vyivel/libsfdo.git -revision = v0.1.3 +revision = v0.1.4 [provide] dependency_names = libsfdo-basedir, libsfdo-desktop, libsfdo-icon From af6a0df2311fa8b38c532285b3868a649f7998f5 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Mon, 15 Sep 2025 03:54:40 +0900 Subject: [PATCH 2/4] view: remove an obsolete code in view_snap_to_edge() We no longer need to call view_apply_tiled_geometry() there, since we now clear view->tiled when dragging a tiled window since 9f51384. --- src/view.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/view.c b/src/view.c index 97616cbc..13b36a54 100644 --- a/src/view.c +++ b/src/view.c @@ -2145,17 +2145,7 @@ view_snap_to_edge(struct view *view, enum lab_edge edge, if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) { /* We are already tiled for this edge; try to switch outputs */ output = output_get_adjacent(view->output, edge, /* wrap */ false); - if (!output) { - /* - * No more output to move to - * - * We re-apply the tiled geometry without changing any - * state because the window might have been moved away - * (and thus got untiled) and then snapped back to the - * original edge. - */ - view_apply_tiled_geometry(view); return; } From 2ac48116e14491abec2326e70190a32192df6764 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Fri, 5 Sep 2025 12:14:52 +0900 Subject: [PATCH 3/4] action: allow SnapToEdge to combine two cardinal directions This patch adds `combine` argument to (Toggle)SnapToEdge actions. This allows to snap a window to e.g. up-left by running two actions: - `` - `` Then running `` snaps it to left again. This behavior is almost the same as KWin, except that snapping a up-right-tiled window to right doesn't move it to the right-adjacent output, but makes it right-tiled first. --- docs/labwc-actions.5.scd | 17 +++++++++----- include/view.h | 2 +- src/action.c | 22 +++++++++++------- src/interactive.c | 5 ++--- src/view.c | 48 ++++++++++++++++++++++++++++++++-------- 5 files changed, 68 insertions(+), 26 deletions(-) diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index 4879873d..4a76a374 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -92,11 +92,18 @@ Actions are used in menus and keyboard/mouse bindings. Move window relative to its current position. Positive value of x moves it right, negative left. Positive value of y moves it down, negative up. -**++ -** - Resize window to fill half the output in the given direction. Supports - directions "left", "up", "right", "down", "up-left", "up-right", "down-left", - "down-right" and "center". +**++ +** + Resize window to fill half or quarter the output in the given direction. + + *direction* [up|down|left|right|up-left|up-right|down-left|down-right|center] + Direction in which to snap the window. + + *combine* [yes|no] + Allows to snap a window to an output corner by combining two + directions. For example, snapping a window to *right* and then + to *up* places it in the *up-right* quarter of the output. + Default is no. ToggleSnapToEdge additionally toggles the active window between tiled to the given direction and its untiled position. diff --git a/include/view.h b/include/view.h index 5ff70984..efdcf3fd 100644 --- a/include/view.h +++ b/include/view.h @@ -548,7 +548,7 @@ void view_move_to_edge(struct view *view, enum lab_edge direction, bool snap_to_ void view_grow_to_edge(struct view *view, enum lab_edge direction); void view_shrink_to_edge(struct view *view, enum lab_edge direction); void view_snap_to_edge(struct view *view, enum lab_edge direction, - bool across_outputs, bool store_natural_geometry); + bool across_outputs, bool combine, bool store_natural_geometry); void view_snap_to_region(struct view *view, struct region *region, bool store_natural_geometry); void view_move_to_output(struct view *view, struct output *output); diff --git a/src/action.c b/src/action.c index 60c57b33..ab9d3e18 100644 --- a/src/action.c +++ b/src/action.c @@ -337,11 +337,6 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char } break; case ACTION_TYPE_MOVE_TO_EDGE: - if (!strcasecmp(argument, "snapWindows")) { - action_arg_add_bool(action, argument, parse_bool(content, true)); - goto cleanup; - } - /* Falls through */ case ACTION_TYPE_TOGGLE_SNAP_TO_EDGE: case ACTION_TYPE_SNAP_TO_EDGE: case ACTION_TYPE_GROW_TO_EDGE: @@ -358,6 +353,17 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char } goto cleanup; } + if (action->type == ACTION_TYPE_MOVE_TO_EDGE + && !strcasecmp(argument, "snapWindows")) { + action_arg_add_bool(action, argument, parse_bool(content, true)); + goto cleanup; + } + if ((action->type == ACTION_TYPE_SNAP_TO_EDGE + || action->type == ACTION_TYPE_TOGGLE_SNAP_TO_EDGE) + && !strcasecmp(argument, "combine")) { + action_arg_add_bool(action, argument, parse_bool(content, false)); + goto cleanup; + } break; case ACTION_TYPE_SHOW_MENU: if (!strcmp(argument, "menu")) { @@ -1031,9 +1037,9 @@ run_action(struct view *view, struct server *server, struct action *action, view_apply_natural_geometry(view); break; } - view_snap_to_edge(view, edge, - /*across_outputs*/ true, - /*store_natural_geometry*/ true); + bool combine = action_get_bool(action, "combine", false); + view_snap_to_edge(view, edge, /*across_outputs*/ true, + combine, /*store_natural_geometry*/ true); } break; case ACTION_TYPE_GROW_TO_EDGE: diff --git a/src/interactive.c b/src/interactive.c index f9c7f771..8ca258c1 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -260,9 +260,8 @@ snap_to_edge(struct view *view) view_maximize(view, VIEW_AXIS_BOTH, /*store_natural_geometry*/ false); } else { - view_snap_to_edge(view, edge, - /*across_outputs*/ false, - /*store_natural_geometry*/ false); + view_snap_to_edge(view, edge, /*across_outputs*/ false, + /*combine*/ false, /*store_natural_geometry*/ false); } return true; diff --git a/src/view.c b/src/view.c index 13b36a54..e402b626 100644 --- a/src/view.c +++ b/src/view.c @@ -2126,7 +2126,7 @@ view_placement_parse(const char *policy) void view_snap_to_edge(struct view *view, enum lab_edge edge, - bool across_outputs, bool store_natural_geometry) + bool across_outputs, bool combine, bool store_natural_geometry) { assert(view); @@ -2142,15 +2142,45 @@ view_snap_to_edge(struct view *view, enum lab_edge edge, view_set_shade(view, false); - if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) { - /* We are already tiled for this edge; try to switch outputs */ - output = output_get_adjacent(view->output, edge, /* wrap */ false); - if (!output) { - return; - } + if (lab_edge_is_cardinal(edge) && view->maximized == VIEW_AXIS_NONE) { + enum lab_edge invert_edge = lab_edge_invert(edge); + /* Represents axis of snapping direction */ + enum lab_edge parallel_mask = edge | invert_edge; + /* + * The vector view->tiled is split to components + * parallel/orthogonal to snapping direction. For example, + * view->tiled=TOP_LEFT is split to parallel_tiled=TOP and + * orthogonal_tiled=LEFT when edge=TOP or edge=BOTTOM. + */ + enum lab_edge parallel_tiled = view->tiled & parallel_mask; + enum lab_edge orthogonal_tiled = view->tiled & ~parallel_mask; - /* When switching outputs, jump to the opposite edge */ - edge = lab_edge_invert(edge); + if (across_outputs && view->tiled == edge) { + /* + * E.g. when window is tiled to up and being snapped + * to up again, move it to the output above and tile + * it to down. + */ + output = output_get_adjacent(view->output, edge, + /* wrap */ false); + if (!output) { + return; + } + edge = invert_edge; + } else if (combine && parallel_tiled == invert_edge + && orthogonal_tiled != LAB_EDGE_NONE) { + /* + * E.g. when window is tiled to downleft/downright and + * being snapped to up, tile it to left/right. + */ + edge = view->tiled & ~parallel_mask; + } else if (combine && parallel_tiled == LAB_EDGE_NONE) { + /* + * E.g. when window is tiled to left/right and being + * snapped to up, tile it to upleft/upright. + */ + edge = view->tiled | edge; + } } if (view->maximized != VIEW_AXIS_NONE) { From 24f39e3a41b50cca3f0c26bada9295a3b39ded9e Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Wed, 17 Sep 2025 16:25:32 +0900 Subject: [PATCH 4/4] default-bindings.h: set combine="yes" for SnapToEdge keybinds --- docs/labwc-config.5.scd | 2 +- docs/rc.xml.all | 8 ++++---- include/config/default-bindings.h | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index a854d886..7ddf2d5b 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -727,7 +727,7 @@ extending outward from the snapped edge. W-Return - lab-sensible-terminal A-F4 - close window W-a - toggle maximize - W- - resize window to fill half the output + W- - resize window to fill half or quarter of the output A-Space - show window menu ``` diff --git a/docs/rc.xml.all b/docs/rc.xml.all index a96993ab..12d0c761 100644 --- a/docs/rc.xml.all +++ b/docs/rc.xml.all @@ -271,16 +271,16 @@ - + - + - + - + diff --git a/include/config/default-bindings.h b/include/config/default-bindings.h index 08caeade..9d42d237 100644 --- a/include/config/default-bindings.h +++ b/include/config/default-bindings.h @@ -35,6 +35,10 @@ static struct key_combos { .name = "direction", .value = "left", }, + .attributes[1] = { + .name = "combine", + .value = "yes", + }, }, { .binding = "W-Right", .action = "SnapToEdge", @@ -42,6 +46,10 @@ static struct key_combos { .name = "direction", .value = "right", }, + .attributes[1] = { + .name = "combine", + .value = "yes", + }, }, { .binding = "W-Up", .action = "SnapToEdge", @@ -49,6 +57,10 @@ static struct key_combos { .name = "direction", .value = "up", }, + .attributes[1] = { + .name = "combine", + .value = "yes", + }, }, { .binding = "W-Down", .action = "SnapToEdge", @@ -56,6 +68,10 @@ static struct key_combos { .name = "direction", .value = "down", }, + .attributes[1] = { + .name = "combine", + .value = "yes", + }, }, { .binding = "A-Space", .action = "ShowMenu",