mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
interactive: allow snapping to corner edges
In addition to <snapping><range>, <snapping><cornerRange> configures the distance from the screen corner to trigger quater window snapping. Also, new values "up-left", "up-right", "down-left" and "down-right" are allowed for <action name="(Toggle)SnapToEdge" direction="[value]"> and <query tiled="[value]">.
This commit is contained in:
parent
b0ff2911b6
commit
2f183cdcb6
14 changed files with 147 additions and 89 deletions
|
|
@ -4,22 +4,24 @@
|
|||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include "view.h"
|
||||
|
||||
enum wlr_direction
|
||||
direction_from_view_edge(enum view_edge edge)
|
||||
bool
|
||||
direction_from_view_edge(enum view_edge edge, enum wlr_direction *direction)
|
||||
{
|
||||
switch (edge) {
|
||||
case VIEW_EDGE_LEFT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
*direction = WLR_DIRECTION_LEFT;
|
||||
return true;
|
||||
case VIEW_EDGE_RIGHT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
*direction = WLR_DIRECTION_RIGHT;
|
||||
return true;
|
||||
case VIEW_EDGE_UP:
|
||||
return WLR_DIRECTION_UP;
|
||||
*direction = WLR_DIRECTION_UP;
|
||||
return true;
|
||||
case VIEW_EDGE_DOWN:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
case VIEW_EDGE_CENTER:
|
||||
case VIEW_EDGE_INVALID:
|
||||
*direction = WLR_DIRECTION_DOWN;
|
||||
return true;
|
||||
default:
|
||||
return WLR_DIRECTION_UP;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1175,6 +1175,8 @@ entry(xmlNode *node, char *nodename, char *content)
|
|||
rc.unmaximize_threshold = atoi(content);
|
||||
} else if (!strcasecmp(nodename, "range.snapping")) {
|
||||
rc.snap_edge_range = atoi(content);
|
||||
} else if (!strcasecmp(nodename, "cornerRange.snapping")) {
|
||||
rc.snap_edge_corner_range = atoi(content);
|
||||
} else if (!strcasecmp(nodename, "enabled.overlay.snapping")) {
|
||||
set_bool(content, &rc.snap_overlay_enabled);
|
||||
} else if (!strcasecmp(nodename, "inner.delay.overlay.snapping")) {
|
||||
|
|
@ -1411,6 +1413,7 @@ rcxml_init(void)
|
|||
rc.unmaximize_threshold = 150;
|
||||
|
||||
rc.snap_edge_range = 10;
|
||||
rc.snap_edge_corner_range = 50;
|
||||
rc.snap_overlay_enabled = true;
|
||||
rc.snap_overlay_delay_inner = 500;
|
||||
rc.snap_overlay_delay_outer = 500;
|
||||
|
|
|
|||
|
|
@ -164,22 +164,26 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
|
|||
}
|
||||
}
|
||||
|
||||
enum view_edge
|
||||
edge_from_cursor(struct seat *seat, struct output **dest_output)
|
||||
bool
|
||||
edge_from_cursor(struct seat *seat, struct output **dest_output,
|
||||
enum view_edge *edge1, enum view_edge *edge2)
|
||||
{
|
||||
*dest_output = NULL;
|
||||
*edge1 = VIEW_EDGE_INVALID;
|
||||
*edge2 = VIEW_EDGE_INVALID;
|
||||
|
||||
if (!view_is_floating(seat->server->grabbed_view)) {
|
||||
return VIEW_EDGE_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
int snap_range = rc.snap_edge_range;
|
||||
if (!snap_range) {
|
||||
return VIEW_EDGE_INVALID;
|
||||
if (rc.snap_edge_range == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct output *output = output_nearest_to_cursor(seat->server);
|
||||
if (!output_is_usable(output)) {
|
||||
wlr_log(WLR_ERROR, "output at cursor is unusable");
|
||||
return VIEW_EDGE_INVALID;
|
||||
return false;
|
||||
}
|
||||
*dest_output = output;
|
||||
|
||||
|
|
@ -190,18 +194,39 @@ edge_from_cursor(struct seat *seat, struct output **dest_output)
|
|||
output->wlr_output, &cursor_x, &cursor_y);
|
||||
|
||||
struct wlr_box *area = &output->usable_area;
|
||||
if (cursor_x <= area->x + snap_range) {
|
||||
return VIEW_EDGE_LEFT;
|
||||
} else if (cursor_x >= area->x + area->width - snap_range) {
|
||||
return VIEW_EDGE_RIGHT;
|
||||
} else if (cursor_y <= area->y + snap_range) {
|
||||
return VIEW_EDGE_UP;
|
||||
} else if (cursor_y >= area->y + area->height - snap_range) {
|
||||
return VIEW_EDGE_DOWN;
|
||||
|
||||
int top = cursor_y - area->y;
|
||||
int bottom = area->y + area->height - cursor_y;
|
||||
int left = cursor_x - area->x;
|
||||
int right = area->x + area->width - cursor_x;
|
||||
|
||||
if (top < rc.snap_edge_range) {
|
||||
*edge1 = VIEW_EDGE_UP;
|
||||
} else if (bottom < rc.snap_edge_range) {
|
||||
*edge1 = VIEW_EDGE_DOWN;
|
||||
} else if (left < rc.snap_edge_range) {
|
||||
*edge1 = VIEW_EDGE_LEFT;
|
||||
} else if (right < rc.snap_edge_range) {
|
||||
*edge1 = VIEW_EDGE_RIGHT;
|
||||
} else {
|
||||
/* Not close to any edge */
|
||||
return VIEW_EDGE_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*edge1 == VIEW_EDGE_UP || *edge1 == VIEW_EDGE_DOWN) {
|
||||
if (left < rc.snap_edge_corner_range) {
|
||||
*edge2 = VIEW_EDGE_LEFT;
|
||||
} else if (right < rc.snap_edge_corner_range) {
|
||||
*edge2 = VIEW_EDGE_RIGHT;
|
||||
}
|
||||
} else if (*edge1 == VIEW_EDGE_LEFT || *edge1 == VIEW_EDGE_RIGHT) {
|
||||
if (top < rc.snap_edge_corner_range) {
|
||||
*edge2 = VIEW_EDGE_UP;
|
||||
} else if (bottom < rc.snap_edge_corner_range) {
|
||||
*edge2 = VIEW_EDGE_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true if view was snapped to any edge */
|
||||
|
|
@ -209,10 +234,11 @@ static bool
|
|||
snap_to_edge(struct view *view)
|
||||
{
|
||||
struct output *output;
|
||||
enum view_edge edge = edge_from_cursor(&view->server->seat, &output);
|
||||
if (edge == VIEW_EDGE_INVALID) {
|
||||
enum view_edge edge1, edge2;
|
||||
if (!edge_from_cursor(&view->server->seat, &output, &edge1, &edge2)) {
|
||||
return false;
|
||||
}
|
||||
enum view_edge edge = edge1 | edge2;
|
||||
|
||||
view_set_output(view, output);
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -979,6 +979,11 @@ output_get_adjacent(struct output *output, enum view_edge edge, bool wrap)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
enum wlr_direction direction;
|
||||
if (!direction_from_view_edge(edge, &direction)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_box box = output_usable_area_in_layout_coords(output);
|
||||
int lx = box.x + box.width / 2;
|
||||
int ly = box.y + box.height / 2;
|
||||
|
|
@ -987,7 +992,6 @@ output_get_adjacent(struct output *output, enum view_edge edge, bool wrap)
|
|||
struct wlr_output *new_output = NULL;
|
||||
struct wlr_output *current_output = output->wlr_output;
|
||||
struct wlr_output_layout *layout = output->server->output_layout;
|
||||
enum wlr_direction direction = direction_from_view_edge(edge);
|
||||
new_output = wlr_output_layout_adjacent_output(layout, direction,
|
||||
current_output, lx, ly);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "overlay.h"
|
||||
#include <assert.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "common/direction.h"
|
||||
#include "common/lab-scene-rect.h"
|
||||
#include "labwc.h"
|
||||
#include "output.h"
|
||||
|
|
@ -137,42 +138,27 @@ handle_edge_overlay_timeout(void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static enum wlr_direction
|
||||
get_wlr_direction(enum view_edge edge)
|
||||
{
|
||||
switch (edge) {
|
||||
case VIEW_EDGE_LEFT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
case VIEW_EDGE_RIGHT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
case VIEW_EDGE_UP:
|
||||
case VIEW_EDGE_CENTER:
|
||||
return WLR_DIRECTION_UP;
|
||||
case VIEW_EDGE_DOWN:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
default:
|
||||
/* not reached */
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
edge_has_adjacent_output_from_cursor(struct seat *seat, struct output *output,
|
||||
enum view_edge edge)
|
||||
{
|
||||
enum wlr_direction dir;
|
||||
if (!direction_from_view_edge(edge, &dir)) {
|
||||
return false;
|
||||
}
|
||||
return wlr_output_layout_adjacent_output(
|
||||
seat->server->output_layout, get_wlr_direction(edge),
|
||||
seat->server->output_layout, dir,
|
||||
output->wlr_output, seat->cursor->x, seat->cursor->y);
|
||||
}
|
||||
|
||||
static void
|
||||
show_edge_overlay(struct seat *seat, enum view_edge edge,
|
||||
show_edge_overlay(struct seat *seat, enum view_edge edge1, enum view_edge edge2,
|
||||
struct output *output)
|
||||
{
|
||||
if (!rc.snap_overlay_enabled) {
|
||||
return;
|
||||
}
|
||||
uint32_t edge = edge1 | edge2;
|
||||
if (seat->overlay.active.edge == edge
|
||||
&& seat->overlay.active.output == output) {
|
||||
return;
|
||||
|
|
@ -182,7 +168,7 @@ show_edge_overlay(struct seat *seat, enum view_edge edge,
|
|||
seat->overlay.active.output = output;
|
||||
|
||||
int delay;
|
||||
if (edge_has_adjacent_output_from_cursor(seat, output, edge)) {
|
||||
if (edge_has_adjacent_output_from_cursor(seat, output, edge1)) {
|
||||
delay = rc.snap_overlay_delay_inner;
|
||||
} else {
|
||||
delay = rc.snap_overlay_delay_outer;
|
||||
|
|
@ -219,9 +205,9 @@ overlay_update(struct seat *seat)
|
|||
|
||||
/* Edge-snapping overlay */
|
||||
struct output *output;
|
||||
enum view_edge edge = edge_from_cursor(seat, &output);
|
||||
if (edge != VIEW_EDGE_INVALID) {
|
||||
show_edge_overlay(seat, edge, output);
|
||||
enum view_edge edge1, edge2;
|
||||
if (edge_from_cursor(seat, &output, &edge1, &edge2)) {
|
||||
show_edge_overlay(seat, edge1, edge2, output);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
52
src/view.c
52
src/view.c
|
|
@ -451,35 +451,29 @@ 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);
|
||||
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 x1 = rc.gap;
|
||||
int y1 = rc.gap;
|
||||
int x2 = usable.width - rc.gap;
|
||||
int y2 = usable.height - 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;
|
||||
if (edge & VIEW_EDGE_RIGHT) {
|
||||
x1 = (usable.width + rc.gap) / 2;
|
||||
}
|
||||
if (edge & VIEW_EDGE_LEFT) {
|
||||
x2 = (usable.width - rc.gap) / 2;
|
||||
}
|
||||
if (edge & VIEW_EDGE_DOWN) {
|
||||
y1 = (usable.height + rc.gap) / 2;
|
||||
}
|
||||
if (edge & VIEW_EDGE_UP) {
|
||||
y2 = (usable.height - rc.gap) / 2;
|
||||
}
|
||||
|
||||
struct wlr_box dst = {
|
||||
.x = x_offset + usable.x,
|
||||
.y = y_offset + usable.y,
|
||||
.width = base_width,
|
||||
.height = base_height,
|
||||
.x = x1 + usable.x,
|
||||
.y = y1 + usable.y,
|
||||
.width = x2 - x1,
|
||||
.height = y2 - y1,
|
||||
};
|
||||
|
||||
if (view) {
|
||||
|
|
@ -2149,6 +2143,14 @@ view_edge_parse(const char *direction, bool tiled, bool any)
|
|||
if (tiled) {
|
||||
if (!strcasecmp(direction, "center")) {
|
||||
return VIEW_EDGE_CENTER;
|
||||
} else if (!strcasecmp(direction, "up-left")) {
|
||||
return VIEW_EDGE_UPLEFT;
|
||||
} else if (!strcasecmp(direction, "up-right")) {
|
||||
return VIEW_EDGE_UPRIGHT;
|
||||
} else if (!strcasecmp(direction, "down-left")) {
|
||||
return VIEW_EDGE_DOWNLEFT;
|
||||
} else if (!strcasecmp(direction, "down-right")) {
|
||||
return VIEW_EDGE_DOWNRIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
13
src/xdg.c
13
src/xdg.c
|
|
@ -660,6 +660,19 @@ xdg_toplevel_view_notify_tiled(struct view *view)
|
|||
case VIEW_EDGE_DOWN:
|
||||
edge = WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT;
|
||||
break;
|
||||
case VIEW_EDGE_UPLEFT:
|
||||
edge = WLR_EDGE_TOP | WLR_EDGE_LEFT;
|
||||
break;
|
||||
case VIEW_EDGE_UPRIGHT:
|
||||
edge = WLR_EDGE_TOP | WLR_EDGE_RIGHT;
|
||||
break;
|
||||
case VIEW_EDGE_DOWNLEFT:
|
||||
edge = WLR_EDGE_BOTTOM | WLR_EDGE_LEFT;
|
||||
break;
|
||||
case VIEW_EDGE_DOWNRIGHT:
|
||||
edge = WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT;
|
||||
break;
|
||||
/* TODO: VIEW_EDGE_CENTER? */
|
||||
default:
|
||||
edge = WLR_EDGE_NONE;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue