Skip to content

Commit

Permalink
feat(wayland): add Wayland support (#51)
Browse files Browse the repository at this point in the history
* fix(wayland) Rebase master to get the latest changes

* chore(wayland) adjust example code

* chore(wayland) align with driver, wait only if the cycle was fully completed

* feat(wayland) Simplify CMakeLists file

Use external scripts to obtain the selected backend in lv_conf.h
Generate wayland protocol via a shell script instead of CMake

* fix(wayland) - Remove test script

* doc(wayland) Update documentation

Remove the step that tells to edit the CMakeLists.txt file
and manually enable the option to select the backend

* feat(wayland) Move wayland display init and runloop to a separate file

Solve merge conflit with the main branch

* fix(wayland) Re-apply the delay timer execution only until the next timer fires up

* fix(wayland) adjust CI

* fix(wayland) fix CI
  • Loading branch information
etag4048 authored Oct 24, 2024
1 parent eb945a8 commit 8b106e2
Show file tree
Hide file tree
Showing 9 changed files with 306 additions and 85 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
sed -i "s/^#define LV_USE_LINUX_DRM.*$/#define LV_USE_LINUX_DRM 0/g" lv_conf.h && \
sed -i "s/^#define LV_USE_SDL.*$/#define LV_USE_SDL 0/g" lv_conf.h && \
docker run --rm -v "$(pwd)":/workdir -t test_${{ matrix.os.image }} \
/bin/bash -ec "mkdir build/ && cd build/ && cmake .. && make -j && ldd ../bin/main"
/bin/bash -ec "cmake -B build -S . && make -j -C build && ldd bin/lvglsim"
- name: DRM Test building the project
run: |
Expand All @@ -50,7 +50,7 @@ jobs:
sed -i "s/^#define LV_USE_LINUX_DRM.*$/#define LV_USE_LINUX_DRM 1/g" lv_conf.h && \
sed -i "s/^#define LV_USE_SDL.*$/#define LV_USE_SDL 0/g" lv_conf.h && \
docker run --rm -v "$(pwd)":/workdir -t test_${{ matrix.os.image }} \
/bin/bash -ec "mkdir build/ && cd build/ && cmake .. && make -j && ldd ../bin/main"
/bin/bash -ec "cmake -B build -S . && make -j -C build && ldd bin/lvglsim"
- name: SDL Test building the project
run: |
Expand All @@ -59,4 +59,5 @@ jobs:
sed -i "s/^#define LV_USE_LINUX_DRM.*$/#define LV_USE_LINUX_DRM 0/g" lv_conf.h && \
sed -i "s/^#define LV_USE_SDL.*$/#define LV_USE_SDL 1/g" lv_conf.h && \
docker run --rm -v "$(pwd)":/workdir -t test_${{ matrix.os.image }} \
/bin/bash -ec "mkdir build/ && cd build/ && cmake .. && make -j && ldd ../bin/main"
/bin/bash -ec "cmake -B build -S . && make -j -C build && ldd bin/lvglsim"
84 changes: 59 additions & 25 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,33 +1,67 @@
cmake_minimum_required(VERSION 3.10)
project(lvgl)

set(CMAKE_C_STANDARD 99)#C99 # lvgl officially support C99 and above
set(CMAKE_CXX_STANDARD 17)#C17
set(CMAKE_CXX_STANDARD_REQUIRED ON)
foreach(BACKEND_NAME "SDL" "LINUX_DRM" "LINUX_FBDEV" "X11" "WAYLAND")
execute_process(COMMAND "scripts/backend_conf.sh" ${BACKEND_NAME} OUTPUT_VARIABLE IS_BACKEND_ENABLED)
set("LV_USE_${BACKEND_NAME}" ${IS_BACKEND_ENABLED})
endforeach()

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# Uncomment if the program needs debugging
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb")

set(CMAKE_C_STANDARD 99) # LVGL officially supports C99 and above
set(CMAKE_CXX_STANDARD 17) #C17
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_subdirectory(lvgl)
add_executable(main main.c mouse_cursor_icon.c)
target_include_directories(lvgl PUBLIC ${PROJECT_SOURCE_DIR})

find_package(PkgConfig REQUIRED) # We use the platform independent pkg-config to find all the libs
pkg_check_modules(LIBDRM REQUIRED libdrm)
pkg_check_modules(SDL2 REQUIRED sdl2)
pkg_check_modules(SDL2_image REQUIRED SDL2_image)
if (LV_USE_LINUX_DRM)

target_include_directories(lvgl PUBLIC ${PROJECT_SOURCE_DIR})
target_include_directories(lvgl PRIVATE ${SDL2_INCLUDE_DIRS})
target_include_directories(lvgl PRIVATE ${SDL2_IMAGE_INCLUDE_DIRS})
target_include_directories(lvgl PRIVATE ${LIBDRM_INCLUDE_DIRS})

target_link_libraries(main PRIVATE lvgl) # Add '-static' if you want a standalone binary
target_link_libraries(main PRIVATE lvgl::examples)
target_link_libraries(main PRIVATE lvgl::demos)
target_link_libraries(main PRIVATE lvgl::thorvg)
target_link_libraries(main PRIVATE ${SDL2_LIBRARIES})
target_link_libraries(main PRIVATE ${SDL2_IMAGE_LIBRARIES})
target_link_libraries(main PRIVATE ${LIBDRM_LIBRARIES})
target_link_libraries(main PRIVATE m)
target_link_libraries(main PRIVATE pthread)

add_custom_target(run COMMAND ${EXECUTABLE_OUTPUT_PATH}/main DEPENDS main)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBDRM REQUIRED libdrm)

