Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/qt5platform-plugins-archlinux-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion archlinux/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Build-Depends: debhelper-compat (= 12),
libcairo2-dev,
libkf5wayland-dev <!nodtk5>,
libdwayland-dev <!nodtk5>,
deepin-wayland-protocols <!nodtk5>,
libwayland-dev,
libxcb-xinput-dev,
libxcb-util-dev | libxcb-util0-dev,
Expand Down
3 changes: 3 additions & 0 deletions src/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 10 additions & 1 deletion wayland/dwayland/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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}
Expand Down
187 changes: 187 additions & 0 deletions wayland/dwayland/dclientmanagement.cpp
Original file line number Diff line number Diff line change
@@ -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 <QtWaylandClient/private/qwaylanddisplay_p.h>
#undef private

#include <QLoggingCategory>

#include <wayland-client-core.h>

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<com_deepin_client_management *>(
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<DClientManagement *>(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
56 changes: 56 additions & 0 deletions wayland/dwayland/dclientmanagement.h
Original file line number Diff line number Diff line change
@@ -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 <QRect>
#include <QQueue>
#include <qwindowdefs.h>

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<quint64> m_pendingRequests;
WId m_windowId = 0;
};

DPP_END_NAMESPACE

#endif // DCLIENTMANAGEMENT_H
23 changes: 22 additions & 1 deletion wayland/dwayland/dwaylandinterfacehook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "dhighdpi.h"
#include "dxsettings.h"
#include "dnotitlebarwindowhelper_wl.h"
#include "dclientmanagement.h"

#include <qpa/qplatformnativeinterface.h>
#include <private/qguiapplication_p.h>
Expand Down Expand Up @@ -46,7 +47,10 @@ static QFunctionPointer getFunction(const QByteArray &function)
{splitWindowOnScreen, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::splitWindowOnScreen)},
{supportForSplittingWindow, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::supportForSplittingWindow)},
{splitWindowOnScreenByType, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::splitWindowOnScreenByType)},
{supportForSplittingWindowByType, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::supportForSplittingWindowByType)}
{supportForSplittingWindowByType, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::supportForSplittingWindowByType)},
{supportSplitMenu, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::supportSplitMenu)},
{showSplitMenu, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::showSplitMenu)},
{hideSplitMenu, reinterpret_cast<QFunctionPointer>(&DWaylandInterfaceHook::hideSplitMenu)}
};
return functionCache.value(function);
}
Expand Down Expand Up @@ -249,4 +253,21 @@ bool DWaylandInterfaceHook::supportForSplittingWindowByType(quint32 wid, quint32
return propertyValue >= 0 && static_cast<quint32>(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
4 changes: 4 additions & 0 deletions wayland/dwayland/dwaylandinterfacehook.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ QT_BEGIN_NAMESPACE
class QObject;
class QWindow;
class QPointF;
class QRect;
class QVariant;
class QPlatformNativeInterface;
QT_END_NAMESPACE
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion xcb/dplatformnativeinterfacehook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ static QFunctionPointer getFunction(const QByteArray &function)
{supportForSplittingWindow, reinterpret_cast<QFunctionPointer>(&Utility::supportForSplittingWindow)},
{sendEndStartupNotifition, reinterpret_cast<QFunctionPointer>(&DPlatformIntegration::sendEndStartupNotifition)},
{splitWindowOnScreenByType, reinterpret_cast<QFunctionPointer>(&Utility::splitWindowOnScreenByType)},
{supportForSplittingWindowByType, reinterpret_cast<QFunctionPointer>(&Utility::supportForSplittingWindowByType)}
{supportForSplittingWindowByType, reinterpret_cast<QFunctionPointer>(&Utility::supportForSplittingWindowByType)},
{supportSplitMenu, reinterpret_cast<QFunctionPointer>(&Utility::supportSplitMenu)},
{showSplitMenu, reinterpret_cast<QFunctionPointer>(&Utility::showSplitMenu)},
{hideSplitMenu, reinterpret_cast<QFunctionPointer>(&Utility::hideSplitMenu)}
};

return functionCache.value(function);
Expand Down
3 changes: 3 additions & 0 deletions xcb/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading