feat(wayland): add dmabuf support with g2d (#8122)

Signed-off-by: Ana Grad <ana.grad@nxp.com>
Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com>
Signed-off-by: Prabhu Sundararaj <prabhu.sundararaj@nxp.com>
Signed-off-by: Cosmin Radu <cosmin.radu_1@nxp.com>
Co-authored-by: Nicușor Cîțu <nicusor.citu@nxp.com>
Co-authored-by: Prabhu Sundararaj <prabhu.sundararaj@nxp.com>
Co-authored-by: Cosmin Radu <cosmin.radu_1@nxp.com>
This commit is contained in:
anaGrad
2025-06-02 17:29:38 +03:00
committed by GitHub
parent 1621751fb0
commit 23bad41299
36 changed files with 4609 additions and 2940 deletions
+25
View File
@@ -1853,6 +1853,31 @@ menu "LVGL configuration"
bool "Support the legacy wl_shell instead of the default XDG Shell protocol"
depends on LV_USE_WAYLAND
default n
config LV_WAYLAND_BUF_COUNT
int "Use 1 for single buffer with partial render mode or 2 for double buffer with full render mode"
depends on LV_USE_WAYLAND
default 1
choice
prompt "Wayland rendering mode"
depends on LV_USE_WAYLAND
default LV_WAYLAND_RENDER_MODE_PARTIAL
config LV_WAYLAND_RENDER_MODE_PARTIAL
bool "Use the buffer(s) to render the screen is smaller parts"
depends on !LV_WAYLAND_USE_DMABUF
config LV_WAYLAND_RENDER_MODE_DIRECT
bool "Only the changed areas will be updated with 2 screen sized buffers"
depends on LV_WAYLAND_USE_DMABUF
config LV_WAYLAND_RENDER_MODE_FULL
bool "Always redraw the whole screen even if only one pixel has been changed with 2 screen sized buffers"
depends on LV_WAYLAND_USE_DMABUF
endchoice
config LV_WAYLAND_USE_DMABUF
bool "Use DMA buffers for frame buffers"
depends on LV_USE_WAYLAND && LV_USE_DRAW_G2D
config LV_USE_LINUX_FBDEV
bool "Use Linux framebuffer device"
+6 -2
View File
@@ -1188,8 +1188,12 @@
/** Use Wayland to open a window and handle input on Linux or BSD desktops */
#define LV_USE_WAYLAND 0
#if LV_USE_WAYLAND
#define LV_WAYLAND_WINDOW_DECORATIONS 0 /**< Draw client side window decorations only necessary on Mutter/GNOME */
#define LV_WAYLAND_WL_SHELL 0 /**< Use the legacy wl_shell protocol instead of the default XDG shell */
#define LV_WAYLAND_BUF_COUNT 1 /**< Use 1 for single buffer with partial render mode or 2 for double buffer with full render mode*/
#define LV_WAYLAND_USE_DMABUF 0 /**< Use DMA buffers for frame buffers. Requires LV_DRAW_USE_G2D */
#define LV_WAYLAND_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL /**< DMABUF supports LV_DISPLAY_RENDER_MODE_FULL and LV_DISPLAY_RENDER_MODE_DIRECT*/
/**< When LV_WAYLAND_USE_DMABUF is disabled, only LV_DISPLAY_RENDER_MODE_PARTIAL is supported*/
#define LV_WAYLAND_WINDOW_DECORATIONS 0 /**< Draw client side window decorations only necessary on Mutter/GNOME. Not supported using DMABUF*/
#define LV_WAYLAND_WL_SHELL 0 /**< Use the legacy wl_shell protocol instead of the default XDG shell*/
#endif
/** Driver for /dev/fb */
+6
View File
@@ -209,6 +209,12 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#define LV_LOG_TRACE_ANIM 0
#endif /*LV_USE_LOG*/
#if LV_USE_WAYLAND == 0
#define LV_WAYLAND_USE_DMABUF 0
#define LV_WAYLAND_WINDOW_DECORATIONS 0
#define LV_WAYLAND_WL_SHELL 0
#endif /* LV_USE_WAYLAND */
#if LV_USE_SYSMON == 0
#define LV_USE_PERF_MONITOR 0
#define LV_USE_MEM_MONITOR 0
-1
View File
@@ -83,7 +83,6 @@ static void _buf_free(void * buf)
static void _invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
{
LV_UNUSED(area);
struct g2d_buf * buf = g2d_search_buf_map(draw_buf->data);
G2D_ASSERT_MSG(buf, "Failed to find buffer in map.");
+59 -40
View File
@@ -51,7 +51,7 @@ static int32_t _g2d_delete(lv_draw_unit_t * draw_unit);
static void _g2d_render_thread_cb(void * ptr);
#endif
static void _g2d_execute_drawing(lv_draw_g2d_unit_t * u);
static void _g2d_execute_drawing(lv_draw_task_t * t);
/**********************
* STATIC VARIABLES
@@ -73,12 +73,17 @@ void lv_draw_g2d_init(void)
draw_g2d_unit->base_unit.evaluate_cb = _g2d_evaluate;
draw_g2d_unit->base_unit.dispatch_cb = _g2d_dispatch;
draw_g2d_unit->base_unit.delete_cb = _g2d_delete;
draw_g2d_unit->base_unit.name = "G2D";
g2d_create_buf_map();
if(g2d_open(&draw_g2d_unit->g2d_handle)) {
LV_LOG_ERROR("g2d_open fail.\n");
}
#if LV_USE_G2D_DRAW_THREAD
lv_thread_init(&draw_g2d_unit->thread, "g2ddraw", LV_DRAW_THREAD_PRIO, _g2d_render_thread_cb, 2 * 1024, draw_g2d_unit);
lv_draw_sw_thread_dsc_t * thread_dsc = &draw_g2d_unit->thread_dsc;
thread_dsc->idx = 0;
thread_dsc->draw_unit = (void *) draw_g2d_unit;
lv_thread_init(&thread_dsc->thread, "g2ddraw", LV_DRAW_THREAD_PRIO, _g2d_render_thread_cb, LV_DRAW_THREAD_STACK_SIZE,
thread_dsc);
#endif
}
@@ -97,6 +102,7 @@ static inline bool _g2d_dest_cf_supported(lv_color_format_t cf)
switch(cf) {
case LV_COLOR_FORMAT_ARGB8888:
case LV_COLOR_FORMAT_XRGB8888:
is_cf_supported = true;
break;
default:
@@ -106,14 +112,24 @@ static inline bool _g2d_dest_cf_supported(lv_color_format_t cf)
return is_cf_supported;
}
static inline bool _g2d_src_cf_supported(lv_color_format_t cf)
static inline bool _g2d_src_cf_supported(lv_draw_unit_t * drawunit, lv_color_format_t cf)
{
bool is_cf_supported = false;
switch(cf) {
case LV_COLOR_FORMAT_ARGB8888:
case LV_COLOR_FORMAT_XRGB8888:
is_cf_supported = true;
break;
case LV_COLOR_FORMAT_RGB565: {
int32_t hw_pxp = 0;
lv_draw_g2d_unit_t * u = (lv_draw_g2d_unit_t *)drawunit;
g2d_query_hardware(u->g2d_handle, G2D_HARDWARE_PXP, &hw_pxp);
if(!hw_pxp) {
is_cf_supported = true;
}
}
break;
default:
break;
}
@@ -123,7 +139,10 @@ static inline bool _g2d_src_cf_supported(lv_color_format_t cf)
static bool _g2d_draw_img_supported(const lv_draw_image_dsc_t * draw_dsc)
{
const lv_image_dsc_t * img_dsc = draw_dsc->src;
bool is_tiled = draw_dsc->tile;
/* Tiled image (repeat image) is currently not supported. */
if(is_tiled)
return false;
bool has_recolor = (draw_dsc->recolor_opa > LV_OPA_MIN);
bool has_rotation = (draw_dsc->rotation != 0);
@@ -165,7 +184,7 @@ static int32_t _g2d_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
case LV_DRAW_TASK_TYPE_IMAGE: {
const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
if(!_g2d_src_cf_supported(draw_dsc->header.cf))
if(!_g2d_src_cf_supported(u, draw_dsc->header.cf))
return 0;
if(!_g2d_draw_img_supported(draw_dsc))
@@ -189,9 +208,17 @@ static int32_t _g2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
{
lv_draw_g2d_unit_t * draw_g2d_unit = (lv_draw_g2d_unit_t *) draw_unit;
#if LV_USE_OS
lv_draw_sw_thread_dsc_t * thread_dsc = &draw_g2d_unit->thread_dsc;
/* Return immediately if it's busy with draw task. */
if(thread_dsc->task_act)
return 0;
#else
/* Return immediately if it's busy with draw task. */
if(draw_g2d_unit->task_act)
return 0;
#endif
/* Try to get an ready to draw. */
lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_G2D);
@@ -203,14 +230,18 @@ static int32_t _g2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
return LV_DRAW_UNIT_IDLE;
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
draw_g2d_unit->task_act = t;
t->draw_unit = draw_unit;
#if LV_USE_G2D_DRAW_THREAD
thread_dsc->task_act = t;
/* Let the render thread work. */
if(draw_g2d_unit->inited)
lv_thread_sync_signal(&draw_g2d_unit->sync);
if(thread_dsc->inited)
lv_thread_sync_signal(&thread_dsc->sync);
#else
_g2d_execute_drawing(draw_g2d_unit);
draw_g2d_unit->task_act = t;
_g2d_execute_drawing(t);
draw_g2d_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
draw_g2d_unit->task_act = NULL;
@@ -228,36 +259,27 @@ static int32_t _g2d_delete(lv_draw_unit_t * draw_unit)
lv_result_t res = LV_RESULT_OK;
#if LV_USE_G2D_DRAW_THREAD
lv_draw_sw_thread_dsc_t * thread_dsc = &draw_g2d_unit->thread_dsc;
LV_LOG_INFO("Cancel G2D draw thread.");
draw_g2d_unit->exit_status = true;
thread_dsc->exit_status = true;
if(draw_g2d_unit->inited)
lv_thread_sync_signal(&draw_g2d_unit->sync);
if(thread_dsc->inited)
lv_thread_sync_signal(&thread_dsc->sync);
res = lv_thread_delete(&draw_g2d_unit->thread);
res = lv_thread_delete(&thread_dsc->thread);
#endif
g2d_close(draw_g2d_unit->g2d_handle);
return res;
}
static void _g2d_execute_drawing(lv_draw_g2d_unit_t * u)
static void _g2d_execute_drawing(lv_draw_task_t * t)
{
lv_draw_task_t * t = u->task_act;
lv_layer_t * layer = t->target_layer;
lv_draw_buf_t * draw_buf = layer->draw_buf;
t->draw_unit = (lv_draw_unit_t *)u;
lv_area_t draw_area;
if(!lv_area_intersect(&draw_area, &t->area, &t->clip_area))
return; /*Fully clipped, nothing to do*/
/* Make area relative to the buffer */
lv_area_move(&draw_area, -layer->buf_area.x1, -layer->buf_area.y1);
/* Invalidate only the drawing area */
lv_draw_buf_invalidate_cache(draw_buf, &draw_area);
lv_draw_buf_invalidate_cache(draw_buf, NULL);
switch(t->type) {
case LV_DRAW_TASK_TYPE_FILL:
@@ -269,47 +291,44 @@ static void _g2d_execute_drawing(lv_draw_g2d_unit_t * u)
default:
break;
}
/* Invalidate only the drawing area */
lv_draw_buf_invalidate_cache(draw_buf, &draw_area);
}
#if LV_USE_G2D_DRAW_THREAD
static void _g2d_render_thread_cb(void * ptr)
{
lv_draw_g2d_unit_t * u = ptr;
lv_draw_sw_thread_dsc_t * thread_dsc = ptr;
lv_thread_sync_init(&u->sync);
u->inited = true;
lv_thread_sync_init(&thread_dsc->sync);
thread_dsc->inited = true;
while(1) {
/* Wait for sync if there is no task set. */
while(u->task_act == NULL) {
if(u->exit_status)
while(thread_dsc->task_act == NULL) {
if(thread_dsc->exit_status)
break;
lv_thread_sync_wait(&u->sync);
lv_thread_sync_wait(&thread_dsc->sync);
}
if(u->exit_status) {
if(thread_dsc->exit_status) {
LV_LOG_INFO("Ready to exit G2D draw thread.");
break;
}
_g2d_execute_drawing(u);
_g2d_execute_drawing(thread_dsc->task_act);
/* Signal the ready state to dispatcher. */
u->task_act->state = LV_DRAW_TASK_STATE_READY;
thread_dsc->task_act->state = LV_DRAW_TASK_STATE_READY;
/* Cleanup. */
u->task_act = NULL;
thread_dsc->task_act = NULL;
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
lv_draw_dispatch_request();
}
u->inited = false;
lv_thread_sync_delete(&u->sync);
thread_dsc->inited = false;
lv_thread_sync_delete(&thread_dsc->sync);
LV_LOG_INFO("Exit G2D draw thread.");
}
#endif
+6 -1
View File
@@ -34,7 +34,12 @@ extern "C" {
**********************/
typedef struct lv_draw_g2d_unit {
lv_draw_sw_unit_t;
lv_draw_unit_t base_unit;
#if LV_USE_OS
lv_draw_sw_thread_dsc_t thread_dsc;
#else
lv_draw_task_t * task_act;
#endif
void * g2d_handle;
} lv_draw_g2d_unit_t;
+13 -24
View File
@@ -35,12 +35,11 @@
**********************/
/* Blit simple w/ opa and alpha channel */
static void _g2d_fill(void * g2d_handle, struct g2d_buf * dst_buf, struct g2d_surface * dst_surf);
static void _g2d_fill_with_opa(void * g2d_handle, struct g2d_buf * dst_buf, struct g2d_surface * dst_surf,
struct g2d_buf * src_buf, struct g2d_surface * src_surf);
static void _g2d_fill(void * g2d_handle, struct g2d_surface * dst_surf);
static void _g2d_fill_with_opa(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf);
static void _g2d_set_src_surf(struct g2d_surface * src_surf, struct g2d_buf * buf, const lv_area_t * area,
int32_t stride, lv_color_t color, lv_opa_t opa);
lv_color_t color, lv_opa_t opa);
static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * buf, const lv_area_t * area,
int32_t stride, lv_color_t color);
@@ -88,26 +87,21 @@ void lv_draw_g2d_fill(lv_draw_task_t * t)
struct g2d_buf * dst_buf = g2d_search_buf_map(draw_buf->data);
bool has_opa = (dsc->opa < (lv_opa_t)LV_OPA_MAX);
struct g2d_surface * dst_surf = lv_malloc(sizeof(struct g2d_surface));
G2D_ASSERT_MSG(dst_surf, "Failed to alloc destination surface.");
_g2d_set_dst_surf(dst_surf, dst_buf, &blend_area, stride, dsc->color);
struct g2d_surface dst_surf;
_g2d_set_dst_surf(&dst_surf, dst_buf, &blend_area, stride, dsc->color);
if(has_opa) {
struct g2d_buf * tmp_buf = g2d_alloc(lv_area_get_width(&blend_area) * lv_area_get_height(&blend_area) * sizeof(
lv_color32_t), 1);
G2D_ASSERT_MSG(tmp_buf, "Failed to alloc temporary buffer.");
struct g2d_surface * src_surf = lv_malloc(sizeof(struct g2d_surface));
G2D_ASSERT_MSG(src_surf, "Failed to alloc source surface.");
_g2d_set_src_surf(src_surf, tmp_buf, &blend_area, stride, dsc->color, dsc->opa);
_g2d_fill_with_opa(u->g2d_handle, dst_buf, dst_surf, tmp_buf, src_surf);
struct g2d_surface src_surf;
_g2d_set_src_surf(&src_surf, tmp_buf, &blend_area, dsc->color, dsc->opa);
_g2d_fill_with_opa(u->g2d_handle, &dst_surf, &src_surf);
g2d_free(tmp_buf);
lv_free(src_surf);
}
else {
_g2d_fill(u->g2d_handle, dst_buf, dst_surf);
_g2d_fill(u->g2d_handle, &dst_surf);
}
lv_free(dst_surf);
}
/**********************
@@ -115,7 +109,7 @@ void lv_draw_g2d_fill(lv_draw_task_t * t)
**********************/
static void _g2d_set_src_surf(struct g2d_surface * src_surf, struct g2d_buf * buf, const lv_area_t * area,
int32_t stride, lv_color_t color, lv_opa_t opa)
lv_color_t color, lv_opa_t opa)
{
int32_t width = lv_area_get_width(area);
int32_t height = lv_area_get_height(area);
@@ -126,7 +120,7 @@ static void _g2d_set_src_surf(struct g2d_surface * src_surf, struct g2d_buf * bu
src_surf->top = 0;
src_surf->right = width;
src_surf->bottom = height;
src_surf->stride = stride;
src_surf->stride = width;
src_surf->width = width;
src_surf->height = height;
@@ -162,13 +156,9 @@ static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * bu
dst_surf->blendfunc = G2D_ONE_MINUS_SRC_ALPHA | G2D_PRE_MULTIPLIED_ALPHA;
}
static void _g2d_fill_with_opa(void * g2d_handle, struct g2d_buf * dst_buf, struct g2d_surface * dst_surf,
struct g2d_buf * src_buf, struct g2d_surface * src_surf)
static void _g2d_fill_with_opa(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf)
{
g2d_cache_op(src_buf, G2D_CACHE_FLUSH);
g2d_clear(g2d_handle, src_surf);
g2d_flush(g2d_handle);
g2d_enable(g2d_handle, G2D_BLEND);
g2d_enable(g2d_handle, G2D_GLOBAL_ALPHA);
@@ -178,10 +168,9 @@ static void _g2d_fill_with_opa(void * g2d_handle, struct g2d_buf * dst_buf, stru
g2d_disable(g2d_handle, G2D_BLEND);
}
static void _g2d_fill(void * g2d_handle, struct g2d_buf * dst_buf, struct g2d_surface * dst_surf)
static void _g2d_fill(void * g2d_handle, struct g2d_surface * dst_surf)
{
g2d_clear(g2d_handle, dst_surf);
g2d_flush(g2d_handle);
g2d_finish(g2d_handle);
}
+9 -17
View File
@@ -44,8 +44,7 @@ static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * bu
int32_t stride, lv_color_format_t cf, const lv_draw_image_dsc_t * dsc);
/* Blit simple w/ opa and alpha channel */
static void _g2d_blit(void * g2d_handle, struct g2d_buf * dst_buf, struct g2d_surface * dst_surf,
struct g2d_buf * src_buf, struct g2d_surface * src_surf);
static void _g2d_blit(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf);
/**********************
* STATIC VARIABLES
@@ -105,18 +104,13 @@ void lv_draw_g2d_img(lv_draw_task_t * t)
int32_t dest_stride = draw_buf->header.stride / (lv_color_format_get_bpp(draw_buf->header.cf) / 8);
lv_color_format_t dest_cf = draw_buf->header.cf;
struct g2d_surface * src_surf = lv_malloc(sizeof(struct g2d_surface));
G2D_ASSERT_MSG(src_surf, "Failed to alloc source surface.");
struct g2d_surface * dst_surf = lv_malloc(sizeof(struct g2d_surface));
G2D_ASSERT_MSG(dst_surf, "Failed to alloc destination surface.");
struct g2d_surface src_surf;
struct g2d_surface dst_surf;
_g2d_set_src_surf(src_surf, src_buf, &src_area, src_stride, src_cf, dsc->opa);
_g2d_set_dst_surf(dst_surf, dst_buf, &blend_area, dest_stride, dest_cf, dsc);
_g2d_set_src_surf(&src_surf, src_buf, &src_area, src_stride, src_cf, dsc->opa);
_g2d_set_dst_surf(&dst_surf, dst_buf, &blend_area, dest_stride, dest_cf, dsc);
_g2d_blit(u->g2d_handle, dst_buf, dst_surf, src_buf, src_surf);
lv_free(src_surf);
lv_free(dst_surf);
_g2d_blit(u->g2d_handle, &dst_surf, &src_surf);
}
/**********************
@@ -130,7 +124,8 @@ static struct g2d_buf * _g2d_handle_src_buf(const lv_image_dsc_t * img_dsc)
if(src_buf == NULL) {
src_buf = g2d_alloc(img_dsc->data_size, 1);
G2D_ASSERT_MSG(src_buf, "Failed to alloc source buffer.");
memcpy((int *)src_buf->buf_vaddr, img_dsc->data, img_dsc->data_size);
memcpy((uint8_t *)src_buf->buf_vaddr, img_dsc->data, img_dsc->data_size);
g2d_cache_op(src_buf, G2D_CACHE_FLUSH);
g2d_insert_buf_map((void *)img_dsc->data, src_buf);
}
@@ -207,11 +202,8 @@ static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * bu
dst_surf->blendfunc = G2D_ONE_MINUS_SRC_ALPHA | G2D_PRE_MULTIPLIED_ALPHA;
}
static void _g2d_blit(void * g2d_handle, struct g2d_buf * dst_buf, struct g2d_surface * dst_surf,
struct g2d_buf * src_buf, struct g2d_surface * src_surf)
static void _g2d_blit(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf)
{
g2d_cache_op(src_buf, G2D_CACHE_FLUSH);
g2d_enable(g2d_handle, G2D_BLEND);
g2d_enable(g2d_handle, G2D_GLOBAL_ALPHA);
g2d_blit(g2d_handle, src_surf, dst_surf);
+4 -10
View File
@@ -57,11 +57,6 @@ void g2d_create_buf_map(void)
table->count = 0;
table->items = (lv_map_item_t **) lv_malloc_zeroed(table->size * sizeof(lv_map_item_t *));
table->overflow_list = (lv_array_t **) lv_malloc_zeroed(table->size * sizeof(lv_array_t *));
for(int i = 0; i < table->size; i++) {
table->items[i] = NULL;
table->overflow_list[i] = NULL;
}
}
void g2d_free_buf_map(void)
@@ -86,7 +81,6 @@ void g2d_insert_buf_map(void * key, struct g2d_buf * value)
{
lv_map_item_t * item = _map_create_item(key, value);
int index = _map_hash_function(key);
lv_map_item_t * curr_item = table->items[index];
if(table->items[index] == NULL) {
/* Key not found. */
@@ -174,11 +168,11 @@ void g2d_print_table(void)
for(int i = 0; i < table->size; i++) {
if(table->items[i]) {
LV_LOG("Index:%d, Key:%p, Value:%p\n", i, table->items[i] -> key, table->items[i]->value);
LV_LOG("Index:%d, Key:%p, Value:%p\n", i, table->items[i] -> key, (void *)table->items[i]->value);
if(table->overflow_list[i]) {
for(int j = 0 ; j < lv_array_size(table->overflow_list[i]); j++) {
for(uint32_t j = 0 ; j < lv_array_size(table->overflow_list[i]); j++) {
lv_map_item_t * item = (lv_map_item_t *)lv_array_at(table->overflow_list[i], j);
LV_LOG("Index:%d, Key:%p, Value:%p\n", i, item -> key, item->value);
LV_LOG("Index:%d, Key:%p, Value:%p\n", i, item -> key, (void *)item->value);
}
}
@@ -217,7 +211,7 @@ static void _handle_collision(unsigned long index, lv_map_item_t * item)
}
else {
lv_array_t * list = (lv_array_t *)table->overflow_list[index];
for(int i = 0; i < lv_array_size(list); i++) {
for(uint32_t i = 0; i < lv_array_size(list); i++) {
lv_map_item_t * it = (lv_map_item_t *)lv_array_at(list, i);
if(it->key == item->key) {
/* Key exists, update value. */
+10 -3
View File
@@ -16,7 +16,7 @@
#include "lv_g2d_utils.h"
#if LV_USE_DRAW_G2D
#include"g2d.h"
#include "lv_g2d_buf_map.h"
#include "lv_draw_g2d.h"
/*********************
@@ -39,9 +39,9 @@
* GLOBAL FUNCTIONS
**********************/
enum g2d_format g2d_get_buf_format(lv_color_format_t cf)
g2d_format_t g2d_get_buf_format(lv_color_format_t cf)
{
enum g2d_format color_f = G2D_RGB565;
g2d_format_t color_f = G2D_RGB565;
switch(cf) {
case LV_COLOR_FORMAT_RGB565:
@@ -83,6 +83,13 @@ uint32_t g2d_rgba_to_u32(lv_color_t color)
return (uint32_t)((color.red) + (color.green << 8) + (color.blue << 16) + ((uint32_t)0xff << 24));
}
int32_t g2d_get_buf_fd(const lv_draw_buf_t * draw_buf)
{
struct g2d_buf * buf = g2d_search_buf_map(draw_buf->data);
G2D_ASSERT_MSG(buf, "Failed to find buffer in map.");
return g2d_buf_export_fd(buf);
}
/**********************
* STATIC FUNCTIONS
**********************/
+6 -1
View File
@@ -23,6 +23,8 @@ extern "C" {
#if LV_USE_DRAW_G2D
#include "../../sw/lv_draw_sw_private.h"
#include "g2d.h"
#include "g2dExt.h"
/*********************
* DEFINES
@@ -46,14 +48,17 @@ extern "C" {
* TYPEDEFS
**********************/
typedef enum g2d_format g2d_format_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
enum g2d_format g2d_get_buf_format(lv_color_format_t cf);
g2d_format_t g2d_get_buf_format(lv_color_format_t cf);
uint32_t g2d_rgba_to_u32(lv_color_t color);
int32_t g2d_get_buf_fd(const lv_draw_buf_t * draw_buf);
/**********************
* MACROS
**********************/
File diff suppressed because it is too large Load Diff
+18 -100
View File
@@ -1,22 +1,10 @@
/*******************************************************************
*
* @file lv_wayland.h - Public functions of the LVGL Wayland client
*
* Based on the original file from the repository.
*
* Porting to LVGL 9.1
* 2024 EDGEMTech Ltd.
*
* See LICENCE.txt for details
*
* Author(s): EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch)
*
******************************************************************/
/**
* @file lv_wayland.h
*/
#ifndef LV_WAYLAND_H
#define LV_WAYLAND_H
#ifndef _WIN32
#ifdef __cplusplus
extern "C" {
#endif
@@ -25,12 +13,16 @@ extern "C" {
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#include "../../indev/lv_indev.h"
#include "../../indev/lv_indev_gesture.h"
#include "../../lv_conf_internal.h"
#if LV_USE_WAYLAND
#include "lv_wl_keyboard.h"
#include "lv_wl_pointer.h"
#include "lv_wl_touch.h"
#include "lv_wl_window.h"
#include "lv_wl_pointer_axis.h"
/*********************
* DEFINES
*********************/
@@ -39,95 +31,22 @@ extern "C" {
* TYPEDEFS
**********************/
typedef bool (*lv_wayland_display_close_f_t)(lv_display_t * disp);
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Retrieves the file descriptor of the wayland socket
*/
int lv_wayland_get_fd(void);
/**
* Creates a window
* @param hor_res The width of the window in pixels
* @param ver_res The height of the window in pixels
* @param title The title of the window
* @param close_cb The callback that will be execute when the user closes the window
* @return The LVGL display associated to the window
*/
lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char * title,
lv_wayland_display_close_f_t close_cb);
/**
* Closes the window programmatically
* @param disp Reference to the LVGL display associated to the window
*/
void lv_wayland_window_close(lv_display_t * disp);
/**
* Check if the window is open
* @param disp Reference to the LVGL display associated to the window
* @return true: The window is open
*/
bool lv_wayland_window_is_open(lv_display_t * disp);
/**
* Sets the fullscreen state of the window
* @param disp Reference to the LVGL display associated to the window
* @param fullscreen If true the window enters fullscreen
*/
void lv_wayland_window_set_fullscreen(lv_display_t * disp, bool fullscreen);
/**
* Sets the maximized state of the window
* @param disp Reference to the LVGL display associated to the window
* @param fullscreen If true the window is maximized
*/
void lv_wayland_window_set_maximized(lv_display_t * disp, bool maximize);
/**
* Obtains the input device of the mouse pointer
* @note It is used to create an input group on application start
* @param disp Reference to the LVGL display associated to the window
* @return The input device
*/
lv_indev_t * lv_wayland_get_pointer(lv_display_t * disp);
/**
* Obtains the input device of the encoder
* @note It is used to create an input group on application start
* @param disp Reference to the LVGL display associated to the window
* @return The input device
*/
lv_indev_t * lv_wayland_get_pointeraxis(lv_display_t * disp);
/**
* Obtains the input device of the keyboard
* @note It is used to create an input group on application start
* @param disp Reference to the LVGL display associated to the window
* @return The input device
*/
lv_indev_t * lv_wayland_get_keyboard(lv_display_t * disp);
/**
* Obtains the input device of the touch screen
* @note It is used to create an input group on application start
* @param disp Reference to the LVGL display associated to the window
* @return The input device
*/
lv_indev_t * lv_wayland_get_touchscreen(lv_display_t * disp);
/**
* Wrapper around lv_timer_handler
* @note Must be called in the application run loop instead of the
* regular lv_timer_handler provided by LVGL
* @return true: if the cycle was completed, false if the application
* went to sleep because the last frame wasn't completed
* @return time till it needs to be run next (in ms)
*/
bool lv_wayland_timer_handler(void);
uint32_t lv_wayland_timer_handler(void);
/**
* Retrieves the file descriptor of the wayland socket
*/
int lv_wayland_get_fd(void);
/**********************
* MACROS
@@ -139,5 +58,4 @@ bool lv_wayland_timer_handler(void);
} /* extern "C" */
#endif
#endif /* _WIN32 */
#endif /* WAYLAND_H */
+374
View File
@@ -0,0 +1,374 @@
/**
* @file lv_wayland_private.h
*
*/
#ifndef LV_WAYLAND_PRIVATE_H
#define LV_WAYLAND_PRIVATE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_USE_WAYLAND
#include "lv_wayland_smm.h"
#include <sys/poll.h>
#include <wayland-client-protocol.h>
#if !LV_WAYLAND_WL_SHELL
#include "wayland_xdg_shell.h"
#define LV_WAYLAND_XDG_SHELL 1
#else
#define LV_WAYLAND_XDG_SHELL 0
#endif
/*********************
* DEFINES
*********************/
#define LV_WAYLAND_DEFAULT_CURSOR_NAME "left_ptr"
#define LVGL_DRAW_BUFFER_DIV (8)
#define DMG_CACHE_CAPACITY (32)
#define TAG_LOCAL (0)
#define TAG_BUFFER_DAMAGE (1)
#if LV_WAYLAND_WINDOW_DECORATIONS
#define TITLE_BAR_HEIGHT 24
#define BORDER_SIZE 2
#else
#define TITLE_BAR_HEIGHT 0
#define BORDER_SIZE 0
#endif
#define BUTTON_MARGIN LV_MAX((TITLE_BAR_HEIGHT / 6), BORDER_SIZE)
#define BUTTON_PADDING LV_MAX((TITLE_BAR_HEIGHT / 8), BORDER_SIZE)
#define BUTTON_SIZE (TITLE_BAR_HEIGHT - (2 * BUTTON_MARGIN))
#ifndef LV_WAYLAND_CYCLE_PERIOD
#define LV_WAYLAND_CYCLE_PERIOD LV_MIN(LV_DEF_REFR_PERIOD, 1)
#endif
/**********************
* TYPEDEFS
**********************/
enum object_type {
OBJECT_TITLEBAR = 0,
OBJECT_BUTTON_CLOSE,
#if LV_WAYLAND_XDG_SHELL
OBJECT_BUTTON_MAXIMIZE,
OBJECT_BUTTON_MINIMIZE,
#endif
OBJECT_BORDER_TOP,
OBJECT_BORDER_BOTTOM,
OBJECT_BORDER_LEFT,
OBJECT_BORDER_RIGHT,
OBJECT_WINDOW,
};
#define FIRST_DECORATION (OBJECT_TITLEBAR)
#define LAST_DECORATION (OBJECT_BORDER_RIGHT)
#define NUM_DECORATIONS (LAST_DECORATION - FIRST_DECORATION + 1)
struct window;
struct input {
struct {
uint32_t x;
uint32_t y;
lv_indev_state_t left_button;
lv_indev_state_t right_button;
lv_indev_state_t wheel_button;
int16_t wheel_diff;
} pointer;
struct {
lv_key_t key;
lv_indev_state_t state;
} keyboard;
#if LV_USE_GESTURE_RECOGNITION
lv_indev_touch_data_t touches[10];
uint8_t touch_event_cnt;
uint8_t primary_id;
#endif
};
struct seat {
struct wl_touch * wl_touch;
struct wl_pointer * wl_pointer;
struct wl_keyboard * wl_keyboard;
struct {
struct xkb_keymap * keymap;
struct xkb_state * state;
} xkb;
};
struct graphic_object {
struct window * window;
struct wl_surface * surface;
struct wl_subsurface * subsurface;
smm_buffer_t * pending_buffer;
smm_group_t * buffer_group;
struct input input;
enum object_type type;
int width;
int height;
};
typedef struct {
struct buffer * buffers;
struct zwp_linux_dmabuf_v1 * handler;
uint32_t format;
} dmabuf_ctx_t;
typedef struct {
lv_draw_buf_t * lv_draw_buf;
struct wl_shm * handler;
uint32_t format;
} shm_ctx_t;
struct lv_wayland_context {
struct wl_display * display;
struct wl_registry * registry;
struct wl_compositor * compositor;
struct wl_subcompositor * subcompositor;
struct wl_seat * wl_seat;
struct wl_cursor_theme * cursor_theme;
struct wl_surface * cursor_surface;
shm_ctx_t shm_ctx;
#if LV_WAYLAND_USE_DMABUF
dmabuf_ctx_t dmabuf_ctx;
#endif
#if LV_WAYLAND_WL_SHELL
struct wl_shell * wl_shell;
#endif
#if LV_WAYLAND_XDG_SHELL
struct xdg_wm_base * xdg_wm;
#endif
#ifdef LV_WAYLAND_WINDOW_DECORATIONS
bool opt_disable_decorations;
#endif
struct xkb_context * xkb_context;
struct seat seat;
struct graphic_object * touch_obj;
struct graphic_object * pointer_obj;
struct graphic_object * keyboard_obj;
lv_ll_t window_ll;
lv_timer_t * cycle_timer;
bool cursor_flush_pending;
struct pollfd wayland_pfd;
};
struct window {
lv_display_t * lv_disp;
lv_indev_t * lv_indev_pointer;
lv_indev_t * lv_indev_pointeraxis;
lv_indev_t * lv_indev_touch;
lv_indev_t * lv_indev_keyboard;
lv_wayland_display_close_f_t close_cb;
struct lv_wayland_context * wl_ctx;
#if LV_WAYLAND_WL_SHELL
struct wl_shell_surface * wl_shell_surface;
#endif
#if LV_WAYLAND_XDG_SHELL
struct xdg_surface * xdg_surface;
struct xdg_toplevel * xdg_toplevel;
uint32_t wm_capabilities;
#endif
struct graphic_object * body;
struct {
lv_area_t cache[DMG_CACHE_CAPACITY];
unsigned char start;
unsigned char end;
unsigned size;
} dmg_cache;
#if LV_WAYLAND_WINDOW_DECORATIONS
struct graphic_object * decoration[NUM_DECORATIONS];
#endif
int width;
int height;
bool resize_pending;
int resize_width;
int resize_height;
bool flush_pending;
bool shall_close;
bool closed;
bool maximized;
bool fullscreen;
uint32_t frame_counter;
};
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
extern struct lv_wayland_context lv_wl_ctx;
/**********************
* Driver
**********************/
void lv_wayland_init(void);
void lv_wayland_deinit(void);
void lv_wayland_wait_flush_cb(lv_display_t * disp);
/**********************
* Window
**********************/
const struct wl_callback_listener * lv_wayland_window_get_wl_surface_frame_listener(void);
void lv_wayland_window_draw(struct window * window, uint32_t width, uint32_t height);
lv_result_t lv_wayland_window_resize(struct window * window, int width, int height);
void lv_wayland_window_destroy(struct window * window);
#if LV_WAYLAND_WINDOW_DECORATIONS
uint32_t lv_wayland_window_decoration_create_all(struct window * window);
void lv_wayland_window_decoration_detach_all(struct window * window);
bool lv_wayland_window_decoration_create(struct window * window, struct graphic_object * decoration, int window_width,
int window_height);
bool lv_wayland_window_decoration_attach(struct window * window, struct graphic_object * decoration,
smm_buffer_t * decoration_buffer, struct graphic_object * parent);
void lv_wayland_window_decoration_detach(struct window * window, struct graphic_object * decoration);
#endif
/**********************
* Window Management
**********************/
#if LV_WAYLAND_WL_SHELL
lv_result_t lv_wayland_wl_shell_create_window(struct lv_wayland_context * app, struct window * window,
const char * title);
const struct wl_shell_surface_listener * lv_wayland_wl_shell_get_listener(void);
void lv_wayland_wl_shell_handle_pointer_event(struct lv_wayland_context * app, uint32_t serial, uint32_t button,
uint32_t state);
lv_result_t lv_wayland_wl_shell_set_maximized(struct window * window, bool maximized);
lv_result_t lv_wayland_wl_shell_set_minimized(struct window * window);
lv_result_t lv_wayland_wl_shell_set_fullscreen(struct window * window, bool fullscreen);
lv_result_t lv_wayland_wl_shell_destroy_window(struct window * window);
void lv_wayland_wl_shell_deinit(void);
#elif LV_WAYLAND_XDG_SHELL
const struct xdg_surface_listener * lv_wayland_xdg_shell_get_surface_listener(void);
const struct xdg_toplevel_listener * lv_wayland_xdg_shell_get_toplevel_listener(void);
const struct xdg_wm_base_listener * lv_wayland_xdg_shell_get_wm_base_listener(void);
lv_result_t lv_wayland_xdg_shell_set_maximized(struct window * window, bool maximized);
lv_result_t lv_wayland_xdg_shell_set_minimized(struct window * window);
lv_result_t lv_wayland_xdg_shell_set_fullscreen(struct window * window, bool fullscreen);
lv_result_t lv_wayland_xdg_shell_create_window(struct lv_wayland_context * app, struct window * window,
const char * title);
lv_result_t lv_wayland_xdg_shell_destroy_window_toplevel(struct window * window);
lv_result_t lv_wayland_xdg_shell_destroy_window_surface(struct window * window);
void lv_wayland_xdg_shell_handle_pointer_event(struct lv_wayland_context * app, uint32_t serial, uint32_t button,
uint32_t state);
const char * lv_wayland_xdg_shell_get_cursor_name(const struct lv_wayland_context * app);
void lv_wayland_xdg_shell_deinit(void);
#endif
/**********************
* SHM
**********************/
void lv_wayland_shm_set_interface(shm_ctx_t * context, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version);
struct graphic_object * lv_wayland_shm_on_graphical_object_creation(shm_ctx_t * context, struct graphic_object * obj);
void lv_wayland_shm_on_graphical_object_destruction(shm_ctx_t * context, struct graphic_object * obj);
lv_result_t lv_wayland_shm_set_draw_buffers(shm_ctx_t * context, lv_display_t * display);
lv_result_t lv_wayland_shm_create_draw_buffers(shm_ctx_t * context, struct window * window);
lv_result_t lv_wayland_shm_resize_window(shm_ctx_t * context, struct window * window, int32_t width, int32_t height);
lv_result_t lv_wayland_shm_is_ready(shm_ctx_t * context);
void lv_wayland_shm_delete_draw_buffers(shm_ctx_t * context, struct window * window);
void lv_wayland_shm_initalize_context(shm_ctx_t * context);
void lv_wayland_shm_deinit(shm_ctx_t * context);
void lv_wayland_shm_flush_partial_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p);
struct wl_cursor_theme * lv_wayland_shm_load_cursor_theme(shm_ctx_t * context);
/**********************
* DMABUF
**********************/
void lv_wayland_dmabuf_set_interface(dmabuf_ctx_t * context, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version);
struct graphic_object * lv_wayland_dmabuf_on_graphical_object_creation(dmabuf_ctx_t * context,
struct graphic_object * obj);
void lv_wayland_dmabuf_on_graphical_object_destruction(dmabuf_ctx_t * context, struct graphic_object * obj);
lv_result_t lv_wayland_dmabuf_set_draw_buffers(dmabuf_ctx_t * context, lv_display_t * display);
lv_result_t lv_wayland_dmabuf_create_draw_buffers(dmabuf_ctx_t * context, struct window * window);
lv_result_t lv_wayland_dmabuf_resize_window(dmabuf_ctx_t * context, struct window * window);
lv_result_t lv_wayland_dmabuf_is_ready(dmabuf_ctx_t * context);
void lv_wayland_dmabuf_destroy_draw_buffers(dmabuf_ctx_t * context, struct window * window);
void lv_wayland_dmabuf_initalize_context(dmabuf_ctx_t * context);
void lv_wayland_dmabuf_deinit(dmabuf_ctx_t * context);
void lv_wayland_dmabuf_flush_full_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p);
/**********************
* SME
**********************/
const struct smm_events * lv_wayland_sme_get_events(void);
/**********************
* Seat
**********************/
const struct wl_seat_listener * lv_wayland_seat_get_listener(void);
/**********************
* Input
**********************/
const struct wl_keyboard_listener * lv_wayland_keyboard_get_listener(void);
const struct wl_pointer_listener * lv_wayland_pointer_get_listener(void);
const struct wl_touch_listener * lv_wayland_touch_get_listener(void);
/**********************
* Cache
**********************/
void lv_wayland_cache_add_area(struct window * window, smm_buffer_t * buf, const lv_area_t * area);
void lv_wayland_cache_clear(struct window * window);
void lv_wayland_cache_apply_areas(struct window * window, void * dest, void * src, smm_buffer_t * src_buf);
void lv_wayland_cache_purge(struct window * window, smm_buffer_t * buf);
#endif /* LV_USE_WAYLAND */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_WAYLAND_PRIVATE_H*/
+1 -2
View File
@@ -8,7 +8,6 @@ typedef int dummy_t; /* Make GCC on windows happy, avoid empty translation u
#ifndef _WIN32
#include "lv_wayland_smm.h"
#include "../../display/lv_display.h"
#if LV_USE_WAYLAND
@@ -144,7 +143,7 @@ static struct {
} smm_instance;
void smm_init(struct smm_events * evs)
void smm_init(const struct smm_events * evs)
{
memcpy(&smm_instance.cbs, evs, sizeof(struct smm_events));
srand((unsigned int)clock());
+1 -1
View File
@@ -69,7 +69,7 @@ struct smm_group_properties {
void * tag[SMM_GROUP_TAGS];
};
void smm_init(struct smm_events * evs);
void smm_init(const struct smm_events * evs);
void smm_setctx(void * ctx);
void smm_deinit(void);
smm_group_t * smm_create(void);
+133
View File
@@ -0,0 +1,133 @@
/**
* @file lv_wl_cache.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_USE_WAYLAND
#include "lv_wayland_private.h"
#include <string.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* PRIVATE FUNCTIONS
**********************/
void lv_wayland_cache_apply_areas(struct window * window, void * dest, void * src, smm_buffer_t * src_buf)
{
unsigned long offset;
unsigned char start;
int32_t y;
lv_area_t * dmg;
lv_area_t * next_dmg;
smm_buffer_t * next_buf = smm_next(src_buf);
const struct smm_buffer_properties * props = SMM_BUFFER_PROPERTIES(src_buf);
struct graphic_object * obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
uint8_t bpp;
if(next_buf == NULL) {
next_dmg = (window->dmg_cache.cache + window->dmg_cache.end);
}
else {
next_dmg = SMM_BUFFER_PROPERTIES(next_buf)->tag[TAG_BUFFER_DAMAGE];
}
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
/* Apply all buffer damage areas */
start = ((lv_area_t *)SMM_BUFFER_PROPERTIES(src_buf)->tag[TAG_BUFFER_DAMAGE] - window->dmg_cache.cache);
while((window->dmg_cache.cache + start) != next_dmg) {
/* Copy an area from source to destination (line-by-line) */
dmg = (window->dmg_cache.cache + start);
for(y = dmg->y1; y <= dmg->y2; y++) {
offset = (dmg->x1 + (y * obj->width)) * bpp;
memcpy(((char *)dest) + offset, ((char *)src) + offset, ((dmg->x2 - dmg->x1 + 1) * bpp));
}
start++;
start %= DMG_CACHE_CAPACITY;
}
}
void lv_wayland_cache_add_area(struct window * window, smm_buffer_t * buf, const lv_area_t * area)
{
if(SMM_BUFFER_PROPERTIES(buf)->tag[TAG_BUFFER_DAMAGE] == NULL) {
/* Buffer damage beyond cache capacity */
return;
}
if((window->dmg_cache.start == window->dmg_cache.end) && (window->dmg_cache.size)) {
/* This buffer has more damage then the cache's capacity, so
* clear cache and leave buffer damage unrecorded
*/
lv_wayland_cache_clear(window);
SMM_TAG(buf, TAG_BUFFER_DAMAGE, NULL);
return;
}
/* Add damage area to cache */
memcpy(window->dmg_cache.cache + window->dmg_cache.end, area, sizeof(lv_area_t));
window->dmg_cache.end++;
window->dmg_cache.end %= DMG_CACHE_CAPACITY;
window->dmg_cache.size++;
}
void lv_wayland_cache_clear(struct window * window)
{
window->dmg_cache.start = window->dmg_cache.end;
window->dmg_cache.size = 0;
}
void lv_wayland_cache_purge(struct window * window, smm_buffer_t * buf)
{
lv_area_t * next_dmg;
smm_buffer_t * next_buf = smm_next(buf);
/* Remove all damage areas up until start of next buffers damage */
if(next_buf == NULL) {
lv_wayland_cache_clear(window);
}
else {
next_dmg = SMM_BUFFER_PROPERTIES(next_buf)->tag[TAG_BUFFER_DAMAGE];
while((window->dmg_cache.cache + window->dmg_cache.start) != next_dmg) {
window->dmg_cache.start++;
window->dmg_cache.start %= DMG_CACHE_CAPACITY;
window->dmg_cache.size--;
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /* LV_USE_WAYLAND */
+360
View File
@@ -0,0 +1,360 @@
/**
* @file lv_wl_dmabuf.c
*
*/
#include "lv_wayland.h"
#if LV_WAYLAND_USE_DMABUF
#include "lv_wayland_private.h"
#include <wayland_linux_dmabuf.h>
#include <drm/drm_fourcc.h>
#include <stdlib.h>
#include <src/misc/lv_types.h>
#include <string.h>
#include "../../draw/nxp/g2d/lv_g2d_utils.h"
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
#define MAX_BUFFER_PLANES 4
struct buffer {
int busy;
#if LV_WAYLAND_USE_DMABUF
struct window * window;
int plane_count;
int dmabuf_fds[MAX_BUFFER_PLANES];
uint32_t strides[MAX_BUFFER_PLANES];
uint32_t offsets[MAX_BUFFER_PLANES];
struct wl_buffer * buffer;
#endif
void * buf_base[MAX_BUFFER_PLANES];
lv_draw_buf_t * lv_draw_buf;
};
/**********************
* STATIC PROTOTYPES
**********************/
static void dmabuf_modifiers(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format,
uint32_t modifier_hi, uint32_t modifier_lo);
static void dmabuf_format(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format);
static struct buffer * dmabuf_acquire_buffer(dmabuf_ctx_t * context, unsigned char * color_p);
static struct buffer * lv_wayland_dmabuf_create_draw_buffers_internal(struct window * window);
static void buffer_free(struct buffer * buf);
/**********************
* STATIC VARIABLES
**********************/
static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener_v3 = {.format = dmabuf_format,
.modifier = dmabuf_modifiers
};
static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {.format = dmabuf_format};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* PRIVATE FUNCTIONS
**********************/
void lv_wayland_dmabuf_initalize_context(dmabuf_ctx_t * context)
{
memset(context, 0, sizeof(*context));
context->format = DRM_FORMAT_INVALID;
}
lv_result_t lv_wayland_dmabuf_set_draw_buffers(dmabuf_ctx_t * context, lv_display_t * display)
{
if(LV_WAYLAND_BUF_COUNT == 2) {
lv_display_set_draw_buffers(display, context->buffers[0].lv_draw_buf, context->buffers[1].lv_draw_buf);
return LV_RESULT_OK;
}
else if(LV_WAYLAND_BUF_COUNT == 1) {
lv_display_set_draw_buffers(display, context->buffers[0].lv_draw_buf, NULL);
return LV_RESULT_OK;
}
return LV_RESULT_INVALID;
}
void lv_wayland_dmabuf_set_interface(dmabuf_ctx_t * context, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version)
{
LV_UNUSED(interface);
if(version > 3) {
LV_LOG_WARN("Unsupported DMABUF version %d. Using version 3 instead", version);
version = 3;
}
context->handler = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version);
if(version < 3) {
zwp_linux_dmabuf_v1_add_listener(context->handler, &dmabuf_listener, context);
}
else if(version == 3) {
zwp_linux_dmabuf_v1_add_listener(context->handler, &dmabuf_listener_v3, context);
}
}
lv_result_t lv_wayland_dmabuf_is_ready(dmabuf_ctx_t * context)
{
return (context->handler && context->format != DRM_FORMAT_INVALID) ? LV_RESULT_OK : LV_RESULT_INVALID;
}
void lv_wayland_dmabuf_destroy_window(dmabuf_ctx_t * context, struct window * window)
{
LV_UNUSED(context);
LV_ASSERT_NULL(window);
}
void lv_wayland_dmabuf_deinit(dmabuf_ctx_t * context)
{
LV_UNUSED(context);
}
struct graphic_object * lv_wayland_dmabuf_on_graphical_object_creation(dmabuf_ctx_t * context,
struct graphic_object * obj)
{
LV_UNUSED(context);
return obj;
}
void lv_wayland_dmabuf_on_graphical_object_destruction(dmabuf_ctx_t * context, struct graphic_object * obj)
{
LV_UNUSED(context);
LV_UNUSED(obj);
}
void lv_wayland_dmabuf_flush_full_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p)
{
struct window * window = lv_display_get_user_data(disp);
struct buffer * buf = dmabuf_acquire_buffer(&window->wl_ctx->dmabuf_ctx, color_p);
if(!buf) {
LV_LOG_ERROR("Failed to acquire a wayland window body buffer");
return;
}
int32_t src_width = lv_area_get_width(area);
int32_t src_height = lv_area_get_height(area);
lv_draw_buf_invalidate_cache(buf->lv_draw_buf, NULL);
/* Mark surface damage */
wl_surface_damage(window->body->surface, area->x1, area->y1, src_width, src_height);
if(lv_display_flush_is_last(disp)) {
/* Finally, attach buffer and commit to surface */
wl_surface_attach(window->body->surface, buf->buffer, 0, 0);
wl_surface_commit(window->body->surface);
struct wl_callback * cb = wl_surface_frame(window->body->surface);
wl_callback_add_listener(cb, lv_wayland_window_get_wl_surface_frame_listener(), window->body);
buf->busy = 1;
window->flush_pending = true;
}
return;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void buffer_release(void * data, struct wl_buffer * buffer)
{
LV_UNUSED(buffer);
struct buffer * buf = data;
buf->busy = 0;
}
static const struct wl_buffer_listener buffer_listener = {.release = buffer_release};
static void create_succeeded(void * data, struct zwp_linux_buffer_params_v1 * params, struct wl_buffer * new_buffer)
{
struct buffer * buffer = data;
buffer->buffer = new_buffer;
/* When not using explicit synchronization listen to wl_buffer.release
* for release notifications, otherwise we are going to use
* zwp_linux_buffer_release_v1. */
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
zwp_linux_buffer_params_v1_destroy(params);
}
static void create_failed(void * data, struct zwp_linux_buffer_params_v1 * params)
{
struct buffer * buffer = data;
buffer->buffer = NULL;
zwp_linux_buffer_params_v1_destroy(params);
LV_LOG_ERROR("Failed to create dmabuf buffer\n");
}
static const struct zwp_linux_buffer_params_v1_listener params_listener = {.created = create_succeeded,
.failed = create_failed
};
lv_result_t lv_wayland_dmabuf_resize_window(dmabuf_ctx_t * context, struct window * window)
{
struct buffer * buffers = lv_wayland_dmabuf_create_draw_buffers_internal(window);
if(!buffers) {
return LV_RESULT_INVALID;
}
lv_wayland_dmabuf_destroy_draw_buffers(context, window);
context->buffers = buffers;
lv_wayland_dmabuf_set_draw_buffers(context, window->lv_disp);
return LV_RESULT_OK;
}
lv_result_t lv_wayland_dmabuf_create_draw_buffers(dmabuf_ctx_t * context, struct window * window)
{
struct buffer * buffers = lv_wayland_dmabuf_create_draw_buffers_internal(window);
if(!buffers) {
return LV_RESULT_INVALID;
}
context->buffers = buffers;
return LV_RESULT_OK;
}
void lv_wayland_dmabuf_destroy_draw_buffers(dmabuf_ctx_t * context, struct window * window)
{
LV_UNUSED(window);
if(context->buffers == NULL) {
return;
}
for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) {
buffer_free(&context->buffers[i]);
return;
}
free(context->buffers);
context->buffers = NULL;
}
static struct buffer * lv_wayland_dmabuf_create_draw_buffers_internal(struct window * window)
{
const uint32_t flags = 0;
struct zwp_linux_buffer_params_v1 * params;
const int stride = lv_draw_buf_width_to_stride(window->width, lv_display_get_color_format(window->lv_disp));
struct buffer * buffers = (struct buffer *)calloc(LV_WAYLAND_BUF_COUNT, sizeof(struct buffer));
LV_ASSERT_MALLOC(buffers);
for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) {
uint32_t drmcf = 0;
buffers[i].window = window;
buffers[i].lv_draw_buf =
lv_draw_buf_create(window->width, window->height, lv_display_get_color_format(window->lv_disp), stride);
buffers[i].strides[0] = stride;
buffers[i].dmabuf_fds[0] = g2d_get_buf_fd(buffers[i].lv_draw_buf);
buffers[i].buf_base[0] = buffers[i].lv_draw_buf->data;
params = zwp_linux_dmabuf_v1_create_params(window->wl_ctx->dmabuf_ctx.handler);
switch(lv_display_get_color_format(window->lv_disp)) {
case LV_COLOR_FORMAT_XRGB8888:
drmcf = DRM_FORMAT_XRGB8888;
break;
case LV_COLOR_FORMAT_ARGB8888:
drmcf = DRM_FORMAT_ARGB8888;
break;
case LV_COLOR_FORMAT_RGB565:
drmcf = DRM_FORMAT_RGB565;
break;
default:
drmcf = DRM_FORMAT_ARGB8888;
}
zwp_linux_buffer_params_v1_add(params, buffers[i].dmabuf_fds[0], 0, buffers[i].offsets[0], buffers[i].strides[0], 0,
0);
zwp_linux_buffer_params_v1_add_listener(params, &params_listener, &buffers[i]);
zwp_linux_buffer_params_v1_create(params, window->width, window->height, drmcf, flags);
}
wl_display_roundtrip(lv_wl_ctx.display);
return buffers;
}
static void buffer_free(struct buffer * buf)
{
if(buf->buffer) wl_buffer_destroy(buf->buffer);
if(buf->lv_draw_buf) lv_draw_buf_destroy(buf->lv_draw_buf);
}
static void dmabuf_modifiers(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format,
uint32_t modifier_hi, uint32_t modifier_lo)
{
LV_UNUSED(modifier_hi);
LV_UNUSED(modifier_lo);
dmabuf_format(data, zwp_linux_dmabuf, format);
}
static void dmabuf_format(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format)
{
dmabuf_ctx_t * ctx = data;
LV_UNUSED(zwp_linux_dmabuf);
if(LV_COLOR_DEPTH == 32 && format == DRM_FORMAT_ARGB8888) {
/* Wayland compositors MUST support ARGB8888 */
ctx->format = format;
}
else if(LV_COLOR_DEPTH == 32 && format == DRM_FORMAT_XRGB8888 && ctx->format != DRM_FORMAT_ARGB8888) {
/* Select XRGB only if the compositor doesn't support transprancy */
ctx->format = format;
}
else if(LV_COLOR_DEPTH == 16 && format == DRM_FORMAT_RGB565) {
ctx->format = format;
}
}
static struct buffer * dmabuf_acquire_buffer(dmabuf_ctx_t * context, unsigned char * color_p)
{
for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) {
struct buffer * buffer = &context->buffers[i];
if(buffer->buf_base[0] == color_p && buffer->busy == 0) {
return buffer;
}
}
while(1) {
wl_display_roundtrip(lv_wl_ctx.display);
for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) {
struct buffer * buffer = &context->buffers[i];
if(buffer->buf_base[0] == color_p && buffer->busy == 0) {
return buffer;
}
}
}
return NULL;
}
#endif /* LV_WAYLAND_DMABUF */
+301
View File
@@ -0,0 +1,301 @@
/**
* @file lv_wl_keyboard.c
*
*/
#include "lv_wl_keyboard.h"
#if LV_USE_WAYLAND
#include "lv_wayland_private.h"
#include <sys/mman.h>
#include <unistd.h>
#include <wayland-client-protocol.h>
#include <xkbcommon/xkbcommon.h>
#include "../../misc/lv_log.h"
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void keyboard_read(lv_indev_t * drv, lv_indev_data_t * data);
static void keyboard_handle_keymap(void * data, struct wl_keyboard * keyboard, uint32_t format, int fd, uint32_t size);
static void keyboard_handle_enter(void * data, struct wl_keyboard * keyboard, uint32_t serial,
struct wl_surface * surface, struct wl_array * keys);
static void keyboard_handle_leave(void * data, struct wl_keyboard * keyboard, uint32_t serial,
struct wl_surface * surface);
static void keyboard_handle_modifiers(void * data, struct wl_keyboard * keyboard, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked,
uint32_t group);
static void keyboard_handle_key(void * data, struct wl_keyboard * keyboard, uint32_t serial, uint32_t time,
uint32_t key, uint32_t state);
static lv_key_t keycode_xkb_to_lv(xkb_keysym_t xkb_key);
/**********************
* STATIC VARIABLES
**********************/
static const struct wl_keyboard_listener keyboard_listener = {
.keymap = keyboard_handle_keymap,
.enter = keyboard_handle_enter,
.leave = keyboard_handle_leave,
.key = keyboard_handle_key,
.modifiers = keyboard_handle_modifiers,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_indev_t * lv_wayland_keyboard_create(void)
{
lv_indev_t * keyboard = lv_indev_create();
lv_indev_set_type(keyboard, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(keyboard, keyboard_read);
return keyboard;
}
lv_indev_t * lv_wayland_get_keyboard(lv_display_t * display)
{
struct window * window = lv_display_get_user_data(display);
if(!window) {
return NULL;
}
return window->lv_indev_keyboard;
}
/**********************
* PRIVATE FUNCTIONS
**********************/
const struct wl_keyboard_listener * lv_wayland_keyboard_get_listener(void)
{
return &keyboard_listener;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void keyboard_read(lv_indev_t * drv, lv_indev_data_t * data)
{
struct window * window = lv_display_get_user_data(lv_indev_get_display(drv));
if(!window || window->closed) {
return;
}
data->key = window->body->input.keyboard.key;
data->state = window->body->input.keyboard.state;
}
static void keyboard_handle_keymap(void * data, struct wl_keyboard * keyboard, uint32_t format, int fd, uint32_t size)
{
struct lv_wayland_context * app = data;
struct xkb_keymap * keymap;
struct xkb_state * state;
char * map_str;
LV_UNUSED(keyboard);
if(format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
close(fd);
return;
}
map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if(map_str == MAP_FAILED) {
close(fd);
return;
}
/* Set up XKB keymap */
keymap = xkb_keymap_new_from_string(app->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
munmap(map_str, size);
close(fd);
if(!keymap) {
LV_LOG_ERROR("failed to compile keymap");
return;
}
/* Set up XKB state */
state = xkb_state_new(keymap);
if(!state) {
LV_LOG_ERROR("failed to create XKB state");
xkb_keymap_unref(keymap);
return;
}
xkb_keymap_unref(app->seat.xkb.keymap);
xkb_state_unref(app->seat.xkb.state);
app->seat.xkb.keymap = keymap;
app->seat.xkb.state = state;
}
static void keyboard_handle_enter(void * data, struct wl_keyboard * keyboard, uint32_t serial,
struct wl_surface * surface, struct wl_array * keys)
{
struct lv_wayland_context * app = data;
LV_UNUSED(keyboard);
LV_UNUSED(serial);
LV_UNUSED(keys);
if(!surface) {
app->keyboard_obj = NULL;
}
else {
app->keyboard_obj = wl_surface_get_user_data(surface);
}
}
static void keyboard_handle_leave(void * data, struct wl_keyboard * keyboard, uint32_t serial,
struct wl_surface * surface)
{
struct lv_wayland_context * app = data;
LV_UNUSED(serial);
LV_UNUSED(keyboard);
if(!surface || (app->keyboard_obj == wl_surface_get_user_data(surface))) {
app->keyboard_obj = NULL;
}
}
static void keyboard_handle_key(void * data, struct wl_keyboard * keyboard, uint32_t serial, uint32_t time,
uint32_t key, uint32_t state)
{
struct lv_wayland_context * app = data;
const uint32_t code = (key + 8);
const xkb_keysym_t * syms;
xkb_keysym_t sym = XKB_KEY_NoSymbol;
LV_UNUSED(serial);
LV_UNUSED(time);
LV_UNUSED(keyboard);
if(!app->keyboard_obj || !app->seat.xkb.state) {
return;
}
if(xkb_state_key_get_syms(app->seat.xkb.state, code, &syms) == 1) {
sym = syms[0];
}
const lv_key_t lv_key = keycode_xkb_to_lv(sym);
const lv_indev_state_t lv_state =
(state == WL_KEYBOARD_KEY_STATE_PRESSED) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
if(lv_key != 0) {
app->keyboard_obj->input.keyboard.key = lv_key;
app->keyboard_obj->input.keyboard.state = lv_state;
}
}
static void keyboard_handle_modifiers(void * data, struct wl_keyboard * keyboard, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{
struct lv_wayland_context * app = data;
LV_UNUSED(serial);
LV_UNUSED(keyboard);
/* If we're not using a keymap, then we don't handle PC-style modifiers */
if(!app->seat.xkb.keymap) {
return;
}
xkb_state_update_mask(app->seat.xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
}
static lv_key_t keycode_xkb_to_lv(xkb_keysym_t xkb_key)
{
lv_key_t key = 0;
if(((xkb_key >= XKB_KEY_space) && (xkb_key <= XKB_KEY_asciitilde))) {
key = xkb_key;
}
else if(((xkb_key >= XKB_KEY_KP_0) && (xkb_key <= XKB_KEY_KP_9))) {
key = (xkb_key & 0x003f);
}
else {
switch(xkb_key) {
case XKB_KEY_BackSpace:
key = LV_KEY_BACKSPACE;
break;
case XKB_KEY_Return:
case XKB_KEY_KP_Enter:
key = LV_KEY_ENTER;
break;
case XKB_KEY_Escape:
key = LV_KEY_ESC;
break;
case XKB_KEY_Delete:
case XKB_KEY_KP_Delete:
key = LV_KEY_DEL;
break;
case XKB_KEY_Home:
case XKB_KEY_KP_Home:
key = LV_KEY_HOME;
break;
case XKB_KEY_Left:
case XKB_KEY_KP_Left:
key = LV_KEY_LEFT;
break;
case XKB_KEY_Up:
case XKB_KEY_KP_Up:
key = LV_KEY_UP;
break;
case XKB_KEY_Right:
case XKB_KEY_KP_Right:
key = LV_KEY_RIGHT;
break;
case XKB_KEY_Down:
case XKB_KEY_KP_Down:
key = LV_KEY_DOWN;
break;
case XKB_KEY_Prior:
case XKB_KEY_KP_Prior:
key = LV_KEY_PREV;
break;
case XKB_KEY_Next:
case XKB_KEY_KP_Next:
case XKB_KEY_Tab:
case XKB_KEY_KP_Tab:
key = LV_KEY_NEXT;
break;
case XKB_KEY_End:
case XKB_KEY_KP_End:
key = LV_KEY_END;
break;
default:
break;
}
}
return key;
}
#endif /* LV_WAYLAND */
+52
View File
@@ -0,0 +1,52 @@
/**
* @file lv_wl_keyboard.h
*
*/
#ifndef LV_WL_KEYBOARD_H
#define LV_WL_KEYBOARD_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../indev/lv_indev.h"
#include "../../indev/lv_indev_gesture.h"
#if LV_USE_WAYLAND
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_indev_t * lv_wayland_keyboard_create(void);
/**
* Get keyboard input device for given LVGL display
* @param display LVGL display
* @return input device connected to keyboard, or NULL on error
*/
lv_indev_t * lv_wayland_get_keyboard(lv_display_t * display);
/**********************
* MACROS
**********************/
#endif /* LV_USE_WAYLAND */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_WL_KEYBOARD_H*/
+245
View File
@@ -0,0 +1,245 @@
/**
* @file lv_wl_pointer.c
*
*/
#include "lv_wl_pointer.h"
#if LV_USE_WAYLAND
#include <sys/mman.h>
#include <unistd.h>
#include <wayland-client-protocol.h>
#include <wayland-cursor.h>
#include <xkbcommon/xkbcommon.h>
#include <linux/input-event-codes.h>
#include "lv_wayland_private.h"
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void _lv_wayland_pointer_read(lv_indev_t * drv, lv_indev_data_t * data);
static void pointer_handle_enter(void * data, struct wl_pointer * pointer, uint32_t serial, struct wl_surface * surface,
wl_fixed_t sx, wl_fixed_t sy);
static void pointer_handle_leave(void * data, struct wl_pointer * pointer, uint32_t serial,
struct wl_surface * surface);
static void pointer_handle_motion(void * data, struct wl_pointer * pointer, uint32_t time, wl_fixed_t sx,
wl_fixed_t sy);
static void pointer_handle_button(void * data, struct wl_pointer * wl_pointer, uint32_t serial, uint32_t time,
uint32_t button, uint32_t state);
static void pointer_handle_axis(void * data, struct wl_pointer * wl_pointer, uint32_t time, uint32_t axis,
wl_fixed_t value);
/**********************
* STATIC VARIABLES
**********************/
static const struct wl_pointer_listener pointer_listener = {
.enter = pointer_handle_enter,
.leave = pointer_handle_leave,
.motion = pointer_handle_motion,
.button = pointer_handle_button,
.axis = pointer_handle_axis,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_indev_t * lv_wayland_pointer_create(void)
{
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, _lv_wayland_pointer_read);
return indev;
}
lv_indev_t * lv_wayland_get_pointer(lv_display_t * disp)
{
struct window * window = lv_display_get_user_data(disp);
if(!window) {
return NULL;
}
return window->lv_indev_pointer;
}
/**********************
* PRIVATE FUNCTIONS
**********************/
const struct wl_pointer_listener * lv_wayland_pointer_get_listener(void)
{
return &pointer_listener;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _lv_wayland_pointer_read(lv_indev_t * drv, lv_indev_data_t * data)
{
struct window * window = lv_display_get_user_data(lv_indev_get_display(drv));
if(!window || window->closed) {
return;
}
data->point.x = window->body->input.pointer.x;
data->point.y = window->body->input.pointer.y;
data->state = window->body->input.pointer.left_button;
}
static void pointer_handle_enter(void * data, struct wl_pointer * pointer, uint32_t serial, struct wl_surface * surface,
wl_fixed_t sx, wl_fixed_t sy)
{
struct lv_wayland_context * app = data;
const char * cursor = LV_WAYLAND_DEFAULT_CURSOR_NAME;
int pos_x = wl_fixed_to_int(sx);
int pos_y = wl_fixed_to_int(sy);
if(!surface) {
app->pointer_obj = NULL;
return;
}
app->pointer_obj = wl_surface_get_user_data(surface);
app->pointer_obj->input.pointer.x = pos_x;
app->pointer_obj->input.pointer.y = pos_y;
#if LV_WAYLAND_XDG_SHELL
cursor = lv_wayland_xdg_shell_get_cursor_name(app);
#endif
if(app->cursor_surface) {
struct wl_cursor_image * cursor_image = wl_cursor_theme_get_cursor(app->cursor_theme, cursor)->images[0];
wl_pointer_set_cursor(pointer, serial, app->cursor_surface, cursor_image->hotspot_x, cursor_image->hotspot_y);
wl_surface_attach(app->cursor_surface, wl_cursor_image_get_buffer(cursor_image), 0, 0);
wl_surface_damage(app->cursor_surface, 0, 0, cursor_image->width, cursor_image->height);
wl_surface_commit(app->cursor_surface);
app->cursor_flush_pending = true;
}
}
static void pointer_handle_leave(void * data, struct wl_pointer * pointer, uint32_t serial, struct wl_surface * surface)
{
struct lv_wayland_context * app = data;
LV_UNUSED(pointer);
LV_UNUSED(serial);
if(!surface || (app->pointer_obj == wl_surface_get_user_data(surface))) {
app->pointer_obj = NULL;
}
}
static void pointer_handle_motion(void * data, struct wl_pointer * pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
{
struct lv_wayland_context * app = data;
LV_UNUSED(pointer);
LV_UNUSED(time);
if(!app->pointer_obj) {
return;
}
app->pointer_obj->input.pointer.x = LV_MAX(0, LV_MIN(wl_fixed_to_int(sx), app->pointer_obj->width - 1));
app->pointer_obj->input.pointer.y = LV_MAX(0, LV_MIN(wl_fixed_to_int(sy), app->pointer_obj->height - 1));
}
static void pointer_handle_button(void * data, struct wl_pointer * wl_pointer, uint32_t serial, uint32_t time,
uint32_t button, uint32_t state)
{
struct lv_wayland_context * app = data;
LV_UNUSED(serial);
LV_UNUSED(wl_pointer);
LV_UNUSED(time);
const lv_indev_state_t lv_state =
(state == WL_POINTER_BUTTON_STATE_PRESSED) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
if(!app->pointer_obj) {
return;
}
struct window * window = app->pointer_obj->window;
#if LV_WAYLAND_WL_SHELL
lv_wayland_wl_shell_handle_pointer_event(app, serial, button, state);
#elif LV_WAYLAND_XDG_SHELL
lv_wayland_xdg_shell_handle_pointer_event(app, serial, button, state);
#endif
switch(app->pointer_obj->type) {
case OBJECT_WINDOW:
switch(button) {
case BTN_LEFT:
app->pointer_obj->input.pointer.left_button = lv_state;
break;
case BTN_RIGHT:
app->pointer_obj->input.pointer.right_button = lv_state;
break;
case BTN_MIDDLE:
app->pointer_obj->input.pointer.wheel_button = lv_state;
break;
default:
break;
}
break;
case OBJECT_BUTTON_CLOSE:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_RELEASED)) {
window->shall_close = true;
}
break;
default:
break;
}
}
static void pointer_handle_axis(void * data, struct wl_pointer * wl_pointer, uint32_t time, uint32_t axis,
wl_fixed_t value)
{
struct lv_wayland_context * app = data;
const int diff = wl_fixed_to_int(value);
LV_UNUSED(time);
LV_UNUSED(wl_pointer);
if(!app->pointer_obj) {
return;
}
if(axis == 0) {
if(diff > 0) {
app->pointer_obj->input.pointer.wheel_diff++;
}
else if(diff < 0) {
app->pointer_obj->input.pointer.wheel_diff--;
}
}
}
#endif /* LV_USE_WAYLAND */
+54
View File
@@ -0,0 +1,54 @@
/**
* @file lv_wl_pointer.h
*
*/
#ifndef LV_WL_POINTER_H
#define LV_WL_POINTER_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../indev/lv_indev.h"
#include "../../indev/lv_indev_gesture.h"
#if LV_USE_WAYLAND
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_indev_t * lv_wayland_pointer_create(void);
/**
* Obtains the input device of the mouse pointer
* @note It is used to create an input group on application start
* @param disp Reference to the LVGL display associated to the window
* @return The input device
*/
lv_indev_t * lv_wayland_get_pointer(lv_display_t * disp);
/**********************
* MACROS
**********************/
#endif /* LV_USE_WAYLAND */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_WL_POINTER_H*/
+79
View File
@@ -0,0 +1,79 @@
/**
* @file lv_wl_pointer_axis.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wl_pointer_axis.h"
#if LV_USE_WAYLAND
#include "lv_wayland_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void pointeraxis_read(lv_indev_t * drv, lv_indev_data_t * data);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_indev_t * lv_wayland_pointer_axis_create(void)
{
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER);
lv_indev_set_read_cb(indev, pointeraxis_read);
return indev;
}
lv_indev_t * lv_wayland_get_pointeraxis(lv_display_t * display)
{
struct window * window = lv_display_get_user_data(display);
if(!window) {
return NULL;
}
return window->lv_indev_pointeraxis;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void pointeraxis_read(lv_indev_t * drv, lv_indev_data_t * data)
{
struct window * window = lv_display_get_user_data(lv_indev_get_display(drv));
if(!window || window->closed) {
return;
}
data->state = window->body->input.pointer.wheel_button;
data->enc_diff = window->body->input.pointer.wheel_diff;
window->body->input.pointer.wheel_diff = 0;
}
#endif /* LV_USE_WAYLAND */
+54
View File
@@ -0,0 +1,54 @@
/**
* @file lv_wl_pointer_axis.h
*
*/
#ifndef LV_WL_POINTER_AXIS_H
#define LV_WL_POINTER_AXIS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "../../indev/lv_indev.h"
#include "../../indev/lv_indev_gesture.h"
#if LV_USE_WAYLAND
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_indev_t * lv_wayland_pointer_axis_create(void);
/**
* Obtains the input device of the encoder
* @note It is used to create an input group on application start
* @param display Reference to the LVGL display associated to the window
* @return The input device
*/
lv_indev_t * lv_wayland_get_pointeraxis(lv_display_t * display);
/**********************
* MACROS
**********************/
#endif /* LV_USE_WAYLAND */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_WL_POINTER_AXIS_H*/
+100
View File
@@ -0,0 +1,100 @@
/**
* @file lv_wl_seat.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_USE_WAYLAND
#include "lv_wayland_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void seat_handle_capabilities(void * data, struct wl_seat * wl_seat, enum wl_seat_capability caps);
/**********************
* STATIC VARIABLES
**********************/
static const struct wl_seat_listener seat_listener = {
.capabilities = seat_handle_capabilities,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* PRIVATE FUNCTIONS
**********************/
const struct wl_seat_listener * lv_wayland_seat_get_listener(void)
{
return &seat_listener;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void seat_handle_capabilities(void * data, struct wl_seat * wl_seat, enum wl_seat_capability caps)
{
struct lv_wayland_context * app = data;
struct seat * seat = &app->seat;
if((caps & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer) {
seat->wl_pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(seat->wl_pointer, lv_wayland_pointer_get_listener(), app);
app->cursor_surface = wl_compositor_create_surface(app->compositor);
if(!app->cursor_surface) {
LV_LOG_WARN("failed to create cursor surface");
}
}
else if(!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) {
wl_pointer_destroy(seat->wl_pointer);
if(app->cursor_surface) {
wl_surface_destroy(app->cursor_surface);
}
seat->wl_pointer = NULL;
}
if((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !seat->wl_keyboard) {
seat->wl_keyboard = wl_seat_get_keyboard(wl_seat);
wl_keyboard_add_listener(seat->wl_keyboard, lv_wayland_keyboard_get_listener(), app);
}
else if(!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->wl_keyboard) {
wl_keyboard_destroy(seat->wl_keyboard);
seat->wl_keyboard = NULL;
}
#if LV_USE_GESTURE_RECOGNITION
if((caps & WL_SEAT_CAPABILITY_TOUCH) && !seat->wl_touch) {
seat->wl_touch = wl_seat_get_touch(wl_seat);
wl_touch_add_listener(seat->wl_touch, lv_wayland_touch_get_listener(), app);
}
#endif
else if(!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch) {
wl_touch_destroy(seat->wl_touch);
seat->wl_touch = NULL;
}
}
#endif /* LV_USE_WAYLAND */
+184
View File
@@ -0,0 +1,184 @@
/**
* @file lv_wl_shell.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_WAYLAND_WL_SHELL
/* WL_SHELL has been deprecated for 3 years now */
#warning LV_WAYLAND_WL_SHELL is deprecated and will be removed in a future release
#include "lv_wayland_private.h"
#include <linux/input-event-codes.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void wl_shell_handle_ping(void * data, struct wl_shell_surface * shell_surface, uint32_t serial);
static void wl_shell_handle_configure(void * data, struct wl_shell_surface * shell_surface, uint32_t edges,
int32_t width, int32_t height);
/**********************
* STATIC VARIABLES
**********************/
static const struct wl_shell_surface_listener shell_surface_listener = {
.ping = wl_shell_handle_ping,
.configure = wl_shell_handle_configure,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* PRIVATE FUNCTIONS
**********************/
void lv_wayland_wl_shell_deinit(void)
{
if(lv_wl_ctx.wl_shell) {
wl_shell_destroy(lv_wl_ctx.wl_shell);
}
}
const struct wl_shell_surface_listener * lv_wayland_wl_shell_get_listener(void)
{
return &shell_surface_listener;
}
lv_result_t lv_wayland_wl_shell_create_window(struct lv_wayland_context * ctx, struct window * window,
const char * title)
{
if(!ctx->wl_shell) {
return LV_RESULT_INVALID;
}
window->wl_shell_surface = wl_shell_get_shell_surface(ctx->wl_shell, window->body->surface);
if(!window->wl_shell_surface) {
LV_LOG_ERROR("cannot create WL shell surface");
return LV_RESULT_INVALID;
}
wl_shell_surface_add_listener(window->wl_shell_surface, lv_wayland_wl_shell_get_listener(), window);
wl_shell_surface_set_toplevel(window->wl_shell_surface);
wl_shell_surface_set_title(window->wl_shell_surface, title);
/* For wl_shell, just draw the window, weston doesn't send it */
lv_wayland_window_draw(window, window->width, window->height);
return LV_RESULT_OK;
}
lv_result_t lv_wayland_wl_shell_set_maximized(struct window * window, bool maximized)
{
if(!window->wl_shell_surface) {
return LV_RESULT_INVALID;
}
if(maximized) {
LV_LOG_ERROR("WL_SHELL - Unsupported operation - Maximization");
return LV_RESULT_INVALID;
}
else {
wl_shell_surface_set_toplevel(window->wl_shell_surface);
}
return LV_RESULT_OK;
}
lv_result_t lv_wayland_wl_shell_set_minimized(struct window * window)
{
LV_LOG_ERROR("WL_SHELL - Unsupported operation - Minization");
return LV_RESULT_INVALID;
}
lv_result_t lv_wayland_wl_shell_set_fullscreen(struct window * window, bool fullscreen)
{
if(!window->wl_shell_surface) {
return LV_RESULT_INVALID;
}
if(fullscreen) {
wl_shell_surface_set_fullscreen(window->wl_shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, 0, NULL);
}
else {
wl_shell_surface_set_toplevel(window->wl_shell_surface);
}
return LV_RESULT_OK;
}
lv_result_t lv_wayland_wl_shell_destroy_window(struct window * window)
{
if(!window->wl_shell_surface) {
return LV_RESULT_INVALID;
}
wl_shell_surface_destroy(window->wl_shell_surface);
return LV_RESULT_OK;
}
void lv_wayland_wl_shell_handle_pointer_event(struct lv_wayland_context * ctx, uint32_t serial, uint32_t button,
uint32_t state)
{
struct window * window = ctx->pointer_obj->window;
switch(ctx->pointer_obj->type) {
case OBJECT_TITLEBAR:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) {
if(window->wl_shell_surface) {
wl_shell_surface_move(window->wl_shell_surface, ctx->wl_seat, serial);
window->flush_pending = true;
}
}
break;
case OBJECT_BUTTON_CLOSE:
case OBJECT_BORDER_TOP:
case OBJECT_BORDER_BOTTOM:
case OBJECT_BORDER_LEFT:
case OBJECT_BORDER_RIGHT:
case OBJECT_WINDOW:
break;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void wl_shell_handle_ping(void * data, struct wl_shell_surface * shell_surface, uint32_t serial)
{
return wl_shell_surface_pong(shell_surface, serial);
}
static void wl_shell_handle_configure(void * data, struct wl_shell_surface * shell_surface, uint32_t edges,
int32_t width, int32_t height)
{
struct window * window = (struct window *)data;
LV_UNUSED(edges);
if((width <= 0) || (height <= 0)) {
return;
}
else if((width != window->width) || (height != window->height)) {
window->resize_width = width;
window->resize_height = height;
window->resize_pending = true;
}
}
#endif /* LV_WAYLAND_WL_SHELL */
+468
View File
@@ -0,0 +1,468 @@
/**
* @file lv_wl_shm.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_USE_WAYLAND
#include "lv_wayland_private.h"
#include <string.h>
#include <src/display/lv_display.h>
#include <src/drivers/wayland/lv_wayland_smm.h>
#include <src/misc/lv_types.h>
#include <wayland-cursor.h>
/*********************
* DEFINES
*********************/
#define SHM_FORMAT_UNKNOWN 0xFFFFFF
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/*
* shm_format
* @description called by the compositor to advertise the supported
* color formats for SHM buffers, there is a call per supported format
*/
static void shm_format(void * data, struct wl_shm * wl_shm, uint32_t format);
static void handle_wl_buffer_release(void * data, struct wl_buffer * wl_buffer);
static bool sme_new_pool(void * ctx, smm_pool_t * pool);
static void sme_expand_pool(void * ctx, smm_pool_t * pool);
static void sme_free_pool(void * ctx, smm_pool_t * pool);
static bool sme_new_buffer(void * ctx, smm_buffer_t * buf);
static bool sme_init_buffer(void * ctx, smm_buffer_t * buf);
static void sme_free_buffer(void * ctx, smm_buffer_t * buf);
/**********************
* STATIC VARIABLES
**********************/
static const struct smm_events sme_events = {NULL, sme_new_pool, sme_expand_pool, sme_free_pool,
sme_new_buffer, sme_init_buffer, sme_free_buffer
};
static const struct wl_shm_listener shm_listener = {.format = shm_format};
static const struct wl_buffer_listener wl_buffer_listener = {
.release = handle_wl_buffer_release,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* PRIVATE FUNCTIONS
**********************/
void lv_wayland_shm_initalize_context(shm_ctx_t * context)
{
memset(context, 0, sizeof(*context));
context->format = SHM_FORMAT_UNKNOWN;
smm_init(&sme_events);
smm_setctx(context);
}
void lv_wayland_shm_set_interface(shm_ctx_t * context, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version)
{
LV_UNUSED(version);
LV_UNUSED(interface);
context->handler = wl_registry_bind(registry, name, &wl_shm_interface, 1);
wl_shm_add_listener(context->handler, &shm_listener, context);
}
lv_result_t lv_wayland_shm_is_ready(shm_ctx_t * context)
{
return (context->handler && context->format != SHM_FORMAT_UNKNOWN) ? LV_RESULT_OK : LV_RESULT_INVALID;
}
/* TODO: Move all cursor functions to a lv_wl_cursor file*/
struct wl_cursor_theme * lv_wayland_shm_load_cursor_theme(shm_ctx_t * context)
{
return wl_cursor_theme_load(NULL, 32, context->handler);
}
void lv_wayland_shm_deinit(shm_ctx_t * context)
{
smm_deinit();
wl_shm_destroy(context->handler);
}
struct graphic_object * lv_wayland_shm_on_graphical_object_creation(shm_ctx_t * context, struct graphic_object * obj)
{
LV_UNUSED(context);
obj->pending_buffer = NULL;
obj->buffer_group = smm_create();
if(obj->buffer_group == NULL) {
LV_LOG_ERROR("Failed to create buffer group for graphic object");
lv_free(obj);
return NULL;
}
SMM_TAG(obj->buffer_group, TAG_LOCAL, obj);
return obj;
}
void lv_wayland_shm_on_graphical_object_destruction(shm_ctx_t * context, struct graphic_object * obj)
{
LV_UNUSED(context);
smm_destroy(obj->buffer_group);
}
lv_result_t lv_wayland_shm_resize_window(shm_ctx_t * context, struct window * window, int32_t width, int32_t height)
{
const uint8_t bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
/* Update size for newly allocated buffers */
smm_resize(window->body->buffer_group, ((width * bpp) * height) * 2);
window->body->width = width;
window->body->height = height;
/* Pre-allocate two buffers for the window body here */
struct smm_buffer_t * body_buf1 = smm_acquire(window->body->buffer_group);
struct smm_buffer_t * body_buf2 = smm_acquire(window->body->buffer_group);
if(smm_map(body_buf2) == NULL) {
LV_LOG_ERROR("Cannot pre-allocate backing buffers for window body");
wl_surface_destroy(window->body->surface);
return LV_RESULT_INVALID;
}
/* Moves the buffers to the the unused list of the group */
smm_release(body_buf1);
smm_release(body_buf2);
LV_LOG_TRACE("resize window:%dx%d body:%dx%d frame: %d", window->width, window->height, window->body->width,
window->body->height, window->frame_counter);
width = window->body->width;
height = window->body->height;
if(window->lv_disp != NULL) {
/* Resize draw buffer */
const uint32_t stride = lv_draw_buf_width_to_stride(width, lv_display_get_color_format(window->lv_disp));
context->lv_draw_buf = lv_draw_buf_reshape(context->lv_draw_buf, lv_display_get_color_format(window->lv_disp),
width, height / LVGL_DRAW_BUFFER_DIV, stride);
}
return LV_RESULT_OK;
}
lv_result_t lv_wayland_shm_create_draw_buffers(shm_ctx_t * context, struct window * window)
{
const uint32_t stride = lv_draw_buf_width_to_stride(window->width, lv_display_get_color_format(window->lv_disp));
context->lv_draw_buf = lv_draw_buf_create(window->width, window->height / LVGL_DRAW_BUFFER_DIV,
lv_display_get_color_format(window->lv_disp), stride);
return LV_RESULT_OK;
}
lv_result_t lv_wayland_shm_set_draw_buffers(shm_ctx_t * context, lv_display_t * display)
{
if(LV_WAYLAND_BUF_COUNT != 1) {
LV_LOG_ERROR("Wayland without dmabuf only supports 1 drawbuffer for now.");
return LV_RESULT_INVALID;
}
lv_display_set_draw_buffers(display, context->lv_draw_buf, NULL);
return LV_RESULT_OK;
}
void lv_wayland_shm_delete_draw_buffers(shm_ctx_t * context, struct window * window)
{
LV_UNUSED(window);
lv_draw_buf_destroy(context->lv_draw_buf);
}
void lv_wayland_shm_flush_partial_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p)
{
struct window * window = lv_display_get_user_data(disp);
uint32_t format = window->wl_ctx->shm_ctx.format;
smm_buffer_t * buf = window->body->pending_buffer;
int32_t src_width = lv_area_get_width(area);
int32_t src_height = lv_area_get_height(area);
uint8_t bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
lv_display_rotation_t rot = lv_display_get_rotation(disp);
int32_t w = lv_display_get_horizontal_resolution(disp);
int32_t h = lv_display_get_vertical_resolution(disp);
/* TODO actually test what happens if the rotation is 90 or 270 or 180 ? */
int32_t hres = (rot == LV_DISPLAY_ROTATION_0) ? w : h;
int32_t vres = (rot == LV_DISPLAY_ROTATION_0) ? h : w;
/* If window has been / is being closed, or is not visible, skip flush */
if(window->closed || window->shall_close) {
goto skip;
}
/* Skip if the area is out the screen */
else if((area->x2 < 0) || (area->y2 < 0) || (area->x1 > hres - 1) || (area->y1 > vres - 1)) {
goto skip;
}
/* Acquire and map a buffer to attach/commit to surface */
if(buf == NULL) {
buf = smm_acquire(window->body->buffer_group);
if(buf == NULL) {
LV_LOG_ERROR("cannot acquire a window body buffer");
goto skip;
}
window->body->pending_buffer = buf;
SMM_TAG(buf, TAG_BUFFER_DAMAGE, window->dmg_cache.cache + window->dmg_cache.end);
}
void * buf_base = smm_map(buf);
if(buf_base == NULL) {
LV_LOG_ERROR("cannot map in window body buffer");
goto skip;
}
/* Modify specified area in buffer */
for(int32_t y = 0; y < src_height; ++y) {
if(format == WL_SHM_FORMAT_ARGB8888) {
for(int32_t x = 0; x < src_width; ++x) {
lv_color_premultiply((lv_color32_t *)color_p + x);
}
}
memcpy(((char *)buf_base) + ((((area->y1 + y) * hres) + area->x1) * bpp), color_p, src_width * bpp);
color_p += src_width * bpp;
}
/* Mark surface damage */
wl_surface_damage(window->body->surface, area->x1, area->y1, src_width, src_height);
lv_wayland_cache_add_area(window, buf, area);
if(lv_display_flush_is_last(disp)) {
/* Finally, attach buffer and commit to surface */
struct wl_buffer * wl_buf = SMM_BUFFER_PROPERTIES(buf)->tag[TAG_LOCAL];
wl_surface_attach(window->body->surface, wl_buf, 0, 0);
wl_surface_commit(window->body->surface);
window->body->pending_buffer = NULL;
struct wl_callback * cb = wl_surface_frame(window->body->surface);
wl_callback_add_listener(cb, lv_wayland_window_get_wl_surface_frame_listener(), window->body);
LV_LOG_TRACE("last flush frame: %d", window->frame_counter);
window->flush_pending = true;
/* Return early here, the lv_display_flush_ready will get called in the frame_listener callback */
return;
}
lv_display_flush_ready(disp);
return;
skip:
if(buf != NULL) {
/* Cleanup any intermediate state (in the event that this flush being
* skipped is in the middle of a flush sequence)
*/
lv_wayland_cache_clear(window);
SMM_TAG(buf, TAG_BUFFER_DAMAGE, NULL);
smm_release(buf);
window->body->pending_buffer = NULL;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void shm_format(void * data, struct wl_shm * wl_shm, uint32_t format)
{
shm_ctx_t * shm_ctx = (shm_ctx_t *)data;
LV_UNUSED(wl_shm);
LV_LOG_TRACE("Supported color space fourcc.h code: %08X", format);
if(LV_COLOR_DEPTH == 32 && format == WL_SHM_FORMAT_ARGB8888) {
LV_LOG_TRACE("Found WL_SHM_FORMAT_ARGB8888");
/* Wayland compositors MUST support ARGB8888 */
shm_ctx->format = format;
}
else if(LV_COLOR_DEPTH == 32 && format == WL_SHM_FORMAT_XRGB8888 && shm_ctx->format != WL_SHM_FORMAT_ARGB8888) {
LV_LOG_TRACE("Found WL_SHM_FORMAT_XRGB8888");
/* Select XRGB only if the compositor doesn't support transprancy */
shm_ctx->format = format;
}
else if(LV_COLOR_DEPTH == 16 && format == WL_SHM_FORMAT_RGB565) {
shm_ctx->format = format;
}
}
static void handle_wl_buffer_release(void * data, struct wl_buffer * wl_buffer)
{
const struct smm_buffer_properties * props;
struct graphic_object * obj;
struct window * window;
smm_buffer_t * buf;
/* window is unused when LV_LOG level is not set to trace */
LV_UNUSED(window);
LV_UNUSED(wl_buffer);
buf = (smm_buffer_t *)data;
props = SMM_BUFFER_PROPERTIES(buf);
obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
window = obj->window;
LV_LOG_TRACE("releasing buffer %p wl_buffer %p w:%d h:%d frame: %d", (smm_buffer_t *)data, (void *)wl_buffer,
obj->width, obj->height, window->frame_counter);
smm_release((smm_buffer_t *)data);
}
static bool sme_new_pool(void * ctx, smm_pool_t * pool)
{
struct wl_shm_pool * wl_pool;
shm_ctx_t * shm_ctx = ctx;
const struct smm_pool_properties * props = SMM_POOL_PROPERTIES(pool);
LV_UNUSED(ctx);
wl_pool = wl_shm_create_pool(shm_ctx->handler, props->fd, props->size);
SMM_TAG(pool, TAG_LOCAL, wl_pool);
return (wl_pool == NULL);
}
static void sme_expand_pool(void * ctx, smm_pool_t * pool)
{
const struct smm_pool_properties * props = SMM_POOL_PROPERTIES(pool);
LV_UNUSED(ctx);
wl_shm_pool_resize(props->tag[TAG_LOCAL], props->size);
}
static void sme_free_pool(void * ctx, smm_pool_t * pool)
{
struct wl_shm_pool * wl_pool = SMM_POOL_PROPERTIES(pool)->tag[TAG_LOCAL];
LV_UNUSED(ctx);
wl_shm_pool_destroy(wl_pool);
}
static bool sme_new_buffer(void * ctx, smm_buffer_t * buf)
{
struct wl_buffer * wl_buf;
bool fail_alloc = true;
const struct smm_buffer_properties * props = SMM_BUFFER_PROPERTIES(buf);
struct wl_shm_pool * wl_pool = SMM_POOL_PROPERTIES(props->pool)->tag[TAG_LOCAL];
shm_ctx_t * shm_ctx = (shm_ctx_t *)ctx;
struct graphic_object * obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
uint8_t bpp;
LV_LOG_TRACE("create new buffer of width %d height %d", obj->width, obj->height);
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
wl_buf =
wl_shm_pool_create_buffer(wl_pool, props->offset, obj->width, obj->height, obj->width * bpp, shm_ctx->format);
if(wl_buf != NULL) {
wl_buffer_add_listener(wl_buf, &wl_buffer_listener, buf);
SMM_TAG(buf, TAG_LOCAL, wl_buf);
SMM_TAG(buf, TAG_BUFFER_DAMAGE, NULL);
fail_alloc = false;
}
return fail_alloc;
}
static bool sme_init_buffer(void * ctx, smm_buffer_t * buf)
{
smm_buffer_t * src;
void * src_base;
bool fail_init = true;
bool dmg_missing = false;
void * buf_base = smm_map(buf);
const struct smm_buffer_properties * props = SMM_BUFFER_PROPERTIES(buf);
struct graphic_object * obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
uint8_t bpp;
LV_UNUSED(ctx);
if(buf_base == NULL) {
LV_LOG_ERROR("cannot map in buffer to initialize");
goto done;
}
/* Determine if all subsequent buffers damage is recorded */
for(src = smm_next(buf); src != NULL; src = smm_next(src)) {
if(SMM_BUFFER_PROPERTIES(src)->tag[TAG_BUFFER_DAMAGE] == NULL) {
dmg_missing = true;
break;
}
}
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
if((smm_next(buf) == NULL) || dmg_missing) {
/* Missing subsequent buffer damage, initialize by copying the most
* recently acquired buffers data
*/
src = smm_latest(props->group);
if((src != NULL) && (src != buf)) {
/* Map and copy latest buffer data */
src_base = smm_map(src);
if(src_base == NULL) {
LV_LOG_ERROR("cannot map most recent buffer to copy");
goto done;
}
memcpy(buf_base, src_base, (obj->width * bpp) * obj->height);
}
}
else {
/* All subsequent buffers damage is recorded, initialize by applying
* their damage to this buffer
*/
for(src = smm_next(buf); src != NULL; src = smm_next(src)) {
src_base = smm_map(src);
if(src_base == NULL) {
LV_LOG_ERROR("cannot map source buffer to copy from");
goto done;
}
lv_wayland_cache_apply_areas(obj->window, buf_base, src_base, src);
}
/* Purge out-of-date cached damage (up to and including next buffer) */
src = smm_next(buf);
if(src == NULL) {
lv_wayland_cache_purge(obj->window, src);
}
}
fail_init = false;
done:
return fail_init;
}
static void sme_free_buffer(void * ctx, smm_buffer_t * buf)
{
struct wl_buffer * wl_buf = SMM_BUFFER_PROPERTIES(buf)->tag[TAG_LOCAL];
LV_UNUSED(ctx);
wl_buffer_destroy(wl_buf);
}
#endif /* LV_USE_WAYLAND */
+275
View File
@@ -0,0 +1,275 @@
/**
* @file lv_wl_touch.c
*
*/
#include "lv_wl_touch.h"
#if LV_USE_WAYLAND && LV_USE_GESTURE_RECOGNITION
#include "lv_wayland_private.h"
#include <wayland-client-protocol.h>
#include <wayland-cursor.h>
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void _lv_wayland_touch_read(lv_indev_t * drv, lv_indev_data_t * data);
static void touch_handle_down(void * data, struct wl_touch * wl_touch, uint32_t serial, uint32_t time,
struct wl_surface * surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
static void touch_handle_up(void * data, struct wl_touch * wl_touch, uint32_t serial, uint32_t time, int32_t id);
static void touch_handle_motion(void * data, struct wl_touch * wl_touch, uint32_t time, int32_t id, wl_fixed_t x_w,
wl_fixed_t y_w);
static void touch_handle_frame(void * data, struct wl_touch * wl_touch);
static void touch_handle_cancel(void * data, struct wl_touch * wl_touch);
/**********************
* STATIC VARIABLES
**********************/
static const struct wl_touch_listener touch_listener = {
.down = touch_handle_down,
.up = touch_handle_up,
.motion = touch_handle_motion,
.frame = touch_handle_frame,
.cancel = touch_handle_cancel,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_indev_t * lv_wayland_touch_create(void)
{
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, _lv_wayland_touch_read);
return indev;
}
lv_indev_t * lv_wayland_get_touchscreen(lv_display_t * display)
{
struct window * window = lv_display_get_user_data(display);
if(!window) {
return NULL;
}
return window->lv_indev_touch;
}
/**********************
* PRIVATE FUNCTIONS
**********************/
const struct wl_touch_listener * lv_wayland_touch_get_listener(void)
{
return &touch_listener;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _lv_wayland_touch_read(lv_indev_t * drv, lv_indev_data_t * data)
{
struct window * window = lv_display_get_user_data(lv_indev_get_display(drv));
if(!window || window->closed) {
return;
}
/* Collect touches if there are any - send them to the gesture recognizer */
lv_indev_gesture_recognizers_update(drv, &window->body->input.touches[0], window->body->input.touch_event_cnt);
LV_LOG_TRACE("collected touch events: %d", window->body->input.touch_event_cnt);
window->body->input.touch_event_cnt = 0;
/* Set the gesture information, before returning to LVGL */
lv_indev_gesture_recognizers_set_data(drv, data);
}
static void touch_handle_down(void * data, struct wl_touch * wl_touch, uint32_t serial, uint32_t time,
struct wl_surface * surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
{
struct lv_wayland_context * app = data;
uint8_t i;
LV_UNUSED(id);
LV_UNUSED(time);
LV_UNUSED(serial);
LV_UNUSED(wl_touch);
if(!surface) {
app->touch_obj = NULL;
return;
}
/* Create the touch down event */
app->touch_obj = wl_surface_get_user_data(surface);
i = app->touch_obj->input.touch_event_cnt;
app->touch_obj->input.touches[i].point.x = wl_fixed_to_int(x_w);
app->touch_obj->input.touches[i].point.y = wl_fixed_to_int(y_w);
app->touch_obj->input.touches[i].id = id;
app->touch_obj->input.touches[i].timestamp = time;
app->touch_obj->input.touches[i].state = LV_INDEV_STATE_PRESSED;
app->touch_obj->input.touch_event_cnt++;
#if LV_WAYLAND_WINDOW_DECORATIONS
struct window * window = app->touch_obj->window;
switch(app->touch_obj->type) {
case OBJECT_TITLEBAR:
#if LV_WAYLAND_XDG_SHELL
if(window->xdg_toplevel) {
xdg_toplevel_move(window->xdg_toplevel, app->wl_seat, serial);
window->flush_pending = true;
}
#endif
#if LV_WAYLAND_WL_SHELL
if(window->wl_shell_surface) {
wl_shell_surface_move(window->wl_shell_surface, app->wl_seat, serial);
window->flush_pending = true;
}
#endif
break;
default:
break;
}
#endif
}
static void touch_handle_up(void * data, struct wl_touch * wl_touch, uint32_t serial, uint32_t time, int32_t id)
{
struct lv_wayland_context * app = data;
uint8_t i;
LV_UNUSED(serial);
LV_UNUSED(time);
LV_UNUSED(id);
LV_UNUSED(wl_touch);
#if LV_USE_GESTURE_RECOGNITION
/* Create a released event */
i = app->touch_obj->input.touch_event_cnt;
app->touch_obj->input.touches[i].point.x = 0;
app->touch_obj->input.touches[i].point.y = 0;
app->touch_obj->input.touches[i].id = id;
app->touch_obj->input.touches[i].timestamp = time;
app->touch_obj->input.touches[i].state = LV_INDEV_STATE_RELEASED;
app->touch_obj->input.touch_event_cnt++;
#endif
#if LV_WAYLAND_WINDOW_DECORATIONS
struct window * window = app->touch_obj->window;
switch(app->touch_obj->type) {
case OBJECT_BUTTON_CLOSE:
window->shall_close = true;
break;
#if LV_WAYLAND_XDG_SHELL
case OBJECT_BUTTON_MAXIMIZE:
if(window->xdg_toplevel) {
if(window->maximized) {
xdg_toplevel_unset_maximized(window->xdg_toplevel);
}
else {
xdg_toplevel_set_maximized(window->xdg_toplevel);
}
window->maximized ^= true;
}
break;
case OBJECT_BUTTON_MINIMIZE:
if(window->xdg_toplevel) {
xdg_toplevel_set_minimized(window->xdg_toplevel);
window->flush_pending = true;
}
#endif /* LV_WAYLAND_XDG_SHELL */
default:
break;
}
#endif /* LV_WAYLAND_WINDOW_DECORATIONS */
}
static void touch_handle_motion(void * data, struct wl_touch * wl_touch, uint32_t time, int32_t id, wl_fixed_t x_w,
wl_fixed_t y_w)
{
struct lv_wayland_context * app = data;
lv_indev_touch_data_t * touch;
lv_indev_touch_data_t * cur;
uint8_t i;
LV_UNUSED(time);
LV_UNUSED(id);
LV_UNUSED(wl_touch);
/* Update the contact point of the corresponding id with the latest coordinate */
touch = &app->touch_obj->input.touches[0];
cur = NULL;
for(i = 0; i < app->touch_obj->input.touch_event_cnt; i++) {
if(touch->id == id) {
cur = touch;
}
touch++;
}
if(cur == NULL) {
i = app->touch_obj->input.touch_event_cnt;
app->touch_obj->input.touches[i].point.x = wl_fixed_to_int(x_w);
app->touch_obj->input.touches[i].point.y = wl_fixed_to_int(y_w);
app->touch_obj->input.touches[i].id = id;
app->touch_obj->input.touches[i].timestamp = time;
app->touch_obj->input.touches[i].state = LV_INDEV_STATE_PRESSED;
app->touch_obj->input.touch_event_cnt++;
}
else {
cur->point.x = wl_fixed_to_int(x_w);
cur->point.y = wl_fixed_to_int(y_w);
cur->id = id;
cur->timestamp = time;
}
}
static void touch_handle_frame(void * data, struct wl_touch * wl_touch)
{
LV_UNUSED(wl_touch);
LV_UNUSED(data);
}
static void touch_handle_cancel(void * data, struct wl_touch * wl_touch)
{
LV_UNUSED(wl_touch);
LV_UNUSED(data);
}
#endif /* LV_USE_WAYLAND && LV_USE_GESTURE_RECOGNITION */
+54
View File
@@ -0,0 +1,54 @@
/**
* @file lv_wl_touch.h
*
*/
#ifndef LV_WL_TOUCH_H
#define LV_WL_TOUCH_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../indev/lv_indev.h"
#include "../../indev/lv_indev_gesture.h"
#if LV_USE_WAYLAND && LV_USE_GESTURE_RECOGNITION
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_indev_t * lv_wayland_touch_create(void);
/**
* Get touchscreen input device for given LVGL display
* @param display LVGL display
* @return input device connected to touchscreen, or NULL on error
*/
lv_indev_t * lv_wayland_get_touchscreen(lv_display_t * display);
/**********************
* MACROS
**********************/
#endif /* LV_USE_WAYLAND */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_WL_TOUCH_H*/
+489
View File
@@ -0,0 +1,489 @@
/**
* @file lv_wl_window.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wl_window.h"
#if LV_USE_WAYLAND
#include <string.h>
#include "lv_wayland_private.h"
#include "lv_wayland_private.h"
#include "lv_wl_pointer.h"
#include "lv_wl_pointer_axis.h"
#include "lv_wl_touch.h"
#include "lv_wl_keyboard.h"
#include "../../core/lv_refr.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static struct graphic_object * create_graphic_obj(struct window * window, enum object_type type,
struct graphic_object * parent);
static void destroy_graphic_obj(struct window * window, struct graphic_object * obj);
/* Create a window
* @description Creates the graphical context for the window body, and then create a toplevel
* wayland surface and commit it to obtain an XDG configuration event
* @param width the height of the window w/decorations
* @param height the width of the window w/decorations
*/
static struct window * create_window(struct lv_wayland_context * app, int width, int height, const char * title);
/**
* The frame callback called when the compositor has finished rendering
* a frame.It increments the frame counter and sets up the callback
* for the next frame the frame counter is used to avoid needlessly
* committing frames too fast on a slow system
*
* NOTE: this function is invoked by the wayland-server library within the compositor
* the event is added to the queue, and then upon the next timer call it's
* called indirectly from _lv_wayland_handle_input (via wl_display_dispatch_queue)
* @param void data the user object defined that was tied to this event during
* the configuration of the callback
* @param struct wl_callback The callback that needs to be destroyed and re-created
* @param time Timestamp of the event (unused)
*/
static void lv_window_graphic_obj_flush_done(void * data, struct wl_callback * cb, uint32_t time);
/**********************
* STATIC VARIABLES
**********************/
static const struct wl_callback_listener wl_surface_frame_listener = {
.done = lv_window_graphic_obj_flush_done,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char * title,
lv_wayland_display_close_f_t close_cb)
{
struct window * window;
int32_t window_width;
int32_t window_height;
lv_wayland_init();
window_width = hor_res;
window_height = ver_res;
#if LV_WAYLAND_WINDOW_DECORATIONS
if(!lv_wl_ctx.opt_disable_decorations) {
window_width = hor_res + (2 * BORDER_SIZE);
window_height = ver_res + (TITLE_BAR_HEIGHT + (2 * BORDER_SIZE));
}
#endif
window = create_window(&lv_wl_ctx, window_width, window_height, title);
if(!window) {
LV_LOG_ERROR("failed to create wayland window");
return NULL;
}
window->close_cb = close_cb;
/* Initialize display driver */
window->lv_disp = lv_display_create(hor_res, ver_res);
if(window->lv_disp == NULL) {
LV_LOG_ERROR("failed to create lvgl display");
return NULL;
}
#if LV_WAYLAND_USE_DMABUF
if(lv_wayland_dmabuf_create_draw_buffers(&lv_wl_ctx.dmabuf_ctx, window) != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to create draw buffers");
return NULL;
}
#else
if(lv_wayland_shm_create_draw_buffers(&lv_wl_ctx.shm_ctx, window) != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to create window buffers");
return NULL;
}
#endif
lv_display_set_user_data(window->lv_disp, window);
lv_display_set_render_mode(window->lv_disp, LV_WAYLAND_RENDER_MODE);
lv_display_set_flush_wait_cb(window->lv_disp, lv_wayland_wait_flush_cb);
#if LV_WAYLAND_USE_DMABUF
lv_wayland_dmabuf_set_draw_buffers(&lv_wl_ctx.dmabuf_ctx, window->lv_disp);
lv_display_set_flush_cb(window->lv_disp, lv_wayland_dmabuf_flush_full_mode);
#else
lv_wayland_shm_set_draw_buffers(&lv_wl_ctx.shm_ctx, window->lv_disp);
lv_display_set_flush_cb(window->lv_disp, lv_wayland_shm_flush_partial_mode);
#endif
/* Register input */
window->lv_indev_pointer = lv_wayland_pointer_create();
lv_indev_set_display(window->lv_indev_pointer, window->lv_disp);
if(!window->lv_indev_pointer) {
LV_LOG_ERROR("failed to register pointer indev");
}
window->lv_indev_pointeraxis = lv_wayland_pointer_axis_create();
lv_indev_set_display(window->lv_indev_pointeraxis, window->lv_disp);
if(!window->lv_indev_pointeraxis) {
LV_LOG_ERROR("failed to register pointeraxis indev");
}
#if LV_USE_GESTURE_RECOGNITION
window->lv_indev_touch = lv_wayland_touch_create();
lv_indev_set_display(window->lv_indev_touch, window->lv_disp);
if(!window->lv_indev_touch) {
LV_LOG_ERROR("failed to register touch indev");
}
#endif /* END LV_USE_GESTURE_RECOGNITION */
window->lv_indev_keyboard = lv_wayland_keyboard_create();
lv_indev_set_display(window->lv_indev_keyboard, window->lv_disp);
if(!window->lv_indev_keyboard) {
LV_LOG_ERROR("failed to register keyboard indev");
}
return window->lv_disp;
}
void lv_wayland_window_close(lv_display_t * disp)
{
struct window * window = lv_display_get_user_data(disp);
if(!window || window->closed) {
return;
}
window->shall_close = true;
window->close_cb = NULL;
lv_wayland_deinit();
}
bool lv_wayland_window_is_open(lv_display_t * disp)
{
struct window * window;
bool open = false;
if(disp == NULL) {
LV_LL_READ(&lv_wl_ctx.window_ll, window) {
if(!window->closed) {
open = true;
break;
}
}
}
else {
window = lv_display_get_user_data(disp);
open = (!window->closed);
}
return open;
}
void lv_wayland_window_set_maximized(lv_display_t * disp, bool maximized)
{
struct window * window = lv_display_get_user_data(disp);
lv_result_t err = LV_RESULT_INVALID;
if(!window || window->closed) {
return;
}
if(window->maximized != maximized) {
#if LV_WAYLAND_WL_SHELL
err = lv_wayland_wl_shell_set_maximized(window, maximized);
#elif LV_WAYLAND_XDG_SHELL
err = lv_wayland_xdg_shell_set_maximized(window, maximized);
#endif
}
if(err == LV_RESULT_INVALID) {
LV_LOG_WARN("Failed to maximize wayland window");
return;
}
window->maximized = maximized;
window->flush_pending = true;
}
void lv_wayland_window_set_fullscreen(lv_display_t * disp, bool fullscreen)
{
struct window * window = lv_display_get_user_data(disp);
lv_result_t err = LV_RESULT_INVALID;
if(!window || window->closed) {
return;
}
if(window->fullscreen == fullscreen) {
return;
}
#if LV_WAYLAND_WL_SHELL
err = lv_wayland_wl_shell_set_fullscreen(window, fullscreen);
#elif LV_WAYLAND_XDG_SHELL
err = lv_wayland_xdg_shell_set_fullscreen(window, fullscreen);
#endif
if(err == LV_RESULT_INVALID) {
LV_LOG_WARN("Failed to set wayland window to fullscreen");
return;
}
window->fullscreen = fullscreen;
window->flush_pending = true;
}
/**********************
* PRIVATE FUNCTIONS
**********************/
void lv_wayland_window_draw(struct window * window, uint32_t width, uint32_t height)
{
#if LV_WAYLAND_WINDOW_DECORATIONS
if(lv_wl_ctx.opt_disable_decorations == false) {
for(size_t i = 0; i < NUM_DECORATIONS; i++) {
window->decoration[i] = create_graphic_obj(window, (FIRST_DECORATION + i), window->body);
if(!window->decoration[i]) {
LV_LOG_ERROR("Failed to create decoration %zu", i);
}
}
}
#endif
LV_LOG_TRACE("Resizing to %d %d", width, height);
/* First resize */
if(lv_wayland_window_resize(window, width, height) != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to resize window");
#if LV_WAYLAND_XDG_SHELL
lv_wayland_xdg_shell_destroy_window_toplevel(window);
#endif
}
lv_refr_now(window->lv_disp);
}
lv_result_t lv_wayland_window_resize(struct window * window, int width, int height)
{
#if LV_WAYLAND_WINDOW_DECORATIONS
if(!window->wl_ctx->opt_disable_decorations && !window->fullscreen) {
width -= (2 * BORDER_SIZE);
height -= (TITLE_BAR_HEIGHT + (2 * BORDER_SIZE));
}
#endif
#if LV_WAYLAND_USE_DMABUF
{
lv_result_t err = lv_wayland_dmabuf_resize_window(&window->wl_ctx->dmabuf_ctx, window);
if(err != LV_RESULT_OK) {
return err;
}
}
#else
{
lv_result_t err = lv_wayland_shm_resize_window(&window->wl_ctx->shm_ctx, window, width, height);
if(err != LV_RESULT_OK) {
return err;
}
}
#endif
#if LV_WAYLAND_WINDOW_DECORATIONS
if(!window->wl_ctx->opt_disable_decorations && !window->fullscreen) {
lv_wayland_window_decoration_create_all(window);
}
else if(!window->wl_ctx->opt_disable_decorations) {
/* Entering fullscreen, detach decorations to prevent xdg_wm_base error 4 */
/* requested geometry larger than the configured fullscreen state */
lv_wayland_window_decoration_detach_all(window);
}
#endif
if(window->lv_disp) {
lv_display_set_resolution(window->lv_disp, width, height);
window->body->input.pointer.x = LV_MIN((int32_t)window->body->input.pointer.x, (width - 1));
window->body->input.pointer.y = LV_MIN((int32_t)window->body->input.pointer.y, (height - 1));
}
window->width = width;
window->height = height;
return LV_RESULT_OK;
}
void lv_wayland_window_destroy(struct window * window)
{
if(!window) {
return;
}
#if LV_WAYLAND_WL_SHELL
lv_wayland_wl_shell_destroy_window(window);
#elif LV_WAYLAND_XDG_SHELL
lv_wayland_xdg_shell_destroy_window_toplevel(window);
lv_wayland_xdg_shell_destroy_window_surface(window);
#endif
#if LV_WAYLAND_WINDOW_DECORATIONS
for(size_t i = 0; i < NUM_DECORATIONS; i++) {
if(window->decoration[i]) {
destroy_graphic_obj(window, window->decoration[i]);
window->decoration[i] = NULL;
}
}
#endif
destroy_graphic_obj(window, window->body);
}
const struct wl_callback_listener * lv_wayland_window_get_wl_surface_frame_listener(void)
{
return &wl_surface_frame_listener;
}
/**********************
* STATIC FUNCTIONS
**********************/
static struct window * create_window(struct lv_wayland_context * app, int width, int height, const char * title)
{
struct window * window;
window = lv_ll_ins_tail(&app->window_ll);
LV_ASSERT_MALLOC(window);
if(!window) {
return NULL;
}
lv_memset(window, 0x00, sizeof(struct window));
window->wl_ctx = app;
// Create wayland buffer and surface
window->body = create_graphic_obj(window, OBJECT_WINDOW, NULL);
window->width = width;
window->height = height;
if(!window->body) {
LV_LOG_ERROR("cannot create window body");
goto err_free_window;
}
#if LV_WAYLAND_WL_SHELL
if(lv_wayland_wl_shell_create_window(app, window, title) != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to create wl shell window");
goto err_destroy_surface;
}
#elif LV_WAYLAND_XDG_SHELL
if(lv_wayland_xdg_shell_create_window(app, window, title) != LV_RESULT_OK) {
goto err_destroy_surface;
}
#endif
return window;
err_destroy_surface:
wl_surface_destroy(window->body->surface);
err_free_window:
lv_ll_remove(&app->window_ll, window);
lv_free(window);
return NULL;
}
static struct graphic_object * create_graphic_obj(struct window * window, enum object_type type,
struct graphic_object * parent)
{
/* For now creating a graphical object is similar enough for both shm and dmabuf
* so the heavylifting is done in this function directly but we still
* call the shm and dmabuf specific functions at the end to make sure they can add additional
* attributes if needed
*/
struct graphic_object * obj = NULL;
LV_UNUSED(parent);
obj = lv_malloc(sizeof(*obj));
LV_ASSERT_MALLOC(obj);
if(!obj) {
LV_LOG_ERROR("Failed to create graphic object");
return NULL;
}
lv_memset(obj, 0, sizeof(*obj));
obj->surface = wl_compositor_create_surface(window->wl_ctx->compositor);
if(!obj->surface) {
LV_LOG_ERROR("Failed to create surface for graphic object");
lv_free(obj);
return NULL;
}
wl_surface_set_user_data(obj->surface, obj);
obj->window = window;
obj->type = type;
#if LV_WAYLAND_USE_DMABUF
return lv_wayland_dmabuf_on_graphical_object_creation(&window->wl_ctx->dmabuf_ctx, obj);
#else
return lv_wayland_shm_on_graphical_object_creation(&window->wl_ctx->shm_ctx, obj);
#endif
}
static void destroy_graphic_obj(struct window * window, struct graphic_object * obj)
{
if(obj->subsurface) {
wl_subsurface_destroy(obj->subsurface);
}
wl_surface_destroy(obj->surface);
#if LV_WAYLAND_USE_DMABUF
lv_wayland_dmabuf_on_graphical_object_destruction(&window->wl_ctx->dmabuf_ctx, obj);
#else
lv_wayland_shm_on_graphical_object_destruction(&window->wl_ctx->shm_ctx, obj);
#endif
lv_free(obj);
}
static void lv_window_graphic_obj_flush_done(void * data, struct wl_callback * cb, uint32_t time)
{
struct graphic_object * obj;
struct window * window;
LV_UNUSED(time);
wl_callback_destroy(cb);
obj = (struct graphic_object *)data;
window = obj->window;
window->frame_counter++;
LV_LOG_TRACE("frame: %d done, new frame: %d", window->frame_counter - 1, window->frame_counter);
lv_display_flush_ready(window->lv_disp);
}
#endif /* LV_USE_WAYLAND */
+84
View File
@@ -0,0 +1,84 @@
/**
* @file lv_wl_display.h
*
*/
#ifndef LV_WL_WINDOW_H
#define LV_WL_WINDOW_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#if LV_USE_WAYLAND
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef bool (*lv_wayland_display_close_f_t)(lv_display_t * disp);
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Creates a window
* @param hor_res The width of the window in pixels
* @param ver_res The height of the window in pixels
* @param title The title of the window
* @param close_cb The callback that will be execute when the user closes the window
* @return The LVGL display associated to the window
*/
lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char * title,
lv_wayland_display_close_f_t close_cb);
/**
* Closes the window programmatically
* @param disp Reference to the LVGL display associated to the window
*/
void lv_wayland_window_close(lv_display_t * disp);
/**
* Check if the window is open
* @param disp Reference to the LVGL display associated to the window
* @return true: The window is open
*/
bool lv_wayland_window_is_open(lv_display_t * disp);
/**
* Sets the fullscreen state of the window
* @param disp Reference to the LVGL display associated to the window
* @param fullscreen If true the window enters fullscreen
*/
void lv_wayland_window_set_fullscreen(lv_display_t * disp, bool fullscreen);
/**
* Sets the maximized state of the window
* @param disp Reference to the LVGL display associated to the window
* @param fullscreen If true the window is maximized
*/
void lv_wayland_window_set_maximized(lv_display_t * disp, bool maximize);
/**********************
* MACROS
**********************/
#endif /* LV_USE_WAYLAND */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_WL_WINDOW_H*/
@@ -0,0 +1,361 @@
/**
* @file lv_wl_window_decorations.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_WAYLAND_WINDOW_DECORATIONS
#include "lv_wayland_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/*
* Fills a buffer with a color
* @description Used to draw the decorations, by writing directly to the SHM buffer,
* most wayland compositors support the ARGB8888, XRGB8888, RGB565 formats
*
* For color depths usually not natively supported by wayland i.e RGB332, Grayscale
* A conversion is performed to match the format of the SHM buffer read by the compositor.
*
* This function can also be used as a visual debugging aid to see how damage is applied
*
* @param pixels pointer to the buffer to fill
* @param lv_color_t color the color that will be used for the fill
* @param width width of the filled area
* @param height height of the filled area
*
*/
static void color_fill(void * pixels, lv_color_t color, uint32_t width, uint32_t height);
static void color_fill_XRGB8888(void * pixels, lv_color_t color, uint32_t width, uint32_t height);
static void color_fill_RGB565(void * pixels, lv_color_t color, uint32_t width, uint32_t height);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
bool lv_wayland_window_decoration_attach(struct window * window, struct graphic_object * decoration,
smm_buffer_t * decoration_buffer, struct graphic_object * parent)
{
struct wl_buffer * wl_buf = SMM_BUFFER_PROPERTIES(decoration_buffer)->tag[TAG_LOCAL];
int pos_x, pos_y;
switch(decoration->type) {
case OBJECT_TITLEBAR:
pos_x = 0;
pos_y = -TITLE_BAR_HEIGHT;
break;
case OBJECT_BUTTON_CLOSE:
pos_x = parent->width - 1 * (BUTTON_MARGIN + BUTTON_SIZE);
pos_y = -1 * (BUTTON_MARGIN + BUTTON_SIZE + (BORDER_SIZE / 2));
break;
#if LV_WAYLAND_XDG_SHELL
case OBJECT_BUTTON_MAXIMIZE:
pos_x = parent->width - 2 * (BUTTON_MARGIN + BUTTON_SIZE);
pos_y = -1 * (BUTTON_MARGIN + BUTTON_SIZE + (BORDER_SIZE / 2));
break;
case OBJECT_BUTTON_MINIMIZE:
pos_x = parent->width - 3 * (BUTTON_MARGIN + BUTTON_SIZE);
pos_y = -1 * (BUTTON_MARGIN + BUTTON_SIZE + (BORDER_SIZE / 2));
break;
#endif
case OBJECT_BORDER_TOP:
pos_x = -BORDER_SIZE;
pos_y = -(BORDER_SIZE + TITLE_BAR_HEIGHT);
break;
case OBJECT_BORDER_BOTTOM:
pos_x = -BORDER_SIZE;
pos_y = parent->height;
break;
case OBJECT_BORDER_LEFT:
pos_x = -BORDER_SIZE;
pos_y = -TITLE_BAR_HEIGHT;
break;
case OBJECT_BORDER_RIGHT:
pos_x = parent->width;
pos_y = -TITLE_BAR_HEIGHT;
break;
default:
LV_ASSERT_MSG(0, "Invalid object type");
return false;
}
/* Enable this, to make it function on weston 10.0.2 */
/* It's not elegant but it forces weston to size the surfaces before */
/* the conversion to a subsurface takes place */
/* Likely related to this issue, some patches were merged into 10.0.0 */
/* https://gitlab.freedesktop.org/wayland/weston/-/issues/446 */
/* Moreover, it crashes on GNOME */
#if 0
wl_surface_attach(decoration->surface, wl_buf, 0, 0);
wl_surface_commit(decoration->surface);
#endif
if(decoration->subsurface == NULL) {
/* Create the subsurface only once */
decoration->subsurface =
wl_subcompositor_get_subsurface(window->wl_ctx->subcompositor, decoration->surface, parent->surface);
if(!decoration->subsurface) {
LV_LOG_ERROR("cannot get subsurface for decoration");
goto err_destroy_surface;
}
}
wl_subsurface_set_position(decoration->subsurface, pos_x, pos_y);
wl_surface_attach(decoration->surface, wl_buf, 0, 0);
wl_surface_commit(decoration->surface);
return true;
err_destroy_surface:
wl_surface_destroy(decoration->surface);
decoration->surface = NULL;
return false;
}
uint32_t lv_wayland_window_decoration_create_all(struct window * window)
{
uint32_t created = 0;
for(size_t i = 0; i < NUM_DECORATIONS; i++) {
if(lv_wayland_window_decoration_create(window, window->decoration[i], window->body->width,
window->body->height)) {
created++;
continue;
}
LV_LOG_ERROR("failed to create decoration %zu", i);
}
return created;
}
void lv_wayland_window_decoration_detach_all(struct window * window)
{
for(int i = 0; i < NUM_DECORATIONS; i++) {
lv_wayland_window_decoration_detach(window, window->decoration[i]);
}
}
bool lv_wayland_window_decoration_create(struct window * window, struct graphic_object * decoration, int window_width,
int window_height)
{
smm_buffer_t * buf;
void * buf_base;
int x, y;
lv_color_t * pixel;
uint8_t bpp;
switch(decoration->type) {
case OBJECT_TITLEBAR:
decoration->width = window_width;
decoration->height = TITLE_BAR_HEIGHT;
break;
case OBJECT_BUTTON_CLOSE:
decoration->width = BUTTON_SIZE;
decoration->height = BUTTON_SIZE;
break;
#if LV_WAYLAND_XDG_SHELL
case OBJECT_BUTTON_MAXIMIZE:
decoration->width = BUTTON_SIZE;
decoration->height = BUTTON_SIZE;
break;
case OBJECT_BUTTON_MINIMIZE:
decoration->width = BUTTON_SIZE;
decoration->height = BUTTON_SIZE;
break;
#endif
case OBJECT_BORDER_TOP:
decoration->width = window_width + 2 * (BORDER_SIZE);
decoration->height = BORDER_SIZE;
break;
case OBJECT_BORDER_BOTTOM:
decoration->width = window_width + 2 * (BORDER_SIZE);
decoration->height = BORDER_SIZE;
break;
case OBJECT_BORDER_LEFT:
decoration->width = BORDER_SIZE;
decoration->height = window_height + TITLE_BAR_HEIGHT;
break;
case OBJECT_BORDER_RIGHT:
decoration->width = BORDER_SIZE;
decoration->height = window_height + TITLE_BAR_HEIGHT;
break;
default:
LV_ASSERT_MSG(0, "Invalid object type");
return false;
}
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
LV_LOG_TRACE("decoration window %dx%d", decoration->width, decoration->height);
smm_resize(decoration->buffer_group, (decoration->width * bpp) * decoration->height);
buf = smm_acquire(decoration->buffer_group);
if(buf == NULL) {
LV_LOG_ERROR("cannot allocate buffer for decoration");
return false;
}
buf_base = smm_map(buf);
if(buf_base == NULL) {
LV_LOG_ERROR("cannot map in allocated decoration buffer");
smm_release(buf);
return false;
}
switch(decoration->type) {
case OBJECT_TITLEBAR:
color_fill(buf_base, lv_color_make(0x66, 0x66, 0x66), decoration->width, decoration->height);
break;
case OBJECT_BUTTON_CLOSE:
color_fill(buf_base, lv_color_make(0xCC, 0xCC, 0xCC), decoration->width, decoration->height);
for(y = 0; y < decoration->height; y++) {
for(x = 0; x < decoration->width; x++) {
pixel = (lv_color_t *)((unsigned char *)buf_base + (y * (decoration->width * bpp)) + x * bpp);
if((x >= BUTTON_PADDING) && (x < decoration->width - BUTTON_PADDING)) {
if((x == y) || (x == decoration->width - 1 - y)) {
color_fill(pixel, lv_color_make(0x33, 0x33, 0x33), 1, 1);
}
else if((x == y - 1) || (x == decoration->width - y)) {
color_fill(pixel, lv_color_make(0x66, 0x66, 0x66), 1, 1);
}
}
}
}
break;
#if LV_WAYLAND_XDG_SHELL
case OBJECT_BUTTON_MAXIMIZE:
color_fill(buf_base, lv_color_make(0xCC, 0xCC, 0xCC), decoration->width, decoration->height);
for(y = 0; y < decoration->height; y++) {
for(x = 0; x < decoration->width; x++) {
pixel = (lv_color_t *)((unsigned char *)buf_base + (y * (decoration->width * bpp)) + x * bpp);
if(((x == BUTTON_PADDING) && (y >= BUTTON_PADDING) && (y < decoration->height - BUTTON_PADDING)) ||
((x == (decoration->width - BUTTON_PADDING)) && (y >= BUTTON_PADDING) &&
(y <= decoration->height - BUTTON_PADDING)) ||
((y == BUTTON_PADDING) && (x >= BUTTON_PADDING) && (x < decoration->width - BUTTON_PADDING)) ||
((y == (BUTTON_PADDING + 1)) && (x >= BUTTON_PADDING) &&
(x < decoration->width - BUTTON_PADDING)) ||
((y == (decoration->height - BUTTON_PADDING)) && (x >= BUTTON_PADDING) &&
(x < decoration->width - BUTTON_PADDING))) {
color_fill(pixel, lv_color_make(0x33, 0x33, 0x33), 1, 1);
}
}
}
break;
case OBJECT_BUTTON_MINIMIZE:
color_fill(buf_base, lv_color_make(0xCC, 0xCC, 0xCC), decoration->width, decoration->height);
for(y = 0; y < decoration->height; y++) {
for(x = 0; x < decoration->width; x++) {
pixel = (lv_color_t *)((unsigned char *)buf_base + (y * (decoration->width * bpp)) + x * bpp);
if((x >= BUTTON_PADDING) && (x < decoration->width - BUTTON_PADDING) &&
(y > decoration->height - (2 * BUTTON_PADDING)) && (y < decoration->height - BUTTON_PADDING)) {
color_fill(pixel, lv_color_make(0x33, 0x33, 0x33), 1, 1);
}
}
}
break;
#endif
case OBJECT_BORDER_TOP:
/* fallthrough */
case OBJECT_BORDER_BOTTOM:
/* fallthrough */
case OBJECT_BORDER_LEFT:
/* fallthrough */
case OBJECT_BORDER_RIGHT:
color_fill(buf_base, lv_color_make(0x66, 0x66, 0x66), decoration->width, decoration->height);
break;
default:
LV_ASSERT_MSG(0, "Invalid object type");
return false;
}
return lv_wayland_window_decoration_attach(window, decoration, buf, window->body);
}
void lv_wayland_window_decoration_detach(struct window * window, struct graphic_object * decoration)
{
LV_UNUSED(window);
if(decoration->subsurface) {
wl_subsurface_destroy(decoration->subsurface);
decoration->subsurface = NULL;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static void color_fill(void * pixels, lv_color_t color, uint32_t width, uint32_t height)
{
switch(lv_wl_ctx.shm_ctx.format) {
case WL_SHM_FORMAT_ARGB8888:
color_fill_XRGB8888(pixels, color, width, height);
break;
case WL_SHM_FORMAT_RGB565:
color_fill_RGB565(pixels, color, width, height);
break;
default:
LV_ASSERT_MSG(0, "Unsupported WL_SHM_FORMAT");
break;
}
}
static void color_fill_XRGB8888(void * pixels, lv_color_t color, uint32_t width, uint32_t height)
{
unsigned char * buf = pixels;
unsigned char * buf_end;
buf_end = (unsigned char *)((uint32_t *)buf + width * height);
while(buf < buf_end) {
*(buf++) = color.blue;
*(buf++) = color.green;
*(buf++) = color.red;
*(buf++) = 0xFF;
}
}
static void color_fill_RGB565(void * pixels, lv_color_t color, uint32_t width, uint32_t height)
{
uint16_t * buf = pixels;
uint16_t * buf_end;
buf_end = (uint16_t *)buf + width * height;
while(buf < buf_end) {
*(buf++) = lv_color_to_u16(color);
}
}
#endif /* LV_WAYLAND_WINDOW_DECORATIONS */
+467
View File
@@ -0,0 +1,467 @@
/**
* @file lv_wl_xdg_shell.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_USE_WAYLAND
/*
* LV_WAYLAND_XDG_SHELL is automatically defined if LV_WAYLAND_WL_SHELL is not set
* inside lv_wayland_private.h so we need include this header file before checking
* for LV_WAYLAND_XDG_SHELL
*/
#include "lv_wayland_private.h"
#if LV_WAYLAND_XDG_SHELL
#include <linux/input-event-codes.h>
#include "wayland_xdg_shell.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void xdg_surface_handle_configure(void * data, struct xdg_surface * xdg_surface, uint32_t serial);
static void xdg_toplevel_handle_configure(void * data, struct xdg_toplevel * xdg_toplevel, int32_t width,
int32_t height, struct wl_array * states);
static void xdg_toplevel_handle_close(void * data, struct xdg_toplevel * xdg_toplevel);
static void xdg_wm_base_ping(void * data, struct xdg_wm_base * xdg_wm_base, uint32_t serial);
/**********************
* STATIC VARIABLES
**********************/
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_handle_configure,
};
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_handle_configure,
.close = xdg_toplevel_handle_close,
};
static const struct xdg_wm_base_listener xdg_wm_base_listener = {.ping = xdg_wm_base_ping};
static bool is_window_configured = false;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* PRIVATE FUNCTIONS
**********************/
/**********************
* Shell
**********************/
void lv_wayland_xdg_shell_deinit(void)
{
if(lv_wl_ctx.xdg_wm) {
xdg_wm_base_destroy(lv_wl_ctx.xdg_wm);
}
}
/**********************
* Listeners
**********************/
const struct xdg_wm_base_listener * lv_wayland_xdg_shell_get_wm_base_listener(void)
{
return &xdg_wm_base_listener;
}
const struct xdg_surface_listener * lv_wayland_xdg_shell_get_surface_listener(void)
{
return &xdg_surface_listener;
}
const struct xdg_toplevel_listener * lv_wayland_xdg_shell_get_toplevel_listener(void)
{
return &xdg_toplevel_listener;
}
/**********************
* Shell Window
**********************/
lv_result_t lv_wayland_xdg_shell_set_fullscreen(struct window * window, bool fullscreen)
{
if(!window->xdg_toplevel) {
return LV_RESULT_INVALID;
}
if(fullscreen) {
xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
}
else {
xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
}
return LV_RESULT_OK;
}
lv_result_t lv_wayland_xdg_shell_set_maximized(struct window * window, bool maximized)
{
if(!window->xdg_toplevel) {
return LV_RESULT_INVALID;
}
if(maximized) {
xdg_toplevel_set_maximized(window->xdg_toplevel);
}
else {
xdg_toplevel_unset_maximized(window->xdg_toplevel);
}
return LV_RESULT_OK;
}
lv_result_t lv_wayland_xdg_shell_set_minimized(struct window * window)
{
if(!window->xdg_toplevel) {
return LV_RESULT_INVALID;
}
xdg_toplevel_set_minimized(window->xdg_toplevel);
return LV_RESULT_OK;
}
lv_result_t lv_wayland_xdg_shell_create_window(struct lv_wayland_context * app, struct window * window,
const char * title)
{
if(!app->xdg_wm) {
return LV_RESULT_INVALID;
}
window->xdg_surface = xdg_wm_base_get_xdg_surface(app->xdg_wm, window->body->surface);
if(!window->xdg_surface) {
LV_LOG_ERROR("cannot create XDG surface");
return LV_RESULT_INVALID;
}
xdg_surface_add_listener(window->xdg_surface, lv_wayland_xdg_shell_get_surface_listener(), window);
window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
if(!window->xdg_toplevel) {
xdg_surface_destroy(window->xdg_surface);
LV_LOG_ERROR("cannot get XDG toplevel surface");
return LV_RESULT_INVALID;
}
xdg_toplevel_add_listener(window->xdg_toplevel, lv_wayland_xdg_shell_get_toplevel_listener(), window);
xdg_toplevel_set_title(window->xdg_toplevel, title);
xdg_toplevel_set_app_id(window->xdg_toplevel, title);
// XDG surfaces need to be configured before a buffer can be attached.
// An (XDG) surface commit (without an attached buffer) triggers this
// configure event
is_window_configured = false;
wl_surface_commit(window->body->surface);
wl_display_roundtrip(lv_wl_ctx.display);
LV_ASSERT_MSG(is_window_configured, "Failed to receive the xdg_surface configuration event");
return LV_RESULT_OK;
}
lv_result_t lv_wayland_xdg_shell_destroy_window_surface(struct window * window)
{
if(!window->xdg_surface) {
return LV_RESULT_INVALID;
}
xdg_surface_destroy(window->xdg_surface);
return LV_RESULT_OK;
}
lv_result_t lv_wayland_xdg_shell_destroy_window_toplevel(struct window * window)
{
if(!window->xdg_toplevel) {
return LV_RESULT_INVALID;
}
xdg_toplevel_destroy(window->xdg_toplevel);
return LV_RESULT_OK;
}
/**********************
* Shell Input
**********************/
void lv_wayland_xdg_shell_handle_pointer_event(struct lv_wayland_context * app, uint32_t serial, uint32_t button,
uint32_t state)
{
struct window * window = app->pointer_obj->window;
int pos_x = (int)app->pointer_obj->input.pointer.x;
int pos_y = (int)app->pointer_obj->input.pointer.y;
switch(app->pointer_obj->type) {
case OBJECT_TITLEBAR:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) {
if(window->xdg_toplevel) {
xdg_toplevel_move(window->xdg_toplevel, app->wl_seat, serial);
window->flush_pending = true;
}
}
break;
case OBJECT_BUTTON_MAXIMIZE:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_RELEASED)) {
if(lv_wayland_xdg_shell_set_maximized(window, !window->maximized) == LV_RESULT_OK) {
window->maximized = !window->maximized;
window->flush_pending = true;
}
}
break;
case OBJECT_BUTTON_MINIMIZE:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_RELEASED)) {
if(lv_wayland_xdg_shell_set_minimized(window) == LV_RESULT_OK) {
window->flush_pending = true;
}
}
break;
case OBJECT_BORDER_TOP:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) {
if(window->xdg_toplevel && !window->maximized) {
uint32_t edge;
if(pos_x < (BORDER_SIZE * 5)) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
}
else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
}
else {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
}
xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge);
window->flush_pending = true;
}
}
break;
case OBJECT_BORDER_BOTTOM:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) {
if(window->xdg_toplevel && !window->maximized) {
uint32_t edge;
if(pos_x < (BORDER_SIZE * 5)) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
}
else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
}
else {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
}
xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge);
window->flush_pending = true;
}
}
break;
case OBJECT_BORDER_LEFT:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) {
if(window->xdg_toplevel && !window->maximized) {
uint32_t edge;
if(pos_y < (BORDER_SIZE * 5)) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
}
else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
}
else {
edge = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
}
xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge);
window->flush_pending = true;
}
}
break;
case OBJECT_BORDER_RIGHT:
if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) {
if(window->xdg_toplevel && !window->maximized) {
uint32_t edge;
if(pos_y < (BORDER_SIZE * 5)) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
}
else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
}
else {
edge = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
}
xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge);
window->flush_pending = true;
}
}
break;
case OBJECT_BUTTON_CLOSE:
case OBJECT_WINDOW:
/* These events are handled in the main pointer callback */
break;
}
}
const char * lv_wayland_xdg_shell_get_cursor_name(const struct lv_wayland_context * app)
{
if(!app->pointer_obj->window->xdg_toplevel || app->opt_disable_decorations) {
return LV_WAYLAND_DEFAULT_CURSOR_NAME;
}
int pos_x = (int)app->pointer_obj->input.pointer.x;
int pos_y = (int)app->pointer_obj->input.pointer.y;
struct window * window = app->pointer_obj->window;
switch(app->pointer_obj->type) {
case OBJECT_BORDER_TOP:
if(window->maximized) {
// do nothing
}
else if(pos_x < (BORDER_SIZE * 5)) {
return "top_left_corner";
}
else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) {
return "top_right_corner";
}
else {
return "top_side";
}
break;
case OBJECT_BORDER_BOTTOM:
if(window->maximized) {
// do nothing
}
else if(pos_x < (BORDER_SIZE * 5)) {
return "bottom_left_corner";
}
else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) {
return "bottom_right_corner";
}
else {
return "bottom_side";
}
break;
case OBJECT_BORDER_LEFT:
if(window->maximized) {
// do nothing
}
else if(pos_y < (BORDER_SIZE * 5)) {
return "top_left_corner";
}
else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) {
return "bottom_left_corner";
}
else {
return "left_side";
}
break;
case OBJECT_BORDER_RIGHT:
if(window->maximized) {
// do nothing
}
else if(pos_y < (BORDER_SIZE * 5)) {
return "top_right_corner";
}
else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) {
return "bottom_right_corner";
}
else {
return "right_side";
}
break;
default:
break;
}
return LV_WAYLAND_DEFAULT_CURSOR_NAME;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void xdg_surface_handle_configure(void * data, struct xdg_surface * xdg_surface, uint32_t serial)
{
struct window * window = (struct window *)data;
xdg_surface_ack_configure(xdg_surface, serial);
if(!is_window_configured) {
/* This branch is executed at launch */
if(!window->resize_pending) {
/* Use the size passed to the create_window function */
lv_wayland_window_draw(window, window->width, window->height);
}
else {
/* Handle early maximization or fullscreen, */
/* by using the size communicated by the compositor */
/* when the initial xdg configure event arrives */
lv_wayland_window_draw(window, window->resize_width, window->resize_height);
window->width = window->resize_width;
window->height = window->resize_height;
window->resize_pending = false;
}
}
is_window_configured = true;
}
static void xdg_toplevel_handle_configure(void * data, struct xdg_toplevel * xdg_toplevel, int32_t width,
int32_t height, struct wl_array * states)
{
struct window * window = (struct window *)data;
LV_UNUSED(xdg_toplevel);
LV_UNUSED(states);
LV_LOG_TRACE("w:%d h:%d", width, height);
LV_LOG_TRACE("current body w:%d h:%d", window->body->width, window->body->height);
LV_LOG_TRACE("window w:%d h:%d", window->width, window->height);
if((width <= 0) || (height <= 0)) {
LV_LOG_TRACE("will not resize to w:%d h:%d", width, height);
return;
}
if((width != window->width) || (height != window->height)) {
window->resize_width = width;
window->resize_height = height;
window->resize_pending = true;
LV_LOG_TRACE("resize_pending is set, will resize to w:%d h:%d", width, height);
}
else {
LV_LOG_TRACE("resize_pending not set w:%d h:%d", width, height);
}
}
static void xdg_toplevel_handle_close(void * data, struct xdg_toplevel * xdg_toplevel)
{
struct window * window = (struct window *)data;
window->shall_close = true;
LV_UNUSED(xdg_toplevel);
}
static void xdg_wm_base_ping(void * data, struct xdg_wm_base * xdg_wm_base, uint32_t serial)
{
LV_UNUSED(data);
xdg_wm_base_pong(xdg_wm_base, serial);
return;
}
#endif /* LV_WAYLAND_XDG_SHELL */
#endif /* LV_USE_WAYLAND */
+34 -2
View File
@@ -3825,18 +3825,44 @@
#endif
#endif
#if LV_USE_WAYLAND
#ifndef LV_WAYLAND_BUF_COUNT
#ifdef LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_WAYLAND_BUF_COUNT
#define LV_WAYLAND_BUF_COUNT CONFIG_LV_WAYLAND_BUF_COUNT
#else
#define LV_WAYLAND_BUF_COUNT 0
#endif
#else
#define LV_WAYLAND_BUF_COUNT 1 /**< Use 1 for single buffer with partial render mode or 2 for double buffer with full render mode*/
#endif
#endif
#ifndef LV_WAYLAND_USE_DMABUF
#ifdef CONFIG_LV_WAYLAND_USE_DMABUF
#define LV_WAYLAND_USE_DMABUF CONFIG_LV_WAYLAND_USE_DMABUF
#else
#define LV_WAYLAND_USE_DMABUF 0 /**< Use DMA buffers for frame buffers. Requires LV_DRAW_USE_G2D */
#endif
#endif
#ifndef LV_WAYLAND_RENDER_MODE
#ifdef CONFIG_LV_WAYLAND_RENDER_MODE
#define LV_WAYLAND_RENDER_MODE CONFIG_LV_WAYLAND_RENDER_MODE
#else
#define LV_WAYLAND_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL /**< DMABUF supports LV_DISPLAY_RENDER_MODE_FULL and LV_DISPLAY_RENDER_MODE_DIRECT*/
#endif
#endif
/**< When LV_WAYLAND_USE_DMABUF is disabled, only LV_DISPLAY_RENDER_MODE_PARTIAL is supported*/
#ifndef LV_WAYLAND_WINDOW_DECORATIONS
#ifdef CONFIG_LV_WAYLAND_WINDOW_DECORATIONS
#define LV_WAYLAND_WINDOW_DECORATIONS CONFIG_LV_WAYLAND_WINDOW_DECORATIONS
#else
#define LV_WAYLAND_WINDOW_DECORATIONS 0 /**< Draw client side window decorations only necessary on Mutter/GNOME */
#define LV_WAYLAND_WINDOW_DECORATIONS 0 /**< Draw client side window decorations only necessary on Mutter/GNOME. Not supported using DMABUF*/
#endif
#endif
#ifndef LV_WAYLAND_WL_SHELL
#ifdef CONFIG_LV_WAYLAND_WL_SHELL
#define LV_WAYLAND_WL_SHELL CONFIG_LV_WAYLAND_WL_SHELL
#else
#define LV_WAYLAND_WL_SHELL 0 /**< Use the legacy wl_shell protocol instead of the default XDG shell */
#define LV_WAYLAND_WL_SHELL 0 /**< Use the legacy wl_shell protocol instead of the default XDG shell*/
#endif
#endif
#endif
@@ -4478,6 +4504,12 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#define LV_LOG_TRACE_ANIM 0
#endif /*LV_USE_LOG*/
#if LV_USE_WAYLAND == 0
#define LV_WAYLAND_USE_DMABUF 0
#define LV_WAYLAND_WINDOW_DECORATIONS 0
#define LV_WAYLAND_WL_SHELL 0
#endif /* LV_USE_WAYLAND */
#if LV_USE_SYSMON == 0
#define LV_USE_PERF_MONITOR 0
#define LV_USE_MEM_MONITOR 0
+12
View File
@@ -271,6 +271,18 @@ extern "C" {
# define CONFIG_LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_FULL
#endif
/*------------------
* WAYLAND
*-----------------*/
#ifdef CONFIG_LV_WAYLAND_RENDER_MODE_PARTIAL
# define CONFIG_LV_WAYLAND_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL
#elif defined(CONFIG_LV_WAYLAND_RENDER_MODE_DIRECT)
# define CONFIG_LV_WAYLAND_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT
#elif defined(CONFIG_LV_WAYLAND_RENDER_MODE_FULL)
# define CONFIG_LV_WAYLAND_RENDER_MODE_FULL LV_DISPLAY_RENDER_MODE_FULL
#endif
/*------------------
* LINUX FBDEV
*-----------------*/
+1
View File
@@ -454,6 +454,7 @@ endif()
if(WIN32)
add_definitions(-DLV_USE_LINUX_FBDEV=0)
add_definitions(-DLV_USE_WINDOWS=1)
add_definitions(-DLV_USE_WAYLAND=0)
add_definitions(-DLV_USE_OS=LV_OS_WINDOWS)
endif()