mirror of
https://gitlab.freedesktop.org/plymouth/plymouth.git
synced 2026-05-06 05:38:14 +02:00
Merge branch 'wayland_renderer' into 'main'
renderers: Add wayland Closes #179 See merge request plymouth/plymouth!365
This commit is contained in:
commit
13e3bf045d
7 changed files with 718 additions and 1 deletions
|
|
@ -36,6 +36,7 @@ libfreetype_dep = dependency('freetype2', required: get_option('freetype'))
|
|||
gtk3_dep = dependency('gtk+-3.0', version: '>= 3.14.0', required: get_option('gtk'))
|
||||
libdrm_dep = dependency('libdrm', required: get_option('drm'))
|
||||
libevdev_dep = dependency('libevdev')
|
||||
wayland_dep = dependency('wayland-client', required: get_option('wayland'))
|
||||
xkbcommon_dep = dependency('xkbcommon')
|
||||
xkeyboard_config_dep = dependency('xkeyboard-config')
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,11 @@ option('drm',
|
|||
value: true,
|
||||
description: 'Build with drm kms support',
|
||||
)
|
||||
option('wayland',
|
||||
type: 'feature',
|
||||
value: 'enabled',
|
||||
description: 'Build with wayland support',
|
||||
)
|
||||
option('docs',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ ply_renderer_open (ply_renderer_t *renderer,
|
|||
const char *path;
|
||||
} known_plugins[] =
|
||||
{
|
||||
{ PLY_RENDERER_TYPE_WAYLAND, PLYMOUTH_PLUGIN_PATH "renderers/wayland.so" },
|
||||
{ PLY_RENDERER_TYPE_X11, PLYMOUTH_PLUGIN_PATH "renderers/x11.so" },
|
||||
{ PLY_RENDERER_TYPE_DRM, PLYMOUTH_PLUGIN_PATH "renderers/drm.so" },
|
||||
{ PLY_RENDERER_TYPE_SIMPLEDRM, PLYMOUTH_PLUGIN_PATH "renderers/drm.so" },
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ typedef enum
|
|||
PLY_RENDERER_TYPE_DRM,
|
||||
PLY_RENDERER_TYPE_SIMPLEDRM,
|
||||
PLY_RENDERER_TYPE_FRAME_BUFFER,
|
||||
PLY_RENDERER_TYPE_X11
|
||||
PLY_RENDERER_TYPE_X11,
|
||||
PLY_RENDERER_TYPE_WAYLAND
|
||||
} ply_renderer_type_t;
|
||||
|
||||
typedef void (*ply_renderer_input_source_handler_t) (void *user_data,
|
||||
|
|
|
|||
|
|
@ -7,3 +7,7 @@ endif
|
|||
if gtk3_dep.found()
|
||||
subdir('x11')
|
||||
endif
|
||||
|
||||
if wayland_dep.found()
|
||||
subdir('wayland')
|
||||
endif
|
||||
|
|
|
|||
19
src/plugins/renderers/wayland/meson.build
Normal file
19
src/plugins/renderers/wayland/meson.build
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
wl_mod = import('unstable-wayland')
|
||||
|
||||
xdg_shell_xml = wl_mod.find_protocol('xdg-shell')
|
||||
|
||||
xdg_shell = wl_mod.scan_xml(xdg_shell_xml)
|
||||
|
||||
wayland_plugin = shared_module('wayland',
|
||||
'plugin.c',
|
||||
xdg_shell,
|
||||
dependencies: [
|
||||
libply_dep,
|
||||
libply_splash_core_dep,
|
||||
wayland_dep,
|
||||
],
|
||||
include_directories: config_h_inc,
|
||||
name_prefix: '',
|
||||
install: true,
|
||||
install_dir: plymouth_plugin_path / 'renderers',
|
||||
)
|
||||
686
src/plugins/renderers/wayland/plugin.c
Normal file
686
src/plugins/renderers/wayland/plugin.c
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
||||
#include "ply-logger.h"
|
||||
#include "ply-renderer-plugin.h"
|
||||
|
||||
struct _ply_renderer_head
|
||||
{
|
||||
ply_renderer_backend_t *backend;
|
||||
struct wl_output *output;
|
||||
|
||||
ply_rectangle_t area;
|
||||
int32_t scale;
|
||||
ply_pixel_buffer_rotation_t rotation;
|
||||
bool damaged;
|
||||
|
||||
int32_t size;
|
||||
ply_pixel_buffer_t *pixel_buffer;
|
||||
void *shm_data;
|
||||
struct wl_buffer *buffer;
|
||||
|
||||
struct wl_surface *surface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *toplevel;
|
||||
};
|
||||
|
||||
struct _ply_renderer_input_source
|
||||
{
|
||||
ply_buffer_t *key_buffer;
|
||||
ply_renderer_input_source_handler_t handler;
|
||||
void *user_data;
|
||||
|
||||
struct wl_keyboard *keyboard;
|
||||
struct xkb_context *xkb_ctx;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *state;
|
||||
};
|
||||
|
||||
struct _ply_renderer_backend
|
||||
{
|
||||
ply_event_loop_t *loop;
|
||||
ply_fd_watch_t *display_watch;
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_registry *registry;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_shm *shm;
|
||||
struct xdg_wm_base *wm_base;
|
||||
struct wl_seat *seat;
|
||||
|
||||
ply_list_t *heads;
|
||||
ply_renderer_input_source_t input_source;
|
||||
|
||||
bool is_active;
|
||||
};
|
||||
|
||||
ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void);
|
||||
|
||||
static void
|
||||
noop ()
|
||||
{
|
||||
}
|
||||
|
||||
static ply_renderer_backend_t *
|
||||
create_backend (const char *device_name,
|
||||
ply_terminal_t *terminal,
|
||||
ply_terminal_t *local_console_terminal)
|
||||
{
|
||||
ply_renderer_backend_t *backend;
|
||||
|
||||
backend = calloc (1, sizeof(ply_renderer_backend_t));
|
||||
|
||||
backend->loop = ply_event_loop_get_default ();
|
||||
backend->heads = ply_list_new ();
|
||||
backend->input_source.key_buffer = ply_buffer_new ();
|
||||
|
||||
return backend;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_backend (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
|
||||
node = ply_list_get_first_node (backend->heads);
|
||||
while (node != NULL) {
|
||||
ply_list_node_t *next_node;
|
||||
ply_renderer_head_t *head;
|
||||
|
||||
head = (ply_renderer_head_t *) ply_list_node_get_data (node);
|
||||
next_node = ply_list_get_next_node (backend->heads, node);
|
||||
|
||||
free (head);
|
||||
node = next_node;
|
||||
}
|
||||
|
||||
ply_buffer_free (backend->input_source.key_buffer);
|
||||
ply_list_free (backend->heads);
|
||||
free (backend);
|
||||
}
|
||||
|
||||
static void
|
||||
on_display_event (void *user_data,
|
||||
int source_fd)
|
||||
{
|
||||
ply_renderer_backend_t *backend = user_data;
|
||||
|
||||
while (wl_display_prepare_read (backend->display)) {
|
||||
wl_display_dispatch_pending (backend->display);
|
||||
}
|
||||
|
||||
wl_display_read_events (backend->display);
|
||||
wl_display_dispatch_pending (backend->display);
|
||||
}
|
||||
|
||||
static void
|
||||
output_mode (void *data,
|
||||
struct wl_output *wl_output,
|
||||
uint32_t flags,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t refresh)
|
||||
{
|
||||
ply_renderer_head_t *head = data;
|
||||
|
||||
head->area.width = width;
|
||||
head->area.height = height;
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener = {
|
||||
.geometry = (void (*)(void *, struct wl_output *, int, int, int, int, int, const char *, const char *, int)) noop,
|
||||
.mode = output_mode,
|
||||
.done = (void (*)(void *, struct wl_output *)) noop,
|
||||
.scale = (void (*)(void *, struct wl_output *, int)) noop,
|
||||
.name = (void (*)(void *, struct wl_output *, const char *)) noop,
|
||||
.description = (void (*)(void *, struct wl_output *, const char *)) noop
|
||||
};
|
||||
|
||||
static void
|
||||
wm_base_ping (void *data,
|
||||
struct xdg_wm_base *xdg_wm_base,
|
||||
uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong (xdg_wm_base, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener wm_base_listener = {
|
||||
.ping = wm_base_ping
|
||||
};
|
||||
|
||||
static void
|
||||
keyboard_keymap (void *data,
|
||||
struct wl_keyboard *wl_keyboard,
|
||||
uint32_t format,
|
||||
int32_t fd,
|
||||
uint32_t size)
|
||||
{
|
||||
char *map_shm;
|
||||
ply_renderer_input_source_t *input = data;
|
||||
|
||||
assert (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
|
||||
|
||||
xkb_keymap_unref (input->keymap);
|
||||
xkb_state_unref (input->state);
|
||||
|
||||
map_shm = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
input->keymap = xkb_keymap_new_from_string (input->xkb_ctx, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
munmap (map_shm, size);
|
||||
close (fd);
|
||||
|
||||
input->state = xkb_state_new (input->keymap);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_key (void *data,
|
||||
struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t key,
|
||||
uint32_t state)
|
||||
{
|
||||
xkb_keysym_t keysym;
|
||||
ply_renderer_input_source_t *input = data;
|
||||
|
||||
if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
|
||||
return;
|
||||
|
||||
keysym = xkb_state_key_get_one_sym (input->state, key + 8);
|
||||
if (keysym == XKB_KEY_Return) {
|
||||
ply_buffer_append_bytes (input->key_buffer, "\n", 1);
|
||||
} else if (keysym == XKB_KEY_Escape) {
|
||||
ply_buffer_append_bytes (input->key_buffer, "\033", 1);
|
||||
} else if (keysym == XKB_KEY_BackSpace) {
|
||||
ply_buffer_append_bytes (input->key_buffer, "\177", 1);
|
||||
} else {
|
||||
char buf[7];
|
||||
int num_bytes;
|
||||
|
||||
num_bytes = xkb_state_key_get_utf8 (input->state, key + 8, buf, sizeof(buf));
|
||||
ply_buffer_append_bytes (input->key_buffer, buf, num_bytes);
|
||||
}
|
||||
|
||||
if (input->handler)
|
||||
input->handler (input->user_data, input->key_buffer, input);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_modifiers (void *data,
|
||||
struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t mods_depressed,
|
||||
uint32_t mods_latched,
|
||||
uint32_t mods_locked,
|
||||
uint32_t group)
|
||||
{
|
||||
ply_renderer_input_source_t *input = data;
|
||||
|
||||
xkb_state_update_mask (input->state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_listener keyboard_listener = {
|
||||
.keymap = keyboard_keymap,
|
||||
.enter = (void (*)(void *,struct wl_keyboard *, unsigned int, struct wl_surface *, struct wl_array *)) noop,
|
||||
.leave = (void (*)(void *,struct wl_keyboard *, unsigned int, struct wl_surface *)) noop,
|
||||
.key = keyboard_key,
|
||||
.modifiers = keyboard_modifiers
|
||||
};
|
||||
|
||||
static void
|
||||
seat_capabilities (void *data,
|
||||
struct wl_seat *wl_seat,
|
||||
uint32_t capabilities)
|
||||
{
|
||||
ply_renderer_input_source_t *input = data;
|
||||
|
||||
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD && !input->keyboard) {
|
||||
input->keyboard = wl_seat_get_keyboard (wl_seat);
|
||||
wl_keyboard_add_listener (input->keyboard, &keyboard_listener, data);
|
||||
} else if (input->keyboard) {
|
||||
wl_keyboard_release (input->keyboard);
|
||||
input->keyboard = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener seat_listener = {
|
||||
.capabilities = seat_capabilities,
|
||||
.name = (void (*)(void *, struct wl_seat *,const char *)) noop,
|
||||
};
|
||||
|
||||
static void
|
||||
registry (void *data,
|
||||
struct wl_registry *wl_registry,
|
||||
uint32_t name,
|
||||
const char *interface,
|
||||
uint32_t version)
|
||||
{
|
||||
ply_renderer_backend_t *backend = data;
|
||||
|
||||
if (!strcmp (interface, wl_output_interface.name)) {
|
||||
ply_renderer_head_t *head;
|
||||
|
||||
head = calloc (1, sizeof(ply_renderer_head_t));
|
||||
|
||||
head->backend = backend;
|
||||
head->output = wl_registry_bind (wl_registry, name, &wl_output_interface, 4);
|
||||
wl_output_add_listener (head->output, &output_listener, head);
|
||||
|
||||
ply_list_append_data (backend->heads, head);
|
||||
} else if (!strcmp (interface, wl_compositor_interface.name)) {
|
||||
backend->compositor = wl_registry_bind (wl_registry, name, &wl_compositor_interface, 6);
|
||||
} else if (!strcmp (interface, wl_shm_interface.name)) {
|
||||
backend->shm = wl_registry_bind (wl_registry, name, &wl_shm_interface, 1);
|
||||
} else if (!strcmp (interface, xdg_wm_base_interface.name)) {
|
||||
backend->wm_base = wl_registry_bind (wl_registry, name, &xdg_wm_base_interface, 3);
|
||||
xdg_wm_base_add_listener (backend->wm_base, &wm_base_listener, data);
|
||||
} else if (!strcmp (interface, wl_seat_interface.name)) {
|
||||
backend->seat = wl_registry_bind (wl_registry, name, &wl_seat_interface, 3);
|
||||
wl_seat_add_listener (backend->seat, &seat_listener, &backend->input_source);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
.global = registry
|
||||
};
|
||||
|
||||
static bool
|
||||
open_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
backend->display = wl_display_connect (NULL);
|
||||
if (!backend->display) {
|
||||
ply_trace ("Couldn't connect to wayland display");
|
||||
return false;
|
||||
}
|
||||
|
||||
backend->display_watch = ply_event_loop_watch_fd (backend->loop, wl_display_get_fd (backend->display), PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, on_display_event, NULL, backend);
|
||||
|
||||
backend->registry = wl_display_get_registry (backend->display);
|
||||
wl_registry_add_listener (backend->registry, ®istry_listener, backend);
|
||||
wl_display_roundtrip (backend->display);
|
||||
|
||||
backend->input_source.xkb_ctx = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
close_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_event_loop_stop_watching_fd (backend->loop, backend->display_watch);
|
||||
backend->display_watch = NULL;
|
||||
wl_display_disconnect (backend->display);
|
||||
xkb_context_unref (backend->input_source.xkb_ctx);
|
||||
}
|
||||
|
||||
static void randname (char *buf)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime (CLOCK_REALTIME, &ts);
|
||||
long r = ts.tv_nsec;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
buf[i] = 'A' + (r & 15) + (r & 16) * 2;
|
||||
r >>= 5;
|
||||
}
|
||||
}
|
||||
|
||||
static int anonymous_shm_open (void)
|
||||
{
|
||||
char name[] = "/plymouth-XXXXXX";
|
||||
int retries = 100;
|
||||
|
||||
do {
|
||||
randname (name + strlen (name) - 6);
|
||||
|
||||
--retries;
|
||||
// shm_open guarantees that O_CLOEXEC is set
|
||||
int fd = shm_open (name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
shm_unlink (name);
|
||||
return fd;
|
||||
}
|
||||
} while (retries > 0 && errno == EEXIST);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int create_shm_file (off_t size)
|
||||
{
|
||||
int fd = anonymous_shm_open ();
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (ftruncate (fd, size) < 0) {
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static bool
|
||||
query_device (ply_renderer_backend_t *backend,
|
||||
bool force)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
|
||||
node = ply_list_get_first_node (backend->heads);
|
||||
while (node != NULL) {
|
||||
ply_list_node_t *next_node;
|
||||
ply_renderer_head_t *head;
|
||||
int fd;
|
||||
struct wl_shm_pool *pool;
|
||||
|
||||
head = (ply_renderer_head_t *) ply_list_node_get_data (node);
|
||||
next_node = ply_list_get_next_node (backend->heads, node);
|
||||
|
||||
wl_display_roundtrip (backend->display);
|
||||
|
||||
head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height);
|
||||
ply_pixel_buffer_fill_with_color (head->pixel_buffer, &head->area, 0.0, 0.0, 0.0, 1.0);
|
||||
head->size = head->area.width * 4 * head->area.height;
|
||||
fd = create_shm_file (head->size);
|
||||
head->shm_data = mmap (NULL, head->size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
pool = wl_shm_create_pool (backend->shm, fd, head->size);
|
||||
head->buffer = wl_shm_pool_create_buffer (pool, 0, head->area.width, head->area.height, head->area.width * 4, WL_SHM_FORMAT_ARGB8888);
|
||||
wl_shm_pool_destroy (pool);
|
||||
close (fd);
|
||||
|
||||
node = next_node;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void surface_preferred_buffer_scale (void *data,
|
||||
struct wl_surface *wl_surface,
|
||||
int32_t factor)
|
||||
{
|
||||
ply_renderer_head_t *head = data;
|
||||
|
||||
head->scale = factor;
|
||||
ply_pixel_buffer_set_device_scale (head->pixel_buffer, head->scale);
|
||||
wl_surface_set_buffer_scale (wl_surface, head->scale);
|
||||
}
|
||||
|
||||
static void
|
||||
surface_preferred_buffer_transform (void *data,
|
||||
struct wl_surface *wl_surface,
|
||||
uint32_t transform)
|
||||
{
|
||||
ply_renderer_head_t *head = data;
|
||||
|
||||
switch (transform) {
|
||||
case WL_OUTPUT_TRANSFORM_NORMAL:
|
||||
head->rotation = PLY_PIXEL_BUFFER_ROTATE_UPRIGHT;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
head->rotation = PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_180:
|
||||
head->rotation = PLY_PIXEL_BUFFER_ROTATE_UPSIDE_DOWN;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
head->rotation = PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE;
|
||||
break;
|
||||
default:
|
||||
head->rotation = PLY_PIXEL_BUFFER_ROTATE_UPRIGHT;
|
||||
transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ply_pixel_buffer_set_device_rotation (head->pixel_buffer, head->rotation);
|
||||
wl_surface_set_buffer_transform (wl_surface, transform);
|
||||
}
|
||||
|
||||
static const struct wl_surface_listener surface_listener = {
|
||||
.enter = (void (*)(void *, struct wl_surface *, struct wl_output *)) noop,
|
||||
.leave = (void (*)(void *, struct wl_surface *, struct wl_output *)) noop,
|
||||
.preferred_buffer_scale = surface_preferred_buffer_scale,
|
||||
.preferred_buffer_transform = surface_preferred_buffer_transform
|
||||
};
|
||||
|
||||
static void
|
||||
surface_configure (void *data,
|
||||
struct xdg_surface *xdg_surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
ply_renderer_head_t *head = data;
|
||||
|
||||
xdg_surface_ack_configure (xdg_surface, serial);
|
||||
wl_surface_commit (head->surface);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = surface_configure
|
||||
};
|
||||
|
||||
static void
|
||||
toplevel_configure (void *data,
|
||||
struct xdg_toplevel *xdg_toplevel,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
struct wl_array *states)
|
||||
{
|
||||
int fd;
|
||||
struct wl_shm_pool *pool;
|
||||
ply_renderer_head_t *head = data;
|
||||
|
||||
if ((!width && !height) || (width == head->area.width && height == head->area.height)) return;
|
||||
|
||||
wl_buffer_destroy (head->buffer);
|
||||
munmap (head->shm_data, head->size);
|
||||
|
||||
head->area.width = width;
|
||||
head->area.height = height;
|
||||
|
||||
head->pixel_buffer = ply_pixel_buffer_resize (head->pixel_buffer, head->area.width, head->area.height);
|
||||
head->size = head->area.width * 4 * head->area.height;
|
||||
fd = create_shm_file (head->size);
|
||||
head->shm_data = mmap (NULL, head->size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
pool = wl_shm_create_pool (head->backend->shm, fd, head->size);
|
||||
head->buffer = wl_shm_pool_create_buffer (pool, 0, head->area.width, head->area.height, head->area.width * 4, WL_SHM_FORMAT_ARGB8888);
|
||||
wl_shm_pool_destroy (pool);
|
||||
close (fd);
|
||||
|
||||
wl_surface_attach (head->surface, head->buffer, 0, 0);
|
||||
wl_surface_damage_buffer (head->surface, 0, 0, UINT32_MAX, UINT32_MAX);
|
||||
wl_surface_commit (head->surface);
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener toplevel_listener = {
|
||||
.configure = toplevel_configure
|
||||
};
|
||||
|
||||
static const struct wl_callback_listener frame_listener;
|
||||
|
||||
static void
|
||||
frame (void *data,
|
||||
struct wl_callback *wl_callback,
|
||||
uint32_t callback_data)
|
||||
{
|
||||
ply_renderer_head_t *head = data;
|
||||
|
||||
wl_callback_destroy (wl_callback);
|
||||
wl_callback = wl_surface_frame (head->surface);
|
||||
wl_callback_add_listener (wl_callback, &frame_listener, data);
|
||||
|
||||
if (head->damaged) {
|
||||
memcpy (head->shm_data, ply_pixel_buffer_get_argb32_data (head->pixel_buffer), head->size);
|
||||
wl_surface_damage_buffer (head->surface, 0, 0, head->area.width, head->area.height);
|
||||
wl_surface_commit (head->surface);
|
||||
head->damaged = false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {
|
||||
.done = frame
|
||||
};
|
||||
|
||||
static bool
|
||||
map_to_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
|
||||
node = ply_list_get_first_node (backend->heads);
|
||||
while (node != NULL) {
|
||||
ply_list_node_t *next_node;
|
||||
ply_renderer_head_t *head;
|
||||
|
||||
head = (ply_renderer_head_t *) ply_list_node_get_data (node);
|
||||
next_node = ply_list_get_next_node (backend->heads, node);
|
||||
|
||||
if (!head->surface) {
|
||||
struct wl_callback *cb;
|
||||
|
||||
head->surface = wl_compositor_create_surface (backend->compositor);
|
||||
wl_surface_add_listener (head->surface, &surface_listener, head);
|
||||
head->xdg_surface = xdg_wm_base_get_xdg_surface (backend->wm_base, head->surface);
|
||||
xdg_surface_add_listener (head->xdg_surface, &xdg_surface_listener, head);
|
||||
head->toplevel = xdg_surface_get_toplevel (head->xdg_surface);
|
||||
xdg_toplevel_add_listener (head->toplevel, &toplevel_listener, head);
|
||||
|
||||
memcpy (head->shm_data, ply_pixel_buffer_get_argb32_data (head->pixel_buffer), head->size);
|
||||
wl_surface_attach (head->surface, head->buffer, 0, 0);
|
||||
wl_surface_damage_buffer (head->surface, 0, 0, head->area.width, head->area.height);
|
||||
|
||||
xdg_toplevel_set_title (head->toplevel, "Plymouth");
|
||||
xdg_toplevel_set_fullscreen (head->toplevel, head->output);
|
||||
wl_surface_commit (head->surface);
|
||||
|
||||
cb = wl_surface_frame (head->surface);
|
||||
wl_callback_add_listener (cb, &frame_listener, head);
|
||||
}
|
||||
|
||||
node = next_node;
|
||||
}
|
||||
|
||||
backend->is_active = true;
|
||||
wl_display_roundtrip (backend->display);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_from_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
|
||||
node = ply_list_get_first_node (backend->heads);
|
||||
while (node != NULL) {
|
||||
ply_list_node_t *next_node;
|
||||
ply_renderer_head_t *head;
|
||||
|
||||
head = (ply_renderer_head_t *) ply_list_node_get_data (node);
|
||||
next_node = ply_list_get_next_node (backend->heads, node);
|
||||
|
||||
xdg_toplevel_destroy (head->toplevel);
|
||||
xdg_surface_destroy (head->xdg_surface);
|
||||
wl_surface_destroy (head->surface);
|
||||
wl_buffer_destroy (head->buffer);
|
||||
munmap (head->shm_data, head->size);
|
||||
ply_pixel_buffer_free (head->pixel_buffer);
|
||||
head->surface = NULL;
|
||||
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
activate (ply_renderer_backend_t *backend)
|
||||
{
|
||||
backend->is_active = true;
|
||||
}
|
||||
|
||||
static void
|
||||
deactivate (ply_renderer_backend_t *backend)
|
||||
{
|
||||
backend->is_active = false;
|
||||
}
|
||||
|
||||
static void
|
||||
flush_head (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head)
|
||||
{
|
||||
if (!backend->is_active)
|
||||
return;
|
||||
|
||||
head->damaged = true;
|
||||
wl_display_roundtrip (backend->display);
|
||||
}
|
||||
|
||||
static ply_list_t *
|
||||
get_heads (ply_renderer_backend_t *backend)
|
||||
{
|
||||
return backend->heads;
|
||||
}
|
||||
|
||||
static ply_pixel_buffer_t *
|
||||
get_buffer_for_head (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head)
|
||||
{
|
||||
return head->pixel_buffer;
|
||||
}
|
||||
|
||||
static ply_renderer_input_source_t *
|
||||
get_input_source (ply_renderer_backend_t *backend)
|
||||
{
|
||||
return &backend->input_source;
|
||||
}
|
||||
|
||||
static bool
|
||||
open_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
return input_source->keyboard != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_handler_for_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source,
|
||||
ply_renderer_input_source_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
input_source->handler = handler;
|
||||
input_source->user_data = user_data;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_device_name (ply_renderer_backend_t *backend)
|
||||
{
|
||||
return "wayland";
|
||||
}
|
||||
|
||||
ply_renderer_plugin_interface_t *
|
||||
ply_renderer_backend_get_interface (void)
|
||||
{
|
||||
static ply_renderer_plugin_interface_t plugin_interface = {
|
||||
.create_backend = create_backend,
|
||||
.destroy_backend = destroy_backend,
|
||||
.open_device = open_device,
|
||||
.close_device = close_device,
|
||||
.query_device = query_device,
|
||||
.map_to_device = map_to_device,
|
||||
.unmap_from_device = unmap_from_device,
|
||||
.activate = activate,
|
||||
.deactivate = deactivate,
|
||||
.flush_head = flush_head,
|
||||
.get_heads = get_heads,
|
||||
.get_buffer_for_head = get_buffer_for_head,
|
||||
.get_input_source = get_input_source,
|
||||
.open_input_source = open_input_source,
|
||||
.set_handler_for_input_source = set_handler_for_input_source,
|
||||
.close_input_source = (void (*)(ply_renderer_backend_t *,ply_renderer_input_source_t *)) noop,
|
||||
.get_device_name = get_device_name
|
||||
};
|
||||
|
||||
return &plugin_interface;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue