blob: 2e999ab5fb802522c901862fb479538ca574b465 [file] [log] [blame]
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +02001/*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Collabora, Ltd.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27#include "config.h"
28
29#include <linux/input.h>
30
Alexandros Frantzisdb907b72018-02-20 14:06:26 +020031#include "input-timestamps-helper.h"
Alexandros Frantzis21808582017-12-13 13:27:55 +020032#include "shared/timespec-util.h"
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +020033#include "weston-test-client-helper.h"
Pekka Paalanen701676d2019-11-13 15:45:10 +020034#include "weston-test-fixture-compositor.h"
35
36static enum test_result_code
37fixture_setup(struct weston_test_harness *harness)
38{
39 struct compositor_setup setup;
40
41 compositor_setup_defaults(&setup);
42
43 return weston_test_harness_execute_as_client(harness, &setup);
44}
45DECLARE_FIXTURE_SETUP(fixture_setup);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +020046
Alexandros Frantzis21808582017-12-13 13:27:55 +020047static const struct timespec t0 = { .tv_sec = 0, .tv_nsec = 100000000 };
48static const struct timespec t1 = { .tv_sec = 1, .tv_nsec = 1000001 };
49static const struct timespec t2 = { .tv_sec = 2, .tv_nsec = 2000001 };
Alexandros Frantzisdb907b72018-02-20 14:06:26 +020050static const struct timespec t_other = { .tv_sec = 123, .tv_nsec = 456 };
Alexandros Frantzis21808582017-12-13 13:27:55 +020051
52static void
53send_motion(struct client *client, const struct timespec *time, int x, int y)
54{
55 uint32_t tv_sec_hi, tv_sec_lo, tv_nsec;
56
57 timespec_to_proto(time, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
58 weston_test_move_pointer(client->test->weston_test, tv_sec_hi, tv_sec_lo,
59 tv_nsec, x, y);
60 client_roundtrip(client);
61}
62
63static void
64send_button(struct client *client, const struct timespec *time,
65 uint32_t button, uint32_t state)
66{
67 uint32_t tv_sec_hi, tv_sec_lo, tv_nsec;
68
69 timespec_to_proto(time, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
70 weston_test_send_button(client->test->weston_test, tv_sec_hi, tv_sec_lo,
71 tv_nsec, button, state);
72 client_roundtrip(client);
73}
74
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +020075static void
Alexandros Frantzisb0341ae2017-12-18 12:16:55 +020076send_axis(struct client *client, const struct timespec *time, uint32_t axis,
77 double value)
78{
79 uint32_t tv_sec_hi, tv_sec_lo, tv_nsec;
80
81 timespec_to_proto(time, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
82 weston_test_send_axis(client->test->weston_test, tv_sec_hi, tv_sec_lo,
83 tv_nsec, axis, wl_fixed_from_double(value));
84 client_roundtrip(client);
85}
86
87static void
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +020088check_pointer(struct client *client, int x, int y)
89{
90 int sx, sy;
91
92 /* check that the client got the global pointer update */
93 assert(client->test->pointer_x == x);
94 assert(client->test->pointer_y == y);
95
96 /* Does global pointer map onto the surface? */
97 if (surface_contains(client->surface, x, y)) {
98 /* check that the surface has the pointer focus */
99 assert(client->input->pointer->focus == client->surface);
100
101 /*
102 * check that the local surface pointer maps
103 * to the global pointer.
104 */
105 sx = client->input->pointer->x + client->surface->x;
106 sy = client->input->pointer->y + client->surface->y;
107 assert(sx == x);
108 assert(sy == y);
109 } else {
110 /*
111 * The global pointer does not map onto surface. So
112 * check that it doesn't have the pointer focus.
113 */
114 assert(client->input->pointer->focus == NULL);
115 }
116}
117
118static void
119check_pointer_move(struct client *client, int x, int y)
120{
Alexandros Frantzis21808582017-12-13 13:27:55 +0200121 send_motion(client, &t0, x, y);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200122 check_pointer(client, x, y);
123}
124
Alexandros Frantzis903e4452017-12-04 15:34:04 +0200125static struct client *
126create_client_with_pointer_focus(int x, int y, int w, int h)
127{
128 struct client *cl = create_client_and_test_surface(x, y, w, h);
129 assert(cl);
130 /* Move the pointer inside the surface to ensure that the surface
131 * has the pointer focus. */
132 check_pointer_move(cl, x, y);
133 return cl;
134}
135
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200136TEST(test_pointer_top_left)
137{
138 struct client *client;
139 int x, y;
140
141 client = create_client_and_test_surface(46, 76, 111, 134);
142 assert(client);
143
144 /* move pointer outside top left */
145 x = client->surface->x - 1;
146 y = client->surface->y - 1;
147 assert(!surface_contains(client->surface, x, y));
148 check_pointer_move(client, x, y);
149
150 /* move pointer on top left */
151 x += 1; y += 1;
152 assert(surface_contains(client->surface, x, y));
153 check_pointer_move(client, x, y);
154
155 /* move pointer outside top left */
156 x -= 1; y -= 1;
157 assert(!surface_contains(client->surface, x, y));
158 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300159
160 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200161}
162
163TEST(test_pointer_bottom_left)
164{
165 struct client *client;
166 int x, y;
167
168 client = create_client_and_test_surface(99, 100, 100, 98);
169 assert(client);
170
171 /* move pointer outside bottom left */
172 x = client->surface->x - 1;
173 y = client->surface->y + client->surface->height;
174 assert(!surface_contains(client->surface, x, y));
175 check_pointer_move(client, x, y);
176
177 /* move pointer on bottom left */
178 x += 1; y -= 1;
179 assert(surface_contains(client->surface, x, y));
180 check_pointer_move(client, x, y);
181
182 /* move pointer outside bottom left */
183 x -= 1; y += 1;
184 assert(!surface_contains(client->surface, x, y));
185 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300186
187 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200188}
189
190TEST(test_pointer_top_right)
191{
192 struct client *client;
193 int x, y;
194
195 client = create_client_and_test_surface(48, 100, 67, 100);
196 assert(client);
197
198 /* move pointer outside top right */
199 x = client->surface->x + client->surface->width;
200 y = client->surface->y - 1;
201 assert(!surface_contains(client->surface, x, y));
202 check_pointer_move(client, x, y);
203
204 /* move pointer on top right */
205 x -= 1; y += 1;
206 assert(surface_contains(client->surface, x, y));
207 check_pointer_move(client, x, y);
208
209 /* move pointer outside top right */
210 x += 1; y -= 1;
211 assert(!surface_contains(client->surface, x, y));
212 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300213
214 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200215}
216
217TEST(test_pointer_bottom_right)
218{
219 struct client *client;
220 int x, y;
221
222 client = create_client_and_test_surface(100, 123, 100, 69);
223 assert(client);
224
225 /* move pointer outside bottom right */
226 x = client->surface->x + client->surface->width;
227 y = client->surface->y + client->surface->height;
228 assert(!surface_contains(client->surface, x, y));
229 check_pointer_move(client, x, y);
230
231 /* move pointer on bottom right */
232 x -= 1; y -= 1;
233 assert(surface_contains(client->surface, x, y));
234 check_pointer_move(client, x, y);
235
236 /* move pointer outside bottom right */
237 x += 1; y += 1;
238 assert(!surface_contains(client->surface, x, y));
239 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300240
241 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200242}
243
244TEST(test_pointer_top_center)
245{
246 struct client *client;
247 int x, y;
248
249 client = create_client_and_test_surface(100, 201, 100, 50);
250 assert(client);
251
252 /* move pointer outside top center */
253 x = client->surface->x + client->surface->width/2;
254 y = client->surface->y - 1;
255 assert(!surface_contains(client->surface, x, y));
256 check_pointer_move(client, x, y);
257
258 /* move pointer on top center */
259 y += 1;
260 assert(surface_contains(client->surface, x, y));
261 check_pointer_move(client, x, y);
262
263 /* move pointer outside top center */
264 y -= 1;
265 assert(!surface_contains(client->surface, x, y));
266 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300267
268 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200269}
270
271TEST(test_pointer_bottom_center)
272{
273 struct client *client;
274 int x, y;
275
276 client = create_client_and_test_surface(100, 45, 67, 100);
277 assert(client);
278
279 /* move pointer outside bottom center */
280 x = client->surface->x + client->surface->width/2;
281 y = client->surface->y + client->surface->height;
282 assert(!surface_contains(client->surface, x, y));
283 check_pointer_move(client, x, y);
284
285 /* move pointer on bottom center */
286 y -= 1;
287 assert(surface_contains(client->surface, x, y));
288 check_pointer_move(client, x, y);
289
290 /* move pointer outside bottom center */
291 y += 1;
292 assert(!surface_contains(client->surface, x, y));
293 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300294
295 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200296}
297
298TEST(test_pointer_left_center)
299{
300 struct client *client;
301 int x, y;
302
303 client = create_client_and_test_surface(167, 45, 78, 100);
304 assert(client);
305
306 /* move pointer outside left center */
307 x = client->surface->x - 1;
308 y = client->surface->y + client->surface->height/2;
309 assert(!surface_contains(client->surface, x, y));
310 check_pointer_move(client, x, y);
311
312 /* move pointer on left center */
313 x += 1;
314 assert(surface_contains(client->surface, x, y));
315 check_pointer_move(client, x, y);
316
317 /* move pointer outside left center */
318 x -= 1;
319 assert(!surface_contains(client->surface, x, y));
320 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300321
322 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200323}
324
325TEST(test_pointer_right_center)
326{
327 struct client *client;
328 int x, y;
329
330 client = create_client_and_test_surface(110, 37, 100, 46);
331 assert(client);
332
333 /* move pointer outside right center */
334 x = client->surface->x + client->surface->width;
335 y = client->surface->y + client->surface->height/2;
336 assert(!surface_contains(client->surface, x, y));
337 check_pointer_move(client, x, y);
338
339 /* move pointer on right center */
340 x -= 1;
341 assert(surface_contains(client->surface, x, y));
342 check_pointer_move(client, x, y);
343
344 /* move pointer outside right center */
345 x += 1;
346 assert(!surface_contains(client->surface, x, y));
347 check_pointer_move(client, x, y);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300348
349 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200350}
351
352TEST(test_pointer_surface_move)
353{
354 struct client *client;
355
356 client = create_client_and_test_surface(100, 100, 100, 100);
357 assert(client);
358
359 /* move pointer outside of client */
360 assert(!surface_contains(client->surface, 50, 50));
361 check_pointer_move(client, 50, 50);
362
363 /* move client center to pointer */
364 move_client(client, 0, 0);
365 assert(surface_contains(client->surface, 50, 50));
366 check_pointer(client, 50, 50);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300367
368 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200369}
370
Alexandros Frantzis903e4452017-12-04 15:34:04 +0200371TEST(pointer_motion_events)
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200372{
Alexandros Frantzis903e4452017-12-04 15:34:04 +0200373 struct client *client = create_client_with_pointer_focus(100, 100,
374 100, 100);
375 struct pointer *pointer = client->input->pointer;
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200376 struct input_timestamps *input_ts =
377 input_timestamps_create_for_pointer(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200378
Alexandros Frantzis21808582017-12-13 13:27:55 +0200379 send_motion(client, &t1, 150, 150);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200380 assert(pointer->x == 50);
381 assert(pointer->y == 50);
Alexandros Frantzis21808582017-12-13 13:27:55 +0200382 assert(pointer->motion_time_msec == timespec_to_msec(&t1));
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200383 assert(timespec_eq(&pointer->motion_time_timespec, &t1));
384
385 input_timestamps_destroy(input_ts);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300386
387 client_destroy(client);
Alexandros Frantzis903e4452017-12-04 15:34:04 +0200388}
389
390TEST(pointer_button_events)
391{
392 struct client *client = create_client_with_pointer_focus(100, 100,
393 100, 100);
394 struct pointer *pointer = client->input->pointer;
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200395 struct input_timestamps *input_ts =
396 input_timestamps_create_for_pointer(client);
Alexandros Frantzis903e4452017-12-04 15:34:04 +0200397
398 assert(pointer->button == 0);
399 assert(pointer->state == 0);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200400
Alexandros Frantzis21808582017-12-13 13:27:55 +0200401 send_button(client, &t1, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200402 assert(pointer->button == BTN_LEFT);
403 assert(pointer->state == WL_POINTER_BUTTON_STATE_PRESSED);
Alexandros Frantzis21808582017-12-13 13:27:55 +0200404 assert(pointer->button_time_msec == timespec_to_msec(&t1));
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200405 assert(timespec_eq(&pointer->button_time_timespec, &t1));
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200406
Alexandros Frantzis21808582017-12-13 13:27:55 +0200407 send_button(client, &t2, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200408 assert(pointer->button == BTN_LEFT);
409 assert(pointer->state == WL_POINTER_BUTTON_STATE_RELEASED);
Alexandros Frantzis21808582017-12-13 13:27:55 +0200410 assert(pointer->button_time_msec == timespec_to_msec(&t2));
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200411 assert(timespec_eq(&pointer->button_time_timespec, &t2));
412
413 input_timestamps_destroy(input_ts);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300414
415 client_destroy(client);
Alexandros Frantzis5d6acf82017-12-04 15:34:03 +0200416}
Alexandros Frantzisb0341ae2017-12-18 12:16:55 +0200417
418TEST(pointer_axis_events)
419{
420 struct client *client = create_client_with_pointer_focus(100, 100,
421 100, 100);
422 struct pointer *pointer = client->input->pointer;
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200423 struct input_timestamps *input_ts =
424 input_timestamps_create_for_pointer(client);
Alexandros Frantzisb0341ae2017-12-18 12:16:55 +0200425
426 send_axis(client, &t1, 1, 1.0);
427 assert(pointer->axis == 1);
428 assert(pointer->axis_value == 1.0);
429 assert(pointer->axis_time_msec == timespec_to_msec(&t1));
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200430 assert(timespec_eq(&pointer->axis_time_timespec, &t1));
Alexandros Frantzisb0341ae2017-12-18 12:16:55 +0200431
432 send_axis(client, &t2, 2, 0.0);
433 assert(pointer->axis == 2);
434 assert(pointer->axis_stop_time_msec == timespec_to_msec(&t2));
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200435 assert(timespec_eq(&pointer->axis_stop_time_timespec, &t2));
436
437 input_timestamps_destroy(input_ts);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300438
439 client_destroy(client);
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200440}
441
442TEST(pointer_timestamps_stop_after_input_timestamps_object_is_destroyed)
443{
444 struct client *client = create_client_with_pointer_focus(100, 100,
445 100, 100);
446 struct pointer *pointer = client->input->pointer;
447 struct input_timestamps *input_ts =
448 input_timestamps_create_for_pointer(client);
449
450 send_button(client, &t1, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
451 assert(pointer->button == BTN_LEFT);
452 assert(pointer->state == WL_POINTER_BUTTON_STATE_PRESSED);
453 assert(pointer->button_time_msec == timespec_to_msec(&t1));
454 assert(timespec_eq(&pointer->button_time_timespec, &t1));
455
456 input_timestamps_destroy(input_ts);
457
458 send_button(client, &t2, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
459 assert(pointer->button == BTN_LEFT);
460 assert(pointer->state == WL_POINTER_BUTTON_STATE_RELEASED);
461 assert(pointer->button_time_msec == timespec_to_msec(&t2));
462 assert(timespec_is_zero(&pointer->button_time_timespec));
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300463
464 client_destroy(client);
Alexandros Frantzisdb907b72018-02-20 14:06:26 +0200465}
466
467TEST(pointer_timestamps_stop_after_client_releases_wl_pointer)
468{
469 struct client *client = create_client_with_pointer_focus(100, 100,
470 100, 100);
471 struct pointer *pointer = client->input->pointer;
472 struct input_timestamps *input_ts =
473 input_timestamps_create_for_pointer(client);
474
475 send_motion(client, &t1, 150, 150);
476 assert(pointer->x == 50);
477 assert(pointer->y == 50);
478 assert(pointer->motion_time_msec == timespec_to_msec(&t1));
479 assert(timespec_eq(&pointer->motion_time_timespec, &t1));
480
481 wl_pointer_release(client->input->pointer->wl_pointer);
482
483 /* Set input_timestamp to an arbitrary value (different from t1, t2
484 * and 0) and check that it is not changed by sending the event.
485 * This is preferred over just checking for 0, since 0 is used
486 * internally for resetting the timestamp after handling an input
487 * event and checking for it here may lead to false negatives. */
488 pointer->input_timestamp = t_other;
489 send_motion(client, &t2, 175, 175);
490 assert(timespec_eq(&pointer->input_timestamp, &t_other));
491
492 input_timestamps_destroy(input_ts);
Pekka Paalanen689e8b32021-06-15 16:41:48 +0300493
494 free(client->input->pointer);
495 client->input->pointer = NULL;
496 client_destroy(client);
Alexandros Frantzisb0341ae2017-12-18 12:16:55 +0200497}