source: mainline/uspace/srv/hid/display/test/display.c@ 5271e4c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5271e4c was 8aef01c, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Configurable display double-buffering

On by default (since turning off creates flicker in the absence of
front-to-back rendering). This is the quick and dirty way: display
server renders locally to a bitmap (using mem GC) and renders the
bitmap when ready.

The more sophisticated way would be to implement buffering in the
display device. That would require, however, enhancing the protocols
to communicate frame boundaries.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*
2 * Copyright (c) 2019 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <disp_srv.h>
30#include <errno.h>
31#include <pcut/pcut.h>
32#include <stdio.h>
33#include <str.h>
34
35#include "../client.h"
36#include "../display.h"
37#include "../seat.h"
38#include "../window.h"
39
40PCUT_INIT;
41
42PCUT_TEST_SUITE(display);
43
44static void test_ds_ev_pending(void *);
45
46static ds_client_cb_t test_ds_client_cb = {
47 .ev_pending = test_ds_ev_pending
48};
49
50static void test_ds_ev_pending(void *arg)
51{
52 bool *called_cb = (bool *) arg;
53 printf("test_ds_ev_pending\n");
54 *called_cb = true;
55}
56
57/** Display creation and destruction. */
58PCUT_TEST(display_create_destroy)
59{
60 ds_display_t *disp;
61 errno_t rc;
62
63 rc = ds_display_create(NULL, df_none, &disp);
64 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
65
66 ds_display_destroy(disp);
67}
68
69/** Basic client operation. */
70PCUT_TEST(display_client)
71{
72 ds_display_t *disp;
73 ds_client_t *client;
74 ds_client_t *c0, *c1;
75 errno_t rc;
76
77 rc = ds_display_create(NULL, df_none, &disp);
78 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
79
80 rc = ds_client_create(disp, &test_ds_client_cb, NULL, &client);
81 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
82
83 c0 = ds_display_first_client(disp);
84 PCUT_ASSERT_EQUALS(c0, client);
85
86 c1 = ds_display_next_client(c0);
87 PCUT_ASSERT_NULL(c1);
88
89 ds_client_destroy(client);
90 ds_display_destroy(disp);
91}
92
93/** Test ds_display_find_window(). */
94PCUT_TEST(display_find_window)
95{
96 ds_display_t *disp;
97 ds_client_t *client;
98 ds_window_t *w0;
99 ds_window_t *w1;
100 ds_window_t *wnd;
101 display_wnd_params_t params;
102 errno_t rc;
103
104 rc = ds_display_create(NULL, df_none, &disp);
105 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
106
107 rc = ds_client_create(disp, &test_ds_client_cb, NULL, &client);
108 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
109
110 display_wnd_params_init(&params);
111 params.rect.p0.x = params.rect.p0.y = 0;
112 params.rect.p1.x = params.rect.p1.y = 1;
113
114 rc = ds_window_create(client, &params, &w1);
115 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
116
117 rc = ds_window_create(client, &params, &w0);
118 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
119
120 wnd = ds_display_first_window(disp);
121 PCUT_ASSERT_EQUALS(w0, wnd);
122
123 wnd = ds_display_next_window(wnd);
124 PCUT_ASSERT_EQUALS(w1, wnd);
125
126 wnd = ds_display_next_window(wnd);
127 PCUT_ASSERT_NULL(wnd);
128
129 wnd = ds_display_last_window(disp);
130 PCUT_ASSERT_EQUALS(w1, wnd);
131
132 wnd = ds_display_prev_window(wnd);
133 PCUT_ASSERT_EQUALS(w0, wnd);
134
135 wnd = ds_display_prev_window(wnd);
136 PCUT_ASSERT_NULL(wnd);
137
138 wnd = ds_display_find_window(disp, w0->id);
139 PCUT_ASSERT_EQUALS(w0, wnd);
140
141 wnd = ds_display_find_window(disp, w1->id);
142 PCUT_ASSERT_EQUALS(w1, wnd);
143
144 wnd = ds_display_find_window(disp, 0);
145 PCUT_ASSERT_NULL(wnd);
146
147 wnd = ds_display_find_window(disp, w0->id + 1);
148 PCUT_ASSERT_NULL(wnd);
149
150 ds_window_destroy(w0);
151 ds_window_destroy(w1);
152 ds_client_destroy(client);
153 ds_display_destroy(disp);
154}
155
156/** Test ds_display_window_by_pos(). */
157PCUT_TEST(display_window_by_pos)
158{
159 ds_display_t *disp;
160 ds_client_t *client;
161 ds_window_t *w0;
162 ds_window_t *w1;
163 ds_window_t *wnd;
164 display_wnd_params_t params;
165 gfx_coord2_t pos;
166 errno_t rc;
167
168 rc = ds_display_create(NULL, df_none, &disp);
169 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
170
171 rc = ds_client_create(disp, &test_ds_client_cb, NULL, &client);
172 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
173
174 display_wnd_params_init(&params);
175 params.rect.p0.x = params.rect.p0.y = 0;
176 params.rect.p1.x = params.rect.p1.y = 100;
177
178 rc = ds_window_create(client, &params, &w0);
179 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
180
181 rc = ds_window_create(client, &params, &w1);
182 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
183
184 w0->dpos.x = 10;
185 w0->dpos.y = 10;
186
187 w1->dpos.x = 400;
188 w1->dpos.y = 400;
189
190 pos.x = 10;
191 pos.y = 10;
192 wnd = ds_display_window_by_pos(disp, &pos);
193 PCUT_ASSERT_EQUALS(w0, wnd);
194
195 pos.x = 400;
196 pos.y = 400;
197 wnd = ds_display_window_by_pos(disp, &pos);
198 PCUT_ASSERT_EQUALS(w1, wnd);
199
200 ds_window_destroy(w0);
201 ds_window_destroy(w1);
202 ds_client_destroy(client);
203 ds_display_destroy(disp);
204}
205
206/** Basic seat operation. */
207PCUT_TEST(display_seat)
208{
209 ds_display_t *disp;
210 ds_seat_t *seat;
211 ds_seat_t *s0, *s1;
212 errno_t rc;
213
214 rc = ds_display_create(NULL, df_none, &disp);
215 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
216
217 rc = ds_seat_create(disp, &seat);
218 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
219
220 s0 = ds_display_first_seat(disp);
221 PCUT_ASSERT_EQUALS(s0, seat);
222
223 s1 = ds_display_next_seat(s0);
224 PCUT_ASSERT_NULL(s1);
225
226 ds_seat_destroy(seat);
227 ds_display_destroy(disp);
228}
229
230/** Test ds_display_post_kbd_event() delivers event to client callback.
231 */
232PCUT_TEST(display_post_kbd_event)
233{
234 ds_display_t *disp;
235 ds_seat_t *seat;
236 ds_client_t *client;
237 ds_window_t *wnd;
238 display_wnd_params_t params;
239 kbd_event_t event;
240 bool called_cb = false;
241 errno_t rc;
242
243 rc = ds_display_create(NULL, df_none, &disp);
244 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
245
246 rc = ds_seat_create(disp, &seat);
247 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
248
249 rc = ds_client_create(disp, &test_ds_client_cb, &called_cb, &client);
250 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
251
252 display_wnd_params_init(&params);
253 params.rect.p0.x = params.rect.p0.y = 0;
254 params.rect.p1.x = params.rect.p1.y = 1;
255
256 rc = ds_window_create(client, &params, &wnd);
257 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
258
259 ds_seat_set_focus(seat, wnd);
260
261 event.type = KEY_PRESS;
262 event.key = KC_ENTER;
263 event.mods = 0;
264 event.c = L'\0';
265
266 called_cb = false;
267
268 rc = ds_display_post_kbd_event(disp, &event);
269 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
270 PCUT_ASSERT_TRUE(called_cb);
271
272 ds_window_destroy(wnd);
273 ds_client_destroy(client);
274 ds_seat_destroy(seat);
275 ds_display_destroy(disp);
276}
277
278/** Test ds_display_post_kbd_event() with Alt-Tab switches focus.
279 */
280PCUT_TEST(display_post_kbd_event_alt_tab)
281{
282 ds_display_t *disp;
283 ds_seat_t *seat;
284 ds_client_t *client;
285 ds_window_t *w0, *w1;
286 display_wnd_params_t params;
287 kbd_event_t event;
288 bool called_cb = false;
289 errno_t rc;
290
291 rc = ds_display_create(NULL, df_none, &disp);
292 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
293
294 rc = ds_seat_create(disp, &seat);
295 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
296
297 rc = ds_client_create(disp, &test_ds_client_cb, &called_cb, &client);
298 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
299
300 display_wnd_params_init(&params);
301 params.rect.p0.x = params.rect.p0.y = 0;
302 params.rect.p1.x = params.rect.p1.y = 1;
303
304 rc = ds_window_create(client, &params, &w0);
305 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
306
307 rc = ds_window_create(client, &params, &w1);
308 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
309
310 ds_seat_set_focus(seat, w0);
311
312 event.type = KEY_PRESS;
313 event.key = KC_TAB;
314 event.mods = KM_ALT;
315 event.c = L'\0';
316
317 called_cb = false;
318
319 rc = ds_display_post_kbd_event(disp, &event);
320 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
321
322 /* Got gocus/unfocus events */
323 PCUT_ASSERT_TRUE(called_cb);
324
325 /* Next window should be focused */
326 PCUT_ASSERT_EQUALS(w1, seat->focus);
327
328 called_cb = false;
329
330 rc = ds_display_post_kbd_event(disp, &event);
331 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
332
333 /* Got gocus/unfocus events */
334 PCUT_ASSERT_TRUE(called_cb);
335
336 /* Focus should be back to the first window */
337 PCUT_ASSERT_EQUALS(w0, seat->focus);
338
339 ds_window_destroy(w0);
340 ds_window_destroy(w1);
341 ds_client_destroy(client);
342 ds_seat_destroy(seat);
343 ds_display_destroy(disp);
344}
345
346/** Test ds_display_post_ptd_event() with click on window switches focus
347 */
348PCUT_TEST(display_post_ptd_event_wnd_switch)
349{
350 ds_display_t *disp;
351 ds_seat_t *seat;
352 ds_client_t *client;
353 ds_window_t *w0, *w1;
354 display_wnd_params_t params;
355 ptd_event_t event;
356 bool called_cb = false;
357 errno_t rc;
358
359 rc = ds_display_create(NULL, df_none, &disp);
360 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
361
362 rc = ds_seat_create(disp, &seat);
363 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
364
365 rc = ds_client_create(disp, &test_ds_client_cb, &called_cb, &client);
366 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
367
368 /*
369 * For PTD_MOVE to work we need to set display dimensions (as pointer
370 * move is clipped to the display rectangle. Here we do it directly
371 * instead of adding a display device.
372 */
373 disp->rect.p0.x = 0;
374 disp->rect.p0.y = 0;
375 disp->rect.p1.x = 500;
376 disp->rect.p1.y = 500;
377
378 display_wnd_params_init(&params);
379 params.rect.p0.x = params.rect.p0.y = 0;
380 params.rect.p1.x = params.rect.p1.y = 1;
381
382 rc = ds_window_create(client, &params, &w0);
383 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
384
385 rc = ds_window_create(client, &params, &w1);
386 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
387
388 w0->dpos.x = 10;
389 w0->dpos.y = 10;
390
391 w1->dpos.x = 400;
392 w1->dpos.y = 400;
393
394 ds_seat_set_focus(seat, w0);
395
396 event.type = PTD_MOVE;
397 event.dmove.x = 400;
398 event.dmove.y = 400;
399 rc = ds_display_post_ptd_event(disp, &event);
400 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
401
402 event.type = PTD_PRESS;
403 event.btn_num = 1;
404 rc = ds_display_post_ptd_event(disp, &event);
405 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
406
407 PCUT_ASSERT_EQUALS(w1, seat->focus);
408
409 event.type = PTD_RELEASE;
410 event.btn_num = 1;
411 rc = ds_display_post_ptd_event(disp, &event);
412 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
413
414 event.type = PTD_MOVE;
415 event.dmove.x = -400 + 10;
416 event.dmove.y = -400 + 10;
417 rc = ds_display_post_ptd_event(disp, &event);
418 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
419
420 event.type = PTD_PRESS;
421 event.btn_num = 1;
422 rc = ds_display_post_ptd_event(disp, &event);
423 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
424
425 PCUT_ASSERT_EQUALS(w0, seat->focus);
426
427 ds_window_destroy(w0);
428 ds_window_destroy(w1);
429 ds_client_destroy(client);
430 ds_seat_destroy(seat);
431 ds_display_destroy(disp);
432}
433
434PCUT_EXPORT(display);
Note: See TracBrowser for help on using the repository browser.