From fa2e6e7d9d5ffbd782063c89e460a915b29d4a58 Mon Sep 17 00:00:00 2001 From: Las Date: Fri, 10 Aug 2018 18:19:16 +0200 Subject: Implement pointer-constraints protocol in wlroots and rootston --- util/region.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'util') diff --git a/util/region.c b/util/region.c index 38f84c5e..76df71f3 100644 --- a/util/region.c +++ b/util/region.c @@ -1,5 +1,8 @@ +#include #include +#include #include +#include #include void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src, @@ -177,3 +180,71 @@ void wlr_region_rotated_bounds(pixman_region32_t *dst, pixman_region32_t *src, pixman_region32_init_rects(dst, dst_rects, nrects); free(dst_rects); } + +static void region_confine(pixman_region32_t *region, double x1, double y1, double x2, + double y2, double *x2_out, double *y2_out, pixman_box32_t box) { + double x_clamped = fmax(fmin(x2, box.x2 - 1), box.x1); + double y_clamped = fmax(fmin(y2, box.y2 - 1), box.y1); + + // If the target coordinates are above box.{x,y}2 - 1, but less than + // box.{x,y}2, then they are still within the box. + if (floor(x_clamped) == floor(x2) && floor(y_clamped) == floor(y2)) { + *x2_out = x2; + *y2_out = y2; + return; + } + + double dx = x2 - x1; + double dy = y2 - y1; + + // We use fabs to avoid negative zeroes and thus avoid a bug + // with negative infinity. + double delta = fmin(fabs(x_clamped - x1) / fabs(dx), fabs(y_clamped - y1) / fabs(dy)); + + // We clamp it again due to precision errors. + double x = fmax(fmin(delta * dx + x1, box.x2 - 1), box.x1); + double y = fmax(fmin(delta * dy + y1, box.y2 - 1), box.y1); + + // Go one unit past the boundary to find an adjacent box. + int x_ext = floor(x) + (dx == 0 ? 0 : dx > 0 ? 1 : -1); + int y_ext = floor(y) + (dy == 0 ? 0 : dy > 0 ? 1 : -1); + + if (pixman_region32_contains_point(region, x_ext, y_ext, &box)) { + return region_confine(region, x1, y1, x2, y2, x2_out, y2_out, box); + } else if (dx == 0 || dy == 0) { + *x2_out = x; + *y2_out = y; + } else { + bool bordering_x = x == box.x1 || x == box.x2 - 1; + bool bordering_y = y == box.y1 || y == box.y2 - 1; + + if ((bordering_x && bordering_y) || (!bordering_x && !bordering_y)) { + double x2_potential, y2_potential; + double tmp1, tmp2; + region_confine(region, x, y, x, y2, &tmp1, &y2_potential, box); + region_confine(region, x, y, x2, y, &x2_potential, &tmp2, box); + if (fabs(x2_potential - x) > fabs(y2_potential - y)) { + *x2_out = x2_potential; + *y2_out = y; + } else { + *x2_out = x; + *y2_out = y2_potential; + } + } else if (bordering_x) { + return region_confine(region, x, y, x, y2, x2_out, y2_out, box); + } else if (bordering_y) { + return region_confine(region, x, y, x2, y, x2_out, y2_out, box); + } + } +} + +bool wlr_region_confine(pixman_region32_t *region, double x1, double y1, double x2, + double y2, double *x2_out, double *y2_out) { + pixman_box32_t box; + if (pixman_region32_contains_point(region, x1, y1, &box)) { + region_confine(region, x1, y1, x2, y2, x2_out, y2_out, box); + return true; + } else { + return false; + } +} -- cgit v1.2.3 From afa2e399aa9c19c250a03cce1cb466f54348a97a Mon Sep 17 00:00:00 2001 From: Las Date: Tue, 18 Sep 2018 13:05:44 +0200 Subject: Fix implicit conversion of floats to ints in calls to pixman_region32_contains_point I do not think the conversion is specifically defined, but on my system and SirCmpwn's the floats are rounded instead of floored, which is incorrect in this case, since for a range from 0 to 256, any value greater or equal to 0 and less than 256 is valid. I.e. [0;256[, or 0 <= x < 256, but if x is e.g. -0.1, then it will be rounded to 0, which is invalid. The correct behavior would be to floor to -1. --- rootston/cursor.c | 6 +++--- types/wlr_surface.c | 2 +- util/region.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'util') diff --git a/rootston/cursor.c b/rootston/cursor.c index 0aaff132..4ec600e1 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -381,7 +381,7 @@ void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor, if (cursor->active_constraint && !pixman_region32_contains_point(&cursor->confine, - lx - view->x, ly - view->y, NULL)) { + floor(lx - view->x), floor(ly - view->y), NULL)) { return; } } @@ -501,7 +501,7 @@ void roots_cursor_handle_tool_axis(struct roots_cursor *cursor, if (cursor->active_constraint && !pixman_region32_contains_point(&cursor->confine, - lx - view->x, ly - view->y, NULL)) { + floor(lx - view->x), floor(ly - view->y), NULL)) { return; } } @@ -602,7 +602,7 @@ void roots_cursor_constrain(struct roots_cursor *cursor, pixman_region32_t *region = &constraint->region; - if (!pixman_region32_contains_point(region, sx, sy, NULL)) { + if (!pixman_region32_contains_point(region, floor(sx), floor(sy), NULL)) { // Warp into region if possible int nboxes; pixman_box32_t *boxes = pixman_region32_rectangles(region, &nboxes); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 773de460..408f38d1 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -943,7 +943,7 @@ bool wlr_surface_point_accepts_input(struct wlr_surface *surface, double sx, double sy) { return sx >= 0 && sx < surface->current.width && sy >= 0 && sy < surface->current.height && - pixman_region32_contains_point(&surface->current.input, sx, sy, NULL); + pixman_region32_contains_point(&surface->current.input, floor(sx), floor(sy), NULL); } struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, diff --git a/util/region.c b/util/region.c index 76df71f3..61f9c7c7 100644 --- a/util/region.c +++ b/util/region.c @@ -241,7 +241,7 @@ static void region_confine(pixman_region32_t *region, double x1, double y1, doub bool wlr_region_confine(pixman_region32_t *region, double x1, double y1, double x2, double y2, double *x2_out, double *y2_out) { pixman_box32_t box; - if (pixman_region32_contains_point(region, x1, y1, &box)) { + if (pixman_region32_contains_point(region, floor(x1), floor(y1), &box)) { region_confine(region, x1, y1, x2, y2, x2_out, y2_out, box); return true; } else { -- cgit v1.2.3