From 12d74c6ff6a382624e5941e8d186a67d7f719ec4 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Mon, 1 Oct 2018 15:05:55 +0200 Subject: [PATCH] Wayland: Add support for xdg-decoration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .travis.yml | 2 +- CMakeLists.txt | 2 +- src/CMakeLists.txt | 4 ++++ src/wl_init.c | 9 ++++++++ src/wl_platform.h | 4 ++++ src/wl_window.c | 56 ++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 68 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index f7ce408cd..804b8647a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,7 +65,7 @@ script: sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; git clone git://anongit.freedesktop.org/wayland/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; fi - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} .. diff --git a/CMakeLists.txt b/CMakeLists.txt index a0517db53..d46d36413 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,7 +262,7 @@ if (_GLFW_WAYLAND) find_package(Wayland REQUIRED Client Cursor Egl) find_package(WaylandScanner REQUIRED) - find_package(WaylandProtocols 1.12 REQUIRED) + find_package(WaylandProtocols 1.15 REQUIRED) list(APPEND glfw_PKG_DEPS "wayland-egl") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 22ce68f1b..d44000657 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,10 @@ elseif (_GLFW_WAYLAND) PROTOCOL "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml" 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 PROTOCOL "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml" diff --git a/src/wl_init.c b/src/wl_init.c index c14a099de..06531fbbf 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -758,6 +758,13 @@ static void registryHandleGlobal(void* data, wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); 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) { _glfw.wl.viewporter = @@ -1138,6 +1145,8 @@ void _glfwPlatformTerminate(void) wl_shell_destroy(_glfw.wl.shell); if (_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) xdg_wm_base_destroy(_glfw.wl.wmBase); if (_glfw.wl.pointer) diff --git a/src/wl_platform.h b/src/wl_platform.h index 108942416..2cf649693 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -57,6 +57,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "osmesa_context.h" #include "wayland-xdg-shell-client-protocol.h" +#include "wayland-xdg-decoration-client-protocol.h" #include "wayland-viewporter-client-protocol.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" @@ -185,6 +186,7 @@ typedef struct _GLFWwindowWayland struct { struct xdg_surface* surface; struct xdg_toplevel* toplevel; + struct zxdg_toplevel_decoration_v1* decoration; } xdg; _GLFWcursor* currentCursor; @@ -210,6 +212,7 @@ typedef struct _GLFWwindowWayland GLFWbool justCreated; struct { + GLFWbool serverSide; struct wl_buffer* buffer; _GLFWdecorationWayland top, left, right, bottom; int focus; @@ -231,6 +234,7 @@ typedef struct _GLFWlibraryWayland struct wl_pointer* pointer; struct wl_keyboard* keyboard; struct xdg_wm_base* wmBase; + struct zxdg_decoration_manager_v1* decorationManager; struct wp_viewporter* viewporter; struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_pointer_constraints_v1* pointerConstraints; diff --git a/src/wl_window.c b/src/wl_window.c index ef45baef5..c1d24f231 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -274,7 +274,7 @@ static void createDecorations(_GLFWwindow* window) const GLFWimage image = { 1, 1, data }; GLFWbool opaque = (data[3] == 255); - if (!_glfw.wl.viewporter) + if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide) return; if (!window->wl.decorations.buffer) @@ -321,6 +321,22 @@ static void destroyDecorations(_GLFWwindow* window) 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. static void setOpaqueRegion(_GLFWwindow* window) { @@ -493,9 +509,6 @@ static GLFWbool createSurface(_GLFWwindow* window, if (!window->wl.transparent) setOpaqueRegion(window); - if (window->decorated && !window->monitor) - createDecorations(window); - return GLFW_TRUE; } @@ -517,7 +530,8 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, monitor->wl.output); } setIdleInhibitor(window, GLFW_TRUE); - destroyDecorations(window); + if (!window->wl.decorations.serverSide) + destroyDecorations(window); } static GLFWbool createShellSurface(_GLFWwindow* window) @@ -553,11 +567,13 @@ static GLFWbool createShellSurface(_GLFWwindow* window) { wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); setIdleInhibitor(window, GLFW_FALSE); + createDecorations(window); } else { wl_shell_surface_set_toplevel(window->wl.shellSurface); setIdleInhibitor(window, GLFW_FALSE); + createDecorations(window); } wl_surface_commit(window->wl.surface); @@ -646,6 +662,27 @@ static const struct xdg_surface_listener xdgSurfaceListener = { 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) { 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); setIdleInhibitor(window, GLFW_FALSE); + setXdgDecorations(window); } else { setIdleInhibitor(window, GLFW_FALSE); + setXdgDecorations(window); } wl_surface_commit(window->wl.surface); @@ -946,6 +985,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) window->context.destroy(window); destroyDecorations(window); + if (window->wl.xdg.decoration) + zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); + if (window->wl.decorations.buffer) wl_buffer_destroy(window->wl.decorations.buffer); @@ -1061,7 +1103,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { - if (window->decorated && !window->monitor) + if (window->decorated && !window->monitor && !window->wl.decorations.serverSide) { if (top) *top = _GLFW_DECORATION_TOP; @@ -1190,7 +1232,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, else if (window->wl.shellSurface) wl_shell_surface_set_toplevel(window->wl.shellSurface); setIdleInhibitor(window, GLFW_FALSE); - if (window->decorated) + if (!_glfw.wl.decorationManager) createDecorations(window); } _glfwInputWindowMonitor(window, monitor);