feat(drivers): initial implementation of a QNX screen driver (#6507)

Co-authored-by: Elad Lahav <elahav@qnx.com>
This commit is contained in:
elahav 2024-07-25 08:26:09 -04:00 committed by GitHub
parent 91c64fc029
commit 91cd8ecf90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 1988 additions and 0 deletions

View File

@ -1724,6 +1724,15 @@ menu "LVGL configuration"
bool "Enable debug mode for OpenGL"
depends on LV_USE_OPENGLES
default n
config LV_USE_QNX
bool "Use a QNX Screen window as a display"
default n
config LV_QNX_BUF_COUNT
int
depends on LV_USE_QNX
default 1
endmenu
menu "Examples"

123
docs/integration/os/qnx.rst Normal file
View File

@ -0,0 +1,123 @@
===
QNX
===
What is QNX?
------------
QNX is a commercial operating system first released in 1980. The operating
system is based on a micro-kernel design, with the file system(s), network
stack, and various other drivers each running in its own process with a separate
address space.
See www.qnx.com for more details.
Highlight of QNX
~~~~~~~~~~~~~~~~
- 64-bit only, runs on x86_64 and ARMv8
- Requires an MMU as the design mandates separation among processes
- Support for thousands of processes and millions of threads
- Up to 64 cores, up to 16TB of RAM
- Virtualization support (as host and guest)
- Full POSIX compatibility
- Safety certification to various automotive, industrial and medical standards
How to run LVGL on QNX?
-----------------------
Build LVGL
~~~~~~~~~~
The top-level `qnx` directory includes a recursive make file for building LVGL,
both as a shared library and as a static library for the supported
architectures. To build all libraries, simply invoke `make` in this directory:
.. code:: shell
# cd $(LVGL_ROOT)/qnx
# make
If you prefer to build for a specific architecture and variant, go to the
appropriate directory and run `make` there. For example, to build a shared
library for ARMv8:
.. code:: shell
# cd $(LVGL_ROOT)/qnx/aarch64/so.le
# make
As a general rule, if you only want to have one LVGL application in your system
then it is better to use a static library. If you have more than one, and
especially if they run concurrently, it is better to use the shared library.
Before building the library, you may wish to edit `$(LVGL_ROOT)/qnx/lv_conf.h`,
e.g. to enable double-buffering.
Writing a LVGL Application
~~~~~~~~~~~~~~~~~~~~~~~~~~
To create a LVGL application for QNX, follow these steps in your code:
1. Initialize the library.
2. Create a window.
3. Add the input devices.
4. Create the UI.
5. Run the event loop.
Steps 2, 3 and 5 use QNX-specific calls, but the rest of the code should be
identical to that of a LVGL application written for any other platform.
The following code shows how to create a "Hello World" application:
.. code:: c
#include <lvgl.h>
int
main(int argc, char **argv)
{
/* Initialize the library. */
lv_init();
/* Create a 800x480 window. */
lv_display_t *disp = lv_qnx_window_create(800, 480);
lv_qnx_window_set_title(disp, "LVGL Example");
/* Add a keyboard and mouse devices. */
lv_qnx_add_keyboard_device(disp);
lv_qnx_add_pointer_device(disp);
/* Generate the UI. */
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
lv_obj_t * label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Hello world");
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
/* Run the event loop until it exits. */
return lv_qnx_event_loop(disp);
}
Build the Application
~~~~~~~~~~~~~~~~~~~~~
Building the application consists of compiling the source with the LVGL headers,
and then linking against the library. This can be done in many ways, using
different build systems. The following is a simple make file for the example
above, which builds for ARMv8 with the shared library:
.. code:: makefile
CC=qcc -Vgcc_ntoaarch64le
LVGL_DIR=$(HOME)/src/lvgl
CCFLAGS=-I$(LVGL_DIR)/qnx -I$(LVGL_DIR)
LDFLAGS=-lscreen -llvgl -L$(LVGL_DIR)/qnx/aarch64/so.le
lvgl_example: lvgl_example.c
$(CC) $(CCFLAGS) -Wall -o $@ $< $(LDFLAGS)
clean:
rm -f *.o *~ lvgl_example

2
env_support/qnx/Makefile Normal file
View File

@ -0,0 +1,2 @@
LIST=CPU
include recurse.mk

View File

@ -0,0 +1,2 @@
LIST=VARIANT
include recurse.mk

View File

@ -0,0 +1 @@
include ../../common.mk

View File

@ -0,0 +1 @@
include ../../common.mk

113
env_support/qnx/common.mk Normal file
View File

@ -0,0 +1,113 @@
ifndef QCONFIG
QCONFIG=qconfig.mk
endif
include $(QCONFIG)
define PINFO
PINFO DESCRIPTION = Light and Versatile Graphics Library
endef
INSTALLDIR=
NAME=lvgl
USEFILE=
SRC_ROOT=$(PROJECT_ROOT)/../../src
EXTRA_SRCVPATH=$(SRC_ROOT) \
$(SRC_ROOT)/libs \
$(SRC_ROOT)/libs/bmp \
$(SRC_ROOT)/libs/libjpeg_turbo \
$(SRC_ROOT)/libs/fsdrv \
$(SRC_ROOT)/libs/libpng \
$(SRC_ROOT)/libs/bin_decoder \
$(SRC_ROOT)/libs/tiny_ttf \
$(SRC_ROOT)/libs/barcode \
$(SRC_ROOT)/libs/rlottie \
$(SRC_ROOT)/libs/qrcode \
$(SRC_ROOT)/libs/lz4 \
$(SRC_ROOT)/libs/ffmpeg \
$(SRC_ROOT)/libs/tjpgd \
$(SRC_ROOT)/libs/thorvg \
$(SRC_ROOT)/libs/thorvg/rapidjson \
$(SRC_ROOT)/libs/thorvg/rapidjson/internal \
$(SRC_ROOT)/libs/thorvg/rapidjson/error \
$(SRC_ROOT)/libs/lodepng \
$(SRC_ROOT)/libs/rle \
$(SRC_ROOT)/libs/gif \
$(SRC_ROOT)/libs/freetype \
$(SRC_ROOT)/draw \
$(SRC_ROOT)/draw/vg_lite \
$(SRC_ROOT)/draw/sw \
$(SRC_ROOT)/draw/sw/arm2d \
$(SRC_ROOT)/draw/sw/blend \
$(SRC_ROOT)/draw/sw/blend/helium \
$(SRC_ROOT)/draw/sw/blend/arm2d \
$(SRC_ROOT)/draw/sw/blend/neon \
$(SRC_ROOT)/misc \
$(SRC_ROOT)/misc/cache \
$(SRC_ROOT)/font \
$(SRC_ROOT)/stdlib \
$(SRC_ROOT)/stdlib/builtin \
$(SRC_ROOT)/stdlib/rtthread \
$(SRC_ROOT)/stdlib/clib \
$(SRC_ROOT)/stdlib/micropython \
$(SRC_ROOT)/drivers \
$(SRC_ROOT)/drivers/qnx \
$(SRC_ROOT)/themes \
$(SRC_ROOT)/themes/simple \
$(SRC_ROOT)/themes/mono \
$(SRC_ROOT)/themes/default \
$(SRC_ROOT)/display \
$(SRC_ROOT)/indev \
$(SRC_ROOT)/core \
$(SRC_ROOT)/tick \
$(SRC_ROOT)/others \
$(SRC_ROOT)/others/monkey \
$(SRC_ROOT)/others/ime \
$(SRC_ROOT)/others/snapshot \
$(SRC_ROOT)/others/file_explorer \
$(SRC_ROOT)/others/imgfont \
$(SRC_ROOT)/others/fragment \
$(SRC_ROOT)/others/observer \
$(SRC_ROOT)/others/vg_lite_tvg \
$(SRC_ROOT)/others/sysmon \
$(SRC_ROOT)/others/gridnav \
$(SRC_ROOT)/widgets \
$(SRC_ROOT)/widgets/objx_templ \
$(SRC_ROOT)/widgets/tabview \
$(SRC_ROOT)/widgets/scale \
$(SRC_ROOT)/widgets/checkbox \
$(SRC_ROOT)/widgets/slider \
$(SRC_ROOT)/widgets/calendar \
$(SRC_ROOT)/widgets/bar \
$(SRC_ROOT)/widgets/win \
$(SRC_ROOT)/widgets/dropdown \
$(SRC_ROOT)/widgets/switch \
$(SRC_ROOT)/widgets/span \
$(SRC_ROOT)/widgets/canvas \
$(SRC_ROOT)/widgets/lottie \
$(SRC_ROOT)/widgets/textarea \
$(SRC_ROOT)/widgets/arc \
$(SRC_ROOT)/widgets/msgbox \
$(SRC_ROOT)/widgets/property \
$(SRC_ROOT)/widgets/chart \
$(SRC_ROOT)/widgets/table \
$(SRC_ROOT)/widgets/list \
$(SRC_ROOT)/widgets/button \
$(SRC_ROOT)/widgets/image \
$(SRC_ROOT)/widgets/line \
$(SRC_ROOT)/widgets/animimage \
$(SRC_ROOT)/widgets/roller \
$(SRC_ROOT)/widgets/spinner \
$(SRC_ROOT)/widgets/imagebutton \
$(SRC_ROOT)/widgets/led \
$(SRC_ROOT)/widgets/spinbox \
$(SRC_ROOT)/widgets/keyboard \
$(SRC_ROOT)/widgets/buttonmatrix \
$(SRC_ROOT)/widgets/menu \
$(SRC_ROOT)/widgets/label \
$(SRC_ROOT)/widgets/tileview \
$(SRC_ROOT)/layouts \
$(SRC_ROOT)/layouts/grid \
$(SRC_ROOT)/layouts/flex \
$(SRC_ROOT)/osal
include $(MKFILES_ROOT)/qtargets.mk

1075
env_support/qnx/lv_conf.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
LIST=VARIANT
include recurse.mk

View File

@ -0,0 +1 @@
include ../../common.mk

View File

@ -0,0 +1 @@
include ../../common.mk

View File

@ -1016,6 +1016,12 @@
#define LV_USE_OPENGLES_DEBUG 1 /* Enable or disable debug for opengles */
#endif
/* QNX Screen display and input drivers */
#define LV_USE_QNX 0
#if LV_USE_QNX
#define LV_QNX_BUF_COUNT 1 /*1 or 2*/
#endif
/*==================
* EXAMPLES
*==================*/

View File

@ -40,6 +40,8 @@ extern "C" {
#include "glfw/lv_glfw_window.h"
#include "glfw/lv_glfw_mouse.h"
#include "qnx/lv_qnx.h"
/*********************
* DEFINES
*********************/

542
src/drivers/qnx/lv_qnx.c Normal file
View File

@ -0,0 +1,542 @@
/**
* @file lv_qnx.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_qnx.h"
#if LV_USE_QNX
#include <stdbool.h>
#include "../../core/lv_refr.h"
#include "../../stdlib/lv_string.h"
#include "../../core/lv_global.h"
#include "../../display/lv_display_private.h"
#include "../../lv_init.h"
#include <stdlib.h>
#include <time.h>
#include <screen/screen.h>
#include <sys/keycodes.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
screen_window_t window;
screen_buffer_t buffers[LV_QNX_BUF_COUNT];
int bufidx;
bool managed;
lv_indev_t * pointer;
lv_indev_t * keyboard;
} lv_qnx_window_t;
typedef struct {
int pos[2];
int buttons;
} lv_qnx_pointer_t;
typedef struct {
int key;
int flags;
} lv_qnx_keyboard_t;
/**********************
* STATIC PROTOTYPES
**********************/
static uint32_t get_ticks(void);
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p);
static bool window_create(lv_display_t * disp);
static bool init_display_from_window(lv_display_t * disp);
static void get_pointer(lv_indev_t * indev, lv_indev_data_t * data);
static void get_key(lv_indev_t * indev, lv_indev_data_t * data);
static bool handle_pointer_event(lv_display_t * disp, screen_event_t event);
static bool handle_keyboard_event(lv_display_t * disp, screen_event_t event);
static void release_disp_cb(lv_event_t * e);
static void refresh_cb(lv_timer_t * timer);
/***********************
* GLOBAL PROTOTYPES
***********************/
static screen_context_t context;
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_qnx_window_create(int32_t hor_res, int32_t ver_res)
{
static bool inited = false;
if(!inited) {
if(screen_create_context(&context,
SCREEN_APPLICATION_CONTEXT) != 0) {
LV_LOG_ERROR("screen_create_context: %s", strerror(errno));
return NULL;
}
lv_tick_set_cb(get_ticks);
inited = true;
}
lv_qnx_window_t * dsc = lv_malloc_zeroed(sizeof(lv_qnx_window_t));
LV_ASSERT_MALLOC(dsc);
if(dsc == NULL) return NULL;
lv_display_t * disp = lv_display_create(hor_res, ver_res);
if(disp == NULL) {
lv_free(dsc);
return NULL;
}
lv_display_add_event_cb(disp, release_disp_cb, LV_EVENT_DELETE, disp);
lv_display_set_driver_data(disp, dsc);
if(!window_create(disp)) {
lv_free(dsc);
return NULL;
}
lv_display_set_flush_cb(disp, flush_cb);
if(!init_display_from_window(disp)) {
screen_destroy_window(dsc->window);
lv_free(dsc);
return NULL;
}
/*Replace the default refresh timer handler, so that we can run it on
*demand instead of constantly.*/
lv_timer_t * refr_timer = lv_display_get_refr_timer(disp);
lv_timer_set_cb(refr_timer, refresh_cb);
return disp;
}
void lv_qnx_window_set_title(lv_display_t * disp, const char * title)
{
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(!dsc->managed) {
/*Can't set title if there is no window manager*/
return;
}
screen_event_t event;
screen_create_event(&event);
char title_buf[64];
lv_snprintf(title_buf, sizeof(title_buf), "Title=%s", title);
int type = SCREEN_EVENT_MANAGER;
screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type);
screen_set_event_property_cv(event, SCREEN_PROPERTY_USER_DATA,
sizeof(title_buf), title_buf);
screen_set_event_property_pv(event, SCREEN_PROPERTY_WINDOW,
(void **)&dsc->window);
screen_set_event_property_pv(event, SCREEN_PROPERTY_CONTEXT,
(void **)&context);
screen_inject_event(NULL, event);
}
bool lv_qnx_add_pointer_device(lv_display_t * disp)
{
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc->pointer != NULL) {
/*Only one pointer device per display*/
return false;
}
lv_qnx_pointer_t * ptr_dsc = lv_malloc_zeroed(sizeof(lv_qnx_pointer_t));
LV_ASSERT_MALLOC(ptr_dsc);
if(ptr_dsc == NULL) {
return false;
}
dsc->pointer = lv_indev_create();
if(dsc->pointer == NULL) {
lv_free(ptr_dsc);
return false;
}
lv_indev_set_type(dsc->pointer, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(dsc->pointer, get_pointer);
lv_indev_set_driver_data(dsc->pointer, ptr_dsc);
lv_indev_set_mode(dsc->pointer, LV_INDEV_MODE_EVENT);
return true;
}
bool lv_qnx_add_keyboard_device(lv_display_t * disp)
{
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc->keyboard != NULL) {
/*Only one keyboard device per display*/
return false;
}
lv_qnx_keyboard_t * kbd_dsc = lv_malloc_zeroed(sizeof(lv_qnx_keyboard_t));
LV_ASSERT_MALLOC(kbd_dsc);
if(dsc == NULL) {
return false;
}
dsc->keyboard = lv_indev_create();
if(dsc->keyboard == NULL) {
lv_free(kbd_dsc);
return false;
}
lv_indev_set_type(dsc->keyboard, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(dsc->keyboard, get_key);
lv_indev_set_driver_data(dsc->keyboard, kbd_dsc);
lv_indev_set_mode(dsc->keyboard, LV_INDEV_MODE_EVENT);
return true;
}
int lv_qnx_event_loop(lv_display_t * disp)
{
lv_refr_now(disp);
/*Run the event loop*/
screen_event_t event;
if(screen_create_event(&event) != 0) {
LV_LOG_ERROR("screen_create_event: %s", strerror(errno));
return EXIT_FAILURE;
}
uint64_t timeout_ns = 0;
for(;;) {
/*Wait for an event, timing out after 16ms if animations are running*/
if(screen_get_event(context, event, timeout_ns) != 0) {
LV_LOG_ERROR("screen_get_event: %s", strerror(errno));
return EXIT_FAILURE;
}
/*Get the event's type*/
int type;
if(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type)
!= 0) {
LV_LOG_ERROR("screen_get_event_property_iv(TYPE): %s", strerror(errno));
return EXIT_FAILURE;
}
if(type == SCREEN_EVENT_POINTER) {
if(!handle_pointer_event(disp, event)) {
return EXIT_FAILURE;
}
}
else if(type == SCREEN_EVENT_KEYBOARD) {
if(!handle_keyboard_event(disp, event)) {
return EXIT_FAILURE;
}
}
else if(type == SCREEN_EVENT_MANAGER) {
/*Only sub-type supported is closing the window*/
break;
}
/*Calculate the next timeout*/
uint32_t timeout_ms = lv_timer_handler();
if(timeout_ms == LV_NO_TIMER_READY) {
timeout_ns = -1ULL;
}
else {
timeout_ns = (uint64_t)timeout_ms * 1000000UL;
}
}
return EXIT_SUCCESS;
}
/**********************
* STATIC FUNCTIONS
**********************/
static uint32_t get_ticks(void)
{
uint64_t const ns = clock_gettime_mon_ns();
return (uint32_t)(ns / 1000000UL);
}
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(screen_post_window(dsc->window, dsc->buffers[dsc->bufidx], 0, NULL, 0)
!= 0) {
LV_LOG_ERROR("screen_post_window: %s", strerror(errno));
}
#if (LV_QNX_BUF_COUNT > 1)
dsc->bufidx = 1 - dsc->bufidx;
#endif
lv_display_flush_ready(disp);
}
static bool window_create(lv_display_t * disp)
{
/*Create a window*/
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(screen_create_window(&dsc->window, context) != 0) {
LV_LOG_ERROR("screen_create_window: %s", strerror(errno));
return false;
}
/*Set window properties*/
int rect[] = { 0, 0, disp->hor_res, disp->ver_res };
if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_POSITION,
&rect[0]) != 0) {
LV_LOG_ERROR("screen_window_set_property_iv(POSITION): %s", strerror(errno));
return false;
}
if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_SIZE,
&rect[2]) != 0) {
LV_LOG_ERROR("screen_window_set_property_iv(SIZE): %s", strerror(errno));
return false;
}
if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_SOURCE_SIZE,
&rect[2]) != 0) {
LV_LOG_ERROR("screen_window_set_property_iv(SOURCE_SIZE): %s", strerror(errno));
return NULL;
}
int usage = SCREEN_USAGE_WRITE;
if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_USAGE,
&usage) != 0) {
LV_LOG_ERROR("screen_window_set_property_iv(USAGE): %s", strerror(errno));
return NULL;
}
int format = SCREEN_FORMAT_RGBA8888;
if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_FORMAT,
&format) != 0) {
LV_LOG_ERROR("screen_window_set_property_iv(USAGE): %s", strerror(errno));
return NULL;
}
/*Initialize window buffers*/
if(screen_create_window_buffers(dsc->window, LV_QNX_BUF_COUNT) != 0) {
LV_LOG_ERROR("screen_create_window_buffers: %s", strerror(errno));
return false;
}
if(screen_get_window_property_pv(dsc->window, SCREEN_PROPERTY_BUFFERS,
(void **)&dsc->buffers) != 0) {
LV_LOG_ERROR("screen_get_window_property_pv(BUFFERS): %s", strerror(errno));
return false;
}
/*Connect to the window manager. Can legitimately fail if one is not running*/
if(screen_manage_window(dsc->window, "Frame=Y") == 0) {
dsc->managed = true;
}
else {
dsc->managed = false;
}
int visible = 1;
if(screen_set_window_property_iv(dsc->window, SCREEN_PROPERTY_VISIBLE,
&visible) != 0) {
LV_LOG_ERROR("screen_set_window_property_iv(VISIBLE): %s", strerror(errno));
return false;
}
return true;
}
static bool init_display_from_window(lv_display_t * disp)
{
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
int bufsize;
if(screen_get_buffer_property_iv(dsc->buffers[0], SCREEN_PROPERTY_SIZE,
&bufsize) == -1) {
LV_LOG_ERROR("screen_get_buffer_property_iv(SIZE): %s", strerror(errno));
return false;
}
void * ptr1 = NULL;
if(screen_get_buffer_property_pv(dsc->buffers[0], SCREEN_PROPERTY_POINTER,
&ptr1) == -1) {
LV_LOG_ERROR("screen_get_buffer_property_pv(POINTER): %s", strerror(errno));
return false;
}
void * ptr2 = NULL;
#if (LV_QNX_BUF_COUNT > 1)
if(screen_get_buffer_property_pv(dsc->buffers[1], SCREEN_PROPERTY_POINTER,
&ptr2) == -1) {
LV_LOG_ERROR("screen_get_buffer_property_pv(POINTER): %s", strerror(errno));
return false;
}
#endif
lv_display_set_buffers(disp, ptr1, ptr2, bufsize, LV_DISPLAY_RENDER_MODE_FULL);
return true;
}
static void release_disp_cb(lv_event_t * e)
{
lv_display_t * disp = (lv_display_t *) lv_event_get_user_data(e);
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc->window != NULL) {
screen_destroy_window(dsc->window);
}
if(dsc->pointer != NULL) {
lv_free(dsc->pointer);
}
if(dsc->keyboard != NULL) {
lv_free(dsc->keyboard);
}
lv_free(dsc);
lv_display_set_driver_data(disp, NULL);
}
static void get_pointer(lv_indev_t * indev, lv_indev_data_t * data)
{
lv_qnx_pointer_t * dsc = lv_indev_get_driver_data(indev);
data->point.x = dsc->pos[0];
data->point.y = dsc->pos[1];
if((dsc->buttons & SCREEN_LEFT_MOUSE_BUTTON) != 0) {
data->state = LV_INDEV_STATE_PRESSED;
}
else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
static bool handle_pointer_event(lv_display_t * disp, screen_event_t event)
{
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc->pointer == NULL) return true;
lv_qnx_pointer_t * ptr_dsc = lv_indev_get_driver_data(dsc->pointer);
if(screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION,
ptr_dsc->pos)
!= 0) {
LV_LOG_ERROR("screen_get_event_property_iv(SOURCE_POSITION): %s", strerror(errno));
return false;
}
if(screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS,
&ptr_dsc->buttons)
!= 0) {
LV_LOG_ERROR("screen_get_event_property_iv(BUTTONS): %s", strerror(errno));
return false;
}
lv_indev_read(dsc->pointer);
return true;
}
static void get_key(lv_indev_t * indev, lv_indev_data_t * data)
{
lv_qnx_keyboard_t * dsc = lv_indev_get_driver_data(indev);
if((dsc->flags & KEY_DOWN) != 0) {
data->state = LV_INDEV_STATE_PRESSED;
data->key = dsc->key;
}
else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
static bool handle_keyboard_event(lv_display_t * disp, screen_event_t event)
{
lv_qnx_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc->keyboard == NULL) return true;
lv_qnx_keyboard_t * kbd_dsc = lv_indev_get_driver_data(dsc->keyboard);
/*Get event data*/
if(screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS,
&kbd_dsc->flags)
!= 0) {
LV_LOG_ERROR("screen_get_event_property_iv(FLAGS): %s", strerror(errno));
return false;
}
if(screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM,
&kbd_dsc->key)
!= 0) {
LV_LOG_ERROR("screen_get_event_property_iv(SYM): %s", strerror(errno));
return false;
}
/*Translate special keys*/
switch(kbd_dsc->key) {
case KEYCODE_UP:
kbd_dsc->key = LV_KEY_UP;
break;
case KEYCODE_DOWN:
kbd_dsc->key = LV_KEY_DOWN;
break;
case KEYCODE_LEFT:
kbd_dsc->key = LV_KEY_LEFT;
break;
case KEYCODE_RIGHT:
kbd_dsc->key = LV_KEY_RIGHT;
break;
case KEYCODE_RETURN:
kbd_dsc->key = LV_KEY_ENTER;
break;
case KEYCODE_BACKSPACE:
kbd_dsc->key = LV_KEY_BACKSPACE;
break;
case KEYCODE_HOME:
kbd_dsc->key = LV_KEY_HOME;
break;
case KEYCODE_END:
kbd_dsc->key = LV_KEY_END;
break;
case KEYCODE_DELETE:
kbd_dsc->key = LV_KEY_DEL;
break;
default:
/*Ignore other non-ASCII keys, including modifiers*/
if(kbd_dsc->key > 0xff) return true;
}
lv_indev_read(dsc->keyboard);
return true;
}
static void refresh_cb(lv_timer_t * timer)
{
/*Refresh the window on timeout, but disable the timer. Any callback can
*re-enable it.*/
lv_display_t * disp = timer->user_data;
lv_refr_now(disp);
lv_timer_pause(timer);
}
#endif /*LV_USE_QNX*/

