From 6cd095724e08199f75f0b0c817b07ae9fc5cd61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Costa?= Date: Mon, 1 Dec 2025 18:02:27 +0100 Subject: [PATCH] feat(wayland): rewrite driver (#9195) Co-authored-by: ychsiao168 --- Kconfig | 32 +- .../embedded_linux/drivers/wayland.rst | 203 ++++-- env_support/cmsis-pack/lv_conf_cmsis.h | 1 - lv_conf_template.h | 6 +- lvgl.h | 12 +- scripts/generate_lv_conf.py | 6 +- scripts/lv_conf_internal_gen.py | 17 +- src/drivers/wayland/lv_wayland.c | 428 ++--------- src/drivers/wayland/lv_wayland_private.h | 391 +++------- src/drivers/wayland/lv_wayland_smm.c | 674 ----------------- src/drivers/wayland/lv_wayland_smm.h | 105 --- src/drivers/wayland/lv_wl_backend_private.h | 206 ++++++ src/drivers/wayland/lv_wl_cache.c | 133 ---- src/drivers/wayland/lv_wl_dmabuf.c | 689 ------------------ src/drivers/wayland/lv_wl_g2d_backend.c | 648 ++++++++++++++++ src/drivers/wayland/lv_wl_keyboard.c | 253 ++++--- src/drivers/wayland/lv_wl_pointer.c | 232 +++--- src/drivers/wayland/lv_wl_pointer_axis.c | 79 -- src/drivers/wayland/lv_wl_seat.c | 104 ++- src/drivers/wayland/lv_wl_shm.c | 473 ------------ src/drivers/wayland/lv_wl_shm_backend.c | 398 ++++++++++ src/drivers/wayland/lv_wl_touch.c | 206 +++--- src/drivers/wayland/lv_wl_window.c | 470 ++++-------- src/drivers/wayland/lv_wl_window.h | 10 +- .../wayland/lv_wl_window_decorations.c | 382 ---------- src/drivers/wayland/lv_wl_xdg_shell.c | 435 +++-------- src/lv_api_map_v9_4.h | 3 +- src/lv_conf_internal.h | 49 +- src/lv_init.c | 4 + tests/src/lv_test_conf_full.h | 1 - tests/src/lv_test_perf_conf.h | 3 - 31 files changed, 2295 insertions(+), 4358 deletions(-) delete mode 100644 src/drivers/wayland/lv_wayland_smm.c delete mode 100644 src/drivers/wayland/lv_wayland_smm.h create mode 100644 src/drivers/wayland/lv_wl_backend_private.h delete mode 100644 src/drivers/wayland/lv_wl_cache.c delete mode 100644 src/drivers/wayland/lv_wl_dmabuf.c create mode 100644 src/drivers/wayland/lv_wl_g2d_backend.c delete mode 100644 src/drivers/wayland/lv_wl_pointer_axis.c delete mode 100644 src/drivers/wayland/lv_wl_shm.c create mode 100644 src/drivers/wayland/lv_wl_shm_backend.c delete mode 100644 src/drivers/wayland/lv_wl_window_decorations.c diff --git a/Kconfig b/Kconfig index 6e288ad9e3..54ceb5ebc7 100644 --- a/Kconfig +++ b/Kconfig @@ -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" diff --git a/docs/src/integration/embedded_linux/drivers/wayland.rst b/docs/src/integration/embedded_linux/drivers/wayland.rst index bcc4263ccf..9f467fdf43 100644 --- a/docs/src/integration/embedded_linux/drivers/wayland.rst +++ b/docs/src/integration/embedded_linux/drivers/wayland.rst @@ -4,20 +4,22 @@ Wayland Display/Inputs driver ============================= + + Overview --------- +******** -The **Wayland** `driver `__ -offers support for simulating the LVGL display and keyboard/mouse inputs in a desktop -window. +The Wayland `driver `__ 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 `__ 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 `__ - -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 `__ +The `reference project `__ 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 - diff --git a/env_support/cmsis-pack/lv_conf_cmsis.h b/env_support/cmsis-pack/lv_conf_cmsis.h index fcaa3785e2..66d54069a3 100644 --- a/env_support/cmsis-pack/lv_conf_cmsis.h +++ b/env_support/cmsis-pack/lv_conf_cmsis.h @@ -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 */ diff --git a/lv_conf_template.h b/lv_conf_template.h index e8182f7092..c3331ecbfb 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -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 */ diff --git a/lvgl.h b/lvgl.h index de3f7b40a4..61fc888f62 100644 --- a/lvgl.h +++ b/lvgl.h @@ -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 diff --git a/scripts/generate_lv_conf.py b/scripts/generate_lv_conf.py index 5e0bb1aa60..bdd62e7eb4 100755 --- a/scripts/generate_lv_conf.py +++ b/scripts/generate_lv_conf.py @@ -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 diff --git a/scripts/lv_conf_internal_gen.py b/scripts/lv_conf_internal_gen.py index 7909c84ff6..599e4ddd97 100755 --- a/scripts/lv_conf_internal_gen.py +++ b/scripts/lv_conf_internal_gen.py @@ -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 diff --git a/src/drivers/wayland/lv_wayland.c b/src/drivers/wayland/lv_wayland.c index 10cee82b9b..58e9c7efed 100644 --- a/src/drivers/wayland/lv_wayland.c +++ b/src/drivers/wayland/lv_wayland.c @@ -6,67 +6,28 @@ * INCLUDES *********************/ -#include "lv_wayland.h" +#include "lv_wayland_private.h" #if LV_USE_WAYLAND -#if LV_USE_G2D - #if LV_USE_ROTATE_G2D - #if !LV_WAYLAND_USE_DMABUF - #error "LV_USE_ROTATE_G2D is supported only with DMABUF" - #endif - #if LV_WAYLAND_BUF_COUNT != 3 - #error "LV_WAYLAND_BUF_COUNT must be 3 when LV_USE_ROTATE_G2D is enabled" - #endif - #define LV_WAYLAND_CHECK_BUF_COUNT 0 - #endif -#endif - -#ifndef LV_WAYLAND_CHECK_BUF_COUNT - #if LV_WAYLAND_BUF_COUNT < 1 || LV_WAYLAND_BUF_COUNT > 2 - #error "Invalid LV_WAYLAND_BUF_COUNT. Expected either 1 or 2" - #endif - - #if !LV_WAYLAND_USE_DMABUF && LV_WAYLAND_BUF_COUNT != 1 - #error "Wayland doesn't support more than 1 LV_WAYLAND_BUF_COUNT without DMABUF" - #endif - - #if LV_WAYLAND_USE_DMABUF && LV_WAYLAND_BUF_COUNT != 2 - #error "Wayland with DMABUF only supports 2 LV_WAYLAND_BUF_COUNT" - #endif -#endif - -#if LV_WAYLAND_USE_DMABUF && !LV_USE_G2D - #error "LV_WAYLAND_USE_DMABUF requires LV_USE_G2D" -#endif - -#ifndef LV_DISPLAY_RENDER_MODE_PARTIAL - /* FIXME: Hacky fix else building fails with -Wundef=error*/ - #define LV_DISPLAY_RENDER_MODE_PARTIAL 0 - #define LV_DISPLAY_RENDER_MODE_DIRECT 1 - #define LV_DISPLAY_RENDER_MODE_FULL 2 -#endif - -#if LV_WAYLAND_USE_DMABUF && LV_WAYLAND_RENDER_MODE == LV_DISPLAY_RENDER_MODE_PARTIAL - #error "LV_WAYLAND_USE_DMABUF doesn't support LV_DISPLAY_RENDER_MODE_PARTIAL" -#endif - -#if !LV_WAYLAND_USE_DMABUF && LV_WAYLAND_RENDER_MODE != LV_DISPLAY_RENDER_MODE_PARTIAL - #error "Wayland without DMABUF only supports LV_DISPLAY_RENDER_MODE_PARTIAL" -#endif - #if (LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1) #error[wayland] Unsupported LV_COLOR_DEPTH #endif +#ifdef LV_WAYLAND_WINDOW_DECORATIONS + #if LV_WAYLAND_WINDOW_DECORATIONS == 1 + #warning LV_WAYLAND_WINDOW_DECORATIONS has been removed for v9.5. \ + It's now the user's responsability to generate their own window decorations. Server side window decorations will be \ + added before the v9.5 release. + #endif +#endif + #include "lv_wayland_private.h" #include #include #include -#include #include #include -#include #include #include #include @@ -77,12 +38,6 @@ #include #include -#if LV_WAYLAND_USE_DMABUF - #include -#endif - -#include "lvgl.h" - /********************* * DEFINES *********************/ @@ -92,7 +47,6 @@ * TYPEDEFS **********************/ -struct lv_wayland_context lv_wl_ctx; /********************** * STATIC PROTOTYPES @@ -101,8 +55,6 @@ struct lv_wayland_context lv_wl_ctx; static void handle_global(void * data, struct wl_registry * registry, uint32_t name, const char * interface, uint32_t version); static void handle_global_remove(void * data, struct wl_registry * registry, uint32_t name); -static void handle_input(void); -static void handle_output(void); static uint32_t tick_get_cb(void); @@ -117,7 +69,8 @@ static void output_geometry(void * data, struct wl_output * output, int32_t x, i * STATIC VARIABLES **********************/ -static bool is_wayland_initialized = false; +static bool is_wayland_initialized = false; +lv_wl_ctx_t lv_wl_ctx; static const struct wl_registry_listener registry_listener = { .global = handle_global, @@ -141,247 +94,98 @@ static const struct wl_output_listener output_listener = { */ int lv_wayland_get_fd(void) { - return wl_display_get_fd(lv_wl_ctx.display); -} - -uint32_t lv_wayland_timer_handler(void) -{ - struct window * window; - - /* Wayland input handling - it will also trigger the frame done handler */ - handle_input(); - - /* Ready input timers (to probe for any input received) */ - LV_LL_READ(&lv_wl_ctx.window_ll, window) { - LV_LOG_TRACE("handle timer frame: %d", window->frame_counter); - - if(window != NULL && window->resize_pending) { -#if LV_WAYLAND_USE_DMABUF - /* Check surface configuration state before resizing */ - if(!window->surface_configured) { - LV_LOG_TRACE("Deferring resize - surface not configured yet"); - continue; - } -#endif - LV_LOG_TRACE("Processing resize: %dx%d -> %dx%d", - window->width, window->height, - window->resize_width, window->resize_height); - - if(lv_wayland_window_resize(window, window->resize_width, window->resize_height) == LV_RESULT_OK) { - window->resize_width = window->width; - window->resize_height = window->height; - window->resize_pending = false; -#if LV_WAYLAND_USE_DMABUF - /* Reset synchronization flags after successful resize */ - window->surface_configured = false; - window->dmabuf_resize_pending = false; -#endif - LV_LOG_TRACE("Window resize completed successfully: %dx%d", - window->width, window->height); - } - else { - LV_LOG_ERROR("Failed to resize window frame: %d", window->frame_counter); - } - } - else if(window->shall_close == true) { - - /* Destroy graphical context and execute close_cb */ - handle_output(); - lv_wayland_deinit(); - return 0; - } + if(!is_wayland_initialized) { + LV_LOG_ERROR("Wayland is not initialized"); + return -1; } - - /* LVGL handling */ - uint32_t idle_time = lv_timer_handler(); - - /* Wayland output handling */ - handle_output(); - - /* Set 'errno' if a Wayland flush is outstanding (i.e. data still needs to - * be sent to the compositor, but the compositor pipe/connection is unable - * to take more data at this time). - */ - LV_LL_READ(&lv_wl_ctx.window_ll, window) { - if(window->flush_pending) { - errno = EAGAIN; - break; - } - } - - return idle_time; + return wl_display_get_fd(lv_wl_ctx.wl_display); } /********************** * PRIVATE FUNCTIONS **********************/ -void lv_wayland_init(void) +lv_result_t lv_wayland_init(void) { if(is_wayland_initialized) { - return; + return LV_RESULT_OK; + } + lv_memset(&lv_wl_ctx, 0, sizeof(lv_wl_ctx)); + + /* Connect to Wayland display */ + lv_wl_ctx.wl_display = wl_display_connect(NULL); + if(!lv_wl_ctx.wl_display) { + LV_LOG_ERROR("failed to connect to Wayland server"); + return LV_RESULT_INVALID; } - // Create XKB context - lv_wl_ctx.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - LV_ASSERT_MSG(lv_wl_ctx.xkb_context, "failed to create XKB context"); - if(lv_wl_ctx.xkb_context == NULL) { - return; - } - - // Connect to Wayland display - lv_wl_ctx.display = wl_display_connect(NULL); - LV_ASSERT_MSG(lv_wl_ctx.display, "failed to connect to Wayland server"); - if(lv_wl_ctx.display == NULL) { - return; - } - -#if LV_WAYLAND_USE_DMABUF - lv_wayland_dmabuf_initalize_context(&lv_wl_ctx.dmabuf_ctx); -#endif - lv_wayland_shm_initalize_context(&lv_wl_ctx.shm_ctx); + lv_wl_ctx.backend_data = wl_backend_ops.init(); /* Add registry listener and wait for registry reception */ - lv_wl_ctx.registry = wl_display_get_registry(lv_wl_ctx.display); - wl_registry_add_listener(lv_wl_ctx.registry, ®istry_listener, &lv_wl_ctx); - wl_display_dispatch(lv_wl_ctx.display); - wl_display_roundtrip(lv_wl_ctx.display); + lv_wl_ctx.wl_registry = wl_display_get_registry(lv_wl_ctx.wl_display); + wl_registry_add_listener(lv_wl_ctx.wl_registry, ®istry_listener, &lv_wl_ctx); + wl_display_dispatch(lv_wl_ctx.wl_display); + wl_display_roundtrip(lv_wl_ctx.wl_display); + + LV_ASSERT_MSG(lv_wl_ctx.wl_compositor, "Wayland compositor not available"); + if(!lv_wl_ctx.wl_compositor) { + LV_LOG_ERROR("Wayland compositor is not available"); + wl_display_disconnect(lv_wl_ctx.wl_display); + lv_wl_ctx.wl_display = NULL; + return LV_RESULT_INVALID; - LV_ASSERT_MSG(lv_wl_ctx.compositor, "Wayland compositor not available"); - if(lv_wl_ctx.compositor == NULL) { - return; } - bool shm_ready = lv_wayland_shm_is_ready(&lv_wl_ctx.shm_ctx); - LV_ASSERT_MSG(shm_ready, "Couldn't initialize wayland SHM"); - if(!shm_ready) { - LV_LOG_ERROR("Couldn't initialize wayland SHM"); - return; - } - lv_wl_ctx.cursor_theme = lv_wayland_shm_load_cursor_theme(&lv_wl_ctx.shm_ctx); - if(!lv_wl_ctx.cursor_theme) { - LV_LOG_WARN("Failed to initialize the cursor theme"); - } - -#if LV_WAYLAND_USE_DMABUF - bool dmabuf_ready = lv_wayland_dmabuf_is_ready(&lv_wl_ctx.dmabuf_ctx); - LV_ASSERT_MSG(dmabuf_ready, "Couldn't initialize wayland DMABUF"); - if(!dmabuf_ready) { - LV_LOG_ERROR("Couldn't initialize wayland DMABUF"); - return; - } -#endif - -#ifdef LV_WAYLAND_WINDOW_DECORATIONS - const char * env_disable_decorations = getenv("LV_WAYLAND_DISABLE_WINDOWDECORATION"); - lv_wl_ctx.opt_disable_decorations = ((env_disable_decorations != NULL) && (env_disable_decorations[0] != '0')); -#endif - - lv_ll_init(&lv_wl_ctx.window_ll, sizeof(struct window)); + lv_ll_init(&lv_wl_ctx.window_ll, sizeof(lv_wl_window_t)); lv_tick_set_cb(tick_get_cb); - /* Used to wait for events when the window is minimized or hidden */ - lv_wl_ctx.wayland_pfd.fd = wl_display_get_fd(lv_wl_ctx.display); - lv_wl_ctx.wayland_pfd.events = POLLIN; - is_wayland_initialized = true; + return LV_RESULT_OK; } void lv_wayland_deinit(void) { - struct window * window = NULL; + lv_wl_window_t * window = NULL; LV_LL_READ(&lv_wl_ctx.window_ll, window) { - if(!window->closed) { - lv_wayland_window_destroy(window); - } - - /* TODO: This should probably be moved inside lv_wayland_window_destroy but not sure about the if condition */ -#if LV_WAYLAND_USE_DMABUF - lv_wayland_dmabuf_destroy_draw_buffers(&lv_wl_ctx.dmabuf_ctx, window); -#else - lv_wayland_shm_delete_draw_buffers(&lv_wl_ctx.shm_ctx, window); -#endif - lv_display_delete(window->lv_disp); + lv_wayland_window_delete(window); } - lv_wayland_shm_deinit(&lv_wl_ctx.shm_ctx); -#if LV_WAYLAND_USE_DMABUF - lv_wayland_dmabuf_deinit(&lv_wl_ctx.dmabuf_ctx); -#endif + lv_wayland_xdg_deinit(); - lv_wayland_xdg_shell_deinit(); - - if(lv_wl_ctx.wl_seat) { - wl_seat_destroy(lv_wl_ctx.wl_seat); + if(is_wayland_initialized) { + wl_backend_ops.deinit(lv_wl_ctx.backend_data); } - if(lv_wl_ctx.subcompositor) { - wl_subcompositor_destroy(lv_wl_ctx.subcompositor); + if(lv_wl_ctx.seat.wl_seat) { + lv_wayland_seat_deinit(&lv_wl_ctx.seat); + lv_wl_ctx.seat.wl_seat = NULL; } - if(lv_wl_ctx.compositor) { - wl_compositor_destroy(lv_wl_ctx.compositor); + if(lv_wl_ctx.wl_registry) { + wl_registry_destroy(lv_wl_ctx.wl_registry); + lv_wl_ctx.wl_registry = NULL; } - wl_registry_destroy(lv_wl_ctx.registry); - wl_display_flush(lv_wl_ctx.display); - wl_display_disconnect(lv_wl_ctx.display); + if(lv_wl_ctx.wl_compositor) { + wl_compositor_destroy(lv_wl_ctx.wl_compositor); + lv_wl_ctx.wl_compositor = NULL; + } + if(lv_wl_ctx.wl_display) { + wl_display_disconnect(lv_wl_ctx.wl_display); + lv_wl_ctx.wl_display = NULL; + } lv_ll_clear(&lv_wl_ctx.window_ll); -} - -void lv_wayland_wait_flush_cb(lv_display_t * disp) -{ - struct window * window = lv_display_get_driver_data(disp); - /* TODO: Figure out why we need this */ - if(window->frame_counter == 0) { - return; - } - uint32_t initial_frame_counter = window->frame_counter; - while(initial_frame_counter == window->frame_counter) { - poll(&lv_wl_ctx.wayland_pfd, 1, -1); - handle_input(); - } -} - -void lv_wayland_event_cb(lv_event_t * e) -{ - lv_event_code_t code = lv_event_get_code(e); - struct window * window = lv_event_get_user_data(e); - lv_display_t * display = (lv_display_t *) lv_event_get_target(e); - - switch(code) { - case LV_EVENT_RESOLUTION_CHANGED: { - uint32_t rotation = lv_display_get_rotation(window->lv_disp); - int width, height; - if(rotation == LV_DISPLAY_ROTATION_90 || rotation == LV_DISPLAY_ROTATION_270) { - width = lv_display_get_vertical_resolution(display); - height = lv_display_get_horizontal_resolution(display); - } - else { - width = lv_display_get_horizontal_resolution(display); - height = lv_display_get_vertical_resolution(display); - } -#if LV_WAYLAND_USE_DMABUF - dmabuf_ctx_t * context = &window->wl_ctx->dmabuf_ctx; - lv_wayland_dmabuf_resize_window(context, window, width, height); -#else - lv_wayland_shm_resize_window(&window->wl_ctx->shm_ctx, window, width, height); -#endif - break; - } - default: - return; - } + is_wayland_initialized = false; } /********************** * STATIC FUNCTIONS **********************/ -// --- wl_output listener callbacks --- + static void output_geometry(void * data, struct wl_output * output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char * make, const char * model, int32_t transform) @@ -395,7 +199,7 @@ static void output_geometry(void * data, struct wl_output * output, int32_t x, i LV_UNUSED(make); LV_UNUSED(transform); - struct output_info * info = data; + lv_wl_output_info_t * info = data; snprintf(info->name, sizeof(info->name), "%s", model); } @@ -404,7 +208,7 @@ static void output_mode(void * data, struct wl_output * wl_output, uint32_t flag { LV_UNUSED(wl_output); - struct output_info * info = data; + lv_wl_output_info_t * info = data; if(flags & WL_OUTPUT_MODE_CURRENT) { info->height = height; @@ -424,7 +228,7 @@ static void output_done(void * data, struct wl_output * output) static void output_scale(void * data, struct wl_output * output, int32_t factor) { LV_UNUSED(output); - struct output_info * info = data; + lv_wl_output_info_t * info = data; info->scale = factor; } @@ -438,122 +242,42 @@ static uint32_t tick_get_cb(void) static void handle_global(void * data, struct wl_registry * registry, uint32_t name, const char * interface, uint32_t version) { - struct lv_wayland_context * app = data; + lv_wl_ctx_t * ctx = data; - LV_UNUSED(version); LV_UNUSED(data); if(strcmp(interface, wl_compositor_interface.name) == 0) { - app->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); - } - else if(strcmp(interface, wl_subcompositor_interface.name) == 0) { - app->subcompositor = wl_registry_bind(registry, name, &wl_subcompositor_interface, 1); + ctx->wl_compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); } else if(strcmp(interface, wl_shm_interface.name) == 0) { - - lv_wayland_shm_set_interface(&app->shm_ctx, app->registry, name, interface, version); - + /* Regardless of the backend, we always need SHM for the pointer cursor*/ + ctx->wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if(strcmp(interface, wl_seat_interface.name) == 0) { - app->wl_seat = wl_registry_bind(app->registry, name, &wl_seat_interface, 1); - wl_seat_add_listener(app->wl_seat, lv_wayland_seat_get_listener(), app); + lv_wayland_seat_init(&ctx->seat, registry, name, version); } else if(strcmp(interface, xdg_wm_base_interface.name) == 0) { - /* supporting version 2 of the XDG protocol - ensures greater compatibility */ - app->xdg_wm = wl_registry_bind(app->registry, name, &xdg_wm_base_interface, 2); - xdg_wm_base_add_listener(app->xdg_wm, lv_wayland_xdg_shell_get_wm_base_listener(), app); + ctx->xdg_wm = wl_registry_bind(ctx->wl_registry, name, &xdg_wm_base_interface, LV_MIN(version, 2)); + xdg_wm_base_add_listener(ctx->xdg_wm, lv_wayland_xdg_get_wm_base_listener(), ctx); } else if(strcmp(interface, wl_output_interface.name) == 0) { - if(app->wl_output_count < LV_WAYLAND_MAX_OUTPUTS) { - memset(&app->outputs[app->wl_output_count], 0, sizeof(struct output_info)); + if(ctx->wl_output_count < LV_WAYLAND_MAX_OUTPUTS) { + memset(&ctx->physical_outputs[ctx->wl_output_count], 0, sizeof(lv_wl_output_info_t)); struct wl_output * out = wl_registry_bind(registry, name, &wl_output_interface, 1); - app->outputs[app->wl_output_count].wl_output = out; - wl_output_add_listener(out, &output_listener, &app->outputs[app->wl_output_count].wl_output); - app->wl_output_count++; + ctx->physical_outputs[ctx->wl_output_count].wl_output = out; + wl_output_add_listener(out, &output_listener, &ctx->physical_outputs[ctx->wl_output_count].wl_output); + ctx->wl_output_count++; } } -#if LV_WAYLAND_USE_DMABUF - else if(strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) { - lv_wayland_dmabuf_set_interface(&app->dmabuf_ctx, app->registry, name, interface, version); - wl_display_roundtrip(app->display); - } -#endif + wl_backend_ops.global_handler(lv_wl_ctx.backend_data, registry, name, interface, version); } static void handle_global_remove(void * data, struct wl_registry * registry, uint32_t name) { - LV_UNUSED(data); LV_UNUSED(registry); LV_UNUSED(name); } -static void handle_input(void) -{ - int prepare_read = -1; - - while(prepare_read != 0) { - wl_display_dispatch_pending(lv_wl_ctx.display); - prepare_read = wl_display_prepare_read(lv_wl_ctx.display); - } - wl_display_read_events(lv_wl_ctx.display); - wl_display_dispatch_pending(lv_wl_ctx.display); -} - -static void handle_output(void) -{ - struct window * window; - bool shall_flush = lv_wl_ctx.cursor_flush_pending; - - LV_LL_READ(&lv_wl_ctx.window_ll, window) { - if((window->shall_close) && (window->close_cb != NULL)) { - window->shall_close = window->close_cb(window->lv_disp); - } - - if(window->closed) { - continue; - } - else if(window->shall_close) { - window->closed = true; - window->shall_close = false; - shall_flush = true; - - window->body->input.pointer.x = 0; - window->body->input.pointer.y = 0; - window->body->input.pointer.left_button = LV_INDEV_STATE_RELEASED; - window->body->input.pointer.right_button = LV_INDEV_STATE_RELEASED; - window->body->input.pointer.wheel_button = LV_INDEV_STATE_RELEASED; - window->body->input.pointer.wheel_diff = 0; - if(window->wl_ctx->pointer_obj == window->body) { - window->wl_ctx->pointer_obj = NULL; - } - - window->body->input.keyboard.key = 0; - window->body->input.keyboard.state = LV_INDEV_STATE_RELEASED; - if(window->wl_ctx->keyboard_obj == window->body) { - window->wl_ctx->keyboard_obj = NULL; - } - lv_wayland_window_destroy(window); - } - - shall_flush |= window->flush_pending; - } - - if(shall_flush) { - if(wl_display_flush(lv_wl_ctx.display) == -1) { - if(errno != EAGAIN) { - LV_LOG_ERROR("failed to flush wayland display"); - } - } - else { - /* All data flushed */ - lv_wl_ctx.cursor_flush_pending = false; - LV_LL_READ(&lv_wl_ctx.window_ll, window) { - window->flush_pending = false; - } - } - } -} - #endif /* LV_USE_WAYLAND */ diff --git a/src/drivers/wayland/lv_wayland_private.h b/src/drivers/wayland/lv_wayland_private.h index 92b3a08706..2a1f3b55e1 100644 --- a/src/drivers/wayland/lv_wayland_private.h +++ b/src/drivers/wayland/lv_wayland_private.h @@ -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 #include #include - -#if LV_WAYLAND_USE_DMABUF -#include -#include -#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 */ diff --git a/src/drivers/wayland/lv_wayland_smm.c b/src/drivers/wayland/lv_wayland_smm.c deleted file mode 100644 index 168e45de81..0000000000 --- a/src/drivers/wayland/lv_wayland_smm.c +++ /dev/null @@ -1,674 +0,0 @@ -/** - * @file lv_wayland_smm.c - * - */ - -typedef int dummy_t; /* Make GCC on windows happy, avoid empty translation unit */ - -#ifndef _WIN32 - -#include "lv_wayland_smm.h" - -#if LV_USE_WAYLAND - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_NAME_ATTEMPTS (5) -#define PREFER_NUM_BUFFERS (3) - -#define ROUND_UP(n, b) (((((n) ? (n) : 1) + (b) - 1) / (b)) * (b)) -#define LLHEAD(type) \ - struct { \ - struct type *first; \ - struct type *last; \ - } - -#define LLLINK(type) \ - struct { \ - struct type *next; \ - struct type *prev; \ - } - -#define LL_FIRST(head) ((head)->first) -#define LL_LAST(head) ((head)->last) -#define LL_IS_EMPTY(head) (LL_FIRST(head) == NULL) -#define LL_NEXT(src, member) ((src)->member.next) -#define LL_PREV(src, member) ((src)->member.prev) - -#define LL_INIT(head) do { \ - (head)->first = NULL; \ - (head)->last = NULL; \ - } while (0) - -#define LL_ENQUEUE(head, src, member) do { \ - (src)->member.next = NULL; \ - (src)->member.prev = (head)->last; \ - if ((head)->last == NULL) { \ - (head)->first = (src); \ - } else { \ - (head)->last->member.next = (src); \ - } \ - (head)->last = (src); \ - } while (0) - -#define LL_DEQUEUE(entry, head, member) do { \ - (entry) = LL_FIRST(head); \ - LL_REMOVE(head, entry, member); \ - } while (0) - -#define LL_INSERT_AFTER(head, dest, src, member) do { \ - (src)->member.prev = (dest); \ - (src)->member.next = (dest)->member.next; \ - if ((dest)->member.next != NULL) { \ - (dest)->member.next->member.prev = (src); \ - } else { \ - (head)->last = (src); \ - } \ - (dest)->member.next = (src); \ - } while (0) - -#define LL_REMOVE(head, src, member) do { \ - if ((src)->member.prev != NULL) { \ - (src)->member.prev->member.next = (src)->member.next; \ - } else { \ - (head)->first = (src)->member.next; \ - } \ - if ((src)->member.next != NULL) { \ - (src)->member.next->member.prev = (src)->member.prev; \ - } else { \ - (head)->last = (src)->member.prev; \ - } \ - } while (0) - -#define LL_FOREACH(entry, head, member) \ - for ((entry) = LL_FIRST(head); \ - (entry) != NULL; \ - (entry) = LL_NEXT(entry, member)) - -#define WAYLAND_FD_NAME "/" SMM_FD_NAME "-XXXXX" - -struct smm_pool { - struct smm_pool_properties props; - LLHEAD(smm_buffer) allocd; - void * map; - size_t map_size; - bool map_outdated; -}; - -struct smm_buffer { - struct smm_buffer_properties props; - bool group_resized; - LLLINK(smm_buffer) pool; - LLLINK(smm_buffer) use; - LLLINK(smm_buffer) age; -}; - -struct smm_group { - struct smm_group_properties props; - size_t size; - unsigned char num_buffers; - LLHEAD(smm_buffer) unused; - LLHEAD(smm_buffer) inuse; - LLHEAD(smm_buffer) history; - LLLINK(smm_group) link; -}; - -static size_t calc_buffer_size(struct smm_buffer * buf); -static void purge_history(struct smm_buffer * buf); -static struct smm_buffer * get_from_pool(struct smm_group * grp); -static void return_to_pool(struct smm_buffer * buf); -static struct smm_pool * alloc_pool(void); -static void free_pool(struct smm_pool * pool); -static struct smm_buffer * alloc_buffer(struct smm_buffer * last, size_t offset); -static void free_buffer(struct smm_buffer * buf); - -static struct { - unsigned long page_sz; - struct smm_events cbs; - struct smm_pool * active; - LLHEAD(smm_group) groups; - struct { - size_t active_used; - } statistics; -} smm_instance; - - -void smm_init(const struct smm_events * evs) -{ - memcpy(&smm_instance.cbs, evs, sizeof(struct smm_events)); - srand((unsigned int)clock()); - smm_instance.page_sz = (unsigned long)sysconf(_SC_PAGESIZE); - LL_INIT(&smm_instance.groups); -} - - -void smm_deinit(void) -{ - struct smm_group * grp; - - /* Destroy all buffer groups */ - while(!LL_IS_EMPTY(&smm_instance.groups)) { - LL_DEQUEUE(grp, &smm_instance.groups, link); - smm_destroy(grp); - } -} - - -void smm_setctx(void * ctx) -{ - smm_instance.cbs.ctx = ctx; -} - - -smm_group_t * smm_create(void) -{ - struct smm_group * grp; - - /* Allocate and initialize a new buffer group */ - grp = malloc(sizeof(struct smm_group)); - if(grp != NULL) { - grp->size = smm_instance.page_sz; - grp->num_buffers = 0; - LL_INIT(&grp->unused); - LL_INIT(&grp->inuse); - LL_INIT(&grp->history); - - /* Add to instance groups queue */ - LL_ENQUEUE(&smm_instance.groups, grp, link); - } - - return grp; -} - - -void smm_resize(smm_group_t * grp, size_t sz) -{ - struct smm_buffer * buf; - struct smm_group * rgrp = grp; - - /* Round allocation size up to a sysconf(_SC_PAGE_SIZE) boundary */ - rgrp->size = ROUND_UP(sz, smm_instance.page_sz); - - /* Return all unused buffers to pool (to be re-allocated at the new size) */ - while(!LL_IS_EMPTY(&rgrp->unused)) { - LL_DEQUEUE(buf, &rgrp->unused, use); - return_to_pool(buf); - } - - /* Mark all buffers in use to be freed to pool when possible */ - LL_FOREACH(buf, &rgrp->inuse, use) { - buf->group_resized = true; - purge_history(buf); - } -} - - -void smm_destroy(smm_group_t * grp) -{ - struct smm_buffer * buf; - struct smm_group * dgrp = grp; - - /* Return unused buffers */ - while(!LL_IS_EMPTY(&dgrp->unused)) { - LL_DEQUEUE(buf, &dgrp->unused, use); - return_to_pool(buf); - } - - /* Return buffers that are still in use (ideally this queue should be empty - * at this time) - */ - while(!LL_IS_EMPTY(&dgrp->inuse)) { - LL_DEQUEUE(buf, &dgrp->inuse, use); - return_to_pool(buf); - } - - /* Remove from instance groups queue */ - LL_REMOVE(&smm_instance.groups, dgrp, link); - free(dgrp); -} - - -smm_buffer_t * smm_acquire(smm_group_t * grp) -{ - struct smm_buffer * buf; - struct smm_group * agrp = grp; - - if(LL_IS_EMPTY(&agrp->unused)) { - /* No unused buffer available, so get a new one from pool */ - buf = get_from_pool(agrp); - } - else { - /* Otherwise, reuse an unused buffer */ - LL_DEQUEUE(buf, &agrp->unused, use); - } - - if(buf != NULL) { - /* Add buffer to in-use queue */ - LL_ENQUEUE(&agrp->inuse, buf, use); - - /* Emit 'init buffer' event */ - if(smm_instance.cbs.init_buffer != NULL) { - if(smm_instance.cbs.init_buffer(smm_instance.cbs.ctx, &buf->props)) { - smm_release(buf); - buf = NULL; - } - } - - if(buf != NULL) { - /* Remove from history */ - purge_history(buf); - - /* Add to history a-new */ - LL_ENQUEUE(&agrp->history, buf, age); - } - } - - return buf; -} - - -void * smm_map(smm_buffer_t * buf) -{ - struct smm_buffer * mbuf = buf; - struct smm_pool * pool = mbuf->props.pool; - void * map = pool->map; - - if(pool->map_outdated) { - /* Update mapping to current pool size */ - if(pool->map != NULL) { - munmap(pool->map, pool->map_size); - } - - map = mmap(NULL, - pool->props.size, - PROT_READ | PROT_WRITE, - MAP_SHARED, - pool->props.fd, - 0); - - if(map == MAP_FAILED) { - map = NULL; - pool->map = NULL; - } - else { - pool->map = map; - pool->map_size = pool->props.size; - pool->map_outdated = false; - } - } - - /* Calculate buffer mapping (from offset in pool) */ - if(map != NULL) { - map = (((char *)map) + mbuf->props.offset); - } - - return map; -} - - -void smm_release(smm_buffer_t * buf) -{ - struct smm_buffer * rbuf = buf; - struct smm_group * grp = rbuf->props.group; - - /* Remove from in-use queue */ - LL_REMOVE(&grp->inuse, rbuf, use); - - if(rbuf->group_resized) { - /* Buffer group was resized while this buffer was in-use, thus it must be - * returned to it's pool - */ - rbuf->group_resized = false; - return_to_pool(rbuf); - } - else { - /* Move to unused queue */ - LL_ENQUEUE(&grp->unused, rbuf, use); - - /* Try to limit total number of buffers to preferred number */ - while((grp->num_buffers > PREFER_NUM_BUFFERS) && - (!LL_IS_EMPTY(&grp->unused))) { - LL_DEQUEUE(rbuf, &grp->unused, use); - return_to_pool(rbuf); - } - } -} - - -smm_buffer_t * smm_latest(smm_group_t * grp) -{ - struct smm_group * lgrp = grp; - - return LL_LAST(&lgrp->history); -} - - -smm_buffer_t * smm_next(smm_buffer_t * buf) -{ - struct smm_buffer * ibuf; - struct smm_buffer * nbuf = buf; - struct smm_group * grp = nbuf->props.group; - - LL_FOREACH(ibuf, &grp->history, age) { - if(ibuf == nbuf) { - ibuf = LL_NEXT(ibuf, age); - break; - } - } - - return ibuf; -} - -void purge_history(struct smm_buffer * buf) -{ - struct smm_buffer * ibuf; - struct smm_group * grp = buf->props.group; - - /* Remove from history (and any older) */ - LL_FOREACH(ibuf, &grp->history, age) { - if(ibuf == buf) { - do { - LL_DEQUEUE(ibuf, &grp->history, age); - } while(ibuf != buf); - break; - } - } -} - - -size_t calc_buffer_size(struct smm_buffer * buf) -{ - size_t buf_sz; - struct smm_pool * buf_pool = buf->props.pool; - - if(buf == LL_LAST(&buf_pool->allocd)) { - buf_sz = (buf_pool->props.size - buf->props.offset); - } - else { - buf_sz = (LL_NEXT(buf, pool)->props.offset - buf->props.offset); - } - - return buf_sz; -} - - -struct smm_buffer * get_from_pool(struct smm_group * grp) -{ - int ret; - size_t buf_sz = 0; - struct smm_buffer * buf; - struct smm_buffer * last = NULL; - - /* TODO: Determine when to allocate a new active pool (i.e. memory shrink) */ - - if(smm_instance.active == NULL) { - /* Allocate a new active pool */ - smm_instance.active = alloc_pool(); - smm_instance.statistics.active_used = 0; - } - - if(smm_instance.active == NULL) { - buf = NULL; - } - else { - /* Search for a free buffer large enough for allocation */ - LL_FOREACH(buf, &smm_instance.active->allocd, pool) { - last = buf; - if(buf->props.group == NULL) { - buf_sz = calc_buffer_size(buf); - if(buf_sz == grp->size) { - break; - } - else if(buf_sz > grp->size) { - if((buf != LL_LAST(&smm_instance.active->allocd)) && - (LL_NEXT(buf, pool)->props.group == NULL)) { - /* Pull back next buffer to use unallocated size */ - LL_NEXT(buf, pool)->props.offset -= (buf_sz - grp->size); - } - else { - /* Allocate another buffer to hold unallocated size */ - alloc_buffer(buf, buf->props.offset + grp->size); - } - - break; - } - } - } - - if(buf == NULL) { - /* No buffer found to meet allocation size, expand pool */ - if((last != NULL) && - (last->props.group == NULL)) { - /* Use last free buffer */ - buf_sz = (grp->size - buf_sz); - } - else { - /* Allocate new buffer */ - buf_sz = grp->size; - if(last == NULL) { - buf = alloc_buffer(NULL, 0); - } - else { - buf = alloc_buffer(last, smm_instance.active->props.size); - } - last = buf; - } - - if(last != NULL) { - /* Expand pool backing memory */ - ret = ftruncate(smm_instance.active->props.fd, - smm_instance.active->props.size + buf_sz); - if(ret) { - if(buf != NULL) { - free_buffer(buf); - buf = NULL; - } - } - else { - smm_instance.active->props.size += buf_sz; - smm_instance.active->map_outdated = true; - buf = last; - - if(!(smm_instance.active->props.size - buf_sz)) { - /* Emit 'new pool' event */ - if((smm_instance.cbs.new_pool != NULL) && - (smm_instance.cbs.new_pool(smm_instance.cbs.ctx, - &smm_instance.active->props))) { - free_buffer(buf); - free_pool(smm_instance.active); - smm_instance.active = NULL; - buf = NULL; - } - } - else { - /* Emit 'expand pool' event */ - if(smm_instance.cbs.expand_pool != NULL) { - smm_instance.cbs.expand_pool(smm_instance.cbs.ctx, - &smm_instance.active->props); - } - } - } - } - } - } - - if(buf != NULL) { - /* Set buffer group */ - memcpy((void *)&buf->props.group, &grp, sizeof(struct smm_group *)); - - /* Emit 'new buffer' event */ - if(smm_instance.cbs.new_buffer != NULL) { - if(smm_instance.cbs.new_buffer(smm_instance.cbs.ctx, &buf->props)) { - grp = NULL; - memcpy((void *)&buf->props.group, &grp, sizeof(struct smm_group *)); - buf = NULL; - } - } - - if(buf != NULL) { - /* Update active pool usage statistic */ - smm_instance.statistics.active_used += grp->size; - grp->num_buffers++; - } - } - - return buf; -} - - -void return_to_pool(struct smm_buffer * buf) -{ - struct smm_group * grp = buf->props.group; - struct smm_pool * pool = buf->props.pool; - - /* Emit 'free buffer' event */ - if(smm_instance.cbs.free_buffer != NULL) { - smm_instance.cbs.free_buffer(smm_instance.cbs.ctx, &buf->props); - } - - /* Buffer is no longer part of history */ - purge_history(buf); - - /* Buffer is no longer part of group */ - grp->num_buffers--; - grp = NULL; - memcpy((void *)&buf->props.group, &grp, sizeof(struct smm_group *)); - - /* Update active pool usage statistic */ - if(smm_instance.active == pool) { - smm_instance.statistics.active_used -= calc_buffer_size(buf); - } - - /* Coalesce with ungrouped buffers beside this one */ - if((buf != LL_LAST(&pool->allocd)) && - (LL_NEXT(buf, pool)->props.group == NULL)) { - free_buffer(LL_NEXT(buf, pool)); - } - if((buf != LL_FIRST(&pool->allocd)) && - (LL_PREV(buf, pool)->props.group == NULL)) { - buf = LL_PREV(buf, pool); - pool = buf->props.pool; - free_buffer(LL_NEXT(buf, pool)); - } - - /* Free buffer (and pool), if only remaining buffer in pool */ - if((buf == LL_FIRST(&pool->allocd)) && - (buf == LL_LAST(&pool->allocd))) { - free_buffer(buf); - - /* Emit 'free pool' event */ - if(smm_instance.cbs.free_pool != NULL) { - smm_instance.cbs.free_pool(smm_instance.cbs.ctx, &pool->props); - } - - free_pool(pool); - if(smm_instance.active == pool) { - smm_instance.active = NULL; - } - } -} - - -struct smm_pool * alloc_pool(void) -{ - struct smm_pool * pool; - char name[] = WAYLAND_FD_NAME; - unsigned char attempts = 0; - bool opened = false; - - pool = malloc(sizeof(struct smm_pool)); - if(pool != NULL) { - do { - /* A randomized pool name should help reduce collisions */ - sprintf(name + sizeof(SMM_FD_NAME) + 1, "%05X", rand() & 0xFFFF); - pool->props.fd = shm_open(name, - O_RDWR | O_CREAT | O_EXCL, - S_IRUSR | S_IWUSR); - if(pool->props.fd >= 0) { - shm_unlink(name); - pool->props.size = 0; - pool->map = NULL; - pool->map_size = 0; - pool->map_outdated = false; - LL_INIT(&pool->allocd); - opened = true; - break; - } - else { - if(errno != EEXIST) { - break; - } - attempts++; - } - } while(attempts < MAX_NAME_ATTEMPTS); - - if(!opened) { - free(pool); - pool = NULL; - } - } - - return pool; -} - - -void free_pool(struct smm_pool * pool) -{ - if(pool->map != NULL) { - munmap(pool->map, pool->map_size); - } - - close(pool->props.fd); - free(pool); -} - - -struct smm_buffer * alloc_buffer(struct smm_buffer * last, size_t offset) -{ - struct smm_buffer * buf; - struct smm_buffer_properties initial_props = { - {NULL}, - NULL, - smm_instance.active, - offset - }; - - /* Allocate and initialize a new buffer (including linking in to pool) */ - buf = malloc(sizeof(struct smm_buffer)); - if(buf != NULL) { - memcpy(&buf->props, &initial_props, sizeof(struct smm_buffer_properties)); - buf->group_resized = false; - - if(last == NULL) { - LL_ENQUEUE(&smm_instance.active->allocd, buf, pool); - } - else { - LL_INSERT_AFTER(&smm_instance.active->allocd, last, buf, pool); - } - } - - return buf; -} - - -void free_buffer(struct smm_buffer * buf) -{ - struct smm_pool * buf_pool = buf->props.pool; - - /* Remove from pool */ - LL_REMOVE(&buf_pool->allocd, buf, pool); - free(buf); -} - -#endif /* LV_USE_WAYLAND */ -#endif /* _WIN32 */ diff --git a/src/drivers/wayland/lv_wayland_smm.h b/src/drivers/wayland/lv_wayland_smm.h deleted file mode 100644 index f3a16e9e24..0000000000 --- a/src/drivers/wayland/lv_wayland_smm.h +++ /dev/null @@ -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 */ diff --git a/src/drivers/wayland/lv_wl_backend_private.h b/src/drivers/wayland/lv_wl_backend_private.h new file mode 100644 index 0000000000..15067a728f --- /dev/null +++ b/src/drivers/wayland/lv_wl_backend_private.h @@ -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 + +/********************* + * 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*/ diff --git a/src/drivers/wayland/lv_wl_cache.c b/src/drivers/wayland/lv_wl_cache.c deleted file mode 100644 index 5d810516f8..0000000000 --- a/src/drivers/wayland/lv_wl_cache.c +++ /dev/null @@ -1,133 +0,0 @@ -/** - * @file lv_wl_cache.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "lv_wayland.h" - -#if LV_USE_WAYLAND - -#include "lv_wayland_private.h" -#include - -/********************* - * 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 */ diff --git a/src/drivers/wayland/lv_wl_dmabuf.c b/src/drivers/wayland/lv_wl_dmabuf.c deleted file mode 100644 index 0d8ff0b44a..0000000000 --- a/src/drivers/wayland/lv_wl_dmabuf.c +++ /dev/null @@ -1,689 +0,0 @@ -/** - * @file lv_wl_dmabuf.c - * - */ - -#include "lv_wayland.h" - -#if LV_WAYLAND_USE_DMABUF - -#include "lv_wayland_private.h" -#include -#include -#include -#include -#include -#include -#include "../../draw/nxp/g2d/lv_g2d_utils.h" -#include -#include -#include -#include - -/********************* - * INCLUDES - *********************/ - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static void dmabuf_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback); -static void dmabuf_format_table(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - int32_t fd, uint32_t size); -static void dmabuf_main_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - struct wl_array * device); -static void dmabuf_tranche_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback); -static void dmabuf_tranche_target_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - struct wl_array * device); -static void dmabuf_tranche_formats(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - struct wl_array * indices); -static void dmabuf_tranche_flags(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - uint32_t flags); -static void dmabuf_modifiers(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format, - uint32_t modifier_hi, uint32_t modifier_lo); -static void dmabuf_format(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format); -static struct buffer * lv_wayland_dmabuf_create_draw_buffers_internal(struct window * window, int width, int height); -static void buffer_free(struct buffer * buf); -static void dmabuf_wait_swap_buf(lv_display_t * disp); - -#if !LV_USE_ROTATE_G2D - static struct buffer * dmabuf_acquire_buffer(dmabuf_ctx_t * context, unsigned char * color_p); -#else - static struct buffer * get_next_buffer(dmabuf_ctx_t * context); -#endif -/********************** - * STATIC VARIABLES - **********************/ - -static const struct zwp_linux_dmabuf_feedback_v1_listener dmabuf_listener_v5 = { - .done = dmabuf_done, - .format_table = dmabuf_format_table, - .main_device = dmabuf_main_device, - .tranche_done = dmabuf_tranche_done, - .tranche_target_device = dmabuf_tranche_target_device, - .tranche_formats = dmabuf_tranche_formats, - .tranche_flags = dmabuf_tranche_flags, -}; - -static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener_v3 = {.format = dmabuf_format, - .modifier = dmabuf_modifiers -}; -static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {.format = dmabuf_format}; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/********************** - * PRIVATE FUNCTIONS - **********************/ - -void lv_wayland_dmabuf_initalize_context(dmabuf_ctx_t * context) -{ - memset(context, 0, sizeof(*context)); - context->format = DRM_FORMAT_INVALID; - context->last_used = 0; -} -lv_result_t lv_wayland_dmabuf_set_draw_buffers(dmabuf_ctx_t * context, lv_display_t * display) -{ - if(LV_USE_ROTATE_G2D == 1) { - lv_display_set_draw_buffers(display, context->buffers[2].lv_draw_buf, NULL); - return LV_RESULT_OK; - } - if(LV_WAYLAND_BUF_COUNT == 2) { - lv_display_set_draw_buffers(display, context->buffers[0].lv_draw_buf, context->buffers[1].lv_draw_buf); - return LV_RESULT_OK; - } - else if(LV_WAYLAND_BUF_COUNT == 1) { - lv_display_set_draw_buffers(display, context->buffers[0].lv_draw_buf, NULL); - return LV_RESULT_OK; - } - return LV_RESULT_INVALID; -} - -void lv_wayland_dmabuf_set_interface(dmabuf_ctx_t * context, struct wl_registry * registry, uint32_t name, - const char * interface, uint32_t version) -{ - LV_UNUSED(interface); - - context->handler = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version); - - if(version >= 4) { - struct zwp_linux_dmabuf_feedback_v1 * feedback = zwp_linux_dmabuf_v1_get_default_feedback(context->handler); - zwp_linux_dmabuf_feedback_v1_add_listener(feedback, &dmabuf_listener_v5, context); - } - else if(version < 3) { - zwp_linux_dmabuf_v1_add_listener(context->handler, &dmabuf_listener, context); - } - else if(version == 3) { - zwp_linux_dmabuf_v1_add_listener(context->handler, &dmabuf_listener_v3, context); - } -} - -lv_result_t lv_wayland_dmabuf_is_ready(dmabuf_ctx_t * context) -{ - return (context->handler && context->format != DRM_FORMAT_INVALID) ? LV_RESULT_OK : LV_RESULT_INVALID; -} - -void lv_wayland_dmabuf_destroy_window(dmabuf_ctx_t * context, struct window * window) -{ - LV_UNUSED(context); - LV_ASSERT_NULL(window); -} - -void lv_wayland_dmabuf_deinit(dmabuf_ctx_t * context) -{ - LV_UNUSED(context); -} - -struct graphic_object * lv_wayland_dmabuf_on_graphical_object_creation(dmabuf_ctx_t * context, - struct graphic_object * obj) -{ - LV_UNUSED(context); - return obj; -} - -void lv_wayland_dmabuf_on_graphical_object_destruction(dmabuf_ctx_t * context, struct graphic_object * obj) -{ - - LV_UNUSED(context); - LV_UNUSED(obj); -} - -static void dmabuf_wait_swap_buf(lv_display_t * disp) -{ - struct window * window = lv_display_get_driver_data(disp); - - if(window->frame_counter == 0) { - return; - } - -#if LV_USE_ROTATE_G2D - int buf_nr = (window->wl_ctx->dmabuf_ctx.last_used + 1) % (LV_WAYLAND_BUF_COUNT - 1); -#else - int buf_nr = (window->wl_ctx->dmabuf_ctx.last_used + 1) % LV_WAYLAND_BUF_COUNT; -#endif - - while(window->wl_ctx->dmabuf_ctx.buffers[buf_nr].busy) { - wl_display_roundtrip(lv_wl_ctx.display); - usleep(500); /* Sleep for 0.5ms to avoid busy waiting */ - } -} - -void lv_wayland_dmabuf_flush_full_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p) -{ - struct window * window = lv_display_get_driver_data(disp); - struct buffer * buf; - int32_t src_width = lv_area_get_width(area); - int32_t src_height = lv_area_get_height(area); - uint32_t rotation = lv_display_get_rotation(window->lv_disp); -#if LV_USE_ROTATE_G2D - LV_UNUSED(color_p); - buf = get_next_buffer(&window->wl_ctx->dmabuf_ctx); - if(rotation == LV_DISPLAY_ROTATION_90 || rotation == LV_DISPLAY_ROTATION_270) { - src_width = lv_area_get_height(area); - src_height = lv_area_get_width(area); - } -#else - buf = dmabuf_acquire_buffer(&window->wl_ctx->dmabuf_ctx, color_p); -#endif - if(!buf) { - LV_LOG_ERROR("Failed to acquire a wayland window body buffer"); - return; - } - - lv_draw_buf_invalidate_cache(buf->lv_draw_buf, NULL); -#if LV_USE_ROTATE_G2D - lv_draw_buf_invalidate_cache(window->wl_ctx->dmabuf_ctx.buffers[2].lv_draw_buf, NULL); -#endif - - const bool force_full_flush = LV_WAYLAND_RENDER_MODE == LV_DISPLAY_RENDER_MODE_DIRECT && - rotation != LV_DISPLAY_ROTATION_0; - /* Mark surface damage */ - if(!force_full_flush) { - wl_surface_damage(window->body->surface, area->x1, area->y1, src_width, src_height); - } - - if(lv_display_flush_is_last(disp)) { - if(force_full_flush) { - wl_surface_damage(window->body->surface, 0, 0, lv_display_get_original_horizontal_resolution(disp), - lv_display_get_original_vertical_resolution(disp)); - } -#if LV_USE_ROTATE_G2D - g2d_rotate(window->wl_ctx->dmabuf_ctx.buffers[2].lv_draw_buf, buf->lv_draw_buf, window->width, window->height, - lv_display_get_rotation(window->lv_disp), lv_display_get_color_format(window->lv_disp)); -#endif - /* Finally, attach buffer and commit to surface */ - wl_surface_attach(window->body->surface, buf->buffer, 0, 0); - wl_surface_commit(window->body->surface); - - struct wl_callback * cb = wl_surface_frame(window->body->surface); - wl_callback_add_listener(cb, lv_wayland_window_get_wl_surface_frame_listener(), window->body); - - window->flush_pending = true; - dmabuf_wait_swap_buf(disp); - } - else { - /* Not the last frame yet, so tell lvgl to keep going - * For the last frame, we wait for the compositor instead */ - buf->busy = 0; - lv_display_flush_ready(disp); - } - - return; -} -/********************** - * STATIC FUNCTIONS - **********************/ - -static void buffer_release(void * data, struct wl_buffer * buffer) -{ - LV_UNUSED(buffer); - struct buffer * buf = data; - buf->busy = 0; -} - -static const struct wl_buffer_listener buffer_listener = {.release = buffer_release}; - -static void create_succeeded(void * data, struct zwp_linux_buffer_params_v1 * params, struct wl_buffer * new_buffer) -{ - struct buffer * buffer = data; - buffer->buffer = new_buffer; - /* When not using explicit synchronization listen to wl_buffer.release - * for release notifications, otherwise we are going to use - * zwp_linux_buffer_release_v1. */ - wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer); - - zwp_linux_buffer_params_v1_destroy(params); -} - -static void create_failed(void * data, struct zwp_linux_buffer_params_v1 * params) -{ - struct buffer * buffer = data; - - buffer->buffer = NULL; - zwp_linux_buffer_params_v1_destroy(params); - LV_LOG_ERROR("Failed to create dmabuf buffer\n"); -} - -static const struct zwp_linux_buffer_params_v1_listener params_listener = {.created = create_succeeded, - .failed = create_failed -}; - -lv_result_t lv_wayland_dmabuf_resize_window(dmabuf_ctx_t * context, struct window * window, int width, int height) -{ - /* Don't attempt to create buffers with invalid dimensions */ - if(width <= 0 || height <= 0) { - LV_LOG_ERROR("DMABUF resize failed: invalid dimensions %dx%d", width, height); - return LV_RESULT_INVALID; - } - - lv_wayland_dmabuf_destroy_draw_buffers(context, window); - - struct buffer * buffers = lv_wayland_dmabuf_create_draw_buffers_internal(window, width, height); - if(!buffers) { - LV_LOG_ERROR("Failed to create DMABUF buffers for %dx%d", width, height); - return LV_RESULT_INVALID; - } - - context->buffers = buffers; - lv_wayland_dmabuf_set_draw_buffers(context, window->lv_disp); - - /* Clear DMABUF resize pending flag and acknowledge XDG configure if needed */ - window->dmabuf_resize_pending = false; - - if(window->surface_configured && window->configure_serial > 0 && !window->configure_acknowledged) { - lv_wayland_xdg_shell_ack_configure(window, window->configure_serial); - window->configure_acknowledged = true; - window->configure_serial = 0; /* Reset after acknowledgment */ - } - else if(window->configure_acknowledged) { - LV_LOG_TRACE("XDG configure already acknowledged, skipping duplicate acknowledgment"); - window->configure_serial = 0; /* Reset the serial */ - } - - LV_LOG_TRACE("DMABUF resize completed successfully: %dx%d", width, height); - return LV_RESULT_OK; -} - -lv_result_t lv_wayland_dmabuf_create_draw_buffers(dmabuf_ctx_t * context, struct window * window) -{ - struct buffer * buffers = lv_wayland_dmabuf_create_draw_buffers_internal(window, window->width, window->height); - if(!buffers) { - return LV_RESULT_INVALID; - } - - context->buffers = buffers; - return LV_RESULT_OK; -} - -void lv_wayland_dmabuf_destroy_draw_buffers(dmabuf_ctx_t * context, struct window * window) -{ - LV_UNUSED(window); - if(context->buffers == NULL) { - return; - } - for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) { - buffer_free(&context->buffers[i]); - } - free(context->buffers); - context->buffers = NULL; -} - -uint32_t lv_wayland_dmabuf_get_format(struct window * window) -{ - uint32_t drmcf = 0; - lv_color_format_t format = lv_display_get_color_format(window->lv_disp); - if(format == LV_COLOR_FORMAT_UNKNOWN) { - return DRM_FORMAT_ARGB8888; /* Default to ARGB8888 */ - } - - switch(format) { - case LV_COLOR_FORMAT_XRGB8888: - drmcf = DRM_FORMAT_XRGB8888; - break; - case LV_COLOR_FORMAT_ARGB8888: - drmcf = DRM_FORMAT_ARGB8888; - break; - case LV_COLOR_FORMAT_RGB565: - drmcf = DRM_FORMAT_RGB565; - break; - default: - drmcf = DRM_FORMAT_ARGB8888; - } - - return drmcf; -} - -static struct buffer * lv_wayland_dmabuf_create_draw_buffers_internal(struct window * window, int width, int height) -{ - const uint32_t flags = 0; - struct zwp_linux_buffer_params_v1 * params; - uint32_t drmcf = lv_wayland_dmabuf_get_format(window); - int stride = lv_draw_buf_width_to_stride(window->width, lv_display_get_color_format(window->lv_disp)); - struct buffer * buffers = (struct buffer *)calloc(LV_WAYLAND_BUF_COUNT, sizeof(struct buffer)); - LV_ASSERT_MALLOC(buffers); - - for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) { - uint32_t w = width; - uint32_t h = height; -#if LV_USE_ROTATE_G2D - uint32_t rotation = lv_display_get_rotation(window->lv_disp); - if(i == 2 && (rotation == LV_DISPLAY_ROTATION_90 || rotation == LV_DISPLAY_ROTATION_270)) { - w = height; - h = width; - } -#endif - stride = lv_draw_buf_width_to_stride(w, lv_display_get_color_format(window->lv_disp)); - - buffers[i].window = window; - buffers[i].lv_draw_buf = - lv_draw_buf_create(w, h, lv_display_get_color_format(window->lv_disp), stride); - buffers[i].strides[0] = stride; - buffers[i].dmabuf_fds[0] = g2d_get_buf_fd(buffers[i].lv_draw_buf); - buffers[i].buf_base[0] = buffers[i].lv_draw_buf->data; - params = zwp_linux_dmabuf_v1_create_params(window->wl_ctx->dmabuf_ctx.handler); - - zwp_linux_buffer_params_v1_add(params, buffers[i].dmabuf_fds[0], 0, buffers[i].offsets[0], buffers[i].strides[0], 0, - 0); - - zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, &buffers[i]); - zwp_linux_buffer_params_v1_create(params, w, h, drmcf, flags); - } - - wl_display_roundtrip(lv_wl_ctx.display); - - window->body->width = width; - window->body->height = height; - - return buffers; -} - -static void buffer_free(struct buffer * buf) -{ - if(buf->buffer) wl_buffer_destroy(buf->buffer); - - if(buf->lv_draw_buf) lv_draw_buf_destroy(buf->lv_draw_buf); -} - -static void dmabuf_format_table(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - int32_t fd, uint32_t size) -{ - dmabuf_ctx_t * ctx = data; - - LV_UNUSED(zwp_linux_dmabuf_feedback); - - if(fd < 0 || size == 0) { - LV_LOG_ERROR("Invalid format table fd=%d size=%u", fd, size); - return; - } - - /* Map the format table file descriptor */ - void * table = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if(table == MAP_FAILED) { - LV_LOG_ERROR("Failed to mmap format table: %s", strerror(errno)); - close(fd); - return; - } - - LV_LOG_TRACE("Received format table with fd %d and size %u", fd, size); - - /* Parse the format table - each entry is 16 bytes: 4 bytes format + 4 bytes padding + 8 bytes modifier */ - size_t num_formats = size / 16; - uint32_t * formats = (uint32_t *)table; - - for(size_t i = 0; i < num_formats; i++) { - uint32_t format = formats[i * 4]; /* Each entry is 4 uint32_t words */ - - if(LV_COLOR_DEPTH == 32) { - if(format == DRM_FORMAT_ARGB8888) { - ctx->format = format; - break; - } - else if(format == DRM_FORMAT_XRGB8888 && ctx->format == DRM_FORMAT_INVALID) { - ctx->format = format; - break; - } - } - else if(LV_COLOR_DEPTH == 16 && format == DRM_FORMAT_RGB565) { - ctx->format = format; - break; - } - } - - LV_ASSERT(ctx->format != DRM_FORMAT_INVALID); - - /* Clean up */ - munmap(table, size); - close(fd); -} - -static void dmabuf_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback) -{ - dmabuf_ctx_t * ctx = data; - - LV_UNUSED(zwp_linux_dmabuf_feedback); - LV_UNUSED(ctx); - - LV_LOG_TRACE("DMABUF feedback done - format is %u", ctx->format); - - /* This event marks the end of a feedback round. The client has received - * all the format and modifier pairs from all tranches. This allows - * the client to proceed with buffer allocation. */ -} - -static void dmabuf_main_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - struct wl_array * device) -{ - LV_UNUSED(data); - LV_UNUSED(zwp_linux_dmabuf_feedback); - LV_UNUSED(device); - - LV_LOG_TRACE("DMABUF main device received (size: %zu)", device->size); - - /* This event advertises the main device that the server-side allocator - * will use for scanout. It should be used by clients as a hint for - * buffer allocation. */ -} - -static void dmabuf_tranche_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback) -{ - LV_UNUSED(data); - LV_UNUSED(zwp_linux_dmabuf_feedback); - - LV_LOG_TRACE("DMABUF tranche done"); - - /* This event marks the end of a tranche. This allows the client to - * process the formats and modifiers it has received for this tranche. */ -} - -static void dmabuf_tranche_target_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - struct wl_array * device) -{ - LV_UNUSED(data); - LV_UNUSED(zwp_linux_dmabuf_feedback); - LV_UNUSED(device); - - LV_LOG_TRACE("DMABUF tranche target device (size: %zu)", device->size); - - /* This event advertises the target device that the following tranche - * will apply to. */ -} - -static void dmabuf_tranche_formats(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - struct wl_array * indices) -{ - dmabuf_ctx_t * ctx = data; - - LV_UNUSED(zwp_linux_dmabuf_feedback); - - LV_LOG_TRACE("DMABUF tranche formats (count: %zu)", indices->size / sizeof(uint16_t)); - - /* This event advertises the format + modifier pairs that the compositor - * supports for the current tranche. The indices are offsets into the - * format table sent earlier. */ - - if(ctx->format == DRM_FORMAT_INVALID && indices->size > 0) { - /* If we don't have a format yet, we could parse the indices here - * to find a suitable format from the format table, but for now - * we rely on the format_table callback to set a format directly */ - LV_LOG_TRACE("Format indices received but format already set or no format table"); - } -} - -static void dmabuf_tranche_flags(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, - uint32_t flags) -{ - LV_UNUSED(data); - LV_UNUSED(zwp_linux_dmabuf_feedback); - LV_UNUSED(flags); - - LV_LOG_TRACE("DMABUF tranche flags: 0x%x", flags); - - /* This event advertises the flags for the current tranche. - * Flags can indicate special properties like scanout support. */ -} - -static void dmabuf_modifiers(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format, - uint32_t modifier_hi, uint32_t modifier_lo) -{ - LV_UNUSED(modifier_hi); - LV_UNUSED(modifier_lo); - dmabuf_format(data, zwp_linux_dmabuf, format); -} - -static void dmabuf_format(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format) -{ - dmabuf_ctx_t * ctx = data; - - LV_UNUSED(zwp_linux_dmabuf); - - if(LV_COLOR_DEPTH == 32 && format == DRM_FORMAT_ARGB8888) { - - /* Wayland compositors MUST support ARGB8888 */ - ctx->format = format; - - } - else if(LV_COLOR_DEPTH == 32 && format == DRM_FORMAT_XRGB8888 && ctx->format != DRM_FORMAT_ARGB8888) { - /* Select XRGB only if the compositor doesn't support transprancy */ - ctx->format = format; - - } - else if(LV_COLOR_DEPTH == 16 && format == DRM_FORMAT_RGB565) { - ctx->format = format; - } -} - -#if !LV_USE_ROTATE_G2D -static struct buffer * dmabuf_acquire_buffer(dmabuf_ctx_t * context, unsigned char * color_p) -{ - - for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) { - struct buffer * buffer = &context->buffers[i]; - if(buffer->buf_base[0] == color_p && buffer->busy == 0) { - context->last_used = i; - buffer->busy = 1; - return buffer; - } - } - - while(1) { - wl_display_roundtrip(lv_wl_ctx.display); - - for(int i = 0; i < LV_WAYLAND_BUF_COUNT; i++) { - struct buffer * buffer = &context->buffers[i]; - if(buffer->buf_base[0] == color_p && buffer->busy == 0) { - context->last_used = i; - buffer->busy = 1; - return buffer; - } - } - } - - return NULL; -} -#else -static struct buffer * get_next_buffer(dmabuf_ctx_t * context) -{ - int next_buf = (context->last_used + 1) % (LV_WAYLAND_BUF_COUNT - 1); - context->buffers[next_buf].busy = 1; - context->last_used = next_buf; - return &context->buffers[next_buf]; -} -#endif - -#if LV_WAYLAND_WINDOW_DECORATIONS -static void create_decorators_buf(struct window * window, struct graphic_object * decoration) -{ - struct zwp_linux_buffer_params_v1 * params; - const uint32_t flags = 0; - uint8_t id = decoration->type; - - window->decorators_buf[id] = (struct buffer *)calloc(1, sizeof(struct buffer)); - LV_ASSERT_MALLOC(window->decorators_buf[id]); - - const int stride = lv_draw_buf_width_to_stride(decoration->width, lv_display_get_color_format(window->lv_disp)); - window->decorators_buf[id]->window = window; - window->decorators_buf[id]->lv_draw_buf = - lv_draw_buf_create(decoration->width, decoration->height, lv_display_get_color_format(window->lv_disp), stride); - - window->decorators_buf[id]->strides[0] = stride; - window->decorators_buf[id]->width = decoration->width; - window->decorators_buf[id]->height = decoration->height; - window->decorators_buf[id]->dmabuf_fds[0] = g2d_get_buf_fd(window->decorators_buf[id]->lv_draw_buf); - window->decorators_buf[id]->buf_base[0] = window->decorators_buf[id]->lv_draw_buf->data; - params = zwp_linux_dmabuf_v1_create_params(window->wl_ctx->dmabuf_ctx.handler); - - zwp_linux_buffer_params_v1_add(params, window->decorators_buf[id]->dmabuf_fds[0], 0, - window->decorators_buf[id]->offsets[0], - window->decorators_buf[id]->strides[0], 0, - 0); - - zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, window->decorators_buf[id]); - zwp_linux_buffer_params_v1_create(params, decoration->width, decoration->height, lv_wayland_dmabuf_get_format(window), - flags); - - wl_display_roundtrip(lv_wl_ctx.display); -} - -void destroy_decorators_buf(struct window * window, struct graphic_object * decoration) -{ - uint8_t id = decoration->type; - - if(window->decorators_buf[id] != NULL) { - buffer_free(window->decorators_buf[id]); - free(window->decorators_buf[id]); - window->decorators_buf[id] = NULL; - } -} - -struct buffer * dmabuf_acquire_pool_buffer(struct window * window, struct graphic_object * decoration) -{ - uint8_t id = decoration->type; - - if(window->decorators_buf[id] == NULL) { - create_decorators_buf(window, decoration); - } - else if(window->decorators_buf[id]->width != (uint32_t)decoration->width || - window->decorators_buf[id]->height != (uint32_t)decoration->height) { - destroy_decorators_buf(window, decoration); - create_decorators_buf(window, decoration); - } - return window->decorators_buf[id]; -} -#endif - -#endif /* LV_WAYLAND_DMABUF */ diff --git a/src/drivers/wayland/lv_wl_g2d_backend.c b/src/drivers/wayland/lv_wl_g2d_backend.c new file mode 100644 index 0000000000..831555befb --- /dev/null +++ b/src/drivers/wayland/lv_wl_g2d_backend.c @@ -0,0 +1,648 @@ + +/** + * @file lv_wl_g2d_backend.c + * + */ + + +/********************* + * INCLUDES + *********************/ + +#include "lv_wayland_private.h" + +#if LV_WAYLAND_USE_G2D + +#include "../../display/lv_display_private.h" +#include +#include +#include +#include +#include "../../misc/lv_types.h" +#include +#include "../../draw/nxp/g2d/lv_g2d_utils.h" +#include +#include +#include +#include + +/********************* + * DEFINES + *********************/ + +#define LV_WL_G2D_BUF_COUNT 2 + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + struct wl_buffer * wl_buffer; + lv_draw_buf_t * lv_draw_buf; + int dmabuf_fd; + uint32_t stride; + uint32_t offset; + bool busy; +} lv_wl_buffer_t; + +typedef struct { + lv_wl_buffer_t buffers[LV_WL_G2D_BUF_COUNT]; +#if LV_USE_ROTATE_G2D + lv_wl_buffer_t rotate_buffer; +#endif + uint32_t drm_cf; + uint8_t last_used; + bool flushing; +} lv_wl_g2d_display_data_t; + +typedef struct { + struct zwp_linux_dmabuf_v1 * handler; + /* XRBG888 and ARGB8888 are always supported*/ + bool supports_rgb565; +} lv_wl_g2d_ctx_t; + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void * wl_g2d_init(void); +static void wl_g2d_deinit(void * backend_ctx); +static void wl_g2d_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name, + const char * interface, uint32_t version); + + +static void * wl_g2d_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height); +static void * wl_g2d_resize_display(void * backend_ctx, lv_display_t * display); +static void wl_g2d_deinit_display(void * backend_ctx, lv_display_t * display); + +static lv_wl_g2d_display_data_t * wl_g2d_create_display_data(lv_wl_g2d_ctx_t * ctx, lv_display_t * display, + int32_t width, int32_t height); + +static void wl_g2d_delete_display_data(lv_wl_g2d_display_data_t * ddata); + +static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p); + + +static void dmabuf_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback); +static void dmabuf_format_table(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + int32_t fd, uint32_t size); +static void dmabuf_main_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + struct wl_array * device); +static void dmabuf_tranche_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback); +static void dmabuf_tranche_target_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + struct wl_array * device); +static void dmabuf_tranche_formats(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + struct wl_array * indices); +static void dmabuf_tranche_flags(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + uint32_t flags); +static void dmabuf_modifiers(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format, + uint32_t modifier_hi, uint32_t modifier_lo); +static void dmabuf_format(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format); + +static void buffer_release(void * data, struct wl_buffer * buffer); + +static void create_succeeded(void * data, struct zwp_linux_buffer_params_v1 * params, struct wl_buffer * new_buffer); +static void create_failed(void * data, struct zwp_linux_buffer_params_v1 * params); + +static uint32_t lv_cf_to_drm_cf(lv_color_format_t cf); + +static void frame_done(void * data, struct wl_callback * callback, uint32_t time); + +static void init_buffer(lv_wl_g2d_ctx_t * ctx, lv_wl_buffer_t * buffer, uint32_t width, uint32_t height, + lv_color_format_t cf); + +static void delete_buffer(lv_wl_buffer_t * buffer); +static void flush_wait_cb(lv_display_t * disp); + +static lv_wl_buffer_t * get_next_buffer(lv_wl_g2d_display_data_t * ddata); + +/********************** + * STATIC VARIABLES + **********************/ + +static lv_wl_g2d_ctx_t ctx; + +const lv_wayland_backend_ops_t wl_backend_ops = { + .init = wl_g2d_init, + .deinit = wl_g2d_deinit, + .global_handler = wl_g2d_global_handler, + .init_display = wl_g2d_init_display, + .deinit_display = wl_g2d_deinit_display, + .resize_display = wl_g2d_resize_display, +}; + +static const struct zwp_linux_dmabuf_feedback_v1_listener dmabuf_listener_v5 = { + .done = dmabuf_done, + .format_table = dmabuf_format_table, + .main_device = dmabuf_main_device, + .tranche_done = dmabuf_tranche_done, + .tranche_target_device = dmabuf_tranche_target_device, + .tranche_formats = dmabuf_tranche_formats, + .tranche_flags = dmabuf_tranche_flags, +}; + +static const struct wl_buffer_listener buffer_listener = { + .release = buffer_release +}; + +static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener_v3 = { + .format = dmabuf_format, + .modifier = dmabuf_modifiers +}; + +static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { + .format = dmabuf_format +}; + +static const struct zwp_linux_buffer_params_v1_listener params_listener = { + .created = create_succeeded, + .failed = create_failed +}; + +static const struct wl_callback_listener frame_listener = { + .done = frame_done, +}; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + + +static void * wl_g2d_init(void) +{ + lv_memset(&ctx, 0, sizeof(ctx)); + return &ctx; +} + +static void wl_g2d_deinit(void * backend_ctx) +{ + lv_wl_g2d_ctx_t * ctx = (lv_wl_g2d_ctx_t *)backend_ctx; + if(!ctx) { + return; + } + if(ctx->handler) { + zwp_linux_dmabuf_v1_destroy(ctx->handler); + } +} + + +static void wl_g2d_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name, + const char * interface, uint32_t version) +{ + + LV_UNUSED(version); + lv_wl_g2d_ctx_t * ctx = (lv_wl_g2d_ctx_t *)backend_ctx; + + if(lv_streq(interface, zwp_linux_dmabuf_v1_interface.name)) { + ctx->handler = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version); + + if(version >= 4) { + struct zwp_linux_dmabuf_feedback_v1 * feedback = zwp_linux_dmabuf_v1_get_default_feedback(ctx->handler); + zwp_linux_dmabuf_feedback_v1_add_listener(feedback, &dmabuf_listener_v5, ctx); + } + else if(version < 3) { + zwp_linux_dmabuf_v1_add_listener(ctx->handler, &dmabuf_listener, ctx); + } + else if(version == 3) { + zwp_linux_dmabuf_v1_add_listener(ctx->handler, &dmabuf_listener_v3, ctx); + } + wl_display_roundtrip(lv_wl_ctx.wl_display); + } +} +static void init_buffer(lv_wl_g2d_ctx_t * ctx, lv_wl_buffer_t * buffer, uint32_t width, uint32_t height, + lv_color_format_t cf) +{ + uint32_t drm_cf = lv_cf_to_drm_cf(cf); + uint32_t stride = lv_draw_buf_width_to_stride(width, cf); + buffer->lv_draw_buf = lv_draw_buf_create(width, height, cf, stride); + buffer->dmabuf_fd = g2d_get_buf_fd(buffer->lv_draw_buf); + buffer->stride = stride; + buffer->offset = 0; + buffer->busy = false; + + /* Will be set on the dmabuf callback if the creation is successful*/ + buffer->wl_buffer = NULL; + + struct zwp_linux_buffer_params_v1 * params = zwp_linux_dmabuf_v1_create_params(ctx->handler); + + zwp_linux_buffer_params_v1_add(params, + buffer->dmabuf_fd, + 0, + buffer->offset, + buffer->stride, + 0, + 0); + + zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, buffer); + zwp_linux_buffer_params_v1_create(params, width, height, drm_cf, 0); +} + +static void delete_buffer(lv_wl_buffer_t * buffer) +{ + if(buffer->wl_buffer) { + wl_buffer_destroy(buffer->wl_buffer); + buffer->wl_buffer = NULL; + } + if(buffer->lv_draw_buf) { + lv_draw_buf_destroy(buffer->lv_draw_buf); + buffer->lv_draw_buf = NULL; + } +} + +static lv_wl_g2d_display_data_t * wl_g2d_create_display_data(lv_wl_g2d_ctx_t * ctx, lv_display_t * display, + int32_t width, int32_t height) +{ + lv_wl_g2d_display_data_t * ddata = lv_zalloc(sizeof(*ddata)); + LV_ASSERT_MALLOC(ddata); + if(!ddata) { + return NULL; + } + + lv_display_rotation_t rotation = lv_display_get_rotation(display); + lv_color_format_t cf = lv_display_get_color_format(display); + if(cf == LV_COLOR_FORMAT_RGB565 && !ctx->supports_rgb565) { + LV_LOG_WARN("RGB565 is not supported by the wayland compositor. Falling back to XRGB8888"); + cf = LV_COLOR_FORMAT_XRGB8888; + lv_display_set_color_format(display, cf); + } + + ddata->drm_cf = lv_cf_to_drm_cf(cf); + for(size_t i = 0; i < LV_WL_G2D_BUF_COUNT; i++) { + init_buffer(ctx, &ddata->buffers[i], width, height, cf); + } + +#if LV_USE_ROTATE_G2D + if(rotation == LV_DISPLAY_ROTATION_90 || rotation == LV_DISPLAY_ROTATION_270) { + init_buffer(ctx, &ddata->rotate_buffer, height, width, cf); + } + else { + init_buffer(ctx, &ddata->rotate_buffer, width, height, cf); + } +#endif + + wl_display_flush(lv_wl_ctx.wl_display); + wl_display_roundtrip(lv_wl_ctx.wl_display); + for(size_t i = 0; i < LV_WL_G2D_BUF_COUNT; ++i) { + if(!ddata->buffers[i].wl_buffer) { + wl_g2d_delete_display_data(ddata); + LV_LOG_ERROR("DMABUF creation failed"); + return NULL; + } + } + +#if LV_USE_ROTATE_G2D + if(!ddata->rotate_buffer.wl_buffer) { + wl_g2d_delete_display_data(ddata); + LV_LOG_ERROR("DMABUF creation failed"); + return NULL; + } + lv_display_set_draw_buffers(display, ddata->rotate_buffer.lv_draw_buf, NULL); +#else + lv_display_set_draw_buffers(display, ddata->buffers[0].lv_draw_buf, ddata->buffers[1].lv_draw_buf); +#endif + + return ddata; +} + +static void wl_g2d_delete_display_data(lv_wl_g2d_display_data_t * ddata) +{ + for(int i = 0; i < LV_WL_G2D_BUF_COUNT; i++) { + delete_buffer(ddata->buffers + i); + } + +#if LV_USE_ROTATE_G2D + delete_buffer(&ddata->rotate_buffer); +#endif + + lv_free(ddata); +} + +static void * wl_g2d_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height) +{ + + lv_wl_g2d_ctx_t * ctx = (lv_wl_g2d_ctx_t *)backend_ctx; + lv_wl_g2d_display_data_t * ddata = wl_g2d_create_display_data(ctx, display, width, height); + if(!ddata) { + LV_LOG_ERROR("Failed to create display data"); + return NULL; + } + + lv_display_set_flush_cb(display, flush_cb); + lv_display_set_flush_wait_cb(display, flush_wait_cb); + lv_display_set_render_mode(display, LV_DISPLAY_RENDER_MODE_DIRECT); + return ddata; +} + +static uint32_t lv_cf_to_drm_cf(lv_color_format_t cf) +{ + if(cf == LV_COLOR_FORMAT_UNKNOWN) { + return DRM_FORMAT_ARGB8888; /* Default to ARGB8888 */ + } + + switch(cf) { + case LV_COLOR_FORMAT_XRGB8888: + return DRM_FORMAT_XRGB8888; + break; + case LV_COLOR_FORMAT_ARGB8888: + case LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED: + return DRM_FORMAT_ARGB8888; + break; + case LV_COLOR_FORMAT_RGB565: + return DRM_FORMAT_RGB565; + break; + default: + return DRM_FORMAT_ARGB8888; + } +} + +static void frame_done(void * data, struct wl_callback * callback, uint32_t time) +{ + LV_LOG_TRACE("Frame done"); + LV_UNUSED(time); + lv_display_t * display = data; + wl_callback_destroy(callback); + lv_display_flush_ready(display); +} + + +static void buffer_release(void * data, struct wl_buffer * buffer) +{ + LV_LOG_TRACE("Buffer released"); + LV_UNUSED(buffer); + lv_wl_buffer_t * buf = data; + buf->busy = false; +} + + +static void create_succeeded(void * data, struct zwp_linux_buffer_params_v1 * params, struct wl_buffer * new_buffer) +{ + LV_LOG_TRACE("Buffer created successfuly"); + lv_wl_buffer_t * buffer = data; + buffer->wl_buffer = new_buffer; + + /* When not using explicit synchronization listen to wl_buffer.release + * for release notifications, otherwise we are going to use + * zwp_linux_buffer_release_v1. */ + wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); + + zwp_linux_buffer_params_v1_destroy(params); +} + +static void create_failed(void * data, struct zwp_linux_buffer_params_v1 * params) +{ + lv_wl_buffer_t * buffer = data; + buffer->wl_buffer = NULL; + zwp_linux_buffer_params_v1_destroy(params); + LV_LOG_ERROR("Failed to create dmabuf buffer\n"); +} + +static void * wl_g2d_resize_display(void * backend_ctx, lv_display_t * disp) +{ + lv_wl_g2d_ctx_t * ctx = (lv_wl_g2d_ctx_t *)backend_ctx; + int32_t width = lv_display_get_original_horizontal_resolution(disp); + int32_t height = lv_display_get_original_vertical_resolution(disp); + + lv_wl_g2d_display_data_t * ddata = wl_g2d_create_display_data(ctx, disp, width, height); + if(!ddata) { + LV_LOG_ERROR("Failed to create DMABUF buffers for %dx%d", width, height); + return NULL; + } + + lv_wl_g2d_display_data_t * old_ddata = lv_wayland_get_backend_display_data(disp); + wl_g2d_delete_display_data(old_ddata); + return ddata; +} + +static void wl_g2d_deinit_display(void * backend_ctx, lv_display_t * display) +{ + LV_UNUSED(backend_ctx); + lv_wl_g2d_display_data_t * ddata = lv_wayland_get_backend_display_data(display); + if(!ddata) { + return; + } + wl_g2d_delete_display_data(ddata); +} + +static void dmabuf_format_table(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + int32_t fd, uint32_t size) +{ + lv_wl_g2d_ctx_t * ctx = data; + + LV_UNUSED(zwp_linux_dmabuf_feedback); + + if(fd < 0 || size == 0) { + LV_LOG_ERROR("Invalid format table fd=%d size=%u", fd, size); + return; + } + + /* Map the format table file descriptor */ + void * table = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if(table == MAP_FAILED) { + LV_LOG_ERROR("Failed to mmap format table: %s", strerror(errno)); + close(fd); + return; + } + + LV_LOG_TRACE("Received format table with fd %d and size %u", fd, size); + + /* Parse the format table - each entry is 16 bytes: 4 bytes format + 4 bytes padding + 8 bytes modifier */ + size_t num_formats = size / 16; + uint32_t * formats = (uint32_t *)table; + + for(size_t i = 0; i < num_formats; i++) { + /* Each entry is 4 uint32_t words */ + uint32_t format = formats[i * 4]; + if(format == DRM_FORMAT_RGB565) { + ctx->supports_rgb565 = true; + } + } + + /* Clean up */ + munmap(table, size); + close(fd); +} + +static void dmabuf_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback) +{ + lv_wl_g2d_ctx_t * ctx = data; + + LV_UNUSED(zwp_linux_dmabuf_feedback); + LV_UNUSED(ctx); + + LV_LOG_TRACE("DMABUF feedback done"); + + /* This event marks the end of a feedback round. The client has received + * all the format and modifier pairs from all tranches. This allows + * the client to proceed with buffer allocation. */ +} + +static void dmabuf_main_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + struct wl_array * device) +{ + LV_UNUSED(data); + LV_UNUSED(zwp_linux_dmabuf_feedback); + LV_UNUSED(device); + + LV_LOG_TRACE("DMABUF main device received (size: %zu)", device->size); + + /* This event advertises the main device that the server-side allocator + * will use for scanout. It should be used by clients as a hint for + * buffer allocation. */ +} + +static void dmabuf_tranche_done(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback) +{ + LV_UNUSED(data); + LV_UNUSED(zwp_linux_dmabuf_feedback); + + LV_LOG_TRACE("DMABUF tranche done"); + + /* This event marks the end of a tranche. This allows the client to + * process the formats and modifiers it has received for this tranche. */ +} + +static void dmabuf_tranche_target_device(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + struct wl_array * device) +{ + LV_UNUSED(data); + LV_UNUSED(zwp_linux_dmabuf_feedback); + LV_UNUSED(device); + + LV_LOG_TRACE("DMABUF tranche target device (size: %zu)", device->size); + + /* This event advertises the target device that the following tranche + * will apply to. */ +} + +static void dmabuf_tranche_formats(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + struct wl_array * indices) +{ + LV_UNUSED(data); + LV_UNUSED(zwp_linux_dmabuf_feedback); + + LV_LOG_TRACE("DMABUF tranche formats (count: %zu)", indices->size / sizeof(uint16_t)); + + /* This event advertises the format + modifier pairs that the compositor + * supports for the current tranche. The indices are offsets into the + * format table sent earlier. */ + + if(indices->size > 0) { + /* If we don't have a format yet, we could parse the indices here + * to find a suitable format from the format table, but for now + * we rely on the format_table callback to set a format directly */ + LV_LOG_TRACE("Format indices received"); + } +} + +static void dmabuf_tranche_flags(void * data, struct zwp_linux_dmabuf_feedback_v1 * zwp_linux_dmabuf_feedback, + uint32_t flags) +{ + LV_UNUSED(data); + LV_UNUSED(zwp_linux_dmabuf_feedback); + LV_UNUSED(flags); + + LV_LOG_TRACE("DMABUF tranche flags: 0x%x", flags); + + /* This event advertises the flags for the current tranche. + * Flags can indicate special properties like scanout support. */ +} + +static void dmabuf_modifiers(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format, + uint32_t modifier_hi, uint32_t modifier_lo) +{ + LV_UNUSED(modifier_hi); + LV_UNUSED(modifier_lo); + dmabuf_format(data, zwp_linux_dmabuf, format); +} + +static void dmabuf_format(void * data, struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf, uint32_t format) +{ + lv_wl_g2d_ctx_t * ctx = data; + + LV_UNUSED(zwp_linux_dmabuf); + if(format == DRM_FORMAT_RGB565) { + ctx->supports_rgb565 = true; + } +} + +static lv_wl_buffer_t * get_next_buffer(lv_wl_g2d_display_data_t * ddata) +{ + lv_wl_buffer_t * ret = &ddata->buffers[ddata->last_used]; + if(ret->busy) { + /* In theory this should never happen, log a warning in case it does */ + LV_LOG_WARN("Failed to acquire a non-busy buffer"); + } + ddata->last_used = (ddata->last_used + 1) % (LV_WL_G2D_BUF_COUNT); + return ret; +} + +static void flush_wait_cb(lv_display_t * disp) +{ + while(disp->flushing) { + wl_display_dispatch(lv_wl_ctx.wl_display); + } +} + +static void flush_cb(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p) +{ + + LV_UNUSED(color_p); + lv_wl_g2d_display_data_t * ddata = lv_wayland_get_backend_display_data(disp); + int32_t src_width = lv_area_get_width(area); + int32_t src_height = lv_area_get_height(area); + uint32_t rotation = lv_display_get_rotation(disp); + lv_wl_buffer_t * buf = get_next_buffer(ddata); + + if(!buf) { + LV_LOG_ERROR("Failed to acquire a wayland window body buffer"); + return; + } + + lv_draw_buf_invalidate_cache(buf->lv_draw_buf, NULL); +#if LV_USE_ROTATE_G2D + lv_draw_buf_invalidate_cache(ddata->rotate_buffer.lv_draw_buf, NULL); +#endif + + struct wl_surface * surface = lv_wayland_get_window_surface(disp); + /* Mark surface damage */ + wl_surface_damage(surface, area->x1, area->y1, src_width, src_height); + + if(!lv_display_flush_is_last(disp)) { + lv_display_flush_ready(disp); + return; + } + + /*Rerender the whole surface if we're using rotation*/ + if(rotation != LV_DISPLAY_ROTATION_0) { + wl_surface_damage(surface, 0, 0, + lv_display_get_original_horizontal_resolution(disp), + lv_display_get_original_vertical_resolution(disp)); + } + +#if LV_USE_ROTATE_G2D + g2d_rotate(ddata->rotate_buffer.lv_draw_buf, buf->lv_draw_buf, + lv_display_get_original_horizontal_resolution(disp), + lv_display_get_original_vertical_resolution(disp), + lv_display_get_rotation(disp), + lv_display_get_color_format(disp)); +#endif + /* Finally, attach buffer and commit to surface */ + struct wl_callback * cb = wl_surface_frame(surface); + wl_callback_add_listener(cb, &frame_listener, disp); + + wl_surface_attach(surface, buf->wl_buffer, 0, 0); + wl_surface_commit(surface); + + buf->busy = true; + return; +} + +#endif /*LV_USE_WAYLAND_G2D*/ diff --git a/src/drivers/wayland/lv_wl_keyboard.c b/src/drivers/wayland/lv_wl_keyboard.c index bcdb3885b4..29e172eda2 100644 --- a/src/drivers/wayland/lv_wl_keyboard.c +++ b/src/drivers/wayland/lv_wl_keyboard.c @@ -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 */ diff --git a/src/drivers/wayland/lv_wl_pointer.c b/src/drivers/wayland/lv_wl_pointer.c index bffa3bae99..4d3dd8603c 100644 --- a/src/drivers/wayland/lv_wl_pointer.c +++ b/src/drivers/wayland/lv_wl_pointer.c @@ -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 */ diff --git a/src/drivers/wayland/lv_wl_pointer_axis.c b/src/drivers/wayland/lv_wl_pointer_axis.c deleted file mode 100644 index 9b6ddac4d4..0000000000 --- a/src/drivers/wayland/lv_wl_pointer_axis.c +++ /dev/null @@ -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 */ diff --git a/src/drivers/wayland/lv_wl_seat.c b/src/drivers/wayland/lv_wl_seat.c index 64b4342a0f..f547a8ec10 100644 --- a/src/drivers/wayland/lv_wl_seat.c +++ b/src/drivers/wayland/lv_wl_seat.c @@ -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; } } diff --git a/src/drivers/wayland/lv_wl_shm.c b/src/drivers/wayland/lv_wl_shm.c deleted file mode 100644 index 5d479b085d..0000000000 --- a/src/drivers/wayland/lv_wl_shm.c +++ /dev/null @@ -1,473 +0,0 @@ -/** - * @file lv_wl_shm.c - * - */ - -/********************* - * INCLUDES - *********************/ - -#include "lv_wayland.h" -#if LV_USE_WAYLAND - -#include "lv_wayland_private.h" -#include -#include -#include -#include -#include - -/********************* - * 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 */ diff --git a/src/drivers/wayland/lv_wl_shm_backend.c b/src/drivers/wayland/lv_wl_shm_backend.c new file mode 100644 index 0000000000..976aa38313 --- /dev/null +++ b/src/drivers/wayland/lv_wl_shm_backend.c @@ -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 +#include +#include +#include +#include +#include + +/********************* + * 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*/ diff --git a/src/drivers/wayland/lv_wl_touch.c b/src/drivers/wayland/lv_wl_touch.c index ea375b0612..d0ea0b269d 100644 --- a/src/drivers/wayland/lv_wl_touch.c +++ b/src/drivers/wayland/lv_wl_touch.c @@ -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 } diff --git a/src/drivers/wayland/lv_wl_window.c b/src/drivers/wayland/lv_wl_window.c index 4bf4ee20d0..ff59aa65a5 100644 --- a/src/drivers/wayland/lv_wl_window.c +++ b/src/drivers/wayland/lv_wl_window.c @@ -10,6 +10,9 @@ #if LV_USE_WAYLAND +#include "../../lv_init.h" +#include +#include #include #include "lv_wayland_private.h" #include "lv_wayland_private.h" @@ -18,8 +21,6 @@ #include "lv_wl_touch.h" #include "lv_wl_keyboard.h" -#include "../../core/lv_refr.h" - /********************* * DEFINES *********************/ @@ -32,42 +33,15 @@ * STATIC PROTOTYPES **********************/ -static struct graphic_object * create_graphic_obj(struct window * window, enum object_type type, - struct graphic_object * parent); -static void destroy_graphic_obj(struct window * window, struct graphic_object * obj); - -/* Create a window - * @description Creates the graphical context for the window body, and then create a toplevel - * wayland surface and commit it to obtain an XDG configuration event - * @param width the height of the window w/decorations - * @param height the width of the window w/decorations - */ -static struct window * create_window(struct lv_wayland_context * app, int width, int height, const char * title); - -/** - * The frame callback called when the compositor has finished rendering - * a frame.It increments the frame counter and sets up the callback - * for the next frame the frame counter is used to avoid needlessly - * committing frames too fast on a slow system - * - * NOTE: this function is invoked by the wayland-server library within the compositor - * the event is added to the queue, and then upon the next timer call it's - * called indirectly from _lv_wayland_handle_input (via wl_display_dispatch_queue) - * @param void data the user object defined that was tied to this event during - * the configuration of the callback - * @param struct wl_callback The callback that needs to be destroyed and re-created - * @param time Timestamp of the event (unused) - */ -static void lv_window_graphic_obj_flush_done(void * data, struct wl_callback * cb, uint32_t time); +static void refr_start_event(lv_event_t * e); +static void refr_end_event(lv_event_t * e); +static void res_changed_event(lv_event_t * e); +static void delete_event(lv_event_t * e); /********************** * STATIC VARIABLES **********************/ -static const struct wl_callback_listener wl_surface_frame_listener = { - .done = lv_window_graphic_obj_flush_done, -}; - /********************** * MACROS **********************/ @@ -77,74 +51,56 @@ static const struct wl_callback_listener wl_surface_frame_listener = { **********************/ 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) { - struct window * window; - int32_t window_width; - int32_t window_height; - - uint32_t width = hor_res; - uint32_t height = ver_res; - lv_wayland_init(); - - window_width = hor_res; - window_height = ver_res; - -#if LV_WAYLAND_WINDOW_DECORATIONS - if(!lv_wl_ctx.opt_disable_decorations) { - window_width = hor_res + (2 * BORDER_SIZE); - window_height = ver_res + (TITLE_BAR_HEIGHT + (2 * BORDER_SIZE)); + if(close_cb) { + LV_LOG_WARN("'lv_wayland_display_close_cb_t' is deprecated and will be removed in the next release. Instead bind an LV_EVENT_DELETE to the display\ + Bind an LV_EVENT_DELETE to the display returned by `lv_wayland_window_create` instead."); } -#endif - window = create_window(&lv_wl_ctx, window_width, window_height, title); + lv_wl_window_t * window = lv_ll_ins_tail(&lv_wl_ctx.window_ll); + LV_ASSERT_MALLOC(window); if(!window) { - LV_LOG_ERROR("failed to create wayland window"); - return NULL; + LV_LOG_ERROR("Failed to allocate memory fo window"); + goto alloc_window_err; } + lv_memset(window, 0, sizeof(*window)); + window->close_cb = close_cb; - /* Initialize display driver */ - window->lv_disp = lv_display_create(width, height); - if(window->lv_disp == NULL) { + window->lv_disp = lv_display_create(hor_res, ver_res); + if(!window->lv_disp) { LV_LOG_ERROR("failed to create lvgl display"); - return NULL; + goto create_display_error; } -#if LV_WAYLAND_USE_DMABUF - if(lv_wayland_dmabuf_create_draw_buffers(&lv_wl_ctx.dmabuf_ctx, window) != LV_RESULT_OK) { - LV_LOG_ERROR("Failed to create draw buffers"); - return NULL; + window->body = wl_compositor_create_surface(lv_wl_ctx.wl_compositor); + if(!window->body) { + LV_LOG_ERROR("Failed to create window body"); + goto create_surface_err; } -#else - if(lv_wayland_shm_create_draw_buffers(&lv_wl_ctx.shm_ctx, window) != LV_RESULT_OK) { - LV_LOG_ERROR("Failed to create window buffers"); - return NULL; - } -#endif - lv_wayland_xdg_shell_configure_surface(window); + if(lv_wl_xdg_create_window(lv_wl_ctx.xdg_wm, window, title) != LV_RESULT_OK) { + LV_LOG_ERROR("Failed to create window"); + goto create_window_err; + } + + /* Initialize display driver */ + window->backend_display_data = wl_backend_ops.init_display(lv_wl_ctx.backend_data, window->lv_disp, hor_res, ver_res); lv_display_set_driver_data(window->lv_disp, window); - lv_display_set_render_mode(window->lv_disp, LV_WAYLAND_RENDER_MODE); - lv_display_set_flush_wait_cb(window->lv_disp, lv_wayland_wait_flush_cb); + lv_wayland_xdg_configure_surface(window); -#if LV_WAYLAND_USE_DMABUF - lv_wayland_dmabuf_set_draw_buffers(&lv_wl_ctx.dmabuf_ctx, window->lv_disp); - lv_display_set_flush_cb(window->lv_disp, lv_wayland_dmabuf_flush_full_mode); -#else - lv_wayland_shm_set_draw_buffers(&lv_wl_ctx.shm_ctx, window->lv_disp, window); - lv_display_set_flush_cb(window->lv_disp, lv_wayland_shm_flush_partial_mode); -#endif - - lv_display_add_event_cb(window->lv_disp, lv_wayland_event_cb, LV_EVENT_RESOLUTION_CHANGED, window); + lv_display_add_event_cb(window->lv_disp, res_changed_event, LV_EVENT_RESOLUTION_CHANGED, NULL); + lv_display_add_event_cb(window->lv_disp, refr_start_event, LV_EVENT_REFR_START, NULL); + lv_display_add_event_cb(window->lv_disp, refr_end_event, LV_EVENT_REFR_READY, NULL); + lv_display_add_event_cb(window->lv_disp, delete_event, LV_EVENT_DELETE, NULL); /* Register input */ window->lv_indev_pointer = lv_wayland_pointer_create(); - lv_indev_set_display(window->lv_indev_pointer, window->lv_disp); if(!window->lv_indev_pointer) { @@ -172,59 +128,71 @@ lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char LV_LOG_ERROR("failed to register keyboard indev"); } return window->lv_disp; + +create_window_err: + wl_surface_destroy(window->body); +create_surface_err: + lv_display_delete(window->lv_disp); +create_display_error: + lv_ll_remove(&lv_wl_ctx.window_ll, window); + lv_free(window); +alloc_window_err: + return NULL; } -void lv_wayland_window_close(lv_display_t * disp) +void * lv_wayland_get_backend_display_data(lv_display_t * display) { - struct window * window = lv_display_get_driver_data(disp); - if(!window || window->closed) { + LV_ASSERT_NULL(display); + lv_wl_window_t * window = lv_display_get_driver_data(display); + LV_ASSERT_NULL(window); + return window->backend_display_data; +} + +struct wl_surface * lv_wayland_get_window_surface(lv_display_t * display) +{ + LV_ASSERT_NULL(display); + lv_wl_window_t * window = lv_display_get_driver_data(display); + LV_ASSERT_NULL(window); + return window->body; +} + +void lv_wayland_window_close(lv_display_t * display) +{ + LV_ASSERT_NULL(display); + lv_wl_window_t * window = lv_display_get_driver_data(display); + if(!window) { return; } - window->shall_close = true; - window->close_cb = NULL; + window->close_cb = NULL; + lv_wayland_window_delete(window); lv_wayland_deinit(); } bool lv_wayland_window_is_open(lv_display_t * disp) { - struct window * window; - bool open = false; - - if(disp == NULL) { - LV_LL_READ(&lv_wl_ctx.window_ll, window) { - if(!window->closed) { - open = true; - break; - } - } - } - else { - window = lv_display_get_driver_data(disp); - open = (!window->closed); - } - - return open; + LV_UNUSED(disp); + return true; } void lv_wayland_window_set_maximized(lv_display_t * disp, bool maximized) { - struct window * window = lv_display_get_driver_data(disp); - lv_result_t err = LV_RESULT_INVALID; - if(!window || window->closed) { + lv_wl_window_t * window = lv_display_get_driver_data(disp); + if(!window) { return; } - if(window->maximized != maximized) { - err = lv_wayland_xdg_shell_set_maximized(window, maximized); + lv_wayland_xdg_set_maximized(&window->xdg, maximized); } - if(err == LV_RESULT_INVALID) { - LV_LOG_WARN("Failed to maximize wayland window"); + window->maximized = maximized; +} +void lv_wayland_window_set_minimized(lv_display_t * disp) +{ + lv_wl_window_t * window = lv_display_get_driver_data(disp); + if(!window) { return; } - - window->maximized = maximized; - window->flush_pending = true; + lv_wayland_xdg_set_minimized(&window->xdg); } void lv_wayland_assign_physical_display(lv_display_t * disp, uint8_t display_number) @@ -234,18 +202,18 @@ void lv_wayland_assign_physical_display(lv_display_t * disp, uint8_t display_num return; } - struct window * window = lv_display_get_driver_data(disp); + lv_wl_window_t * window = lv_display_get_driver_data(disp); - if(!window || window->closed) { + if(!window) { LV_LOG_ERROR("Invalid window"); return; } - if(display_number >= window->wl_ctx->wl_output_count) { - LV_LOG_WARN("Invalid display number '%d'. Expected '0'..'%d'", display_number, window->wl_ctx->wl_output_count - 1); + if(display_number >= lv_wl_ctx.wl_output_count) { + LV_LOG_WARN("Invalid display number '%d'. Expected '0'..'%d'", display_number, lv_wl_ctx.wl_output_count - 1); return; } - window->assigned_output = lv_wl_ctx.outputs[display_number].wl_output; + window->physical_output = lv_wl_ctx.physical_outputs[display_number].wl_output; } void lv_wayland_unassign_physical_display(lv_display_t * disp) @@ -256,252 +224,132 @@ void lv_wayland_unassign_physical_display(lv_display_t * disp) return; } - struct window * window = lv_display_get_user_data(disp); - - if(!window || window->closed) { + lv_wl_window_t * window = lv_display_get_user_data(disp); + if(!window) { LV_LOG_ERROR("Invalid window"); return; } - window->assigned_output = NULL; + window->physical_output = NULL; } void lv_wayland_window_set_fullscreen(lv_display_t * disp, bool fullscreen) { - struct window * window = lv_display_get_driver_data(disp); - lv_result_t err = LV_RESULT_INVALID; - if(!window || window->closed) { + lv_wl_window_t * window = lv_display_get_driver_data(disp); + if(!window) { return; } if(window->fullscreen == fullscreen) { return; } - err = lv_wayland_xdg_shell_set_fullscreen(window, fullscreen, window->assigned_output); - - if(err == LV_RESULT_INVALID) { - LV_LOG_WARN("Failed to set wayland window to fullscreen"); - return; - } - + lv_wayland_xdg_set_fullscreen(&window->xdg, fullscreen, window->physical_output); window->fullscreen = fullscreen; - window->flush_pending = true; } /********************** * PRIVATE FUNCTIONS **********************/ -void lv_wayland_window_draw(struct window * window, uint32_t width, uint32_t height) +int32_t lv_wayland_window_get_width(lv_wl_window_t * window) { - -#if LV_WAYLAND_WINDOW_DECORATIONS - if(lv_wl_ctx.opt_disable_decorations == false) { - for(size_t i = 0; i < NUM_DECORATIONS; i++) { - window->decoration[i] = create_graphic_obj(window, (FIRST_DECORATION + i), window->body); - if(!window->decoration[i]) { - LV_LOG_ERROR("Failed to create decoration %zu", i); - } - } - } -#endif - - LV_LOG_TRACE("Resizing to %d %d", width, height); - /* First resize */ - if(lv_wayland_window_resize(window, width, height) != LV_RESULT_OK) { - LV_LOG_ERROR("Failed to resize window"); - lv_wayland_xdg_shell_destroy_window_toplevel(window); - } - - lv_refr_now(window->lv_disp); + return lv_display_get_horizontal_resolution(window->lv_disp); +} +int32_t lv_wayland_window_get_height(lv_wl_window_t * window) +{ + return lv_display_get_vertical_resolution(window->lv_disp); } -lv_result_t lv_wayland_window_resize(struct window * window, int width, int height) -{ - -#if LV_WAYLAND_WINDOW_DECORATIONS - if(!window->wl_ctx->opt_disable_decorations && !window->fullscreen) { - width -= (2 * BORDER_SIZE); - height -= (TITLE_BAR_HEIGHT + (2 * BORDER_SIZE)); - } -#endif - if(window->lv_disp) { - lv_display_set_resolution(window->lv_disp, width, height); - window->body->input.pointer.x = LV_MIN((int32_t)window->body->input.pointer.x, (width - 1)); - window->body->input.pointer.y = LV_MIN((int32_t)window->body->input.pointer.y, (height - 1)); - } - - /* On the first resize call, the resolution of the display is already set, so there won't be a trigger on the resolution changed event.*/ - if(!window->is_window_configured) { -#if LV_WAYLAND_USE_DMABUF - lv_result_t err = lv_wayland_dmabuf_resize_window(&window->wl_ctx->dmabuf_ctx, window, width, height); - if(err != LV_RESULT_OK) { - return err; - } -#else - lv_result_t err = lv_wayland_shm_resize_window(&window->wl_ctx->shm_ctx, window, width, height); - if(err != LV_RESULT_OK) { - return err; - } -#endif - } - -#if LV_WAYLAND_WINDOW_DECORATIONS - if(!window->wl_ctx->opt_disable_decorations && !window->fullscreen) { - lv_wayland_window_decoration_create_all(window); - } - else if(!window->wl_ctx->opt_disable_decorations) { - /* Entering fullscreen, detach decorations to prevent xdg_wm_base error 4 */ - /* requested geometry larger than the configured fullscreen state */ - lv_wayland_window_decoration_detach_all(window); - } -#endif - - window->width = width; - window->height = height; - return LV_RESULT_OK; -} - -void lv_wayland_window_destroy(struct window * window) +void lv_wayland_window_delete(lv_wl_window_t * window) { if(!window) { return; } - lv_wayland_xdg_shell_destroy_window_toplevel(window); - lv_wayland_xdg_shell_destroy_window_surface(window); - -#if LV_WAYLAND_WINDOW_DECORATIONS - for(size_t i = 0; i < NUM_DECORATIONS; i++) { - if(window->decoration[i]) { - destroy_graphic_obj(window, window->decoration[i]); - window->decoration[i] = NULL; - } + if(window->close_cb) { + window->close_cb(window->lv_disp); } -#endif + lv_wayland_xdg_delete_window(&window->xdg); - destroy_graphic_obj(window, window->body); -} + /* Commit a NULL buffer to the body surface so that we release buffers*/ + wl_surface_attach(window->body, NULL, 0, 0); + wl_surface_commit(window->body); + wl_display_roundtrip(lv_wl_ctx.wl_display); -const struct wl_callback_listener * lv_wayland_window_get_wl_surface_frame_listener(void) -{ - return &wl_surface_frame_listener; + wl_surface_destroy(window->body); + window->body = NULL; + + /* Make sure buffer is correctly released*/ + wl_display_roundtrip(lv_wl_ctx.wl_display); + + wl_backend_ops.deinit_display(window->backend_display_data, window->lv_disp); + window->backend_display_data = NULL; + + /* Set the driver data to NULL before calling display delete + * so that the delete event doesn't do anything*/ + lv_display_set_driver_data(window->lv_disp, NULL); + lv_display_delete(window->lv_disp); + + + lv_ll_remove(&lv_wl_ctx.window_ll, window); + + if(LV_WAYLAND_DIRECT_EXIT && lv_ll_is_empty(&lv_wl_ctx.window_ll)) { + /* lv_deinit will deinit the wayland driver*/ + lv_deinit(); + exit(0); + } } /********************** * STATIC FUNCTIONS **********************/ -static struct window * create_window(struct lv_wayland_context * app, int width, int height, const char * title) +static void delete_event(lv_event_t * e) { - struct window * window; - - window = lv_ll_ins_tail(&app->window_ll); - LV_ASSERT_MALLOC(window); - if(!window) { - return NULL; - } - - lv_memset(window, 0x00, sizeof(struct window)); - - window->wl_ctx = app; - - // Create wayland buffer and surface - window->body = create_graphic_obj(window, OBJECT_WINDOW, NULL); - window->width = width; - window->height = height; - - if(!window->body) { - LV_LOG_ERROR("cannot create window body"); - goto err_free_window; - } - - if(lv_wayland_xdg_shell_create_window(app, window, title) != LV_RESULT_OK) { - goto err_destroy_surface; - } - - return window; - -err_destroy_surface: - wl_surface_destroy(window->body->surface); - -err_free_window: - lv_ll_remove(&app->window_ll, window); - lv_free(window); - return NULL; + lv_display_t * display = lv_event_get_target(e); + lv_wl_window_t * window = lv_display_get_driver_data(display); + lv_wayland_window_delete(window); } -static struct graphic_object * create_graphic_obj(struct window * window, enum object_type type, - struct graphic_object * parent) +static void refr_start_event(lv_event_t * e) { + lv_display_t * display = lv_event_get_target(e); + lv_wl_window_t * window = lv_display_get_driver_data(display); - /* For now creating a graphical object is similar enough for both shm and dmabuf - * so the heavylifting is done in this function directly but we still - * call the shm and dmabuf specific functions at the end to make sure they can add additional - * attributes if needed - */ - struct graphic_object * obj = NULL; - - LV_UNUSED(parent); - - obj = lv_malloc(sizeof(*obj)); - LV_ASSERT_MALLOC(obj); - if(!obj) { - LV_LOG_ERROR("Failed to create graphic object"); - return NULL; + while(wl_display_prepare_read(lv_wl_ctx.wl_display) != 0) { + wl_display_dispatch_pending(lv_wl_ctx.wl_display); } - lv_memset(obj, 0, sizeof(*obj)); + wl_display_read_events(lv_wl_ctx.wl_display); + wl_display_dispatch_pending(lv_wl_ctx.wl_display); - obj->surface = wl_compositor_create_surface(window->wl_ctx->compositor); - if(!obj->surface) { - LV_LOG_ERROR("Failed to create surface for graphic object"); - lv_free(obj); - return NULL; + + if(lv_wayland_xdg_is_resize_pending(window)) { + lv_wayland_xdg_resize(window); } - wl_surface_set_user_data(obj->surface, obj); - - obj->window = window; - obj->type = type; - -#if LV_WAYLAND_USE_DMABUF - return lv_wayland_dmabuf_on_graphical_object_creation(&window->wl_ctx->dmabuf_ctx, obj); -#else - return lv_wayland_shm_on_graphical_object_creation(&window->wl_ctx->shm_ctx, obj); -#endif } -static void destroy_graphic_obj(struct window * window, struct graphic_object * obj) +static void refr_end_event(lv_event_t * e) { - if(obj->subsurface) { - wl_subsurface_destroy(obj->subsurface); + LV_UNUSED(e); + int ret; + while((ret = wl_display_flush(lv_wl_ctx.wl_display)) == -1 && errno == EAGAIN) { + struct pollfd pfd = { + .fd = wl_display_get_fd(lv_wl_ctx.wl_display), + .events = POLLOUT, + }; + + if(poll(&pfd, 1, -1) == -1) { + LV_LOG_ERROR("poll failed: %s", strerror(errno)); + break; + } + /* Socket is writable now, loop back and try flush again */ } - - wl_surface_destroy(obj->surface); - -#if LV_WAYLAND_USE_DMABUF - lv_wayland_dmabuf_on_graphical_object_destruction(&window->wl_ctx->dmabuf_ctx, obj); -#else - lv_wayland_shm_on_graphical_object_destruction(&window->wl_ctx->shm_ctx, obj); -#endif - lv_free(obj); } - -static void lv_window_graphic_obj_flush_done(void * data, struct wl_callback * cb, uint32_t time) +static void res_changed_event(lv_event_t * e) { - struct graphic_object * obj; - struct window * window; - - LV_UNUSED(time); - - wl_callback_destroy(cb); - - obj = (struct graphic_object *)data; - window = obj->window; - window->frame_counter++; - - LV_LOG_TRACE("frame: %d done, new frame: %d", window->frame_counter - 1, window->frame_counter); - - lv_display_flush_ready(window->lv_disp); + lv_display_t * display = (lv_display_t *) lv_event_get_target(e); + lv_wl_window_t * window = lv_display_get_driver_data(display); + window->backend_display_data = wl_backend_ops.resize_display(lv_wl_ctx.backend_data, display); } #endif /* LV_USE_WAYLAND */ diff --git a/src/drivers/wayland/lv_wl_window.h b/src/drivers/wayland/lv_wl_window.h index 84fd916314..d41ead16be 100644 --- a/src/drivers/wayland/lv_wl_window.h +++ b/src/drivers/wayland/lv_wl_window.h @@ -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 **********************/ diff --git a/src/drivers/wayland/lv_wl_window_decorations.c b/src/drivers/wayland/lv_wl_window_decorations.c deleted file mode 100644 index a1cbd033f3..0000000000 --- a/src/drivers/wayland/lv_wl_window_decorations.c +++ /dev/null @@ -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 -#include - -/********************* - * 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 */ diff --git a/src/drivers/wayland/lv_wl_xdg_shell.c b/src/drivers/wayland/lv_wl_xdg_shell.c index c2010118aa..c395a7acb3 100644 --- a/src/drivers/wayland/lv_wl_xdg_shell.c +++ b/src/drivers/wayland/lv_wl_xdg_shell.c @@ -6,11 +6,10 @@ /********************* * INCLUDES *********************/ -#include "lv_wayland.h" -#if LV_USE_WAYLAND #include "lv_wayland_private.h" +#if LV_USE_WAYLAND #include #include "wayland_xdg_shell.h" @@ -64,9 +63,8 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = {.ping = xdg_wm_ * Shell **********************/ -void lv_wayland_xdg_shell_deinit(void) +void lv_wayland_xdg_deinit(void) { - if(lv_wl_ctx.xdg_wm) { xdg_wm_base_destroy(lv_wl_ctx.xdg_wm); } @@ -76,410 +74,167 @@ void lv_wayland_xdg_shell_deinit(void) * Listeners **********************/ -const struct xdg_wm_base_listener * lv_wayland_xdg_shell_get_wm_base_listener(void) +const struct xdg_wm_base_listener * lv_wayland_xdg_get_wm_base_listener(void) { return &xdg_wm_base_listener; } -const struct xdg_surface_listener * lv_wayland_xdg_shell_get_surface_listener(void) -{ - return &xdg_surface_listener; -} - -const struct xdg_toplevel_listener * lv_wayland_xdg_shell_get_toplevel_listener(void) -{ - return &xdg_toplevel_listener; -} - /********************** * Shell Window **********************/ -lv_result_t lv_wayland_xdg_shell_set_fullscreen(struct window * window, bool fullscreen, struct wl_output * output) +void lv_wayland_xdg_set_fullscreen(lv_wl_window_xdg_t * xdg, bool fullscreen, + struct wl_output * output) { - - if(!window->xdg_toplevel) { - return LV_RESULT_INVALID; - } + LV_ASSERT_NULL(xdg); + LV_ASSERT_NULL(xdg->xdg_toplevel); if(fullscreen) { - xdg_toplevel_set_fullscreen(window->xdg_toplevel, output); + xdg_toplevel_set_fullscreen(xdg->xdg_toplevel, output); } else { - xdg_toplevel_unset_fullscreen(window->xdg_toplevel); + xdg_toplevel_unset_fullscreen(xdg->xdg_toplevel); } - return LV_RESULT_OK; } -lv_result_t lv_wayland_xdg_shell_set_maximized(struct window * window, bool maximized) +void lv_wayland_xdg_set_maximized(lv_wl_window_xdg_t * xdg, bool maximized) { - if(!window->xdg_toplevel) { - return LV_RESULT_INVALID; - } - + LV_ASSERT_NULL(xdg); + LV_ASSERT_NULL(xdg->xdg_toplevel); if(maximized) { - xdg_toplevel_set_maximized(window->xdg_toplevel); + xdg_toplevel_set_maximized(xdg->xdg_toplevel); } else { - xdg_toplevel_unset_maximized(window->xdg_toplevel); + xdg_toplevel_unset_maximized(xdg->xdg_toplevel); + } +} + +void lv_wayland_xdg_set_minimized(lv_wl_window_xdg_t * xdg) +{ + LV_ASSERT_NULL(xdg); + LV_ASSERT_NULL(xdg->xdg_toplevel); + xdg_toplevel_set_minimized(xdg->xdg_toplevel); +} + +lv_result_t lv_wl_xdg_create_window(struct xdg_wm_base * xdg_wm, lv_wl_window_t * window, const char * title) +{ + LV_ASSERT_NULL(xdg_wm); + + window->xdg.xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm, window->body); + if(!window->xdg.xdg_surface) { + LV_LOG_ERROR("Failed to create XDG surface"); + return LV_RESULT_INVALID; } + window->xdg.xdg_toplevel = xdg_surface_get_toplevel(window->xdg.xdg_surface); + if(!window->xdg.xdg_toplevel) { + xdg_surface_destroy(window->xdg.xdg_surface); + window->xdg.xdg_surface = NULL; + LV_LOG_ERROR("Failed to acquire XDG toplevel surface"); + return LV_RESULT_INVALID; + } + xdg_surface_add_listener(window->xdg.xdg_surface, &xdg_surface_listener, window); + xdg_toplevel_add_listener(window->xdg.xdg_toplevel, &xdg_toplevel_listener, window); + xdg_toplevel_set_title(window->xdg.xdg_toplevel, title); + xdg_toplevel_set_app_id(window->xdg.xdg_toplevel, title); return LV_RESULT_OK; } -lv_result_t lv_wayland_xdg_shell_set_minimized(struct window * window) +void lv_wayland_xdg_configure_surface(lv_wl_window_t * window) { - if(!window->xdg_toplevel) { - return LV_RESULT_INVALID; - } - - xdg_toplevel_set_minimized(window->xdg_toplevel); - return LV_RESULT_OK; + /* XDG surfaces need to be configured before a buffer can be attached. + * An (XDG) surface commit (without an attached buffer) triggers this + * configure event */ + wl_surface_commit(window->body); + wl_display_roundtrip(lv_wl_ctx.wl_display); + LV_ASSERT_MSG(window->resize_event.pending, "Failed to receive the xdg_surface configuration event"); +} +bool lv_wayland_xdg_is_resize_pending(lv_wl_window_t * window) +{ + return window->resize_event.pending; } -#if LV_WAYLAND_USE_DMABUF -void lv_wayland_xdg_shell_ack_configure(struct window * window, uint32_t serial) +void lv_wayland_xdg_resize(lv_wl_window_t * window) { - if(window->xdg_surface && serial > 0) { - xdg_surface_ack_configure(window->xdg_surface, serial); - LV_LOG_TRACE("XDG surface configure acknowledged (serial=%u)", serial); - } -} -#endif - -lv_result_t lv_wayland_xdg_shell_create_window(struct lv_wayland_context * app, struct window * window, - const char * title) -{ - if(!app->xdg_wm) { - return LV_RESULT_INVALID; + if(!window->resize_event.pending) { + return; } - window->xdg_surface = xdg_wm_base_get_xdg_surface(app->xdg_wm, window->body->surface); - if(!window->xdg_surface) { - LV_LOG_ERROR("cannot create XDG surface"); - return LV_RESULT_INVALID; - } - xdg_surface_add_listener(window->xdg_surface, lv_wayland_xdg_shell_get_surface_listener(), window); - - window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); - if(!window->xdg_toplevel) { - xdg_surface_destroy(window->xdg_surface); - LV_LOG_ERROR("cannot get XDG toplevel surface"); - return LV_RESULT_INVALID; - } - - xdg_toplevel_add_listener(window->xdg_toplevel, lv_wayland_xdg_shell_get_toplevel_listener(), window); - xdg_toplevel_set_title(window->xdg_toplevel, title); - xdg_toplevel_set_app_id(window->xdg_toplevel, title); - - return LV_RESULT_OK; + lv_display_set_resolution(window->lv_disp, + window->resize_event.width, + window->resize_event.height); + xdg_surface_ack_configure(window->resize_event.xdg_surface, window->resize_event.serial); + window->resize_event.pending = false; + window->xdg.configured = true; } -void lv_wayland_xdg_shell_configure_surface(struct window * window) +void lv_wayland_xdg_delete_window(lv_wl_window_xdg_t * xdg) { - // XDG surfaces need to be configured before a buffer can be attached. - // An (XDG) surface commit (without an attached buffer) triggers this - // configure event - window->is_window_configured = false; - wl_surface_commit(window->body->surface); - wl_display_roundtrip(lv_wl_ctx.display); - LV_ASSERT_MSG(window->is_window_configured, "Failed to receive the xdg_surface configuration event"); -} - -lv_result_t lv_wayland_xdg_shell_destroy_window_surface(struct window * window) -{ - - if(!window->xdg_surface) { - return LV_RESULT_INVALID; + if(xdg->xdg_toplevel) { + xdg_toplevel_destroy(xdg->xdg_toplevel); } - xdg_surface_destroy(window->xdg_surface); - return LV_RESULT_OK; -} - -lv_result_t lv_wayland_xdg_shell_destroy_window_toplevel(struct window * window) -{ - - if(!window->xdg_toplevel) { - return LV_RESULT_INVALID; + if(xdg->xdg_surface) { + xdg_surface_destroy(xdg->xdg_surface); } - xdg_toplevel_destroy(window->xdg_toplevel); - return LV_RESULT_OK; -} - -/********************** - * Shell Input - **********************/ - -void lv_wayland_xdg_shell_handle_pointer_event(struct lv_wayland_context * app, uint32_t serial, uint32_t button, - uint32_t state) -{ - struct window * window = app->pointer_obj->window; - int pos_x = (int)app->pointer_obj->input.pointer.x; - int pos_y = (int)app->pointer_obj->input.pointer.y; - - switch(app->pointer_obj->type) { - case OBJECT_TITLEBAR: - if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) { - if(window->xdg_toplevel) { - xdg_toplevel_move(window->xdg_toplevel, app->wl_seat, serial); - window->flush_pending = true; - } - } - break; - case OBJECT_BUTTON_MAXIMIZE: - if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_RELEASED)) { - if(lv_wayland_xdg_shell_set_maximized(window, !window->maximized) == LV_RESULT_OK) { - window->maximized = !window->maximized; - window->flush_pending = true; - } - } - break; - case OBJECT_BUTTON_MINIMIZE: - if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_RELEASED)) { - if(lv_wayland_xdg_shell_set_minimized(window) == LV_RESULT_OK) { - window->flush_pending = true; - } - } - break; - case OBJECT_BORDER_TOP: - if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) { - if(window->xdg_toplevel && !window->maximized) { - uint32_t edge; - if(pos_x < (BORDER_SIZE * 5)) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; - } - else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - } - else { - edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP; - } - xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge); - window->flush_pending = true; - } - } - break; - case OBJECT_BORDER_BOTTOM: - if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) { - if(window->xdg_toplevel && !window->maximized) { - uint32_t edge; - if(pos_x < (BORDER_SIZE * 5)) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; - } - else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; - } - else { - edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; - } - xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge); - window->flush_pending = true; - } - } - break; - case OBJECT_BORDER_LEFT: - if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) { - if(window->xdg_toplevel && !window->maximized) { - uint32_t edge; - if(pos_y < (BORDER_SIZE * 5)) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; - } - else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; - } - else { - edge = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; - } - xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge); - window->flush_pending = true; - } - } - break; - case OBJECT_BORDER_RIGHT: - if((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) { - if(window->xdg_toplevel && !window->maximized) { - uint32_t edge; - if(pos_y < (BORDER_SIZE * 5)) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - } - else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) { - edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; - } - else { - edge = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - } - xdg_toplevel_resize(window->xdg_toplevel, window->wl_ctx->wl_seat, serial, edge); - window->flush_pending = true; - } - } - break; - case OBJECT_BUTTON_CLOSE: - case OBJECT_WINDOW: - /* These events are handled in the main pointer callback */ - break; - } -} - -const char * lv_wayland_xdg_shell_get_cursor_name(const struct lv_wayland_context * app) -{ - - if(!app->pointer_obj->window->xdg_toplevel || app->opt_disable_decorations) { - return LV_WAYLAND_DEFAULT_CURSOR_NAME; - } - int pos_x = (int)app->pointer_obj->input.pointer.x; - int pos_y = (int)app->pointer_obj->input.pointer.y; - - struct window * window = app->pointer_obj->window; - - switch(app->pointer_obj->type) { - case OBJECT_BORDER_TOP: - if(window->maximized) { - // do nothing - } - else if(pos_x < (BORDER_SIZE * 5)) { - return "top_left_corner"; - } - else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) { - return "top_right_corner"; - } - else { - return "top_side"; - } - break; - case OBJECT_BORDER_BOTTOM: - if(window->maximized) { - // do nothing - } - else if(pos_x < (BORDER_SIZE * 5)) { - return "bottom_left_corner"; - } - else if(pos_x >= (window->width + BORDER_SIZE - (BORDER_SIZE * 5))) { - return "bottom_right_corner"; - } - else { - return "bottom_side"; - } - break; - case OBJECT_BORDER_LEFT: - if(window->maximized) { - // do nothing - } - else if(pos_y < (BORDER_SIZE * 5)) { - return "top_left_corner"; - } - else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) { - return "bottom_left_corner"; - } - else { - return "left_side"; - } - break; - case OBJECT_BORDER_RIGHT: - if(window->maximized) { - // do nothing - } - else if(pos_y < (BORDER_SIZE * 5)) { - return "top_right_corner"; - } - else if(pos_y >= (window->height + BORDER_SIZE - (BORDER_SIZE * 5))) { - return "bottom_right_corner"; - } - else { - return "right_side"; - } - break; - default: - break; - } - - return LV_WAYLAND_DEFAULT_CURSOR_NAME; + xdg->xdg_surface = NULL; + xdg->xdg_toplevel = NULL; } /********************** * STATIC FUNCTIONS **********************/ + static void xdg_surface_handle_configure(void * data, struct xdg_surface * xdg_surface, uint32_t serial) { - struct window * window = (struct window *)data; + lv_wl_window_t * window = (lv_wl_window_t *)data; -#if LV_WAYLAND_USE_DMABUF - LV_LOG_TRACE("XDG surface configure: serial=%u, dmabuf_resize_pending=%d", - serial, window->dmabuf_resize_pending); - - /* Store the configure serial for synchronization */ - window->configure_serial = serial; - window->surface_configured = true; - window->configure_acknowledged = false; - - /* Only acknowledge immediately if no DMABUF resize is pending */ - if(!window->dmabuf_resize_pending) { + if(!window->resize_event.requested) { + LV_LOG_TRACE("resize event not requested. ignoring it"); + window->xdg.configured = true; xdg_surface_ack_configure(xdg_surface, serial); - window->configure_acknowledged = true; - LV_LOG_TRACE("XDG surface configure acknowledged immediately"); + return; } - else { - LV_LOG_TRACE("XDG surface configure deferred - DMABUF resize pending"); - } -#else - xdg_surface_ack_configure(xdg_surface, serial); -#endif - if(!window->is_window_configured) { - /* This branch is executed at launch */ - if(!window->resize_pending) { - /* Use the size passed to the create_window function */ - lv_wayland_window_draw(window, window->width, window->height); - } - else { - /* Handle early maximization or fullscreen, */ - /* by using the size communicated by the compositor */ - /* when the initial xdg configure event arrives */ - lv_wayland_window_draw(window, window->resize_width, window->resize_height); - window->width = window->resize_width; - window->height = window->resize_height; - window->resize_pending = false; - } - } - window->is_window_configured = true; + LV_LOG_TRACE("resize event requested and now pending"); + window->resize_event.pending = true; + window->resize_event.requested = false; + window->resize_event.xdg_surface = xdg_surface; + window->resize_event.serial = serial; } static void xdg_toplevel_handle_configure(void * data, struct xdg_toplevel * xdg_toplevel, int32_t width, int32_t height, struct wl_array * states) { - struct window * window = (struct window *)data; + lv_wl_window_t * window = (lv_wl_window_t *)data; LV_UNUSED(xdg_toplevel); LV_UNUSED(states); - LV_LOG_TRACE("XDG toplevel configure: w=%d h=%d (current: %dx%d)", - width, height, window->width, window->height); - LV_LOG_TRACE("current body w:%d h:%d", window->body->width, window->body->height); + width, height, lv_wayland_window_get_width(window), lv_wayland_window_get_height(window)); - if((width <= 0) || (height <= 0)) { + if((width < 0) || (height < 0)) { LV_LOG_TRACE("will not resize to w:%d h:%d", width, height); return; } - if((width != window->width) || (height != window->height)) { - window->resize_width = width; - window->resize_height = height; - window->resize_pending = true; -#if LV_WAYLAND_USE_DMABUF - window->dmabuf_resize_pending = true; -#endif - } - else { - LV_LOG_TRACE("resize_pending not set w:%d h:%d", width, height); + window->xdg.configured = false; + /* Width and height are already ok, don't resize*/ + if(width == lv_wayland_window_get_width(window) && + height == lv_wayland_window_get_height(window)) { + LV_LOG_TRACE("Window's size is already correct. Ignore resize request"); + return; } + window->resize_event.requested = true; + window->resize_event.width = width ? width : lv_display_get_horizontal_resolution(window->lv_disp); + window->resize_event.height = height ? height : lv_display_get_vertical_resolution(window->lv_disp); } static void xdg_toplevel_handle_close(void * data, struct xdg_toplevel * xdg_toplevel) { - struct window * window = (struct window *)data; - window->shall_close = true; - LV_UNUSED(xdg_toplevel); + lv_wl_window_t * window = (lv_wl_window_t *)data; + lv_wayland_window_delete(window); } static void xdg_wm_base_ping(void * data, struct xdg_wm_base * xdg_wm_base, uint32_t serial) diff --git a/src/lv_api_map_v9_4.h b/src/lv_api_map_v9_4.h index 9978e90245..031012dc0b 100644 --- a/src/lv_api_map_v9_4.h +++ b/src/lv_api_map_v9_4.h @@ -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"*/ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index eb92fb9d44..80107a3396 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -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 diff --git a/src/lv_init.c b/src/lv_init.c index 02a5f75e4f..d4c83e8a61 100644 --- a/src/lv_init.c +++ b/src/lv_init.c @@ -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(); diff --git a/tests/src/lv_test_conf_full.h b/tests/src/lv_test_conf_full.h index 27d323ca11..1f38331828 100644 --- a/tests/src/lv_test_conf_full.h +++ b/tests/src/lv_test_conf_full.h @@ -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 diff --git a/tests/src/lv_test_perf_conf.h b/tests/src/lv_test_perf_conf.h index 4e1d57c01e..6c4ad37a7d 100644 --- a/tests/src/lv_test_perf_conf.h +++ b/tests/src/lv_test_perf_conf.h @@ -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