Commit a7fe8d18 authored by Olivier Fourdan's avatar Olivier Fourdan 🛠
Browse files

xwayland: add optional support for libdecor



When running rootful, the Xwayland window is not decorated (as all
Wayland surfaces), which makes it quite inconvenient to move on screen.

libdecor is "a client-side decorations library for Wayland clients"
which can be used precisely for adding decorations to Wayland surfaces.

Add optional support for libdecor in Xwayland to gain decorations when
running rootful and a new command line option "-decorate".

Signed-off-by: Olivier Fourdan's avatarOlivier Fourdan <ofourdan@redhat.com>
Closes: xorg/xserver#1332
parent c5e9d9b2
......@@ -46,6 +46,14 @@ Like all of the X servers, \fIXwayland\fP accepts the command line options
described in the \fIXserver\fP(@miscmansuffix@) manual page.
The following additional arguments are supported as well.
.TP 8
.B \-decorate
Add decorations to the Xwayland root window when running rootful.
This option has no effect when \fIXwayland\fP is built without libdecor
support (optional).
This option is not compatible with rootless mode (\fI-rootless\fP).
.TP 8
.B \-eglstream
Use EGLStream backend for NVidia GPUs. If \fIXwayland\fP was compiled with
EGLStream support, this option will instruct \fIXwayland\fP to try that
......
......@@ -128,6 +128,10 @@ if libdrm_dep.found()
xwayland_dep += libdrm_dep
endif
if have_libdecor
xwayland_dep += libdecor_dep
endif
xwayland_server = executable(
'Xwayland',
srcs,
......@@ -158,6 +162,7 @@ xwayland_data.set('PACKAGE_VERSION', meson.project_version())
xwayland_data.set('xwayland_path', xwayland_path)
xwayland_data.set('have_glamor', build_glamor ? 'true' : 'false')
xwayland_data.set('have_eglstream', build_eglstream ? 'true' : 'false')
xwayland_data.set('have_libdecor', have_libdecor ? 'true' : 'false')
configure_file(
input: 'xwayland.pc.in',
output: 'xwayland.pc',
......
......@@ -513,6 +513,33 @@ xwl_display_pollout (struct xwl_screen *xwl_screen, int timeout)
return xserver_poll(&poll_fd, 1, timeout);
}
#ifdef XWL_HAS_LIBDECOR
static void
xwl_dispatch_events_with_libdecor(struct xwl_screen *xwl_screen)
{
int ret = 0;
assert(!xwl_screen->rootless);
ret = libdecor_dispatch(xwl_screen->libdecor_context, 0);
if (ret == -1)
xwl_give_up("failed to dispatch Wayland events with libdecor: %s\n",
strerror(errno));
}
static void
handle_libdecor_error(struct libdecor *context,
enum libdecor_error error,
const char *message)
{
xwl_give_up("libdecor error (%d): %s\n", error, message);
}
static struct libdecor_interface libdecor_iface = {
.error = handle_libdecor_error,
};
#endif
static void
xwl_dispatch_events (struct xwl_screen *xwl_screen)
{
......@@ -551,7 +578,12 @@ socket_handler(int fd, int ready, void *data)
{
struct xwl_screen *xwl_screen = data;
xwl_read_events (xwl_screen);
#ifdef XWL_HAS_LIBDECOR
if (xwl_screen->libdecor_context)
xwl_dispatch_events_with_libdecor(xwl_screen);
else
#endif
xwl_read_events (xwl_screen);
}
static void
......@@ -565,14 +597,24 @@ block_handler(void *data, void *timeout)
struct xwl_screen *xwl_screen = data;
xwl_screen_post_damage(xwl_screen);
xwl_dispatch_events (xwl_screen);
#ifdef XWL_HAS_LIBDECOR
if (xwl_screen->libdecor_context)
xwl_dispatch_events_with_libdecor(xwl_screen);
else
#endif
xwl_dispatch_events (xwl_screen);
}
void
xwl_sync_events (struct xwl_screen *xwl_screen)
{
xwl_dispatch_events (xwl_screen);
xwl_read_events (xwl_screen);
#ifdef XWL_HAS_LIBDECOR
if (xwl_screen->libdecor_context)
xwl_dispatch_events_with_libdecor(xwl_screen);
else
#endif
xwl_read_events (xwl_screen);
}
void xwl_surface_damage(struct xwl_screen *xwl_screen,
......@@ -679,6 +721,13 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
xwl_screen->host_grab = 1;
xwl_screen->has_grab = 1;
}
else if (strcmp(argv[i], "-decorate") == 0) {
#ifdef XWL_HAS_LIBDECOR
xwl_screen->decorate = 1;
#else
ErrorF("This build does not have libdecor support\n");
#endif
}
}
if (use_fixed_size) {
......@@ -735,11 +784,17 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
&registry_listener, xwl_screen);
xwl_screen_roundtrip(xwl_screen);
if (xwl_screen->fullscreen && xwl_screen->rootless) {
ErrorF("error, cannot set fullscreen when running rootless\n");
return FALSE;
}
if (xwl_screen->fullscreen && xwl_screen->decorate) {
ErrorF("error, cannot use the decorate option when running fullscreen\n");
return FALSE;
}
if (xwl_screen->fullscreen && !xwl_screen_has_viewport_support(xwl_screen)) {
ErrorF("missing viewport support in the compositor, ignoring fullscreen\n");
xwl_screen->fullscreen = FALSE;
......@@ -786,7 +841,16 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
return FALSE;
#endif
xwl_screen->wayland_fd = wl_display_get_fd(xwl_screen->display);
#ifdef XWL_HAS_LIBDECOR
if (xwl_screen->decorate && !xwl_screen->rootless) {
xwl_screen->libdecor_context = libdecor_new(xwl_screen->display, &libdecor_iface);
xwl_screen->wayland_fd = libdecor_get_fd(xwl_screen->libdecor_context);
}
else
#endif
{
xwl_screen->wayland_fd = wl_display_get_fd(xwl_screen->display);
}
SetNotifyFd(xwl_screen->wayland_fd, socket_handler, X_NOTIFY_READ, xwl_screen);
RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, xwl_screen);
......
......@@ -38,6 +38,10 @@
#include "xwayland-glamor.h"
#include "xwayland-drm-lease.h"
#ifdef XWL_HAS_LIBDECOR
#include <libdecor.h>
#endif
struct xwl_format {
uint32_t format;
int num_modifiers;
......@@ -59,6 +63,7 @@ struct xwl_screen {
int fullscreen;
int host_grab;
int has_grab;
int decorate;
CreateScreenResourcesProcPtr CreateScreenResources;
CloseScreenProcPtr CloseScreen;
......@@ -121,6 +126,10 @@ struct xwl_screen {
/* The preferred GLVND vendor. If NULL, "mesa" is assumed. */
const char *glvnd_vendor;
#ifdef XWL_HAS_LIBDECOR
int libdecor_fd;
struct libdecor *libdecor_context;
#endif
};
/* Apps which use randr/vidmode to change the mode when going fullscreen,
......
......@@ -498,6 +498,11 @@ xwl_window_rootful_update_title(struct xwl_window *xwl_window)
snprintf(title, sizeof(title), "Xwayland on :%s%s", display, grab_message);
#ifdef XWL_HAS_LIBDECOR
if (xwl_window->libdecor_frame)
libdecor_frame_set_title(xwl_window->libdecor_frame, title);
else
#endif
if (xwl_window->xdg_toplevel)
xdg_toplevel_set_title(xwl_window->xdg_toplevel, title);
}
......@@ -507,10 +512,76 @@ xwl_window_rootful_set_app_id(struct xwl_window *xwl_window)
{
const char *app_id = "org.freedesktop.Xwayland";
#ifdef XWL_HAS_LIBDECOR
if (xwl_window->libdecor_frame)
libdecor_frame_set_app_id(xwl_window->libdecor_frame, app_id);
else
#endif
if (xwl_window->xdg_toplevel)
xdg_toplevel_set_app_id(xwl_window->xdg_toplevel, app_id);
}
#ifdef XWL_HAS_LIBDECOR
static void
xwl_window_update_libdecor_size(struct xwl_window *xwl_window, int width, int height)
{
struct libdecor_state *state;
if (xwl_window->libdecor_frame) {
state = libdecor_state_new((int) width, (int) height);
libdecor_frame_commit(xwl_window->libdecor_frame, state, NULL);
libdecor_state_free(state);
}
}
static void
handle_libdecor_configure(struct libdecor_frame *frame,
struct libdecor_configuration *configuration,
void *data)
{
struct xwl_window *xwl_window = data;
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
struct libdecor_state *state;
state = libdecor_state_new(xwl_screen->width, xwl_screen->height);
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
if (libdecor_frame_has_capability(frame, LIBDECOR_ACTION_RESIZE))
libdecor_frame_unset_capabilities(frame, LIBDECOR_ACTION_RESIZE);
}
static void
handle_libdecor_close(struct libdecor_frame *frame,
void *data)
{
DebugF("Terminating on compositor request");
GiveUp(0);
}
static void
handle_libdecor_commit(struct libdecor_frame *frame,
void *data)
{
struct xwl_window *xwl_window = data;
wl_surface_commit(xwl_window->surface);
}
static void
handle_libdecor_dismiss_popup(struct libdecor_frame *frame,
const char *seat_name,
void *data)
{
}
static struct libdecor_frame_interface libdecor_frame_iface = {
handle_libdecor_configure,
handle_libdecor_close,
handle_libdecor_commit,
handle_libdecor_dismiss_popup,
};
#endif
static void
xdg_surface_handle_configure(void *data,
struct xdg_surface *xdg_surface,
......@@ -591,29 +662,43 @@ xwl_create_root_surface(struct xwl_window *xwl_window)
WindowPtr window = xwl_window->window;
struct wl_region *region;
xwl_window->xdg_surface =
xdg_wm_base_get_xdg_surface(xwl_screen->xdg_wm_base, xwl_window->surface);
if (xwl_window->xdg_surface == NULL) {
ErrorF("Failed creating xdg_wm_base xdg_surface\n");
goto err_surf;
}
xwl_window->xdg_toplevel =
xdg_surface_get_toplevel(xwl_window->xdg_surface);
if (xwl_window->xdg_surface == NULL) {
ErrorF("Failed creating xdg_toplevel\n");
goto err_surf;
#ifdef XWL_HAS_LIBDECOR
if (xwl_screen->decorate) {
xwl_window->libdecor_frame =
libdecor_decorate(xwl_screen->libdecor_context,
xwl_window->surface,
&libdecor_frame_iface,
xwl_window);
libdecor_frame_map(xwl_window->libdecor_frame);
}
else
#endif
{
xwl_window->xdg_surface =
xdg_wm_base_get_xdg_surface(xwl_screen->xdg_wm_base, xwl_window->surface);
if (xwl_window->xdg_surface == NULL) {
ErrorF("Failed creating xdg_wm_base xdg_surface\n");
goto err_surf;
}
xwl_window->xdg_toplevel =
xdg_surface_get_toplevel(xwl_window->xdg_surface);
if (xwl_window->xdg_surface == NULL) {
ErrorF("Failed creating xdg_toplevel\n");
goto err_surf;
}
wl_surface_add_listener(xwl_window->surface,
&surface_listener, xwl_window);
wl_surface_add_listener(xwl_window->surface,
&surface_listener, xwl_window);
xdg_surface_add_listener(xwl_window->xdg_surface,
&xdg_surface_listener, xwl_window);
xdg_surface_add_listener(xwl_window->xdg_surface,
&xdg_surface_listener, xwl_window);
xdg_toplevel_add_listener(xwl_window->xdg_toplevel,
&xdg_toplevel_listener,
NULL);
xdg_toplevel_add_listener(xwl_window->xdg_toplevel,
&xdg_toplevel_listener,
NULL);
}
xwl_window_rootful_update_title(xwl_window);
xwl_window_rootful_set_app_id(xwl_window);
......@@ -908,8 +993,14 @@ xwl_resize_window(WindowPtr window,
xwl_screen->ResizeWindow = screen->ResizeWindow;
screen->ResizeWindow = xwl_resize_window;
if (xwl_window && (xwl_window_get(window) || xwl_window_is_toplevel(window)))
xwl_window_check_resolution_change_emulation(xwl_window);
if (xwl_window) {
if (xwl_window_get(window) || xwl_window_is_toplevel(window))
xwl_window_check_resolution_change_emulation(xwl_window);
#ifdef XWL_HAS_LIBDECOR
if (window == screen->root)
xwl_window_update_libdecor_size(xwl_window, width, height);
#endif
}
}
void
......
......@@ -58,6 +58,9 @@ struct xwl_window {
struct xorg_list frame_callback_list;
Bool present_flipped;
#endif
#ifdef XWL_HAS_LIBDECOR
struct libdecor_frame *libdecor_frame;
#endif
};
struct xwl_window *xwl_window_get(WindowPtr window);
......
......@@ -105,6 +105,9 @@ ddxUseMsg(void)
ErrorF("-verbose [n] verbose startup messages\n");
ErrorF("-version show the server version and exit\n");
ErrorF("-noTouchPointerEmulation disable touch pointer emulation\n");
#ifdef XWL_HAS_LIBDECOR
ErrorF("-decorate add decorations to Xwayland when rootful (experimental)\n");
#endif
}
static int init_fd = -1;
......@@ -236,6 +239,9 @@ ddxProcessArgument(int argc, char *argv[], int i)
else if (strcmp(argv[i], "-host-grab") == 0) {
return 1;
}
else if (strcmp(argv[i], "-decorate") == 0) {
return 1;
}
return 0;
}
......
......@@ -15,3 +15,4 @@ have_no_touch_pointer_emulation=true
have_geometry=true
have_fullscreen=true
have_host_grab=true
have_decorate=@have_libdecor@
......@@ -415,6 +415,7 @@ configure_file(output : 'xwin-config.h',
xwayland_data = configuration_data()
xwayland_data.set('XWL_HAS_GLAMOR', build_glamor and (gbm_dep.found() or build_eglstream) ? '1' : false)
xwayland_data.set('XWL_HAS_EGLSTREAM', build_eglstream ? '1' : false)
xwayland_data.set('XWL_HAS_LIBDECOR', have_libdecor ? '1' : false)
configure_file(output : 'xwayland-config.h',
input : 'xwayland-config.h.meson.in',
......
......@@ -9,3 +9,6 @@
/* Build eglstream support for Xwayland */
#mesondefine XWL_HAS_EGLSTREAM
/* Build Xwayland with libdecor support*/
#mesondefine XWL_HAS_LIBDECOR
......@@ -338,6 +338,21 @@ if build_glamor
epoxy_dep = dependency('epoxy', required: false)
endif
if build_xwayland
libdecor_dep = dependency('libdecor-0', required: false)
libdecor_option = get_option('libdecor')
if libdecor_option == 'auto'
have_libdecor = libdecor_dep.found()
else
have_libdecor = libdecor_option == 'true'
if have_libdecor and not libdecor_dep.found()
error('libdecor support requested but not found')
endif
endif
else
have_libdecor = false
endif
eglstream_option = get_option('xwayland_eglstream')
if build_xwayland and build_glamor
eglstream_dep = dependency('wayland-eglstream-protocols', required:false)
......
......@@ -129,6 +129,8 @@ option('libunwind', type: 'boolean', value: false,
description: 'Use libunwind for backtrace reporting')
option('xwayland-path', type: 'string', description: 'Directory containing Xwayland executable')
option('libdecor', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
description: 'Whether Xwayland should use libdecor when running rootful.')
option('docs', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
description: 'Build documentation')
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment