1 /**
2 * @file lv_qnx.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_qnx.h"
10 #if LV_USE_QNX
11 #include <stdbool.h>
12 #include "../../core/lv_refr.h"
13 #include "../../stdlib/lv_string.h"
14 #include "../../core/lv_global.h"
15 #include "../../display/lv_display_private.h"
16 #include "../../lv_init.h"
17 #include <stdlib.h>
18 #include <time.h>
19 #include <screen/screen.h>
20 #include <sys/keycodes.h>
21
22 /*********************
23 * DEFINES
24 *********************/
25
26 /**********************
27 * TYPEDEFS
28 **********************/
29 typedef struct {
30 screen_window_t window;
31 screen_buffer_t buffers[LV_QNX_BUF_COUNT];
32 int bufidx;
33 bool managed;
34 lv_indev_t * pointer;
35 lv_indev_t * keyboard;
36 } lv_qnx_window_t;
37
38 typedef struct {
39 int pos[2];
40 int buttons;
41 } lv_qnx_pointer_t;
42
43 typedef struct {
44 int key;
45 int flags;
46 } lv_qnx_keyboard_t;
47
48 /**********************
49 * STATIC PROTOTYPES
50 **********************/
51 static uint32_t get_ticks(void);
52 static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p);
53 static bool window_create(lv_display_t * disp);
54 static bool init_display_from_window(lv_display_t * disp);
55 static void get_pointer(lv_indev_t * indev, lv_indev_data_t * data);
56 static void get_key(lv_indev_t * indev, lv_indev_data_t * data);
57 static bool handle_pointer_event(lv_display_t * disp, screen_event_t event);
58 static bool handle_keyboard_event(lv_display_t * disp, screen_event_t event);
59 static void release_disp_cb(lv_event_t * e);
60 static void refresh_cb(lv_timer_t * timer);
61
62 /***********************
63 * GLOBAL PROTOTYPES
64 ***********************/
65
66 static screen_context_t context;
67
68 /**********************
69 * STATIC VARIABLES
70 **********************/
71
72 /**********************
73 * MACROS
74 **********************/
75
76 /**********************
77 * GLOBAL FUNCTIONS
78 **********************/
79
lv_qnx_window_create(int32_t hor_res,int32_t ver_res)80 lv_display_t * lv_qnx_window_create(int32_t hor_res, int32_t ver_res)
81 {
82 static bool inited = false;
83
84 if(!inited) {
85 if(screen_create_context(&context,
86 SCREEN_APPLICATION_CONTEXT) != 0) {
87 LV_LOG_ERROR("screen_create_context: %s", strerror(errno));
88 return NULL;
89 }
90
91 lv_tick_set_cb(get_ticks);
92 inited = true;
93 }
94
95 lv_qnx_window_t * dsc = lv_malloc_zeroed(sizeof(lv_qnx_window_t));
96 LV_ASSERT_MALLOC(dsc);
97 if(dsc == NULL) return NULL;
98
99 lv_display_t * disp = lv_display_create(hor_res, ver_res);
100 if(disp == NULL) {
101 lv_free(dsc);
102 return NULL;
103 }
104 lv_display_add_event_cb(disp, release_disp_cb, LV_EVENT_DELETE, disp);
105 lv_display_set_driver_data(disp, dsc);
106 if(!window_create(disp)) {
107 lv_free(dsc);
108 return NULL;
109 }
110
111 lv_display_set_flush_cb(disp, flush_cb);
112
113 if(!init_display_from_window(disp)) {
114 screen_destroy_window(dsc->window);
115 lv_free(dsc);
116 return NULL;
117 }
118
119 /*Replace the default refresh timer handler, so that we can run it on
120 *demand instead of constantly.*/
121 lv_timer_t * refr_timer = lv_display_get_refr_timer(disp);
122 lv_timer_set_cb(refr_timer, refresh_cb);
123
124 return disp;
125 }
126
lv_qnx_window_set_title(lv_display_t * disp,const char * title)127 void lv_qnx_window_set_title(lv_display_t * disp, const char * title)
128 {
129 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
130 if(!dsc->managed) {
131 /*Can't set title if there is no window manager*/
132 return;
133 }
134
135 screen_event_t event;
136 screen_create_event(&event);
137
138 char title_buf[64];
139 lv_snprintf(title_buf, sizeof(title_buf), "Title=%s", title);
140
141 int type = SCREEN_EVENT_MANAGER;
142 screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type);
143 screen_set_event_property_cv(event, SCREEN_PROPERTY_USER_DATA,
144 sizeof(title_buf), title_buf);
145 screen_set_event_property_pv(event, SCREEN_PROPERTY_WINDOW,
146 (void **)&dsc->window);
147 screen_set_event_property_pv(event, SCREEN_PROPERTY_CONTEXT,
148 (void **)&context);
149
150 screen_inject_event(NULL, event);
151 }
152
lv_qnx_add_pointer_device(lv_display_t * disp)153 bool lv_qnx_add_pointer_device(lv_display_t * disp)
154 {
155 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
156 if(dsc->pointer != NULL) {
157 /*Only one pointer device per display*/
158 return false;
159 }
160
161 lv_qnx_pointer_t * ptr_dsc = lv_malloc_zeroed(sizeof(lv_qnx_pointer_t));
162 LV_ASSERT_MALLOC(ptr_dsc);
163 if(ptr_dsc == NULL) {
164 return false;
165 }
166
167 dsc->pointer = lv_indev_create();
168 if(dsc->pointer == NULL) {
169 lv_free(ptr_dsc);
170 return false;
171 }
172
173 lv_indev_set_type(dsc->pointer, LV_INDEV_TYPE_POINTER);
174 lv_indev_set_read_cb(dsc->pointer, get_pointer);
175 lv_indev_set_driver_data(dsc->pointer, ptr_dsc);
176 lv_indev_set_mode(dsc->pointer, LV_INDEV_MODE_EVENT);
177 return true;
178 }
179
lv_qnx_add_keyboard_device(lv_display_t * disp)180 bool lv_qnx_add_keyboard_device(lv_display_t * disp)
181 {
182 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
183 if(dsc->keyboard != NULL) {
184 /*Only one keyboard device per display*/
185 return false;
186 }
187
188 lv_qnx_keyboard_t * kbd_dsc = lv_malloc_zeroed(sizeof(lv_qnx_keyboard_t));
189 LV_ASSERT_MALLOC(kbd_dsc);
190 if(dsc == NULL) {
191 return false;
192 }
193
194 dsc->keyboard = lv_indev_create();
195 if(dsc->keyboard == NULL) {
196 lv_free(kbd_dsc);
197 return false;
198 }
199
200 lv_indev_set_type(dsc->keyboard, LV_INDEV_TYPE_KEYPAD);
201 lv_indev_set_read_cb(dsc->keyboard, get_key);
202 lv_indev_set_driver_data(dsc->keyboard, kbd_dsc);
203 lv_indev_set_mode(dsc->keyboard, LV_INDEV_MODE_EVENT);
204 return true;
205 }
206
lv_qnx_event_loop(lv_display_t * disp)207 int lv_qnx_event_loop(lv_display_t * disp)
208 {
209 lv_refr_now(disp);
210
211 /*Run the event loop*/
212 screen_event_t event;
213 if(screen_create_event(&event) != 0) {
214 LV_LOG_ERROR("screen_create_event: %s", strerror(errno));
215 return EXIT_FAILURE;
216 }
217
218 uint64_t timeout_ns = 0;
219 for(;;) {
220 /*Wait for an event, timing out after 16ms if animations are running*/
221 if(screen_get_event(context, event, timeout_ns) != 0) {
222 LV_LOG_ERROR("screen_get_event: %s", strerror(errno));
223 return EXIT_FAILURE;
224 }
225
226 /*Get the event's type*/
227 int type;
228 if(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type)
229 != 0) {
230 LV_LOG_ERROR("screen_get_event_property_iv(TYPE): %s", strerror(errno));
231 return EXIT_FAILURE;
232 }
233
234 if(type == SCREEN_EVENT_POINTER) {
235 if(!handle_pointer_event(disp, event)) {
236 return EXIT_FAILURE;
237 }
238 }
239 else if(type == SCREEN_EVENT_KEYBOARD) {
240 if(!handle_keyboard_event(disp, event)) {
241 return EXIT_FAILURE;
242 }
243 }
244 else if(type == SCREEN_EVENT_MANAGER) {
245 /*Only sub-type supported is closing the window*/
246 break;
247 }
248
249 /*Calculate the next timeout*/
250 uint32_t timeout_ms = lv_timer_handler();
251 if(timeout_ms == LV_NO_TIMER_READY) {
252 timeout_ns = -1ULL;
253 }
254 else {
255 timeout_ns = (uint64_t)timeout_ms * 1000000UL;
256 }
257 }
258
259 return EXIT_SUCCESS;
260 }
261
262 /**********************
263 * STATIC FUNCTIONS
264 **********************/
265
get_ticks(void)266 static uint32_t get_ticks(void)
267 {
268 uint64_t const ns = clock_gettime_mon_ns();
269 return (uint32_t)(ns / 1000000UL);
270 }
271
flush_cb(lv_display_t * disp,const lv_area_t * area,uint8_t * px_map)272 static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
273 {
274 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
275 if(screen_post_window(dsc->window, dsc->buffers[dsc->bufidx], 0, NULL, 0)
276 != 0) {
277 LV_LOG_ERROR("screen_post_window: %s", strerror(errno));
278 }
279
280 #if (LV_QNX_BUF_COUNT > 1)
281 dsc->bufidx = 1 - dsc->bufidx;
282 #endif
283
284 lv_display_flush_ready(disp);
285 }
286
window_create(lv_display_t * disp)287 static bool window_create(lv_display_t * disp)
288 {
289 /*Create a window*/
290 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
291 if(screen_create_window(&dsc->window, context) != 0) {
292 LV_LOG_ERROR("screen_create_window: %s", strerror(errno));
293 return false;
294 }
295
296 /*Set window properties*/
297 int rect[] = { 0, 0, disp->hor_res, disp->ver_res };
298 if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_POSITION,
299 &rect[0]) != 0) {
300 LV_LOG_ERROR("screen_window_set_property_iv(POSITION): %s", strerror(errno));
301 return false;
302 }
303
304 if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_SIZE,
305 &rect[2]) != 0) {
306 LV_LOG_ERROR("screen_window_set_property_iv(SIZE): %s", strerror(errno));
307 return false;
308 }
309
310 if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_SOURCE_SIZE,
311 &rect[2]) != 0) {
312 LV_LOG_ERROR("screen_window_set_property_iv(SOURCE_SIZE): %s", strerror(errno));
313 return NULL;
314 }
315
316 int usage = SCREEN_USAGE_WRITE;
317 if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_USAGE,
318 &usage) != 0) {
319 LV_LOG_ERROR("screen_window_set_property_iv(USAGE): %s", strerror(errno));
320 return NULL;
321 }
322
323 int format = SCREEN_FORMAT_RGBA8888;
324 if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_FORMAT,
325 &format) != 0) {
326 LV_LOG_ERROR("screen_window_set_property_iv(USAGE): %s", strerror(errno));
327 return NULL;
328 }
329
330 /*Initialize window buffers*/
331 if(screen_create_window_buffers(dsc->window, LV_QNX_BUF_COUNT) != 0) {
332 LV_LOG_ERROR("screen_create_window_buffers: %s", strerror(errno));
333 return false;
334 }
335
336 if(screen_get_window_property_pv(dsc->window, SCREEN_PROPERTY_BUFFERS,
337 (void **)&dsc->buffers) != 0) {
338 LV_LOG_ERROR("screen_get_window_property_pv(BUFFERS): %s", strerror(errno));
339 return false;
340 }
341
342 /*Connect to the window manager. Can legitimately fail if one is not running*/
343 if(screen_manage_window(dsc->window, "Frame=Y") == 0) {
344 dsc->managed = true;
345 }
346 else {
347 dsc->managed = false;
348 }
349
350 int visible = 1;
351 if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_VISIBLE,
352 &visible) != 0) {
353 LV_LOG_ERROR("screen_set_window_property_iv(VISIBLE): %s", strerror(errno));
354 return false;
355 }
356
357 return true;
358 }
359
init_display_from_window(lv_display_t * disp)360 static bool init_display_from_window(lv_display_t * disp)
361 {
362 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
363
364 int bufsize;
365 if(screen_get_buffer_property_iv(dsc->buffers[0], SCREEN_PROPERTY_SIZE,
366 &bufsize) == -1) {
367 LV_LOG_ERROR("screen_get_buffer_property_iv(SIZE): %s", strerror(errno));
368 return false;
369 }
370
371 void * ptr1 = NULL;
372 if(screen_get_buffer_property_pv(dsc->buffers[0], SCREEN_PROPERTY_POINTER,
373 &ptr1) == -1) {
374 LV_LOG_ERROR("screen_get_buffer_property_pv(POINTER): %s", strerror(errno));
375 return false;
376 }
377
378 void * ptr2 = NULL;
379 #if (LV_QNX_BUF_COUNT > 1)
380 if(screen_get_buffer_property_pv(dsc->buffers[1], SCREEN_PROPERTY_POINTER,
381 &ptr2) == -1) {
382 LV_LOG_ERROR("screen_get_buffer_property_pv(POINTER): %s", strerror(errno));
383 return false;
384 }
385 #endif
386
387 lv_display_set_buffers(disp, ptr1, ptr2, bufsize, LV_DISPLAY_RENDER_MODE_FULL);
388 return true;
389 }
390
release_disp_cb(lv_event_t * e)391 static void release_disp_cb(lv_event_t * e)
392 {
393 lv_display_t * disp = (lv_display_t *) lv_event_get_user_data(e);
394 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
395
396 if(dsc->window != NULL) {
397 screen_destroy_window(dsc->window);
398 }
399
400 if(dsc->pointer != NULL) {
401 lv_free(dsc->pointer);
402 }
403
404 if(dsc->keyboard != NULL) {
405 lv_free(dsc->keyboard);
406 }
407
408 lv_free(dsc);
409 lv_display_set_driver_data(disp, NULL);
410 }
411
get_pointer(lv_indev_t * indev,lv_indev_data_t * data)412 static void get_pointer(lv_indev_t * indev, lv_indev_data_t * data)
413 {
414 lv_qnx_pointer_t * dsc = lv_indev_get_driver_data(indev);
415
416 data->point.x = dsc->pos[0];
417 data->point.y = dsc->pos[1];
418 if((dsc->buttons & SCREEN_LEFT_MOUSE_BUTTON) != 0) {
419 data->state = LV_INDEV_STATE_PRESSED;
420 }
421 else {
422 data->state = LV_INDEV_STATE_RELEASED;
423 }
424 }
425
handle_pointer_event(lv_display_t * disp,screen_event_t event)426 static bool handle_pointer_event(lv_display_t * disp, screen_event_t event)
427 {
428 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
429 if(dsc->pointer == NULL) return true;
430
431 lv_qnx_pointer_t * ptr_dsc = lv_indev_get_driver_data(dsc->pointer);
432
433 if(screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION,
434 ptr_dsc->pos)
435 != 0) {
436 LV_LOG_ERROR("screen_get_event_property_iv(SOURCE_POSITION): %s", strerror(errno));
437 return false;
438 }
439
440 if(screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS,
441 &ptr_dsc->buttons)
442 != 0) {
443 LV_LOG_ERROR("screen_get_event_property_iv(BUTTONS): %s", strerror(errno));
444 return false;
445 }
446
447 lv_indev_read(dsc->pointer);
448 return true;
449 }
450
get_key(lv_indev_t * indev,lv_indev_data_t * data)451 static void get_key(lv_indev_t * indev, lv_indev_data_t * data)
452 {
453 lv_qnx_keyboard_t * dsc = lv_indev_get_driver_data(indev);
454
455 if((dsc->flags & KEY_DOWN) != 0) {
456 data->state = LV_INDEV_STATE_PRESSED;
457 data->key = dsc->key;
458 }
459 else {
460 data->state = LV_INDEV_STATE_RELEASED;
461 }
462 }
463
handle_keyboard_event(lv_display_t * disp,screen_event_t event)464 static bool handle_keyboard_event(lv_display_t * disp, screen_event_t event)
465 {
466 lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
467 if(dsc->keyboard == NULL) return true;
468
469 lv_qnx_keyboard_t * kbd_dsc = lv_indev_get_driver_data(dsc->keyboard);
470
471 /*Get event data*/
472 if(screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS,
473 &kbd_dsc->flags)
474 != 0) {
475 LV_LOG_ERROR("screen_get_event_property_iv(FLAGS): %s", strerror(errno));
476 return false;
477 }
478
479 if(screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM,
480 &kbd_dsc->key)
481 != 0) {
482 LV_LOG_ERROR("screen_get_event_property_iv(SYM): %s", strerror(errno));
483 return false;
484 }
485
486 /*Translate special keys*/
487 switch(kbd_dsc->key) {
488 case KEYCODE_UP:
489 kbd_dsc->key = LV_KEY_UP;
490 break;
491
492 case KEYCODE_DOWN:
493 kbd_dsc->key = LV_KEY_DOWN;
494 break;
495
496 case KEYCODE_LEFT:
497 kbd_dsc->key = LV_KEY_LEFT;
498 break;
499
500 case KEYCODE_RIGHT:
501 kbd_dsc->key = LV_KEY_RIGHT;
502 break;
503
504 case KEYCODE_RETURN:
505 kbd_dsc->key = LV_KEY_ENTER;
506 break;
507
508 case KEYCODE_BACKSPACE:
509 kbd_dsc->key = LV_KEY_BACKSPACE;
510 break;
511
512 case KEYCODE_HOME:
513 kbd_dsc->key = LV_KEY_HOME;
514 break;
515
516 case KEYCODE_END:
517 kbd_dsc->key = LV_KEY_END;
518 break;
519
520 case KEYCODE_DELETE:
521 kbd_dsc->key = LV_KEY_DEL;
522 break;
523
524 default:
525 /*Ignore other non-ASCII keys, including modifiers*/
526 if(kbd_dsc->key > 0xff) return true;
527 }
528
529 lv_indev_read(dsc->keyboard);
530 return true;
531 }
532
refresh_cb(lv_timer_t * timer)533 static void refresh_cb(lv_timer_t * timer)
534 {
535 /*Refresh the window on timeout, but disable the timer. Any callback can
536 *re-enable it.*/
537 lv_display_t * disp = timer->user_data;
538 lv_refr_now(disp);
539 lv_timer_pause(timer);
540 }
541
542 #endif /*LV_USE_QNX*/
543