From e0fed15ab7f521840d5416f034dd1a556b24b290 Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Mon, 2 Feb 2026 11:24:25 +0800 Subject: [PATCH] feat: add X11 WM_CLASS support for layer shell windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Added xcb-icccm dependency to CMakeLists.txt for X11 ICCCM support 2. Modified DLayerShellWindow to have empty default scope instead of "window" 3. Implemented onScopeChanged() method to set WM_CLASS property on X11 windows 4. Connected scopeChanged signal to update WM_CLASS when scope changes 5. WM_CLASS is set using both instance and class name from the scope property Log: Layer shell windows now set WM_CLASS property on X11 for better window identification Influence: 1. Test layer shell windows on X11 display server 2. Verify WM_CLASS property is correctly set using xprop tool 3. Test scope changes dynamically update WM_CLASS 4. Verify empty scope doesn't set WM_CLASS property 5. Test backward compatibility with existing layer shell windows 6. Verify window managers can properly identify layer shell windows by class feat: 为层壳窗口添加X11 WM_CLASS支持 1. 在CMakeLists.txt中添加xcb-icccm依赖以支持X11 ICCCM 2. 修改DLayerShellWindow的scope默认值为空而不是"window" 3. 实现onScopeChanged()方法为X11窗口设置WM_CLASS属性 4. 连接scopeChanged信号以便在scope变化时更新WM_CLASS 5. WM_CLASS使用scope属性同时作为实例名和类名进行设置 Log: 层壳窗口现在会在X11上设置WM_CLASS属性,便于窗口识别 Influence: 1. 在X11显示服务器上测试层壳窗口 2. 使用xprop工具验证WM_CLASS属性是否正确设置 3. 测试scope变化时WM_CLASS是否动态更新 4. 验证空scope不会设置WM_CLASS属性 5. 测试与现有层壳窗口的向后兼容性 6. 验证窗口管理器能否通过类名正确识别层壳窗口 --- frame/CMakeLists.txt | 2 +- frame/layershell/dlayershellwindow.cpp | 2 +- frame/layershell/x11dlayershellemulation.cpp | 37 ++++++++++++++++++-- frame/layershell/x11dlayershellemulation.h | 1 + 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/frame/CMakeLists.txt b/frame/CMakeLists.txt index 1f5fb57c1..69ece6b19 100644 --- a/frame/CMakeLists.txt +++ b/frame/CMakeLists.txt @@ -117,7 +117,7 @@ target_link_directories(dde-shell-frame INTERFACE if (BUILD_WITH_X11) target_compile_definitions(dde-shell-frame PRIVATE BUILD_WITH_X11) - pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb-ewmh xtst x11) + pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb-ewmh xcb-icccm xtst x11) target_sources(dde-shell-frame PRIVATE layershell/x11dlayershellemulation.h layershell/x11dlayershellemulation.cpp) target_link_libraries(dde-shell-frame PRIVATE PkgConfig::XCB) endif(BUILD_WITH_X11) diff --git a/frame/layershell/dlayershellwindow.cpp b/frame/layershell/dlayershellwindow.cpp index 66e16bb87..25a184c9c 100644 --- a/frame/layershell/dlayershellwindow.cpp +++ b/frame/layershell/dlayershellwindow.cpp @@ -30,7 +30,7 @@ class DLayerShellWindowPrivate } QWindow* parentWindow; - QString scope = QStringLiteral("window"); + QString scope; DLayerShellWindow::Anchors anchors = {DLayerShellWindow::AnchorNone}; int32_t exclusionZone = 0; DLayerShellWindow::KeyboardInteractivity keyboardInteractivity = DLayerShellWindow::KeyboardInteractivityNone; diff --git a/frame/layershell/x11dlayershellemulation.cpp b/frame/layershell/x11dlayershellemulation.cpp index d22e9a82c..c38280967 100644 --- a/frame/layershell/x11dlayershellemulation.cpp +++ b/frame/layershell/x11dlayershellemulation.cpp @@ -6,16 +6,17 @@ #include "dlayershellwindow.h" #include "x11dlayershellemulation.h" -#include -#include #include #include +#include +#include #include #include #include #include +#include DS_BEGIN_NAMESPACE @@ -66,6 +67,9 @@ LayerShellEmulation::LayerShellEmulation(QWindow* window, QObject *parent) connect(qApp, &QGuiApplication::screenRemoved, &m_exclusionZoneChangedTimer, static_cast(&QTimer::start)); + onScopeChanged(); + connect(m_dlayerShellWindow, &DLayerShellWindow::scopeChanged, this, &LayerShellEmulation::onScopeChanged); + // connect(m_dlayerShellWindow, &DS_NAMESPACE::DLayerShellWindow::keyboardInteractivityChanged, this, &LayerShellEmulation::onKeyboardInteractivityChanged); } @@ -272,6 +276,35 @@ void LayerShellEmulation::onExclusionZoneChanged() xcb_ewmh_set_wm_strut_partial(&ewmh_connection, m_window->winId(), strut_partial); } +void LayerShellEmulation::onScopeChanged() +{ + auto *x11Application = qGuiApp->nativeInterface(); + if (!x11Application || !m_window->winId()) { + return; + } + + QString instanceName = m_dlayerShellWindow->scope(); + if (instanceName.isEmpty()) { + // Don't set WM_CLASS for default scope, let X11 use its default behavior + return; + } + + // Set WM_CLASS property + // Format: instance_name\0class_name\0 + // - instance_name: scope value (e.g., "dock", "notification") + // - class_name: application binary name (e.g., "dde-shell") + QString className = QCoreApplication::applicationName(); + QByteArray wmClassData; + wmClassData.append(instanceName.toUtf8()); + wmClassData.append('\0'); + wmClassData.append(className.toUtf8()); + wmClassData.append('\0'); + + xcb_icccm_set_wm_class(x11Application->connection(), m_window->winId(), wmClassData.length(), wmClassData.constData()); + + qCDebug(layershell) << "Set WM_CLASS for window" << m_window->winId() << " wm_class:" << wmClassData; +} + // void X11Emulation::onKeyboardInteractivityChanged() // { // // kwin no implentation on wayland diff --git a/frame/layershell/x11dlayershellemulation.h b/frame/layershell/x11dlayershellemulation.h index 075445362..72aec4d9e 100644 --- a/frame/layershell/x11dlayershellemulation.h +++ b/frame/layershell/x11dlayershellemulation.h @@ -27,6 +27,7 @@ private slots: // margins or anchor changed void onPositionChanged(); void onExclusionZoneChanged(); + void onScopeChanged(); // void onKeyboardInteractivityChanged(); private: