From f11da7849ee0f496ee0769facaebca522f4c322a Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Fri, 11 Sep 2026 17:46:49 +0800 Subject: [PATCH] feat: add split menu support for wayland and xcb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add DClientManagement class for Wayland client management protocol 2. Implement showSplitMenu, hideSplitMenu, and supportSplitMenu functions 3. Add Wayland protocol binding for com_deepin_client_management interface 4. Implement XCB split menu via _WM_TOGGLE_SPLIT_MENU client messages 5. Register new function pointers in both Wayland and XCB hooks 6. Fix potential out-of-bounds read in supportForSplittingWindowByType 7. Add logging categories for split menu debugging 8. Update copyright year and CMake configuration for Wayland protocols Log: Added split menu support for window splitting feature Influence: 1. Test SplitMenu display when hovering over split button on XCB platform 2. Test SplitMenu display and hide on Wayland platform 3. Verify supportSplitMenu returns correct values based on window properties 4. Test menu positioning with different button rectangle coordinates 5. Verify menu hides properly with and without delay parameter 6. Test behavior when compositor does not support the protocol 7. Verify window switching triggers proper menu hide 8. Test edge cases with invalid window IDs and button rectangles feat: 为 Wayland 和 XCB 添加分屏菜单支持 1. 新增 DClientManagement 类用于 Wayland 客户端管理协议 2. 实现 showSplitMenu、hideSplitMenu 和 supportSplitMenu 函数 3. 添加 com_deepin_client_management 接口的 Wayland 协议绑定 4. 通过 _WM_TOGGLE_SPLIT_MENU 客户端消息实现 XCB 分屏菜单 5. 在 Wayland 和 XCB 钩子中注册新的函数指针 6. 修复 supportForSplittingWindowByType 中潜在的越界读取问题 7. 添加分屏菜单调试日志分类 8. 更新版权年份和 Wayland 协议的 CMake 配置 Log: 新增窗口分屏菜单功能 Influence: 1. 测试 XCB 平台下悬停分屏按钮时菜单的显示 2. 测试 Wayland 平台下分屏菜单的显示和隐藏 3. 验证 supportSplitMenu 根据窗口属性返回正确的值 4. 测试不同按钮矩形坐标下的菜单位置 5. 验证带延迟和不带延迟参数时菜单的正确隐藏 6. 测试合成器不支持该协议时的行为 7. 验证窗口切换时是否正确隐藏菜单 8. 测试无效窗口 ID 和按钮矩形的边界情况 PMS: BUG-370181 --- .../qt5platform-plugins-archlinux-build.yml | 2 +- archlinux/PKGBUILD | 2 +- debian/control | 1 + src/global.h | 3 + wayland/dwayland/CMakeLists.txt | 11 +- wayland/dwayland/dclientmanagement.cpp | 187 ++++++++++++++++++ wayland/dwayland/dclientmanagement.h | 56 ++++++ wayland/dwayland/dwaylandinterfacehook.cpp | 23 ++- wayland/dwayland/dwaylandinterfacehook.h | 4 + xcb/dplatformnativeinterfacehook.cpp | 5 +- xcb/utility.h | 3 + xcb/utility_x11.cpp | 71 ++++++- 12 files changed, 361 insertions(+), 7 deletions(-) create mode 100644 wayland/dwayland/dclientmanagement.cpp create mode 100644 wayland/dwayland/dclientmanagement.h diff --git a/.github/workflows/qt5platform-plugins-archlinux-build.yml b/.github/workflows/qt5platform-plugins-archlinux-build.yml index b6404e33..76c0fd6e 100644 --- a/.github/workflows/qt5platform-plugins-archlinux-build.yml +++ b/.github/workflows/qt5platform-plugins-archlinux-build.yml @@ -30,7 +30,7 @@ jobs: libxkbcommon libxkbcommon-x11 \ libxi libxrender libsm libice cairo \ dbus libglvnd fontconfig glib2 mtdev systemd \ - kwayland5 \ + kwayland5 deepin-wayland-protocols \ dtkcommon - uses: actions/checkout@v4 diff --git a/archlinux/PKGBUILD b/archlinux/PKGBUILD index 62a493fb..3345b787 100644 --- a/archlinux/PKGBUILD +++ b/archlinux/PKGBUILD @@ -12,7 +12,7 @@ license=('GPL3') provides=('deepin-qt5platform-plugins') conflicts=('deepin-qt5platform-plugins') depends=('cairo' 'qt5-wayland' 'qt5-x11extras' 'qt5-base' 'dwayland') -makedepends=('git' 'expac' 'qt5-xcb-private-headers' 'libglvnd' 'ninja' 'cmake' 'libxcb' 'gtest' 'gmock' 'extra-cmake-modules') +makedepends=('git' 'expac' 'qt5-xcb-private-headers' 'libglvnd' 'ninja' 'cmake' 'libxcb' 'gtest' 'gmock' 'extra-cmake-modules' 'deepin-wayland-protocols') groups=('deepin-git') source=("${sourcetars[@]}") sha512sums=('SKIP') diff --git a/debian/control b/debian/control index 8a8b2645..dddfc8f8 100644 --- a/debian/control +++ b/debian/control @@ -37,6 +37,7 @@ Build-Depends: debhelper-compat (= 12), libcairo2-dev, libkf5wayland-dev , libdwayland-dev , + deepin-wayland-protocols , libwayland-dev, libxcb-xinput-dev, libxcb-util-dev | libxcb-util0-dev, diff --git a/src/global.h b/src/global.h index 9ed8a42b..e5f03005 100644 --- a/src/global.h +++ b/src/global.h @@ -107,6 +107,9 @@ DEFINE_CONST_CHAR(supportForSplittingWindow); DEFINE_CONST_CHAR(sendEndStartupNotifition); DEFINE_CONST_CHAR(splitWindowOnScreenByType); DEFINE_CONST_CHAR(supportForSplittingWindowByType); +DEFINE_CONST_CHAR(supportSplitMenu); +DEFINE_CONST_CHAR(showSplitMenu); +DEFINE_CONST_CHAR(hideSplitMenu); // others DEFINE_CONST_CHAR(WmWindowTypes); diff --git a/wayland/dwayland/CMakeLists.txt b/wayland/dwayland/CMakeLists.txt index cb1c9ddc..ccc55d50 100644 --- a/wayland/dwayland/CMakeLists.txt +++ b/wayland/dwayland/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +# SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later @@ -12,11 +12,20 @@ endif() find_package(PkgConfig REQUIRED) pkg_check_modules(WAYLAND REQUIRED wayland-client wayland-cursor IMPORTED_TARGET) pkg_check_modules(X11 REQUIRED xkbcommon IMPORTED_TARGET) +find_package(ECM REQUIRED) +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH}) +find_package(WaylandScanner REQUIRED) +find_package(DeepinWaylandProtocols REQUIRED CONFIG) add_definitions(-DQT5DWAYLANDPLUGIN_LIBRARY -DQT_DEPRECATED_WARNINGS) include(${CMAKE_CURRENT_LIST_DIR}/dwayland.cmake) +ecm_add_wayland_client_protocol(wayland_SRC + PROTOCOL ${DEEPIN_WAYLAND_PROTOCOLS_DIR}/client-management.xml + BASENAME deepin-client-management +) + add_library(${PROJECT_NAME} MODULE main.cpp ${wayland_SRC}) target_compile_definitions(${PROJECT_NAME} diff --git a/wayland/dwayland/dclientmanagement.cpp b/wayland/dwayland/dclientmanagement.cpp new file mode 100644 index 00000000..07ac95ff --- /dev/null +++ b/wayland/dwayland/dclientmanagement.cpp @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "dclientmanagement.h" + +#include "dwaylandintegration.h" +#include "wayland-deepin-client-management-client-protocol.h" + +#define private public +#include +#undef private + +#include + +#include + +DPP_BEGIN_NAMESPACE + +#ifndef QT_DEBUG +Q_LOGGING_CATEGORY(lcWaylandSplitMenu, "dtk.qpa.wayland.splitmenu", QtInfoMsg) +#else +Q_LOGGING_CATEGORY(lcWaylandSplitMenu, "dtk.qpa.wayland.splitmenu") +#endif + +DClientManagement *DClientManagement::instance() +{ + static DClientManagement *management = new DClientManagement; + return management; +} + +bool DClientManagement::ensureBound() +{ + if (m_management) + return true; + + auto *display = DWaylandIntegration::instance()->display(); + if (!display) { + qCDebug(lcWaylandSplitMenu) << "Cannot bind client management without a Wayland display"; + return false; + } + + const auto globals = display->globals(); + for (const auto &global : globals) { + if (global.interface != QLatin1String("com_deepin_client_management")) + continue; + + m_management = static_cast( + wl_registry_bind(global.registry, global.id, + &com_deepin_client_management_interface, + qMin(global.version, 1u))); + if (!m_management) { + qCWarning(lcWaylandSplitMenu) << "Failed to bind com_deepin_client_management"; + return false; + } + + static const com_deepin_client_management_listener listener = { + DClientManagement::windowStates, + DClientManagement::windowFromPoint, + DClientManagement::allWindowId, + DClientManagement::specificWindowState, + }; + com_deepin_client_management_add_listener(m_management, &listener, this); + qCDebug(lcWaylandSplitMenu) << "Bound com_deepin_client_management, registry id:" + << global.id << "version:" << qMin(global.version, 1u); + return true; + } + + qCDebug(lcWaylandSplitMenu) << "com_deepin_client_management is not advertised"; + return false; +} + +bool DClientManagement::isValid() +{ + return ensureBound(); +} + +void DClientManagement::showSplitMenu(WId wid, const QRect &buttonRect) +{ + if (!wid || !buttonRect.isValid()) { + qCDebug(lcWaylandSplitMenu) << "Ignore invalid SplitMenu show request, wid:" << wid + << "button rect:" << buttonRect; + return; + } + + if (!ensureBound()) { + qCDebug(lcWaylandSplitMenu) << "Cannot show SplitMenu: client management is unavailable"; + return; + } + + m_pendingButtonRect = buttonRect; + m_showPending = true; + m_windowId = wid; + m_pendingRequests.enqueue(++m_requestSerial); + com_deepin_client_management_get_window_from_point(m_management); + wl_display_flush(DWaylandIntegration::instance()->display()->wl_display()); + qCDebug(lcWaylandSplitMenu) << "Requested window id for SplitMenu, Qt wid:" << wid + << "button rect:" << buttonRect; +} + +void DClientManagement::hideSplitMenu(WId wid, bool delay) +{ + if (!wid || wid != m_windowId) + return; + m_showPending = false; + ++m_requestSerial; + if (!ensureBound()) { + qCDebug(lcWaylandSplitMenu) << "Cannot hide SplitMenu: client management is unavailable"; + return; + } + + com_deepin_client_management_hide_split_menu(m_management, delay); + wl_display_flush(DWaylandIntegration::instance()->display()->wl_display()); + qCDebug(lcWaylandSplitMenu) << "Sent SplitMenu hide request, Qt wid:" << wid + << "delay:" << delay; +} + +void DClientManagement::handleWindowFromPoint(quint32 windowId) +{ + if (m_pendingRequests.isEmpty() || m_pendingRequests.dequeue() != m_requestSerial) + return; + if (!m_showPending || !windowId || !m_management) { + qCDebug(lcWaylandSplitMenu) << "Ignore window-from-point result, pending:" << m_showPending + << "window id:" << windowId + << "management valid:" << bool(m_management); + return; + } + + m_showPending = false; + com_deepin_client_management_show_split_menu( + m_management, + m_pendingButtonRect.x(), m_pendingButtonRect.y(), + m_pendingButtonRect.width(), m_pendingButtonRect.height(), + windowId); + wl_display_flush(DWaylandIntegration::instance()->display()->wl_display()); + qCDebug(lcWaylandSplitMenu) << "Sent SplitMenu show request, compositor window id:" + << windowId << "button rect:" << m_pendingButtonRect; +} + +void DClientManagement::windowStates(void *data, com_deepin_client_management *management, + quint32 count, wl_array *states) +{ + Q_UNUSED(data) + Q_UNUSED(management) + Q_UNUSED(count) + Q_UNUSED(states) +} + +void DClientManagement::windowFromPoint(void *data, com_deepin_client_management *management, + quint32 windowId) +{ + Q_UNUSED(management) + static_cast(data)->handleWindowFromPoint(windowId); +} + +void DClientManagement::allWindowId(void *data, com_deepin_client_management *management, + wl_array *idArray) +{ + Q_UNUSED(data) + Q_UNUSED(management) + Q_UNUSED(idArray) +} + +void DClientManagement::specificWindowState( + void *data, com_deepin_client_management *management, + qint32 pid, quint32 windowId, const char *resourceName, + qint32 x, qint32 y, qint32 width, qint32 height, + qint32 isMinimized, qint32 isFullscreen, qint32 isActive, + qint32 splitable, const char *uuid) +{ + Q_UNUSED(data) + Q_UNUSED(management) + Q_UNUSED(pid) + Q_UNUSED(windowId) + Q_UNUSED(resourceName) + Q_UNUSED(x) + Q_UNUSED(y) + Q_UNUSED(width) + Q_UNUSED(height) + Q_UNUSED(isMinimized) + Q_UNUSED(isFullscreen) + Q_UNUSED(isActive) + Q_UNUSED(splitable) + Q_UNUSED(uuid) +} + +DPP_END_NAMESPACE diff --git a/wayland/dwayland/dclientmanagement.h b/wayland/dwayland/dclientmanagement.h new file mode 100644 index 00000000..b2e572e0 --- /dev/null +++ b/wayland/dwayland/dclientmanagement.h @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DCLIENTMANAGEMENT_H +#define DCLIENTMANAGEMENT_H + +#include "global.h" + +#include +#include +#include + +struct com_deepin_client_management; +struct wl_array; + +DPP_BEGIN_NAMESPACE + +class DClientManagement +{ +public: + static DClientManagement *instance(); + + bool isValid(); + void showSplitMenu(WId wid, const QRect &buttonRect); + void hideSplitMenu(WId wid, bool delay); + +private: + DClientManagement() = default; + + bool ensureBound(); + void handleWindowFromPoint(quint32 windowId); + + static void windowStates(void *data, com_deepin_client_management *management, + quint32 count, wl_array *states); + static void windowFromPoint(void *data, com_deepin_client_management *management, + quint32 windowId); + static void allWindowId(void *data, com_deepin_client_management *management, + wl_array *idArray); + static void specificWindowState(void *data, com_deepin_client_management *management, + qint32 pid, quint32 windowId, const char *resourceName, + qint32 x, qint32 y, qint32 width, qint32 height, + qint32 isMinimized, qint32 isFullscreen, qint32 isActive, + qint32 splitable, const char *uuid); + + com_deepin_client_management *m_management = nullptr; + QRect m_pendingButtonRect; + bool m_showPending = false; + quint64 m_requestSerial = 0; + QQueue m_pendingRequests; + WId m_windowId = 0; +}; + +DPP_END_NAMESPACE + +#endif // DCLIENTMANAGEMENT_H diff --git a/wayland/dwayland/dwaylandinterfacehook.cpp b/wayland/dwayland/dwaylandinterfacehook.cpp index be7abec2..8cadf7b9 100755 --- a/wayland/dwayland/dwaylandinterfacehook.cpp +++ b/wayland/dwayland/dwaylandinterfacehook.cpp @@ -8,6 +8,7 @@ #include "dhighdpi.h" #include "dxsettings.h" #include "dnotitlebarwindowhelper_wl.h" +#include "dclientmanagement.h" #include #include @@ -46,7 +47,10 @@ static QFunctionPointer getFunction(const QByteArray &function) {splitWindowOnScreen, reinterpret_cast(&DWaylandInterfaceHook::splitWindowOnScreen)}, {supportForSplittingWindow, reinterpret_cast(&DWaylandInterfaceHook::supportForSplittingWindow)}, {splitWindowOnScreenByType, reinterpret_cast(&DWaylandInterfaceHook::splitWindowOnScreenByType)}, - {supportForSplittingWindowByType, reinterpret_cast(&DWaylandInterfaceHook::supportForSplittingWindowByType)} + {supportForSplittingWindowByType, reinterpret_cast(&DWaylandInterfaceHook::supportForSplittingWindowByType)}, + {supportSplitMenu, reinterpret_cast(&DWaylandInterfaceHook::supportSplitMenu)}, + {showSplitMenu, reinterpret_cast(&DWaylandInterfaceHook::showSplitMenu)}, + {hideSplitMenu, reinterpret_cast(&DWaylandInterfaceHook::hideSplitMenu)} }; return functionCache.value(function); } @@ -249,4 +253,21 @@ bool DWaylandInterfaceHook::supportForSplittingWindowByType(quint32 wid, quint32 return propertyValue >= 0 && static_cast(propertyValue) >= screenSplittingType; } +bool DWaylandInterfaceHook::supportSplitMenu(WId wid) +{ + auto *window = fromQtWinId(wid); + return window && window->handle() && supportForSplittingWindow(wid) + && DClientManagement::instance()->isValid(); +} + +void DWaylandInterfaceHook::showSplitMenu(WId wid, const QRect &buttonRect) +{ + DClientManagement::instance()->showSplitMenu(wid, buttonRect); +} + +void DWaylandInterfaceHook::hideSplitMenu(WId wid, bool delay) +{ + DClientManagement::instance()->hideSplitMenu(wid, delay); +} + DPP_END_NAMESPACE diff --git a/wayland/dwayland/dwaylandinterfacehook.h b/wayland/dwayland/dwaylandinterfacehook.h index 3ade8ae7..ae2762b6 100755 --- a/wayland/dwayland/dwaylandinterfacehook.h +++ b/wayland/dwayland/dwaylandinterfacehook.h @@ -14,6 +14,7 @@ QT_BEGIN_NAMESPACE class QObject; class QWindow; class QPointF; +class QRect; class QVariant; class QPlatformNativeInterface; QT_END_NAMESPACE @@ -55,6 +56,9 @@ class DWaylandInterfaceHook static void splitWindowOnScreenByType(WId wid, quint32 position, quint32 type); static bool supportForSplittingWindow(WId wid); static bool supportForSplittingWindowByType(quint32 wid, quint32 screenSplittingType); + static bool supportSplitMenu(WId wid); + static void showSplitMenu(WId wid, const QRect &buttonRect); + static void hideSplitMenu(WId wid, bool delay); }; DPP_END_NAMESPACE diff --git a/xcb/dplatformnativeinterfacehook.cpp b/xcb/dplatformnativeinterfacehook.cpp index d9af2ac3..85372787 100644 --- a/xcb/dplatformnativeinterfacehook.cpp +++ b/xcb/dplatformnativeinterfacehook.cpp @@ -79,7 +79,10 @@ static QFunctionPointer getFunction(const QByteArray &function) {supportForSplittingWindow, reinterpret_cast(&Utility::supportForSplittingWindow)}, {sendEndStartupNotifition, reinterpret_cast(&DPlatformIntegration::sendEndStartupNotifition)}, {splitWindowOnScreenByType, reinterpret_cast(&Utility::splitWindowOnScreenByType)}, - {supportForSplittingWindowByType, reinterpret_cast(&Utility::supportForSplittingWindowByType)} + {supportForSplittingWindowByType, reinterpret_cast(&Utility::supportForSplittingWindowByType)}, + {supportSplitMenu, reinterpret_cast(&Utility::supportSplitMenu)}, + {showSplitMenu, reinterpret_cast(&Utility::showSplitMenu)}, + {hideSplitMenu, reinterpret_cast(&Utility::hideSplitMenu)} }; return functionCache.value(function); diff --git a/xcb/utility.h b/xcb/utility.h index 6c93d717..010349f8 100644 --- a/xcb/utility.h +++ b/xcb/utility.h @@ -75,6 +75,9 @@ class Utility static void splitWindowOnScreenByType(quint32 WId, quint32 position, quint32 type); static bool supportForSplittingWindow(quint32 WId); static bool supportForSplittingWindowByType(quint32 WId, quint32 screenSplittingType); + static bool supportSplitMenu(WId wid); + static void showSplitMenu(WId wid, const QRect &buttonRect); + static void hideSplitMenu(WId wid, bool delay); struct BlurArea { qint32 x; diff --git a/xcb/utility_x11.cpp b/xcb/utility_x11.cpp index 06386bf0..b100a0de 100644 --- a/xcb/utility_x11.cpp +++ b/xcb/utility_x11.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #else @@ -48,6 +49,12 @@ QT_END_NAMESPACE DPP_BEGIN_NAMESPACE +#ifndef QT_DEBUG +Q_LOGGING_CATEGORY(lcDxcbSplitMenu, "dtk.qpa.dxcb.splitmenu", QtInfoMsg) +#else +Q_LOGGING_CATEGORY(lcDxcbSplitMenu, "dtk.qpa.dxcb.splitmenu") +#endif + QImage Utility::dropShadow(const QPixmap &px, qreal radius, const QColor &color) { if (px.isNull()) @@ -500,12 +507,72 @@ bool Utility::supportForSplittingWindowByType(quint32 WId, quint32 screenSplitti auto propAtom = internAtom("_DEEPIN_NET_SUPPORTED"); QByteArray data = windowProperty(WId, propAtom, XCB_ATOM_CARDINAL, 4); - if (const char *cdata = data.constData()) - return *(reinterpret_cast(cdata)) >= screenSplittingType; + if (!data.isEmpty()) + return static_cast(data.at(0)) >= screenSplittingType; return false; } +bool Utility::supportSplitMenu(WId wid) +{ + const bool hasToggleAtom = internAtom("_WM_TOGGLE_SPLIT_MENU", true) != XCB_ATOM_NONE; + const bool splitable = wid && supportForSplittingWindow(wid); + const bool supported = hasToggleAtom && splitable && DXcbWMSupport::instance()->hasComposite(); + qCDebug(lcDxcbSplitMenu) << "SplitMenu support check, wid:" << wid + << "toggle atom:" << hasToggleAtom + << "splitable:" << splitable + << "supported:" << supported; + return supported; +} + +void Utility::showSplitMenu(WId wid, const QRect &buttonRect) +{ + if (!wid || !buttonRect.isValid()) { + qCDebug(lcDxcbSplitMenu) << "Ignore invalid SplitMenu show request, wid:" << wid + << "button rect:" << buttonRect; + return; + } + + xcb_client_message_event_t event{}; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = internAtom("_WM_TOGGLE_SPLIT_MENU", false); + event.window = wid; + event.format = 32; + event.data.data32[0] = 1; + event.data.data32[1] = buttonRect.x(); + event.data.data32[2] = buttonRect.y(); + event.data.data32[3] = buttonRect.width(); + event.data.data32[4] = buttonRect.height(); + + xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()), + SubstructureNotifyMask, reinterpret_cast(&event)); + xcb_flush(QX11Info::connection()); + qCDebug(lcDxcbSplitMenu) << "Sent SplitMenu show request, wid:" << wid + << "button rect:" << buttonRect; +} + +void Utility::hideSplitMenu(WId wid, bool delay) +{ + if (!wid) { + qCDebug(lcDxcbSplitMenu) << "Ignore SplitMenu hide request without a window"; + return; + } + + xcb_client_message_event_t event{}; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = internAtom("_WM_TOGGLE_SPLIT_MENU", false); + event.window = wid; + event.format = 32; + event.data.data32[0] = 0; + event.data.data32[1] = delay; + + xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()), + SubstructureNotifyMask, reinterpret_cast(&event)); + xcb_flush(QX11Info::connection()); + qCDebug(lcDxcbSplitMenu) << "Sent SplitMenu hide request, wid:" << wid + << "delay:" << delay; +} + bool Utility::setEnableBlurWindow(const quint32 WId, bool enable) { if (!DXcbWMSupport::instance()->hasBlurWindow() || !DXcbWMSupport::instance()->isKwin())