diff --git a/examples/pointer.c b/examples/pointer.c index bae205f5..98b4735a 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -58,12 +58,20 @@ struct touch_point { double x, y; }; -static void warp_to_touch(struct sample_state *sample) { - wlr_log(L_DEBUG, "TODO: warp to touch"); +static void warp_to_touch(struct sample_state *sample, struct wlr_input_device *dev) { + if (sample->touch_points->length == 0) { + return; + } + + double x = 0, y = 0; for (size_t i = 0; i < sample->touch_points->length; ++i) { struct touch_point *point = sample->touch_points->items[i]; - wlr_log(L_DEBUG, "have point x=%f,y=%f", point->x, point->y); + x += point->x; + y += point->y; } + x /= sample->touch_points->length; + y /= sample->touch_points->length; + wlr_cursor_warp_absolute(sample->cursor, dev, x, y); } static void handle_output_frame(struct output_state *output, struct timespec *ts) { @@ -248,7 +256,7 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { } } - warp_to_touch(sample); + warp_to_touch(sample, event->device); } static void handle_touch_down(struct wl_listener *listener, void *data) { @@ -262,7 +270,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { free(point); } - warp_to_touch(sample); + warp_to_touch(sample, event->device); } static void handle_touch_motion(struct wl_listener *listener, void *data) { @@ -277,7 +285,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { } } - warp_to_touch(sample); + warp_to_touch(sample, event->device); } static void handle_touch_cancel(struct wl_listener *listener, void *data) { diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index ad5c52a4..4ba7b25f 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -46,6 +46,9 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur); bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, double x, double y); +void wlr_cursor_warp_absolute(struct wlr_cursor *cur, + struct wlr_input_device *dev, double x_mm, double y_mm); + /** * Move the cursor in the direction of the given x and y coordinates. * diff --git a/include/wlr/types/wlr_geometry.h b/include/wlr/types/wlr_geometry.h index 7ac2f843..cac75431 100644 --- a/include/wlr/types/wlr_geometry.h +++ b/include/wlr/types/wlr_geometry.h @@ -15,4 +15,6 @@ bool wlr_geometry_intersection(struct wlr_geometry *geo_a, bool wlr_geometry_contains_point(struct wlr_geometry *geo, int x, int y); +bool wlr_geometry_empty(struct wlr_geometry *geo); + #endif diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 144c2d5a..0d157f56 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -4,14 +4,20 @@ #include #include +struct wlr_output_layout_state; + struct wlr_output_layout { struct wl_list outputs; + struct wlr_output_layout_state *state; }; +struct wlr_output_layout_output_state; + struct wlr_output_layout_output { struct wlr_output *output; int x, y; struct wl_list link; + struct wlr_output_layout_output_state *state; }; struct wlr_output_layout *wlr_output_layout_init(); @@ -55,4 +61,11 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, struct wlr_output *reference, double x, double y, double *dest_x, double *dest_y); +/** + * Get the geometry of the layout for the given reference output. If `reference` + * is NULL, the geometry will be for the extents of the entire layout. + */ +struct wlr_geometry *wlr_output_layout_get_geometry( + struct wlr_output_layout *layout, struct wlr_output *reference); + #endif diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f9e1fcc9..f315727f 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,29 @@ static struct wlr_cursor_device *get_cursor_device(struct wlr_cursor *cur, return ret; } +static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, double x, double y) { + int hotspot_x = 0; + int hotspot_y = 0; + + if (cur->state->xcursor && cur->state->xcursor->image_count > 0) { + struct wlr_xcursor_image *image = cur->state->xcursor->images[0]; + hotspot_x = image->hotspot_x; + hotspot_y = image->hotspot_y; + } + + + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &cur->state->layout->outputs, link) { + double output_x = x; + double output_y = y; + + wlr_output_layout_output_coords(cur->state->layout, + l_output->output, &output_x, &output_y); + wlr_output_move_cursor(l_output->output, output_x - hotspot_x, + output_y - hotspot_y); + } +} + bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, double x, double y) { assert(cur->state->layout); @@ -120,30 +144,61 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, return false; } - int hotspot_x = 0; - int hotspot_y = 0; - - if (cur->state->xcursor && cur->state->xcursor->image_count > 0) { - struct wlr_xcursor_image *image = cur->state->xcursor->images[0]; - hotspot_x = image->hotspot_x; - hotspot_y = image->hotspot_y; - } - - - struct wlr_output_layout_output *l_output; - wl_list_for_each(l_output, &cur->state->layout->outputs, link) { - double output_x = x; - double output_y = y; - - wlr_output_layout_output_coords(cur->state->layout, - l_output->output, &output_x, &output_y); - wlr_output_move_cursor(l_output->output, output_x - hotspot_x, - output_y - hotspot_y); - } - + wlr_cursor_warp_unchecked(cur, x, y); return true; } +void wlr_cursor_warp_absolute(struct wlr_cursor *cur, + struct wlr_input_device *dev, double x_mm, double y_mm) { + // convert from absolute to global coordinates + assert(cur->state->layout); + struct wlr_output *mapped_output = NULL; + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + + if (c_device && c_device->mapped_output) { + mapped_output = c_device->mapped_output; + } else { + mapped_output = cur->state->mapped_output; + } + + struct wlr_geometry *constraints = calloc(1, sizeof(struct wlr_geometry)); + // XXX how do we express infinite regions? + constraints->x = INT_MIN / 2; + constraints->y = INT_MIN / 2; + constraints->width = INT_MAX; + constraints->height = INT_MAX; + + if (cur->state->mapped_geometry) { + wlr_geometry_intersection(cur->state->mapped_geometry, constraints, + &constraints); + } + if (c_device->mapped_geometry) { + wlr_geometry_intersection(c_device->mapped_geometry, constraints, + &constraints); + } + struct wlr_geometry *geo; + if (mapped_output) { + geo = wlr_output_layout_get_geometry(cur->state->layout, mapped_output); + wlr_geometry_intersection(geo, constraints, &constraints); + } + geo = wlr_output_layout_get_geometry(cur->state->layout, NULL); + wlr_geometry_intersection(geo, constraints, &constraints); + + if (wlr_geometry_empty(constraints)) { + goto out; + } + + double x = constraints->width * x_mm + constraints->x; + double y = constraints->height * y_mm + constraints->y; + + wlr_cursor_warp_unchecked(cur, x, y); + +out: + if (constraints) { + free(constraints); + } +} + void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, double delta_x, double delta_y) { assert(cur->state->layout); @@ -195,10 +250,9 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, goto out; } - if (wlr_cursor_warp(cur, dev, x, y)) { - cur->x = x; - cur->y = y; - } + wlr_cursor_warp_unchecked(cur, x, y); + cur->x = x; + cur->y = y; out: if (constraints) { diff --git a/types/wlr_geometry.c b/types/wlr_geometry.c index be4a80eb..32dbb81f 100644 --- a/types/wlr_geometry.c +++ b/types/wlr_geometry.c @@ -45,8 +45,8 @@ void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, #define min(a,b) ((a) < (b) ? (a) : (b)) #endif -static bool wlr_geometry_empty(struct wlr_geometry *geo) { - return geo == NULL || geo->width < 0 || geo->height < 0; +bool wlr_geometry_empty(struct wlr_geometry *geo) { + return geo == NULL || geo->width <= 0 || geo->height <= 0; } bool wlr_geometry_intersection(struct wlr_geometry *geo_a, @@ -55,20 +55,12 @@ bool wlr_geometry_intersection(struct wlr_geometry *geo_a, bool a_empty = wlr_geometry_empty(geo_a); bool b_empty = wlr_geometry_empty(geo_b); - if (a_empty && b_empty) { + if (a_empty || b_empty) { + dest->x = 0; + dest->y = 0; + dest->width = -100; + dest->height = -100; return false; - } else if (a_empty) { - dest->x = geo_b->x; - dest->y = geo_b->y; - dest->height = geo_b->height; - dest->width = geo_b->width; - return true; - } else if (b_empty) { - dest->x = geo_a->x; - dest->y = geo_a->y; - dest->height = geo_a->height; - dest->width = geo_a->width; - return true; } int x1 = max(geo_a->x, geo_b->x); diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 7dcb4651..0b5e0411 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -1,16 +1,35 @@ #include #include #include +#include #include #include #include +struct wlr_output_layout_state { + struct wlr_geometry *_geo; +}; + +struct wlr_output_layout_output_state { + struct wlr_geometry *_geo; +}; + struct wlr_output_layout *wlr_output_layout_init() { struct wlr_output_layout *layout = calloc(1, sizeof(struct wlr_output_layout)); + layout->state = calloc(1, sizeof(struct wlr_output_layout_state)); + layout->state->_geo = calloc(1, sizeof(struct wlr_geometry)); wl_list_init(&layout->outputs); return layout; } +static void wlr_output_layout_output_destroy( + struct wlr_output_layout_output *l_output) { + wl_list_remove(&l_output->link); + free(l_output->state->_geo); + free(l_output->state); + free(l_output); +} + void wlr_output_layout_destroy(struct wlr_output_layout *layout) { if (!layout) { return; @@ -18,20 +37,24 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { struct wlr_output_layout_output *_output, *temp = NULL; wl_list_for_each_safe(_output, temp, &layout->outputs, link) { - wl_list_remove(&_output->link); - free(_output); + wlr_output_layout_output_destroy(_output); } + free(layout->state->_geo); + free(layout->state); free(layout); } void wlr_output_layout_add(struct wlr_output_layout *layout, struct wlr_output *output, int x, int y) { - struct wlr_output_layout_output *layout_output = calloc(1, sizeof(struct wlr_output_layout_output)); - layout_output->output = output; - layout_output->x = x; - layout_output->y = y; - wl_list_insert(&layout->outputs, &layout_output->link); + struct wlr_output_layout_output *l_output; + l_output= calloc(1, sizeof(struct wlr_output_layout_output)); + l_output->state = calloc(1, sizeof(struct wlr_output_layout_output_state)); + l_output->state->_geo = calloc(1, sizeof(struct wlr_geometry)); + l_output->output = output; + l_output->x = x; + l_output->y = y; + wl_list_insert(&layout->outputs, &l_output->link); } struct wlr_output_layout_output *wlr_output_layout_get( @@ -104,11 +127,10 @@ void wlr_output_layout_move(struct wlr_output_layout *layout, void wlr_output_layout_remove(struct wlr_output_layout *layout, struct wlr_output *output) { - struct wlr_output_layout_output *layout_output = - wlr_output_layout_get(layout, output); - if (layout_output) { - wl_list_remove(&layout_output->link); - free(layout_output); + struct wlr_output_layout_output *l_output; + l_output= wlr_output_layout_get(layout, output); + if (l_output) { + wlr_output_layout_output_destroy(l_output); } } @@ -179,3 +201,46 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, *dest_x = min_x; *dest_y = min_y; } + +struct wlr_geometry *wlr_output_layout_get_geometry( + struct wlr_output_layout *layout, struct wlr_output *reference) { + struct wlr_output_layout_output *l_output; + if (reference) { + // output extents + l_output= wlr_output_layout_get(layout, reference); + l_output->state->_geo->x = l_output->x; + l_output->state->_geo->y = l_output->y; + wlr_output_effective_resolution(reference, + &l_output->state->_geo->width, &l_output->state->_geo->height); + return l_output->state->_geo; + } else { + // layout extents + int min_x = INT_MAX, min_y = INT_MAX; + int max_x = INT_MIN, max_y = INT_MIN; + wl_list_for_each(l_output, &layout->outputs, link) { + int width, height; + wlr_output_effective_resolution(l_output->output, &width, &height); + if (l_output->x < min_x) { + min_x = l_output->x; + } + if (l_output->y < min_y) { + min_y = l_output->y; + } + if (l_output->x + width > max_x) { + max_x = l_output->x + width; + } + if (l_output->y + height > max_y) { + max_y = l_output->y + height; + } + } + + layout->state->_geo->x = min_x; + layout->state->_geo->y = min_y; + layout->state->_geo->width = max_x - min_x; + layout->state->_geo->height = max_y - min_y; + + return layout->state->_geo; + } + + // not reached +}