mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-14 15:40:32 +01:00
Add a physical scale factor for the regions
This isn't something that libei itself uses but clients like synergy need to know about this to be able to map relative pointer motion from one host into the right physical pixel on another host. This is required for mutter in the x11-compat mode where a 4k screen is logically twice the size of a 2k screen, despite having the same physical size. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
56b82c2b8f
commit
6095a0d99f
12 changed files with 113 additions and 2 deletions
|
|
@ -183,6 +183,7 @@ message DeviceRegion {
|
|||
uint32 offset_y = 3;
|
||||
uint32 width = 4;
|
||||
uint32 height = 5;
|
||||
double scale = 6;
|
||||
}
|
||||
|
||||
message DeviceAddedDone {
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ struct ei_region {
|
|||
struct list link;
|
||||
uint32_t x, y;
|
||||
uint32_t width, height;
|
||||
double physical_scale;
|
||||
};
|
||||
|
||||
struct ei_device {
|
||||
|
|
@ -275,6 +276,9 @@ ei_region_set_size(struct ei_region *region, uint32_t w, uint32_t h);
|
|||
void
|
||||
ei_region_set_offset(struct ei_region *region, uint32_t x, uint32_t y);
|
||||
|
||||
void
|
||||
ei_region_set_physical_scale(struct ei_region *region, double scale);
|
||||
|
||||
bool
|
||||
ei_region_contains(struct ei_region *region, double x, double y);
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ ei_proto_parse_message(struct brei_message *bmsg, size_t *consumed)
|
|||
.device_region.y = r->offset_y,
|
||||
.device_region.w = r->width,
|
||||
.device_region.h = r->height,
|
||||
.device_region.scale = r->scale,
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ struct message {
|
|||
uint32_t y;
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
double scale;
|
||||
} device_region;
|
||||
struct message_device_removed {
|
||||
uint32_t deviceid;
|
||||
|
|
|
|||
|
|
@ -50,12 +50,16 @@ _public_
|
|||
OBJECT_IMPLEMENT_GETTER(ei_region, width, uint32_t);
|
||||
_public_
|
||||
OBJECT_IMPLEMENT_GETTER(ei_region, height, uint32_t);
|
||||
_public_
|
||||
OBJECT_IMPLEMENT_GETTER(ei_region, physical_scale, double);
|
||||
OBJECT_IMPLEMENT_SETTER(ei_region, physical_scale, double);
|
||||
|
||||
struct ei_region *
|
||||
ei_region_new(void)
|
||||
{
|
||||
struct ei_region *region = ei_region_create(NULL);
|
||||
|
||||
region->physical_scale = 1.0;
|
||||
list_init(®ion->link);
|
||||
|
||||
return region;
|
||||
|
|
|
|||
|
|
@ -597,7 +597,8 @@ handle_msg_device_added_done(struct ei *ei, uint32_t deviceid)
|
|||
static int
|
||||
handle_msg_device_region(struct ei *ei, uint32_t deviceid,
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t w, uint32_t h)
|
||||
uint32_t w, uint32_t h,
|
||||
double scale)
|
||||
{
|
||||
log_debug(ei, "Adding device region for %#x\n", deviceid);
|
||||
|
||||
|
|
@ -608,6 +609,7 @@ handle_msg_device_region(struct ei *ei, uint32_t deviceid,
|
|||
_unref_(ei_region) *r = ei_region_new();
|
||||
ei_region_set_offset(r, x, y);
|
||||
ei_region_set_size(r, w, h);
|
||||
ei_region_set_physical_scale(r, scale);
|
||||
|
||||
ei_device_add_region(device, r);
|
||||
|
||||
|
|
@ -894,7 +896,8 @@ connection_connected_handle_msg(struct ei *ei, struct message *msg)
|
|||
case MESSAGE_DEVICE_REGION:
|
||||
rc = handle_msg_device_region(ei, msg->device_region.deviceid,
|
||||
msg->device_region.x, msg->device_region.y,
|
||||
msg->device_region.w, msg->device_region.h);
|
||||
msg->device_region.w, msg->device_region.h,
|
||||
msg->device_region.scale);
|
||||
break;
|
||||
case MESSAGE_DEVICE_REMOVED:
|
||||
rc = handle_msg_device_removed(ei, msg->device_removed.deviceid);
|
||||
|
|
|
|||
70
src/libei.h
70
src/libei.h
|
|
@ -825,6 +825,76 @@ ei_region_get_width(struct ei_region *region);
|
|||
uint32_t
|
||||
ei_region_get_height(struct ei_region *region);
|
||||
|
||||
/**
|
||||
* Return the physical scale for this region. The default scale is 1.0.
|
||||
*
|
||||
* The regions' coordinate space is in logical pixels in the EIS range. The
|
||||
* logical pixels may or may not match the physical pixels on the output
|
||||
* range but the mapping from logical pixels to physical pixels is performed
|
||||
* by the EIS implementation.
|
||||
*
|
||||
* In some use-cases though, relative data from a remote input source needs
|
||||
* to be converted by the libei client into an absolute movement on an EIS
|
||||
* region. In that case, the physical scale provides the factor to multiply
|
||||
* the relative logical input to provide the expected physical relative
|
||||
* movement.
|
||||
*
|
||||
* For example consider the following dual-monitor setup comprising a 2k and
|
||||
* a 4k monitor **of the same physical size**:
|
||||
* The physical layout of the monitors appears like this:
|
||||
* @code
|
||||
* 2k 4k
|
||||
* +-------------++-------------+
|
||||
* | || |
|
||||
* | a b || c d |
|
||||
* | || |
|
||||
* +-------------++-------------+
|
||||
* @endcode
|
||||
*
|
||||
* The physical distance `ab` is the same as the physical distance `cd`.
|
||||
* Where the EIS implementation supports high-dpi screens, the logical
|
||||
* distance (in pixels) are identical too.
|
||||
*
|
||||
* Where the EIS implementation does not support high-dpi screens, the
|
||||
* logical layout of these two monitors appears like this:
|
||||
*
|
||||
* @code
|
||||
* 2k 4k
|
||||
* +-------------++--------------------------+
|
||||
* | || |
|
||||
* | a b || |
|
||||
* | || |
|
||||
* +-------------+| c d |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +--------------------------+
|
||||
* @endcode
|
||||
*
|
||||
* While the two physical distances `ab` and `cd` are still identical, the
|
||||
* logical distance `cd` (in pixels) is twice that of `ab`.
|
||||
* Where a libei client receives relative deltas from an input source and
|
||||
* converts that relative input into an absolute position on the screen, it
|
||||
* needs to take this into account.
|
||||
*
|
||||
* For example, if a remote input source moves by relative 100 logical
|
||||
* pixels, the libei client would convert this as `a + 100 = b` on the
|
||||
* region for the 2k screen and send the absolute events to logically change
|
||||
* the position from `a` to `b`. If the same remote input source moves by
|
||||
* relative 100 logical pixels, the libei client would convert this as
|
||||
* `c + 100 * scale = d` on the region for the 4k screen to logically
|
||||
* change the position from `c` to `d`. While the pixel movement differs,
|
||||
* the physical movement as seen by the user is thus identical.
|
||||
*
|
||||
* A second possible use-case for the physical scale is to match pixels from
|
||||
* one region to their respective counterpart on a different region.
|
||||
* For example, if the bottom-right corner of the 2k screen in the
|
||||
* illustration above has a coordinate of x/y, the neighbouring pixel on the
|
||||
* **physical** 4k screen is (0/y * scale).
|
||||
*/
|
||||
double
|
||||
ei_region_get_physical_scale(struct ei_region *region);
|
||||
|
||||
/**
|
||||
* Return the keymap for this device or `NULL`. The keymap is constant for
|
||||
* the lifetime of the device after the @ref EI_EVENT_DEVICE_ADDED was
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ struct eis_region {
|
|||
struct list link;
|
||||
uint32_t x, y;
|
||||
uint32_t width, height;
|
||||
double physical_scale;
|
||||
};
|
||||
|
||||
struct eis_device {
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ eis_proto_send_device_region(struct eis_client *client, struct eis_device *devic
|
|||
region.offset_y = r->y;
|
||||
region.width = r->width;
|
||||
region.height = r->height;
|
||||
region.scale = r->physical_scale;
|
||||
|
||||
msg.device_region = ®ion;
|
||||
msg.msg_case = SERVER_MESSAGE__MSG_DEVICE_REGION;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ eis_region_new(void)
|
|||
{
|
||||
struct eis_region *region = eis_region_create(NULL);
|
||||
|
||||
region->physical_scale = 1.0;
|
||||
list_init(®ion->link);
|
||||
|
||||
return region;
|
||||
|
|
@ -67,6 +68,13 @@ eis_region_set_size(struct eis_region *region, uint32_t w, uint32_t h)
|
|||
region->height = h;
|
||||
}
|
||||
|
||||
_public_ void
|
||||
eis_region_set_physical_scale(struct eis_region *region, double scale)
|
||||
{
|
||||
if (scale > 0.0)
|
||||
region->physical_scale = scale;
|
||||
}
|
||||
|
||||
bool
|
||||
eis_region_contains(struct eis_region *r, double x, double y)
|
||||
{
|
||||
|
|
|
|||
11
src/libeis.h
11
src/libeis.h
|
|
@ -465,6 +465,17 @@ eis_region_set_size(struct eis_region *region, uint32_t w, uint32_t h);
|
|||
void
|
||||
eis_region_set_offset(struct eis_region *region, uint32_t x, uint32_t y);
|
||||
|
||||
/**
|
||||
* Set the physical scale for this region. If unset, the scale defaults to
|
||||
* 1.0.
|
||||
*
|
||||
* A @a scale value of less or equal to 0.0 will be silently ignored.
|
||||
*
|
||||
* See ei_region_get_physical_scale() for details.
|
||||
*/
|
||||
void
|
||||
eis_region_set_physical_scale(struct eis_region *region, double scale);
|
||||
|
||||
struct eis_region *
|
||||
eis_region_ref(struct eis_region *region);
|
||||
|
||||
|
|
|
|||
|
|
@ -282,16 +282,19 @@ MUNIT_TEST(test_ei_device_regions)
|
|||
_unref_(eis_region) *r1 = eis_region_new();
|
||||
eis_region_set_size(r1, 100, 200);
|
||||
eis_region_set_offset(r1, 300, 400);
|
||||
/* no scale, default to 1.0 */
|
||||
eis_device_configure_region(device, r1);
|
||||
|
||||
_unref_(eis_region) *r2 = eis_region_new();
|
||||
eis_region_set_size(r2, 500, 600);
|
||||
eis_region_set_offset(r2, 700, 800);
|
||||
eis_region_set_physical_scale(r2, 3.9);
|
||||
eis_device_configure_region(device, r2);
|
||||
|
||||
_unref_(eis_region) *r3 = eis_region_new();
|
||||
eis_region_set_size(r3, 900, 1000);
|
||||
eis_region_set_offset(r3, 1100, 1200);
|
||||
eis_region_set_physical_scale(r3, 0.3);
|
||||
eis_device_configure_region(device, r3);
|
||||
|
||||
/* Add the same region twice, should be ignored */
|
||||
|
|
@ -311,18 +314,21 @@ MUNIT_TEST(test_ei_device_regions)
|
|||
munit_assert_int(ei_region_get_height(r), ==, 200);
|
||||
munit_assert_int(ei_region_get_x(r), ==, 300);
|
||||
munit_assert_int(ei_region_get_y(r), ==, 400);
|
||||
munit_assert_double_equal(ei_region_get_physical_scale(r), 1.0, 2 /* precision */);
|
||||
|
||||
r = ei_device_get_region(device, 1);
|
||||
munit_assert_int(ei_region_get_width(r), ==, 500);
|
||||
munit_assert_int(ei_region_get_height(r), ==, 600);
|
||||
munit_assert_int(ei_region_get_x(r), ==, 700);
|
||||
munit_assert_int(ei_region_get_y(r), ==, 800);
|
||||
munit_assert_double_equal(ei_region_get_physical_scale(r), 3.9, 2 /* precision */);
|
||||
|
||||
r = ei_device_get_region(device, 2);
|
||||
munit_assert_int(ei_region_get_width(r), ==, 900);
|
||||
munit_assert_int(ei_region_get_height(r), ==, 1000);
|
||||
munit_assert_int(ei_region_get_x(r), ==, 1100);
|
||||
munit_assert_int(ei_region_get_y(r), ==, 1200);
|
||||
munit_assert_double_equal(ei_region_get_physical_scale(r), 0.3, 2 /* precision */);
|
||||
|
||||
munit_assert_ptr_null(ei_device_get_region(device, 3));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue