mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-10 04:37:55 +08:00
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:
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
**********************/
|
||||
|
||||
@@ -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
|
||||
**********************/
|
||||
|
||||
+264
-2736
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
@@ -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*/
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
@@ -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, ¶ms_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 */
|
||||
@@ -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 */
|
||||
@@ -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*/
|
||||
@@ -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 */
|
||||
@@ -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*/
|
||||
@@ -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 */
|
||||
@@ -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*/
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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*/
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
*-----------------*/
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user