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:
@@ -6,6 +6,7 @@ add_executable(${BINARY_NAME}
|
||||
"main.cc"
|
||||
"my_application.cc"
|
||||
"protocols/xdg-decoration-unstable-v1-protocol.c"
|
||||
"protocols/server-decoration-protocol.c"
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <gdk/gdkwayland.h>
|
||||
#endif
|
||||
#ifdef HAS_WAYLAND_CLIENT
|
||||
#include "protocols/xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include "protocols/server-decoration-client-protocol.h"
|
||||
#endif
|
||||
|
||||
#include "flutter/generated_plugin_registrant.h"
|
||||
@@ -20,17 +20,18 @@ struct _MyApplication {
|
||||
|
||||
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||
|
||||
// D-057: xdg-decoration state.
|
||||
// D-057: KDE server-decoration protocol — request no decorations.
|
||||
#ifdef HAS_WAYLAND_CLIENT
|
||||
static struct zxdg_decoration_manager_v1* decoration_manager = nullptr;
|
||||
static struct org_kde_kwin_server_decoration_manager* kde_deco_manager = nullptr;
|
||||
|
||||
static void registry_handler(void* data, struct wl_registry* registry,
|
||||
uint32_t id, const char* interface,
|
||||
uint32_t version) {
|
||||
if (g_strcmp0(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
|
||||
decoration_manager = (struct zxdg_decoration_manager_v1*)
|
||||
if (g_strcmp0(interface,
|
||||
org_kde_kwin_server_decoration_manager_interface.name) == 0) {
|
||||
kde_deco_manager = (struct org_kde_kwin_server_decoration_manager*)
|
||||
wl_registry_bind(registry, id,
|
||||
&zxdg_decoration_manager_v1_interface, 1);
|
||||
&org_kde_kwin_server_decoration_manager_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,21 +41,31 @@ static void registry_remover(void* data, struct wl_registry* registry,
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
registry_handler, registry_remover};
|
||||
|
||||
static void request_client_side_decorations(GtkWindow* window) {
|
||||
static void kde_deco_default_mode(void* data,
|
||||
struct org_kde_kwin_server_decoration_manager* mgr, uint32_t mode) {}
|
||||
|
||||
static const struct org_kde_kwin_server_decoration_manager_listener
|
||||
kde_deco_manager_listener = {kde_deco_default_mode};
|
||||
|
||||
static void request_no_server_decorations(GtkWindow* window) {
|
||||
GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(window));
|
||||
if (!GDK_IS_WAYLAND_DISPLAY(display)) return;
|
||||
|
||||
struct wl_display* wl_display =
|
||||
struct wl_display* wl_dpy =
|
||||
gdk_wayland_display_get_wl_display(display);
|
||||
struct wl_registry* registry = wl_display_get_registry(wl_display);
|
||||
struct wl_registry* registry = wl_display_get_registry(wl_dpy);
|
||||
wl_registry_add_listener(registry, ®istry_listener, nullptr);
|
||||
wl_display_roundtrip(wl_display);
|
||||
wl_display_roundtrip(wl_dpy);
|
||||
|
||||
if (decoration_manager == nullptr) {
|
||||
if (kde_deco_manager == nullptr) {
|
||||
wl_registry_destroy(registry);
|
||||
return;
|
||||
}
|
||||
|
||||
org_kde_kwin_server_decoration_manager_add_listener(
|
||||
kde_deco_manager, &kde_deco_manager_listener, nullptr);
|
||||
wl_display_roundtrip(wl_dpy);
|
||||
|
||||
GdkWindow* gdk_win = gtk_widget_get_window(GTK_WIDGET(window));
|
||||
if (gdk_win == nullptr) {
|
||||
wl_registry_destroy(registry);
|
||||
@@ -67,17 +78,14 @@ static void request_client_side_decorations(GtkWindow* window) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct zxdg_toplevel_decoration_v1* toplevel_decoration =
|
||||
zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
decoration_manager, surface);
|
||||
|
||||
if (toplevel_decoration != nullptr) {
|
||||
zxdg_toplevel_decoration_v1_set_mode(
|
||||
toplevel_decoration,
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
|
||||
struct org_kde_kwin_server_decoration* deco =
|
||||
org_kde_kwin_server_decoration_manager_create(kde_deco_manager, surface);
|
||||
if (deco != nullptr) {
|
||||
// Mode 0 = None (no decorations at all)
|
||||
org_kde_kwin_server_decoration_request_mode(deco, 0);
|
||||
wl_display_roundtrip(wl_dpy);
|
||||
}
|
||||
|
||||
wl_display_roundtrip(wl_display);
|
||||
wl_registry_destroy(registry);
|
||||
}
|
||||
#endif
|
||||
@@ -88,7 +96,7 @@ static void on_window_realize(GtkWidget* widget, gpointer data) {
|
||||
gdk_window_set_decorations(gdk_win, (GdkWMDecoration)0);
|
||||
}
|
||||
#ifdef HAS_WAYLAND_CLIENT
|
||||
request_client_side_decorations(GTK_WINDOW(widget));
|
||||
request_no_server_decorations(GTK_WINDOW(widget));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user