Patch KDE to force serverside decoraations and full window frame

This commit is contained in:
Davíð Steinn Geirsson 2026-02-09 17:16:34 +00:00
parent ddbf16133e
commit 6722c0fbb4
3 changed files with 267 additions and 99 deletions

View file

@ -863,7 +863,7 @@ in
kfinal: kprev: {
kwin = kprev.kwin.overrideAttrs (old: {
patches = (old.patches or [ ]) ++ [
../patches/kde-decoration.patch
../patches/vmsilo-decorations-combined-v6.5.5.patch
];
});
}

View file

@ -1,98 +0,0 @@
From 9c102e0fa2e268dad187f0a882f8b2db5feb1967 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dav=C3=AD=C3=B0=20Steinn=20Geirsson?= <david@dsg.is>
Date: Sun, 8 Feb 2026 23:31:28 +0000
Subject: [PATCH] decorations: support vmsilo security context color override
Add support for changing window decoration colors based on Wayland
security context. When a window's security context has the format
"vmsilo:<vmname>:<color>", the decoration uses the specified color
for the frame and titlebar, with automatic contrast adjustment for
foreground text.
Windows without a security context or with non-vmsilo contexts
continue to use standard palette behavior.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---
src/decorations/decoratedwindow.cpp | 49 ++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/src/decorations/decoratedwindow.cpp b/src/decorations/decoratedwindow.cpp
index 74f799daa8..1cf52c647d 100644
--- a/src/decorations/decoratedwindow.cpp
+++ b/src/decorations/decoratedwindow.cpp
@@ -17,11 +17,32 @@
#include <KDecoration3/DecoratedWindow>
#include <KDecoration3/Decoration>
+#include "wayland/clientconnection.h"
+#include "wayland/surface.h"
+
#include <QDebug>
#include <QMenu>
#include <QStyle>
#include <QToolTip>
+namespace {
+QColor parseVmsiloColor(const QString &securityContextAppId)
+{
+ if (securityContextAppId.isEmpty() ||
+ !securityContextAppId.startsWith(QLatin1String("vmsilo:"))) {
+ return QColor();
+ }
+
+ const QStringList parts = securityContextAppId.split(QLatin1Char(':'));
+ if (parts.size() != 3) {
+ return QColor();
+ }
+
+ // parts[0] = "vmsilo", parts[1] = vmname, parts[2] = color
+ return QColor(parts[2]);
+}
+} // anonymous namespace
+
namespace KWin
{
namespace Decoration
@@ -192,11 +213,37 @@ void DecoratedWindowImpl::requestClose()
QColor DecoratedWindowImpl::color(KDecoration3::ColorGroup group, KDecoration3::ColorRole role) const
{
+ // Check for vmsilo security context color override
+ if (SurfaceInterface *surf = m_window->surface()) {
+ if (ClientConnection *client = surf->client()) {
+ const QColor vmsiloColor = parseVmsiloColor(client->securityContextAppId());
+ if (vmsiloColor.isValid()) {
+ switch (role) {
+ case KDecoration3::ColorRole::Frame:
+ case KDecoration3::ColorRole::TitleBar:
+ if (group == KDecoration3::ColorGroup::Inactive) {
+ return vmsiloColor.darker(120);
+ }
+ return vmsiloColor;
+ case KDecoration3::ColorRole::Foreground: {
+ // Calculate contrasting foreground color
+ const qreal luminance = 0.299 * vmsiloColor.redF()
+ + 0.587 * vmsiloColor.greenF()
+ + 0.114 * vmsiloColor.blueF();
+ return (luminance > 0.5) ? Qt::black : Qt::white;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // Fall back to standard palette behavior
auto dp = m_window->decorationPalette();
if (dp) {
return dp->color(group, role);
}
-
return QColor();
}
--
2.52.0

View file

@ -0,0 +1,266 @@
diff --git a/src/decorations/decoratedwindow.cpp b/src/decorations/decoratedwindow.cpp
index ff1a4ad245..300dd996cb 100644
--- a/src/decorations/decoratedwindow.cpp
+++ b/src/decorations/decoratedwindow.cpp
@@ -17,11 +17,32 @@
#include <KDecoration3/DecoratedWindow>
#include <KDecoration3/Decoration>
+#include "wayland/clientconnection.h"
+#include "wayland/surface.h"
+
#include <QDebug>
#include <QMenu>
#include <QStyle>
#include <QToolTip>
+namespace {
+QColor parseVmsiloColor(const QString &securityContextAppId)
+{
+ if (securityContextAppId.isEmpty() ||
+ !securityContextAppId.startsWith(QLatin1String("vmsilo:"))) {
+ return QColor();
+ }
+
+ const QStringList parts = securityContextAppId.split(QLatin1Char(':'));
+ if (parts.size() != 3) {
+ return QColor();
+ }
+
+ // parts[0] = "vmsilo", parts[1] = vmname, parts[2] = color
+ return QColor(parts[2]);
+}
+} // anonymous namespace
+
namespace KWin
{
namespace Decoration
@@ -187,11 +208,37 @@ void DecoratedWindowImpl::requestClose()
QColor DecoratedWindowImpl::color(KDecoration3::ColorGroup group, KDecoration3::ColorRole role) const
{
+ // Check for vmsilo security context color override
+ if (SurfaceInterface *surf = m_window->surface()) {
+ if (ClientConnection *client = surf->client()) {
+ const QColor vmsiloColor = parseVmsiloColor(client->securityContextAppId());
+ if (vmsiloColor.isValid()) {
+ switch (role) {
+ case KDecoration3::ColorRole::Frame:
+ case KDecoration3::ColorRole::TitleBar:
+ if (group == KDecoration3::ColorGroup::Inactive) {
+ return vmsiloColor.darker(120);
+ }
+ return vmsiloColor;
+ case KDecoration3::ColorRole::Foreground: {
+ // Calculate contrasting foreground color
+ const qreal luminance = 0.299 * vmsiloColor.redF()
+ + 0.587 * vmsiloColor.greenF()
+ + 0.114 * vmsiloColor.blueF();
+ return (luminance > 0.5) ? Qt::black : Qt::white;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // Fall back to standard palette behavior
auto dp = m_window->decorationPalette();
if (dp) {
return dp->color(group, role);
}
-
return QColor();
}
diff --git a/src/decorations/decorationbridge.cpp b/src/decorations/decorationbridge.cpp
index bde1d82b06..48726d0fc2 100644
--- a/src/decorations/decorationbridge.cpp
+++ b/src/decorations/decorationbridge.cpp
@@ -89,6 +89,10 @@ void DecorationBridge::init()
}
m_settings = std::make_shared<KDecoration3::DecorationSettings>(this);
+ m_pendingBorderSizeOverride = KDecoration3::BorderSize::Tiny;
+ m_vmsiloSettings = std::make_shared<KDecoration3::DecorationSettings>(this);
+ m_pendingBorderSizeOverride.reset();
+
const QString pluginId = readPlugin();
if (!initPlugin(pluginId)) {
if (s_defaultPlugin != pluginId) {
@@ -144,6 +148,7 @@ void DecorationBridge::reconfigure()
m_plugin = QString();
m_factory.reset();
m_settings.reset();
+ m_vmsiloSettings.reset();
} else {
// decorations enabled now
init();
@@ -212,7 +217,7 @@ std::unique_ptr<KDecoration3::DecoratedWindowPrivate> DecorationBridge::createCl
std::unique_ptr<KDecoration3::DecorationSettingsPrivate> DecorationBridge::settings(KDecoration3::DecorationSettings *parent)
{
- return std::unique_ptr<SettingsImpl>(new SettingsImpl(parent));
+ return std::make_unique<SettingsImpl>(parent, m_pendingBorderSizeOverride);
}
KDecoration3::Decoration *DecorationBridge::createDecoration(Window *window)
@@ -229,7 +234,11 @@ KDecoration3::Decoration *DecorationBridge::createDecoration(Window *window)
args.insert(QStringLiteral("theme"), m_theme);
}
auto deco = m_factory->create<KDecoration3::Decoration>(window, QVariantList{args});
- deco->setSettings(m_settings);
+ if (window->hasVmsiloSecurityContext()) {
+ deco->setSettings(m_vmsiloSettings);
+ } else {
+ deco->setSettings(m_settings);
+ }
deco->create();
deco->init();
return deco;
diff --git a/src/decorations/decorationbridge.h b/src/decorations/decorationbridge.h
index e06a131134..51c96dcd27 100644
--- a/src/decorations/decorationbridge.h
+++ b/src/decorations/decorationbridge.h
@@ -10,7 +10,9 @@
#include "kwin_export.h"
#include <KDecoration3/Private/DecorationBridge>
+#include <KDecoration3/DecorationSettings>
#include <QObject>
+#include <optional>
class KPluginFactory;
namespace KDecoration3
@@ -76,6 +78,8 @@ private:
QString m_defaultTheme;
QString m_theme;
std::shared_ptr<KDecoration3::DecorationSettings> m_settings;
+ std::shared_ptr<KDecoration3::DecorationSettings> m_vmsiloSettings;
+ std::optional<KDecoration3::BorderSize> m_pendingBorderSizeOverride;
bool m_noPlugin;
};
} // Decoration
diff --git a/src/decorations/settings.cpp b/src/decorations/settings.cpp
index 21b5bbf5cf..70f313d636 100644
--- a/src/decorations/settings.cpp
+++ b/src/decorations/settings.cpp
@@ -22,10 +22,12 @@ namespace KWin
{
namespace Decoration
{
-SettingsImpl::SettingsImpl(KDecoration3::DecorationSettings *parent)
+SettingsImpl::SettingsImpl(KDecoration3::DecorationSettings *parent,
+ std::optional<KDecoration3::BorderSize> borderSizeOverride)
: QObject()
, DecorationSettingsPrivate(parent)
, m_borderSize(KDecoration3::BorderSize::Normal)
+ , m_borderSizeOverride(borderSizeOverride)
{
readSettings();
diff --git a/src/decorations/settings.h b/src/decorations/settings.h
index 128bead161..e6e4e83b60 100644
--- a/src/decorations/settings.h
+++ b/src/decorations/settings.h
@@ -11,6 +11,7 @@
#include <KDecoration3/Private/DecorationSettingsPrivate>
#include <QObject>
+#include <optional>
class KConfigGroup;
@@ -23,14 +24,15 @@ class SettingsImpl : public QObject, public KDecoration3::DecorationSettingsPriv
{
Q_OBJECT
public:
- explicit SettingsImpl(KDecoration3::DecorationSettings *parent);
+ explicit SettingsImpl(KDecoration3::DecorationSettings *parent,
+ std::optional<KDecoration3::BorderSize> borderSizeOverride = std::nullopt);
~SettingsImpl() override;
bool isAlphaChannelSupported() const override;
bool isOnAllDesktopsAvailable() const override;
bool isCloseOnDoubleClickOnMenu() const override;
KDecoration3::BorderSize borderSize() const override
{
- return m_borderSize;
+ return m_borderSizeOverride.value_or(m_borderSize);
}
QList<KDecoration3::DecorationButtonType> decorationButtonsLeft() const override
{
@@ -53,6 +55,7 @@ private:
QList<KDecoration3::DecorationButtonType> m_leftButtons;
QList<KDecoration3::DecorationButtonType> m_rightButtons;
KDecoration3::BorderSize m_borderSize;
+ std::optional<KDecoration3::BorderSize> m_borderSizeOverride;
bool m_autoBorderSize = true;
bool m_closeDoubleClickMenu = false;
QFont m_font;
diff --git a/src/window.cpp b/src/window.cpp
index c4dd92c06f..e8f1901252 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -36,6 +36,7 @@
#include "useractions.h"
#include "virtualdesktops.h"
#include "wayland/output.h"
+#include "wayland/clientconnection.h"
#include "wayland/plasmawindowmanagement.h"
#include "wayland/surface.h"
#include "wayland_server.h"
@@ -4336,6 +4337,16 @@ bool Window::userCanSetNoBorder() const
return false;
}
+bool Window::hasVmsiloSecurityContext() const
+{
+ if (SurfaceInterface *surf = surface()) {
+ if (ClientConnection *client = surf->client()) {
+ return client->securityContextAppId().startsWith(QLatin1String("vmsilo:"));
+ }
+ }
+ return false;
+}
+
void Window::setNoBorder(bool set)
{
qCWarning(KWIN_CORE, "%s doesn't support setting decorations", metaObject()->className());
diff --git a/src/window.h b/src/window.h
index 2b11fa365c..fcf37d32bb 100644
--- a/src/window.h
+++ b/src/window.h
@@ -844,6 +844,8 @@ public:
SurfaceInterface *surface() const;
void setSurface(SurfaceInterface *surface);
+ bool hasVmsiloSecurityContext() const;
+
/**
* @returns Transformation to map from global to window coordinates.
*/
diff --git a/src/xdgshellwindow.cpp b/src/xdgshellwindow.cpp
index 092c284b8c..0439025636 100644
--- a/src/xdgshellwindow.cpp
+++ b/src/xdgshellwindow.cpp
@@ -694,6 +694,9 @@ bool XdgToplevelWindow::isTransient() const
bool XdgToplevelWindow::userCanSetNoBorder() const
{
+ if (hasVmsiloSecurityContext()) {
+ return false;
+ }
return (m_serverDecoration || m_xdgDecoration) && !isFullScreen();
}
@@ -704,6 +707,9 @@ bool XdgToplevelWindow::noBorder() const
void XdgToplevelWindow::setNoBorder(bool set)
{
+ if (hasVmsiloSecurityContext()) {
+ set = false;
+ }
set = rules()->checkNoBorder(set);
if (m_userNoBorder == set) {
return;