(Wayland) Add libdecor for client side decoration (#13397)

This commit is contained in:
Colin Kinloch 2021-12-24 13:20:45 +00:00 committed by GitHub
parent b67b93ebfe
commit f0392474f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 268 additions and 0 deletions

View File

@ -1264,6 +1264,12 @@ ifeq ($(HAVE_WAYLAND), 1)
DEF_FLAGS += $(WAYLAND_CFLAGS) $(WAYLAND_CURSOR_CFLAGS)
LIBS += $(WAYLAND_LIBS) $(WAYLAND_CURSOR_LIBS)
ifeq ($(HAVE_LIBDECOR), 1)
DEFINES += -DHAVE_LIBDECOR
LIBS += $(LIBDECOR_LIBS)
DEF_FLAGS += $(LIBDECOR_CFLAGS)
endif
endif
# XML

View File

@ -30,6 +30,10 @@
#include "../common/egl_common.h"
#endif
#ifdef HAVE_LIBDECOR
#include <libdecor.h>
#endif
#include "../../frontend/frontend_driver.h"
#include "../../input/common/wayland_common.h"
#include "../../input/input_driver.h"
@ -246,6 +250,11 @@ static void gfx_ctx_wl_update_title(void *data)
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])
{
if (wl->deco)
@ -255,6 +264,7 @@ static void gfx_ctx_wl_update_title(void *data)
}
xdg_toplevel_set_title(wl->xdg_toplevel, title);
}
#endif
}
static bool gfx_ctx_wl_get_metrics(void *data,
@ -287,6 +297,95 @@ static bool gfx_ctx_wl_get_metrics(void *data,
return true;
}
#ifdef HAVE_LIBDECOR
static void
handle_libdecor_error(struct libdecor *context,
enum libdecor_error error, const char *message)
{
RARCH_ERR("[Wayland]: libdecor Caught error (%d): %s\n", error, message);
}
static struct libdecor_interface libdecor_interface = {
.error = handle_libdecor_error,
};
static void
handle_libdecor_frame_configure(struct libdecor_frame *frame,
struct libdecor_configuration *configuration, void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
struct libdecor_state *state;
int width, height;
static const enum libdecor_window_state tiled_states = (
LIBDECOR_WINDOW_STATE_TILED_LEFT | LIBDECOR_WINDOW_STATE_TILED_RIGHT |
LIBDECOR_WINDOW_STATE_TILED_TOP | LIBDECOR_WINDOW_STATE_TILED_BOTTOM
);
enum libdecor_window_state window_state;
bool focused = false;
wl->fullscreen = false;
wl->maximized = false;
bool tiled = false;
if (libdecor_configuration_get_window_state(configuration, &window_state)) {
wl->fullscreen = (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;
wl->maximized = (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;
focused = (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
tiled = (window_state & tiled_states) != 0;
}
if (!libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = wl->prev_width;
height = wl->prev_height;
}
if (width > 0 && height > 0)
{
wl->prev_width = width;
wl->prev_height = height;
wl->width = width;
wl->height = height;
}
#ifdef HAVE_EGL
if (wl->win)
wl_egl_window_resize(wl->win, wl->width, wl->height, 0, 0);
else
wl->win = wl_egl_window_create(wl->surface,
wl->width * wl->buffer_scale,
wl->height * wl->buffer_scale);
#endif
state = libdecor_state_new(wl->width, wl->height);
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
wl->configured = false;
}
static void
handle_libdecor_frame_close(struct libdecor_frame *frame,
void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
command_event(CMD_EVENT_QUIT, NULL);
}
static void
handle_libdecor_frame_commit(struct libdecor_frame *frame,
void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
}
static struct libdecor_frame_interface libdecor_frame_interface = {
handle_libdecor_frame_configure,
handle_libdecor_frame_close,
handle_libdecor_frame_commit,
};
#endif
#define DEFAULT_WINDOWED_WIDTH 640
#define DEFAULT_WINDOWED_HEIGHT 480
@ -594,6 +693,30 @@ static bool gfx_ctx_wl_set_video_mode(void *data,
wl->win = wl_egl_window_create(wl->surface, wl->width * wl->buffer_scale, wl->height * wl->buffer_scale);
#endif
#ifdef HAVE_LIBDECOR
wl->libdecor_context = libdecor_new(wl->input.dpy, &libdecor_interface);
if (wl->libdecor_context) {
wl->libdecor_frame = libdecor_decorate(wl->libdecor_context, wl->surface, &libdecor_frame_interface, wl);
if (wl->libdecor_frame == NULL) {
RARCH_ERR("[Wayland]: Failed to crate libdecor frame\n");
goto error;
} else {
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;
while (wl->configured)
if (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);
@ -615,6 +738,7 @@ static bool gfx_ctx_wl_set_video_mode(void *data,
while (wl->configured)
wl_display_dispatch(wl->input.dpy);
#endif
wl_display_roundtrip(wl->input.dpy);
xdg_wm_base_add_listener(wl->xdg_shell, &xdg_shell_listener, NULL);
@ -634,7 +758,11 @@ static bool gfx_ctx_wl_set_video_mode(void *data,
if (fullscreen)
{
#ifdef HAVE_LIBDECOR
libdecor_frame_set_fullscreen(wl->libdecor_frame, NULL);
#else
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
#endif
}
flush_wayland_fd(&wl->input);

View File

@ -25,6 +25,10 @@
#include "../../config.h"
#endif
#ifdef HAVE_LIBDECOR
#include <libdecor.h>
#endif
#include "../common/vulkan_common.h"
#include "../../frontend/frontend_driver.h"
@ -238,6 +242,11 @@ static void gfx_ctx_wl_update_title(void *data)
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])
{
if (wl->deco)
@ -248,6 +257,7 @@ static void gfx_ctx_wl_update_title(void *data)
xdg_toplevel_set_title(wl->xdg_toplevel, title);
}
#endif
}
static bool gfx_ctx_wl_get_metrics(void *data,
@ -280,6 +290,86 @@ static bool gfx_ctx_wl_get_metrics(void *data,
return true;
}
#ifdef HAVE_LIBDECOR
static void
handle_libdecor_error(struct libdecor *context,
enum libdecor_error error, const char *message)
{
RARCH_ERR("[Wayland/Vulkan]: libdecor Caught error (%d): %s\n", error, message);
}
static struct libdecor_interface libdecor_interface = {
.error = handle_libdecor_error,
};
static void
handle_libdecor_frame_configure(struct libdecor_frame *frame,
struct libdecor_configuration *configuration, void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
struct libdecor_state *state;
int width, height;
static const enum libdecor_window_state tiled_states = (
LIBDECOR_WINDOW_STATE_TILED_LEFT | LIBDECOR_WINDOW_STATE_TILED_RIGHT |
LIBDECOR_WINDOW_STATE_TILED_TOP | LIBDECOR_WINDOW_STATE_TILED_BOTTOM
);
enum libdecor_window_state window_state;
bool focused = false;
wl->fullscreen = false;
wl->maximized = false;
bool tiled = false;
if (libdecor_configuration_get_window_state(configuration, &window_state)) {
wl->fullscreen = (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;
wl->maximized = (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;
focused = (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
tiled = (window_state & tiled_states) != 0;
}
if (!libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = wl->prev_width;
height = wl->prev_height;
}
if (width > 0 && height > 0)
{
wl->prev_width = width;
wl->prev_height = height;
wl->width = width;
wl->height = height;
}
state = libdecor_state_new(wl->width, wl->height);
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
wl->configured = false;
}
static void
handle_libdecor_frame_close(struct libdecor_frame *frame,
void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
command_event(CMD_EVENT_QUIT, NULL);
}
static void
handle_libdecor_frame_commit(struct libdecor_frame *frame,
void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
}
static struct libdecor_frame_interface libdecor_frame_interface = {
handle_libdecor_frame_configure,
handle_libdecor_frame_close,
handle_libdecor_frame_commit,
};
#endif
#define DEFAULT_WINDOWED_WIDTH 640
#define DEFAULT_WINDOWED_HEIGHT 480
@ -420,6 +510,30 @@ static bool gfx_ctx_wl_set_video_mode(void *data,
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) {
wl->libdecor_frame = libdecor_decorate(wl->libdecor_context, wl->surface, &libdecor_frame_interface, wl);
if (wl->libdecor_frame == NULL) {
RARCH_ERR("[Wayland/Vulkan]: Failed to crate libdecor frame\n");
goto error;
} else {
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;
while (wl->configured)
if (libdecor_dispatch(wl->libdecor_context, 0) < 0) {
RARCH_ERR("[Wayland/Vulkan]: 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);
@ -441,13 +555,18 @@ static bool gfx_ctx_wl_set_video_mode(void *data,
while (wl->configured)
wl_display_dispatch(wl->input.dpy);
#endif
wl_display_roundtrip(wl->input.dpy);
xdg_wm_base_add_listener(wl->xdg_shell, &xdg_shell_listener, NULL);
if (fullscreen)
{
#ifdef HAVE_LIBDECOR
libdecor_frame_set_fullscreen(wl->libdecor_frame, NULL);
#else
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
#endif
}
flush_wayland_fd(&wl->input);

View File

@ -21,6 +21,10 @@
#include <string/stdstring.h>
#ifdef HAVE_LIBDECOR
#include <libdecor.h>
#endif
#include "wayland_common.h"
#include "../input_keymaps.h"
@ -208,7 +212,11 @@ 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);
#endif
}
break;
case BTN_RIGHT:

View File

@ -126,6 +126,10 @@ typedef struct gfx_ctx_wayland_data
struct wl_touch *wl_touch;
struct wl_seat *seat;
struct wl_shm *shm;
#ifdef HAVE_LIBDECOR
struct libdecor *libdecor_context;
struct libdecor_frame *libdecor_frame;
#endif
struct zxdg_decoration_manager_v1 *deco_manager;
struct zxdg_toplevel_decoration_v1 *deco;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;

View File

@ -534,6 +534,8 @@ if [ "$HAVE_WAYLAND_SCANNER" = yes ] &&
-p "$HAVE_WAYLAND_PROTOS" \
-s "$SHARE_DIR" ||
die 1 'Error: Failed generating wayland protocols.'
check_pkgconf LIBDECOR libdecor-0
else
die : 'Notice: wayland libraries not found, disabling wayland support.'
HAVE_WAYLAND='no'

View File

@ -97,6 +97,7 @@ HAVE_EXYNOS=no # Exynos video support
HAVE_DISPMANX=no # Dispmanx video support
HAVE_SUNXI=no # Sunxi video support
HAVE_WAYLAND=auto # Wayland support
HAVE_LIBDECOR=auto # libdecor support
C89_WAYLAND=no
CXX_WAYLAND=no
HAVE_DYNAMIC_EGL=no # Dynamic library EGL support