Wayland: Add support for xdg-decoration

This allows compositors which prefer to draw the decorations around
clients to do so, rather than letting GLFW draw its own decorations.
The appearance is thus entirely subject to the compositor used, but
should generally be better than the current solid colour decorations we
have, which we continue to use when the compositor doesn’t support this
protocol or tells us to draw the decorations ourselves.

This new protocol has been tested against wlroots’s rootston compositor.

Fixes #1257.
This commit is contained in:
Emmanuel Gil Peyrot 2018-10-01 15:05:55 +02:00 committed by linkmauve
parent 3e884aea46
commit dcd2a19d90
6 changed files with 68 additions and 9 deletions

View File

@ -65,7 +65,7 @@ script:
sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb;
git clone git://anongit.freedesktop.org/wayland/wayland-protocols; git clone git://anongit.freedesktop.org/wayland/wayland-protocols;
pushd wayland-protocols; pushd wayland-protocols;
git checkout 1.12 && ./autogen.sh --prefix=/usr && make && sudo make install; git checkout 1.15 && ./autogen.sh --prefix=/usr && make && sudo make install;
popd; popd;
fi fi
- cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} .. - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} ..

View File

@ -262,7 +262,7 @@ if (_GLFW_WAYLAND)
find_package(Wayland REQUIRED Client Cursor Egl) find_package(Wayland REQUIRED Client Cursor Egl)
find_package(WaylandScanner REQUIRED) find_package(WaylandScanner REQUIRED)
find_package(WaylandProtocols 1.12 REQUIRED) find_package(WaylandProtocols 1.15 REQUIRED)
list(APPEND glfw_PKG_DEPS "wayland-egl") list(APPEND glfw_PKG_DEPS "wayland-egl")

View File

