(Wayland) Dynamically load libdecor at runtime

This commit is contained in:
Colin Kinloch 2022-03-21 19:34:52 +00:00 committed by Autechre
parent 1e31a8d5fd
commit d95bc2dd54
8 changed files with 240 additions and 120 deletions

View File

@ -1275,8 +1275,7 @@ ifeq ($(HAVE_WAYLAND), 1)
LIBS += $(WAYLAND_LIBS) $(WAYLAND_CURSOR_LIBS)
ifeq ($(HAVE_LIBDECOR), 1)
DEFINES += -DHAVE_LIBDECOR
LIBS += $(LIBDECOR_LIBS)
DEFINES += -DHAVE_LIBDECOR_H
DEF_FLAGS += $(LIBDECOR_CFLAGS)
endif

View File

@ -0,0 +1,76 @@
#ifndef RA_WAYLAND_MODULE
#define RA_WAYLAND_MODULE(modname)
#endif
#ifndef RA_WAYLAND_SYM
#define RA_WAYLAND_SYM(rc,fn,params)
#endif
#ifndef RA_WAYLAND_INTERFACE
#define RA_WAYLAND_INTERFACE(iface)
#endif
#include <stdbool.h>
#ifdef HAVE_LIBDECOR_H
RA_WAYLAND_MODULE(WAYLAND_LIBDECOR)
RA_WAYLAND_SYM(void, libdecor_unref, (struct libdecor *))
RA_WAYLAND_SYM(struct libdecor *, libdecor_new, (struct wl_display *, struct libdecor_interface *))
RA_WAYLAND_SYM(int, libdecor_dispatch, (struct libdecor *, int timeout))
RA_WAYLAND_SYM(struct libdecor_frame *, libdecor_decorate, (struct libdecor *,\
struct wl_surface *,\
struct libdecor_frame_interface *,\
void *))
RA_WAYLAND_SYM(void, libdecor_frame_unref, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_title, (struct libdecor_frame *, const char *))
RA_WAYLAND_SYM(void, libdecor_frame_set_app_id, (struct libdecor_frame *, const char *))
RA_WAYLAND_SYM(void, libdecor_frame_set_max_content_size, (struct libdecor_frame *frame,\
int content_width,\
int content_height))
RA_WAYLAND_SYM(void, libdecor_frame_set_min_content_size, (struct libdecor_frame *frame,\
int content_width,\
int content_height))
RA_WAYLAND_SYM(void, libdecor_frame_resize, (struct libdecor_frame *,\
struct wl_seat *,\
uint32_t,\
enum libdecor_resize_edge))
RA_WAYLAND_SYM(void, libdecor_frame_move, (struct libdecor_frame *,\
struct wl_seat *,\
uint32_t))
RA_WAYLAND_SYM(void, libdecor_frame_commit, (struct libdecor_frame *,\
struct libdecor_state *,\
struct libdecor_configuration *))
RA_WAYLAND_SYM(void, libdecor_frame_set_minimized, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_maximized, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_unset_maximized, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_fullscreen, (struct libdecor_frame *, struct wl_output *))
RA_WAYLAND_SYM(void, libdecor_frame_unset_fullscreen, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_capabilities, (struct libdecor_frame *, \
enum libdecor_capabilities))
RA_WAYLAND_SYM(void, libdecor_frame_unset_capabilities, (struct libdecor_frame *, \
enum libdecor_capabilities))
RA_WAYLAND_SYM(bool, libdecor_frame_has_capability, (struct libdecor_frame *, \
enum libdecor_capabilities))
RA_WAYLAND_SYM(void, libdecor_frame_set_visibility, (struct libdecor_frame *, bool))
RA_WAYLAND_SYM(bool, libdecor_frame_is_visible, (struct libdecor_frame *))
RA_WAYLAND_SYM(bool, libdecor_frame_is_floating, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_parent, (struct libdecor_frame *,\
struct libdecor_frame *))
RA_WAYLAND_SYM(struct xdg_surface *, libdecor_frame_get_xdg_surface, (struct libdecor_frame *))
RA_WAYLAND_SYM(struct xdg_toplevel *, libdecor_frame_get_xdg_toplevel, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_map, (struct libdecor_frame *))
RA_WAYLAND_SYM(struct libdecor_state *, libdecor_state_new, (int, int))
RA_WAYLAND_SYM(void, libdecor_state_free, (struct libdecor_state *))
RA_WAYLAND_SYM(bool, libdecor_configuration_get_content_size, (struct libdecor_configuration *,\
struct libdecor_frame *,\
int *,\
int *))
RA_WAYLAND_SYM(bool, libdecor_configuration_get_window_state, (struct libdecor_configuration *,\
enum libdecor_window_state *))
#endif
#undef RA_WAYLAND_MODULE
#undef RA_WAYLAND_SYM
#undef RA_WAYLAND_INTERFACE