target_include_directories(lvgl PUBLIC ${LIBDRM_INCLUDE_DIRS})
add_executable(lvglsim main.c mouse_cursor_icon.c)
target_link_libraries(lvglsim lvgl lvgl::examples lvgl::demos lvgl::thorvg ${LIBDRM_LIBRARIES} m pthread)

elseif (LV_USE_SDL)

find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
pkg_check_modules(SDL2_image REQUIRED SDL2_image)

target_include_directories(lvgl PRIVATE ${SDL2_INCLUDE_DIRS})
target_include_directories(lvgl PRIVATE ${SDL2_IMAGE_INCLUDE_DIRS})
add_executable(lvglsim main.c mouse_cursor_icon.c)
target_link_libraries(lvglsim lvgl lvgl::examples lvgl::demos lvgl::thorvg ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES} m pthread)

elseif (LV_USE_WAYLAND)

find_package(PkgConfig REQUIRED)
pkg_check_modules(wayland-client REQUIRED wayland-client)
pkg_check_modules(wayland-cursor REQUIRED wayland-cursor)
pkg_check_modules(xkbcommon REQUIRED xkbcommon)

# Wayland protocols
pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.25)
pkg_get_variable(WAYLAND_PROTOCOLS_BASE wayland-protocols pkgdatadir)

execute_process(COMMAND "scripts/gen_wl_protocols.sh" OUTPUT_VARIABLE WAYLAND_PROTOCOLS_SRC)

target_include_directories(lvgl PRIVATE ${PROJECT_SOURCE_DIR}
"${PROJECT_SOURCE_DIR}/wl_protocols")
add_executable(lvglsim main.c ${WAYLAND_PROTOCOLS_SRC}
mouse_cursor_icon.c backends/wayland.c)
target_compile_definitions(lvglsim PRIVATE LV_CONF_INCLUDE_SIMPLE)
target_link_libraries(lvglsim lvgl lvgl::examples lvgl::demos lvgl::thorvg m
wayland-client wayland-cursor xkbcommon)

else()

# No specific build steps required for FBDEV
add_executable(lvglsim main.c mouse_cursor_icon.c)
target_link_libraries(lvglsim lvgl lvgl::examples lvgl::demos lvgl::thorvg m pthread)
endif()

add_custom_target (run COMMAND ${EXECUTABLE_OUTPUT_PATH}/lvglsim DEPENDS lvglsim)
77 changes: 48 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# LVGL on top of Linux graphics stack

Example project to use LVGL on top of Linux graphics stack.
Currently supported backends are either legacy framebuffer
(fbdev), modern DRM/KMS, or SDL2.
Currently supported backends are legacy framebuffer
(fbdev), modern DRM/KMS, Wayland or SDL2.

