From 2fad37473f20406159dde6e43c3c24fa241686d7 Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Mon, 10 Feb 2020 00:59:44 +0000 Subject: [PATCH] wl: add decorations --- src/wl_init.c | 64 +++++++++-- src/wl_platform.h | 21 ++-- src/wl_window.c | 273 +++++++++++++++++++++++++++++++++------------- 3 files changed, 267 insertions(+), 91 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index d49e44e7..b6cdb39d 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -44,11 +44,14 @@ #include +const char *proxy_tag = "glfw-proxy"; + static inline int min(int n1, int n2) { return n1 < n2 ? n1 : n2; } +#ifndef WITH_DECORATION static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which) { @@ -56,7 +59,6 @@ static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, _GLFWwindow* window = _glfw.windowListHead; if (!which) which = &focus; -#ifndef WITH_DECORATION while (window) { if (surface == window->wl.decorations.top.surface) @@ -81,9 +83,22 @@ static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, } window = window->next; } -#endif return window; } +#endif + +#ifdef WITH_DECORATION +void decoration_error(struct libdecor *context, + enum libdecor_error error, + const char *message) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Caught error (%d): %s\n", error, message); +} + +static struct libdecor_interface decoration_interface = { + decoration_error, +}; +#endif static void pointerHandleEnter(void* data, struct wl_pointer* pointer, @@ -96,8 +111,16 @@ static void pointerHandleEnter(void* data, if (!surface) return; - int focus = 0; + if (wl_proxy_get_tag((struct wl_proxy *) surface) != &proxy_tag) + return; + _GLFWwindow* window = wl_surface_get_user_data(surface); + +#ifdef WITH_DECORATION + if (surface != window->wl.surface) + return; +#else + int focus = 0; if (!window) { window = findWindowFromDecorationSurface(surface, &focus); @@ -105,7 +128,6 @@ static void pointerHandleEnter(void* data, return; } -#ifndef WITH_DECORATION window->wl.decorations.focus = focus; #endif @@ -196,10 +218,16 @@ static void pointerHandleMotion(void* data, if (window->cursorMode == GLFW_CURSOR_DISABLED) return; + x = wl_fixed_to_double(sx); y = wl_fixed_to_double(sy); -#ifndef WITH_DECORATION +#ifdef WITH_DECORATION + window->wl.cursorPosX = x; + window->wl.cursorPosY = y; + _glfwInputCursorPos(window, x, y); + _glfw.wl.cursorPreviousName = NULL; +#else switch (window->wl.decorations.focus) { case mainWindow: @@ -251,11 +279,11 @@ static void pointerHandleButton(void* data, { _GLFWwindow* window = _glfw.wl.pointerFocus; int glfwButton; - uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE; if (!window) return; #ifndef WITH_DECORATION + uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE; if (button == BTN_LEFT) { switch (window->wl.decorations.focus) @@ -477,13 +505,21 @@ static void keyboardHandleEnter(void* data, if (!surface) return; + if (wl_proxy_get_tag((struct wl_proxy *) surface) != &proxy_tag) + return; + _GLFWwindow* window = wl_surface_get_user_data(surface); +#ifdef WITH_DECORATION + if (surface != window->wl.surface) + return; +#else if (!window) { window = findWindowFromDecorationSurface(surface, NULL); if (!window) return; } +#endif _glfw.wl.serial = serial; _glfw.wl.keyboardFocus = window; @@ -778,6 +814,7 @@ static const struct wl_data_device_listener dataDeviceListener = { dataDeviceHandleSelection, }; +#ifndef WITH_DECORATION static void wmBaseHandlePing(void* data, struct xdg_wm_base* wmBase, uint32_t serial) @@ -788,6 +825,7 @@ static void wmBaseHandlePing(void* data, static const struct xdg_wm_base_listener wmBaseListener = { wmBaseHandlePing }; +#endif static void registryHandleGlobal(void* data, struct wl_registry* registry, @@ -836,6 +874,7 @@ static void registryHandleGlobal(void* data, &wl_data_device_manager_interface, 1); } } +#ifndef WITH_DECORATION else if (strcmp(interface, "xdg_wm_base") == 0) { _glfw.wl.wmBase = @@ -849,7 +888,6 @@ static void registryHandleGlobal(void* data, &zxdg_decoration_manager_v1_interface, 1); } -#ifndef WITH_DECORATION else if (strcmp(interface, "wp_viewporter") == 0) { _glfw.wl.viewporter = @@ -1163,12 +1201,14 @@ int _glfwPlatformInit(void) if (_glfw.wl.seatVersion >= 4) _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); +#ifndef WITH_DECORATION if (!_glfw.wl.wmBase) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to find xdg-shell in your compositor"); return GLFW_FALSE; } +#endif if (_glfw.wl.pointer && _glfw.wl.shm) { @@ -1214,6 +1254,10 @@ int _glfwPlatformInit(void) _glfw.wl.clipboardSize = 4096; } +#ifdef WITH_DECORATION + _glfw.wl.csd_context = libdecor_new(_glfw.wl.display, &decoration_interface); +#endif + return GLFW_TRUE; } @@ -1260,14 +1304,16 @@ void _glfwPlatformTerminate(void) wl_compositor_destroy(_glfw.wl.compositor); if (_glfw.wl.shm) wl_shm_destroy(_glfw.wl.shm); -#ifndef WITH_DECORATION +#ifdef WITH_DECORATION + libdecor_unref(_glfw.wl.csd_context); +#else if (_glfw.wl.viewporter) wp_viewporter_destroy(_glfw.wl.viewporter); -#endif if (_glfw.wl.decorationManager) zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager); if (_glfw.wl.wmBase) xdg_wm_base_destroy(_glfw.wl.wmBase); +#endif if (_glfw.wl.dataSource) wl_data_source_destroy(_glfw.wl.dataSource); if (_glfw.wl.dataDevice) diff --git a/src/wl_platform.h b/src/wl_platform.h index 4591becb..b6b3392e 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -54,15 +54,18 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #endif #include "xkb_unicode.h" -#include "wayland-xdg-shell-client-protocol.h" -#include "wayland-xdg-decoration-client-protocol.h" -#ifndef WITH_DECORATION -#include "wayland-viewporter-client-protocol.h" -#endif #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" +#ifdef WITH_DECORATION +#include +#else +#include "wayland-xdg-shell-client-protocol.h" +#include "wayland-xdg-decoration-client-protocol.h" +#include "wayland-viewporter-client-protocol.h" +#endif + #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) @@ -181,11 +184,13 @@ typedef struct _GLFWwindowWayland struct wl_egl_window* native; struct wl_callback* callback; +#ifndef WITH_DECORATION struct { struct xdg_surface* surface; struct xdg_toplevel* toplevel; struct zxdg_toplevel_decoration_v1* decoration; } xdg; +#endif _GLFWcursor* currentCursor; double cursorPosX, cursorPosY; @@ -216,7 +221,7 @@ typedef struct _GLFWwindowWayland int focus; } decorations; #else - GLFWbool ssd; + struct libdecor_frame *decoration_frame; #endif } _GLFWwindowWayland; @@ -237,9 +242,11 @@ typedef struct _GLFWlibraryWayland struct wl_data_device* dataDevice; struct wl_data_offer* dataOffer; struct wl_data_source* dataSource; +#ifdef WITH_DECORATION + struct libdecor *csd_context; +#else struct xdg_wm_base* wmBase; struct zxdg_decoration_manager_v1* decorationManager; -#ifndef WITH_DECORATION struct wp_viewporter* viewporter; #endif struct zwp_relative_pointer_manager_v1* relativePointerManager; diff --git a/src/wl_window.c b/src/wl_window.c index 9e10e8a3..47cc1437 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -41,10 +41,12 @@ #include #ifdef WITH_DECORATION -#include +#include #endif +extern const char *proxy_tag; + static int createTmpfileCloexec(char* tmpname) { int fd; @@ -186,7 +188,61 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) return buffer; } -#ifndef WITH_DECORATION +#ifdef WITH_DECORATION +static void resizeWindow(_GLFWwindow* window); +void frame_configure(struct libdecor_frame *frame, struct libdecor_configuration *configuration, void *user_data) +{ + _GLFWwindow* window = user_data; + + int width, height; + if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) { + width = window->wl.width; + height = window->wl.height; + } + + window->wl.width = width; + window->wl.height = height; + resizeWindow(window); + + _glfwInputWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); + _glfwInputWindowDamage(window); + + struct libdecor_state *state = libdecor_state_new(width, height); + libdecor_frame_commit(frame, state, configuration); + libdecor_state_free(state); +} + +void frame_close(struct libdecor_frame *frame, void *user_data) +{ + _glfwInputWindowCloseRequest(user_data); +} + +void frame_commit(struct libdecor_frame *frame, void *user_data) +{ + _GLFWwindow* window = user_data; + + _glfwInputWindowDamage(window); +} + +static struct libdecor_frame_interface frame_interface = { + frame_configure, + frame_close, + frame_commit, +}; +#endif + +#ifdef WITH_DECORATION +static void createDecorations(_GLFWwindow* window) +{ + // TODO: enable decoration +} + +static void destroyDecorations(_GLFWwindow* window) +{ + // TODO: disable decoration +} +#else static void createDecoration(_GLFWdecorationWayland* decoration, struct wl_surface* parent, struct wl_buffer* buffer, GLFWbool opaque, @@ -216,14 +272,7 @@ static void createDecoration(_GLFWdecorationWayland* decoration, else wl_surface_commit(decoration->surface); } -#endif -#ifdef WITH_DECORATION -static void createDecorations(_GLFWwindow* window) -{ - // -} -#else static void createDecorations(_GLFWwindow* window) { unsigned char data[] = { 224, 224, 224, 255 }; @@ -255,9 +304,7 @@ static void createDecorations(_GLFWwindow* window) -_GLFW_DECORATION_WIDTH, window->wl.height, window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); } -#endif -#ifndef WITH_DECORATION static void destroyDecoration(_GLFWdecorationWayland* decoration) { if (decoration->subsurface) @@ -270,14 +317,7 @@ static void destroyDecoration(_GLFWdecorationWayland* decoration) decoration->subsurface = NULL; decoration->viewport = NULL; } -#endif -#ifdef WITH_DECORATION -static void destroyDecorations(_GLFWwindow* window) -{ - // -} -#else static void destroyDecorations(_GLFWwindow* window) { destroyDecoration(&window->wl.decorations.top); @@ -287,23 +327,21 @@ static void destroyDecorations(_GLFWwindow* window) } #endif +#ifndef WITH_DECORATION static void xdgDecorationHandleConfigure(void* data, struct zxdg_toplevel_decoration_v1* decoration, uint32_t mode) { _GLFWwindow* window = data; -#ifdef WITH_DECORATION - if (!(window->wl.ssd = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE))) -#else if (!(window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE))) -#endif createDecorations(window); } static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = { xdgDecorationHandleConfigure, }; +#endif // Makes the surface considered as XRGB instead of ARGB. static void setOpaqueRegion(_GLFWwindow* window) @@ -392,6 +430,9 @@ static void surfaceHandleEnter(void *data, struct wl_surface *surface, struct wl_output *output) { + if (wl_proxy_get_tag((struct wl_proxy *) output) != &proxy_tag) + return; + _GLFWwindow* window = data; _GLFWmonitor* monitor = wl_output_get_user_data(output); @@ -412,6 +453,9 @@ static void surfaceHandleLeave(void *data, struct wl_surface *surface, struct wl_output *output) { + if (wl_proxy_get_tag((struct wl_proxy *) output) != &proxy_tag) + return; + _GLFWwindow* window = data; _GLFWmonitor* monitor = wl_output_get_user_data(output); GLFWbool found; @@ -452,8 +496,7 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) } } -static GLFWbool createSurface(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) +static GLFWbool createSurface(_GLFWwindow* window) { window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); if (!window->wl.surface) @@ -464,41 +507,60 @@ static GLFWbool createSurface(_GLFWwindow* window, window); wl_surface_set_user_data(window->wl.surface, window); + wl_proxy_set_tag((struct wl_proxy *) window->wl.surface, &proxy_tag); + + wl_display_roundtrip(_glfw.wl.display); + wl_display_roundtrip(_glfw.wl.display); window->wl.native = wl_egl_window_create(window->wl.surface, - wndconfig->width, - wndconfig->height); + window->wl.width, + window->wl.height); if (!window->wl.native) return GLFW_FALSE; - window->wl.width = wndconfig->width; - window->wl.height = wndconfig->height; - window->wl.scale = 1; - if (!window->wl.transparent) setOpaqueRegion(window); return GLFW_TRUE; } +#ifdef WITH_DECORATION +static GLFWbool createSurfaceDecoration(_GLFWwindow* window) +{ + window->wl.decoration_frame = libdecor_decorate(_glfw.wl.csd_context, + window->wl.surface, + &frame_interface, + window); + libdecor_frame_map(window->wl.decoration_frame); + + window->wl.scale = 1; + + return GLFW_TRUE; +} +#endif + static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refreshRate) { +#ifdef WITH_DECORATION + libdecor_frame_set_fullscreen(window->wl.decoration_frame, monitor->wl.output); +#else if (window->wl.xdg.toplevel) { xdg_toplevel_set_fullscreen( window->wl.xdg.toplevel, monitor->wl.output); } - setIdleInhibitor(window, GLFW_TRUE); -#ifdef WITH_DECORATION - if (!window->wl.ssd) -#else - if (!window->wl.decorations.serverSide) #endif + setIdleInhibitor(window, GLFW_TRUE); +#ifndef WITH_DECORATION + if (!window->wl.decorations.serverSide) destroyDecorations(window); +#endif } +#ifndef WITH_DECORATION + static void xdgToplevelHandleConfigure(void* data, struct xdg_toplevel* toplevel, int32_t width, @@ -603,11 +665,7 @@ static void setXdgDecorations(_GLFWwindow* window) } else { -#ifdef WITH_DECORATION - window->wl.ssd = GLFW_FALSE; -#else window->wl.decorations.serverSide = GLFW_FALSE; -#endif createDecorations(window); } } @@ -672,6 +730,7 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) return GLFW_TRUE; } +#endif static void setCursorImage(_GLFWwindow* window, _GLFWcursorWayland* cursorWayland) @@ -825,7 +884,17 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, { window->wl.transparent = fbconfig->transparent; - if (!createSurface(window, wndconfig)) + window->wl.visible = wndconfig->visible; + window->wl.width = wndconfig->width; + window->wl.height = wndconfig->height; + + // TODO: enable visibility support + window->wl.visible = GLFW_TRUE; + + // unsupported on Wayland by design + window->focusOnShow = GLFW_FALSE; + + if (!createSurface(window)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) @@ -847,9 +916,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, } } - if (wndconfig->title) - window->wl.title = _glfw_strdup(wndconfig->title); - +#ifndef WITH_DECORATION if (wndconfig->visible) { if (!createXdgSurface(window)) @@ -863,6 +930,16 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, window->wl.xdg.toplevel = NULL; window->wl.visible = GLFW_FALSE; } +#else + if (!createSurfaceDecoration(window)) + return GLFW_FALSE; +#endif + + window->wl.scale = 1; + + _glfwPlatformSetWindowTitle(window, wndconfig->title); + + _glfwPlatformSetWindowResizable(window, wndconfig->resizable); if (window->monitor) setFullscreen(window, window->monitor, window->videoMode.refreshRate); @@ -873,6 +950,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, window->wl.monitorsCount = 0; window->wl.monitorsSize = 1; + wl_display_roundtrip(_glfw.wl.display); + return GLFW_TRUE; } @@ -896,9 +975,11 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) window->context.destroy(window); destroyDecorations(window); +#ifdef WITH_DECORATION + libdecor_frame_unref(window->wl.decoration_frame); +#else if (window->wl.xdg.decoration) zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); -#ifndef WITH_DECORATION if (window->wl.decorations.buffer) wl_buffer_destroy(window->wl.decorations.buffer); #endif @@ -906,11 +987,13 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->wl.native) wl_egl_window_destroy(window->wl.native); +#ifndef WITH_DECORATION if (window->wl.xdg.toplevel) xdg_toplevel_destroy(window->wl.xdg.toplevel); if (window->wl.xdg.surface) xdg_surface_destroy(window->wl.xdg.surface); +#endif if (window->wl.surface) wl_surface_destroy(window->wl.surface); @@ -924,8 +1007,15 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) if (window->wl.title) free(window->wl.title); window->wl.title = _glfw_strdup(title); - if (window->wl.xdg.toplevel) - xdg_toplevel_set_title(window->wl.xdg.toplevel, title); + +#ifdef WITH_DECORATION + if (window->wl.decoration_frame) { + libdecor_frame_set_title(window->wl.decoration_frame, window->wl.title); + libdecor_frame_set_app_id(window->wl.decoration_frame, window->wl.title); + } +#else + xdg_toplevel_set_title(window->wl.xdg.toplevel, title); +#endif } void _glfwPlatformSetWindowIcon(_GLFWwindow* window, @@ -971,16 +1061,23 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { + if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) + minwidth = minheight = 0; + if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) + maxwidth = maxheight = 0; +#ifdef WITH_DECORATION + libdecor_frame_set_min_content_size(window->wl.decoration_frame, + minwidth, minheight); + libdecor_frame_set_max_content_size(window->wl.decoration_frame, + maxwidth, maxheight); +#else if (window->wl.xdg.toplevel) { - if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) - minwidth = minheight = 0; - if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) - maxwidth = maxheight = 0; xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight); xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight); - wl_surface_commit(window->wl.surface); } +#endif + wl_surface_commit(window->wl.surface); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, @@ -1032,31 +1129,37 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, void _glfwPlatformIconifyWindow(_GLFWwindow* window) { - if (window->wl.xdg.toplevel) - xdg_toplevel_set_minimized(window->wl.xdg.toplevel); +#ifdef WITH_DECORATION + libdecor_frame_set_minimized(window->wl.decoration_frame); +#else + xdg_toplevel_set_minimized(window->wl.xdg.toplevel); +#endif } void _glfwPlatformRestoreWindow(_GLFWwindow* window) { - if (window->wl.xdg.toplevel) - { - if (window->monitor) - xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); - if (window->wl.maximized) - xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); - // There is no way to unset minimized, or even to know if we are - // minimized, so there is nothing to do in this case. - } +#ifdef WITH_DECORATION + libdecor_frame_unset_fullscreen(window->wl.decoration_frame); + libdecor_frame_unset_maximized(window->wl.decoration_frame); +#else + if (window->monitor) + xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); + if (window->wl.maximized) + xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); + // There is no way to unset minimized, or even to know if we are + // minimized, so there is nothing to do in this case. +#endif _glfwInputWindowMonitor(window, NULL); window->wl.maximized = GLFW_FALSE; } void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { - if (window->wl.xdg.toplevel) - { - xdg_toplevel_set_maximized(window->wl.xdg.toplevel); - } +#ifdef WITH_DECORATION + libdecor_frame_set_maximized(window->wl.decoration_frame); +#else + xdg_toplevel_set_maximized(window->wl.xdg.toplevel); +#endif window->wl.maximized = GLFW_TRUE; } @@ -1064,13 +1167,18 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) { if (!window->wl.visible) { - createXdgSurface(window); window->wl.visible = GLFW_TRUE; +#ifndef WITH_DECORATION + createXdgSurface(window); +#else + // TODO: enable visibility support +#endif } } void _glfwPlatformHideWindow(_GLFWwindow* window) { +#ifndef WITH_DECORATION if (window->wl.xdg.toplevel) { xdg_toplevel_destroy(window->wl.xdg.toplevel); @@ -1078,6 +1186,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) window->wl.xdg.toplevel = NULL; window->wl.xdg.surface = NULL; } +#else + // TODO: enable visibility support +#endif window->wl.visible = GLFW_FALSE; } @@ -1106,11 +1217,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, } else { - if (window->wl.xdg.toplevel) - xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); +#ifdef WITH_DECORATION + libdecor_frame_unset_fullscreen(window->wl.decoration_frame); +#else + xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); setIdleInhibitor(window, GLFW_FALSE); if (!_glfw.wl.decorationManager) createDecorations(window); +#endif } _glfwInputWindowMonitor(window, monitor); } @@ -1149,9 +1263,14 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { - // TODO - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Wayland: Window attribute setting not implemented yet"); +#ifdef WITH_DECORATION + if (enabled) + libdecor_frame_set_capabilities(window->wl.decoration_frame, + LIBDECOR_ACTION_RESIZE); + else + libdecor_frame_unset_capabilities(window->wl.decoration_frame, + LIBDECOR_ACTION_RESIZE); +#endif } void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) @@ -1167,9 +1286,13 @@ void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { - // TODO - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Wayland: Window attribute setting not implemented yet"); +#ifdef WITH_DECORATION + if (window->wl.maximized) + libdecor_frame_unset_maximized(window->wl.decoration_frame); + + if (window->wl.wasFullscreen) + libdecor_frame_unset_fullscreen(window->wl.decoration_frame); +#endif } void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled)