feat(wayland): rewrite driver (#9195)

Co-authored-by: ychsiao168 <ychsiao168@pm.me>
This commit is contained in:
André Costa
2025-12-01 18:02:27 +01:00
committed by GitHub
parent 5cf3c8e887
commit 6cd095724e
31 changed files with 2295 additions and 4358 deletions
+4 -28
View File
@@ -1896,35 +1896,11 @@ menu "LVGL configuration"
config LV_USE_WAYLAND
bool "Use the wayland client to open a window and handle inputs on Linux or BSD"
default n
config LV_WAYLAND_WINDOW_DECORATIONS
bool "Draw client side window decorations, only necessary on Mutter (GNOME)"
config LV_WAYLAND_DIRECT_EXIT
bool "Deinitialize LVGL and quit the application when the last wayland window closes"
default y
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_G2D
config LV_USE_LINUX_FBDEV
bool "Use Linux framebuffer device"
@@ -4,20 +4,22 @@
Wayland Display/Inputs driver
=============================
Overview
--------
********
The **Wayland** `driver <https://github.com/lvgl/lvgl/tree/master/src/drivers/wayland>`__
offers support for simulating the LVGL display and keyboard/mouse inputs in a desktop
window.
The Wayland `driver <https://github.com/lvgl/lvgl/tree/master/src/drivers/wayland>`__ provides integration between LVGL and Wayland-based systems,
allowing LVGL applications to render directly into a Wayland surface and handle keyboard, mouse and touch input. This makes it suitable
for production deployments, such as kiosk interfaces, control panels, or other embedded GUIs where Wayland is the display server.
In addition to production use, the driver is also useful for development on linux desktop environments, offering a convenient way to simulate and validate
your LVGL applications without dedicated hardware. It serves as an alternative to the X11 and SDL2 drivers.
It is an alternative to **X11** or **SDL2**
The main purpose for this driver is for testing/debugging the LVGL application. It can
also be used to run applications in "kiosk mode".
Dependencies
------------
************
The wayland driver requires some dependencies.
@@ -34,8 +36,64 @@ On Fedora
sudo dnf install wayland-devel libxkbcommon-devel wayland-utils wayland-protocols-devel
Rendering Backends
******************
The Wayland driver supports multiple rendering backends, allowing you to choose the most appropriate rendering method for your hardware and use case.
SHM Backend (Default)
---------------------
The **SHM (Shared Memory)** backend is the default rendering backend used by the Wayland driver.
It uses Wayland's shared memory protocol (``wl_shm``) for rendering, which is supported across all Wayland compositors.
**Features:**
* Double-buffered direct rendering
* Universal compatibility with all Wayland compositors
* No special hardware requirements
**Limitations:**
* Rotation is not currently supported
**Usage:**
The SHM backend is enabled by default and requires no additional configuration.
G2D Backend
-----------
The G2D backend leverages NXP's hardware-accelerated 2D graphics engine available on i.MX processors. This backend provides improved performance on NXP platforms.
**Features:**
* Hardware-accelerated rendering
* Double-buffered direct rendering
* Rotation support (0°, 90°, 180°, 270°)
**Requirements:**
* Hardware with G2D support (e.g., NXP i.MX6/i.MX8 series)
* G2D library and drivers installed on the system
**Usage:**
Enable the G2D backend in ``lv_conf.h``:
.. code:: c
#define LV_USE_DRAW_G2D 1
When ``LV_USE_DRAW_G2D`` is enabled, the Wayland driver will automatically use the G2D backend instead of the default SHM backend.
Configuring the wayland driver
------------------------------
******************************
1. Enable the wayland driver in ``lv_conf.h``
@@ -43,46 +101,18 @@ Configuring the wayland driver
#define LV_USE_WAYLAND 1
2. Optional configuration options:
Some optional settings depend on whether DMA buffer support is enabled (`LV_WAYLAND_USE_DMABUF`). The table below summarizes valid combinations and limitations:
.. list-table:: Configuration possibilities
:widths: 50 25 25
:header-rows: 1
Reference Project
*****************
* - Configuration Option
- Without DMABUF
- With DMABUF
`LVGL Linux port <https://github.com/lvgl/lv_port_linux/>`__ serves as a reference project for setting up wayland. It uses CMake to generate
the required protocols at build time.
* - `LV_DRAW_USE_G2D`
- Not required
- **Required**
* - `LV_WAYLAND_BUF_COUNT`
- `1`
- `1` or `2`
* - `LV_WAYLAND_RENDER_MODE`
- `LV_DISPLAY_RENDER_MODE_PARTIAL`
- `LV_DISPLAY_RENDER_MODE_DIRECT` or `LV_DISPLAY_RENDER_MODE_FULL`
* - `LV_WAYLAND_WINDOW_DECORATIONS`
- `1` or `0`
- `0`
Additional notes
* DMABUF support (`LV_WAYLAND_USE_DMABUF`) improves performance and enables more render modes but has specific requirements and restrictions.
* `LV_WAYLAND_WINDOW_DECORATIONS` is only required for some compositors (e.g., GNOME/Mutter or Weston).
Example
-------
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
Usage
-----
Getting started
***************
#. In ``main.c`` ``#include "lv_drivers/wayland/wayland.h"``
#. Enable the Wayland driver in ``lv_conf.h`` with ``LV_USE_WAYLAND 1``
@@ -113,14 +143,29 @@ Handles for input devices of each display can be obtained using
``lv_wayland_get_indev_keyboard()``, ``lv_wayland_get_indev_touchscreen()``,
``lv_wayland_get_indev_pointer()`` and ``lv_wayland_get_indev_pointeraxis()`` respectively.
Fullscreen mode
^^^^^^^^^^^^^^^
---------------
To programmatically fullscreen the window, use the ``lv_wayland_window_set_fullscreen()``
function respectively with ``true`` or ``false`` for the ``fullscreen`` argument.
Maximized mode
--------------
To programmatically maximize the window,
use the ``lv_wayland_window_set_maximized()`` function respectively with ``true``
or ``false`` for the ``maximized`` argument.
Minimize window
---------------
To programmatically minimize the window, use the ``lv_wayland_window_set_minimized()`` function.
Physical display assignment
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
---------------------------
When using multiple physical displays, you can control which display a fullscreen window
appears on by assigning it to a specific physical display before entering fullscreen mode.
@@ -142,12 +187,6 @@ To remove the physical display assignment and return to default behavior, use
lv_wayland_unassign_physical_display(disp);
Maximized mode
^^^^^^^^^^^^^^
To programmatically maximize the window,
use the ``lv_wayland_window_set_maximized()`` function respectively with ``true``
or ``false`` for the ``maximized`` argument.
Custom timer handler
@@ -164,22 +203,15 @@ Wrapping the call to ``lv_timer_handler()`` is a necessity to have more control
when the LVGL flush callback is called.
Building the wayland driver
---------------------------
***************************
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
The `reference project <https://github.com/lvgl/lv_port_linux/>`__ uses CMakeLists to generate the necessary dependencies at build time.
If there is a need to use driver with another build system. The source and header files for the XDG shell
must be generated from the definitions for the XDG shell protocol.
Mainly, the project generates the necessary protocols with the ``wayland-scanner`` utility.
In the example CMake is used to perform the operation by invoking the ``wayland-scanner`` utility
The wayland protocols are defined using XML files which are present in ``/usr/share/wayland-protocols``
To achieve this manually,
Make sure the dependencies listed at the start of the article are installed.
The wayland protocol is defined using XML files which are present in ``/usr/share/wayland-protocols``
To generate the required files run the following commands:
By default, LVGL relies on the ``xdg-shell`` protocol for window management to generate it run the following commands:
.. code-block:: sh
@@ -198,19 +230,45 @@ The resulting files can then be integrated into the project, it's better to re-r
each build to ensure that the correct versions are generated, they must match the version of the ``wayland-client``
dynamically linked library installed on the system.
Current state and objectives
----------------------------
* Add direct rendering mode
* Refactor the shell integrations to avoid excessive conditional compilation
* Technically, the wayland driver allows to create multiple windows - but this feature is experimental.
* Eventually add enhanced support for XDG shell to allow the creation of desktop apps on Unix-like platforms,
similar to what the win32 driver does.
* Add a support for Mesa, currently wl_shm is used and it's not the most effective technique.
Window Decorations
******************
.. note::
As of LVGL v9.5, the `LV_WAYLAND_WINDOW_DECORATIONS` option has been removed.
Window decorations (title bars, borders, close buttons, etc.) are now the responsibility of the application developer, not LVGL.
This change gives you full control over the appearance and behavior of your window decorations.
Creating Window Decorations
---------------------------
You can create your own window decorations using LVGL widgets. For example, use the :ref:`lv_win` widget to add a title bar with buttons,
or build custom decorations from basic widgets like containers, labels, and buttons.
This approach allows you to:
- Design decorations that match your application's style
- Add custom controls and functionality
- Maintain consistent UI across different Wayland compositors
- Have complete control over the look and feel
For applications that don't need decorations (fullscreen, kiosk mode, etc.), simply create your UI without them.
Current state and objectives
****************************
* EGL Support
* Server-side window decorations
* Rotation support for the SHM backend
Bug reports
-----------
***********
The wayland driver is currently under construction, bug reports, contributions and feedback are always welcome.
@@ -226,4 +284,3 @@ This will create a log file called ``debug`` in the ``/tmp`` directory, copy-pas
The log file contains LVGL logs and the wayland messages.
Be sure to replicate the problem quickly otherwise the logs become too big
-1
View File
@@ -1168,7 +1168,6 @@
#define LV_WAYLAND_USE_DMABUF 0 /**< Use DMA buffers for frame buffers. Requires LV_USE_DRAW_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*/
#endif
/** Driver for /dev/fb */
+1 -5
View File
@@ -1242,11 +1242,7 @@
/** 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_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_DIRECT_EXIT 1 /**< 1: Exit the application when all Wayland windows are closed */
#endif
/** Driver for /dev/fb */
+6 -6
View File
@@ -139,12 +139,12 @@ extern "C" {
/* Define LV_DISABLE_API_MAPPING using a compiler option
* to make sure your application is not using deprecated names */
#ifndef LV_DISABLE_API_MAPPING
#include "src/lv_api_map_v8.h"
#include "src/lv_api_map_v9_0.h"
#include "src/lv_api_map_v9_1.h"
#include "src/lv_api_map_v9_2.h"
#include "src/lv_api_map_v9_3.h"
#include "src/lv_api_map_v9_4.h"
#include "src/lv_api_map_v8.h"
#include "src/lv_api_map_v9_0.h"
#include "src/lv_api_map_v9_1.h"
#include "src/lv_api_map_v9_2.h"
#include "src/lv_api_map_v9_3.h"
#include "src/lv_api_map_v9_4.h"
#endif /*LV_DISABLE_API_MAPPING*/
#if LV_USE_PRIVATE_API
+5 -1
View File
@@ -64,7 +64,11 @@ def parse_defaults(path: str):
for line in file.readlines():
if len(line.strip()) == 0 or line.startswith('#'):
continue
groups = re.search(r'([A-Z0-9_]+)\s+(.+)', line).groups()
search_result = re.search(r'([A-Z0-9_]+)\s+(.+)', line)
if not search_result:
print(f"WARNING: Ignoring line {line}")
continue
groups = search_result.groups()
defaults[groups[0]] = groups[1]
return defaults
+13 -4
View File
@@ -218,10 +218,19 @@ 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
#endif /* LV_USE_WAYLAND */
#if LV_USE_WAYLAND
/*Automatically detect wayland backend*/
#if LV_USE_G2D
#define LV_WAYLAND_USE_G2D 1
#define LV_WAYLAND_USE_SHM 0
#else
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 1
#endif
#else
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 0
#endif
#if LV_USE_LINUX_DRM == 0
#define LV_LINUX_DRM_USE_EGL 0
File diff suppressed because it is too large Load Diff
+100 -291
View File
@@ -14,19 +14,16 @@ extern "C" {
* INCLUDES
*********************/
#include "lv_wayland.h"
#include "../../lv_conf_internal.h"
#if LV_USE_WAYLAND
#include "lv_wayland_smm.h"
#include <sys/poll.h>
#include <wayland-client-protocol.h>
#include <wayland_xdg_shell.h>
#if LV_WAYLAND_USE_DMABUF
#include <sys/mman.h>
#include <string.h>
#endif
#include "../../misc/lv_types.h"
#include "lv_wl_backend_private.h"
/*********************
* DEFINES
@@ -35,115 +32,57 @@ extern "C" {
#define LV_WAYLAND_DEFAULT_CURSOR_NAME "left_ptr"
#define LV_WAYLAND_MAX_OUTPUTS 8
#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,
OBJECT_BUTTON_MAXIMIZE,
OBJECT_BUTTON_MINIMIZE,
OBJECT_BORDER_TOP,
OBJECT_BORDER_BOTTOM,
OBJECT_BORDER_LEFT,
OBJECT_BORDER_RIGHT,
OBJECT_WINDOW,
};
struct _lv_wl_window_t;
#define FIRST_DECORATION (OBJECT_TITLEBAR)
#define LAST_DECORATION (OBJECT_BORDER_RIGHT)
#define NUM_DECORATIONS (LAST_DECORATION - FIRST_DECORATION + 1)
typedef struct {
struct wl_pointer * wl_pointer;
struct wl_surface * cursor_surface;
lv_point_t point;
lv_indev_state_t left_btn_state;
lv_indev_state_t right_btn_state;
lv_indev_state_t wheel_btn_state;
int16_t wheel_diff;
} lv_wl_seat_pointer_t;
#if LV_WAYLAND_USE_DMABUF
#define MAX_BUFFER_PLANES 4
#endif
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;
typedef struct {
struct wl_touch * wl_touch;
#if LV_USE_GESTURE_RECOGNITION
lv_indev_touch_data_t touches[10];
uint8_t touch_event_cnt;
uint8_t event_cnt;
uint8_t primary_id;
#else
struct {
lv_point_t point;
lv_indev_state_t state;
} touch;
#endif
};
lv_point_t point;
lv_indev_state_t state;
#endif /*LV_USE_GESTURE_RECOGNITION*/
} lv_wl_seat_touch_t;
struct seat {
struct wl_touch * wl_touch;
struct wl_pointer * wl_pointer;
typedef struct {
struct wl_keyboard * wl_keyboard;
struct xkb_keymap * xkb_keymap;
struct xkb_state * xkb_state;
struct {
struct xkb_keymap * keymap;
struct xkb_state * state;
} xkb;
};
lv_key_t key;
lv_indev_state_t state;
bool is_pressed;
} lv_wl_seat_keyboard_t;
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;
uint8_t last_used;
} dmabuf_ctx_t;
struct wl_seat * wl_seat;
lv_wl_seat_pointer_t * pointer;
lv_wl_seat_touch_t * touch;
lv_wl_seat_keyboard_t * keyboard;
} lv_wl_seat_t;
typedef struct {
struct wl_shm * handler;
uint32_t format;
} shm_ctx_t;
struct output_info {
struct wl_output * wl_output;
char name[64];
int width;
@@ -151,117 +90,64 @@ struct output_info {
int refresh;
int scale;
int flags;
};
} lv_wl_output_info_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;
struct output_info outputs[LV_WAYLAND_MAX_OUTPUTS];
typedef struct {
struct wl_display * wl_display;
struct wl_registry * wl_registry;
struct wl_compositor * wl_compositor;
struct wl_shm * wl_shm;
lv_wl_seat_t seat;
void * backend_data;
lv_wl_output_info_t physical_outputs[LV_WAYLAND_MAX_OUTPUTS];
uint8_t wl_output_count;
#if LV_WAYLAND_USE_DMABUF
dmabuf_ctx_t dmabuf_ctx;
#endif
struct xdg_wm_base * xdg_wm;
#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;
} lv_wl_ctx_t;
bool cursor_flush_pending;
struct pollfd wayland_pfd;
};
typedef struct {
struct xdg_surface * xdg_surface;
uint32_t serial;
int32_t width;
int32_t height;
bool requested;
bool pending;
} lv_wl_resize_event_t;
struct window {
typedef struct {
struct xdg_surface * xdg_surface;
struct xdg_toplevel * xdg_toplevel;
bool configured;
} lv_wl_window_xdg_t;
typedef struct _lv_wl_window_t {
lv_display_t * lv_disp;
void * backend_display_data;
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_draw_buf_t * lv_draw_buf;
lv_wayland_display_close_f_t close_cb;
struct lv_wayland_context * wl_ctx;
lv_wayland_display_close_cb_t close_cb;
lv_wl_window_xdg_t xdg;
/* The current physical assigned output */
struct wl_output * assigned_output;
struct xdg_surface * xdg_surface;
struct xdg_toplevel * xdg_toplevel;
uint32_t wm_capabilities;
struct wl_output * physical_output;
struct graphic_object * body;
struct {
lv_area_t cache[DMG_CACHE_CAPACITY];
unsigned char start;
unsigned char end;
unsigned size;
} dmg_cache;
/* The current body surface */
struct wl_surface * body;
#if LV_WAYLAND_WINDOW_DECORATIONS
struct graphic_object * decoration[NUM_DECORATIONS];
#endif
lv_wl_resize_event_t resize_event;
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;
bool is_window_configured;
#if LV_WAYLAND_USE_DMABUF
/* XDG/DMABUF synchronization fields */
bool dmabuf_resize_pending;
bool surface_configured;
bool configure_acknowledged;
uint32_t configure_serial;
#if LV_WAYLAND_WINDOW_DECORATIONS
struct buffer * decorators_buf[8];
#endif
#endif
};
} lv_wl_window_t;
#if LV_WAYLAND_USE_DMABUF
struct buffer {
int busy;
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;
uint32_t width;
uint32_t height;
void * buf_base[MAX_BUFFER_PLANES];
lv_draw_buf_t * lv_draw_buf;
};
#endif
/**********************
* GLOBAL PROTOTYPES
@@ -271,133 +157,56 @@ struct buffer {
* MACROS
**********************/
extern struct lv_wayland_context lv_wl_ctx;
extern lv_wl_ctx_t lv_wl_ctx;
/**********************
* Driver
**********************/
void lv_wayland_init(void);
lv_result_t lv_wayland_init(void);
void lv_wayland_deinit(void);
void lv_wayland_wait_flush_cb(lv_display_t * disp);
void lv_wayland_event_cb(lv_event_t * e);
/**********************
* Window
**********************/
const struct wl_callback_listener * lv_wayland_window_get_wl_surface_frame_listener(void);
int32_t lv_wayland_window_get_width(lv_wl_window_t * window);
int32_t lv_wayland_window_get_height(lv_wl_window_t * window);
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,
void * decoration_buffer, struct graphic_object * parent);
void lv_wayland_window_decoration_detach(struct window * window, struct graphic_object * decoration);
#endif
void lv_wayland_window_delete(lv_wl_window_t * window);
/**********************
* Window Management
**********************/
const struct xdg_wm_base_listener * lv_wayland_xdg_get_wm_base_listener(void);
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, struct wl_output * output);
#if LV_WAYLAND_USE_DMABUF
void lv_wayland_xdg_shell_ack_configure(struct window * window, uint32_t serial);
#endif
lv_result_t lv_wayland_xdg_shell_create_window(struct lv_wayland_context * app, struct window * window,
const char * title);
void lv_wayland_xdg_shell_configure_surface(struct window * window);
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);
/**********************
* 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, struct window * window);
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, int width, int height);
lv_result_t lv_wayland_dmabuf_is_ready(dmabuf_ctx_t * context);
void destroy_decorators_buf(struct window * window, struct graphic_object * decoration);
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);
#if LV_WAYLAND_WINDOW_DECORATIONS
struct buffer * dmabuf_acquire_pool_buffer(struct window * window, struct graphic_object * decoration);
#endif
/**********************
* SME
**********************/
const struct smm_events * lv_wayland_sme_get_events(void);
/**********************
* Seat
**********************/
const struct wl_seat_listener * lv_wayland_seat_get_listener(void);
void lv_wayland_xdg_set_maximized(lv_wl_window_xdg_t * xdg, bool maximized);
void lv_wayland_xdg_set_minimized(lv_wl_window_xdg_t * xdg);
void lv_wayland_xdg_set_fullscreen(lv_wl_window_xdg_t * xdg, bool fullscreen,
struct wl_output * output);
lv_result_t lv_wl_xdg_create_window(struct xdg_wm_base * xdg_wm, lv_wl_window_t * window,
const char * title);
bool lv_wayland_xdg_is_resize_pending(lv_wl_window_t * window);
void lv_wayland_xdg_configure_surface(lv_wl_window_t * window);
void lv_wayland_xdg_resize(lv_wl_window_t * window);
void lv_wayland_xdg_delete_window(lv_wl_window_xdg_t * xdg);
void lv_wayland_xdg_deinit(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);
void lv_wayland_seat_init(lv_wl_seat_t * seat, struct wl_registry * registry, uint32_t name, uint32_t version);
void lv_wayland_seat_deinit(lv_wl_seat_t * seat);
/**********************
* Cache
**********************/
lv_wl_seat_pointer_t * lv_wayland_seat_pointer_create(struct wl_seat * seat, struct wl_surface * surface);
void lv_wayland_seat_pointer_delete(lv_wl_seat_pointer_t * seat_pointer);
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);
lv_wl_seat_touch_t * lv_wayland_seat_touch_create(struct wl_seat * seat);
void lv_wayland_seat_touch_delete(lv_wl_seat_touch_t * seat_touch);
lv_wl_seat_keyboard_t * lv_wayland_seat_keyboard_create(struct wl_seat * seat);
void lv_wayland_seat_keyboard_delete(lv_wl_seat_keyboard_t * seat_keyboard);
/* Updates indev's driver data with the given 'read_cb' to 'new_driver_data' */
void lv_wayland_update_indevs(lv_indev_read_cb_t read_cb, void * new_driver_data);
#endif /* LV_USE_WAYLAND */
File diff suppressed because it is too large Load Diff
-105
View File
@@ -1,105 +0,0 @@
/**
* @file lv_wayland_smm.h
*
*/
#ifndef LV_WAYLAND_SMM_H
#define LV_WAYLAND_SMM_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _WIN32
/*********************
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#include LV_STDDEF_INCLUDE
#include LV_STDBOOL_INCLUDE
#if LV_USE_WAYLAND
/*********************
* DEFINES
*********************/
#define SMM_FD_NAME "lvgl-wayland"
#define SMM_POOL_TAGS (1)
#define SMM_BUFFER_TAGS (2)
#define SMM_GROUP_TAGS (1)
/**********************
* TYPEDEFS
**********************/
typedef void smm_pool_t;
typedef void smm_buffer_t;
typedef void smm_group_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
struct smm_events {
void * ctx;
bool (*new_pool)(void * ctx, smm_pool_t * pool);
void (*expand_pool)(void * ctx, smm_pool_t * pool);
void (*free_pool)(void * ctx, smm_pool_t * pool);
bool (*new_buffer)(void * ctx, smm_buffer_t * buf);
bool (*init_buffer)(void * ctx, smm_buffer_t * buf);
void (*free_buffer)(void * ctx, smm_buffer_t * buf);
};
struct smm_pool_properties {
void * tag[SMM_POOL_TAGS];
size_t size;
int fd;
};
struct smm_buffer_properties {
void * tag[SMM_BUFFER_TAGS];
smm_group_t * const group;
smm_pool_t * const pool;
size_t offset;
};
struct smm_group_properties {
void * tag[SMM_GROUP_TAGS];
};
void smm_init(const struct smm_events * evs);
void smm_setctx(void * ctx);
void smm_deinit(void);
smm_group_t * smm_create(void);
void smm_resize(smm_group_t * grp, size_t sz);
void smm_destroy(smm_group_t * grp);
smm_buffer_t * smm_acquire(smm_group_t * grp);
void * smm_map(smm_buffer_t * buf);
void smm_release(smm_buffer_t * buf);
smm_buffer_t * smm_latest(smm_group_t * grp);
smm_buffer_t * smm_next(smm_buffer_t * buf);
/**********************
* MACROS
**********************/
#define SMM_POOL_PROPERTIES(p) ((const struct smm_pool_properties *)(p))
#define SMM_BUFFER_PROPERTIES(b) ((const struct smm_buffer_properties *)(b))
#define SMM_GROUP_PROPERTIES(g) ((const struct smm_group_properties *)(g))
#define SMM_TAG(o, n, v) \
do { \
void **smm_tag = (void **)((char *)o + (n * sizeof(void *))); \
*smm_tag = (v); \
} while(0)
#endif /* LV_USE_WAYLAND */
#endif /* _WIN32 */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /* LV_WAYLAND_SMM_H */
+206
View File
@@ -0,0 +1,206 @@
/**
* @file lv_wl_backend_private.h
*
*/
#ifndef LV_WL_BACKEND_PRIVATE_H
#define LV_WL_BACKEND_PRIVATE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_USE_WAYLAND
#include <wayland-client.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**
* @typedef lv_wayland_backend_init_t
* @brief Initialize the backend context
*
* This function is called once when the Wayland driver is initialized to create
* the global backend context. The returned pointer will be passed as backend_ctx
* to all other backend operations.
*
* @return Pointer to backend-specific context data, or NULL on failure
*
* @note This is called before any displays are created
* @see lv_wayland_backend_deinit_t
*/
typedef void * (*lv_wayland_backend_init_t)(void);
/**
* @typedef lv_wayland_backend_deinit_t
* @brief Deinitialize the backend context
*
* This function is called when the Wayland driver is deinitialized. It must
* clean up all resources allocated in the init function and free the backend
* context.
*
* @param[in] backend_ctx Pointer to the backend context returned by init
*
* @note This is called after all displays have been destroyed
* @see lv_wayland_backend_init_t
*/
typedef void (*lv_wayland_backend_deinit_t)(void * backend_ctx);
/**
* @typedef lv_wayland_backend_init_display_t
* @brief Initialize a new display
*
* This function is called when creating a new LVGL display on Wayland. It should
* allocate and initialize per-display resources needed for rendering.
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] display Pointer to the LVGL display object
* @param[in] width Initial width of the display in pixels
* @param[in] height Initial height of the display in pixels
* @return Pointer to display-specific data, or NULL on failure
*
* @note The returned pointer can be retrieved later using
* lv_wayland_get_backend_display_data()
* @note It is expected that each display gets its own data structure in order for a backend
* to support multiple displays
*/
typedef void * (*lv_wayland_backend_init_display_t)(void * backend_ctx, lv_display_t * display, int32_t width,
int32_t height);
/**
* @typedef lv_wayland_backend_resize_display_t
* @brief Resize or reconfigure a display
*
* This function is called when a display needs to be resized or when its rotation
* is modified. The backend should update its rendering resources accordingly.
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] display Pointer to the LVGL display object being resized
* @return Pointer to updated display-specific data, or NULL on failure
*
* @note This may be called multiple times during a display's lifetime
* @note The returned pointer will replace the previous display data. It can be
* retrieved using lv_wayland_get_backend_display_data()
* @warning The display data is overwritten with the return value of this function
*/
typedef void * (*lv_wayland_backend_resize_display_t)(void * backend_ctx, lv_display_t * display);
/**
* @typedef lv_wayland_backend_destroy_display_t
* @brief Destroy a display
*
* This function is called when an LVGL display is being destroyed. It must clean up
* all per-display resources and free the display data that was allocated in
* init_display.
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] display Pointer to the LVGL display object being destroyed
*
* @note The display data associated with this display must be freed
*/
typedef void (*lv_wayland_backend_destroy_display_t)(void * backend_ctx, lv_display_t * display);
/**
* @typedef lv_wayland_backend_global_handler_t
* @brief Handle Wayland global objects
*
* This function is called for every global object advertised by the Wayland
* compositor. The backend can use this to bind to Wayland protocols it requires
* (e.g., wl_shm, EGL extensions, DMA-BUF protocols, etc.).
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] registry Wayland registry object
* @param[in] name Numeric name of the global object
* @param[in] interface String name of the interface (e.g., "wl_shm")
* @param[in] version Version number of the interface
*
* @note This is called during Wayland connection setup
* @note The backend should use wl_registry_bind() to bind to needed protocols
*/
typedef void (*lv_wayland_backend_global_handler_t)(void * backend_ctx, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version);
/**
* @struct lv_wayland_backend_ops_t
* @brief Wayland backend operations structure
*
* This structure defines the complete set of operations that a Wayland backend
* must implement. All function pointers must be non-NULL.
*
* @par Lifecycle Order:
* 1. init() - Initialize backend context
* 2. global_handler() - Called for each Wayland global (may be called multiple times)
* 3. init_display() - Create display (may be called multiple times for multiple displays)
* 4. resize_display() - Resize display (called as needed)
* 5. deinit_display() - Destroy display (called once per display)
* 6. deinit() - Clean up backend context
*/
typedef struct {
lv_wayland_backend_init_t init; /**< Initialize backend context */
lv_wayland_backend_global_handler_t global_handler; /**< Handle Wayland global objects */
lv_wayland_backend_init_display_t init_display; /**< Initialize a new display */
lv_wayland_backend_resize_display_t resize_display; /**< Resize or reconfigure display */
lv_wayland_backend_destroy_display_t deinit_display; /**< Destroy a display */
lv_wayland_backend_deinit_t deinit; /**< Deinitialize backend context */
} lv_wayland_backend_ops_t;
extern const lv_wayland_backend_ops_t wl_backend_ops;
/** @brief Get the backend-specific display data
*
* Retrieves the per-display data pointer that was returned by the backend's
* init_display/resize_display functions. This allows the backend to access its own
* display-specific state and resources.
*
* @param[in] display Pointer to the LVGL display object
* @return Pointer to backend-specific display data
*
* @note This returns the value that was returned by lv_wayland_backend_init_display_t
* or lv_wayland_backend_resize_display_t
* @see lv_wayland_backend_init_display_t
*/
void * lv_wayland_get_backend_display_data(lv_display_t * display);
/**
* @brief Get the Wayland surface for rendering
*
* Retrieves the wl_surface object associated with the display window. This is the
* surface that the backend must use for all rendering operations (attaching buffers,
* committing frames, etc.).
*
* @param[in] display Pointer to the LVGL display object
* @return Pointer to the Wayland surface for rendering, or NULL if not available
*
* @note This surface is managed by the Wayland driver and must not be destroyed
* by the backend
* @note All rendering output should be attached to this surface
*/
struct wl_surface * lv_wayland_get_window_surface(lv_display_t * display);
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_WAYLAND*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_WL_BACKEND_PRIVATE_H*/
-133
View File
@@ -1,133 +0,0 @@
/**
* @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 */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+134 -119
View File
@@ -51,6 +51,8 @@ static lv_key_t keycode_xkb_to_lv(xkb_keysym_t xkb_key);
* STATIC VARIABLES
**********************/
static struct xkb_context * xkb_context;
static const struct wl_keyboard_listener keyboard_listener = {
.keymap = keyboard_handle_keymap,
.enter = keyboard_handle_enter,
@@ -70,16 +72,20 @@ static const struct wl_keyboard_listener keyboard_listener = {
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);
lv_indev_t * indev = lv_indev_create();
if(!indev) {
return NULL;
}
lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(indev, keyboard_read);
lv_indev_set_driver_data(indev, lv_wl_ctx.seat.keyboard);
return keyboard;
return indev;
}
lv_indev_t * lv_wayland_get_keyboard(lv_display_t * display)
{
struct window * window = lv_display_get_driver_data(display);
lv_wl_window_t * window = lv_display_get_driver_data(display);
if(!window) {
return NULL;
}
@@ -90,128 +96,142 @@ lv_indev_t * lv_wayland_get_keyboard(lv_display_t * display)
* PRIVATE FUNCTIONS
**********************/
const struct wl_keyboard_listener * lv_wayland_keyboard_get_listener(void)
lv_wl_seat_keyboard_t * lv_wayland_seat_keyboard_create(struct wl_seat * wl_seat)
{
return &keyboard_listener;
struct wl_keyboard * keyboard = wl_seat_get_keyboard(wl_seat);
if(!keyboard) {
LV_LOG_WARN("Failed to get seat keyboard");
return NULL;
}
if(!xkb_context && !(xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS))) {
LV_LOG_WARN("Failed to create xkb context");
return NULL;
}
lv_wl_seat_keyboard_t * wl_seat_keyboard = lv_zalloc(sizeof(*wl_seat_keyboard));
LV_ASSERT_MALLOC(wl_seat_keyboard);
if(!wl_seat_keyboard) {
LV_LOG_WARN("Failed to allocate memory for wayland keyboard");
return NULL;
}
wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
wl_keyboard_set_user_data(keyboard, wl_seat_keyboard);
wl_seat_keyboard->wl_keyboard = keyboard;
lv_wayland_update_indevs(keyboard_read, wl_seat_keyboard);
return wl_seat_keyboard;
}
void lv_wayland_seat_keyboard_delete(lv_wl_seat_keyboard_t * seat_keyboard)
{
lv_wayland_update_indevs(keyboard_read, NULL);
lv_free(seat_keyboard);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void keyboard_read(lv_indev_t * drv, lv_indev_data_t * data)
static void keyboard_read(lv_indev_t * indev, lv_indev_data_t * data)
{
struct window * window = lv_display_get_driver_data(lv_indev_get_display(drv));
if(!window || window->closed) {
lv_wl_seat_keyboard_t * kbdata = lv_indev_get_driver_data(indev);
if(!kbdata) {
return;
}
data->key = window->body->input.keyboard.key;
data->state = window->body->input.keyboard.state;
data->key = kbdata->key;
data->state = kbdata->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);
LV_UNUSED(data);
lv_wl_seat_keyboard_t * kbdata = wl_keyboard_get_user_data(keyboard);
if(format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
LV_LOG_WARN("Can't handle formats other than WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1");
close(fd);
return;
}
map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
char * map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if(map_str == MAP_FAILED) {
LV_LOG_WARN("Failed to mmap keyboard keymap file");
close(fd);
return;
}
/* Set up XKB keymap */
keymap = xkb_keymap_new_from_string(app->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
struct xkb_keymap * keymap = xkb_keymap_new_from_string(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");
LV_LOG_WARN("Failed to compile keymap");
return;
}
/* Set up XKB state */
state = xkb_state_new(keymap);
struct xkb_state * state = xkb_state_new(keymap);
if(!state) {
LV_LOG_ERROR("failed to create XKB state");
LV_LOG_WARN("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;
xkb_keymap_unref(kbdata->xkb_keymap);
xkb_state_unref(kbdata->xkb_state);
kbdata->xkb_keymap = keymap;
kbdata->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(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);
}
LV_UNUSED(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;
}
LV_UNUSED(data);
LV_UNUSED(surface);
}
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(data);
LV_UNUSED(serial);
LV_UNUSED(time);
LV_UNUSED(keyboard);
if(!app->keyboard_obj || !app->seat.xkb.state) {
lv_wl_seat_keyboard_t * kbdata = wl_keyboard_get_user_data(keyboard);
const uint32_t code = (key + 8);
if(!kbdata->xkb_state) {
return;
}
if(xkb_state_key_get_syms(app->seat.xkb.state, code, &syms) == 1) {
sym = syms[0];
const xkb_keysym_t * syms = XKB_KEY_NoSymbol;
if(xkb_state_key_get_syms(kbdata->xkb_state, code, &syms) != 1) {
return;
}
const lv_key_t lv_key = keycode_xkb_to_lv(sym);
const lv_key_t lv_key = keycode_xkb_to_lv(syms[0]);
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;
kbdata->key = lv_key;
kbdata->state = lv_state;
}
}
@@ -219,83 +239,78 @@ static void keyboard_handle_modifiers(void * data, struct wl_keyboard * keyboard
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);
LV_UNUSED(data);
lv_wl_seat_keyboard_t * kbdata = wl_keyboard_get_user_data(keyboard);
/* If we're not using a keymap, then we don't handle PC-style modifiers */
if(!app->seat.xkb.keymap) {
if(!kbdata->xkb_keymap) {
return;
}
xkb_state_update_mask(app->seat.xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
xkb_state_update_mask(kbdata->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;
if(xkb_key >= XKB_KEY_space && xkb_key <= XKB_KEY_asciitilde) {
return xkb_key;
}
else if(((xkb_key >= XKB_KEY_KP_0) && (xkb_key <= XKB_KEY_KP_9))) {
key = (xkb_key & 0x003f);
if(xkb_key >= XKB_KEY_KP_0 && xkb_key <= XKB_KEY_KP_9) {
return (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;
}
switch(xkb_key) {
case XKB_KEY_BackSpace:
return LV_KEY_BACKSPACE;
break;
case XKB_KEY_Return:
case XKB_KEY_KP_Enter:
return LV_KEY_ENTER;
break;
case XKB_KEY_Escape:
return LV_KEY_ESC;
break;
case XKB_KEY_Delete:
case XKB_KEY_KP_Delete:
return LV_KEY_DEL;
break;
case XKB_KEY_Home:
case XKB_KEY_KP_Home:
return LV_KEY_HOME;
break;
case XKB_KEY_Left:
case XKB_KEY_KP_Left:
return LV_KEY_LEFT;
break;
case XKB_KEY_Up:
case XKB_KEY_KP_Up:
return LV_KEY_UP;
break;
case XKB_KEY_Right:
case XKB_KEY_KP_Right:
return LV_KEY_RIGHT;
break;
case XKB_KEY_Down:
case XKB_KEY_KP_Down:
return LV_KEY_DOWN;
break;
case XKB_KEY_Prior:
case XKB_KEY_KP_Prior:
return LV_KEY_PREV;
break;
case XKB_KEY_Next:
case XKB_KEY_KP_Next:
case XKB_KEY_Tab:
case XKB_KEY_KP_Tab:
return LV_KEY_NEXT;
break;
case XKB_KEY_End:
case XKB_KEY_KP_End:
return LV_KEY_END;
break;
default:
return 0;
}
return key;
}
#endif /* LV_WAYLAND */
+129 -103
View File
@@ -31,7 +31,9 @@
* STATIC PROTOTYPES
**********************/
static void _lv_wayland_pointer_read(lv_indev_t * drv, lv_indev_data_t * data);
static void pointer_read(lv_indev_t * indev, lv_indev_data_t * data);
static void pointeraxis_read(lv_indev_t * indev, 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);
@@ -52,6 +54,8 @@ static void pointer_handle_axis(void * data, struct wl_pointer * wl_pointer, uin
* STATIC VARIABLES
**********************/
static struct wl_cursor_theme * cursor_theme = NULL;
static const struct wl_pointer_listener pointer_listener = {
.enter = pointer_handle_enter,
.leave = pointer_handle_leave,
@@ -71,169 +75,191 @@ static const struct wl_pointer_listener pointer_listener = {
lv_indev_t * lv_wayland_pointer_create(void)
{
lv_indev_t * indev = lv_indev_create();
if(!indev) {
return NULL;
}
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, _lv_wayland_pointer_read);
lv_indev_set_read_cb(indev, pointer_read);
lv_indev_set_driver_data(indev, lv_wl_ctx.seat.pointer);
return indev;
}
lv_indev_t * lv_wayland_get_pointer(lv_display_t * disp)
{
struct window * window = lv_display_get_driver_data(disp);
lv_wl_window_t * window = lv_display_get_driver_data(disp);
if(!window) {
return NULL;
}
return window->lv_indev_pointer;
}
/**********************
* PRIVATE FUNCTIONS
**********************/
const struct wl_pointer_listener * lv_wayland_pointer_get_listener(void)
lv_indev_t * lv_wayland_pointer_axis_create(void)
{
return &pointer_listener;
lv_indev_t * indev = lv_indev_create();
if(!indev) {
return NULL;
}
lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER);
lv_indev_set_read_cb(indev, pointeraxis_read);
lv_indev_set_driver_data(indev, lv_wl_ctx.seat.pointer);
return indev;
}
lv_indev_t * lv_wayland_get_pointeraxis(lv_display_t * display)
{
lv_wl_window_t * window = lv_display_get_driver_data(display);
if(!window) {
return NULL;
}
return window->lv_indev_pointeraxis;
}
lv_wl_seat_pointer_t * lv_wayland_seat_pointer_create(struct wl_seat * seat, struct wl_surface * surface)
{
LV_ASSERT_NULL(seat);
LV_ASSERT_NULL(surface);
if(!cursor_theme && !(cursor_theme = wl_cursor_theme_load(NULL, 32, lv_wl_ctx.wl_shm))) {
LV_LOG_WARN("Failed to load cursor theme for pointer");
return NULL;
}
struct wl_pointer * pointer = wl_seat_get_pointer(seat);
if(!pointer) {
LV_LOG_WARN("Failed to get seat pointer");
return NULL;
}
lv_wl_seat_pointer_t * wl_seat_pointer = lv_zalloc(sizeof(*wl_seat_pointer));
LV_ASSERT_MALLOC(wl_seat_pointer);
if(!wl_seat_pointer) {
LV_LOG_WARN("Failed to allocate memory for wayland pointer");
return NULL;
}
wl_pointer_add_listener(pointer, &pointer_listener, NULL);
wl_pointer_set_user_data(pointer, wl_seat_pointer);
wl_seat_pointer->cursor_surface = surface;
wl_seat_pointer->wl_pointer = pointer;
lv_wayland_update_indevs(pointer_read, wl_seat_pointer);
lv_wayland_update_indevs(pointeraxis_read, wl_seat_pointer);
return wl_seat_pointer;
}
void lv_wayland_seat_pointer_delete(lv_wl_seat_pointer_t * seat_pointer)
{
lv_wayland_update_indevs(pointer_read, NULL);
lv_wayland_update_indevs(pointeraxis_read, NULL);
wl_pointer_destroy(seat_pointer->wl_pointer);
lv_free(seat_pointer);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _lv_wayland_pointer_read(lv_indev_t * drv, lv_indev_data_t * data)
static void pointeraxis_read(lv_indev_t * indev, lv_indev_data_t * data)
{
struct window * window = lv_display_get_driver_data(lv_indev_get_display(drv));
if(!window || window->closed) {
lv_wl_seat_pointer_t * seat_pointer = lv_indev_get_driver_data(indev);
if(!seat_pointer) {
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;
data->state = seat_pointer->wheel_btn_state;
data->enc_diff = seat_pointer->wheel_diff;
seat_pointer->wheel_diff = 0;
}
static void pointer_read(lv_indev_t * indev, lv_indev_data_t * data)
{
lv_wl_seat_pointer_t * seat_pointer = lv_indev_get_driver_data(indev);
if(!seat_pointer) {
return;
}
data->point = seat_pointer->point;
data->state = seat_pointer->left_btn_state;
}
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);
LV_UNUSED(data);
LV_UNUSED(surface);
lv_wl_seat_pointer_t * seat_pointer = wl_pointer_get_user_data(pointer);
int pos_x = wl_fixed_to_int(sx);
int pos_y = wl_fixed_to_int(sy);
if(!surface) {
app->pointer_obj = NULL;
return;
}
seat_pointer->point.x = pos_x;
seat_pointer->point.y = pos_y;
app->pointer_obj = wl_surface_get_user_data(surface);
struct wl_cursor * wl_cursor = wl_cursor_theme_get_cursor(cursor_theme, LV_WAYLAND_DEFAULT_CURSOR_NAME);
struct wl_cursor_image * cursor_image = wl_cursor->images[0];
app->pointer_obj->input.pointer.x = pos_x;
app->pointer_obj->input.pointer.y = pos_y;
wl_pointer_set_cursor(pointer, serial, seat_pointer->cursor_surface, cursor_image->hotspot_x, cursor_image->hotspot_y);
cursor = lv_wayland_xdg_shell_get_cursor_name(app);
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;
}
wl_surface_attach(seat_pointer->cursor_surface, wl_cursor_image_get_buffer(cursor_image), 0, 0);
wl_surface_damage(seat_pointer->cursor_surface, 0, 0, cursor_image->width, cursor_image->height);
wl_surface_commit(seat_pointer->cursor_surface);
}
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(data);
LV_UNUSED(serial);
if(!surface || (app->pointer_obj == wl_surface_get_user_data(surface))) {
app->pointer_obj = NULL;
}
LV_UNUSED(surface);
LV_UNUSED(pointer);
}
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(data);
LV_UNUSED(time);
if(!app->pointer_obj) {
return;
}
lv_wl_seat_pointer_t * seat_pointer = wl_pointer_get_user_data(pointer);
LV_ASSERT_NULL(seat_pointer);
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));
seat_pointer->point.x = wl_fixed_to_int(sx);
seat_pointer->point.y = wl_fixed_to_int(sy);
}
static void pointer_handle_button(void * data, struct wl_pointer * wl_pointer, uint32_t serial, uint32_t time,
static void pointer_handle_button(void * data, struct wl_pointer * pointer, uint32_t serial, uint32_t time,
uint32_t button, uint32_t state)
{
struct lv_wayland_context * app = data;
LV_UNUSED(data);
LV_UNUSED(serial);
LV_UNUSED(wl_pointer);
LV_UNUSED(time);
lv_wl_seat_pointer_t * seat_pointer = wl_pointer_get_user_data(pointer);
LV_ASSERT_NULL(seat_pointer);
const lv_indev_state_t lv_state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ?
LV_INDEV_STATE_PRESSED :
LV_INDEV_STATE_RELEASED;
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;
if(button == BTN_LEFT) {
seat_pointer->left_btn_state = lv_state;
}
struct window * window = app->pointer_obj->window;
lv_wayland_xdg_shell_handle_pointer_event(app, serial, button, state);
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;
else if(button == BTN_RIGHT) {
seat_pointer->right_btn_state = lv_state;
}
else if(button == BTN_MIDDLE) {
seat_pointer->wheel_btn_state = lv_state;
}
}
static void pointer_handle_axis(void * data, struct wl_pointer * wl_pointer, uint32_t time, uint32_t axis,
static void pointer_handle_axis(void * data, struct wl_pointer * 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(data);
LV_UNUSED(time);
LV_UNUSED(wl_pointer);
if(!app->pointer_obj) {
lv_wl_seat_pointer_t * seat_pointer = wl_pointer_get_user_data(pointer);
const int diff = wl_fixed_to_int(value);
if(axis != 0) {
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--;
}
}
seat_pointer->wheel_diff += diff;
}
#endif /* LV_USE_WAYLAND */
-79
View File
@@ -1,79 +0,0 @@
/**
* @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_driver_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_driver_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 */
+75 -29
View File
@@ -26,6 +26,9 @@
static void seat_handle_capabilities(void * data, struct wl_seat * wl_seat, enum wl_seat_capability caps);
static lv_wl_seat_pointer_t * create_pointer(struct wl_seat * wl_seat);
static void delete_pointer(lv_wl_seat_pointer_t * seat_pointer);
/**********************
* STATIC VARIABLES
**********************/
@@ -46,52 +49,95 @@ static const struct wl_seat_listener seat_listener = {
* PRIVATE FUNCTIONS
**********************/
const struct wl_seat_listener * lv_wayland_seat_get_listener(void)
void lv_wayland_seat_init(lv_wl_seat_t * seat, struct wl_registry * registry, uint32_t name, uint32_t version)
{
return &seat_listener;
LV_ASSERT_NULL(seat);
LV_UNUSED(version);
seat->wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
}
void lv_wayland_seat_deinit(lv_wl_seat_t * seat)
{
if(seat->pointer) {
delete_pointer(seat->pointer);
seat->pointer = NULL;
}
if(seat->keyboard) {
lv_wayland_seat_keyboard_delete(seat->keyboard);
seat->keyboard = NULL;
}
if(seat->touch) {
lv_wayland_seat_touch_delete(seat->touch);
seat->touch = NULL;
}
wl_seat_destroy(seat->wl_seat);
}
void lv_wayland_update_indevs(lv_indev_read_cb_t read_cb, void * new_driver_data)
{
lv_indev_t * indev = NULL;
while((indev = lv_indev_get_next(indev))) {
if(lv_indev_get_read_cb(indev) != read_cb) {
continue;
}
lv_indev_set_driver_data(indev, new_driver_data);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_wl_seat_pointer_t * create_pointer(struct wl_seat * wl_seat)
{
struct wl_surface * surface = wl_compositor_create_surface(lv_wl_ctx.wl_compositor);
if(!surface) {
LV_LOG_WARN("Failed to get surface for pointer");
return NULL;
}
lv_wl_seat_pointer_t * seat_pointer = lv_wayland_seat_pointer_create(wl_seat, surface);
if(!seat_pointer) {
LV_LOG_WARN("Failed to create seat pointer");
wl_surface_destroy(surface);
return NULL;
}
return seat_pointer;
}
static void delete_pointer(lv_wl_seat_pointer_t * seat_pointer)
{
wl_surface_destroy(seat_pointer->cursor_surface);
lv_wayland_seat_pointer_delete(seat_pointer);
}
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;
lv_wl_seat_t * seat = (lv_wl_seat_t *) data;
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");
}
if((caps & WL_SEAT_CAPABILITY_POINTER) && !seat->pointer) {
seat->pointer = create_pointer(wl_seat);
}
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;
else if(!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer) {
delete_pointer(seat->pointer);
seat->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);
if((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !seat->keyboard) {
seat->keyboard = lv_wayland_seat_keyboard_create(wl_seat);
}
else if(!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->wl_keyboard) {
wl_keyboard_destroy(seat->wl_keyboard);
seat->wl_keyboard = NULL;
else if(!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard) {
lv_wayland_seat_keyboard_delete(seat->keyboard);
seat->keyboard = NULL;
}
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);
if((caps & WL_SEAT_CAPABILITY_TOUCH) && !seat->touch) {
seat->touch = lv_wayland_seat_touch_create(wl_seat);
}
else if(!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch) {
wl_touch_destroy(seat->wl_touch);
seat->wl_touch = NULL;
else if(!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch) {
lv_wayland_seat_touch_delete(seat->touch);
seat->touch = NULL;
}
}
-473
View File
@@ -1,473 +0,0 @@
/**
* @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)
{
LV_UNUSED(context);
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 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));
window->lv_draw_buf = lv_draw_buf_reshape(window->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)
{
LV_UNUSED(context);
const uint32_t stride = lv_draw_buf_width_to_stride(window->width, lv_display_get_color_format(window->lv_disp));
window->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 window->lv_draw_buf ? LV_RESULT_OK : LV_RESULT_INVALID;
}
lv_result_t lv_wayland_shm_set_draw_buffers(shm_ctx_t * context, lv_display_t * display, struct window * window)
{
LV_UNUSED(context);
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, window->lv_draw_buf, NULL);
return LV_RESULT_OK;
}
void lv_wayland_shm_delete_draw_buffers(shm_ctx_t * context, struct window * window)
{
LV_UNUSED(context);
if(window->lv_draw_buf) lv_draw_buf_destroy(window->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_driver_data(disp);
const uint32_t buf_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);
const uint8_t cf = lv_display_get_color_format(disp);
const int32_t stride = lv_draw_buf_width_to_stride(src_width, cf);
/* 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(buf_format == WL_SHM_FORMAT_ARGB8888 &&
cf != LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED) {
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 += stride;
}
/* 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 */
+398
View File
@@ -0,0 +1,398 @@
/**
* @file lv_wl_shm_backend.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland_private.h"
#if LV_WAYLAND_USE_SHM
#include "../../display/lv_display_private.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
/*********************
* DEFINES
*********************/
#define LV_WL_SHM_BUF_COUNT 2
/**********************
* TYPEDEFS
**********************/
typedef struct {
struct wl_shm * shm;
} lv_wl_shm_ctx_t;
typedef struct {
struct wl_buffer * wl_buffer;
bool busy;
} lv_wl_buffer_t;
typedef struct {
void * mmap_ptr;
size_t mmap_size;
struct wl_shm_pool * pool;
lv_wl_buffer_t buffers[LV_WL_SHM_BUF_COUNT];
size_t curr_wl_buffer_idx;
uint32_t shm_cf;
int fd;
bool delete_on_release;
} lv_wl_shm_display_data_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void * shm_init(void);
static void shm_deinit(void *);
static void * shm_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height);
static void * shm_resize_display(void * backend_ctx, lv_display_t * display);
static void shm_deinit_display(void * backend_ctx, lv_display_t * display);
static void shm_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version);
static int create_shm_file(size_t size);
static void shm_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
static lv_wl_shm_display_data_t * shm_create_display_data(lv_wl_shm_ctx_t * ctx, lv_display_t * display, int32_t width,
int32_t height, size_t buf_count);
static void shm_destroy_display_data(lv_wl_shm_display_data_t * ddata);
static void frame_done(void * data, struct wl_callback * callback, uint32_t time);
static void buffer_release(void * data, struct wl_buffer * wl_buffer);
/**********************
* STATIC VARIABLES
**********************/
static lv_wl_shm_ctx_t shm_ctx;
static const struct wl_callback_listener frame_listener = {
.done = frame_done,
};
static const struct wl_buffer_listener buffer_listener = {
.release = buffer_release
};
const lv_wayland_backend_ops_t wl_backend_ops = {
.init = shm_init,
.deinit = shm_deinit,
.global_handler = shm_global_handler,
.init_display = shm_init_display,
.deinit_display = shm_deinit_display,
.resize_display = shm_resize_display,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
static void buffer_release(void * data, struct wl_buffer * wl_buffer)
{
lv_wl_shm_display_data_t * ddata = data;
for(size_t i = 0; i < LV_WL_SHM_BUF_COUNT; ++i) {
if(wl_buffer == ddata->buffers[i].wl_buffer) {
ddata->buffers[i].busy = false;
}
}
if(ddata->delete_on_release) {
shm_destroy_display_data(ddata);
}
}
static void frame_done(void * data, struct wl_callback * callback, uint32_t time)
{
LV_UNUSED(time);
lv_display_t * display = data;
wl_callback_destroy(callback);
lv_display_flush_ready(display);
}
static uint32_t lv_cf_to_shm_cf(lv_color_format_t cf)
{
switch(cf) {
case LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED:
case LV_COLOR_FORMAT_ARGB8888:
return WL_SHM_FORMAT_ARGB8888;
case LV_COLOR_FORMAT_XRGB8888:
return WL_SHM_FORMAT_XRGB8888;
case LV_COLOR_FORMAT_RGB565:
return WL_SHM_FORMAT_RGB565;
default:
return 0;
}
}
static void * shm_init(void)
{
lv_memzero(&shm_ctx, sizeof(shm_ctx));
return &shm_ctx;
}
static void shm_deinit(void * backend_ctx)
{
lv_wl_shm_ctx_t * ctx = backend_ctx;
if(ctx->shm) {
wl_shm_destroy(ctx->shm);
}
}
static lv_wl_shm_display_data_t * shm_create_display_data(lv_wl_shm_ctx_t * ctx, lv_display_t * display, int32_t width,
int32_t height, size_t buf_count)
{
lv_wl_shm_display_data_t * ddata = lv_zalloc(sizeof(*ddata));
if(!ddata) {
LV_LOG_ERROR("Failed to allocate data for display");
return NULL;
}
lv_color_format_t cf = lv_display_get_color_format(display);
ddata->shm_cf = lv_cf_to_shm_cf(cf);
if(!ddata->shm_cf) {
LV_LOG_WARN("Unsupported color format %d. Falling back to XRGB8888", cf);
cf = LV_COLOR_FORMAT_XRGB8888;
lv_display_set_color_format(display, cf);
ddata->shm_cf = WL_SHM_FORMAT_XRGB8888;
}
const uint32_t stride = lv_draw_buf_width_to_stride(width, cf);
const size_t buf_size = stride * height;
ddata->mmap_size = buf_size * buf_count;
ddata->fd = create_shm_file(ddata->mmap_size);
if(ddata->fd < 0) {
LV_LOG_ERROR("Failed to create shm file");
goto shm_file_err;
}
ddata->mmap_ptr = mmap(NULL, ddata->mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, ddata->fd, 0);
if(ddata->mmap_ptr == MAP_FAILED) {
LV_LOG_ERROR("Failed to map shm file: %s", strerror(errno));
goto mmap_err;
}
ddata->pool = wl_shm_create_pool(ctx->shm, ddata->fd, ddata->mmap_size);
if(!ddata->pool) {
LV_LOG_ERROR("Failed to create wl_shm_pool");
goto shm_pool_err;
}
for(size_t i = 0; i < buf_count; ++i) {
size_t offset = i * buf_size;
ddata->buffers[i].wl_buffer = wl_shm_pool_create_buffer(ddata->pool, offset, width, height, stride, ddata->shm_cf);
if(!ddata->buffers[i].wl_buffer) {
LV_LOG_ERROR("Failed to create wl_buffer %zu", i);
goto pool_buffer_err;
}
wl_buffer_add_listener(ddata->buffers[i].wl_buffer, &buffer_listener, ddata);
ddata->buffers[i].busy = false;
}
lv_display_set_buffers(display, ddata->mmap_ptr, (uint8_t *)ddata->mmap_ptr + buf_size,
buf_size, LV_DISPLAY_RENDER_MODE_DIRECT);
return ddata;
pool_buffer_err:
wl_shm_pool_destroy(ddata->pool);
shm_pool_err:
munmap(ddata->mmap_ptr, ddata->mmap_size);
mmap_err:
close(ddata->fd);
shm_file_err:
lv_free(ddata);
return NULL;
}
static void shm_destroy_display_data(lv_wl_shm_display_data_t * ddata)
{
for(size_t i = 0; i < LV_WL_SHM_BUF_COUNT; ++i) {
lv_wl_buffer_t * buffer = &ddata->buffers[i];
if(!buffer->wl_buffer) {
continue;
}
if(buffer->busy) {
/* Defer the deletion of this display data until the buffers are released */
LV_LOG_INFO("Buffer is still busy, deferring deletion to when its released");
ddata->delete_on_release = true;
return;
}
wl_buffer_destroy(ddata->buffers[i].wl_buffer);
ddata->buffers[i].wl_buffer = NULL;
}
if(ddata->pool) {
wl_shm_pool_destroy(ddata->pool);
ddata->pool = NULL;
}
if(ddata->mmap_ptr != MAP_FAILED) {
munmap(ddata->mmap_ptr, ddata->mmap_size);
ddata->mmap_ptr = MAP_FAILED;
}
if(ddata->fd >= 0) {
close(ddata->fd);
ddata->fd = -1;
}
LV_LOG_INFO("Deleted buffers and display data");
lv_free(ddata);
}
static void flush_wait_cb(lv_display_t * disp)
{
while(disp->flushing) {
wl_display_dispatch(lv_wl_ctx.wl_display);
}
}
static void * shm_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height)
{
lv_wl_shm_ctx_t * ctx = (lv_wl_shm_ctx_t *)backend_ctx;
if(!ctx->shm) {
LV_LOG_ERROR("wl_shm not available");
return NULL;
}
lv_wl_shm_display_data_t * ddata = shm_create_display_data(ctx, display, width, height, LV_WL_SHM_BUF_COUNT);
if(!ddata) {
LV_LOG_ERROR("Failed to allocate data for display");
return NULL;
}
lv_display_set_flush_cb(display, shm_flush_cb);
lv_display_set_flush_wait_cb(display, flush_wait_cb);
return ddata;
}
static void * shm_resize_display(void * backend_ctx, lv_display_t * display)
{
lv_wl_shm_ctx_t * ctx = (lv_wl_shm_ctx_t *)backend_ctx;
const int32_t new_width = lv_display_get_horizontal_resolution(display);
const int32_t new_height = lv_display_get_vertical_resolution(display);
lv_wl_shm_display_data_t * ddata = shm_create_display_data(ctx, display, new_width, new_height, LV_WL_SHM_BUF_COUNT);
if(!ddata) {
LV_LOG_ERROR("Failed to allocate data for new display resolution");
return NULL;
}
lv_wl_shm_display_data_t * curr_ddata = lv_wayland_get_backend_display_data(display);
shm_destroy_display_data(curr_ddata);
return ddata;
}
static void shm_deinit_display(void * backend_ctx, lv_display_t * display)
{
LV_UNUSED(backend_ctx);
lv_wl_shm_display_data_t * ddata = lv_wayland_get_backend_display_data(display);
if(!ddata) {
return;
}
shm_destroy_display_data(ddata);
}
static int create_shm_file(size_t size)
{
int fd = -1;
char name[255];
snprintf(name, sizeof(name), "/lvgl-wayland-%d-%ld", getpid(), (long)lv_tick_get());
fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if(fd < 0) {
LV_LOG_ERROR("shm_open failed: %s", strerror(errno));
return -1;
}
shm_unlink(name);
if(ftruncate(fd, size) < 0) {
LV_LOG_ERROR("ftruncate failed: %s", strerror(errno));
close(fd);
return -1;
}
return fd;
}
static void shm_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version)
{
LV_UNUSED(version);
lv_wl_shm_ctx_t * ctx = (lv_wl_shm_ctx_t *)backend_ctx;
if(lv_streq(interface, wl_shm_interface.name)) {
ctx->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
}
}
static void shm_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
LV_UNUSED(px_map);
lv_wl_shm_display_data_t * ddata = lv_wayland_get_backend_display_data(disp);
struct wl_surface * surface = lv_wayland_get_window_surface(disp);
if(!surface) {
lv_display_flush_ready(disp);
return;
}
int32_t w = lv_area_get_width(area);
int32_t h = lv_area_get_height(area);
lv_color_format_t cf = lv_display_get_color_format(disp);
/* When using ARGB8888, the compositor expects premultiplied ARGB8888 so premultiply it here*/
if(ddata->shm_cf == WL_SHM_FORMAT_ARGB8888 && cf != LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED) {
size_t index = 0;
for(int32_t y = area->y1; y <= area->y2; ++y) {
for(int32_t x = area->x1; x <= area->x2; ++x) {
lv_color_premultiply((lv_color32_t *) px_map + (index++));
}
}
}
wl_surface_damage(surface, area->x1, area->y1, w, h);
if(!lv_display_flush_is_last(disp)) {
lv_display_flush_ready(disp);
return;
}
struct wl_callback * callback = wl_surface_frame(surface);
wl_callback_add_listener(callback, &frame_listener, disp);
lv_wl_buffer_t * buffer = &ddata->buffers[ddata->curr_wl_buffer_idx];
if(buffer->busy) {
LV_LOG_WARN("Failed to acquire a non-busy buffer");
}
wl_surface_attach(surface, buffer->wl_buffer, 0, 0);
wl_surface_commit(surface);
buffer->busy = true;
ddata->curr_wl_buffer_idx = (ddata->curr_wl_buffer_idx + 1) % LV_WL_SHM_BUF_COUNT;
}
#endif /*LV_WAYLAND_USE_SHM*/
+84 -122
View File
@@ -28,7 +28,7 @@
* STATIC PROTOTYPES
**********************/
static void _lv_wayland_touch_read(lv_indev_t * drv, lv_indev_data_t * data);
static void 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);
@@ -67,14 +67,14 @@ 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);
lv_indev_set_read_cb(indev, touch_read);
return indev;
}
lv_indev_t * lv_wayland_get_touchscreen(lv_display_t * display)
{
struct window * window = lv_display_get_driver_data(display);
lv_wl_window_t * window = lv_display_get_driver_data(display);
if(!window) {
return NULL;
}
@@ -85,176 +85,141 @@ lv_indev_t * lv_wayland_get_touchscreen(lv_display_t * display)
* PRIVATE FUNCTIONS
**********************/
const struct wl_touch_listener * lv_wayland_touch_get_listener(void)
lv_wl_seat_touch_t * lv_wayland_seat_touch_create(struct wl_seat * seat)
{
return &touch_listener;
struct wl_touch * touch = wl_seat_get_touch(seat);
if(!touch) {
LV_LOG_WARN("Failed to get seat touch");
return NULL;
}
lv_wl_seat_touch_t * wl_seat_touch = lv_zalloc(sizeof(*wl_seat_touch));
LV_ASSERT_MALLOC(wl_seat_touch);
if(!wl_seat_touch) {
LV_LOG_WARN("Failed to allocate memory for wayland touch");
wl_touch_destroy(touch);
return NULL;
}
wl_touch_add_listener(touch, &touch_listener, NULL);
wl_touch_set_user_data(touch, wl_seat_touch);
wl_seat_touch->wl_touch = touch;
lv_wayland_update_indevs(touch_read, wl_seat_touch);
return wl_seat_touch;
}
void lv_wayland_seat_touch_delete(lv_wl_seat_touch_t * seat_touch)
{
lv_wayland_update_indevs(touch_read, NULL);
wl_touch_destroy(seat_touch->wl_touch);
lv_free(seat_touch);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _lv_wayland_touch_read(lv_indev_t * drv, lv_indev_data_t * data)
static void touch_read(lv_indev_t * indev, lv_indev_data_t * data)
{
struct window * window = lv_display_get_driver_data(lv_indev_get_display(drv));
lv_wl_seat_touch_t * tdata = lv_indev_get_driver_data(indev);
if(!window || window->closed) {
if(!tdata) {
return;
}
#if LV_USE_GESTURE_RECOGNITION
/* 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_indev_gesture_recognizers_update(indev, tdata->touches, tdata->event_cnt);
LV_LOG_TRACE("collected touch events: %d", window->body->input.touch_event_cnt);
LV_LOG_TRACE("collected touch events: %d", tdata->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);
if(window->body->input.touch_event_cnt > 0) {
data->point.x = window->body->input.touches[0].point.x;
data->point.y = window->body->input.touches[0].point.y;
if(tdata->event_cnt > 0) {
data->point = tdata->touches[0].point;
}
else {
data->point.x = 0;
data->point.y = 0;
data->point.x = data->point.y = 0;
}
tdata->event_cnt = 0;
/* Set the gesture information, before returning to LVGL */
lv_indev_gesture_recognizers_set_data(indev, data);
#else
data->point.x = window->body->input.touch.point.x;
data->point.y = window->body->input.touch.point.y;
data->state = window->body->input.touch.state;
data->point = tdata->point;
data->state = tdata->state;
#endif
}
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;
#if LV_USE_GESTURE_RECOGNITION
uint8_t i;
#endif
LV_UNUSED(data);
LV_UNUSED(id);
LV_UNUSED(time);
LV_UNUSED(serial);
LV_UNUSED(wl_touch);
lv_wl_seat_touch_t * tdata = wl_touch_get_user_data(wl_touch);
if(!surface) {
app->touch_obj = NULL;
return;
}
/* Create the touch down event */
app->touch_obj = wl_surface_get_user_data(surface);
#if LV_USE_GESTURE_RECOGNITION
i = app->touch_obj->input.touch_event_cnt;
uint8_t i = tdata->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++;
tdata->touches[i].point.x = wl_fixed_to_int(x_w);
tdata->touches[i].point.y = wl_fixed_to_int(y_w);
tdata->touches[i].id = id;
tdata->touches[i].timestamp = time;
tdata->touches[i].state = LV_INDEV_STATE_PRESSED;
tdata->event_cnt++;
#else
app->touch_obj->input.touch.point.x = wl_fixed_to_int(x_w);
app->touch_obj->input.touch.point.y = wl_fixed_to_int(y_w);
app->touch_obj->input.touch.state = LV_INDEV_STATE_PRESSED;
#endif
#if LV_WAYLAND_WINDOW_DECORATIONS
struct window * window = app->touch_obj->window;
switch(app->touch_obj->type) {
case OBJECT_TITLEBAR:
if(window->xdg_toplevel) {
xdg_toplevel_move(window->xdg_toplevel, app->wl_seat, serial);
window->flush_pending = true;
}
break;
default:
break;
}
tdata->point.x = wl_fixed_to_int(x_w);
tdata->point.y = wl_fixed_to_int(y_w);
tdata->state = LV_INDEV_STATE_PRESSED;
#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;
#if LV_USE_GESTURE_RECOGNITION
uint8_t i;
#endif
LV_UNUSED(serial);
LV_UNUSED(time);
LV_UNUSED(id);
LV_UNUSED(wl_touch);
LV_UNUSED(data);
lv_wl_seat_touch_t * tdata = wl_touch_get_user_data(wl_touch);
/* Create a released event */
#if LV_USE_GESTURE_RECOGNITION
i = app->touch_obj->input.touch_event_cnt;
uint8_t i = tdata->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;
tdata->touches[i].point.x = 0;
tdata->touches[i].point.y = 0;
tdata->touches[i].id = id;
tdata->touches[i].timestamp = time;
tdata->touches[i].state = LV_INDEV_STATE_RELEASED;
app->touch_obj->input.touch_event_cnt++;
tdata->event_cnt++;
#else
app->touch_obj->input.touch.state = LV_INDEV_STATE_RELEASED;
tdata->state = LV_INDEV_STATE_RELEASED;
#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;
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;
}
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;
#if LV_USE_GESTURE_RECOGNITION
lv_indev_touch_data_t * touch;
lv_indev_touch_data_t * cur;
uint8_t i;
#endif
LV_UNUSED(time);
LV_UNUSED(id);
LV_UNUSED(wl_touch);
LV_UNUSED(time);
LV_UNUSED(data);
lv_wl_seat_touch_t * tdata = wl_touch_get_user_data(wl_touch);
#if LV_USE_GESTURE_RECOGNITION
/* Update the contact point of the corresponding id with the latest coordinate */
touch = &app->touch_obj->input.touches[0];
cur = NULL;
lv_indev_touch_data_t * touch = &tdata->touches[0];
lv_indev_touch_data_t * cur = NULL;
for(i = 0; i < app->touch_obj->input.touch_event_cnt; i++) {
for(uint8_t i = 0; i < tdata->event_cnt; i++) {
if(touch->id == id) {
cur = touch;
}
@@ -262,26 +227,23 @@ static void touch_handle_motion(void * data, struct wl_touch * wl_touch, uint32_
}
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++;
uint8_t i = tdata->event_cnt;
tdata->touches[i].point.x = wl_fixed_to_int(x_w);
tdata->touches[i].point.y = wl_fixed_to_int(y_w);
tdata->touches[i].id = id;
tdata->touches[i].timestamp = time;
tdata->touches[i].state = LV_INDEV_STATE_PRESSED;
tdata->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;
}
#else
app->touch_obj->input.touch.point.x = wl_fixed_to_int(x_w);
app->touch_obj->input.touch.point.y = wl_fixed_to_int(y_w);
tdata->point.x = wl_fixed_to_int(x_w);
tdata->point.y = wl_fixed_to_int(y_w);
#endif
}
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -27,7 +27,7 @@ extern "C" {
* TYPEDEFS
**********************/
typedef bool (*lv_wayland_display_close_f_t)(lv_display_t * disp);
typedef bool (*lv_wayland_display_close_cb_t)(lv_display_t * disp);
/**********************
* GLOBAL PROTOTYPES
@@ -42,7 +42,7 @@ typedef bool (*lv_wayland_display_close_f_t)(lv_display_t * disp);
* @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);
lv_wayland_display_close_cb_t close_cb);
/**
* Closes the window programmatically
@@ -85,6 +85,12 @@ void lv_wayland_window_set_fullscreen(lv_display_t * disp, bool fullscreen);
*/
void lv_wayland_window_set_maximized(lv_display_t * disp, bool maximize);
/**
* Minimizes the window
* @param disp Reference to the LVGL display associated to the window
*/
void lv_wayland_window_set_minimized(lv_display_t * disp);
/**********************
* MACROS
**********************/
@@ -1,382 +0,0 @@
/**
* @file lv_wl_window_decorations.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland.h"
#if LV_WAYLAND_WINDOW_DECORATIONS
#include "lv_wayland_private.h"
#include <errno.h>
#include <unistd.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,
void * decoration_buffer, struct graphic_object * parent)
{
#if LV_WAYLAND_USE_DMABUF
struct wl_buffer * wl_buf = ((struct buffer *)decoration_buffer)->buffer;
#else
struct wl_buffer * wl_buf = SMM_BUFFER_PROPERTIES((smm_buffer_t *)decoration_buffer)->tag[TAG_LOCAL];
#endif
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;
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;
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)
{
#if LV_WAYLAND_USE_DMABUF
struct buffer * buf;
#else
smm_buffer_t * buf;
#endif
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;
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;
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;
}
#if LV_WAYLAND_USE_DMABUF
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
buf = dmabuf_acquire_pool_buffer(window, decoration);
buf_base = mmap(0, (decoration->width * bpp) * decoration->height, PROT_READ | PROT_WRITE, MAP_SHARED,
buf->dmabuf_fds[0], 0);
if(buf_base == MAP_FAILED) {
destroy_decorators_buf(window, decoration);
LV_LOG_ERROR("cannot map in allocated decoration buffer %d (%s)", errno, strerror(errno));
return false;
}
#else
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;
}
#endif
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;
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;
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;
}
bool ret = lv_wayland_window_decoration_attach(window, decoration, buf, window->body);
#if LV_WAYLAND_USE_DMABUF
munmap(buf_base, (decoration->width * bpp) * decoration->height);
#endif
return ret;
}
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 */
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -13,7 +13,6 @@ extern "C" {
/*********************
* INCLUDES
*********************/
#include "misc/lv_types.h"
/*********************
* DEFINES
@@ -32,6 +31,8 @@ extern "C" {
**********************/
#define lv_tabview_rename_tab lv_tabview_set_tab_text
#define lv_wayland_timer_handler lv_timer_handler
#define lv_wayland_display_close_f_t lv_wayland_display_close_cb_t
#ifdef __cplusplus
} /*extern "C"*/
+18 -31
View File
@@ -3987,37 +3987,15 @@
#endif
#endif
#if LV_USE_WAYLAND
#ifndef LV_WAYLAND_BUF_COUNT
#ifndef LV_WAYLAND_DIRECT_EXIT
#ifdef LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_WAYLAND_BUF_COUNT
#define LV_WAYLAND_BUF_COUNT CONFIG_LV_WAYLAND_BUF_COUNT
#ifdef CONFIG_LV_WAYLAND_DIRECT_EXIT
#define LV_WAYLAND_DIRECT_EXIT CONFIG_LV_WAYLAND_DIRECT_EXIT
#else
#define LV_WAYLAND_BUF_COUNT 0
#define LV_WAYLAND_DIRECT_EXIT 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. Not supported using DMABUF*/
#define LV_WAYLAND_DIRECT_EXIT 1 /**< 1: Exit the application when all Wayland windows are closed */
#endif
#endif
#endif
@@ -4754,10 +4732,19 @@ 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
#endif /* LV_USE_WAYLAND */
#if LV_USE_WAYLAND
/*Automatically detect wayland backend*/
#if LV_USE_G2D
#define LV_WAYLAND_USE_G2D 1
#define LV_WAYLAND_USE_SHM 0
#else
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 1
#endif
#else
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 0
#endif
#if LV_USE_LINUX_DRM == 0
#define LV_LINUX_DRM_USE_EGL 0
+4
View File
@@ -42,6 +42,7 @@
#include "debugging/sysmon/lv_sysmon_private.h"
#include "others/translation/lv_translation.h"
#include "xml/lv_xml.h"
#include "drivers/wayland/lv_wayland_private.h"
#if LV_USE_SVG
#include "libs/svg/lv_svg_decoder.h"
@@ -484,6 +485,9 @@ void lv_deinit(void)
#endif
#endif
#if LV_USE_WAYLAND
lv_wayland_deinit();
#endif
#if LV_USE_G2D
#if LV_USE_DRAW_G2D || LV_USE_ROTATE_G2D
lv_draw_g2d_deinit();
-1
View File
@@ -150,7 +150,6 @@
#ifndef LV_USE_WAYLAND
#define LV_USE_WAYLAND 1
#define LV_WAYLAND_WINDOW_DECORATIONS 1
#endif
#define LV_USE_ILI9341 1
-3
View File
@@ -1135,9 +1135,6 @@
/** 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 */
#endif
/** Driver for /dev/fb */
#define LV_USE_LINUX_FBDEV 0