mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-09 20:27:41 +08:00
feat(wayland): rewrite driver (#9195)
Co-authored-by: ychsiao168 <ychsiao168@pm.me>
This commit is contained in:
@@ -1896,35 +1896,11 @@ menu "LVGL configuration"
|
||||
config LV_USE_WAYLAND
|
||||
bool "Use the wayland client to open a window and handle inputs on Linux or BSD"
|
||||
default n
|
||||
config LV_WAYLAND_WINDOW_DECORATIONS
|
||||
bool "Draw client side window decorations, only necessary on Mutter (GNOME)"
|
||||
|
||||
config LV_WAYLAND_DIRECT_EXIT
|
||||
bool "Deinitialize LVGL and quit the application when the last wayland window closes"
|
||||
default y
|
||||
depends on LV_USE_WAYLAND
|
||||
default n
|
||||
config LV_WAYLAND_BUF_COUNT
|
||||
int "Use 1 for single buffer with partial render mode or 2 for double buffer with full render mode"
|
||||
depends on LV_USE_WAYLAND
|
||||
default 1
|
||||
choice
|
||||
prompt "Wayland rendering mode"
|
||||
depends on LV_USE_WAYLAND
|
||||
default LV_WAYLAND_RENDER_MODE_PARTIAL
|
||||
|
||||
config LV_WAYLAND_RENDER_MODE_PARTIAL
|
||||
bool "Use the buffer(s) to render the screen is smaller parts"
|
||||
depends on !LV_WAYLAND_USE_DMABUF
|
||||
|
||||
config LV_WAYLAND_RENDER_MODE_DIRECT
|
||||
bool "Only the changed areas will be updated with 2 screen sized buffers"
|
||||
depends on LV_WAYLAND_USE_DMABUF
|
||||
|
||||
config LV_WAYLAND_RENDER_MODE_FULL
|
||||
bool "Always redraw the whole screen even if only one pixel has been changed with 2 screen sized buffers"
|
||||
depends on LV_WAYLAND_USE_DMABUF
|
||||
endchoice
|
||||
|
||||
config LV_WAYLAND_USE_DMABUF
|
||||
bool "Use DMA buffers for frame buffers"
|
||||
depends on LV_USE_WAYLAND && LV_USE_G2D
|
||||
|
||||
config LV_USE_LINUX_FBDEV
|
||||
bool "Use Linux framebuffer device"
|
||||
|
||||
@@ -4,20 +4,22 @@
|
||||
Wayland Display/Inputs driver
|
||||
=============================
|
||||
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
********
|
||||
|
||||
The **Wayland** `driver <https://github.com/lvgl/lvgl/tree/master/src/drivers/wayland>`__
|
||||
offers support for simulating the LVGL display and keyboard/mouse inputs in a desktop
|
||||
window.
|
||||
The Wayland `driver <https://github.com/lvgl/lvgl/tree/master/src/drivers/wayland>`__ provides integration between LVGL and Wayland-based systems,
|
||||
allowing LVGL applications to render directly into a Wayland surface and handle keyboard, mouse and touch input. This makes it suitable
|
||||
for production deployments, such as kiosk interfaces, control panels, or other embedded GUIs where Wayland is the display server.
|
||||
|
||||
In addition to production use, the driver is also useful for development on linux desktop environments, offering a convenient way to simulate and validate
|
||||
your LVGL applications without dedicated hardware. It serves as an alternative to the X11 and SDL2 drivers.
|
||||
|
||||
It is an alternative to **X11** or **SDL2**
|
||||
|
||||
The main purpose for this driver is for testing/debugging the LVGL application. It can
|
||||
also be used to run applications in "kiosk mode".
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
************
|
||||
|
||||
The wayland driver requires some dependencies.
|
||||
|
||||
@@ -34,8 +36,64 @@ On Fedora
|
||||
sudo dnf install wayland-devel libxkbcommon-devel wayland-utils wayland-protocols-devel
|
||||
|
||||
|
||||
|
||||
Rendering Backends
|
||||
******************
|
||||
|
||||
The Wayland driver supports multiple rendering backends, allowing you to choose the most appropriate rendering method for your hardware and use case.
|
||||
|
||||
|
||||
SHM Backend (Default)
|
||||
---------------------
|
||||
|
||||
The **SHM (Shared Memory)** backend is the default rendering backend used by the Wayland driver.
|
||||
It uses Wayland's shared memory protocol (``wl_shm``) for rendering, which is supported across all Wayland compositors.
|
||||
|
||||
**Features:**
|
||||
|
||||
* Double-buffered direct rendering
|
||||
* Universal compatibility with all Wayland compositors
|
||||
* No special hardware requirements
|
||||
|
||||
**Limitations:**
|
||||
|
||||
* Rotation is not currently supported
|
||||
|
||||
**Usage:**
|
||||
|
||||
The SHM backend is enabled by default and requires no additional configuration.
|
||||
|
||||
|
||||
G2D Backend
|
||||
-----------
|
||||
|
||||
The G2D backend leverages NXP's hardware-accelerated 2D graphics engine available on i.MX processors. This backend provides improved performance on NXP platforms.
|
||||
|
||||
**Features:**
|
||||
|
||||
* Hardware-accelerated rendering
|
||||
* Double-buffered direct rendering
|
||||
* Rotation support (0°, 90°, 180°, 270°)
|
||||
|
||||
**Requirements:**
|
||||
|
||||
* Hardware with G2D support (e.g., NXP i.MX6/i.MX8 series)
|
||||
* G2D library and drivers installed on the system
|
||||
|
||||
**Usage:**
|
||||
|
||||
Enable the G2D backend in ``lv_conf.h``:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define LV_USE_DRAW_G2D 1
|
||||
|
||||
When ``LV_USE_DRAW_G2D`` is enabled, the Wayland driver will automatically use the G2D backend instead of the default SHM backend.
|
||||
|
||||
|
||||
|
||||
Configuring the wayland driver
|
||||
------------------------------
|
||||
******************************
|
||||
|
||||
1. Enable the wayland driver in ``lv_conf.h``
|
||||
|
||||
@@ -43,46 +101,18 @@ Configuring the wayland driver
|
||||
|
||||
#define LV_USE_WAYLAND 1
|
||||
|
||||
2. Optional configuration options:
|
||||
|
||||
Some optional settings depend on whether DMA buffer support is enabled (`LV_WAYLAND_USE_DMABUF`). The table below summarizes valid combinations and limitations:
|
||||
|
||||
.. list-table:: Configuration possibilities
|
||||
:widths: 50 25 25
|
||||
:header-rows: 1
|
||||
Reference Project
|
||||
*****************
|
||||
|
||||
* - Configuration Option
|
||||
- Without DMABUF
|
||||
- With DMABUF
|
||||
`LVGL Linux port <https://github.com/lvgl/lv_port_linux/>`__ serves as a reference project for setting up wayland. It uses CMake to generate
|
||||
the required protocols at build time.
|
||||
|
||||
* - `LV_DRAW_USE_G2D`
|
||||
- Not required
|
||||
- **Required**
|
||||
|
||||
* - `LV_WAYLAND_BUF_COUNT`
|
||||
- `1`
|
||||
- `1` or `2`
|
||||
|
||||
* - `LV_WAYLAND_RENDER_MODE`
|
||||
- `LV_DISPLAY_RENDER_MODE_PARTIAL`
|
||||
- `LV_DISPLAY_RENDER_MODE_DIRECT` or `LV_DISPLAY_RENDER_MODE_FULL`
|
||||
|
||||
* - `LV_WAYLAND_WINDOW_DECORATIONS`
|
||||
- `1` or `0`
|
||||
- `0`
|
||||
|
||||
Additional notes
|
||||
|
||||
* DMABUF support (`LV_WAYLAND_USE_DMABUF`) improves performance and enables more render modes but has specific requirements and restrictions.
|
||||
* `LV_WAYLAND_WINDOW_DECORATIONS` is only required for some compositors (e.g., GNOME/Mutter or Weston).
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
|
||||
|
||||
Usage
|
||||
-----
|
||||
Getting started
|
||||
***************
|
||||
|
||||
#. In ``main.c`` ``#include "lv_drivers/wayland/wayland.h"``
|
||||
#. Enable the Wayland driver in ``lv_conf.h`` with ``LV_USE_WAYLAND 1``
|
||||
@@ -113,14 +143,29 @@ Handles for input devices of each display can be obtained using
|
||||
``lv_wayland_get_indev_keyboard()``, ``lv_wayland_get_indev_touchscreen()``,
|
||||
``lv_wayland_get_indev_pointer()`` and ``lv_wayland_get_indev_pointeraxis()`` respectively.
|
||||
|
||||
|
||||
Fullscreen mode
|
||||
^^^^^^^^^^^^^^^
|
||||
---------------
|
||||
|
||||
To programmatically fullscreen the window, use the ``lv_wayland_window_set_fullscreen()``
|
||||
function respectively with ``true`` or ``false`` for the ``fullscreen`` argument.
|
||||
|
||||
|
||||
Maximized mode
|
||||
--------------
|
||||
|
||||
To programmatically maximize the window,
|
||||
use the ``lv_wayland_window_set_maximized()`` function respectively with ``true``
|
||||
or ``false`` for the ``maximized`` argument.
|
||||
|
||||
Minimize window
|
||||
---------------
|
||||
|
||||
To programmatically minimize the window, use the ``lv_wayland_window_set_minimized()`` function.
|
||||
|
||||
|
||||
Physical display assignment
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
---------------------------
|
||||
|
||||
When using multiple physical displays, you can control which display a fullscreen window
|
||||
appears on by assigning it to a specific physical display before entering fullscreen mode.
|
||||
@@ -142,12 +187,6 @@ To remove the physical display assignment and return to default behavior, use
|
||||
|
||||
lv_wayland_unassign_physical_display(disp);
|
||||
|
||||
Maximized mode
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
To programmatically maximize the window,
|
||||
use the ``lv_wayland_window_set_maximized()`` function respectively with ``true``
|
||||
or ``false`` for the ``maximized`` argument.
|
||||
|
||||
|
||||
Custom timer handler
|
||||
@@ -164,22 +203,15 @@ Wrapping the call to ``lv_timer_handler()`` is a necessity to have more control
|
||||
when the LVGL flush callback is called.
|
||||
|
||||
Building the wayland driver
|
||||
---------------------------
|
||||
***************************
|
||||
|
||||
An example simulator is available in this `repo <https://github.com/lvgl/lv_port_linux/>`__
|
||||
The `reference project <https://github.com/lvgl/lv_port_linux/>`__ uses CMakeLists to generate the necessary dependencies at build time.
|
||||
|
||||
If there is a need to use driver with another build system. The source and header files for the XDG shell
|
||||
must be generated from the definitions for the XDG shell protocol.
|
||||
Mainly, the project generates the necessary protocols with the ``wayland-scanner`` utility.
|
||||
|
||||
In the example CMake is used to perform the operation by invoking the ``wayland-scanner`` utility
|
||||
The wayland protocols are defined using XML files which are present in ``/usr/share/wayland-protocols``
|
||||
|
||||
To achieve this manually,
|
||||
|
||||
Make sure the dependencies listed at the start of the article are installed.
|
||||
|
||||
The wayland protocol is defined using XML files which are present in ``/usr/share/wayland-protocols``
|
||||
|
||||
To generate the required files run the following commands:
|
||||
By default, LVGL relies on the ``xdg-shell`` protocol for window management to generate it run the following commands:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
@@ -198,19 +230,45 @@ The resulting files can then be integrated into the project, it's better to re-r
|
||||
each build to ensure that the correct versions are generated, they must match the version of the ``wayland-client``
|
||||
dynamically linked library installed on the system.
|
||||
|
||||
Current state and objectives
|
||||
----------------------------
|
||||
|
||||
* Add direct rendering mode
|
||||
* Refactor the shell integrations to avoid excessive conditional compilation
|
||||
* Technically, the wayland driver allows to create multiple windows - but this feature is experimental.
|
||||
* Eventually add enhanced support for XDG shell to allow the creation of desktop apps on Unix-like platforms,
|
||||
similar to what the win32 driver does.
|
||||
* Add a support for Mesa, currently wl_shm is used and it's not the most effective technique.
|
||||
|
||||
Window Decorations
|
||||
******************
|
||||
|
||||
.. note::
|
||||
|
||||
As of LVGL v9.5, the `LV_WAYLAND_WINDOW_DECORATIONS` option has been removed.
|
||||
|
||||
Window decorations (title bars, borders, close buttons, etc.) are now the responsibility of the application developer, not LVGL.
|
||||
This change gives you full control over the appearance and behavior of your window decorations.
|
||||
|
||||
Creating Window Decorations
|
||||
---------------------------
|
||||
|
||||
You can create your own window decorations using LVGL widgets. For example, use the :ref:`lv_win` widget to add a title bar with buttons,
|
||||
or build custom decorations from basic widgets like containers, labels, and buttons.
|
||||
|
||||
This approach allows you to:
|
||||
- Design decorations that match your application's style
|
||||
- Add custom controls and functionality
|
||||
- Maintain consistent UI across different Wayland compositors
|
||||
- Have complete control over the look and feel
|
||||
|
||||
For applications that don't need decorations (fullscreen, kiosk mode, etc.), simply create your UI without them.
|
||||
|
||||
|
||||
|
||||
Current state and objectives
|
||||
****************************
|
||||
|
||||
* EGL Support
|
||||
* Server-side window decorations
|
||||
* Rotation support for the SHM backend
|
||||
|
||||
|
||||
|
||||
Bug reports
|
||||
-----------
|
||||
***********
|
||||
|
||||
The wayland driver is currently under construction, bug reports, contributions and feedback are always welcome.
|
||||
|
||||
@@ -226,4 +284,3 @@ This will create a log file called ``debug`` in the ``/tmp`` directory, copy-pas
|
||||
The log file contains LVGL logs and the wayland messages.
|
||||
|
||||
Be sure to replicate the problem quickly otherwise the logs become too big
|
||||
|
||||
|
||||
@@ -1168,7 +1168,6 @@
|
||||
#define LV_WAYLAND_USE_DMABUF 0 /**< Use DMA buffers for frame buffers. Requires LV_USE_DRAW_G2D */
|
||||
#define LV_WAYLAND_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL /**< DMABUF supports LV_DISPLAY_RENDER_MODE_FULL and LV_DISPLAY_RENDER_MODE_DIRECT*/
|
||||
/**< When LV_WAYLAND_USE_DMABUF is disabled, only LV_DISPLAY_RENDER_MODE_PARTIAL is supported*/
|
||||
#define LV_WAYLAND_WINDOW_DECORATIONS 0 /**< Draw client side window decorations only necessary on Mutter/GNOME. Not supported using DMABUF*/
|
||||
#endif
|
||||
|
||||
/** Driver for /dev/fb */
|
||||
|
||||
+1
-5
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -218,10 +218,19 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
|
||||
#define LV_LOG_TRACE_ANIM 0
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
#if LV_USE_WAYLAND == 0
|
||||
#define LV_WAYLAND_USE_DMABUF 0
|
||||
#define LV_WAYLAND_WINDOW_DECORATIONS 0
|
||||
#endif /* LV_USE_WAYLAND */
|
||||
#if LV_USE_WAYLAND
|
||||
/*Automatically detect wayland backend*/
|
||||
#if LV_USE_G2D
|
||||
#define LV_WAYLAND_USE_G2D 1
|
||||
#define LV_WAYLAND_USE_SHM 0
|
||||
#else
|
||||
#define LV_WAYLAND_USE_G2D 0
|
||||
#define LV_WAYLAND_USE_SHM 1
|
||||
#endif
|
||||
#else
|
||||
#define LV_WAYLAND_USE_G2D 0
|
||||
#define LV_WAYLAND_USE_SHM 0
|
||||
#endif
|
||||
|
||||
#if LV_USE_LINUX_DRM == 0
|
||||
#define LV_LINUX_DRM_USE_EGL 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,19 +14,16 @@ extern "C" {
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_wayland.h"
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_WAYLAND
|
||||
|
||||
|
||||
#include "lv_wayland_smm.h"
|
||||
#include <sys/poll.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland_xdg_shell.h>
|
||||
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include "../../misc/lv_types.h"
|
||||
#include "lv_wl_backend_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -35,115 +32,57 @@ extern "C" {
|
||||
#define LV_WAYLAND_DEFAULT_CURSOR_NAME "left_ptr"
|
||||
#define LV_WAYLAND_MAX_OUTPUTS 8
|
||||
|
||||
#define LVGL_DRAW_BUFFER_DIV (8)
|
||||
#define DMG_CACHE_CAPACITY (32)
|
||||
#define TAG_LOCAL (0)
|
||||
#define TAG_BUFFER_DAMAGE (1)
|
||||
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
#define TITLE_BAR_HEIGHT 24
|
||||
#define BORDER_SIZE 2
|
||||
#else
|
||||
#define TITLE_BAR_HEIGHT 0
|
||||
#define BORDER_SIZE 0
|
||||
#endif
|
||||
|
||||
#define BUTTON_MARGIN LV_MAX((TITLE_BAR_HEIGHT / 6), BORDER_SIZE)
|
||||
#define BUTTON_PADDING LV_MAX((TITLE_BAR_HEIGHT / 8), BORDER_SIZE)
|
||||
#define BUTTON_SIZE (TITLE_BAR_HEIGHT - (2 * BUTTON_MARGIN))
|
||||
|
||||
#ifndef LV_WAYLAND_CYCLE_PERIOD
|
||||
#define LV_WAYLAND_CYCLE_PERIOD LV_MIN(LV_DEF_REFR_PERIOD, 1)
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
enum object_type {
|
||||
OBJECT_TITLEBAR = 0,
|
||||
OBJECT_BUTTON_CLOSE,
|
||||
OBJECT_BUTTON_MAXIMIZE,
|
||||
OBJECT_BUTTON_MINIMIZE,
|
||||
OBJECT_BORDER_TOP,
|
||||
OBJECT_BORDER_BOTTOM,
|
||||
OBJECT_BORDER_LEFT,
|
||||
OBJECT_BORDER_RIGHT,
|
||||
OBJECT_WINDOW,
|
||||
};
|
||||
struct _lv_wl_window_t;
|
||||
|
||||
#define FIRST_DECORATION (OBJECT_TITLEBAR)
|
||||
#define LAST_DECORATION (OBJECT_BORDER_RIGHT)
|
||||
#define NUM_DECORATIONS (LAST_DECORATION - FIRST_DECORATION + 1)
|
||||
typedef struct {
|
||||
struct wl_pointer * wl_pointer;
|
||||
struct wl_surface * cursor_surface;
|
||||
lv_point_t point;
|
||||
lv_indev_state_t left_btn_state;
|
||||
lv_indev_state_t right_btn_state;
|
||||
lv_indev_state_t wheel_btn_state;
|
||||
int16_t wheel_diff;
|
||||
} lv_wl_seat_pointer_t;
|
||||
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
#define MAX_BUFFER_PLANES 4
|
||||
#endif
|
||||
|
||||
struct window;
|
||||
struct input {
|
||||
struct {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
lv_indev_state_t left_button;
|
||||
lv_indev_state_t right_button;
|
||||
lv_indev_state_t wheel_button;
|
||||
int16_t wheel_diff;
|
||||
} pointer;
|
||||
|
||||
struct {
|
||||
lv_key_t key;
|
||||
lv_indev_state_t state;
|
||||
} keyboard;
|
||||
typedef struct {
|
||||
struct wl_touch * wl_touch;
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
lv_indev_touch_data_t touches[10];
|
||||
uint8_t touch_event_cnt;
|
||||
uint8_t event_cnt;
|
||||
uint8_t primary_id;
|
||||
#else
|
||||
struct {
|
||||
lv_point_t point;
|
||||
lv_indev_state_t state;
|
||||
} touch;
|
||||
#endif
|
||||
};
|
||||
lv_point_t point;
|
||||
lv_indev_state_t state;
|
||||
#endif /*LV_USE_GESTURE_RECOGNITION*/
|
||||
} lv_wl_seat_touch_t;
|
||||
|
||||
struct seat {
|
||||
struct wl_touch * wl_touch;
|
||||
struct wl_pointer * wl_pointer;
|
||||
typedef struct {
|
||||
struct wl_keyboard * wl_keyboard;
|
||||
struct xkb_keymap * xkb_keymap;
|
||||
struct xkb_state * xkb_state;
|
||||
|
||||
struct {
|
||||
struct xkb_keymap * keymap;
|
||||
struct xkb_state * state;
|
||||
} xkb;
|
||||
};
|
||||
lv_key_t key;
|
||||
lv_indev_state_t state;
|
||||
bool is_pressed;
|
||||
} lv_wl_seat_keyboard_t;
|
||||
|
||||
struct graphic_object {
|
||||
struct window * window;
|
||||
struct wl_surface * surface;
|
||||
struct wl_subsurface * subsurface;
|
||||
smm_buffer_t * pending_buffer;
|
||||
smm_group_t * buffer_group;
|
||||
struct input input;
|
||||
enum object_type type;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct buffer * buffers;
|
||||
struct zwp_linux_dmabuf_v1 * handler;
|
||||
uint32_t format;
|
||||
uint8_t last_used;
|
||||
} dmabuf_ctx_t;
|
||||
struct wl_seat * wl_seat;
|
||||
|
||||
lv_wl_seat_pointer_t * pointer;
|
||||
lv_wl_seat_touch_t * touch;
|
||||
lv_wl_seat_keyboard_t * keyboard;
|
||||
} lv_wl_seat_t;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct wl_shm * handler;
|
||||
uint32_t format;
|
||||
} shm_ctx_t;
|
||||
|
||||
struct output_info {
|
||||
struct wl_output * wl_output;
|
||||
char name[64];
|
||||
int width;
|
||||
@@ -151,117 +90,64 @@ struct output_info {
|
||||
int refresh;
|
||||
int scale;
|
||||
int flags;
|
||||
};
|
||||
} lv_wl_output_info_t;
|
||||
|
||||
struct lv_wayland_context {
|
||||
struct wl_display * display;
|
||||
struct wl_registry * registry;
|
||||
struct wl_compositor * compositor;
|
||||
struct wl_subcompositor * subcompositor;
|
||||
struct wl_seat * wl_seat;
|
||||
struct wl_cursor_theme * cursor_theme;
|
||||
struct wl_surface * cursor_surface;
|
||||
shm_ctx_t shm_ctx;
|
||||
struct output_info outputs[LV_WAYLAND_MAX_OUTPUTS];
|
||||
typedef struct {
|
||||
struct wl_display * wl_display;
|
||||
struct wl_registry * wl_registry;
|
||||
struct wl_compositor * wl_compositor;
|
||||
struct wl_shm * wl_shm;
|
||||
lv_wl_seat_t seat;
|
||||
|
||||
void * backend_data;
|
||||
lv_wl_output_info_t physical_outputs[LV_WAYLAND_MAX_OUTPUTS];
|
||||
uint8_t wl_output_count;
|
||||
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
dmabuf_ctx_t dmabuf_ctx;
|
||||
#endif
|
||||
|
||||
struct xdg_wm_base * xdg_wm;
|
||||
|
||||
#ifdef LV_WAYLAND_WINDOW_DECORATIONS
|
||||
bool opt_disable_decorations;
|
||||
#endif
|
||||
|
||||
struct xkb_context * xkb_context;
|
||||
|
||||
struct seat seat;
|
||||
|
||||
struct graphic_object * touch_obj;
|
||||
struct graphic_object * pointer_obj;
|
||||
struct graphic_object * keyboard_obj;
|
||||
|
||||
lv_ll_t window_ll;
|
||||
lv_timer_t * cycle_timer;
|
||||
} lv_wl_ctx_t;
|
||||
|
||||
bool cursor_flush_pending;
|
||||
struct pollfd wayland_pfd;
|
||||
};
|
||||
typedef struct {
|
||||
struct xdg_surface * xdg_surface;
|
||||
uint32_t serial;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
bool requested;
|
||||
bool pending;
|
||||
} lv_wl_resize_event_t;
|
||||
|
||||
struct window {
|
||||
typedef struct {
|
||||
struct xdg_surface * xdg_surface;
|
||||
struct xdg_toplevel * xdg_toplevel;
|
||||
bool configured;
|
||||
} lv_wl_window_xdg_t;
|
||||
|
||||
|
||||
typedef struct _lv_wl_window_t {
|
||||
lv_display_t * lv_disp;
|
||||
void * backend_display_data;
|
||||
lv_indev_t * lv_indev_pointer;
|
||||
lv_indev_t * lv_indev_pointeraxis;
|
||||
lv_indev_t * lv_indev_touch;
|
||||
lv_indev_t * lv_indev_keyboard;
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf;
|
||||
|
||||
lv_wayland_display_close_f_t close_cb;
|
||||
struct lv_wayland_context * wl_ctx;
|
||||
lv_wayland_display_close_cb_t close_cb;
|
||||
lv_wl_window_xdg_t xdg;
|
||||
|
||||
/* The current physical assigned output */
|
||||
struct wl_output * assigned_output;
|
||||
struct xdg_surface * xdg_surface;
|
||||
struct xdg_toplevel * xdg_toplevel;
|
||||
uint32_t wm_capabilities;
|
||||
struct wl_output * physical_output;
|
||||
|
||||
struct graphic_object * body;
|
||||
struct {
|
||||
lv_area_t cache[DMG_CACHE_CAPACITY];
|
||||
unsigned char start;
|
||||
unsigned char end;
|
||||
unsigned size;
|
||||
} dmg_cache;
|
||||
/* The current body surface */
|
||||
struct wl_surface * body;
|
||||
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
struct graphic_object * decoration[NUM_DECORATIONS];
|
||||
#endif
|
||||
lv_wl_resize_event_t resize_event;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
bool resize_pending;
|
||||
int resize_width;
|
||||
int resize_height;
|
||||
|
||||
bool flush_pending;
|
||||
bool shall_close;
|
||||
bool closed;
|
||||
bool maximized;
|
||||
bool fullscreen;
|
||||
uint32_t frame_counter;
|
||||
bool is_window_configured;
|
||||
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
/* XDG/DMABUF synchronization fields */
|
||||
bool dmabuf_resize_pending;
|
||||
bool surface_configured;
|
||||
bool configure_acknowledged;
|
||||
uint32_t configure_serial;
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
struct buffer * decorators_buf[8];
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
} lv_wl_window_t;
|
||||
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
struct buffer {
|
||||
int busy;
|
||||
struct window * window;
|
||||
int plane_count;
|
||||
int dmabuf_fds[MAX_BUFFER_PLANES];
|
||||
uint32_t strides[MAX_BUFFER_PLANES];
|
||||
uint32_t offsets[MAX_BUFFER_PLANES];
|
||||
struct wl_buffer * buffer;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
void * buf_base[MAX_BUFFER_PLANES];
|
||||
lv_draw_buf_t * lv_draw_buf;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@@ -271,133 +157,56 @@ struct buffer {
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
extern struct lv_wayland_context lv_wl_ctx;
|
||||
extern lv_wl_ctx_t lv_wl_ctx;
|
||||
|
||||
/**********************
|
||||
* Driver
|
||||
**********************/
|
||||
|
||||
void lv_wayland_init(void);
|
||||
lv_result_t lv_wayland_init(void);
|
||||
void lv_wayland_deinit(void);
|
||||
void lv_wayland_wait_flush_cb(lv_display_t * disp);
|
||||
void lv_wayland_event_cb(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* Window
|
||||
**********************/
|
||||
|
||||
const struct wl_callback_listener * lv_wayland_window_get_wl_surface_frame_listener(void);
|
||||
int32_t lv_wayland_window_get_width(lv_wl_window_t * window);
|
||||
int32_t lv_wayland_window_get_height(lv_wl_window_t * window);
|
||||
|
||||
void lv_wayland_window_draw(struct window * window, uint32_t width, uint32_t height);
|
||||
lv_result_t lv_wayland_window_resize(struct window * window, int width, int height);
|
||||
void lv_wayland_window_destroy(struct window * window);
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
uint32_t lv_wayland_window_decoration_create_all(struct window * window);
|
||||
void lv_wayland_window_decoration_detach_all(struct window * window);
|
||||
bool lv_wayland_window_decoration_create(struct window * window, struct graphic_object * decoration, int window_width,
|
||||
int window_height);
|
||||
bool lv_wayland_window_decoration_attach(struct window * window, struct graphic_object * decoration,
|
||||
void * decoration_buffer, struct graphic_object * parent);
|
||||
void lv_wayland_window_decoration_detach(struct window * window, struct graphic_object * decoration);
|
||||
#endif
|
||||
void lv_wayland_window_delete(lv_wl_window_t * window);
|
||||
|
||||
/**********************
|
||||
* Window Management
|
||||
**********************/
|
||||
const struct xdg_wm_base_listener * lv_wayland_xdg_get_wm_base_listener(void);
|
||||
|
||||
const struct xdg_surface_listener * lv_wayland_xdg_shell_get_surface_listener(void);
|
||||
const struct xdg_toplevel_listener * lv_wayland_xdg_shell_get_toplevel_listener(void);
|
||||
const struct xdg_wm_base_listener * lv_wayland_xdg_shell_get_wm_base_listener(void);
|
||||
lv_result_t lv_wayland_xdg_shell_set_maximized(struct window * window, bool maximized);
|
||||
lv_result_t lv_wayland_xdg_shell_set_minimized(struct window * window);
|
||||
lv_result_t lv_wayland_xdg_shell_set_fullscreen(struct window * window, bool fullscreen, struct wl_output * output);
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
void lv_wayland_xdg_shell_ack_configure(struct window * window, uint32_t serial);
|
||||
#endif
|
||||
lv_result_t lv_wayland_xdg_shell_create_window(struct lv_wayland_context * app, struct window * window,
|
||||
const char * title);
|
||||
void lv_wayland_xdg_shell_configure_surface(struct window * window);
|
||||
lv_result_t lv_wayland_xdg_shell_destroy_window_toplevel(struct window * window);
|
||||
lv_result_t lv_wayland_xdg_shell_destroy_window_surface(struct window * window);
|
||||
void lv_wayland_xdg_shell_handle_pointer_event(struct lv_wayland_context * app, uint32_t serial, uint32_t button,
|
||||
uint32_t state);
|
||||
|
||||
const char * lv_wayland_xdg_shell_get_cursor_name(const struct lv_wayland_context * app);
|
||||
void lv_wayland_xdg_shell_deinit(void);
|
||||
|
||||
/**********************
|
||||
* SHM
|
||||
**********************/
|
||||
|
||||
void lv_wayland_shm_set_interface(shm_ctx_t * context, struct wl_registry * registry, uint32_t name,
|
||||
const char * interface, uint32_t version);
|
||||
|
||||
struct graphic_object * lv_wayland_shm_on_graphical_object_creation(shm_ctx_t * context, struct graphic_object * obj);
|
||||
void lv_wayland_shm_on_graphical_object_destruction(shm_ctx_t * context, struct graphic_object * obj);
|
||||
lv_result_t lv_wayland_shm_set_draw_buffers(shm_ctx_t * context, lv_display_t * display, struct window * window);
|
||||
lv_result_t lv_wayland_shm_create_draw_buffers(shm_ctx_t * context, struct window * window);
|
||||
lv_result_t lv_wayland_shm_resize_window(shm_ctx_t * context, struct window * window, int32_t width, int32_t height);
|
||||
lv_result_t lv_wayland_shm_is_ready(shm_ctx_t * context);
|
||||
|
||||
void lv_wayland_shm_delete_draw_buffers(shm_ctx_t * context, struct window * window);
|
||||
void lv_wayland_shm_initalize_context(shm_ctx_t * context);
|
||||
void lv_wayland_shm_deinit(shm_ctx_t * context);
|
||||
void lv_wayland_shm_flush_partial_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p);
|
||||
|
||||
struct wl_cursor_theme * lv_wayland_shm_load_cursor_theme(shm_ctx_t * context);
|
||||
|
||||
/**********************
|
||||
* DMABUF
|
||||
**********************/
|
||||
|
||||
void lv_wayland_dmabuf_set_interface(dmabuf_ctx_t * context, struct wl_registry * registry, uint32_t name,
|
||||
const char * interface, uint32_t version);
|
||||
|
||||
struct graphic_object * lv_wayland_dmabuf_on_graphical_object_creation(dmabuf_ctx_t * context,
|
||||
struct graphic_object * obj);
|
||||
|
||||
void lv_wayland_dmabuf_on_graphical_object_destruction(dmabuf_ctx_t * context, struct graphic_object * obj);
|
||||
lv_result_t lv_wayland_dmabuf_set_draw_buffers(dmabuf_ctx_t * context, lv_display_t * display);
|
||||
lv_result_t lv_wayland_dmabuf_create_draw_buffers(dmabuf_ctx_t * context, struct window * window);
|
||||
lv_result_t lv_wayland_dmabuf_resize_window(dmabuf_ctx_t * context, struct window * window, int width, int height);
|
||||
lv_result_t lv_wayland_dmabuf_is_ready(dmabuf_ctx_t * context);
|
||||
void destroy_decorators_buf(struct window * window, struct graphic_object * decoration);
|
||||
void lv_wayland_dmabuf_destroy_draw_buffers(dmabuf_ctx_t * context, struct window * window);
|
||||
void lv_wayland_dmabuf_initalize_context(dmabuf_ctx_t * context);
|
||||
void lv_wayland_dmabuf_deinit(dmabuf_ctx_t * context);
|
||||
void lv_wayland_dmabuf_flush_full_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p);
|
||||
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
struct buffer * dmabuf_acquire_pool_buffer(struct window * window, struct graphic_object * decoration);
|
||||
#endif
|
||||
/**********************
|
||||
* SME
|
||||
**********************/
|
||||
|
||||
const struct smm_events * lv_wayland_sme_get_events(void);
|
||||
|
||||
/**********************
|
||||
* Seat
|
||||
**********************/
|
||||
|
||||
const struct wl_seat_listener * lv_wayland_seat_get_listener(void);
|
||||
void lv_wayland_xdg_set_maximized(lv_wl_window_xdg_t * xdg, bool maximized);
|
||||
void lv_wayland_xdg_set_minimized(lv_wl_window_xdg_t * xdg);
|
||||
void lv_wayland_xdg_set_fullscreen(lv_wl_window_xdg_t * xdg, bool fullscreen,
|
||||
struct wl_output * output);
|
||||
lv_result_t lv_wl_xdg_create_window(struct xdg_wm_base * xdg_wm, lv_wl_window_t * window,
|
||||
const char * title);
|
||||
bool lv_wayland_xdg_is_resize_pending(lv_wl_window_t * window);
|
||||
void lv_wayland_xdg_configure_surface(lv_wl_window_t * window);
|
||||
void lv_wayland_xdg_resize(lv_wl_window_t * window);
|
||||
void lv_wayland_xdg_delete_window(lv_wl_window_xdg_t * xdg);
|
||||
void lv_wayland_xdg_deinit(void);
|
||||
|
||||
/**********************
|
||||
* Input
|
||||
**********************/
|
||||
|
||||
const struct wl_keyboard_listener * lv_wayland_keyboard_get_listener(void);
|
||||
const struct wl_pointer_listener * lv_wayland_pointer_get_listener(void);
|
||||
const struct wl_touch_listener * lv_wayland_touch_get_listener(void);
|
||||
void lv_wayland_seat_init(lv_wl_seat_t * seat, struct wl_registry * registry, uint32_t name, uint32_t version);
|
||||
void lv_wayland_seat_deinit(lv_wl_seat_t * seat);
|
||||
|
||||
/**********************
|
||||
* Cache
|
||||
**********************/
|
||||
lv_wl_seat_pointer_t * lv_wayland_seat_pointer_create(struct wl_seat * seat, struct wl_surface * surface);
|
||||
void lv_wayland_seat_pointer_delete(lv_wl_seat_pointer_t * seat_pointer);
|
||||
|
||||
void lv_wayland_cache_add_area(struct window * window, smm_buffer_t * buf, const lv_area_t * area);
|
||||
void lv_wayland_cache_clear(struct window * window);
|
||||
void lv_wayland_cache_apply_areas(struct window * window, void * dest, void * src, smm_buffer_t * src_buf);
|
||||
void lv_wayland_cache_purge(struct window * window, smm_buffer_t * buf);
|
||||
lv_wl_seat_touch_t * lv_wayland_seat_touch_create(struct wl_seat * seat);
|
||||
void lv_wayland_seat_touch_delete(lv_wl_seat_touch_t * seat_touch);
|
||||
|
||||
lv_wl_seat_keyboard_t * lv_wayland_seat_keyboard_create(struct wl_seat * seat);
|
||||
void lv_wayland_seat_keyboard_delete(lv_wl_seat_keyboard_t * seat_keyboard);
|
||||
|
||||
/* Updates indev's driver data with the given 'read_cb' to 'new_driver_data' */
|
||||
void lv_wayland_update_indevs(lv_indev_read_cb_t read_cb, void * new_driver_data);
|
||||
|
||||
#endif /* LV_USE_WAYLAND */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* @file lv_wl_backend_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_WL_BACKEND_PRIVATE_H
|
||||
#define LV_WL_BACKEND_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_wayland.h"
|
||||
|
||||
#if LV_USE_WAYLAND
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* @typedef lv_wayland_backend_init_t
|
||||
* @brief Initialize the backend context
|
||||
*
|
||||
* This function is called once when the Wayland driver is initialized to create
|
||||
* the global backend context. The returned pointer will be passed as backend_ctx
|
||||
* to all other backend operations.
|
||||
*
|
||||
* @return Pointer to backend-specific context data, or NULL on failure
|
||||
*
|
||||
* @note This is called before any displays are created
|
||||
* @see lv_wayland_backend_deinit_t
|
||||
*/
|
||||
typedef void * (*lv_wayland_backend_init_t)(void);
|
||||
|
||||
/**
|
||||
* @typedef lv_wayland_backend_deinit_t
|
||||
* @brief Deinitialize the backend context
|
||||
*
|
||||
* This function is called when the Wayland driver is deinitialized. It must
|
||||
* clean up all resources allocated in the init function and free the backend
|
||||
* context.
|
||||
*
|
||||
* @param[in] backend_ctx Pointer to the backend context returned by init
|
||||
*
|
||||
* @note This is called after all displays have been destroyed
|
||||
* @see lv_wayland_backend_init_t
|
||||
*/
|
||||
typedef void (*lv_wayland_backend_deinit_t)(void * backend_ctx);
|
||||
|
||||
/**
|
||||
* @typedef lv_wayland_backend_init_display_t
|
||||
* @brief Initialize a new display
|
||||
*
|
||||
* This function is called when creating a new LVGL display on Wayland. It should
|
||||
* allocate and initialize per-display resources needed for rendering.
|
||||
*
|
||||
* @param[in] backend_ctx Pointer to the backend context
|
||||
* @param[in] display Pointer to the LVGL display object
|
||||
* @param[in] width Initial width of the display in pixels
|
||||
* @param[in] height Initial height of the display in pixels
|
||||
* @return Pointer to display-specific data, or NULL on failure
|
||||
*
|
||||
* @note The returned pointer can be retrieved later using
|
||||
* lv_wayland_get_backend_display_data()
|
||||
* @note It is expected that each display gets its own data structure in order for a backend
|
||||
* to support multiple displays
|
||||
*/
|
||||
typedef void * (*lv_wayland_backend_init_display_t)(void * backend_ctx, lv_display_t * display, int32_t width,
|
||||
int32_t height);
|
||||
|
||||
/**
|
||||
* @typedef lv_wayland_backend_resize_display_t
|
||||
* @brief Resize or reconfigure a display
|
||||
*
|
||||
* This function is called when a display needs to be resized or when its rotation
|
||||
* is modified. The backend should update its rendering resources accordingly.
|
||||
*
|
||||
* @param[in] backend_ctx Pointer to the backend context
|
||||
* @param[in] display Pointer to the LVGL display object being resized
|
||||
* @return Pointer to updated display-specific data, or NULL on failure
|
||||
*
|
||||
* @note This may be called multiple times during a display's lifetime
|
||||
* @note The returned pointer will replace the previous display data. It can be
|
||||
* retrieved using lv_wayland_get_backend_display_data()
|
||||
* @warning The display data is overwritten with the return value of this function
|
||||
*/
|
||||
typedef void * (*lv_wayland_backend_resize_display_t)(void * backend_ctx, lv_display_t * display);
|
||||
|
||||
/**
|
||||
* @typedef lv_wayland_backend_destroy_display_t
|
||||
* @brief Destroy a display
|
||||
*
|
||||
* This function is called when an LVGL display is being destroyed. It must clean up
|
||||
* all per-display resources and free the display data that was allocated in
|
||||
* init_display.
|
||||
*
|
||||
* @param[in] backend_ctx Pointer to the backend context
|
||||
* @param[in] display Pointer to the LVGL display object being destroyed
|
||||
*
|
||||
* @note The display data associated with this display must be freed
|
||||
*/
|
||||
typedef void (*lv_wayland_backend_destroy_display_t)(void * backend_ctx, lv_display_t * display);
|
||||
|
||||
/**
|
||||
* @typedef lv_wayland_backend_global_handler_t
|
||||
* @brief Handle Wayland global objects
|
||||
*
|
||||
* This function is called for every global object advertised by the Wayland
|
||||
* compositor. The backend can use this to bind to Wayland protocols it requires
|
||||
* (e.g., wl_shm, EGL extensions, DMA-BUF protocols, etc.).
|
||||
*
|
||||
* @param[in] backend_ctx Pointer to the backend context
|
||||
* @param[in] registry Wayland registry object
|
||||
* @param[in] name Numeric name of the global object
|
||||
* @param[in] interface String name of the interface (e.g., "wl_shm")
|
||||
* @param[in] version Version number of the interface
|
||||
*
|
||||
* @note This is called during Wayland connection setup
|
||||
* @note The backend should use wl_registry_bind() to bind to needed protocols
|
||||
*/
|
||||
typedef void (*lv_wayland_backend_global_handler_t)(void * backend_ctx, struct wl_registry * registry, uint32_t name,
|
||||
const char * interface, uint32_t version);
|
||||
|
||||
/**
|
||||
* @struct lv_wayland_backend_ops_t
|
||||
* @brief Wayland backend operations structure
|
||||
*
|
||||
* This structure defines the complete set of operations that a Wayland backend
|
||||
* must implement. All function pointers must be non-NULL.
|
||||
*
|
||||
* @par Lifecycle Order:
|
||||
* 1. init() - Initialize backend context
|
||||
* 2. global_handler() - Called for each Wayland global (may be called multiple times)
|
||||
* 3. init_display() - Create display (may be called multiple times for multiple displays)
|
||||
* 4. resize_display() - Resize display (called as needed)
|
||||
* 5. deinit_display() - Destroy display (called once per display)
|
||||
* 6. deinit() - Clean up backend context
|
||||
*/
|
||||
typedef struct {
|
||||
lv_wayland_backend_init_t init; /**< Initialize backend context */
|
||||
lv_wayland_backend_global_handler_t global_handler; /**< Handle Wayland global objects */
|
||||
lv_wayland_backend_init_display_t init_display; /**< Initialize a new display */
|
||||
lv_wayland_backend_resize_display_t resize_display; /**< Resize or reconfigure display */
|
||||
lv_wayland_backend_destroy_display_t deinit_display; /**< Destroy a display */
|
||||
lv_wayland_backend_deinit_t deinit; /**< Deinitialize backend context */
|
||||
} lv_wayland_backend_ops_t;
|
||||
|
||||
extern const lv_wayland_backend_ops_t wl_backend_ops;
|
||||
|
||||
/** @brief Get the backend-specific display data
|
||||
*
|
||||
* Retrieves the per-display data pointer that was returned by the backend's
|
||||
* init_display/resize_display functions. This allows the backend to access its own
|
||||
* display-specific state and resources.
|
||||
*
|
||||
* @param[in] display Pointer to the LVGL display object
|
||||
* @return Pointer to backend-specific display data
|
||||
*
|
||||
* @note This returns the value that was returned by lv_wayland_backend_init_display_t
|
||||
* or lv_wayland_backend_resize_display_t
|
||||
* @see lv_wayland_backend_init_display_t
|
||||
*/
|
||||
void * lv_wayland_get_backend_display_data(lv_display_t * display);
|
||||
|
||||
/**
|
||||
* @brief Get the Wayland surface for rendering
|
||||
*
|
||||
* Retrieves the wl_surface object associated with the display window. This is the
|
||||
* surface that the backend must use for all rendering operations (attaching buffers,
|
||||
* committing frames, etc.).
|
||||
*
|
||||
* @param[in] display Pointer to the LVGL display object
|
||||
* @return Pointer to the Wayland surface for rendering, or NULL if not available
|
||||
*
|
||||
* @note This surface is managed by the Wayland driver and must not be destroyed
|
||||
* by the backend
|
||||
* @note All rendering output should be attached to this surface
|
||||
*/
|
||||
struct wl_surface * lv_wayland_get_window_surface(lv_display_t * display);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_WAYLAND*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_WL_BACKEND_PRIVATE_H*/
|
||||
@@ -1,133 +0,0 @@
|
||||
/**
|
||||
* @file lv_wl_cache.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_wayland.h"
|
||||
|
||||
#if LV_USE_WAYLAND
|
||||
|
||||
#include "lv_wayland_private.h"
|
||||
#include <string.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* PRIVATE FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_wayland_cache_apply_areas(struct window * window, void * dest, void * src, smm_buffer_t * src_buf)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned char start;
|
||||
int32_t y;
|
||||
lv_area_t * dmg;
|
||||
lv_area_t * next_dmg;
|
||||
smm_buffer_t * next_buf = smm_next(src_buf);
|
||||
const struct smm_buffer_properties * props = SMM_BUFFER_PROPERTIES(src_buf);
|
||||
struct graphic_object * obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
|
||||
uint8_t bpp;
|
||||
|
||||
if(next_buf == NULL) {
|
||||
next_dmg = (window->dmg_cache.cache + window->dmg_cache.end);
|
||||
}
|
||||
else {
|
||||
next_dmg = SMM_BUFFER_PROPERTIES(next_buf)->tag[TAG_BUFFER_DAMAGE];
|
||||
}
|
||||
|
||||
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
|
||||
|
||||
/* Apply all buffer damage areas */
|
||||
start = ((lv_area_t *)SMM_BUFFER_PROPERTIES(src_buf)->tag[TAG_BUFFER_DAMAGE] - window->dmg_cache.cache);
|
||||
while((window->dmg_cache.cache + start) != next_dmg) {
|
||||
/* Copy an area from source to destination (line-by-line) */
|
||||
dmg = (window->dmg_cache.cache + start);
|
||||
for(y = dmg->y1; y <= dmg->y2; y++) {
|
||||
offset = (dmg->x1 + (y * obj->width)) * bpp;
|
||||
|
||||
memcpy(((char *)dest) + offset, ((char *)src) + offset, ((dmg->x2 - dmg->x1 + 1) * bpp));
|
||||
}
|
||||
|
||||
start++;
|
||||
start %= DMG_CACHE_CAPACITY;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_wayland_cache_add_area(struct window * window, smm_buffer_t * buf, const lv_area_t * area)
|
||||
{
|
||||
if(SMM_BUFFER_PROPERTIES(buf)->tag[TAG_BUFFER_DAMAGE] == NULL) {
|
||||
/* Buffer damage beyond cache capacity */
|
||||
return;
|
||||
}
|
||||
|
||||
if((window->dmg_cache.start == window->dmg_cache.end) && (window->dmg_cache.size)) {
|
||||
/* This buffer has more damage then the cache's capacity, so
|
||||
* clear cache and leave buffer damage unrecorded
|
||||
*/
|
||||
lv_wayland_cache_clear(window);
|
||||
SMM_TAG(buf, TAG_BUFFER_DAMAGE, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add damage area to cache */
|
||||
memcpy(window->dmg_cache.cache + window->dmg_cache.end, area, sizeof(lv_area_t));
|
||||
window->dmg_cache.end++;
|
||||
window->dmg_cache.end %= DMG_CACHE_CAPACITY;
|
||||
window->dmg_cache.size++;
|
||||
}
|
||||
|
||||
void lv_wayland_cache_clear(struct window * window)
|
||||
{
|
||||
window->dmg_cache.start = window->dmg_cache.end;
|
||||
window->dmg_cache.size = 0;
|
||||
}
|
||||
|
||||
void lv_wayland_cache_purge(struct window * window, smm_buffer_t * buf)
|
||||
{
|
||||
lv_area_t * next_dmg;
|
||||
smm_buffer_t * next_buf = smm_next(buf);
|
||||
|
||||
/* Remove all damage areas up until start of next buffers damage */
|
||||
if(next_buf == NULL) {
|
||||
lv_wayland_cache_clear(window);
|
||||
}
|
||||
else {
|
||||
next_dmg = SMM_BUFFER_PROPERTIES(next_buf)->tag[TAG_BUFFER_DAMAGE];
|
||||
while((window->dmg_cache.cache + window->dmg_cache.start) != next_dmg) {
|
||||
window->dmg_cache.start++;
|
||||
window->dmg_cache.start %= DMG_CACHE_CAPACITY;
|
||||
window->dmg_cache.size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /* LV_USE_WAYLAND */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -51,6 +51,8 @@ static lv_key_t keycode_xkb_to_lv(xkb_keysym_t xkb_key);
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static struct xkb_context * xkb_context;
|
||||
|
||||
static const struct wl_keyboard_listener keyboard_listener = {
|
||||
.keymap = keyboard_handle_keymap,
|
||||
.enter = keyboard_handle_enter,
|
||||
@@ -70,16 +72,20 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
||||
lv_indev_t * lv_wayland_keyboard_create(void)
|
||||
{
|
||||
|
||||
lv_indev_t * keyboard = lv_indev_create();
|
||||
lv_indev_set_type(keyboard, LV_INDEV_TYPE_KEYPAD);
|
||||
lv_indev_set_read_cb(keyboard, keyboard_read);
|
||||
lv_indev_t * indev = lv_indev_create();
|
||||
if(!indev) {
|
||||
return NULL;
|
||||
}
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
|
||||
lv_indev_set_read_cb(indev, keyboard_read);
|
||||
lv_indev_set_driver_data(indev, lv_wl_ctx.seat.keyboard);
|
||||
|
||||
return keyboard;
|
||||
return indev;
|
||||
}
|
||||
|
||||
lv_indev_t * lv_wayland_get_keyboard(lv_display_t * display)
|
||||
{
|
||||
struct window * window = lv_display_get_driver_data(display);
|
||||
lv_wl_window_t * window = lv_display_get_driver_data(display);
|
||||
if(!window) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -90,128 +96,142 @@ lv_indev_t * lv_wayland_get_keyboard(lv_display_t * display)
|
||||
* PRIVATE FUNCTIONS
|
||||
**********************/
|
||||
|
||||
const struct wl_keyboard_listener * lv_wayland_keyboard_get_listener(void)
|
||||
lv_wl_seat_keyboard_t * lv_wayland_seat_keyboard_create(struct wl_seat * wl_seat)
|
||||
{
|
||||
return &keyboard_listener;
|
||||
|
||||
struct wl_keyboard * keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
if(!keyboard) {
|
||||
LV_LOG_WARN("Failed to get seat keyboard");
|
||||
return NULL;
|
||||
}
|
||||
if(!xkb_context && !(xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS))) {
|
||||
LV_LOG_WARN("Failed to create xkb context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_wl_seat_keyboard_t * wl_seat_keyboard = lv_zalloc(sizeof(*wl_seat_keyboard));
|
||||
LV_ASSERT_MALLOC(wl_seat_keyboard);
|
||||
if(!wl_seat_keyboard) {
|
||||
LV_LOG_WARN("Failed to allocate memory for wayland keyboard");
|
||||
return NULL;
|
||||
}
|
||||
wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
|
||||
wl_keyboard_set_user_data(keyboard, wl_seat_keyboard);
|
||||
|
||||
wl_seat_keyboard->wl_keyboard = keyboard;
|
||||
lv_wayland_update_indevs(keyboard_read, wl_seat_keyboard);
|
||||
|
||||
return wl_seat_keyboard;
|
||||
}
|
||||
void lv_wayland_seat_keyboard_delete(lv_wl_seat_keyboard_t * seat_keyboard)
|
||||
{
|
||||
lv_wayland_update_indevs(keyboard_read, NULL);
|
||||
lv_free(seat_keyboard);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void keyboard_read(lv_indev_t * drv, lv_indev_data_t * data)
|
||||
static void keyboard_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
struct window * window = lv_display_get_driver_data(lv_indev_get_display(drv));
|
||||
if(!window || window->closed) {
|
||||
lv_wl_seat_keyboard_t * kbdata = lv_indev_get_driver_data(indev);
|
||||
if(!kbdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->key = window->body->input.keyboard.key;
|
||||
data->state = window->body->input.keyboard.state;
|
||||
data->key = kbdata->key;
|
||||
data->state = kbdata->state;
|
||||
}
|
||||
|
||||
static void keyboard_handle_keymap(void * data, struct wl_keyboard * keyboard, uint32_t format, int fd, uint32_t size)
|
||||
{
|
||||
struct lv_wayland_context * app = data;
|
||||
|
||||
struct xkb_keymap * keymap;
|
||||
struct xkb_state * state;
|
||||
char * map_str;
|
||||
|
||||
LV_UNUSED(keyboard);
|
||||
LV_UNUSED(data);
|
||||
lv_wl_seat_keyboard_t * kbdata = wl_keyboard_get_user_data(keyboard);
|
||||
|
||||
if(format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
||||
LV_LOG_WARN("Can't handle formats other than WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
char * map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if(map_str == MAP_FAILED) {
|
||||
LV_LOG_WARN("Failed to mmap keyboard keymap file");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up XKB keymap */
|
||||
keymap = xkb_keymap_new_from_string(app->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
|
||||
struct xkb_keymap * keymap = xkb_keymap_new_from_string(xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
|
||||
munmap(map_str, size);
|
||||
close(fd);
|
||||
|
||||
if(!keymap) {
|
||||
LV_LOG_ERROR("failed to compile keymap");
|
||||
LV_LOG_WARN("Failed to compile keymap");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up XKB state */
|
||||
state = xkb_state_new(keymap);
|
||||
struct xkb_state * state = xkb_state_new(keymap);
|
||||
if(!state) {
|
||||
LV_LOG_ERROR("failed to create XKB state");
|
||||
LV_LOG_WARN("Failed to create XKB state");
|
||||
xkb_keymap_unref(keymap);
|
||||
return;
|
||||
}
|
||||
|
||||
xkb_keymap_unref(app->seat.xkb.keymap);
|
||||
xkb_state_unref(app->seat.xkb.state);
|
||||
app->seat.xkb.keymap = keymap;
|
||||
app->seat.xkb.state = state;
|
||||
xkb_keymap_unref(kbdata->xkb_keymap);
|
||||
xkb_state_unref(kbdata->xkb_state);
|
||||
|
||||
kbdata->xkb_keymap = keymap;
|
||||
kbdata->xkb_state = state;
|
||||
}
|
||||
|
||||
static void keyboard_handle_enter(void * data, struct wl_keyboard * keyboard, uint32_t serial,
|
||||
struct wl_surface * surface, struct wl_array * keys)
|
||||
{
|
||||
struct lv_wayland_context * app = data;
|
||||
|
||||
LV_UNUSED(data);
|
||||
LV_UNUSED(keyboard);
|
||||
LV_UNUSED(serial);
|
||||
LV_UNUSED(keys);
|
||||
|
||||
if(!surface) {
|
||||
app->keyboard_obj = NULL;
|
||||
}
|
||||
else {
|
||||
app->keyboard_obj = wl_surface_get_user_data(surface);
|
||||
}
|
||||
LV_UNUSED(surface);
|
||||
}
|
||||
|
||||
static void keyboard_handle_leave(void * data, struct wl_keyboard * keyboard, uint32_t serial,
|
||||
struct wl_surface * surface)
|
||||
{
|
||||
struct lv_wayland_context * app = data;
|
||||
|
||||
LV_UNUSED(serial);
|
||||
LV_UNUSED(keyboard);
|
||||
|
||||
if(!surface || (app->keyboard_obj == wl_surface_get_user_data(surface))) {
|
||||
app->keyboard_obj = NULL;
|
||||
}
|
||||
LV_UNUSED(data);
|
||||
LV_UNUSED(surface);
|
||||
}
|
||||
|
||||
static void keyboard_handle_key(void * data, struct wl_keyboard * keyboard, uint32_t serial, uint32_t time,
|
||||
uint32_t key, uint32_t state)
|
||||
{
|
||||
struct lv_wayland_context * app = data;
|
||||
const uint32_t code = (key + 8);
|
||||
const xkb_keysym_t * syms;
|
||||
xkb_keysym_t sym = XKB_KEY_NoSymbol;
|
||||
|
||||
LV_UNUSED(data);
|
||||
LV_UNUSED(serial);
|
||||
LV_UNUSED(time);
|
||||
LV_UNUSED(keyboard);
|
||||
|
||||
if(!app->keyboard_obj || !app->seat.xkb.state) {
|
||||
lv_wl_seat_keyboard_t * kbdata = wl_keyboard_get_user_data(keyboard);
|
||||
const uint32_t code = (key + 8);
|
||||
|
||||
if(!kbdata->xkb_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(xkb_state_key_get_syms(app->seat.xkb.state, code, &syms) == 1) {
|
||||
sym = syms[0];
|
||||
const xkb_keysym_t * syms = XKB_KEY_NoSymbol;
|
||||
if(xkb_state_key_get_syms(kbdata->xkb_state, code, &syms) != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lv_key_t lv_key = keycode_xkb_to_lv(sym);
|
||||
const lv_key_t lv_key = keycode_xkb_to_lv(syms[0]);
|
||||
const lv_indev_state_t lv_state =
|
||||
(state == WL_KEYBOARD_KEY_STATE_PRESSED) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
|
||||
|
||||
if(lv_key != 0) {
|
||||
app->keyboard_obj->input.keyboard.key = lv_key;
|
||||
app->keyboard_obj->input.keyboard.state = lv_state;
|
||||
kbdata->key = lv_key;
|
||||
kbdata->state = lv_state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,83 +239,78 @@ static void keyboard_handle_modifiers(void * data, struct wl_keyboard * keyboard
|
||||
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked,
|
||||
uint32_t group)
|
||||
{
|
||||
struct lv_wayland_context * app = data;
|
||||
|
||||
LV_UNUSED(serial);
|
||||
LV_UNUSED(keyboard);
|
||||
LV_UNUSED(data);
|
||||
lv_wl_seat_keyboard_t * kbdata = wl_keyboard_get_user_data(keyboard);
|
||||
|
||||
/* If we're not using a keymap, then we don't handle PC-style modifiers */
|
||||
if(!app->seat.xkb.keymap) {
|
||||
if(!kbdata->xkb_keymap) {
|
||||
return;
|
||||
}
|
||||
|
||||
xkb_state_update_mask(app->seat.xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
xkb_state_update_mask(kbdata->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
static lv_key_t keycode_xkb_to_lv(xkb_keysym_t xkb_key)
|
||||
{
|
||||
lv_key_t key = 0;
|
||||
|
||||
if(((xkb_key >= XKB_KEY_space) && (xkb_key <= XKB_KEY_asciitilde))) {
|
||||
key = xkb_key;
|
||||
if(xkb_key >= XKB_KEY_space && xkb_key <= XKB_KEY_asciitilde) {
|
||||
return xkb_key;
|
||||
}
|
||||
else if(((xkb_key >= XKB_KEY_KP_0) && (xkb_key <= XKB_KEY_KP_9))) {
|
||||
key = (xkb_key & 0x003f);
|
||||
if(xkb_key >= XKB_KEY_KP_0 && xkb_key <= XKB_KEY_KP_9) {
|
||||
return (xkb_key & 0x003f);
|
||||
}
|
||||
else {
|
||||
switch(xkb_key) {
|
||||
case XKB_KEY_BackSpace:
|
||||
key = LV_KEY_BACKSPACE;
|
||||
break;
|
||||
case XKB_KEY_Return:
|
||||
case XKB_KEY_KP_Enter:
|
||||
key = LV_KEY_ENTER;
|
||||
break;
|
||||
case XKB_KEY_Escape:
|
||||
key = LV_KEY_ESC;
|
||||
break;
|
||||
case XKB_KEY_Delete:
|
||||
case XKB_KEY_KP_Delete:
|
||||
key = LV_KEY_DEL;
|
||||
break;
|
||||
case XKB_KEY_Home:
|
||||
case XKB_KEY_KP_Home:
|
||||
key = LV_KEY_HOME;
|
||||
break;
|
||||
case XKB_KEY_Left:
|
||||
case XKB_KEY_KP_Left:
|
||||
key = LV_KEY_LEFT;
|
||||
break;
|
||||
case XKB_KEY_Up:
|
||||
case XKB_KEY_KP_Up:
|
||||
key = LV_KEY_UP;
|
||||
break;
|
||||
case XKB_KEY_Right:
|
||||
case XKB_KEY_KP_Right:
|
||||
key = LV_KEY_RIGHT;
|
||||
break;
|
||||
case XKB_KEY_Down:
|
||||
case XKB_KEY_KP_Down:
|
||||
key = LV_KEY_DOWN;
|
||||
break;
|
||||
case XKB_KEY_Prior:
|
||||
case XKB_KEY_KP_Prior:
|
||||
key = LV_KEY_PREV;
|
||||
break;
|
||||
case XKB_KEY_Next:
|
||||
case XKB_KEY_KP_Next:
|
||||
case XKB_KEY_Tab:
|
||||
case XKB_KEY_KP_Tab:
|
||||
key = LV_KEY_NEXT;
|
||||
break;
|
||||
case XKB_KEY_End:
|
||||
case XKB_KEY_KP_End:
|
||||
key = LV_KEY_END;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(xkb_key) {
|
||||
case XKB_KEY_BackSpace:
|
||||
return LV_KEY_BACKSPACE;
|
||||
break;
|
||||
case XKB_KEY_Return:
|
||||
case XKB_KEY_KP_Enter:
|
||||
return LV_KEY_ENTER;
|
||||
break;
|
||||
case XKB_KEY_Escape:
|
||||
return LV_KEY_ESC;
|
||||
break;
|
||||
case XKB_KEY_Delete:
|
||||
case XKB_KEY_KP_Delete:
|
||||
return LV_KEY_DEL;
|
||||
break;
|
||||
case XKB_KEY_Home:
|
||||
case XKB_KEY_KP_Home:
|
||||
return LV_KEY_HOME;
|
||||
break;
|
||||
case XKB_KEY_Left:
|
||||
case XKB_KEY_KP_Left:
|
||||
return LV_KEY_LEFT;
|
||||
break;
|
||||
case XKB_KEY_Up:
|
||||
case XKB_KEY_KP_Up:
|
||||
return LV_KEY_UP;
|
||||
break;
|
||||
case XKB_KEY_Right:
|
||||
case XKB_KEY_KP_Right:
|
||||
return LV_KEY_RIGHT;
|
||||
break;
|
||||
case XKB_KEY_Down:
|
||||
case XKB_KEY_KP_Down:
|
||||
return LV_KEY_DOWN;
|
||||
break;
|
||||
case XKB_KEY_Prior:
|
||||
case XKB_KEY_KP_Prior:
|
||||
return LV_KEY_PREV;
|
||||
break;
|
||||
case XKB_KEY_Next:
|
||||
case XKB_KEY_KP_Next:
|
||||
case XKB_KEY_Tab:
|
||||
case XKB_KEY_KP_Tab:
|
||||
return LV_KEY_NEXT;
|
||||
break;
|
||||
case XKB_KEY_End:
|
||||
case XKB_KEY_KP_End:
|
||||
return LV_KEY_END;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
#endif /* LV_WAYLAND */
|
||||
|
||||
+129
-103
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,473 +0,0 @@
|
||||
/**
|
||||
* @file lv_wl_shm.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_wayland.h"
|
||||
#if LV_USE_WAYLAND
|
||||
|
||||
#include "lv_wayland_private.h"
|
||||
#include <string.h>
|
||||
#include <src/display/lv_display.h>
|
||||
#include <src/drivers/wayland/lv_wayland_smm.h>
|
||||
#include <src/misc/lv_types.h>
|
||||
#include <wayland-cursor.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define SHM_FORMAT_UNKNOWN 0xFFFFFF
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
/*
|
||||
* shm_format
|
||||
* @description called by the compositor to advertise the supported
|
||||
* color formats for SHM buffers, there is a call per supported format
|
||||
*/
|
||||
static void shm_format(void * data, struct wl_shm * wl_shm, uint32_t format);
|
||||
static void handle_wl_buffer_release(void * data, struct wl_buffer * wl_buffer);
|
||||
static bool sme_new_pool(void * ctx, smm_pool_t * pool);
|
||||
static void sme_expand_pool(void * ctx, smm_pool_t * pool);
|
||||
static void sme_free_pool(void * ctx, smm_pool_t * pool);
|
||||
static bool sme_new_buffer(void * ctx, smm_buffer_t * buf);
|
||||
static bool sme_init_buffer(void * ctx, smm_buffer_t * buf);
|
||||
static void sme_free_buffer(void * ctx, smm_buffer_t * buf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static const struct smm_events sme_events = {NULL, sme_new_pool, sme_expand_pool, sme_free_pool,
|
||||
sme_new_buffer, sme_init_buffer, sme_free_buffer
|
||||
};
|
||||
|
||||
static const struct wl_shm_listener shm_listener = {.format = shm_format};
|
||||
|
||||
static const struct wl_buffer_listener wl_buffer_listener = {
|
||||
.release = handle_wl_buffer_release,
|
||||
};
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* PRIVATE FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_wayland_shm_initalize_context(shm_ctx_t * context)
|
||||
{
|
||||
memset(context, 0, sizeof(*context));
|
||||
context->format = SHM_FORMAT_UNKNOWN;
|
||||
smm_init(&sme_events);
|
||||
smm_setctx(context);
|
||||
}
|
||||
|
||||
void lv_wayland_shm_set_interface(shm_ctx_t * context, struct wl_registry * registry, uint32_t name,
|
||||
const char * interface, uint32_t version)
|
||||
{
|
||||
LV_UNUSED(version);
|
||||
LV_UNUSED(interface);
|
||||
context->handler = wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
||||
wl_shm_add_listener(context->handler, &shm_listener, context);
|
||||
}
|
||||
|
||||
lv_result_t lv_wayland_shm_is_ready(shm_ctx_t * context)
|
||||
{
|
||||
return (context->handler && context->format != SHM_FORMAT_UNKNOWN) ? LV_RESULT_OK : LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/* TODO: Move all cursor functions to a lv_wl_cursor file*/
|
||||
struct wl_cursor_theme * lv_wayland_shm_load_cursor_theme(shm_ctx_t * context)
|
||||
{
|
||||
return wl_cursor_theme_load(NULL, 32, context->handler);
|
||||
}
|
||||
|
||||
void lv_wayland_shm_deinit(shm_ctx_t * context)
|
||||
{
|
||||
smm_deinit();
|
||||
wl_shm_destroy(context->handler);
|
||||
}
|
||||
|
||||
struct graphic_object * lv_wayland_shm_on_graphical_object_creation(shm_ctx_t * context, struct graphic_object * obj)
|
||||
{
|
||||
LV_UNUSED(context);
|
||||
obj->pending_buffer = NULL;
|
||||
obj->buffer_group = smm_create();
|
||||
if(obj->buffer_group == NULL) {
|
||||
LV_LOG_ERROR("Failed to create buffer group for graphic object");
|
||||
lv_free(obj);
|
||||
return NULL;
|
||||
}
|
||||
SMM_TAG(obj->buffer_group, TAG_LOCAL, obj);
|
||||
return obj;
|
||||
}
|
||||
void lv_wayland_shm_on_graphical_object_destruction(shm_ctx_t * context, struct graphic_object * obj)
|
||||
{
|
||||
LV_UNUSED(context);
|
||||
smm_destroy(obj->buffer_group);
|
||||
}
|
||||
|
||||
lv_result_t lv_wayland_shm_resize_window(shm_ctx_t * context, struct window * window, int32_t width, int32_t height)
|
||||
{
|
||||
LV_UNUSED(context);
|
||||
const uint8_t bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
|
||||
|
||||
/* Update size for newly allocated buffers */
|
||||
smm_resize(window->body->buffer_group, ((width * bpp) * height) * 2);
|
||||
|
||||
window->body->width = width;
|
||||
window->body->height = height;
|
||||
|
||||
/* Pre-allocate two buffers for the window body here */
|
||||
struct smm_buffer_t * body_buf1 = smm_acquire(window->body->buffer_group);
|
||||
struct smm_buffer_t * body_buf2 = smm_acquire(window->body->buffer_group);
|
||||
|
||||
if(smm_map(body_buf2) == NULL) {
|
||||
LV_LOG_ERROR("Cannot pre-allocate backing buffers for window body");
|
||||
wl_surface_destroy(window->body->surface);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/* Moves the buffers to the unused list of the group */
|
||||
smm_release(body_buf1);
|
||||
smm_release(body_buf2);
|
||||
|
||||
LV_LOG_TRACE("resize window:%dx%d body:%dx%d frame: %d", window->width, window->height, window->body->width,
|
||||
window->body->height, window->frame_counter);
|
||||
|
||||
width = window->body->width;
|
||||
height = window->body->height;
|
||||
|
||||
if(window->lv_disp != NULL) {
|
||||
/* Resize draw buffer */
|
||||
const uint32_t stride = lv_draw_buf_width_to_stride(width, lv_display_get_color_format(window->lv_disp));
|
||||
window->lv_draw_buf = lv_draw_buf_reshape(window->lv_draw_buf, lv_display_get_color_format(window->lv_disp),
|
||||
width, height / LVGL_DRAW_BUFFER_DIV, stride);
|
||||
}
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
lv_result_t lv_wayland_shm_create_draw_buffers(shm_ctx_t * context, struct window * window)
|
||||
{
|
||||
LV_UNUSED(context);
|
||||
const uint32_t stride = lv_draw_buf_width_to_stride(window->width, lv_display_get_color_format(window->lv_disp));
|
||||
|
||||
window->lv_draw_buf = lv_draw_buf_create(window->width, window->height / LVGL_DRAW_BUFFER_DIV,
|
||||
lv_display_get_color_format(window->lv_disp), stride);
|
||||
return window->lv_draw_buf ? LV_RESULT_OK : LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
lv_result_t lv_wayland_shm_set_draw_buffers(shm_ctx_t * context, lv_display_t * display, struct window * window)
|
||||
{
|
||||
LV_UNUSED(context);
|
||||
if(LV_WAYLAND_BUF_COUNT != 1) {
|
||||
LV_LOG_ERROR("Wayland without dmabuf only supports 1 drawbuffer for now.");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
lv_display_set_draw_buffers(display, window->lv_draw_buf, NULL);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
void lv_wayland_shm_delete_draw_buffers(shm_ctx_t * context, struct window * window)
|
||||
{
|
||||
LV_UNUSED(context);
|
||||
if(window->lv_draw_buf) lv_draw_buf_destroy(window->lv_draw_buf);
|
||||
}
|
||||
void lv_wayland_shm_flush_partial_mode(lv_display_t * disp, const lv_area_t * area, unsigned char * color_p)
|
||||
{
|
||||
struct window * window = lv_display_get_driver_data(disp);
|
||||
const uint32_t buf_format = window->wl_ctx->shm_ctx.format;
|
||||
smm_buffer_t * buf = window->body->pending_buffer;
|
||||
int32_t src_width = lv_area_get_width(area);
|
||||
int32_t src_height = lv_area_get_height(area);
|
||||
uint8_t bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
|
||||
lv_display_rotation_t rot = lv_display_get_rotation(disp);
|
||||
int32_t w = lv_display_get_horizontal_resolution(disp);
|
||||
int32_t h = lv_display_get_vertical_resolution(disp);
|
||||
const uint8_t cf = lv_display_get_color_format(disp);
|
||||
const int32_t stride = lv_draw_buf_width_to_stride(src_width, cf);
|
||||
|
||||
/* TODO actually test what happens if the rotation is 90 or 270 or 180 ? */
|
||||
int32_t hres = (rot == LV_DISPLAY_ROTATION_0) ? w : h;
|
||||
int32_t vres = (rot == LV_DISPLAY_ROTATION_0) ? h : w;
|
||||
|
||||
/* If window has been / is being closed, or is not visible, skip flush */
|
||||
if(window->closed || window->shall_close) {
|
||||
goto skip;
|
||||
}
|
||||
/* Skip if the area is out the screen */
|
||||
else if((area->x2 < 0) || (area->y2 < 0) || (area->x1 > hres - 1) || (area->y1 > vres - 1)) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/* Acquire and map a buffer to attach/commit to surface */
|
||||
if(buf == NULL) {
|
||||
buf = smm_acquire(window->body->buffer_group);
|
||||
if(buf == NULL) {
|
||||
LV_LOG_ERROR("cannot acquire a window body buffer");
|
||||
goto skip;
|
||||
}
|
||||
|
||||
window->body->pending_buffer = buf;
|
||||
SMM_TAG(buf, TAG_BUFFER_DAMAGE, window->dmg_cache.cache + window->dmg_cache.end);
|
||||
}
|
||||
|
||||
void * buf_base = smm_map(buf);
|
||||
if(buf_base == NULL) {
|
||||
LV_LOG_ERROR("cannot map in window body buffer");
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/* Modify specified area in buffer */
|
||||
for(int32_t y = 0; y < src_height; ++y) {
|
||||
if(buf_format == WL_SHM_FORMAT_ARGB8888 &&
|
||||
cf != LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED) {
|
||||
for(int32_t x = 0; x < src_width; ++x) {
|
||||
lv_color_premultiply((lv_color32_t *)color_p + x);
|
||||
}
|
||||
}
|
||||
memcpy(((char *)buf_base) + ((((area->y1 + y) * hres) + area->x1) * bpp), color_p, src_width * bpp);
|
||||
color_p += stride;
|
||||
}
|
||||
|
||||
/* Mark surface damage */
|
||||
wl_surface_damage(window->body->surface, area->x1, area->y1, src_width, src_height);
|
||||
|
||||
lv_wayland_cache_add_area(window, buf, area);
|
||||
|
||||
if(lv_display_flush_is_last(disp)) {
|
||||
/* Finally, attach buffer and commit to surface */
|
||||
struct wl_buffer * wl_buf = SMM_BUFFER_PROPERTIES(buf)->tag[TAG_LOCAL];
|
||||
wl_surface_attach(window->body->surface, wl_buf, 0, 0);
|
||||
wl_surface_commit(window->body->surface);
|
||||
window->body->pending_buffer = NULL;
|
||||
|
||||
struct wl_callback * cb = wl_surface_frame(window->body->surface);
|
||||
wl_callback_add_listener(cb, lv_wayland_window_get_wl_surface_frame_listener(), window->body);
|
||||
LV_LOG_TRACE("last flush frame: %d", window->frame_counter);
|
||||
|
||||
window->flush_pending = true;
|
||||
/* Return early here, the lv_display_flush_ready will get called in the frame_listener callback */
|
||||
return;
|
||||
}
|
||||
lv_display_flush_ready(disp);
|
||||
return;
|
||||
skip:
|
||||
if(buf != NULL) {
|
||||
/* Cleanup any intermediate state (in the event that this flush being
|
||||
* skipped is in the middle of a flush sequence)
|
||||
*/
|
||||
lv_wayland_cache_clear(window);
|
||||
SMM_TAG(buf, TAG_BUFFER_DAMAGE, NULL);
|
||||
smm_release(buf);
|
||||
window->body->pending_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void shm_format(void * data, struct wl_shm * wl_shm, uint32_t format)
|
||||
{
|
||||
shm_ctx_t * shm_ctx = (shm_ctx_t *)data;
|
||||
|
||||
LV_UNUSED(wl_shm);
|
||||
|
||||
LV_LOG_TRACE("Supported color space fourcc.h code: %08X", format);
|
||||
|
||||
if(LV_COLOR_DEPTH == 32 && format == WL_SHM_FORMAT_ARGB8888) {
|
||||
LV_LOG_TRACE("Found WL_SHM_FORMAT_ARGB8888");
|
||||
|
||||
/* Wayland compositors MUST support ARGB8888 */
|
||||
shm_ctx->format = format;
|
||||
|
||||
}
|
||||
else if(LV_COLOR_DEPTH == 32 && format == WL_SHM_FORMAT_XRGB8888 && shm_ctx->format != WL_SHM_FORMAT_ARGB8888) {
|
||||
|
||||
LV_LOG_TRACE("Found WL_SHM_FORMAT_XRGB8888");
|
||||
/* Select XRGB only if the compositor doesn't support transprancy */
|
||||
shm_ctx->format = format;
|
||||
|
||||
}
|
||||
else if(LV_COLOR_DEPTH == 16 && format == WL_SHM_FORMAT_RGB565) {
|
||||
|
||||
shm_ctx->format = format;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_wl_buffer_release(void * data, struct wl_buffer * wl_buffer)
|
||||
{
|
||||
const struct smm_buffer_properties * props;
|
||||
struct graphic_object * obj;
|
||||
struct window * window;
|
||||
smm_buffer_t * buf;
|
||||
/* window is unused when LV_LOG level is not set to trace */
|
||||
LV_UNUSED(window);
|
||||
LV_UNUSED(wl_buffer);
|
||||
|
||||
buf = (smm_buffer_t *)data;
|
||||
props = SMM_BUFFER_PROPERTIES(buf);
|
||||
obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
|
||||
window = obj->window;
|
||||
|
||||
LV_LOG_TRACE("releasing buffer %p wl_buffer %p w:%d h:%d frame: %d", (smm_buffer_t *)data, (void *)wl_buffer,
|
||||
obj->width, obj->height, window->frame_counter);
|
||||
smm_release((smm_buffer_t *)data);
|
||||
}
|
||||
|
||||
static bool sme_new_pool(void * ctx, smm_pool_t * pool)
|
||||
{
|
||||
struct wl_shm_pool * wl_pool;
|
||||
shm_ctx_t * shm_ctx = ctx;
|
||||
const struct smm_pool_properties * props = SMM_POOL_PROPERTIES(pool);
|
||||
|
||||
LV_UNUSED(ctx);
|
||||
|
||||
wl_pool = wl_shm_create_pool(shm_ctx->handler, props->fd, props->size);
|
||||
|
||||
SMM_TAG(pool, TAG_LOCAL, wl_pool);
|
||||
return (wl_pool == NULL);
|
||||
}
|
||||
|
||||
static void sme_expand_pool(void * ctx, smm_pool_t * pool)
|
||||
{
|
||||
const struct smm_pool_properties * props = SMM_POOL_PROPERTIES(pool);
|
||||
|
||||
LV_UNUSED(ctx);
|
||||
|
||||
wl_shm_pool_resize(props->tag[TAG_LOCAL], props->size);
|
||||
}
|
||||
|
||||
static void sme_free_pool(void * ctx, smm_pool_t * pool)
|
||||
{
|
||||
struct wl_shm_pool * wl_pool = SMM_POOL_PROPERTIES(pool)->tag[TAG_LOCAL];
|
||||
|
||||
LV_UNUSED(ctx);
|
||||
|
||||
wl_shm_pool_destroy(wl_pool);
|
||||
}
|
||||
|
||||
static bool sme_new_buffer(void * ctx, smm_buffer_t * buf)
|
||||
{
|
||||
|
||||
struct wl_buffer * wl_buf;
|
||||
bool fail_alloc = true;
|
||||
const struct smm_buffer_properties * props = SMM_BUFFER_PROPERTIES(buf);
|
||||
struct wl_shm_pool * wl_pool = SMM_POOL_PROPERTIES(props->pool)->tag[TAG_LOCAL];
|
||||
shm_ctx_t * shm_ctx = (shm_ctx_t *)ctx;
|
||||
struct graphic_object * obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
|
||||
uint8_t bpp;
|
||||
|
||||
LV_LOG_TRACE("create new buffer of width %d height %d", obj->width, obj->height);
|
||||
|
||||
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
|
||||
wl_buf =
|
||||
wl_shm_pool_create_buffer(wl_pool, props->offset, obj->width, obj->height, obj->width * bpp, shm_ctx->format);
|
||||
|
||||
if(wl_buf != NULL) {
|
||||
wl_buffer_add_listener(wl_buf, &wl_buffer_listener, buf);
|
||||
SMM_TAG(buf, TAG_LOCAL, wl_buf);
|
||||
SMM_TAG(buf, TAG_BUFFER_DAMAGE, NULL);
|
||||
fail_alloc = false;
|
||||
}
|
||||
|
||||
return fail_alloc;
|
||||
}
|
||||
|
||||
static bool sme_init_buffer(void * ctx, smm_buffer_t * buf)
|
||||
{
|
||||
smm_buffer_t * src;
|
||||
void * src_base;
|
||||
bool fail_init = true;
|
||||
bool dmg_missing = false;
|
||||
void * buf_base = smm_map(buf);
|
||||
const struct smm_buffer_properties * props = SMM_BUFFER_PROPERTIES(buf);
|
||||
struct graphic_object * obj = SMM_GROUP_PROPERTIES(props->group)->tag[TAG_LOCAL];
|
||||
uint8_t bpp;
|
||||
|
||||
LV_UNUSED(ctx);
|
||||
|
||||
if(buf_base == NULL) {
|
||||
LV_LOG_ERROR("cannot map in buffer to initialize");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Determine if all subsequent buffers damage is recorded */
|
||||
for(src = smm_next(buf); src != NULL; src = smm_next(src)) {
|
||||
if(SMM_BUFFER_PROPERTIES(src)->tag[TAG_BUFFER_DAMAGE] == NULL) {
|
||||
dmg_missing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
|
||||
|
||||
if((smm_next(buf) == NULL) || dmg_missing) {
|
||||
/* Missing subsequent buffer damage, initialize by copying the most
|
||||
* recently acquired buffers data
|
||||
*/
|
||||
src = smm_latest(props->group);
|
||||
if((src != NULL) && (src != buf)) {
|
||||
/* Map and copy latest buffer data */
|
||||
src_base = smm_map(src);
|
||||
if(src_base == NULL) {
|
||||
LV_LOG_ERROR("cannot map most recent buffer to copy");
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(buf_base, src_base, (obj->width * bpp) * obj->height);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* All subsequent buffers damage is recorded, initialize by applying
|
||||
* their damage to this buffer
|
||||
*/
|
||||
for(src = smm_next(buf); src != NULL; src = smm_next(src)) {
|
||||
src_base = smm_map(src);
|
||||
if(src_base == NULL) {
|
||||
LV_LOG_ERROR("cannot map source buffer to copy from");
|
||||
goto done;
|
||||
}
|
||||
|
||||
lv_wayland_cache_apply_areas(obj->window, buf_base, src_base, src);
|
||||
}
|
||||
|
||||
/* Purge out-of-date cached damage (up to and including next buffer) */
|
||||
src = smm_next(buf);
|
||||
if(src == NULL) {
|
||||
lv_wayland_cache_purge(obj->window, src);
|
||||
}
|
||||
}
|
||||
|
||||
fail_init = false;
|
||||
done:
|
||||
return fail_init;
|
||||
}
|
||||
|
||||
static void sme_free_buffer(void * ctx, smm_buffer_t * buf)
|
||||
{
|
||||
struct wl_buffer * wl_buf = SMM_BUFFER_PROPERTIES(buf)->tag[TAG_LOCAL];
|
||||
|
||||
LV_UNUSED(ctx);
|
||||
|
||||
wl_buffer_destroy(wl_buf);
|
||||
}
|
||||
|
||||
#endif /* LV_USE_WAYLAND */
|
||||
@@ -0,0 +1,398 @@
|
||||
/**
|
||||
* @file lv_wl_shm_backend.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_wayland_private.h"
|
||||
|
||||
#if LV_WAYLAND_USE_SHM
|
||||
|
||||
#include "../../display/lv_display_private.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_WL_SHM_BUF_COUNT 2
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
struct wl_shm * shm;
|
||||
} lv_wl_shm_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
struct wl_buffer * wl_buffer;
|
||||
bool busy;
|
||||
} lv_wl_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
void * mmap_ptr;
|
||||
size_t mmap_size;
|
||||
struct wl_shm_pool * pool;
|
||||
lv_wl_buffer_t buffers[LV_WL_SHM_BUF_COUNT];
|
||||
size_t curr_wl_buffer_idx;
|
||||
uint32_t shm_cf;
|
||||
int fd;
|
||||
bool delete_on_release;
|
||||
} lv_wl_shm_display_data_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void * shm_init(void);
|
||||
static void shm_deinit(void *);
|
||||
static void * shm_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height);
|
||||
static void * shm_resize_display(void * backend_ctx, lv_display_t * display);
|
||||
static void shm_deinit_display(void * backend_ctx, lv_display_t * display);
|
||||
static void shm_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name,
|
||||
const char * interface, uint32_t version);
|
||||
|
||||
static int create_shm_file(size_t size);
|
||||
static void shm_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
|
||||
|
||||
static lv_wl_shm_display_data_t * shm_create_display_data(lv_wl_shm_ctx_t * ctx, lv_display_t * display, int32_t width,
|
||||
int32_t height, size_t buf_count);
|
||||
static void shm_destroy_display_data(lv_wl_shm_display_data_t * ddata);
|
||||
|
||||
static void frame_done(void * data, struct wl_callback * callback, uint32_t time);
|
||||
static void buffer_release(void * data, struct wl_buffer * wl_buffer);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static lv_wl_shm_ctx_t shm_ctx;
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {
|
||||
.done = frame_done,
|
||||
};
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
.release = buffer_release
|
||||
};
|
||||
|
||||
const lv_wayland_backend_ops_t wl_backend_ops = {
|
||||
.init = shm_init,
|
||||
.deinit = shm_deinit,
|
||||
.global_handler = shm_global_handler,
|
||||
.init_display = shm_init_display,
|
||||
.deinit_display = shm_deinit_display,
|
||||
.resize_display = shm_resize_display,
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void buffer_release(void * data, struct wl_buffer * wl_buffer)
|
||||
{
|
||||
lv_wl_shm_display_data_t * ddata = data;
|
||||
for(size_t i = 0; i < LV_WL_SHM_BUF_COUNT; ++i) {
|
||||
if(wl_buffer == ddata->buffers[i].wl_buffer) {
|
||||
ddata->buffers[i].busy = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(ddata->delete_on_release) {
|
||||
shm_destroy_display_data(ddata);
|
||||
}
|
||||
}
|
||||
|
||||
static void frame_done(void * data, struct wl_callback * callback, uint32_t time)
|
||||
{
|
||||
LV_UNUSED(time);
|
||||
lv_display_t * display = data;
|
||||
wl_callback_destroy(callback);
|
||||
lv_display_flush_ready(display);
|
||||
}
|
||||
|
||||
static uint32_t lv_cf_to_shm_cf(lv_color_format_t cf)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED:
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
return WL_SHM_FORMAT_ARGB8888;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
return WL_SHM_FORMAT_XRGB8888;
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
return WL_SHM_FORMAT_RGB565;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void * shm_init(void)
|
||||
{
|
||||
lv_memzero(&shm_ctx, sizeof(shm_ctx));
|
||||
return &shm_ctx;
|
||||
}
|
||||
|
||||
static void shm_deinit(void * backend_ctx)
|
||||
{
|
||||
lv_wl_shm_ctx_t * ctx = backend_ctx;
|
||||
if(ctx->shm) {
|
||||
wl_shm_destroy(ctx->shm);
|
||||
}
|
||||
}
|
||||
|
||||
static lv_wl_shm_display_data_t * shm_create_display_data(lv_wl_shm_ctx_t * ctx, lv_display_t * display, int32_t width,
|
||||
int32_t height, size_t buf_count)
|
||||
{
|
||||
lv_wl_shm_display_data_t * ddata = lv_zalloc(sizeof(*ddata));
|
||||
if(!ddata) {
|
||||
LV_LOG_ERROR("Failed to allocate data for display");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_color_format_t cf = lv_display_get_color_format(display);
|
||||
ddata->shm_cf = lv_cf_to_shm_cf(cf);
|
||||
|
||||
if(!ddata->shm_cf) {
|
||||
LV_LOG_WARN("Unsupported color format %d. Falling back to XRGB8888", cf);
|
||||
cf = LV_COLOR_FORMAT_XRGB8888;
|
||||
lv_display_set_color_format(display, cf);
|
||||
ddata->shm_cf = WL_SHM_FORMAT_XRGB8888;
|
||||
}
|
||||
|
||||
const uint32_t stride = lv_draw_buf_width_to_stride(width, cf);
|
||||
const size_t buf_size = stride * height;
|
||||
|
||||
ddata->mmap_size = buf_size * buf_count;
|
||||
|
||||
ddata->fd = create_shm_file(ddata->mmap_size);
|
||||
if(ddata->fd < 0) {
|
||||
LV_LOG_ERROR("Failed to create shm file");
|
||||
goto shm_file_err;
|
||||
}
|
||||
ddata->mmap_ptr = mmap(NULL, ddata->mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, ddata->fd, 0);
|
||||
if(ddata->mmap_ptr == MAP_FAILED) {
|
||||
LV_LOG_ERROR("Failed to map shm file: %s", strerror(errno));
|
||||
goto mmap_err;
|
||||
}
|
||||
ddata->pool = wl_shm_create_pool(ctx->shm, ddata->fd, ddata->mmap_size);
|
||||
if(!ddata->pool) {
|
||||
LV_LOG_ERROR("Failed to create wl_shm_pool");
|
||||
goto shm_pool_err;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < buf_count; ++i) {
|
||||
size_t offset = i * buf_size;
|
||||
ddata->buffers[i].wl_buffer = wl_shm_pool_create_buffer(ddata->pool, offset, width, height, stride, ddata->shm_cf);
|
||||
if(!ddata->buffers[i].wl_buffer) {
|
||||
LV_LOG_ERROR("Failed to create wl_buffer %zu", i);
|
||||
goto pool_buffer_err;
|
||||
}
|
||||
wl_buffer_add_listener(ddata->buffers[i].wl_buffer, &buffer_listener, ddata);
|
||||
ddata->buffers[i].busy = false;
|
||||
}
|
||||
|
||||
lv_display_set_buffers(display, ddata->mmap_ptr, (uint8_t *)ddata->mmap_ptr + buf_size,
|
||||
buf_size, LV_DISPLAY_RENDER_MODE_DIRECT);
|
||||
|
||||
return ddata;
|
||||
|
||||
pool_buffer_err:
|
||||
wl_shm_pool_destroy(ddata->pool);
|
||||
shm_pool_err:
|
||||
munmap(ddata->mmap_ptr, ddata->mmap_size);
|
||||
mmap_err:
|
||||
close(ddata->fd);
|
||||
shm_file_err:
|
||||
lv_free(ddata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void shm_destroy_display_data(lv_wl_shm_display_data_t * ddata)
|
||||
{
|
||||
for(size_t i = 0; i < LV_WL_SHM_BUF_COUNT; ++i) {
|
||||
lv_wl_buffer_t * buffer = &ddata->buffers[i];
|
||||
if(!buffer->wl_buffer) {
|
||||
continue;
|
||||
}
|
||||
if(buffer->busy) {
|
||||
/* Defer the deletion of this display data until the buffers are released */
|
||||
LV_LOG_INFO("Buffer is still busy, deferring deletion to when its released");
|
||||
ddata->delete_on_release = true;
|
||||
return;
|
||||
}
|
||||
wl_buffer_destroy(ddata->buffers[i].wl_buffer);
|
||||
ddata->buffers[i].wl_buffer = NULL;
|
||||
}
|
||||
|
||||
if(ddata->pool) {
|
||||
wl_shm_pool_destroy(ddata->pool);
|
||||
ddata->pool = NULL;
|
||||
}
|
||||
|
||||
|
||||
if(ddata->mmap_ptr != MAP_FAILED) {
|
||||
munmap(ddata->mmap_ptr, ddata->mmap_size);
|
||||
ddata->mmap_ptr = MAP_FAILED;
|
||||
}
|
||||
|
||||
if(ddata->fd >= 0) {
|
||||
close(ddata->fd);
|
||||
ddata->fd = -1;
|
||||
}
|
||||
|
||||
LV_LOG_INFO("Deleted buffers and display data");
|
||||
lv_free(ddata);
|
||||
}
|
||||
|
||||
static void flush_wait_cb(lv_display_t * disp)
|
||||
{
|
||||
while(disp->flushing) {
|
||||
wl_display_dispatch(lv_wl_ctx.wl_display);
|
||||
}
|
||||
}
|
||||
|
||||
static void * shm_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height)
|
||||
{
|
||||
lv_wl_shm_ctx_t * ctx = (lv_wl_shm_ctx_t *)backend_ctx;
|
||||
if(!ctx->shm) {
|
||||
LV_LOG_ERROR("wl_shm not available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_wl_shm_display_data_t * ddata = shm_create_display_data(ctx, display, width, height, LV_WL_SHM_BUF_COUNT);
|
||||
if(!ddata) {
|
||||
LV_LOG_ERROR("Failed to allocate data for display");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_display_set_flush_cb(display, shm_flush_cb);
|
||||
lv_display_set_flush_wait_cb(display, flush_wait_cb);
|
||||
|
||||
return ddata;
|
||||
}
|
||||
|
||||
static void * shm_resize_display(void * backend_ctx, lv_display_t * display)
|
||||
{
|
||||
lv_wl_shm_ctx_t * ctx = (lv_wl_shm_ctx_t *)backend_ctx;
|
||||
|
||||
const int32_t new_width = lv_display_get_horizontal_resolution(display);
|
||||
const int32_t new_height = lv_display_get_vertical_resolution(display);
|
||||
|
||||
lv_wl_shm_display_data_t * ddata = shm_create_display_data(ctx, display, new_width, new_height, LV_WL_SHM_BUF_COUNT);
|
||||
|
||||
if(!ddata) {
|
||||
LV_LOG_ERROR("Failed to allocate data for new display resolution");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_wl_shm_display_data_t * curr_ddata = lv_wayland_get_backend_display_data(display);
|
||||
shm_destroy_display_data(curr_ddata);
|
||||
return ddata;
|
||||
}
|
||||
|
||||
|
||||
static void shm_deinit_display(void * backend_ctx, lv_display_t * display)
|
||||
{
|
||||
LV_UNUSED(backend_ctx);
|
||||
lv_wl_shm_display_data_t * ddata = lv_wayland_get_backend_display_data(display);
|
||||
if(!ddata) {
|
||||
return;
|
||||
}
|
||||
shm_destroy_display_data(ddata);
|
||||
}
|
||||
|
||||
static int create_shm_file(size_t size)
|
||||
{
|
||||
int fd = -1;
|
||||
char name[255];
|
||||
snprintf(name, sizeof(name), "/lvgl-wayland-%d-%ld", getpid(), (long)lv_tick_get());
|
||||
|
||||
fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if(fd < 0) {
|
||||
LV_LOG_ERROR("shm_open failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
shm_unlink(name);
|
||||
|
||||
if(ftruncate(fd, size) < 0) {
|
||||
LV_LOG_ERROR("ftruncate failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void shm_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name,
|
||||
const char * interface, uint32_t version)
|
||||
{
|
||||
LV_UNUSED(version);
|
||||
lv_wl_shm_ctx_t * ctx = (lv_wl_shm_ctx_t *)backend_ctx;
|
||||
|
||||
if(lv_streq(interface, wl_shm_interface.name)) {
|
||||
ctx->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void shm_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
|
||||
{
|
||||
LV_UNUSED(px_map);
|
||||
lv_wl_shm_display_data_t * ddata = lv_wayland_get_backend_display_data(disp);
|
||||
struct wl_surface * surface = lv_wayland_get_window_surface(disp);
|
||||
if(!surface) {
|
||||
lv_display_flush_ready(disp);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t w = lv_area_get_width(area);
|
||||
int32_t h = lv_area_get_height(area);
|
||||
lv_color_format_t cf = lv_display_get_color_format(disp);
|
||||
/* When using ARGB8888, the compositor expects premultiplied ARGB8888 so premultiply it here*/
|
||||
if(ddata->shm_cf == WL_SHM_FORMAT_ARGB8888 && cf != LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED) {
|
||||
size_t index = 0;
|
||||
for(int32_t y = area->y1; y <= area->y2; ++y) {
|
||||
for(int32_t x = area->x1; x <= area->x2; ++x) {
|
||||
lv_color_premultiply((lv_color32_t *) px_map + (index++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wl_surface_damage(surface, area->x1, area->y1, w, h);
|
||||
if(!lv_display_flush_is_last(disp)) {
|
||||
lv_display_flush_ready(disp);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_callback * callback = wl_surface_frame(surface);
|
||||
wl_callback_add_listener(callback, &frame_listener, disp);
|
||||
|
||||
lv_wl_buffer_t * buffer = &ddata->buffers[ddata->curr_wl_buffer_idx];
|
||||
if(buffer->busy) {
|
||||
LV_LOG_WARN("Failed to acquire a non-busy buffer");
|
||||
}
|
||||
wl_surface_attach(surface, buffer->wl_buffer, 0, 0);
|
||||
wl_surface_commit(surface);
|
||||
|
||||
buffer->busy = true;
|
||||
ddata->curr_wl_buffer_idx = (ddata->curr_wl_buffer_idx + 1) % LV_WL_SHM_BUF_COUNT;
|
||||
}
|
||||
|
||||
#endif /*LV_WAYLAND_USE_SHM*/
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+159
-311
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@ extern "C" {
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef bool (*lv_wayland_display_close_f_t)(lv_display_t * disp);
|
||||
typedef bool (*lv_wayland_display_close_cb_t)(lv_display_t * disp);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@@ -42,7 +42,7 @@ typedef bool (*lv_wayland_display_close_f_t)(lv_display_t * disp);
|
||||
* @return The LVGL display associated to the window
|
||||
*/
|
||||
lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char * title,
|
||||
lv_wayland_display_close_f_t close_cb);
|
||||
lv_wayland_display_close_cb_t close_cb);
|
||||
|
||||
/**
|
||||
* Closes the window programmatically
|
||||
@@ -85,6 +85,12 @@ void lv_wayland_window_set_fullscreen(lv_display_t * disp, bool fullscreen);
|
||||
*/
|
||||
void lv_wayland_window_set_maximized(lv_display_t * disp, bool maximize);
|
||||
|
||||
/**
|
||||
* Minimizes the window
|
||||
* @param disp Reference to the LVGL display associated to the window
|
||||
*/
|
||||
void lv_wayland_window_set_minimized(lv_display_t * disp);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -1,382 +0,0 @@
|
||||
/**
|
||||
* @file lv_wl_window_decorations.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_wayland.h"
|
||||
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
|
||||
#include "lv_wayland_private.h"
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/*
|
||||
* Fills a buffer with a color
|
||||
* @description Used to draw the decorations, by writing directly to the SHM buffer,
|
||||
* most wayland compositors support the ARGB8888, XRGB8888, RGB565 formats
|
||||
*
|
||||
* For color depths usually not natively supported by wayland i.e RGB332, Grayscale
|
||||
* A conversion is performed to match the format of the SHM buffer read by the compositor.
|
||||
*
|
||||
* This function can also be used as a visual debugging aid to see how damage is applied
|
||||
*
|
||||
* @param pixels pointer to the buffer to fill
|
||||
* @param lv_color_t color the color that will be used for the fill
|
||||
* @param width width of the filled area
|
||||
* @param height height of the filled area
|
||||
*
|
||||
*/
|
||||
static void color_fill(void * pixels, lv_color_t color, uint32_t width, uint32_t height);
|
||||
static void color_fill_XRGB8888(void * pixels, lv_color_t color, uint32_t width, uint32_t height);
|
||||
static void color_fill_RGB565(void * pixels, lv_color_t color, uint32_t width, uint32_t height);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
bool lv_wayland_window_decoration_attach(struct window * window, struct graphic_object * decoration,
|
||||
void * decoration_buffer, struct graphic_object * parent)
|
||||
{
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
struct wl_buffer * wl_buf = ((struct buffer *)decoration_buffer)->buffer;
|
||||
#else
|
||||
struct wl_buffer * wl_buf = SMM_BUFFER_PROPERTIES((smm_buffer_t *)decoration_buffer)->tag[TAG_LOCAL];
|
||||
#endif
|
||||
|
||||
|
||||
int pos_x, pos_y;
|
||||
|
||||
switch(decoration->type) {
|
||||
case OBJECT_TITLEBAR:
|
||||
pos_x = 0;
|
||||
pos_y = -TITLE_BAR_HEIGHT;
|
||||
break;
|
||||
case OBJECT_BUTTON_CLOSE:
|
||||
pos_x = parent->width - 1 * (BUTTON_MARGIN + BUTTON_SIZE);
|
||||
pos_y = -1 * (BUTTON_MARGIN + BUTTON_SIZE + (BORDER_SIZE / 2));
|
||||
break;
|
||||
case OBJECT_BUTTON_MAXIMIZE:
|
||||
pos_x = parent->width - 2 * (BUTTON_MARGIN + BUTTON_SIZE);
|
||||
pos_y = -1 * (BUTTON_MARGIN + BUTTON_SIZE + (BORDER_SIZE / 2));
|
||||
break;
|
||||
case OBJECT_BUTTON_MINIMIZE:
|
||||
pos_x = parent->width - 3 * (BUTTON_MARGIN + BUTTON_SIZE);
|
||||
pos_y = -1 * (BUTTON_MARGIN + BUTTON_SIZE + (BORDER_SIZE / 2));
|
||||
break;
|
||||
case OBJECT_BORDER_TOP:
|
||||
pos_x = -BORDER_SIZE;
|
||||
pos_y = -(BORDER_SIZE + TITLE_BAR_HEIGHT);
|
||||
break;
|
||||
case OBJECT_BORDER_BOTTOM:
|
||||
pos_x = -BORDER_SIZE;
|
||||
pos_y = parent->height;
|
||||
break;
|
||||
case OBJECT_BORDER_LEFT:
|
||||
pos_x = -BORDER_SIZE;
|
||||
pos_y = -TITLE_BAR_HEIGHT;
|
||||
break;
|
||||
case OBJECT_BORDER_RIGHT:
|
||||
pos_x = parent->width;
|
||||
pos_y = -TITLE_BAR_HEIGHT;
|
||||
break;
|
||||
default:
|
||||
LV_ASSERT_MSG(0, "Invalid object type");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Enable this, to make it function on weston 10.0.2 */
|
||||
/* It's not elegant but it forces weston to size the surfaces before */
|
||||
/* the conversion to a subsurface takes place */
|
||||
|
||||
/* Likely related to this issue, some patches were merged into 10.0.0 */
|
||||
/* https://gitlab.freedesktop.org/wayland/weston/-/issues/446 */
|
||||
/* Moreover, it crashes on GNOME */
|
||||
|
||||
#if 0
|
||||
wl_surface_attach(decoration->surface, wl_buf, 0, 0);
|
||||
wl_surface_commit(decoration->surface);
|
||||
#endif
|
||||
|
||||
if(decoration->subsurface == NULL) {
|
||||
/* Create the subsurface only once */
|
||||
|
||||
decoration->subsurface =
|
||||
wl_subcompositor_get_subsurface(window->wl_ctx->subcompositor, decoration->surface, parent->surface);
|
||||
if(!decoration->subsurface) {
|
||||
LV_LOG_ERROR("cannot get subsurface for decoration");
|
||||
goto err_destroy_surface;
|
||||
}
|
||||
}
|
||||
|
||||
wl_subsurface_set_position(decoration->subsurface, pos_x, pos_y);
|
||||
wl_surface_attach(decoration->surface, wl_buf, 0, 0);
|
||||
wl_surface_commit(decoration->surface);
|
||||
|
||||
return true;
|
||||
|
||||
err_destroy_surface:
|
||||
wl_surface_destroy(decoration->surface);
|
||||
decoration->surface = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t lv_wayland_window_decoration_create_all(struct window * window)
|
||||
{
|
||||
uint32_t created = 0;
|
||||
for(size_t i = 0; i < NUM_DECORATIONS; i++) {
|
||||
if(lv_wayland_window_decoration_create(window, window->decoration[i], window->body->width,
|
||||
window->body->height)) {
|
||||
created++;
|
||||
continue;
|
||||
}
|
||||
LV_LOG_ERROR("failed to create decoration %zu", i);
|
||||
}
|
||||
return created;
|
||||
}
|
||||
|
||||
void lv_wayland_window_decoration_detach_all(struct window * window)
|
||||
{
|
||||
for(int i = 0; i < NUM_DECORATIONS; i++) {
|
||||
lv_wayland_window_decoration_detach(window, window->decoration[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool lv_wayland_window_decoration_create(struct window * window, struct graphic_object * decoration, int window_width,
|
||||
int window_height)
|
||||
{
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
struct buffer * buf;
|
||||
#else
|
||||
smm_buffer_t * buf;
|
||||
#endif
|
||||
void * buf_base;
|
||||
int x, y;
|
||||
lv_color_t * pixel;
|
||||
uint8_t bpp;
|
||||
|
||||
switch(decoration->type) {
|
||||
case OBJECT_TITLEBAR:
|
||||
decoration->width = window_width;
|
||||
decoration->height = TITLE_BAR_HEIGHT;
|
||||
break;
|
||||
case OBJECT_BUTTON_CLOSE:
|
||||
decoration->width = BUTTON_SIZE;
|
||||
decoration->height = BUTTON_SIZE;
|
||||
break;
|
||||
case OBJECT_BUTTON_MAXIMIZE:
|
||||
decoration->width = BUTTON_SIZE;
|
||||
decoration->height = BUTTON_SIZE;
|
||||
break;
|
||||
case OBJECT_BUTTON_MINIMIZE:
|
||||
decoration->width = BUTTON_SIZE;
|
||||
decoration->height = BUTTON_SIZE;
|
||||
break;
|
||||
case OBJECT_BORDER_TOP:
|
||||
decoration->width = window_width + 2 * (BORDER_SIZE);
|
||||
decoration->height = BORDER_SIZE;
|
||||
break;
|
||||
case OBJECT_BORDER_BOTTOM:
|
||||
decoration->width = window_width + 2 * (BORDER_SIZE);
|
||||
decoration->height = BORDER_SIZE;
|
||||
break;
|
||||
case OBJECT_BORDER_LEFT:
|
||||
decoration->width = BORDER_SIZE;
|
||||
decoration->height = window_height + TITLE_BAR_HEIGHT;
|
||||
break;
|
||||
case OBJECT_BORDER_RIGHT:
|
||||
decoration->width = BORDER_SIZE;
|
||||
decoration->height = window_height + TITLE_BAR_HEIGHT;
|
||||
break;
|
||||
default:
|
||||
LV_ASSERT_MSG(0, "Invalid object type");
|
||||
return false;
|
||||
}
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
|
||||
buf = dmabuf_acquire_pool_buffer(window, decoration);
|
||||
buf_base = mmap(0, (decoration->width * bpp) * decoration->height, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
buf->dmabuf_fds[0], 0);
|
||||
if(buf_base == MAP_FAILED) {
|
||||
destroy_decorators_buf(window, decoration);
|
||||
LV_LOG_ERROR("cannot map in allocated decoration buffer %d (%s)", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bpp = lv_color_format_get_size(LV_COLOR_FORMAT_NATIVE);
|
||||
|
||||
LV_LOG_TRACE("decoration window %dx%d", decoration->width, decoration->height);
|
||||
|
||||
smm_resize(decoration->buffer_group, (decoration->width * bpp) * decoration->height);
|
||||
|
||||
buf = smm_acquire(decoration->buffer_group);
|
||||
|
||||
if(buf == NULL) {
|
||||
LV_LOG_ERROR("cannot allocate buffer for decoration");
|
||||
return false;
|
||||
}
|
||||
|
||||
buf_base = smm_map(buf);
|
||||
if(buf_base == NULL) {
|
||||
LV_LOG_ERROR("cannot map in allocated decoration buffer");
|
||||
smm_release(buf);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
switch(decoration->type) {
|
||||
case OBJECT_TITLEBAR:
|
||||
color_fill(buf_base, lv_color_make(0x66, 0x66, 0x66), decoration->width, decoration->height);
|
||||
break;
|
||||
case OBJECT_BUTTON_CLOSE:
|
||||
color_fill(buf_base, lv_color_make(0xCC, 0xCC, 0xCC), decoration->width, decoration->height);
|
||||
for(y = 0; y < decoration->height; y++) {
|
||||
for(x = 0; x < decoration->width; x++) {
|
||||
pixel = (lv_color_t *)((unsigned char *)buf_base + (y * (decoration->width * bpp)) + x * bpp);
|
||||
if((x >= BUTTON_PADDING) && (x < decoration->width - BUTTON_PADDING)) {
|
||||
if((x == y) || (x == decoration->width - 1 - y)) {
|
||||
color_fill(pixel, lv_color_make(0x33, 0x33, 0x33), 1, 1);
|
||||
}
|
||||
else if((x == y - 1) || (x == decoration->width - y)) {
|
||||
color_fill(pixel, lv_color_make(0x66, 0x66, 0x66), 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BUTTON_MAXIMIZE:
|
||||
color_fill(buf_base, lv_color_make(0xCC, 0xCC, 0xCC), decoration->width, decoration->height);
|
||||
for(y = 0; y < decoration->height; y++) {
|
||||
for(x = 0; x < decoration->width; x++) {
|
||||
pixel = (lv_color_t *)((unsigned char *)buf_base + (y * (decoration->width * bpp)) + x * bpp);
|
||||
if(((x == BUTTON_PADDING) && (y >= BUTTON_PADDING) && (y < decoration->height - BUTTON_PADDING)) ||
|
||||
((x == (decoration->width - BUTTON_PADDING)) && (y >= BUTTON_PADDING) &&
|
||||
(y <= decoration->height - BUTTON_PADDING)) ||
|
||||
((y == BUTTON_PADDING) && (x >= BUTTON_PADDING) && (x < decoration->width - BUTTON_PADDING)) ||
|
||||
((y == (BUTTON_PADDING + 1)) && (x >= BUTTON_PADDING) &&
|
||||
(x < decoration->width - BUTTON_PADDING)) ||
|
||||
((y == (decoration->height - BUTTON_PADDING)) && (x >= BUTTON_PADDING) &&
|
||||
(x < decoration->width - BUTTON_PADDING))) {
|
||||
color_fill(pixel, lv_color_make(0x33, 0x33, 0x33), 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BUTTON_MINIMIZE:
|
||||
color_fill(buf_base, lv_color_make(0xCC, 0xCC, 0xCC), decoration->width, decoration->height);
|
||||
for(y = 0; y < decoration->height; y++) {
|
||||
for(x = 0; x < decoration->width; x++) {
|
||||
pixel = (lv_color_t *)((unsigned char *)buf_base + (y * (decoration->width * bpp)) + x * bpp);
|
||||
if((x >= BUTTON_PADDING) && (x < decoration->width - BUTTON_PADDING) &&
|
||||
(y > decoration->height - (2 * BUTTON_PADDING)) && (y < decoration->height - BUTTON_PADDING)) {
|
||||
color_fill(pixel, lv_color_make(0x33, 0x33, 0x33), 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BORDER_TOP:
|
||||
/* fallthrough */
|
||||
case OBJECT_BORDER_BOTTOM:
|
||||
/* fallthrough */
|
||||
case OBJECT_BORDER_LEFT:
|
||||
/* fallthrough */
|
||||
case OBJECT_BORDER_RIGHT:
|
||||
color_fill(buf_base, lv_color_make(0x66, 0x66, 0x66), decoration->width, decoration->height);
|
||||
break;
|
||||
default:
|
||||
LV_ASSERT_MSG(0, "Invalid object type");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = lv_wayland_window_decoration_attach(window, decoration, buf, window->body);
|
||||
|
||||
#if LV_WAYLAND_USE_DMABUF
|
||||
munmap(buf_base, (decoration->width * bpp) * decoration->height);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lv_wayland_window_decoration_detach(struct window * window, struct graphic_object * decoration)
|
||||
{
|
||||
|
||||
LV_UNUSED(window);
|
||||
|
||||
if(decoration->subsurface) {
|
||||
wl_subsurface_destroy(decoration->subsurface);
|
||||
decoration->subsurface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void color_fill(void * pixels, lv_color_t color, uint32_t width, uint32_t height)
|
||||
{
|
||||
|
||||
switch(lv_wl_ctx.shm_ctx.format) {
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
color_fill_XRGB8888(pixels, color, width, height);
|
||||
break;
|
||||
case WL_SHM_FORMAT_RGB565:
|
||||
color_fill_RGB565(pixels, color, width, height);
|
||||
break;
|
||||
default:
|
||||
LV_ASSERT_MSG(0, "Unsupported WL_SHM_FORMAT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void color_fill_XRGB8888(void * pixels, lv_color_t color, uint32_t width, uint32_t height)
|
||||
{
|
||||
unsigned char * buf = pixels;
|
||||
unsigned char * buf_end;
|
||||
|
||||
buf_end = (unsigned char *)((uint32_t *)buf + width * height);
|
||||
|
||||
while(buf < buf_end) {
|
||||
*(buf++) = color.blue;
|
||||
*(buf++) = color.green;
|
||||
*(buf++) = color.red;
|
||||
*(buf++) = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void color_fill_RGB565(void * pixels, lv_color_t color, uint32_t width, uint32_t height)
|
||||
{
|
||||
uint16_t * buf = pixels;
|
||||
uint16_t * buf_end;
|
||||
|
||||
buf_end = (uint16_t *)buf + width * height;
|
||||
|
||||
while(buf < buf_end) {
|
||||
*(buf++) = lv_color_to_u16(color);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LV_WAYLAND_WINDOW_DECORATIONS */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,6 @@ extern "C" {
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "misc/lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -32,6 +31,8 @@ extern "C" {
|
||||
**********************/
|
||||
|
||||
#define lv_tabview_rename_tab lv_tabview_set_tab_text
|
||||
#define lv_wayland_timer_handler lv_timer_handler
|
||||
#define lv_wayland_display_close_f_t lv_wayland_display_close_cb_t
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
|
||||
+18
-31
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user