From 13b10f691d9c035921d4c41487e81bdc00182948 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 3 Oct 2018 12:27:51 +0530 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. --- glfw/source-info.json | 7 +++--- glfw/wl_init.c | 8 +++++++ glfw/wl_platform.h | 4 ++++ glfw/wl_window.c | 53 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/glfw/source-info.json b/glfw/source-info.json index 2f832403c..b4a8b8bcb 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -71,7 +71,8 @@ "stable/viewporter/viewporter.xml", "unstable/relative-pointer/relative-pointer-unstable-v1.xml", "unstable/pointer-constraints/pointer-constraints-unstable-v1.xml", - "unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" + "unstable/idle-inhibit/idle-inhibit-unstable-v1.xml", + "unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" ], "sources": [ "wl_init.c", @@ -91,7 +92,7 @@ }, "wayland_protocols": [ 1, - 12 + 15 ], "win32": { "headers": [ @@ -145,4 +146,4 @@ "null_joystick.c" ] } -} \ No newline at end of file +} diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 766bb5cb7..b622b0bf9 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -571,6 +571,12 @@ 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 = @@ -763,6 +769,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/glfw/wl_platform.h b/glfw/wl_platform.h index 347290f15..9f5ad0a35 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -56,6 +56,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-xdg-shell-client-protocol.h" #include "wayland-viewporter-client-protocol.h" +#include "wayland-xdg-decoration-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-idle-inhibit-unstable-v1-client-protocol.h" @@ -143,6 +144,7 @@ typedef struct _GLFWwindowWayland struct { struct xdg_surface* surface; struct xdg_toplevel* toplevel; + struct zxdg_toplevel_decoration_v1* decoration; } xdg; _GLFWcursor* currentCursor; @@ -169,6 +171,7 @@ typedef struct _GLFWwindowWayland GLFWbool justCreated; struct { + GLFWbool serverSide; struct wl_buffer* buffer; _GLFWdecorationWayland top, left, right, bottom; int focus; @@ -203,6 +206,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/glfw/wl_window.c b/glfw/wl_window.c index 62314a528..295afcfc6 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -272,7 +272,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) @@ -319,6 +319,20 @@ 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) { @@ -491,9 +505,6 @@ static GLFWbool createSurface(_GLFWwindow* window, if (!window->wl.transparent) setOpaqueRegion(window); - if (window->decorated && !window->monitor) - createDecorations(window); - return GLFW_TRUE; } @@ -514,7 +525,8 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refres monitor->wl.output); } setIdleInhibitor(window, GLFW_TRUE); - destroyDecorations(window); + if (!window->wl.decorations.serverSide) + destroyDecorations(window); } static GLFWbool createShellSurface(_GLFWwindow* window) @@ -550,11 +562,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); @@ -643,6 +657,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, @@ -690,10 +725,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); } if (strlen(window->wl.appId)) xdg_toplevel_set_app_id(window->wl.xdg.toplevel, window->wl.appId); @@ -914,6 +951,8 @@ 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); @@ -1027,7 +1066,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; @@ -1169,7 +1208,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);