diff options
| author | Las <las@protonmail.ch> | 2018-08-10 18:19:16 +0200 | 
|---|---|---|
| committer | Las <las@protonmail.ch> | 2018-09-18 10:14:33 +0200 | 
| commit | fa2e6e7d9d5ffbd782063c89e460a915b29d4a58 (patch) | |
| tree | 219c3ff57b4430b7840e7b71684a5deec36bcf70 /util | |
| parent | 437f5387728703aca859f6fcec021a700472be33 (diff) | |
| download | wlroots-fa2e6e7d9d5ffbd782063c89e460a915b29d4a58.tar.xz | |
Implement pointer-constraints protocol in wlroots and rootston
Diffstat (limited to 'util')
| -rw-r--r-- | util/region.c | 71 | 
1 files changed, 71 insertions, 0 deletions
| 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 <assert.h>  #include <math.h> +#include <limits.h>  #include <stdlib.h> +#include <wlr/types/wlr_box.h>  #include <wlr/util/region.h>  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; +	} +} | 
