Implement pointer-constraints protocol in wlroots and rootston

This commit is contained in:
Las 2018-08-10 18:19:16 +02:00
parent 437f538772
commit fa2e6e7d9d
23 changed files with 1134 additions and 20 deletions

View file

@ -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;
}
}