use KDE server-decoration protocol for native Wayland frameless

Replace xdg-decoration (needs xdg_toplevel, GTK3 doesn't expose it)
with org_kde_kwin_server_decoration (works with wl_surface which
GDK provides). On KDE Wayland: binds the manager from the registry,
creates a per-surface decoration object, requests mode=None (0).
Falls back gracefully on GNOME (protocol not present, GTK's
set_decorated(FALSE) already works). X11 fallback via
gdk_window_set_decorations(0) unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 09:30:51 +02:00
co-authored by Claude Opus 4.6
parent a6b11a4cd8
commit db550d6829
5 changed files with 365 additions and 21 deletions
@@ -0,0 +1,240 @@
/* Generated by wayland-scanner 1.24.0 */
#ifndef SERVER_DECORATION_CLIENT_PROTOCOL_H
#define SERVER_DECORATION_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_server_decoration The server_decoration protocol
* @section page_ifaces_server_decoration Interfaces
* - @subpage page_iface_org_kde_kwin_server_decoration_manager -
* - @subpage page_iface_org_kde_kwin_server_decoration -
* @section page_copyright_server_decoration Copyright
* <pre>
*
* SPDX-FileCopyrightText: 2015 Martin Gräßlin
* SPDX-License-Identifier: LGPL-2.1-or-later
* </pre>
*/
struct org_kde_kwin_server_decoration;
struct org_kde_kwin_server_decoration_manager;
struct wl_surface;
#ifndef ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_INTERFACE
#define ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_INTERFACE
/**
* @page page_iface_org_kde_kwin_server_decoration_manager org_kde_kwin_server_decoration_manager
* @section page_iface_org_kde_kwin_server_decoration_manager_api API
* See @ref iface_org_kde_kwin_server_decoration_manager.
*/
/**
* @defgroup iface_org_kde_kwin_server_decoration_manager The org_kde_kwin_server_decoration_manager interface
*/
extern const struct wl_interface org_kde_kwin_server_decoration_manager_interface;
#endif
#ifndef ORG_KDE_KWIN_SERVER_DECORATION_INTERFACE
#define ORG_KDE_KWIN_SERVER_DECORATION_INTERFACE
/**
* @page page_iface_org_kde_kwin_server_decoration org_kde_kwin_server_decoration
* @section page_iface_org_kde_kwin_server_decoration_api API
* See @ref iface_org_kde_kwin_server_decoration.
*/
/**
* @defgroup iface_org_kde_kwin_server_decoration The org_kde_kwin_server_decoration interface
*/
extern const struct wl_interface org_kde_kwin_server_decoration_interface;
#endif
#ifndef ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_ENUM
#define ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_ENUM
enum org_kde_kwin_server_decoration_manager_mode {
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE = 0,
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT = 1,
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER = 2,
};
#endif /* ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_ENUM */
/**
* @ingroup iface_org_kde_kwin_server_decoration_manager
* @struct org_kde_kwin_server_decoration_manager_listener
*/
struct org_kde_kwin_server_decoration_manager_listener {
/**
*/
void (*default_mode)(void *data,
struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager,
uint32_t mode);
};
/**
* @ingroup iface_org_kde_kwin_server_decoration_manager
*/
static inline int
org_kde_kwin_server_decoration_manager_add_listener(struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager,
const struct org_kde_kwin_server_decoration_manager_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) org_kde_kwin_server_decoration_manager,
(void (**)(void)) listener, data);
}
#define ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_CREATE 0
/**
* @ingroup iface_org_kde_kwin_server_decoration_manager
*/
#define ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_DEFAULT_MODE_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_server_decoration_manager
*/
#define ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_CREATE_SINCE_VERSION 1
/** @ingroup iface_org_kde_kwin_server_decoration_manager */
static inline void
org_kde_kwin_server_decoration_manager_set_user_data(struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) org_kde_kwin_server_decoration_manager, user_data);
}
/** @ingroup iface_org_kde_kwin_server_decoration_manager */
static inline void *
org_kde_kwin_server_decoration_manager_get_user_data(struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager)
{
return wl_proxy_get_user_data((struct wl_proxy *) org_kde_kwin_server_decoration_manager);
}
static inline uint32_t
org_kde_kwin_server_decoration_manager_get_version(struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager)
{
return wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_server_decoration_manager);
}
/** @ingroup iface_org_kde_kwin_server_decoration_manager */
static inline void
org_kde_kwin_server_decoration_manager_destroy(struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager)
{
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_server_decoration_manager);
}
/**
* @ingroup iface_org_kde_kwin_server_decoration_manager
*/
static inline struct org_kde_kwin_server_decoration *
org_kde_kwin_server_decoration_manager_create(struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager, struct wl_surface *surface)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) org_kde_kwin_server_decoration_manager,
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_CREATE, &org_kde_kwin_server_decoration_interface, wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_server_decoration_manager), 0, NULL, surface);
return (struct org_kde_kwin_server_decoration *) id;
}
#ifndef ORG_KDE_KWIN_SERVER_DECORATION_MODE_ENUM
#define ORG_KDE_KWIN_SERVER_DECORATION_MODE_ENUM
enum org_kde_kwin_server_decoration_mode {
ORG_KDE_KWIN_SERVER_DECORATION_MODE_NONE = 0,
ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT = 1,
ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER = 2,
};
#endif /* ORG_KDE_KWIN_SERVER_DECORATION_MODE_ENUM */
/**
* @ingroup iface_org_kde_kwin_server_decoration
* @struct org_kde_kwin_server_decoration_listener
*/
struct org_kde_kwin_server_decoration_listener {
/**
*/
void (*mode)(void *data,
struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration,
uint32_t mode);
};
/**
* @ingroup iface_org_kde_kwin_server_decoration
*/
static inline int
org_kde_kwin_server_decoration_add_listener(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration,
const struct org_kde_kwin_server_decoration_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) org_kde_kwin_server_decoration,
(void (**)(void)) listener, data);
}
#define ORG_KDE_KWIN_SERVER_DECORATION_RELEASE 0
#define ORG_KDE_KWIN_SERVER_DECORATION_REQUEST_MODE 1
/**
* @ingroup iface_org_kde_kwin_server_decoration
*/
#define ORG_KDE_KWIN_SERVER_DECORATION_MODE_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_server_decoration
*/
#define ORG_KDE_KWIN_SERVER_DECORATION_RELEASE_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_server_decoration
*/
#define ORG_KDE_KWIN_SERVER_DECORATION_REQUEST_MODE_SINCE_VERSION 1
/** @ingroup iface_org_kde_kwin_server_decoration */
static inline void
org_kde_kwin_server_decoration_set_user_data(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) org_kde_kwin_server_decoration, user_data);
}
/** @ingroup iface_org_kde_kwin_server_decoration */
static inline void *
org_kde_kwin_server_decoration_get_user_data(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration)
{
return wl_proxy_get_user_data((struct wl_proxy *) org_kde_kwin_server_decoration);
}
static inline uint32_t
org_kde_kwin_server_decoration_get_version(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration)
{
return wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_server_decoration);
}
/** @ingroup iface_org_kde_kwin_server_decoration */
static inline void
org_kde_kwin_server_decoration_destroy(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration)
{
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_server_decoration);
}
/**
* @ingroup iface_org_kde_kwin_server_decoration
*/
static inline void
org_kde_kwin_server_decoration_release(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration)
{
wl_proxy_marshal_flags((struct wl_proxy *) org_kde_kwin_server_decoration,
ORG_KDE_KWIN_SERVER_DECORATION_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_server_decoration), WL_MARSHAL_FLAG_DESTROY);
}
/**
* @ingroup iface_org_kde_kwin_server_decoration
*/
static inline void
org_kde_kwin_server_decoration_request_mode(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration, uint32_t mode)
{
wl_proxy_marshal_flags((struct wl_proxy *) org_kde_kwin_server_decoration,
ORG_KDE_KWIN_SERVER_DECORATION_REQUEST_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_server_decoration), 0, mode);
}
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,60 @@
/* Generated by wayland-scanner 1.24.0 */
/*
* SPDX-FileCopyrightText: 2015 Martin Gräßlin
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface org_kde_kwin_server_decoration_interface;
extern const struct wl_interface wl_surface_interface;
static const struct wl_interface *server_decoration_types[] = {
NULL,
&org_kde_kwin_server_decoration_interface,
&wl_surface_interface,
};
static const struct wl_message org_kde_kwin_server_decoration_manager_requests[] = {
{ "create", "no", server_decoration_types + 1 },
};
static const struct wl_message org_kde_kwin_server_decoration_manager_events[] = {
{ "default_mode", "u", server_decoration_types + 0 },
};
WL_PRIVATE const struct wl_interface org_kde_kwin_server_decoration_manager_interface = {
"org_kde_kwin_server_decoration_manager", 1,
1, org_kde_kwin_server_decoration_manager_requests,
1, org_kde_kwin_server_decoration_manager_events,
};
static const struct wl_message org_kde_kwin_server_decoration_requests[] = {
{ "release", "", server_decoration_types + 0 },
{ "request_mode", "u", server_decoration_types + 0 },
};
static const struct wl_message org_kde_kwin_server_decoration_events[] = {
{ "mode", "u", server_decoration_types + 0 },
};
WL_PRIVATE const struct wl_interface org_kde_kwin_server_decoration_interface = {
"org_kde_kwin_server_decoration", 1,
2, org_kde_kwin_server_decoration_requests,
1, org_kde_kwin_server_decoration_events,
};
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="server_decoration">
<copyright><![CDATA[
SPDX-FileCopyrightText: 2015 Martin Gräßlin
SPDX-License-Identifier: LGPL-2.1-or-later
]]></copyright>
<interface name="org_kde_kwin_server_decoration_manager" version="1">
<request name="create">
<arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<enum name="mode">
<entry name="None" value="0"/>
<entry name="Client" value="1"/>
<entry name="Server" value="2"/>
</enum>
<event name="default_mode">
<arg name="mode" type="uint"/>
</event>
</interface>
<interface name="org_kde_kwin_server_decoration" version="1">
<request name="release" type="destructor"/>
<enum name="mode">
<entry name="None" value="0"/>
<entry name="Client" value="1"/>
<entry name="Server" value="2"/>
</enum>
<request name="request_mode">
<arg name="mode" type="uint"/>
</request>
<event name="mode">
<arg name="mode" type="uint"/>
</event>
</interface>
</protocol>