By default, legacy framebuffer backend uses `/dev/fb0` device node,
DRM/KMS backend uses '/dev/dri/card0' card node, SDL2 uses window
Expand All @@ -24,38 +24,47 @@ cd lv_port_linux/
git submodule update --init --recursive
```

## Select graphics backend (optional)
## Select graphics backend

To use legacy framebuffer (fbdev) support, adjust `lv_conf.h` as follows:
```
#define LV_USE_LINUX_FBDEV 1
#define LV_USE_LINUX_DRM 0
#define LV_USE_SDL 0
#define LV_USE_WAYLAND 0
```

To use modern DRM/KMS support, adjust `lv_conf.h` as follows:
```
#define LV_USE_LINUX_FBDEV 0
#define LV_USE_LINUX_DRM 1
#define LV_USE_SDL 0
#define LV_USE_WAYLAND 0
```

To use SDL2 support, adjust `lv_conf.h` as follows:
```
#define LV_USE_LINUX_FBDEV 0
#define LV_USE_LINUX_DRM 0
#define LV_USE_SDL 1
#define LV_USE_WAYLAND 0
```


To use wayland, adjust `lv_conf.h` as follows:
```
#define LV_USE_LINUX_FBDEV 0
#define LV_USE_LINUX_DRM 0
#define LV_USE_SDL 0
#define LV_USE_WAYLAND 1
```

## Build the project (cmake or Makefile)

### cmake

```
mkdir build
cd build
cmake ..
make -j
cmake -B build -S .
make -C build -j
```

### Makefile
Expand All @@ -64,10 +73,25 @@ make -j
make -j
```

## Command line options

Command line options are used to modify behavior of the demo, they take precedence over environment variables.

### Wayland

- `-f` - enters fullscreen on startup
- `-m` - maximizes window on startup
- `-w <window width>` - set the width of the window
- `-h <window height>` - set the height of the window

### SDL2

- `-w <window width>` - set the width of the window
- `-h <window height>` - set the height of the window

## Environment variables

Environment variables can be set to modify behavior of the demo.
The following variables are supported.
Environment variables can be set to modify the behavior of the demo.

### Legacy framebuffer (fbdev)

Expand All @@ -84,19 +108,25 @@ The following variables are supported.

### SDL2

- `LV_SDL_VIDEO_WIDTH` - width of SDL2 surface (default `800`).
- `LV_SDL_VIDEO_HEIGHT` - height of SDL2 surface (default `480`).
- `LV_SIM_WINDOW_WIDTH` - width of SDL2 surface (default `800`).
- `LV_SIM_WINDOW_HEIGHT` - height of SDL2 surface (default `480`).

### Wayland

- `LV_SIM_WINDOW_WIDTH` - width of the window (default `800`).
- `LV_SIM_WINDOW_HEIGHT` - height of the window (default `480`).


## Run the demo application

### As root
### FBDEV

Normal users don't have access to `/dev/fb0` so use `sudo` (or see below) :
Unpriviledged users don't have access to the framebuffer device `/dev/fb0`
`sudo` or `su` must be used.

cmake:
```
cd ../bin
sudo main
sudo ./bin/lvglsim
```

Makefile:
Expand All @@ -105,23 +135,12 @@ cd build/bin/
sudo main
```

### Userland

You can give a normal user access to the framebuffer by adding them to the `video` group :

Access to the framebuffer device can be granted by adding the unpriviledged user to the `video` group

cmake:
```
sudo adduser $USER video
newgrp video
cd ../bin
./main
./bin/lvglsim
```

Makefile:
```
sudo adduser $USER video
newgrp video
cd build/bin/
./main
```
6 changes: 6 additions & 0 deletions backends/interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

/* Enters the run loop of the selected backend */
void lv_linux_run_loop(void);

/* Initializes the display */
void lv_linux_disp_init(void);
11 changes: 11 additions & 0 deletions backends/settings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdbool.h>
#include <stdint.h>

/* Settings defined in main.c */

extern uint16_t window_width;
extern uint16_t window_height;

extern bool fullscreen;
extern bool maximize;

50 changes: 50 additions & 0 deletions backends/wayland.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <unistd.h>
#include <stdlib.h>

#include "lvgl/lvgl.h"
#include "settings.h"

/* Currently, the wayland driver calls lv_timer_handler internaly */
void lv_linux_run_loop(void)
{

bool completed;

/* Handle LVGL tasks */
while (1) {

completed = lv_wayland_timer_handler();

if (completed) {
/* wait only if the cycle was completed */
usleep(LV_DEF_REFR_PERIOD * 1000);
}

/* Run until the last window closes */
if (!lv_wayland_window_is_open(NULL)) {
break;
}
}

}

void lv_linux_disp_init(void)
{
lv_display_t *disp;
lv_group_t *g;

disp = lv_wayland_window_create(window_width, window_height,
"LVGL Simulator", NULL);

if (fullscreen) {
lv_wayland_window_set_fullscreen(disp, fullscreen);
} else if (maximize) {
lv_wayland_window_set_maximized(disp, maximize);
}

g = lv_group_create();
lv_group_set_default(g);
lv_indev_set_group(lv_wayland_get_keyboard(disp), g);
lv_indev_set_group(lv_wayland_get_pointeraxis(disp), g);

}
Loading

0 comments on commit 8b106e2

Please sign in to comment.