@ -35,6 +35,10 @@ elseif (_GLFW_WAYLAND)
PROTOCOL PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml" "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml"
BASENAME xdg-shell) BASENAME xdg-shell)
ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
BASENAME xdg-decoration)
ecm_add_wayland_client_protocol(glfw_SOURCES ecm_add_wayland_client_protocol(glfw_SOURCES
PROTOCOL PROTOCOL
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml" "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml"

View File

@ -758,6 +758,13 @@ static void registryHandleGlobal(void* data,
wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL); xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
} }
else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0)
{
_glfw.wl.decorationManager =
wl_registry_bind(registry, name,
&zxdg_decoration_manager_v1_interface,
1);
}
else if (strcmp(interface, "wp_viewporter") == 0) else if (strcmp(interface, "wp_viewporter") == 0)
{ {
_glfw.wl.viewporter = _glfw.wl.viewporter =
@ -1138,6 +1145,8 @@ void _glfwPlatformTerminate(void)
wl_shell_destroy(_glfw.wl.shell); wl_shell_destroy(_glfw.wl.shell);
if (_glfw.wl.viewporter) if (_glfw.wl.viewporter)
wp_viewporter_destroy(_glfw.wl.viewporter); wp_viewporter_destroy(_glfw.wl.viewporter);
if (_glfw.wl.decorationManager)
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
if (_glfw.wl.wmBase) if (_glfw.wl.wmBase)
xdg_wm_base_destroy(_glfw.wl.wmBase); xdg_wm_base_destroy(_glfw.wl.wmBase);
if (_glfw.wl.pointer) if (_glfw.wl.pointer)

View File

@ -57,6 +57,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#include "osmesa_context.h" #include "osmesa_context.h"
#include "wayland-xdg-shell-client-protocol.h" #include "wayland-xdg-shell-client-protocol.h"
#include "wayland-xdg-decoration-client-protocol.h"
#include "wayland-viewporter-client-protocol.h" #include "wayland-viewporter-client-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
@ -185,6 +186,7 @@ typedef struct _GLFWwindowWayland
struct { struct {
struct xdg_surface* surface; struct xdg_surface* surface;
struct xdg_toplevel* toplevel; struct xdg_toplevel* toplevel;
struct zxdg_toplevel_decoration_v1* decoration;
} xdg; } xdg;
_GLFWcursor* currentCursor; _GLFWcursor* currentCursor;
@ -210,6 +212,7 @@ typedef struct _GLFWwindowWayland
GLFWbool justCreated; GLFWbool justCreated;
struct { struct {
GLFWbool serverSide;
struct wl_buffer* buffer; struct wl_buffer* buffer;
_GLFWdecorationWayland top, left, right, bottom; _GLFWdecorationWayland top, left, right, bottom;
int focus; int focus;
@ -231,6 +234,7 @@ typedef struct _GLFWlibraryWayland
struct wl_pointer* pointer; struct wl_pointer* pointer;
struct wl_keyboard* keyboard; struct wl_keyboard* keyboard;
struct xdg_wm_base* wmBase; struct xdg_wm_base* wmBase;
struct zxdg_decoration_manager_v1* decorationManager;
struct wp_viewporter* viewporter; struct wp_viewporter* viewporter;
struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_relative_pointer_manager_v1* relativePointerManager;
struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_pointer_constraints_v1* pointerConstraints;

View File

@ -274,7 +274,7 @@ static void createDecorations(_GLFWwindow* window)
const GLFWimage image = { 1, 1, data }; const GLFWimage image = { 1, 1, data };
GLFWbool opaque = (data[3] == 255); GLFWbool opaque = (data[3] == 255);
if (!_glfw.wl.viewporter) if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide)
return; return;
if (!window->wl.decorations.buffer) if (!window->wl.decorations.buffer)
@ -321,6 +321,22 @@ static void destroyDecorations(_GLFWwindow* window)
destroyDecoration(&window->wl.decorations.bottom); destroyDecoration(&window->wl.decorations.bottom);
} }
static void xdgDecorationHandleConfigure(void* data,
struct zxdg_toplevel_decoration_v1* decoration,
uint32_t mode)
{
_GLFWwindow* window = data;
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
if (!window->wl.decorations.serverSide)
createDecorations(window);
}
static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {
xdgDecorationHandleConfigure,
};
// Makes the surface considered as XRGB instead of ARGB. // Makes the surface considered as XRGB instead of ARGB.
static void setOpaqueRegion(_GLFWwindow* window) static void setOpaqueRegion(_GLFWwindow* window)
{ {
@ -493,9 +509,6 @@ static GLFWbool createSurface(_GLFWwindow* window,
if (!window->wl.transparent) if (!window->wl.transparent)
setOpaqueRegion(window); setOpaqueRegion(window);
if (window->decorated && !window->monitor)
createDecorations(window);
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -517,7 +530,8 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,
monitor->wl.output); monitor->wl.output);
} }
setIdleInhibitor(window, GLFW_TRUE); setIdleInhibitor(window, GLFW_TRUE);
destroyDecorations(window); if (!window->wl.decorations.serverSide)
destroyDecorations(window);
} }
static GLFWbool createShellSurface(_GLFWwindow* window) static GLFWbool createShellSurface(_GLFWwindow* window)
@ -553,11 +567,13 @@ static GLFWbool createShellSurface(_GLFWwindow* window)
{ {
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
} }
else else
{ {
wl_shell_surface_set_toplevel(window->wl.shellSurface); wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
} }
wl_surface_commit(window->wl.surface); wl_surface_commit(window->wl.surface);
@ -646,6 +662,27 @@ static const struct xdg_surface_listener xdgSurfaceListener = {
xdgSurfaceHandleConfigure xdgSurfaceHandleConfigure
}; };
static void setXdgDecorations(_GLFWwindow* window)
{
if (_glfw.wl.decorationManager)
{
window->wl.xdg.decoration =
zxdg_decoration_manager_v1_get_toplevel_decoration(
_glfw.wl.decorationManager, window->wl.xdg.toplevel);
zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,
&xdgDecorationListener,
window);
zxdg_toplevel_decoration_v1_set_mode(
window->wl.xdg.decoration,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
else
{
window->wl.decorations.serverSide = GLFW_FALSE;
createDecorations(window);
}
}
static GLFWbool createXdgSurface(_GLFWwindow* window) static GLFWbool createXdgSurface(_GLFWwindow* window)
{ {
window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
@ -693,10 +730,12 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
{ {
xdg_toplevel_set_maximized(window->wl.xdg.toplevel); xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
setXdgDecorations(window);
} }
else else
{ {
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
setXdgDecorations(window);
} }
wl_surface_commit(window->wl.surface); wl_surface_commit(window->wl.surface);
@ -946,6 +985,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
window->context.destroy(window); window->context.destroy(window);
destroyDecorations(window); destroyDecorations(window);
if (window->wl.xdg.decoration)
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
if (window->wl.decorations.buffer) if (window->wl.decorations.buffer)
wl_buffer_destroy(window->wl.decorations.buffer); wl_buffer_destroy(window->wl.decorations.buffer);
@ -1061,7 +1103,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top, int* left, int* top,
int* right, int* bottom) int* right, int* bottom)
{ {
if (window->decorated && !window->monitor) if (window->decorated && !window->monitor && !window->wl.decorations.serverSide)
{ {
if (top) if (top)
*top = _GLFW_DECORATION_TOP; *top = _GLFW_DECORATION_TOP;
@ -1190,7 +1232,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
else if (window->wl.shellSurface) else if (window->wl.shellSurface)
wl_shell_surface_set_toplevel(window->wl.shellSurface); wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
if (window->decorated) if (!_glfw.wl.decorationManager)
createDecorations(window); createDecorations(window);
} }
_glfwInputWindowMonitor(window, monitor); _glfwInputWindowMonitor(window, monitor);