diff --git a/12to11-test.xml b/12to11-test.xml
index 30e7bec..fab139b 100644
--- a/12to11-test.xml
+++ b/12to11-test.xml
@@ -45,6 +45,14 @@
summary="an invalid version was specified"/>
+
+
+
+
@@ -239,12 +247,156 @@
+
+
+ Simulated XInput 2 device information for a device.
+
+
+
+
+ Destroy the test device info resource.
+
+
+
+
+
+ Set the device ID of this device info structure to the
+ specified ID. If the ID is less than 65536, post an
+ invalid_device_id error.
+
+
+
+
+
+
+
+ Set the name of this device to the specified name.
+
+
+
+
+
+
+
+ Set the use of this device to the specified value.
+
+
+
+
+
+
+
+ Set the device attachment to the master pointer and keyboard
+ of the specified seat controller.
+
+
+
+
+
+
+
+ Set whether or not the device is enabled.
+
+
+
+
+
+
+
+ Add a scroll class with the specified type, source ID, number,
+ scroll type, increment and flags to the device info.
+
+ If the specified source device ID is less than 65536, post an
+ invalid_device_id error.
+
+
+
+
+
+
+
+
+
+
+
+ Add a valuator class with the specified type, source ID,
+ number, label, min, max, value, resolution and mode to the
+ device info.
+
+ If the specified source device ID is less than 65536, post an
+ invalid_device_id error.
+
+ Intern the label into an atom. If the string is empty, raise
+ an invalid_label error.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This object allows registering a list of artificial input
+ devices to use during tests. These devices must have a device
+ ID larger than 65535, and are removed upon destruction of the
+ test controller resource.
+
+
+
+
+ Destroy the test device controller resource.
+
+
+
+
+
+ Register a device with the specified device information. If
+ the device info is incomplete, meaning that one of
+ set_device_id, set_name, set_use, set_attachment, or
+ set_enabled was not called after it was created, post an
+ incomplete_device_info error. If the device ID already
+ exists, post a device_exists error if the device was not
+ created by this device controller, or update the device with
+ the new information if it was.
+
+ If a test seat is created with the device ID in the specified
+ device info after add_device_info is called, then the seat
+ will not possess this device info.
+
+ The device will be removed upon destruction of the
+ test_device_controller resource.
+
+
+
+
+
+
+
+ Create a device information object. The device information
+ object is not associated with the test controller in any way.
+
+
+
+
+
+
This object extends a wl_seat created with the
test_manager.get_test_seat request with several requests to
dispatch generated events.
+ Immediately after being created, a device_id event is sent with
+ the device ID of this seat.
+
If the seat associated with the test controller is destroyed by
the time a request is made with the test controller, the latter
request is simply ignored.
@@ -420,5 +572,21 @@
+
+
+
+ Obtain a new device controller.
+
+
+
+
+
+
+
+ This event is sent immediately after the test_seat_controller
+ is created, with the device ID of the test seat.
+
+
+
diff --git a/seat.c b/seat.c
index f664111..2fecdd3 100644
--- a/seat.c
+++ b/seat.c
@@ -95,6 +95,7 @@ enum
IsInPinchGesture = (1 << 9),
IsInSwipeGesture = (1 << 10),
IsTestSeat = (1 << 11),
+ IsTestDeviceSpecified = (1 << 12),
};
enum
@@ -2189,7 +2190,9 @@ NoticeDeviceDisabled (int deviceid)
seat = XLLookUpAssoc (seats, deviceid);
- if (seat)
+ /* Test seats should not be destroyed here. */
+
+ if (seat && !(seat->flags & IsTestSeat))
{
/* The device has been disabled, mark the seat inert and
dereference it. The seat is still referred to by the
@@ -6181,13 +6184,16 @@ XLSeatDispatchCoreKeyEvent (Seat *seat, Surface *surface, XEvent *event,
if (keysym)
{
/* If looking up the event keycode also results in the keysym,
- then just use the keycode specified in the event. */
+ then just use the keycode specified in the event. This is
+ because French keyboard layouts have multiple keycodes that
+ decode to the same keysym, which causes problems later on
+ when Wayland clients keep repeating the "a" key, as a keysym
+ was looked up for the key press but not for the corresponding
+ key release. */
if (XkbLookupKeySym (compositor.display, event->xkey.keycode,
event->xkey.state, &mods_return, &sym_return)
&& keysym == sym_return)
- {
- keycode = event->xkey.keycode;
- }
+ keycode = event->xkey.keycode;
else
keycode = XKeysymToKeycode (compositor.display, keysym);
diff --git a/test_seat.c b/test_seat.c
index ebcf1e0..6d2f99a 100644
--- a/test_seat.c
+++ b/test_seat.c
@@ -23,9 +23,11 @@ along with 12to11. If not, see . */
have to include anything itself! */
typedef struct _TestSeatController TestSeatController;
+typedef struct _TestDeviceController TestDeviceController;
typedef struct _TestXIModifierState TestXIModifierState;
typedef struct _TestXIValuatorState TestXIValuatorState;
typedef struct _TestXIButtonState TestXIButtonState;
+typedef struct _TestXIDeviceInfo TestXIDeviceInfo;
/* The current test seat counter. */
static unsigned int test_seat_counter;
@@ -42,6 +44,18 @@ struct _TestSeatController
struct wl_resource *resource;
};
+struct _TestDeviceController
+{
+ /* The associated struct wl_resource. */
+ struct wl_resource *resource;
+
+ /* Array of device IDs used by this test device controller. */
+ int *device_ids;
+
+ /* Number of device IDs associated with this controller. */
+ int num_ids;
+};
+
struct _TestXIModifierState
{
/* Modifier state. These fields mean the same as they do in
@@ -73,6 +87,43 @@ struct _TestXIButtonState
unsigned char mask[XIMaskLen (8)];
};
+enum
+ {
+ StateDeviceIdSet = 1,
+ StateNameSet = 1 << 1,
+ StateUseSet = 1 << 2,
+ StateAttachmentSet = 1 << 3,
+ StateEnabledSet = 1 << 4,
+ StateComplete = 0x1f,
+ };
+
+struct _TestXIDeviceInfo
+{
+ /* The associated resource. */
+ struct wl_resource *resource;
+
+ /* The device name. */
+ char *name;
+
+ /* Array of classes. */
+ XIAnyClassInfo **classes;
+
+ /* The device ID. */
+ int device_id;
+
+ /* The use, attachment. */
+ int use, attachment;
+
+ /* Whether or not the device is enabled. */
+ Bool enabled;
+
+ /* The number of classes there are. */
+ int num_classes;
+
+ /* How many fields are set. */
+ int state;
+};
+
static void
@@ -168,6 +219,13 @@ HandleXIButtonStateDestroy (struct wl_resource *resource)
+static void
+DestroyXIValuatorState (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
static void
AddValuatorToTestXIValuatorState (struct wl_client *client,
struct wl_resource *resource,
@@ -200,7 +258,7 @@ AddValuatorToTestXIValuatorState (struct wl_client *client,
if (state->mask_len < XIMaskLen (valuator))
{
state->mask = XLRealloc (state->mask,
- state->mask_len);
+ XIMaskLen (valuator));
/* Clear the newly allocated part of the mask. */
memset (state->mask + state->mask_len,
@@ -221,7 +279,7 @@ AddValuatorToTestXIValuatorState (struct wl_client *client,
if (i == valuator)
/* Insert the new value. */
new_values[j++] = wl_fixed_to_double (value);
- else if (XIMaskIsSet (state->mask, valuator))
+ else if (XIMaskIsSet (state->mask, i))
/* Use the old value. */
new_values[j++] = *old_values++;
}
@@ -238,6 +296,7 @@ AddValuatorToTestXIValuatorState (struct wl_client *client,
static const struct test_XIValuatorState_interface XIValuatorState_impl =
{
+ .destroy = DestroyXIValuatorState,
.add_valuator = AddValuatorToTestXIValuatorState,
};
@@ -261,8 +320,355 @@ HandleXIValuatorStateDestroy (struct wl_resource *resource)
static void
-DestroyTestSeatController (struct wl_client *client,
- struct wl_resource *resource)
+DestroyDeviceInfo (struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static void
+SetDeviceId (struct wl_client *client, struct wl_resource *resource,
+ uint32_t device_id)
+{
+ TestXIDeviceInfo *info;
+
+ info = wl_resource_get_user_data (resource);
+
+ if (device_id < 65536)
+ {
+ wl_resource_post_error (resource, TEST_MANAGER_ERROR_INVALID_DEVICE_ID,
+ "invalid device id specified");
+ return;
+ }
+
+ info->device_id = device_id;
+ info->state |= StateDeviceIdSet;
+}
+
+static void
+SetName (struct wl_client *client, struct wl_resource *resource,
+ const char *name)
+{
+ TestXIDeviceInfo *info;
+
+ info = wl_resource_get_user_data (resource);
+
+ if (info->name)
+ XLFree (info->name);
+ info->name = XLStrdup (name);
+ info->state |= StateNameSet;
+}
+
+static void
+SetUse (struct wl_client *client, struct wl_resource *resource,
+ int32_t use)
+{
+ TestXIDeviceInfo *info;
+
+ info = wl_resource_get_user_data (resource);
+ info->use = use;
+ info->state |= StateUseSet;
+}
+
+static void
+SetAttachment (struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *attachment_resource)
+{
+ TestSeatController *controller;
+ TestXIDeviceInfo *info;
+
+ controller = wl_resource_get_user_data (attachment_resource);
+ info = wl_resource_get_user_data (resource);
+
+ info->attachment = controller->seat->master_pointer;
+ info->state |= StateAttachmentSet;
+}
+
+static void
+SetEnabled (struct wl_client *client, struct wl_resource *resource,
+ uint32_t enabled)
+{
+ TestXIDeviceInfo *info;
+
+ info = wl_resource_get_user_data (resource);
+
+ if (enabled)
+ info->enabled = True;
+ else
+ info->enabled = False;
+ info->state |= StateEnabledSet;
+}
+
+static void
+AddXIScrollClassInfo (struct wl_client *client, struct wl_resource *resource,
+ int32_t sourceid, int32_t number, int32_t scroll_type,
+ wl_fixed_t increment, int32_t flags)
+{
+ TestXIDeviceInfo *info;
+ XIScrollClassInfo *class;
+
+ if (sourceid < 65536)
+ {
+ wl_resource_post_error (resource, TEST_MANAGER_ERROR_INVALID_DEVICE_ID,
+ "invalid device ID specified");
+ return;
+ }
+
+ info = wl_resource_get_user_data (resource);
+
+ class = XLMalloc (sizeof *class);
+ class->type = XIScrollClass;
+ class->sourceid = sourceid;
+ class->number = number;
+ class->scroll_type = scroll_type;
+ class->increment = wl_fixed_to_double (increment);
+ class->flags = flags;
+
+ /* Extend info->classes to hold more classes. */
+ info->num_classes++;
+ info->classes = XLRealloc (info->classes,
+ sizeof *info->classes * info->num_classes);
+
+ /* Attach the class. */
+ info->classes[info->num_classes - 1] = (XIAnyClassInfo *) class;
+}
+
+static void
+AddXIValuatorClassInfo (struct wl_client *client, struct wl_resource *resource,
+ int32_t sourceid, int32_t number, const char *label,
+ wl_fixed_t min, wl_fixed_t max, wl_fixed_t value,
+ int32_t resolution, int32_t mode)
+{
+ TestXIDeviceInfo *info;
+ XIValuatorClassInfo *class;
+
+ if (sourceid < 65536)
+ {
+ wl_resource_post_error (resource, TEST_MANAGER_ERROR_INVALID_DEVICE_ID,
+ "invalid device ID specified");
+ return;
+ }
+
+ /* Avoid interning empty strings. */
+
+ if (!strlen (label))
+ {
+ wl_resource_post_error (resource, TEST_MANAGER_ERROR_INVALID_LABEL,
+ "the specified label is invalid");
+ return;
+ }
+
+ info = wl_resource_get_user_data (resource);
+ class = XLMalloc (sizeof *class);
+ class->type = XIValuatorClass;
+ class->sourceid = sourceid;
+ class->number = number;
+ class->label = InternAtom (label);
+ class->min = wl_fixed_to_double (min);
+ class->max = wl_fixed_to_double (max);
+ class->value = wl_fixed_to_double (value);
+ class->resolution = resolution;
+ class->mode = mode;
+
+ /* Extend info->classes to hold more classes. */
+ info->num_classes++;
+ info->classes = XLRealloc (info->classes,
+ sizeof *info->classes * info->num_classes);
+
+ /* Attach the class. */
+ info->classes[info->num_classes - 1] = (XIAnyClassInfo *) class;
+}
+
+static const struct test_XIDeviceInfo_interface XIDeviceInfo_impl =
+ {
+ .destroy = DestroyDeviceInfo,
+ .set_device_id = SetDeviceId,
+ .set_name = SetName,
+ .set_use = SetUse,
+ .set_attachment = SetAttachment,
+ .set_enabled = SetEnabled,
+ .add_XIScrollClassInfo = AddXIScrollClassInfo,
+ .add_XIValuatorClassInfo = AddXIValuatorClassInfo,
+ };
+
+static void
+HandleXIDeviceInfoDestroy (struct wl_resource *resource)
+{
+ TestXIDeviceInfo *info;
+ int i;
+
+ info = wl_resource_get_user_data (resource);
+
+ /* Free the name. */
+ XLFree (info->name);
+
+ /* Free each of the classes. */
+ for (i = 0; i < info->num_classes; ++i)
+ XLFree (info->classes[i]);
+
+ /* Free the class array. */
+ XLFree (info->classes);
+
+ /* Free the info itself. */
+ XLFree (info);
+}
+
+
+
+static void
+DestroyDeviceController (struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static void
+AddDeviceInfo (struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *device_info)
+{
+ TestDeviceController *controller;
+ TestXIDeviceInfo *info;
+ Seat *seat;
+ DeviceInfo *deviceinfo;
+ int i;
+ XIDeviceInfo test_info;
+
+ /* Add a virtual device to the device controller. */
+ controller = wl_resource_get_user_data (resource);
+ info = wl_resource_get_user_data (device_info);
+
+ /* First, ensure that the device info is completely specified. */
+
+ if ((info->state & StateComplete) != StateComplete)
+ {
+ wl_resource_post_error (resource,
+ TEST_MANAGER_ERROR_INCOMPLETE_DEVICE_INFO,
+ "the specified device information was not"
+ " completely specified");
+ return;
+ }
+
+ /* Next, check whether or not a device already exists. */
+ seat = XLLookUpAssoc (seats, info->device_id);
+ deviceinfo = XLLookUpAssoc (devices, info->device_id);
+
+ if ((seat && seat->flags & IsTestDeviceSpecified) || deviceinfo)
+ {
+ /* If a device already exists, see whether or not it was created
+ by this test device controller. */
+
+ for (i = 0; i < controller->num_ids; ++i)
+ {
+ if (controller->device_ids[i] == info->device_id)
+ /* It was created by this controller. Simply update the
+ values. */
+ goto continue_update;
+ }
+
+ /* Otherwise, post an error. */
+ wl_resource_post_error (resource,
+ TEST_MANAGER_ERROR_DEVICE_EXISTS,
+ "the device %d already exists, and was "
+ "not created by this controller",
+ info->device_id);
+ return;
+ }
+
+ continue_update:
+
+ /* Now, construct the XIDeviceInfo. */
+ test_info.deviceid = info->device_id;
+ test_info.name = info->name;
+ test_info.use = info->use;
+ test_info.attachment = info->attachment;
+ test_info.enabled = info->enabled;
+ test_info.num_classes = info->num_classes;
+ test_info.classes = info->classes;
+
+ /* If the seat exists, repopulate its valuators with that specified
+ in the device info. */
+
+ if (seat)
+ {
+ FreeValuators (seat);
+ UpdateValuators (seat, &test_info);
+
+ /* Next, set a flag that means the seat has its information
+ provided by device info. */
+ seat->flags |= IsTestDeviceSpecified;
+ }
+
+ /* Now, record the device info. */
+ RecordDeviceInformation (&test_info);
+}
+
+static void
+GetDeviceInfo (struct wl_client *client, struct wl_resource *resource,
+ uint32_t id)
+{
+ TestXIDeviceInfo *info;
+
+ info = XLSafeMalloc (sizeof *info);
+
+ if (!info)
+ {
+ wl_resource_post_no_memory (resource);
+ return;
+ }
+
+ memset (info, 0, sizeof *info);
+ info->resource
+ = wl_resource_create (client, &test_XIDeviceInfo_interface,
+ wl_resource_get_version (resource), id);
+
+ if (!info->resource)
+ {
+ XLFree (info);
+ return;
+ }
+
+ wl_resource_set_implementation (info->resource, &XIDeviceInfo_impl,
+ info, HandleXIDeviceInfoDestroy);
+}
+
+static const struct test_device_controller_interface device_controller_impl =
+ {
+ .destroy = DestroyDeviceController,
+ .add_device_info = AddDeviceInfo,
+ .get_device_info = GetDeviceInfo,
+ };
+
+static void
+HandleTestDeviceControllerDestroy (struct wl_resource *resource)
+{
+ TestDeviceController *controller;
+ int i;
+ Seat *seat;
+
+ controller = wl_resource_get_user_data (resource);
+
+ /* Remove each device associated with the device controller. */
+ for (i = 0; i < controller->num_ids; ++i)
+ {
+ NoticeDeviceDisabled (controller->device_ids[i]);
+
+ /* NoticeDeviceDisabled is special-cased to not free valuators
+ for test seats. If there is a seat associated with this
+ device ID, free the valuators on it as well. */
+ seat = XLLookUpAssoc (seats, controller->device_ids[i]);
+ FreeValuators (seat);
+
+ /* Clear the test device specified flag. */
+ seat->flags &= ~IsTestDeviceSpecified;
+ }
+
+ XLFree (controller);
+}
+
+
+
+static void
+DestroySeatController (struct wl_client *client,
+ struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
@@ -664,9 +1070,41 @@ DispatchXIButtonRelease (struct wl_client *client, struct wl_resource *resource,
DispatchTestEvent (controller, event, (XIEvent *) &test_event);
}
+static void
+GetDeviceController (struct wl_client *client, struct wl_resource *resource,
+ uint32_t id)
+{
+ TestDeviceController *controller;
+
+ controller = XLSafeMalloc (sizeof *controller);
+
+ if (!controller)
+ {
+ wl_resource_post_no_memory (resource);
+ return;
+ }
+
+ memset (controller, 0, sizeof *controller);
+ controller->resource
+ = wl_resource_create (client, &test_device_controller_interface,
+ wl_resource_get_version (resource), id);
+
+ if (!controller->resource)
+ {
+ XLFree (controller);
+ wl_resource_post_no_memory (resource);
+ return;
+ }
+
+ wl_resource_set_implementation (controller->resource,
+ &device_controller_impl,
+ controller,
+ HandleTestDeviceControllerDestroy);
+}
+
static const struct test_seat_controller_interface seat_controller_impl =
{
- .destroy = DestroyTestSeatController,
+ .destroy = DestroySeatController,
.bind_seat = BindSeat,
.get_XIModifierState = GetXIModifierState,
.get_XIButtonState = GetXIButtonState,
@@ -676,6 +1114,7 @@ static const struct test_seat_controller_interface seat_controller_impl =
.dispatch_XI_Motion = DispatchXIMotion,
.dispatch_XI_ButtonPress = DispatchXIButtonPress,
.dispatch_XI_ButtonRelease = DispatchXIButtonRelease,
+ .get_device_controller = GetDeviceController,
};
static void
@@ -787,4 +1226,8 @@ XLGetTestSeat (struct wl_client *client, struct wl_resource *resource,
wl_resource_set_implementation (controller->resource, &seat_controller_impl,
controller, HandleControllerResourceDestroy);
+
+ /* Send the device ID to the client. */
+ test_seat_controller_send_device_id (controller->resource,
+ seat->master_pointer);
}
diff --git a/tests/seat_test.c b/tests/seat_test.c
index fe4c78d..6502866 100644
--- a/tests/seat_test.c
+++ b/tests/seat_test.c
@@ -29,6 +29,7 @@ enum test_expect_event_kind
POINTER_MOTION_EVENT,
POINTER_LEAVE_EVENT,
POINTER_BUTTON_EVENT,
+ POINTER_AXIS_VALUE120_EVENT,
};
struct test_recorded_event
@@ -82,6 +83,18 @@ struct test_recorded_button_event
uint32_t button, state;
};
+struct test_recorded_axis_value120_event
+{
+ /* The event header. */
+ struct test_recorded_event header;
+
+ /* The axis. */
+ uint32_t axis;
+
+ /* The value120. */
+ int32_t value120;
+};
+
struct test_subsurface
{
/* The subsurface itself. */
@@ -97,6 +110,7 @@ enum test_kind
TEST_ENTRY_KIND,
TEST_CLICK_KIND,
TEST_GRAB_KIND,
+ TEST_VALUATOR_KIND,
};
static const char *test_names[] =
@@ -105,9 +119,10 @@ static const char *test_names[] =
"test_entry",
"test_click",
"test_grab",
+ "test_valuator",
};
-#define LAST_TEST TEST_GRAB_KIND
+#define LAST_TEST TEST_VALUATOR_KIND
#define TEST_SOURCE_DEVICE 4500000
/* The display. */
@@ -148,6 +163,7 @@ static void expect_enter_event (struct wl_surface *, double, double);
static void expect_motion_event (double, double);
static void expect_leave_event (void);
static void expect_button_event (int, int);
+static void expect_axis_value120_event (uint32_t, int32_t);
static void expect_no_events (void);
@@ -466,6 +482,159 @@ run_grab_test (struct test_XIButtonState *button_state,
expect_enter_event (wayland_surface, 0.0, 0.0);
}
+static void
+run_valuator_test (void)
+{
+ struct test_XIDeviceInfo *info;
+ struct test_XIValuatorState *valuator_state;
+
+ /* First, create the device info. */
+ info
+ = test_device_controller_get_device_info (display->seat->device_controller);
+
+ /* Send the first leave event. */
+ test_seat_controller_dispatch_XI_Leave (display->seat->controller,
+ test_get_time (),
+ TEST_SOURCE_DEVICE,
+ XINotifyAncestor,
+ test_get_root (),
+ test_surface_window,
+ None,
+ wl_fixed_from_double (-1.0),
+ wl_fixed_from_double (-1.0),
+ wl_fixed_from_double (-1.0),
+ wl_fixed_from_double (-1.0),
+ XINotifyNormal,
+ False, True,
+ NULL, NULL, NULL);
+
+ /* Set the device ID and add the valuators. */
+ test_XIDeviceInfo_set_device_id (info, display->seat->device_id);
+ test_XIDeviceInfo_set_use (info, XIMasterPointer);
+ test_XIDeviceInfo_set_attachment (info, display->seat->controller);
+ test_XIDeviceInfo_set_name (info, "Test virtual pointer");
+ test_XIDeviceInfo_set_enabled (info, 1);
+ test_XIDeviceInfo_add_XIScrollClassInfo (info,
+ TEST_SOURCE_DEVICE,
+ 1,
+ XIScrollTypeVertical,
+ wl_fixed_from_double (1.0),
+ XIScrollFlagPreferred);
+ test_XIDeviceInfo_add_XIScrollClassInfo (info,
+ TEST_SOURCE_DEVICE,
+ 2,
+ XIScrollTypeHorizontal,
+ wl_fixed_from_double (2.0),
+ XIScrollFlagPreferred);
+ test_XIDeviceInfo_add_XIValuatorClassInfo (info,
+ TEST_SOURCE_DEVICE,
+ 1,
+ "Rel Scroll Vertical",
+ wl_fixed_from_double (0.0),
+ wl_fixed_from_double (0.0),
+ wl_fixed_from_double (0.0),
+ 1,
+ XIModeRelative);
+ test_XIDeviceInfo_add_XIValuatorClassInfo (info,
+ TEST_SOURCE_DEVICE,
+ 2,
+ "Rel Scroll Horizontal",
+ wl_fixed_from_double (0.0),
+ wl_fixed_from_double (0.0),
+ wl_fixed_from_double (0.0),
+ 1,
+ XIModeRelative);
+ test_device_controller_add_device_info (display->seat->device_controller,
+ info);
+ test_XIDeviceInfo_destroy (info);
+
+ /* Dispatch the first entry event. */
+ test_seat_controller_dispatch_XI_Enter (display->seat->controller,
+ test_get_time (),
+ TEST_SOURCE_DEVICE,
+ XINotifyAncestor,
+ test_get_root (),
+ test_surface_window,
+ None,
+ wl_fixed_from_double (1.0),
+ wl_fixed_from_double (1.0),
+ wl_fixed_from_double (1.0),
+ wl_fixed_from_double (1.0),
+ XINotifyNormal,
+ False, True, NULL, NULL,
+ NULL);
+
+ /* Create the valuator state. */
+ valuator_state
+ = test_seat_controller_get_XIValuatorState (display->seat->controller);
+
+ if (!valuator_state)
+ report_test_failure ("failed to create valuator state");
+
+ test_XIValuatorState_add_valuator (valuator_state, 1,
+ wl_fixed_from_double (1.0));
+ test_XIValuatorState_add_valuator (valuator_state, 2,
+ wl_fixed_from_double (1.0));
+
+ /* Dispatch the first motion event. */
+ test_seat_controller_dispatch_XI_Motion (display->seat->controller,
+ test_get_time (),
+ TEST_SOURCE_DEVICE,
+ 0,
+ test_get_root (),
+ test_surface_window,
+ None,
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ 0,
+ NULL,
+ valuator_state,
+ NULL, NULL);
+ test_XIValuatorState_destroy (valuator_state);
+
+ /* Dispatch the second motion event. */
+ valuator_state
+ = test_seat_controller_get_XIValuatorState (display->seat->controller);
+
+ if (!valuator_state)
+ report_test_failure ("failed to create valuator state");
+
+ test_XIValuatorState_add_valuator (valuator_state, 1,
+ wl_fixed_from_double (1.1));
+ test_XIValuatorState_add_valuator (valuator_state, 2,
+ wl_fixed_from_double (2.6));
+ test_seat_controller_dispatch_XI_Motion (display->seat->controller,
+ test_get_time (),
+ TEST_SOURCE_DEVICE,
+ 0,
+ test_get_root (),
+ test_surface_window,
+ None,
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ wl_fixed_from_double (2.0),
+ 0,
+ NULL,
+ valuator_state,
+ NULL, NULL);
+ test_XIValuatorState_destroy (valuator_state);
+
+ /* Now, verify the events that arrive. */
+ record_events ();
+ expect_frame_event ();
+ expect_axis_value120_event (WL_POINTER_AXIS_VERTICAL_SCROLL, 12);
+ expect_axis_value120_event (WL_POINTER_AXIS_HORIZONTAL_SCROLL, 96);
+ expect_frame_event ();
+ expect_motion_event (2.0, 2.0);
+ expect_frame_event ();
+ expect_enter_event (wayland_surface, 1.0, 1.0);
+ expect_frame_event ();
+ expect_leave_event ();
+}
+
static void
test_single_step (enum test_kind kind)
{
@@ -473,6 +642,8 @@ test_single_step (enum test_kind kind)
struct test_XIButtonState *button_state;
struct test_subsurface *child;
+ button_state = NULL;
+
again:
test_log ("running test step: %s", test_names[kind]);
@@ -613,7 +784,99 @@ test_single_step (enum test_kind kind)
/* Run the test. */
run_grab_test (button_state, child);
+ kind = TEST_VALUATOR_KIND;
+ goto again;
+ case TEST_VALUATOR_KIND:
+ /* Dispatch a leave event at -1, -1, and then attach the following
+ scroll valuator information to the seat:
+
+ type
+ ScrollClass
+ number
+ 1
+ scroll_type
+ Vertical
+ flags
+ Preferred
+ increment
+ 1.0
+
+ type
+ ScrollClass
+ number
+ 2
+ scroll_type
+ Horizontal
+ flags
+ Preferred
+ increment
+ 2.0
+
+ type
+ ValuatorClass
+ sourceid
+ TEST_SOURCE_DEVICE
+ number
+ 1
+ label
+ Rel Scroll Vertical
+ min
+ 0.0
+ max
+ 0.0
+ resolution
+ 1
+ mode
+ Relative
+ value
+ 0.0
+
+ type
+ ValuatorClass
+ sourceid
+ TEST_SOURCE_DEVICE
+ number
+ 2
+ label
+ Rel Scroll Horizontal
+ min
+ 0.0
+ max
+ 0.0
+ resolution
+ 1
+ mode
+ Relative
+ value
+ 0.0
+
+ then, dispatch an entry event at 1, 1, followed by two motion
+ events at 2, 2 with the following valuators:
+
+ 1, 1.0, 2, 1.0
+ 1, 1.1, 2, 2.6
+
+ verify that the following events arrive in the specified order:
+
+ leave ()
+ frame ()
+ enter (SERIAL, PARENT, 1.0, 1.0)
+ frame ()
+
+ motion (TIME, 2.0, 2.0) (this motion event should arrive because
+ the entry event happened after
+ the scroll valuator information was
+ recorded. The first motion event to
+ arrive after that should be used to obtain
+ the current value of the valuator, and
+ not for calculating scroll deltas.)
+ frame ();
+ axis_value120 (WL_POINTER_AXIS_HORIZONTAL_SCROLL, 96)
+ axis_value120 (WL_POINTER_AXIS_VERTICAL_SCROLL, 12)
+ frame (); */
+
+ run_valuator_test ();
break;
}
@@ -752,6 +1015,37 @@ expect_button_event (int button, int state)
report_test_failure ("expected button event, but it was not received");
}
+static void
+expect_axis_value120_event (uint32_t axis, int32_t value120)
+{
+ struct test_recorded_event *event;
+ struct test_recorded_axis_value120_event *axis_value120_event;
+
+ event = record_tail;
+
+ if (!event)
+ report_test_failure ("expected event not sent");
+
+ record_tail = event->last;
+
+ if (event->kind == POINTER_AXIS_VALUE120_EVENT)
+ {
+ axis_value120_event
+ = (struct test_recorded_axis_value120_event *) event;
+
+ if (axis_value120_event->axis == axis
+ && axis_value120_event->value120 == value120)
+ free (event);
+ else
+ report_test_failure ("expected axis_value120 event received "
+ "with incorrect parameters (axis: %"PRIu32","
+ " value120: %"PRIi32")", axis, value120);
+ }
+ else
+ report_test_failure ("expected axis_value120 event, but it was not "
+ "received");
+}
+
static void
expect_no_events (void)
{
@@ -1011,7 +1305,34 @@ static void
handle_pointer_axis_value120 (void *data, struct wl_pointer *wl_pointer,
uint32_t axis, int32_t value120)
{
- /* TODO... */
+ struct test_recorded_axis_value120_event *event;
+
+ if (!recording_events)
+ {
+ test_log ("ignored button event");
+ return;
+ }
+
+ event = malloc (sizeof *event);
+
+ if (!event)
+ report_test_failure ("failed to record event");
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
+#endif
+
+ event->header.kind = POINTER_AXIS_VALUE120_EVENT;
+ event->header.last = record_tail;
+ record_tail = &event->header;
+
+ event->axis = axis;
+ event->value120 = value120;
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
}
static const struct wl_pointer_listener pointer_listener =
diff --git a/tests/test_harness.c b/tests/test_harness.c
index efb7744..6aaaec0 100644
--- a/tests/test_harness.c
+++ b/tests/test_harness.c
@@ -825,6 +825,26 @@ test_init (void)
= getenv ("TEST_WRITE_REFERENCE") != NULL;
}
+
+
+static void
+handle_seat_controller_device_id (void *data,
+ struct test_seat_controller *controller,
+ uint32_t device_id)
+{
+ struct test_display *display;
+
+ display = data;
+ display->seat->device_id = device_id;
+}
+
+static const struct test_seat_controller_listener seat_controller_listener =
+ {
+ handle_seat_controller_device_id,
+ };
+
+
+
void
test_init_seat (struct test_display *display)
{
@@ -842,6 +862,22 @@ test_init_seat (struct test_display *display)
if (!display->seat->controller)
report_test_failure ("failed to obtain seat controller");
+ display->seat->device_controller
+ = test_seat_controller_get_device_controller (display->seat->controller);
+
+ if (!display->seat->device_controller)
+ report_test_failure ("failed to obtain device controller");
+
+ /* Fetch the device ID of the seat. */
+ display->seat->device_id = 0;
+ test_seat_controller_add_listener (display->seat->controller,
+ &seat_controller_listener,
+ display);
+ wl_display_roundtrip (display->display);
+
+ if (!display->seat->device_id)
+ report_test_failure ("failed to obtain device ID");
+
/* The protocol translator currently supports version 8 of wl_seat,
so bind to that. */
diff --git a/tests/test_harness.h b/tests/test_harness.h
index 2cc90b1..a17972d 100644
--- a/tests/test_harness.h
+++ b/tests/test_harness.h
@@ -40,12 +40,18 @@ struct test_seat
/* The test seat, if any. */
struct test_seat_controller *controller;
+ /* The device manager, if any. */
+ struct test_device_controller *device_controller;
+
/* The seat resource itself. */
struct wl_seat *seat;
/* The wl_pointer resource. */
struct wl_pointer *pointer;
+ /* The device ID of the seat. */
+ uint32_t device_id;
+
/* The buttons currently held down. */
unsigned char buttons;
};