View File

@ -25,7 +25,7 @@
#define SPLASH_SHM_NAME "retroarch-wayland-vk-splash"
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
@ -71,7 +71,7 @@ void xdg_toplevel_handle_close(void *data,
command_event(CMD_EVENT_QUIT, NULL);
}
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
void libdecor_frame_handle_configure_common(struct libdecor_frame *frame,
struct libdecor_configuration *configuration,
gfx_ctx_wayland_data_t *wl)
@ -92,7 +92,7 @@ void libdecor_frame_handle_configure_common(struct libdecor_frame *frame,
wl->fullscreen = false;
wl->maximized = false;
if (libdecor_configuration_get_window_state(
if (wl->libdecor_configuration_get_window_state(
configuration, &window_state))
{
wl->fullscreen = (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;
@ -101,7 +101,7 @@ void libdecor_frame_handle_configure_common(struct libdecor_frame *frame,
tiled = (window_state & tiled_states) != 0;
}
if (!libdecor_configuration_get_content_size(configuration, frame,
if (!wl->libdecor_configuration_get_content_size(configuration, frame,
&width, &height))
{
width = wl->floating_width;
@ -115,11 +115,11 @@ void libdecor_frame_handle_configure_common(struct libdecor_frame *frame,
wl->height = height;
}
state = libdecor_state_new(wl->width, wl->height);
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
state = wl->libdecor_state_new(wl->width, wl->height);
wl->libdecor_frame_commit(frame, state, configuration);
wl->libdecor_state_free(state);
if (libdecor_frame_is_floating(frame)) {
if (wl->libdecor_frame_is_floating(frame)) {
wl->floating_width = width;
wl->floating_height = height;
}
@ -231,18 +231,23 @@ void gfx_ctx_wl_update_title_common(gfx_ctx_wayland_data_t *wl)
video_driver_get_window_title(title, sizeof(title));
#ifdef HAVE_LIBDECOR
if (wl && title[0])
libdecor_frame_set_title(wl->libdecor_frame, title);
#else
if (wl && title[0])
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
{
if (wl->deco)
zxdg_toplevel_decoration_v1_set_mode(wl->deco,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
xdg_toplevel_set_title(wl->xdg_toplevel, title);
if (wl && title[0])
wl->libdecor_frame_set_title(wl->libdecor_frame, title);
}
else
#endif
{
if (wl && title[0])
{
if (wl->deco)
zxdg_toplevel_decoration_v1_set_mode(wl->deco,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
xdg_toplevel_set_title(wl->xdg_toplevel, title);
}
}
}
bool gfx_ctx_wl_get_metrics_common(gfx_ctx_wayland_data_t *wl,
@ -279,7 +284,7 @@ bool gfx_ctx_wl_get_metrics_common(gfx_ctx_wayland_data_t *wl,
}
bool gfx_ctx_wl_init_common(void *video_driver,
toplevel_listener_t **toplevel_listener, gfx_ctx_wayland_data_t **wwl)
const toplevel_listener_t *toplevel_listener, gfx_ctx_wayland_data_t **wwl)
{
int i;
*wwl = calloc(1, sizeof(gfx_ctx_wayland_data_t));
@ -288,6 +293,18 @@ bool gfx_ctx_wl_init_common(void *video_driver,
if (!wl)
return false;
#ifdef HAVE_LIBDECOR_H
#ifdef HAVE_DYNAMIC
wl->libdecor = dylib_load("libdecor-0.so");
if (wl->libdecor)
{
#define RA_WAYLAND_SYM(rc,fn,params) wl->fn = (rc (*) params)dylib_proc(wl->libdecor, #fn);
#include "wayland/libdecor_sym.h"
}
#endif
#endif
wl_list_init(&wl->all_outputs);
frontend_driver_destroy_signal_handler_state();
@ -343,55 +360,60 @@ bool gfx_ctx_wl_init_common(void *video_driver,
wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale);
wl_surface_add_listener(wl->surface, &wl_surface_listener, wl);
#ifdef HAVE_LIBDECOR
wl->libdecor_context = libdecor_new(wl->input.dpy, &libdecor_interface);
if (wl->libdecor_context)
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
{
wl->libdecor_frame = libdecor_decorate(wl->libdecor_context, wl->surface, toplevel_listener, wl);
if (!wl->libdecor_frame)
wl->libdecor_context = wl->libdecor_new(wl->input.dpy, &libdecor_interface);
if (wl->libdecor_context)
{
RARCH_ERR("[Wayland]: Failed to crate libdecor frame\n");
goto error;
wl->libdecor_frame = wl->libdecor_decorate(wl->libdecor_context, wl->surface, &toplevel_listener->libdecor_frame_interface, wl);
if (!wl->libdecor_frame)
{
RARCH_ERR("[Wayland]: Failed to crate libdecor frame\n");
goto error;
}
wl->libdecor_frame_set_app_id(wl->libdecor_frame, "retroarch");
wl->libdecor_frame_set_title(wl->libdecor_frame, "RetroArch");
wl->libdecor_frame_map(wl->libdecor_frame);
}
libdecor_frame_set_app_id(wl->libdecor_frame, "retroarch");
libdecor_frame_set_title(wl->libdecor_frame, "RetroArch");
libdecor_frame_map(wl->libdecor_frame);
}
/* Waiting for libdecor to be configured before starting to draw */
wl_surface_commit(wl->surface);
wl->configured = true;
/* Waiting for libdecor to be configured before starting to draw */
wl_surface_commit(wl->surface);
wl->configured = true;
while (wl->configured)
{
if (libdecor_dispatch(wl->libdecor_context, 0) < 0)
while (wl->configured)
{
RARCH_ERR("[Wayland]: libdecor failed to dispatch\n");
goto error;
if (wl->libdecor_dispatch(wl->libdecor_context, 0) < 0)
{
RARCH_ERR("[Wayland]: libdecor failed to dispatch\n");
goto error;
}
}
}
#else
wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_shell, wl->surface);
xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
xdg_toplevel_add_listener(wl->xdg_toplevel, toplevel_listener, wl);
xdg_toplevel_set_app_id(wl->xdg_toplevel, "retroarch");
xdg_toplevel_set_title(wl->xdg_toplevel, "RetroArch");
if (wl->deco_manager)
wl->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(
wl->deco_manager, wl->xdg_toplevel);
/* Waiting for xdg_toplevel to be configured before starting to draw */
wl_surface_commit(wl->surface);
wl->configured = true;
while (wl->configured)
wl_display_dispatch(wl->input.dpy);
else
#endif
{
wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_shell, wl->surface);
xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
xdg_toplevel_add_listener(wl->xdg_toplevel, &toplevel_listener->xdg_toplevel_listener, wl);
xdg_toplevel_set_app_id(wl->xdg_toplevel, "retroarch");
xdg_toplevel_set_title(wl->xdg_toplevel, "RetroArch");
if (wl->deco_manager)
wl->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(
wl->deco_manager, wl->xdg_toplevel);
/* Waiting for xdg_toplevel to be configured before starting to draw */
wl_surface_commit(wl->surface);
wl->configured = true;
while (wl->configured)
wl_display_dispatch(wl->input.dpy);
}
wl_display_roundtrip(wl->input.dpy);
xdg_wm_base_add_listener(wl->xdg_shell, &xdg_shell_listener, NULL);
@ -443,10 +465,13 @@ bool gfx_ctx_wl_set_video_mode_common_size(gfx_ctx_wayland_data_t *wl,
wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale);
#ifdef HAVE_LIBDECOR
struct libdecor_state *state = libdecor_state_new(width, height);
libdecor_frame_commit(wl->libdecor_frame, state, NULL);
libdecor_state_free(state);
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
{
struct libdecor_state *state = wl->libdecor_state_new(width, height);
wl->libdecor_frame_commit(wl->libdecor_frame, state, NULL);
wl->libdecor_state_free(state);
}
#endif
return true;
@ -486,11 +511,14 @@ bool gfx_ctx_wl_set_video_mode_common_fullscreen(gfx_ctx_wayland_data_t *wl,
if (output == NULL)
RARCH_LOG("[Wayland] Failed to specify monitor for fullscreen, letting compositor decide\n");
#ifdef HAVE_LIBDECOR
libdecor_frame_set_fullscreen(wl->libdecor_frame, output);
#else
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, output);
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
wl->libdecor_frame_set_fullscreen(wl->libdecor_frame, output);
else
#endif
{
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, output);
}
}
flush_wayland_fd(&wl->input);
@ -589,10 +617,10 @@ static void shm_buffer_handle_release(void *data,
static void xdg_surface_handle_configure(void *data, struct xdg_surface *surface,
uint32_t serial)
{
xdg_surface_ack_configure(surface, serial);
xdg_surface_ack_configure(surface, serial);
}
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
static void libdecor_handle_error(struct libdecor *context,
enum libdecor_error error, const char *message)
{
@ -610,16 +638,16 @@ int create_shm_file(off_t size)
fd = memfd_create(SPLASH_SHM_NAME, MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd >= 0) {
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
do {
ret = posix_fallocate(fd, 0, size);
} while (ret == EINTR);
if (ret != 0) {
close(fd);
errno = ret;
fd = -1;
}
do {
ret = posix_fallocate(fd, 0, size);
} while (ret == EINTR);
if (ret != 0) {
close(fd);
errno = ret;
fd = -1;
}
}
if (fd < 0)
#endif
@ -747,7 +775,7 @@ const struct wl_buffer_listener shm_buffer_listener = {
shm_buffer_handle_release,
};
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
const struct libdecor_interface libdecor_interface = {
.error = libdecor_handle_error,
};

View File

@ -15,19 +15,18 @@
#pragma once
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
#include "../../input/common/wayland_common.h"
#ifdef HAVE_LIBDECOR
typedef struct libdecor_frame_interface toplevel_listener_t;
#else
typedef struct xdg_toplevel_listener toplevel_listener_t;
typedef struct toplevel_listener {
#ifdef HAVE_LIBDECOR_H
struct libdecor_frame_interface libdecor_frame_interface;
#endif
struct xdg_toplevel_listener xdg_toplevel_listener;
} toplevel_listener_t;
typedef struct shm_buffer {
struct wl_buffer *wl_buffer;
@ -41,7 +40,7 @@ void xdg_toplevel_handle_configure_common(gfx_ctx_wayland_data_t *wl, void *topl
void xdg_toplevel_handle_close(void *data,
struct xdg_toplevel *xdg_toplevel);
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
void libdecor_frame_handle_configure_common(struct libdecor_frame *frame,
struct libdecor_configuration *configuration, gfx_ctx_wayland_data_t *wl);
@ -63,7 +62,7 @@ bool gfx_ctx_wl_get_metrics_common(gfx_ctx_wayland_data_t *wl,
enum display_metric_types type, float *value);
bool gfx_ctx_wl_init_common(void *video_driver,
toplevel_listener_t **toplevel_listener,
const toplevel_listener_t *toplevel_listener,
gfx_ctx_wayland_data_t **wl);
bool gfx_ctx_wl_set_video_mode_common_size(gfx_ctx_wayland_data_t *wl,
@ -97,7 +96,7 @@ void shm_buffer_paint_checkerboard(shm_buffer_t *buffer,
bool draw_splash_screen(gfx_ctx_wayland_data_t *wl);
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
extern const struct libdecor_interface libdecor_interface;
#endif

View File

@ -134,7 +134,7 @@ static bool gfx_ctx_wl_get_metrics(void *data,
return gfx_ctx_wl_get_metrics_common(wl, type, value);
}
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
static void
libdecor_frame_handle_configure(struct libdecor_frame *frame,
struct libdecor_configuration *configuration, void *data)
@ -154,18 +154,24 @@ libdecor_frame_handle_configure(struct libdecor_frame *frame,
wl->configured = false;
}
#endif
static const toplevel_listener_t toplevel_listener = {
libdecor_frame_handle_configure,
libdecor_frame_handle_close,
libdecor_frame_handle_commit,
};
#else
static const toplevel_listener_t toplevel_listener = {
xdg_toplevel_handle_configure,
xdg_toplevel_handle_close,
};
#ifdef HAVE_LIBDECOR_H
.libdecor_frame_interface = {
libdecor_frame_handle_configure,
libdecor_frame_handle_close,
libdecor_frame_handle_commit,
},
#endif
.xdg_toplevel_listener = {
xdg_toplevel_handle_configure,
xdg_toplevel_handle_close,
},
};
static const toplevel_listener_t xdg_toplevel_listener = {
};
#ifdef HAVE_EGL
#define WL_EGL_ATTRIBS_BASE \

View File

@ -125,7 +125,7 @@ static bool gfx_ctx_wl_get_metrics(void *data,
return gfx_ctx_wl_get_metrics_common(wl, type, value);
}
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
static void
libdecor_frame_handle_configure(struct libdecor_frame *frame,
struct libdecor_configuration *configuration, void *data)
@ -135,18 +135,21 @@ libdecor_frame_handle_configure(struct libdecor_frame *frame,
wl->configured = false;
}
#endif
static const toplevel_listener_t toplevel_listener = {
libdecor_frame_handle_configure,
libdecor_frame_handle_close,
libdecor_frame_handle_commit,
};
#else
static const toplevel_listener_t toplevel_listener = {
xdg_toplevel_handle_configure,
xdg_toplevel_handle_close,
};
#ifdef HAVE_LIBDECOR_H
.libdecor_frame_interface = {
libdecor_frame_handle_configure,
libdecor_frame_handle_close,
libdecor_frame_handle_commit,
},
#endif
.xdg_toplevel_listener = {
xdg_toplevel_handle_configure,
xdg_toplevel_handle_close,
},
};
static void *gfx_ctx_wl_init(void *video_driver)
{

View File

@ -29,7 +29,7 @@
#include <string/stdstring.h>
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
@ -244,11 +244,14 @@ static void pointer_handle_button(void *data,
if (BIT_GET(wl->input.key_state, KEY_LEFTALT))
{
#ifdef HAVE_LIBDECOR
libdecor_frame_move(wl->libdecor_frame, wl->seat, serial);
#else
xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
wl->libdecor_frame_move(wl->libdecor_frame, wl->seat, serial);
else
#endif
{
xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
}
}
break;
case BTN_RIGHT:

View File

@ -13,8 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WAYLAND_INPUT_COMMON_H__
#define WAYLAND_INPUT_COMMON_H__
#pragma once
#include <stdint.h>
#include <boolean.h>
@ -52,6 +51,10 @@
(const char *) pos < ((const char *) (array)->data + (array)->size); \
(pos)++)
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
typedef struct
{
int16_t x;
@ -141,9 +144,14 @@ typedef struct gfx_ctx_wayland_data
struct wl_data_device_manager *data_device_manager;
struct wl_data_device *data_device;
data_offer_ctx *current_drag_offer;
#ifdef HAVE_LIBDECOR
#ifdef HAVE_LIBDECOR_H
struct libdecor *libdecor_context;
struct libdecor_frame *libdecor_frame;
#ifdef HAVE_DYNAMIC
struct dylib_t *libdecor;
#define RA_WAYLAND_SYM(rc,fn,params) rc (*fn) params;
#include "../../gfx/common/wayland/libdecor_sym.h"
#endif
#endif
struct zxdg_decoration_manager_v1 *deco_manager;
struct zxdg_toplevel_decoration_v1 *deco;
@ -220,5 +228,3 @@ extern const struct wl_buffer_listener shm_buffer_listener;
extern const struct wl_data_device_listener data_device_listener;
extern const struct wl_data_offer_listener data_offer_listener;
#endif