86
src/drivers/qnx/lv_qnx.h Normal file
View File

@ -0,0 +1,86 @@
/**
* @file lv_qnx_window.h
* @brief LVGL driver for the QNX Screen compositing window manager
*/
#ifndef LV_QNX_DISP_H
#define LV_QNX_DISP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#include "../../indev/lv_indev.h"
#if LV_USE_QNX
#include <stdbool.h>
#include <screen/screen.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a window to use as a display for LVGL.
* @param hor_res The horizontal resolution (size) of the window
* @param ver_res The vertical resolution (size) of the window
* @return A pointer to a new display object if successful, NULL otherwise
*/
lv_display_t * lv_qnx_window_create(int32_t hor_res, int32_t ver_res);
/**
* Set the title of the window identified by the given display.
* @param disp The display object for the window
* @param title The new title to set
*/
void lv_qnx_window_set_title(lv_display_t * disp, const char * title);
/**
* Create a pointer input device for the display.
* Only one pointer object is currently supported.
* @param disp The display object associated with the device
* @return true if successful, false otherwise
*/
bool lv_qnx_add_pointer_device(lv_display_t * disp);
/**
* Create a keyboard input device for the display.
* Only one keyboard object is currently supported.
* @param disp The display object associated with the device
* @return true if successful, false otherwise
*/
bool lv_qnx_add_keyboard_device(lv_display_t * disp);
/**
* Runs the event loop for the display.
* The function only returns in response to a close event.
* @param disp The display for the event loop
* @return Exit code
*/
int lv_qnx_event_loop(lv_display_t * disp);
/**********************
* MACROS
**********************/
#endif /* LV_DRV_QNX */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_QNX_DISP_H */

View File

@ -3367,6 +3367,28 @@
#endif
#endif
/* QNX Screen display and input drivers */
#ifndef LV_USE_QNX
#ifdef CONFIG_LV_USE_QNX
#define LV_USE_QNX CONFIG_LV_USE_QNX
#else
#define LV_USE_QNX 0
#endif
#endif
#if LV_USE_QNX
#ifndef LV_QNX_BUF_COUNT
#ifdef _LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_QNX_BUF_COUNT
#define LV_QNX_BUF_COUNT CONFIG_LV_QNX_BUF_COUNT
#else
#define LV_QNX_BUF_COUNT 0
#endif
#else
#define LV_QNX_BUF_COUNT 1 /*1 or 2*/
#endif
#endif
#endif
/*==================
* EXAMPLES
*==================*/