Add scroll valuator tests

* 12to11-test.xml (test_manager): <error>: New errors.
(test_XIDeviceInfo, test_device_controller): New interfaces.
(test_seat_controller): <get_device_controller>: New request.
<device_id>: New event.

* seat.c (NoticeDeviceDisabled): Ignore test seats.
(XLSeatDispatchCoreKeyEvent): Expand commentary.

* test_seat.c (struct _TestDeviceController)
(struct _TestXIDeviceInfo): New structs.
(DestroyXIValuatorState): New function.
(AddValuatorToTestXIValuatorState): Fix crashes.
(XIValuatorState_impl): Add DestroyXIValuatorState.
(DestroyDeviceInfo, SetDeviceId, SetName, SetUse, SetAttachment)
(SetEnabled, AddXIScrollClassInfo, AddXIValuatorClassInfo): New
functions.
(XIDeviceInfo_impl): New interface implementation.
(HandleXIDeviceInfoDestroy): New function.
(DestroyDeviceController, AddDeviceInfo, GetDeviceInfo): New
functions.
(device_controller_impl): New interface.
(HandleTestDeviceControllerDestroy): New function.
(GetDeviceController): New function.
(seat_controller_impl): Add it.
(XLGetTestSeat): Send new `device_id' event.

* tests/seat_test.c (enum test_expect_event_kind): Add
POINTER_AXIS_VALUE120_EVENT.
(struct test_recorded_axis_value120_event): New event kind.
(enum test_kind): Add TEST_VALUATOR_KIND.
(test_names): Add test_valuator.
(LAST_TEST): Set to TEST_VALUATOR_KIND.
(run_valuator_test): New function.
(test_single_step): Implement accordingly.
(expect_axis_value120_event, handle_pointer_axis_value120): New
functions.

* tests/test_harness.c (handle_seat_controller_device_id): New
function.
(seat_controller_listener): New listener.
(test_init_seat): Wait for device ID and init device controller.

* tests/test_harness.h (struct test_seat): Add device controller
and device ID fields.
This commit is contained in:
hujianwei 2022-11-10 06:14:51 +00:00
parent e2afe671df
commit 163dca96bd
6 changed files with 992 additions and 12 deletions

View file

@ -45,6 +45,14 @@
summary="an invalid version was specified"/>
<entry name="invalid_valuator" value="7"
summary="the specified valuator is invalid"/>
<entry name="invalid_device_id" value="8"
summary="the specified device ID is too small"/>
<entry name="incomplete_device_info" value="9"
summary="the specified device info is incomplete"/>
<entry name="device_exists" value="10"
summary="the specified artifical device already exists"/>
<entry name="invalid_label" value="11"
summary="the specified label is invalid"/>
</enum>
<request name="get_test_surface">
@ -239,12 +247,156 @@
</request>
</interface>
<interface name="test_XIDeviceInfo" version="1">
<description summary="XInput 2 device information">
Simulated XInput 2 device information for a device.
</description>
<request name="destroy" type="destructor">
<description summary="destroy test device info">
Destroy the test device info resource.
</description>
</request>
<request name="set_device_id">
<description summary="set the device ID">
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.
</description>
<arg name="device_id" type="uint"/>
</request>
<request name="set_name">
<description summary="set the device name">
Set the name of this device to the specified name.
</description>
<arg name="name" type="string"/>
</request>
<request name="set_use">
<description summary="set the device use">
Set the use of this device to the specified value.
</description>
<arg name="use" type="int"/>
</request>
<request name="set_attachment">
<description summary="set the device attachment">
Set the device attachment to the master pointer and keyboard
of the specified seat controller.
</description>
<arg name="attachment" type="object"
interface="test_seat_controller"/>
</request>
<request name="set_enabled">
<description summary="set device enabled">
Set whether or not the device is enabled.
</description>
<arg name="enabled" type="uint"/>
</request>
<request name="add_XIScrollClassInfo">
<description summary="add a scroll class to the device information">
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.
</description>
<arg name="sourceid" type="int"/>
<arg name="number" type="int"/>
<arg name="scroll_type" type="int"/>
<arg name="increment" type="fixed"/>
<arg name="flags" type="int"/>
</request>
<request name="add_XIValuatorClassInfo">
<description summary="add a valuator class to the device information">
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.
</description>
<arg name="sourceid" type="int"/>
<arg name="number" type="int"/>
<arg name="label" type="string"/>
<arg name="min" type="fixed"/>
<arg name="max" type="fixed"/>
<arg name="value" type="fixed"/>
<arg name="resolution" type="int"/>
<arg name="mode" type="int"/>
</request>
</interface>
<interface name="test_device_controller" version="1">
<description summary="test device controller">
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.
</description>
<request name="destroy" type="destructor">
<description summary="destroy test device controller">
Destroy the test device controller resource.
</description>
</request>
<request name="add_device_info">
<description summary="add artificial device">
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.
</description>
<arg name="device_info" type="object" interface="test_XIDeviceInfo"/>
</request>
<request name="get_device_info">
<description summary="create device info">
Create a device information object. The device information
object is not associated with the test controller in any way.
</description>
<arg name="id" type="new_id" interface="test_XIDeviceInfo"/>
</request>
</interface>
<interface name="test_seat_controller" version="1">
<description summary="test seat">
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 @@
<arg name="group" type="object" interface="test_XIModifierState"
allow-null="true"/>
</request>
<request name="get_device_controller">
<description summary="get device controller">
Obtain a new device controller.
</description>
<arg name="id" type="new_id" interface="test_device_controller"/>
</request>
<event name="device_id">
<description summary="device ID">
This event is sent immediately after the test_seat_controller
is created, with the device ID of the test seat.
</description>
<arg name="device_id" type="uint"/>
</event>
</interface>
</protocol>

14
seat.c
View file

@ -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;
}
else
keycode = XKeysymToKeycode (compositor.display, keysym);

View file

@ -23,9 +23,11 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
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,7 +320,354 @@ HandleXIValuatorStateDestroy (struct wl_resource *resource)
static void
DestroyTestSeatController (struct wl_client *client,
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);
}

View file

@ -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 =

View file

@ -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. */

View file

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