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