diff --git a/src/kernel/dplatformhandle.cpp b/src/kernel/dplatformhandle.cpp index d21fbd9..b08bc8e 100644 --- a/src/kernel/dplatformhandle.cpp +++ b/src/kernel/dplatformhandle.cpp @@ -5,118 +5,38 @@ #include "dguiapplicationhelper.h" #include "dplatformhandle.h" -#include "dplatformtheme.h" -#include "dwindowmanagerhelper.h" +#include "dplatformwindowinterface_p.h" +#ifndef DTK_DISABLE_XCB +#include "plugins/platform/xcb/dxcbplatformwindowinterface.h" +#endif #ifndef DTK_DISABLE_TREELAND #include "plugins/platform/treeland/dtreelandplatformwindowinterface.h" #endif -#include -#include - -#include -#include -#include -#include -#include - DGUI_BEGIN_NAMESPACE -#define DXCB_PLUGIN_KEY "dxcb" -#define DXCB_PLUGIN_SYMBOLIC_PROPERTY "_d_isDxcb" - -#define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name - -DEFINE_CONST_CHAR(useDxcb); -DEFINE_CONST_CHAR(redirectContent); -DEFINE_CONST_CHAR(netWmStates); -DEFINE_CONST_CHAR(windowRadius); -DEFINE_CONST_CHAR(borderWidth); -DEFINE_CONST_CHAR(borderColor); -DEFINE_CONST_CHAR(windowEffect); -DEFINE_CONST_CHAR(windowStartUpEffect); -DEFINE_CONST_CHAR(shadowRadius); -DEFINE_CONST_CHAR(shadowOffset); -DEFINE_CONST_CHAR(shadowColor); -DEFINE_CONST_CHAR(clipPath); -DEFINE_CONST_CHAR(frameMask); -DEFINE_CONST_CHAR(frameMargins); -DEFINE_CONST_CHAR(translucentBackground); -DEFINE_CONST_CHAR(enableSystemResize); -DEFINE_CONST_CHAR(enableSystemMove); -DEFINE_CONST_CHAR(enableBlurWindow); -DEFINE_CONST_CHAR(windowBlurAreas); -DEFINE_CONST_CHAR(windowBlurPaths); -DEFINE_CONST_CHAR(windowWallpaperParas); -DEFINE_CONST_CHAR(autoInputMaskByClipPath); - -DEFINE_CONST_CHAR(resolve_mask); -enum PropRole { - WindowRadius, - - // TO BE CONTINUE -}; - -// functions -DEFINE_CONST_CHAR(setWmBlurWindowBackgroundArea); -DEFINE_CONST_CHAR(setWmBlurWindowBackgroundPathList); -DEFINE_CONST_CHAR(setWmBlurWindowBackgroundMaskImage); -DEFINE_CONST_CHAR(setWmWallpaperParameter); -DEFINE_CONST_CHAR(setWindowProperty); -DEFINE_CONST_CHAR(pluginVersion); -DEFINE_CONST_CHAR(disableOverrideCursor); -DEFINE_CONST_CHAR(enableDxcb); -DEFINE_CONST_CHAR(isEnableDxcb); -DEFINE_CONST_CHAR(setEnableNoTitlebar); -DEFINE_CONST_CHAR(isEnableNoTitlebar); -DEFINE_CONST_CHAR(clientLeader); - -static void resolve(QObject *obj, PropRole role) -{ - int mask = obj->property(_resolve_mask).toInt(); - obj->setProperty(_resolve_mask, (mask |= 1 << role)); -} +static QHash g_platformThemeMap; -static bool resolved(QObject *obj, PropRole role) +static DPlatformWindowInterface *getPlatformWindowInterface(DPlatformHandle *platformHandle) { - int mask = obj->property(_resolve_mask).toInt(); - return mask & (1 << role); + return g_platformThemeMap.value(platformHandle); } -static void setWindowProperty(QWindow *window, const char *name, const QVariant &value) +static DPlatformWindowInterface *getPlatformWindowInterface(const DPlatformHandle *platformHandle) { - if (!window) - return; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - static QFunctionPointer setWindowProperty = qApp->platformFunction(_setWindowProperty); -#else - constexpr QFunctionPointer setWindowProperty = nullptr; -#endif - - if (!setWindowProperty) { - window->setProperty(name, value); - - return; - } - - reinterpret_cast(setWindowProperty)(window, name, value); + return g_platformThemeMap.value(const_cast(platformHandle)); } -#ifndef DTK_DISABLE_TREELAND -static QHash g_platformThemeMap; - -static DTreeLandPlatformWindowInterface *dPlatformWindowInterfaceByWindow(QWindow * window) +static DPlatformWindowInterface *dPlatformWindowInterfaceByWindow(QWindow *window) { for (auto it = g_platformThemeMap.cbegin(); it != g_platformThemeMap.cend(); ++it) { - if (it.value()->getWindow() == window) { + if (it.value()->window() == window) { return it.value(); } } return nullptr; } -#endif /*! \class Dtk::Gui::DPlatformHandle @@ -394,6 +314,13 @@ static DTreeLandPlatformWindowInterface *dPlatformWindowInterfaceByWindow(QWindo 竖直方向的圆角半径 */ +static DPlatformWindowInterfaceFactory::HelperCreator OutsideWindowInterfaceCreator = nullptr; + +void DPlatformWindowInterfaceFactory::registerInterface(HelperCreator creator) +{ + OutsideWindowInterfaceCreator = creator; +} + /*! \brief DPlatformHandle::DPlatformHandle 将 \a window 对象传递给 enableDXcbForWindow @@ -405,11 +332,25 @@ DPlatformHandle::DPlatformHandle(QWindow *window, QObject *parent) : QObject(parent) , m_window(window) { + if (OutsideWindowInterfaceCreator) { + g_platformThemeMap.insert(this, OutsideWindowInterfaceCreator(window, this)); + } else { +#ifndef DTK_DISABLE_XCB + if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsXWindowPlatform)) { + g_platformThemeMap.insert(this, new DXCBPlatformWindowInterface(window, this, parent)); + } +#endif + #ifndef DTK_DISABLE_TREELAND - if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { - g_platformThemeMap.insert(this, new DTreeLandPlatformWindowInterface(nullptr, window)); - } + if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { + g_platformThemeMap.insert(this, new DTreeLandPlatformWindowInterface(window, this, parent)); + } #endif + } + + if (g_platformThemeMap.isEmpty()) { + g_platformThemeMap.insert(this, new DPlatformWindowInterface(window, this, parent)); + } enableDXcbForWindow(window); @@ -418,11 +359,9 @@ DPlatformHandle::DPlatformHandle(QWindow *window, QObject *parent) DPlatformHandle::~DPlatformHandle() { -#ifndef DTK_DISABLE_TREELAND if (auto item = g_platformThemeMap.take(this)) { item->deleteLater(); } -#endif } /*! @@ -432,16 +371,11 @@ DPlatformHandle::~DPlatformHandle() */ QString DPlatformHandle::pluginVersion() { - QFunctionPointer pv = 0; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - pv = qApp->platformFunction(_pluginVersion); +#ifndef DTK_DISABLE_XCB + return DXCBPlatformWindowInterface::pluginVersion(); +#else + return {}; #endif - - if (Q_UNLIKELY(!pv)) - return QString(); - - return reinterpret_cast(pv)(); } /*! @@ -450,12 +384,11 @@ QString DPlatformHandle::pluginVersion() */ bool DPlatformHandle::isDXcbPlatform() { - if (!qApp) - return false; - - static bool _is_dxcb = qApp->platformName() == DXCB_PLUGIN_KEY || qApp->property(DXCB_PLUGIN_SYMBOLIC_PROPERTY).toBool(); - - return _is_dxcb; +#ifndef DTK_DISABLE_XCB + return DXCBPlatformWindowInterface::isDXcbPlatform(); +#else + return false; +#endif } /*! @@ -551,28 +484,12 @@ bool DPlatformHandle::isDXcbPlatform() */ void DPlatformHandle::enableDXcbForWindow(QWindow *window) { - // 优先使用窗口管理器中实现的no titlebar接口实现自定义窗口修饰器的效果 - if (setEnabledNoTitlebarForWindow(window, true)) { - return; +#ifndef DTK_DISABLE_XCB + DXCBPlatformWindowInterface *xcbPlatformWindowInterface = qobject_cast(dPlatformWindowInterfaceByWindow(window)); + if (xcbPlatformWindowInterface) { + return xcbPlatformWindowInterface->enableDXcb(); } - - if (!isDXcbPlatform()) - return; - - QFunctionPointer enable_dxcb = nullptr; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - enable_dxcb = qApp->platformFunction(_enableDxcb); #endif - - if (enable_dxcb) { - (*reinterpret_cast(enable_dxcb))(window); - } else if (window->handle()) { - Q_ASSERT_X(window->property(_useDxcb).toBool(), "DPlatformHandler:", - "Must be called before window handle has been created. See also QWindow::handle()"); - } else { - window->setProperty(_useDxcb, true); - } } /*! @@ -593,9 +510,12 @@ void DPlatformHandle::enableDXcbForWindow(QWindow *window) */ void DPlatformHandle::enableDXcbForWindow(QWindow *window, bool redirectContent) { - window->setProperty(_redirectContent, redirectContent); - - enableDXcbForWindow(window); +#ifndef DTK_DISABLE_XCB + DXCBPlatformWindowInterface *xcbPlatformWindowInterface = qobject_cast(dPlatformWindowInterfaceByWindow(window)); + if (xcbPlatformWindowInterface) { + return xcbPlatformWindowInterface->enableDXcb(redirectContent); + } +#endif } /*! @@ -606,61 +526,15 @@ void DPlatformHandle::enableDXcbForWindow(QWindow *window, bool redirectContent) */ bool DPlatformHandle::isEnabledDXcb(const QWindow *window) { - if (isEnabledNoTitlebar(window)) - return true; - - QFunctionPointer is_enable_dxcb = nullptr; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - is_enable_dxcb = qApp->platformFunction(_isEnableDxcb); -#endif - - if (is_enable_dxcb) { - return (*reinterpret_cast(is_enable_dxcb))(window); - } - - return window->property(_useDxcb).toBool(); -} - -static void initWindowRadius(QWindow *window) -{ - if (window->property(_windowRadius).isValid()) - return; - - auto theme = DGuiApplicationHelper::instance()->systemTheme(); - int radius = theme->windowRadius(18); //###(zccrs): 暂时在此处给窗口默认设置为18px的圆角 - - setWindowProperty(window, _windowRadius, radius); - // Qt::UniqueConnection will report a warning - // to `unique connections require a pointer to member function of a QObject subclass`. - const char *uniqueueConnectionFlag("_d_uniqueueConnectionFlag"); - bool connected = window->property(uniqueueConnectionFlag).toBool(); - if (!connected) { - window->setProperty(uniqueueConnectionFlag, true); - window->connect(theme, &DPlatformTheme::windowRadiusChanged, window, [window] (int radius) { - if (!resolved(window, PropRole::WindowRadius)) - setWindowProperty(window, _windowRadius, radius); - }); +#ifndef DTK_DISABLE_XCB + DXCBPlatformWindowInterface *xcbPlatformWindowInterface = qobject_cast(dPlatformWindowInterfaceByWindow(const_cast(window))); + if (xcbPlatformWindowInterface) { + return xcbPlatformWindowInterface->isEnabledDXcb(); } +#endif + return false; } -class Q_DECL_HIDDEN CreatorWindowEventFilter : public QObject { -public: - CreatorWindowEventFilter(QObject *par= nullptr): QObject(par){} - -public: - bool eventFilter(QObject *watched, QEvent *event) override { - if (event->type() == QEvent::PlatformSurface) { - QPlatformSurfaceEvent *se = static_cast(event); - if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { // 若收到此信号, 则 WinID 已被创建 - auto window = qobject_cast(watched); - initWindowRadius(window); - } - } - return QObject::eventFilter(watched, event); - } -}; - /*! \brief DPlatformHandle::setEnabledNoTitlebarForWindow. @@ -675,45 +549,10 @@ class Q_DECL_HIDDEN CreatorWindowEventFilter : public QObject { */ bool DPlatformHandle::setEnabledNoTitlebarForWindow(QWindow *window, bool enable) { - auto isDWaylandPlatform = [] { - return qApp->platformName() == "dwayland" || qApp->property("_d_isDwayland").toBool(); - }; - if (!(isDXcbPlatform() || isDWaylandPlatform() || DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform))) - return false; - -#ifndef DTK_DISABLE_TREELAND - if (window && DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { - - auto handle = dPlatformWindowInterfaceByWindow(window); - if (handle) { - handle->setEnabledNoTitlebar(enable); - } - return true; + auto windowInterface = dPlatformWindowInterfaceByWindow(window); + if (windowInterface) { + return windowInterface->setEnabledNoTitlebar(enable); } -#endif - - if (isEnabledNoTitlebar(window) == enable) - return true; - - QFunctionPointer enable_no_titlear = nullptr; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - enable_no_titlear = qApp->platformFunction(_setEnableNoTitlebar); -#endif - - if (enable_no_titlear) { - bool ok = (*reinterpret_cast(enable_no_titlear))(window, enable); - if (ok && enable) { - if (window->handle()) { - initWindowRadius(window); - } else { - window->installEventFilter(new CreatorWindowEventFilter(window)); - } - } - - return ok; - } - return false; } @@ -725,36 +564,13 @@ bool DPlatformHandle::setEnabledNoTitlebarForWindow(QWindow *window, bool enable */ bool DPlatformHandle::isEnabledNoTitlebar(const QWindow *window) { - QFunctionPointer is_enable_no_titlebar = nullptr; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - is_enable_no_titlebar = qApp->platformFunction(_isEnableNoTitlebar); -#endif - - if (is_enable_no_titlebar) { - return (*reinterpret_cast(is_enable_no_titlebar))(window); + auto windowInterface = dPlatformWindowInterfaceByWindow(const_cast(window)); + if (windowInterface) { + return windowInterface->isEnabledNoTitlebar(); } - return false; } -inline DPlatformHandle::WMBlurArea operator *(const DPlatformHandle::WMBlurArea &area, qreal scale) -{ - if (qFuzzyCompare(scale, 1.0)) - return area; - - DPlatformHandle::WMBlurArea new_area; - - new_area.x = qRound64(area.x * scale); - new_area.y = qRound64(area.y * scale); - new_area.width = qRound64(area.width * scale); - new_area.height = qRound64(area.height * scale); - new_area.xRadius = qRound64(area.xRadius * scale); - new_area.yRaduis = qRound64(area.yRaduis * scale); - - return new_area; -} - /*! \brief DPlatformHandle::setWindowBlurAreaByWM 设置窗口背景的模糊区域,示例: @@ -799,66 +615,11 @@ inline DPlatformHandle::WMBlurArea operator *(const DPlatformHandle::WMBlurArea */ bool DPlatformHandle::setWindowBlurAreaByWM(QWindow *window, const QVector &area) { - if (!window) { - return false; - } - - if (isEnabledDXcb(window)) { - QVector areas; - for (auto item : area) - areas << item.x << item.y << item.width << item.height << item.xRadius << item.yRaduis; - setWindowProperty(window, _windowBlurAreas, QVariant::fromValue(areas)); - return true; - } - - QFunctionPointer setWmBlurWindowBackgroundArea = Q_NULLPTR; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - setWmBlurWindowBackgroundArea = qApp->platformFunction(_setWmBlurWindowBackgroundArea); -#endif - - if (!setWmBlurWindowBackgroundArea) { - qWarning("setWindowBlurAreaByWM is not support"); - - return false; - } - - QSurfaceFormat format = window->format(); - - format.setAlphaBufferSize(8); - window->setFormat(format); - - const qreal device_ratio = window->devicePixelRatio(); - - if (qFuzzyCompare(device_ratio, 1.0)) { - return reinterpret_cast&)>(setWmBlurWindowBackgroundArea)(window->winId(), area); - } - - QVector new_areas; - - new_areas.reserve(area.size()); - - for (const WMBlurArea &a : area) { - new_areas.append(a * device_ratio); - } - - return reinterpret_cast&)>(setWmBlurWindowBackgroundArea)(window->winId(), new_areas); -} - -inline QPainterPath operator *(const QPainterPath &path, qreal scale) -{ - if (qFuzzyCompare(1.0, scale)) - return path; - - QPainterPath new_path = path; - - for (int i = 0; i < path.elementCount(); ++i) { - const QPainterPath::Element &e = path.elementAt(i); - - new_path.setElementPositionAt(i, qRound(e.x * scale), qRound(e.y * scale)); + auto windowInterface = dPlatformWindowInterfaceByWindow(window); + if (windowInterface) { + return windowInterface->setWindowBlurArea(area); } - - return new_path; + return false; } /*! @@ -907,48 +668,11 @@ inline QPainterPath operator *(const QPainterPath &path, qreal scale) */ bool DPlatformHandle::setWindowBlurAreaByWM(QWindow *window, const QList &paths) { - if (!window) { - return false; + auto windowInterface = dPlatformWindowInterfaceByWindow(window); + if (windowInterface) { + return windowInterface->setWindowBlurArea(paths); } - - if (isEnabledDXcb(window)) { - setWindowProperty(window, _windowBlurPaths, QVariant::fromValue(paths)); - - return true; - } - - QFunctionPointer setWmBlurWindowBackgroundPathList = Q_NULLPTR; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - setWmBlurWindowBackgroundPathList = qApp->platformFunction(_setWmBlurWindowBackgroundPathList); -#endif - - if (!setWmBlurWindowBackgroundPathList) { - qWarning("setWindowBlurAreaByWM is not support"); - - return false; - } - - QSurfaceFormat format = window->format(); - - format.setAlphaBufferSize(8); - window->setFormat(format); - - const qreal device_ratio = window->devicePixelRatio(); - - if (qFuzzyCompare(device_ratio, 1.0)) { - return reinterpret_cast&)>(setWmBlurWindowBackgroundPathList)(window->winId(), paths); - } - - QList new_paths; - - new_paths.reserve(paths.size()); - - for (const QPainterPath &p : paths) { - new_paths.append(p * device_ratio); - } - - return reinterpret_cast&)>(setWmBlurWindowBackgroundPathList)(window->winId(), new_paths); + return false; } /*! @@ -990,49 +714,11 @@ bool DPlatformHandle::setWindowBlurAreaByWM(QWindow *window, const QList= QT_VERSION_CHECK(5, 4, 0) - setWmWallpaperParameter = qApp->platformFunction(_setWmWallpaperParameter); -#endif - - if (!setWmWallpaperParameter) { - qWarning("setWindowWallpaperParaByWM is not support"); - - return false; + auto windowInterface = dPlatformWindowInterfaceByWindow(window); + if (windowInterface) { + return windowInterface->setWindowWallpaperPara(area, sMode, fMode); } - - QSurfaceFormat format = window->format(); - - format.setAlphaBufferSize(8); - window->setFormat(format); - - quint32 bMode = sMode | fMode; - - // 激活 backing store - window->setProperty("_d_dxcb_wallpaper", QVariant::fromValue(QPair(area, bMode))); - - if (!window->handle()) { - return true; - } else { - qWarning() << "because the window handle has been created, so 2D mode will have no effect"; - } - - const qreal device_ratio = window->devicePixelRatio(); - if (qFuzzyCompare(device_ratio, 1.0) || !area.isValid()) { - return reinterpret_cast(setWmWallpaperParameter)(window->winId(), area, bMode); - } - - QRect new_area(area.x() * device_ratio, - area.y() * device_ratio, - area.width() * device_ratio, - area.height() * device_ratio); - - return reinterpret_cast(setWmWallpaperParameter)(window->winId(), new_area, bMode); + return false; } /*! @@ -1045,11 +731,10 @@ bool DPlatformHandle::setWindowWallpaperParaByWM(QWindow *window, const QRect &a */ bool DPlatformHandle::connectWindowManagerChangedSignal(QObject *object, std::function slot) { - if (object) { - return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::windowManagerChanged, object, slot); - } - - return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::windowManagerChanged, slot); +#ifndef DTK_DISABLE_XCB + return DXCBPlatformWindowInterface::connectWindowManagerChangedSignal(object, slot); +#endif + return false; } /*! @@ -1063,11 +748,10 @@ bool DPlatformHandle::connectWindowManagerChangedSignal(QObject *object, std::fu */ bool DPlatformHandle::connectHasBlurWindowChanged(QObject *object, std::function slot) { - if (object) { - return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasBlurWindowChanged, object, slot); - } - - return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasBlurWindowChanged, slot); +#ifndef DTK_DISABLE_XCB + return DXCBPlatformWindowInterface::connectHasBlurWindowChanged(object, slot); +#endif + return false; } /*! @@ -1105,229 +789,301 @@ bool DPlatformHandle::setWindowBlurAreaByWM(const QList &paths) */ void DPlatformHandle::setDisableWindowOverrideCursor(QWindow *window, bool disable) { - window->setProperty(_disableOverrideCursor, disable); + auto windowInterface = dPlatformWindowInterfaceByWindow(window); + if (windowInterface) { + windowInterface->setDisableWindowOverrideCursor(disable); + } } int DPlatformHandle::windowRadius() const { - return m_window->property(_windowRadius).toInt(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->windowRadius(); + } + return {}; } int DPlatformHandle::borderWidth() const { - return m_window->property(_borderWidth).toInt(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->borderWidth(); + } + return {}; } QColor DPlatformHandle::borderColor() const { - return qvariant_cast(m_window->property(_borderColor)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->borderColor(); + } + return {}; } int DPlatformHandle::shadowRadius() const { - return m_window->property(_shadowRadius).toInt(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->shadowRadius(); + } + return {}; } QPoint DPlatformHandle::shadowOffset() const { - return m_window->property(_shadowOffset).toPoint(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->shadowOffset(); + } + return {}; } QColor DPlatformHandle::shadowColor() const { - return qvariant_cast(m_window->property(_shadowColor)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->shadowColor(); + } + return {}; } DPlatformHandle::EffectScene DPlatformHandle::windowEffect() { - return qvariant_cast(m_window->property(_windowEffect)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->windowEffect(); + } + return {}; } DPlatformHandle::EffectType DPlatformHandle::windowStartUpEffect() { - return qvariant_cast(m_window->property(_windowStartUpEffect)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->windowStartUpEffect(); + } + return {}; } QPainterPath DPlatformHandle::clipPath() const { - return qvariant_cast(m_window->property(_clipPath)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->clipPath(); + } + return {}; } QRegion DPlatformHandle::frameMask() const { - return qvariant_cast(m_window->property(_frameMask)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->frameMask(); + } + return {}; } QMargins DPlatformHandle::frameMargins() const { - return qvariant_cast(m_window->property(_frameMargins)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->frameMargins(); + } + return {}; } bool DPlatformHandle::translucentBackground() const { - return m_window->property(_translucentBackground).toBool(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->translucentBackground(); + } + return {}; } bool DPlatformHandle::enableSystemResize() const { - return m_window->property(_enableSystemResize).toBool(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->enableSystemResize(); + } + return {}; } bool DPlatformHandle::enableSystemMove() const { - return m_window->property(_enableSystemMove).toBool(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->enableSystemMove(); + } + return {}; } bool DPlatformHandle::enableBlurWindow() const { - return m_window->property(_enableBlurWindow).toBool(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->enableBlurWindow(); + } + return {}; } bool DPlatformHandle::autoInputMaskByClipPath() const { - return m_window->property(_autoInputMaskByClipPath).toBool(); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->autoInputMaskByClipPath(); + } + return {}; } WId DPlatformHandle::realWindowId() const { - return qvariant_cast(m_window->property("_d_real_content_window")); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + return windowInterface->realWindowId(); + } + return {}; } WId DPlatformHandle::windowLeader() { - QFunctionPointer clientLeader = Q_NULLPTR; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - clientLeader = qApp->platformFunction(_clientLeader); +#ifndef DTK_DISABLE_XCB + return DXCBPlatformWindowInterface::windowLeader(); #endif - - if (!clientLeader) { - return 0; - } - - return reinterpret_cast(clientLeader)(); } void DPlatformHandle::setWindowRadius(int windowRadius) { - setWindowProperty(m_window, _windowRadius, windowRadius); - resolve(m_window, PropRole::WindowRadius); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setWindowRadius(windowRadius); + } } void DPlatformHandle::setBorderWidth(int borderWidth) { - setWindowProperty(m_window, _borderWidth, borderWidth); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setBorderWidth(borderWidth); + } } void DPlatformHandle::setBorderColor(const QColor &borderColor) { - setWindowProperty(m_window, _borderColor, QVariant::fromValue(borderColor)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setBorderColor(borderColor); + } } void DPlatformHandle::setWindowEffect(DPlatformHandle::EffectScenes effectScene) { - setWindowProperty(m_window, _windowEffect, static_cast(effectScene)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setWindowEffect(effectScene); + } } void DPlatformHandle::setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) { - setWindowProperty(m_window, _windowStartUpEffect, static_cast(effectType)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setWindowStartUpEffect(effectType); + } } void DPlatformHandle::setShadowRadius(int shadowRadius) { - setWindowProperty(m_window, _shadowRadius, shadowRadius); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setShadowRadius(shadowRadius); + } } void DPlatformHandle::setShadowOffset(const QPoint &shadowOffset) { - setWindowProperty(m_window, _shadowOffset, shadowOffset); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setShadowOffset(shadowOffset); + } } void DPlatformHandle::setShadowColor(const QColor &shadowColor) { - setWindowProperty(m_window, _shadowColor, QVariant::fromValue(shadowColor)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setShadowColor(shadowColor); + } } void DPlatformHandle::setClipPath(const QPainterPath &clipPath) { - setWindowProperty(m_window, _clipPath, QVariant::fromValue(clipPath)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setClipPath(clipPath); + } } void DPlatformHandle::setFrameMask(const QRegion &frameMask) { - setWindowProperty(m_window, _frameMask, QVariant::fromValue(frameMask)); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setFrameMask(frameMask); + } } void DPlatformHandle::setTranslucentBackground(bool translucentBackground) { - setWindowProperty(m_window, _translucentBackground, translucentBackground); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setTranslucentBackground(translucentBackground); + } } void DPlatformHandle::setEnableSystemResize(bool enableSystemResize) { - setWindowProperty(m_window, _enableSystemResize, enableSystemResize); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setEnableSystemResize(enableSystemResize); + } } void DPlatformHandle::setEnableSystemMove(bool enableSystemMove) { - setWindowProperty(m_window, _enableSystemMove, enableSystemMove); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setEnableSystemMove(enableSystemMove); + } } void DPlatformHandle::setEnableBlurWindow(bool enableBlurWindow) { -#ifndef DTK_DISABLE_TREELAND - if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { - g_platformThemeMap.value(this)->setEnableBlurWindow(enableBlurWindow); - return; + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setEnableBlurWindow(enableBlurWindow); } -#endif - setWindowProperty(m_window, _enableBlurWindow, enableBlurWindow); } void DPlatformHandle::setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) { - setWindowProperty(m_window, _autoInputMaskByClipPath, autoInputMaskByClipPath); + auto windowInterface = getPlatformWindowInterface(this); + if (windowInterface) { + windowInterface->setAutoInputMaskByClipPath(autoInputMaskByClipPath); + } } bool DPlatformHandle::eventFilter(QObject *obj, QEvent *event) { - if (obj == m_window) { - if (event->type() == QEvent::DynamicPropertyChange) { - QDynamicPropertyChangeEvent *e = static_cast(event); - - if (e->propertyName() == _windowRadius) { - Q_EMIT windowRadiusChanged(); - } else if (e->propertyName() == _borderWidth) { - Q_EMIT borderWidthChanged(); - } else if (e->propertyName() == _borderColor) { - Q_EMIT borderColorChanged(); - } else if (e->propertyName() == _shadowRadius) { - Q_EMIT shadowRadiusChanged(); - } else if (e->propertyName() == _shadowOffset) { - Q_EMIT shadowOffsetChanged(); - } else if (e->propertyName() == _shadowColor) { - Q_EMIT shadowColorChanged(); - } else if (e->propertyName() == _clipPath) { - Q_EMIT clipPathChanged(); - } else if (e->propertyName() == _frameMask) { - Q_EMIT frameMaskChanged(); - } else if (e->propertyName() == _frameMargins) { - Q_EMIT frameMarginsChanged(); - } else if (e->propertyName() == _translucentBackground) { - Q_EMIT translucentBackgroundChanged(); - } else if (e->propertyName() == _enableSystemResize) { - Q_EMIT enableSystemResizeChanged(); - } else if (e->propertyName() == _enableSystemMove) { - Q_EMIT enableSystemMoveChanged(); - } else if (e->propertyName() == _enableBlurWindow) { - Q_EMIT enableBlurWindowChanged(); - } else if (e->propertyName() == _autoInputMaskByClipPath) { - Q_EMIT autoInputMaskByClipPathChanged(); - } - } +#ifndef DTK_DISABLE_XCB + DXCBPlatformWindowInterface *xcbPlatformWindowInterface = qobject_cast(getPlatformWindowInterface(this)); + if (!xcbPlatformWindowInterface) { + return false; } - + return xcbPlatformWindowInterface->eventFilterForXcb(obj, event); +#endif return false; } diff --git a/src/plugins/dplatformwindowinterface.cpp b/src/plugins/dplatformwindowinterface.cpp new file mode 100644 index 0000000..2c8da53 --- /dev/null +++ b/src/plugins/dplatformwindowinterface.cpp @@ -0,0 +1,214 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "private/dplatformwindowinterface_p.h" +#include "private/dplatformwindowinterface_p_p.h" + +DGUI_BEGIN_NAMESPACE + +DPlatformWindowInterfacePrivate::DPlatformWindowInterfacePrivate(DPlatformWindowInterface *qq) + : DObjectPrivate(qq) +{ +} + +DPlatformWindowInterface::DPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent) + : DPlatformWindowInterface(*new DPlatformWindowInterfacePrivate(this), window, platformHandle, parent) +{ +} + +DPlatformWindowInterface::~DPlatformWindowInterface() +{ +} + +QWindow *DPlatformWindowInterface::window() const +{ + D_DC(DPlatformWindowInterface); + + return d->m_window; +} + +bool DPlatformWindowInterface::setWindowBlurArea(const QVector &area) +{ + return {}; +} + +bool DPlatformWindowInterface::setWindowBlurArea(const QList &paths) +{ + return {}; +} + +bool DPlatformWindowInterface::setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode) +{ + return {}; +} + +bool DPlatformWindowInterface::isEnabledNoTitlebar() const +{ + return {}; +} + +bool DPlatformWindowInterface::setEnabledNoTitlebar(bool enable) +{ + return {}; +} + +void DPlatformWindowInterface::setDisableWindowOverrideCursor(bool disable) +{ +} + +int DPlatformWindowInterface::windowRadius() const +{ + return {}; +} + +void DPlatformWindowInterface::setWindowRadius(int windowRadius) +{ +} + +int DPlatformWindowInterface::borderWidth() const +{ + return {}; +} + +void DPlatformWindowInterface::setBorderWidth(int borderWidth) +{ +} + +QColor DPlatformWindowInterface::borderColor() const +{ + return {}; +} + +void DPlatformWindowInterface::setBorderColor(const QColor &borderColor) +{ +} + +int DPlatformWindowInterface::shadowRadius() const +{ + return {}; +} + +void DPlatformWindowInterface::setShadowRadius(int shadowRadius) +{ +} + +QPoint DPlatformWindowInterface::shadowOffset() const +{ + return {}; +} + +void DPlatformWindowInterface::setShadowOffset(const QPoint &shadowOffset) +{ +} + +QColor DPlatformWindowInterface::shadowColor() const +{ + return {}; +} + +void DPlatformWindowInterface::setShadowColor(const QColor &shadowColor) +{ +} + +DPlatformHandle::EffectScene DPlatformWindowInterface::windowEffect() +{ + return {}; +} + +void DPlatformWindowInterface::setWindowEffect(DPlatformHandle::EffectScenes effectScene) +{ +} + +DPlatformHandle::EffectType DPlatformWindowInterface::windowStartUpEffect() +{ + return {}; +} + +void DPlatformWindowInterface::setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) +{ +} + +QPainterPath DPlatformWindowInterface::clipPath() const +{ + return {}; +} + +void DPlatformWindowInterface::setClipPath(const QPainterPath &clipPath) +{ +} + +QRegion DPlatformWindowInterface::frameMask() const +{ + return {}; +} + +void DPlatformWindowInterface::setFrameMask(const QRegion &frameMask) +{ +} + +QMargins DPlatformWindowInterface::frameMargins() const +{ + return {}; +} + +bool DPlatformWindowInterface::translucentBackground() const +{ + return {}; +} + +void DPlatformWindowInterface::setTranslucentBackground(bool translucentBackground) +{ +} + +bool DPlatformWindowInterface::enableSystemResize() const +{ + return {}; +} + +void DPlatformWindowInterface::setEnableSystemResize(bool enableSystemResize) +{ +} + +bool DPlatformWindowInterface::enableSystemMove() const +{ + return {}; +} + +void DPlatformWindowInterface::setEnableSystemMove(bool enableSystemMove) +{ +} + +bool DPlatformWindowInterface::enableBlurWindow() const +{ + return {}; +} + +void DPlatformWindowInterface::setEnableBlurWindow(bool enableBlurWindow) +{ +} + +bool DPlatformWindowInterface::autoInputMaskByClipPath() const +{ + return {}; +} + +void DPlatformWindowInterface::setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) +{ +} + +WId DPlatformWindowInterface::realWindowId() const +{ + return {}; +} + +DPlatformWindowInterface::DPlatformWindowInterface(DPlatformWindowInterfacePrivate &dd, QWindow *window, DPlatformHandle *platformHandle, QObject *parent) + : QObject(parent) + , DObject(dd) +{ + d_func()->m_window = window; + d_func()->m_platformHandle = platformHandle; +} + +DGUI_END_NAMESPACE + diff --git a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp index 357d600..0a7705f 100644 --- a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp @@ -6,14 +6,16 @@ #include #undef protected +#include "dtkgui_global.h" +#include "plugins/platform/treeland/dtreelandplatforminterface.h" + #include "dtreelandplatformwindowinterface.h" -#include "dtreelandplatformwindowinterface.h" -#include "dtreelandplatforminterface.h" +#include "dtreelandplatformwindowinterface_p.h" + #include #include #include -#include "personalizationwaylandclientextension.h" #include #include "dvtablehook.h" @@ -153,7 +155,7 @@ class Q_DECL_HIDDEN WindowEventFilter : public QObject { } public: - bool eventFilter(QObject *watched, QEvent *event) override { + bool eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::PlatformSurface) { QPlatformSurfaceEvent *se = static_cast(event); if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { @@ -167,14 +169,22 @@ class Q_DECL_HIDDEN WindowEventFilter : public QObject { DTreeLandPlatformWindowInterface *m_interface; }; -DTreeLandPlatformWindowInterface::DTreeLandPlatformWindowInterface(QObject *parent, QWindow *window) - : QObject(parent) - , m_window(window) +DGUI_BEGIN_NAMESPACE + +DTreeLandPlatformWindowInterfacePrivate::DTreeLandPlatformWindowInterfacePrivate(DTreeLandPlatformWindowInterface *qq) + : DPlatformWindowInterfacePrivate(qq) { - m_manager = PersonalizationManager::instance(); - m_window->installEventFilter(new WindowEventFilter(this, this)); - connect(m_manager, &PersonalizationManager::activeChanged, this, [this](){ - if (m_manager->isActive()) { +} + +DTreeLandPlatformWindowInterface::DTreeLandPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent) + : DPlatformWindowInterface(*new DTreeLandPlatformWindowInterfacePrivate(this), window, platformHandle, parent) +{ + D_D(DTreeLandPlatformWindowInterface); + + d->m_manager = PersonalizationManager::instance(); + d->m_window->installEventFilter(new WindowEventFilter(this, this)); + connect(d->m_manager, &PersonalizationManager::activeChanged, this, [this, d](){ + if (d->m_manager->isActive()) { handlePendingTasks(); } }); @@ -188,33 +198,38 @@ DTreeLandPlatformWindowInterface::DTreeLandPlatformWindowInterface(QObject *pare DTreeLandPlatformWindowInterface::~DTreeLandPlatformWindowInterface() { - } void DTreeLandPlatformWindowInterface::onSurfaceCreated() { - if (m_isNoTitlebar) { + D_D(DTreeLandPlatformWindowInterface); + + if (d->m_isNoTitlebar) { doSetEnabledNoTitlebar(); } - if (m_isWindowBlur) { + if (d->m_isWindowBlur) { doSetEnabledBlurWindow(); } } void DTreeLandPlatformWindowInterface::onSurfaceDestroyed() { - if (m_windowContext) { - m_windowContext->deleteLater(); - m_windowContext = nullptr; + D_D(DTreeLandPlatformWindowInterface); + + if (d->m_windowContext) { + d->m_windowContext->deleteLater(); + d->m_windowContext = nullptr; } } void DTreeLandPlatformWindowInterface::initWaylandWindow() { + D_D(DTreeLandPlatformWindowInterface); + // force create window handle - m_window->winId(); + d->m_window->winId(); - auto waylandWindow = dynamic_cast(m_window->handle()); + auto waylandWindow = dynamic_cast(d->m_window->handle()); if (!waylandWindow) { qWarning() << "waylandWindow is nullptr!!!"; @@ -227,18 +242,19 @@ void DTreeLandPlatformWindowInterface::initWaylandWindow() PersonalizationWindowContext *DTreeLandPlatformWindowInterface::getWindowContext() { - if (!m_manager->isSupported()) { + D_D(DTreeLandPlatformWindowInterface); + + if (!d->m_manager->isSupported()) { return nullptr; } - if (!m_window) { + if (!d->m_window) { qWarning() << "window is nullptr!!!"; return nullptr; } - if (m_windowContext) { - return m_windowContext; + if (d->m_windowContext) { + return d->m_windowContext; } - - auto waylandWindow = dynamic_cast(m_window->handle()); + auto waylandWindow = dynamic_cast(d->m_window->handle()); if (!waylandWindow) { qWarning() << "waylandWindow is nullptr!!!"; return nullptr; @@ -250,71 +266,326 @@ PersonalizationWindowContext *DTreeLandPlatformWindowInterface::getWindowContext return nullptr; } - if (!m_windowContext) { - m_windowContext = new PersonalizationWindowContext(m_manager->get_window_context(surface)); + if (!d->m_windowContext) { + d->m_windowContext = new PersonalizationWindowContext(d->m_manager->get_window_context(surface)); } - return m_windowContext; + return d->m_windowContext; } void DTreeLandPlatformWindowInterface::handlePendingTasks() { - while (!m_pendingTasks.isEmpty()) { - auto handleFunc = m_pendingTasks.dequeue(); + D_D(DTreeLandPlatformWindowInterface); + + while (!d->m_pendingTasks.isEmpty()) { + auto handleFunc = d->m_pendingTasks.dequeue(); handleFunc(); } } +bool DTreeLandPlatformWindowInterface::isEnabledNoTitlebar() const +{ + D_DC(DTreeLandPlatformWindowInterface); + + return d->m_isNoTitlebar; +} + bool DTreeLandPlatformWindowInterface::setEnabledNoTitlebar(bool enable) { - if (m_isNoTitlebar == enable) { + D_D(DTreeLandPlatformWindowInterface); + + if (d->m_isNoTitlebar == enable) { return true; } - m_isNoTitlebar = enable; + d->m_isNoTitlebar = enable; doSetEnabledNoTitlebar(); return true; } +bool DTreeLandPlatformWindowInterface::setWindowBlurArea(const QVector &area) +{ + qWarning("the interface (setWindowBlurArea) is not currently supported in Treeland"); + return false; +} + +bool DTreeLandPlatformWindowInterface::setWindowBlurArea(const QList &paths) +{ + qWarning("the interface (setWindowBlurArea) is not currently supported in Treeland"); + return false; +} + +bool DTreeLandPlatformWindowInterface::setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode) +{ + qWarning("the interface (setWindowWallpaperPara) is not currently supported in Treeland"); + return false; +} + +void DTreeLandPlatformWindowInterface::setDisableWindowOverrideCursor(bool disable) +{ + qWarning("the interface (setWindowBlurArea) is not currently supported in Treeland"); + return; +} + +int DTreeLandPlatformWindowInterface::windowRadius() const +{ + D_DC(DTreeLandPlatformWindowInterface); + + return d->m_radius; +} + +void DTreeLandPlatformWindowInterface::setWindowRadius(int windowRadius) +{ + D_D(DTreeLandPlatformWindowInterface); + + if (d->m_radius == windowRadius) { + return; + } + d->m_radius = windowRadius; + doSetWindowRadius(windowRadius); +} + +int DTreeLandPlatformWindowInterface::borderWidth() const +{ + qWarning("the interface (borderWidth) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setBorderWidth(int borderWidth) +{ + qWarning("the interface (setBorderWidth) is not currently supported in Treeland"); + return; +} + +QColor DTreeLandPlatformWindowInterface::borderColor() const +{ + qWarning("the interface (borderColor) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setBorderColor(const QColor &borderColor) +{ + qWarning("the interface (setBorderColor) is not currently supported in Treeland"); + return; +} + +int DTreeLandPlatformWindowInterface::shadowRadius() const +{ + qWarning("the interface (shadowRadius) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setShadowRadius(int shadowRadius) +{ + qWarning("the interface (setShadowRadius) is not currently supported in Treeland"); + return; +} + +QPoint DTreeLandPlatformWindowInterface::shadowOffset() const +{ + qWarning("the interface (shadowOffset) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setShadowOffset(const QPoint &shadowOffset) +{ + qWarning("the interface (setShadowOffset) is not currently supported in Treeland"); + return; +} + +QColor DTreeLandPlatformWindowInterface::shadowColor() const +{ + qWarning("the interface (shadowColor) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setShadowColor(const QColor &shadowColor) +{ + qWarning("the interface (setShadowColor) is not currently supported in Treeland"); + return; +} + +DPlatformHandle::EffectScene DTreeLandPlatformWindowInterface::windowEffect() +{ + qWarning("the interface (windowEffect) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setWindowEffect(DPlatformHandle::EffectScenes effectScene) +{ + qWarning("the interface (setWindowEffect) is not currently supported in Treeland"); + return; +} + +DPlatformHandle::EffectType DTreeLandPlatformWindowInterface::windowStartUpEffect() +{ + qWarning("the interface (windowStartUpEffect) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) +{ + qWarning("the interface (setWindowStartUpEffect) is not currently supported in Treeland"); + return; +} + +QPainterPath DTreeLandPlatformWindowInterface::clipPath() const +{ + qWarning("the interface (clipPath) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setClipPath(const QPainterPath &clipPath) +{ + qWarning("the interface (setClipPath) is not currently supported in Treeland"); + return; +} + +QRegion DTreeLandPlatformWindowInterface::frameMask() const +{ + qWarning("the interface (frameMask) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setFrameMask(const QRegion &frameMask) +{ + qWarning("the interface (setFrameMask) is not currently supported in Treeland"); + return; +} + +QMargins DTreeLandPlatformWindowInterface::frameMargins() const +{ + qWarning("the interface (frameMargins) is not currently supported in Treeland"); + return {}; +} + +bool DTreeLandPlatformWindowInterface::translucentBackground() const +{ + qWarning("the interface (translucentBackground) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setTranslucentBackground(bool translucentBackground) +{ + qWarning("the interface (setTranslucentBackground) is not currently supported in Treeland"); + return; +} + +bool DTreeLandPlatformWindowInterface::enableSystemResize() const +{ + qWarning("the interface (enableSystemResize) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setEnableSystemResize(bool enableSystemResize) +{ + qWarning("the interface (setWindowWallpaperPara) is not currently supported in Treeland"); + return; +} + +bool DTreeLandPlatformWindowInterface::enableSystemMove() const +{ + qWarning("the interface (enableSystemMove) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setEnableSystemMove(bool enableSystemMove) +{ + qWarning("the interface (setEnableSystemMove) is not currently supported in Treeland"); + return; +} + +bool DTreeLandPlatformWindowInterface::enableBlurWindow() const +{ + qWarning("the interface (enableBlurWindow) is not currently supported in Treeland"); + return {}; +} + void DTreeLandPlatformWindowInterface::setEnableBlurWindow(bool enable) { - if (m_isWindowBlur == enable) { + D_D(DTreeLandPlatformWindowInterface); + + if (d->m_isWindowBlur == enable) { return; } - m_isWindowBlur = enable; + + d->m_isWindowBlur = enable; doSetEnabledBlurWindow(); } -void DTreeLandPlatformWindowInterface::doSetEnabledNoTitlebar() +bool DTreeLandPlatformWindowInterface::autoInputMaskByClipPath() const { - auto handleFunc = [this](){ + qWarning("the interface (autoInputMaskByClipPath) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) +{ + qWarning("the interface (setAutoInputMaskByClipPath) is not currently supported in Treeland"); + return; +} + +WId DTreeLandPlatformWindowInterface::realWindowId() const +{ + qWarning("the interface (realWindowId) is not currently supported in Treeland"); + return {}; +} + +void DTreeLandPlatformWindowInterface::doSetEnabledBlurWindow() +{ + D_D(DTreeLandPlatformWindowInterface); + + auto handleFunc = [this, d](){ auto windowContext = getWindowContext(); if (!windowContext) { qWarning() << "windowContext is nullptr!"; return; } - windowContext->set_titlebar(m_isNoTitlebar ? PersonalizationWindowContext::enable_mode_disable : PersonalizationWindowContext::enable_mode_enable); - return; + windowContext->set_blend_mode(d->m_isWindowBlur ? PersonalizationWindowContext::blend_mode_blur : PersonalizationWindowContext::blend_mode_transparent); }; - if (m_manager->isActive()) { + if (d->m_manager->isActive()) { handleFunc(); } else { - m_pendingTasks.enqueue(handleFunc); + d->m_pendingTasks.enqueue(handleFunc); } } -void DTreeLandPlatformWindowInterface::doSetEnabledBlurWindow() +void DTreeLandPlatformWindowInterface::doSetEnabledNoTitlebar() { - auto handleFunc = [this](){ + D_D(DTreeLandPlatformWindowInterface); + + auto handleFunc = [this, d](){ auto windowContext = getWindowContext(); if (!windowContext) { qWarning() << "windowContext is nullptr!"; - return; + return false; } - windowContext->set_blend_mode(m_isWindowBlur ? PersonalizationWindowContext::blend_mode_blur : PersonalizationWindowContext::blend_mode_transparent); + windowContext->set_titlebar(d->m_isNoTitlebar ? PersonalizationWindowContext::enable_mode_disable : PersonalizationWindowContext::enable_mode_enable); + return true; + }; + if (d->m_manager->isActive()) { + handleFunc(); + } else { + d->m_pendingTasks.enqueue(handleFunc); + } +} + +void DTreeLandPlatformWindowInterface::doSetWindowRadius() +{ + D_D(DTreeLandPlatformWindowInterface); + + auto handleFunc = [this, d] (){ + auto windowContext = getWindowContext(); + if (!windowContext) { + qWarning() << "windowContext is nullptr!"; + return false; + } + windowContext->set_round_corner_radius(d->m_radius); + return true; }; - if (m_manager->isActive()) { + if (d->m_manager->isActive()) { handleFunc(); } else { - m_pendingTasks.enqueue(handleFunc); + d->m_pendingTasks.enqueue(handleFunc); } } +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h index 1a35320..b9c629f 100644 --- a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h @@ -9,21 +9,80 @@ #include "dtreelandplatforminterface.h" #include #include +#include "private/dplatformwindowinterface_p.h" -DGUI_USE_NAMESPACE -class DTreeLandPlatformWindowInterface : public QObject +DGUI_BEGIN_NAMESPACE + +class PersonalizationWindowContext; +class DTreeLandPlatformWindowInterfacePrivate; +class DTreeLandPlatformWindowInterface : public DPlatformWindowInterface { Q_OBJECT + D_DECLARE_PRIVATE(DTreeLandPlatformWindowInterface) public: - explicit DTreeLandPlatformWindowInterface(QObject *parent = nullptr, QWindow *window = nullptr); + explicit DTreeLandPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent = nullptr); ~DTreeLandPlatformWindowInterface(); - bool setEnabledNoTitlebar(bool enable); - void setEnableBlurWindow(bool enable); - void doSetEnabledNoTitlebar(); - void doSetEnabledBlurWindow(); - [[nodiscard]]QWindow *getWindow() const { return m_window; } + void initWaylandWindow(); + bool setWindowBlurArea(const QVector &area) override; + bool setWindowBlurArea(const QList &paths) override; + bool setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode) override; + + void setDisableWindowOverrideCursor(bool disable) override; + + bool isEnabledNoTitlebar() const override; + bool setEnabledNoTitlebar(bool enable) override; + + int windowRadius() const override; + void setWindowRadius(int windowRadius) override; + + int borderWidth() const override; + void setBorderWidth(int borderWidth) override; + + QColor borderColor() const override; + void setBorderColor(const QColor &borderColor) override; + + int shadowRadius() const override; + void setShadowRadius(int shadowRadius) override; + + QPoint shadowOffset() const override; + void setShadowOffset(const QPoint &shadowOffset) override; + + QColor shadowColor() const override; + void setShadowColor(const QColor &shadowColor) override; + + DPlatformHandle::EffectScene windowEffect() override; + void setWindowEffect(DPlatformHandle::EffectScenes effectScene) override; + + DPlatformHandle::EffectType windowStartUpEffect() override; + void setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) override; + + QPainterPath clipPath() const override; + void setClipPath(const QPainterPath &clipPath) override; + + QRegion frameMask() const override; + void setFrameMask(const QRegion &frameMask) override; + + QMargins frameMargins() const override; + + bool translucentBackground() const override; + void setTranslucentBackground(bool translucentBackground) override; + + bool enableSystemResize() const override; + void setEnableSystemResize(bool enableSystemResize) override; + + bool enableSystemMove() const override; + void setEnableSystemMove(bool enableSystemMove) override; + + bool enableBlurWindow() const override; + void setEnableBlurWindow(bool enableBlurWindow) override; + + bool autoInputMaskByClipPath() const override; + void setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) override; + + WId realWindowId() const override; + public slots: void onSurfaceCreated(); void onSurfaceDestroyed(); @@ -31,14 +90,10 @@ public slots: private: PersonalizationWindowContext *getWindowContext(); void handlePendingTasks(); - -private: - QWindow *m_window = nullptr; - QQueue> m_pendingTasks; - PersonalizationManager *m_manager = nullptr; - PersonalizationWindowContext *m_windowContext = nullptr; - bool m_isNoTitlebar = true; - bool m_isWindowBlur = false; + void doSetEnabledBlurWindow(); + void doSetEnabledNoTitlebar(); + void doSetWindowRadius(); }; +DGUI_END_NAMESPACE #endif // DTREELANDPLATFORMWINDOWINTERFACE_H diff --git a/src/plugins/platform/treeland/dtreelandplatformwindowinterface_p.h b/src/plugins/platform/treeland/dtreelandplatformwindowinterface_p.h new file mode 100644 index 0000000..a7652f5 --- /dev/null +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface_p.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DTREELANDPLATFORMWINDOWINTERFACE_P_H +#define DTREELANDPLATFORMWINDOWINTERFACE_P_H + +#include "dplatformwindowinterface_p_p.h" +#include "dtreelandplatformwindowinterface.h" +#include "personalizationwaylandclientextension.h" + +#include + +DGUI_BEGIN_NAMESPACE + +class DTreeLandPlatformWindowInterfacePrivate : public DPlatformWindowInterfacePrivate +{ +public: + D_DECLARE_PUBLIC(DTreeLandPlatformWindowInterface) + DTreeLandPlatformWindowInterfacePrivate(DTreeLandPlatformWindowInterface *qq); + +public: + QQueue> m_pendingTasks; + PersonalizationManager *m_manager = nullptr; + PersonalizationWindowContext *m_windowContext = nullptr; + bool m_isNoTitlebar = true; + bool m_isWindowBlur = false; + int m_radius; +}; + +DGUI_END_NAMESPACE + +#endif // DTREELANDPLATFORMWINDOWINTERFACE_P_H diff --git a/src/plugins/platform/xcb/dxcbplatformwindowinterface.cpp b/src/plugins/platform/xcb/dxcbplatformwindowinterface.cpp new file mode 100644 index 0000000..65e8cb0 --- /dev/null +++ b/src/plugins/platform/xcb/dxcbplatformwindowinterface.cpp @@ -0,0 +1,782 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "dxcbplatformwindowinterface.h" +#include "dxcbplatformwindowinterface_p.h" +#include "dguiapplicationhelper.h" +#include "dplatformtheme.h" +#include "dwindowmanagerhelper.h" + +#include + +#include +#include +#include + +DGUI_BEGIN_NAMESPACE + +#define DXCB_PLUGIN_KEY "dxcb" +#define DXCB_PLUGIN_SYMBOLIC_PROPERTY "_d_isDxcb" + +#define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name + +DEFINE_CONST_CHAR(useDxcb); +DEFINE_CONST_CHAR(redirectContent); +DEFINE_CONST_CHAR(netWmStates); +DEFINE_CONST_CHAR(windowRadius); +DEFINE_CONST_CHAR(borderWidth); +DEFINE_CONST_CHAR(borderColor); +DEFINE_CONST_CHAR(windowEffect); +DEFINE_CONST_CHAR(windowStartUpEffect); +DEFINE_CONST_CHAR(shadowRadius); +DEFINE_CONST_CHAR(shadowOffset); +DEFINE_CONST_CHAR(shadowColor); +DEFINE_CONST_CHAR(clipPath); +DEFINE_CONST_CHAR(frameMask); +DEFINE_CONST_CHAR(frameMargins); +DEFINE_CONST_CHAR(translucentBackground); +DEFINE_CONST_CHAR(enableSystemResize); +DEFINE_CONST_CHAR(enableSystemMove); +DEFINE_CONST_CHAR(enableBlurWindow); +DEFINE_CONST_CHAR(windowBlurAreas); +DEFINE_CONST_CHAR(windowBlurPaths); +DEFINE_CONST_CHAR(windowWallpaperParas); +DEFINE_CONST_CHAR(autoInputMaskByClipPath); + +DEFINE_CONST_CHAR(resolve_mask); +enum PropRole { + WindowRadius, + + // TO BE CONTINUE +}; + +// functions +DEFINE_CONST_CHAR(setWmBlurWindowBackgroundArea); +DEFINE_CONST_CHAR(setWmBlurWindowBackgroundPathList); +DEFINE_CONST_CHAR(setWmBlurWindowBackgroundMaskImage); +DEFINE_CONST_CHAR(setWmWallpaperParameter); +DEFINE_CONST_CHAR(setWindowProperty); +DEFINE_CONST_CHAR(pluginVersion); +DEFINE_CONST_CHAR(disableOverrideCursor); +DEFINE_CONST_CHAR(enableDxcb); +DEFINE_CONST_CHAR(isEnableDxcb); +DEFINE_CONST_CHAR(setEnableNoTitlebar); +DEFINE_CONST_CHAR(isEnableNoTitlebar); +DEFINE_CONST_CHAR(clientLeader); + +static void resolve(QObject *obj, PropRole role) +{ + int mask = obj->property(_resolve_mask).toInt(); + obj->setProperty(_resolve_mask, (mask |= 1 << role)); +} + +static bool resolved(QObject *obj, PropRole role) +{ + int mask = obj->property(_resolve_mask).toInt(); + return mask & (1 << role); +} + +static void setWindowProperty(QWindow *window, const char *name, const QVariant &value) +{ + if (!window) + return; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + static QFunctionPointer setWindowProperty = qApp->platformFunction(_setWindowProperty); +#else + constexpr QFunctionPointer setWindowProperty = nullptr; +#endif + + if (!setWindowProperty) { + window->setProperty(name, value); + + return; + } + + reinterpret_cast(setWindowProperty)(window, name, value); +} + +DXCBPlatformWindowInterfacePrivate::DXCBPlatformWindowInterfacePrivate(DXCBPlatformWindowInterface *qq) + : DPlatformWindowInterfacePrivate(qq) +{ +} + +DXCBPlatformWindowInterface::DXCBPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent) + : DPlatformWindowInterface(*new DXCBPlatformWindowInterfacePrivate(this), window, platformHandle, parent) +{ +} + +DXCBPlatformWindowInterface::~DXCBPlatformWindowInterface() +{ +} + +QString DXCBPlatformWindowInterface::pluginVersion() +{ + QFunctionPointer pv = 0; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + pv = qApp->platformFunction(_pluginVersion); +#endif + + if (Q_UNLIKELY(!pv)) + return QString(); + + return reinterpret_cast(pv)(); +} + +bool DXCBPlatformWindowInterface::isDXcbPlatform() +{ + if (!qApp) + return false; + + static bool _is_dxcb = qApp->platformName() == DXCB_PLUGIN_KEY || qApp->property(DXCB_PLUGIN_SYMBOLIC_PROPERTY).toBool(); + + return _is_dxcb; +} + +bool DXCBPlatformWindowInterface::connectWindowManagerChangedSignal(QObject *object, std::function slot) +{ + if (object) { + return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::windowManagerChanged, object, slot); + } + + return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::windowManagerChanged, slot); +} + +bool DXCBPlatformWindowInterface::connectHasBlurWindowChanged(QObject *object, std::function slot) +{ + if (object) { + return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasBlurWindowChanged, object, slot); + } + + return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasBlurWindowChanged, slot); +} + +WId DXCBPlatformWindowInterface::windowLeader() +{ + QFunctionPointer clientLeader = Q_NULLPTR; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + clientLeader = qApp->platformFunction(_clientLeader); +#endif + + if (!clientLeader) { + return 0; + } + + return reinterpret_cast(clientLeader)(); +} + +void DXCBPlatformWindowInterface::enableDXcb() +{ + D_D(DXCBPlatformWindowInterface); + + // 优先使用窗口管理器中实现的no titlebar接口实现自定义窗口修饰器的效果 + if (setEnabledNoTitlebar(true)) { + return; + } + + if (!isDXcbPlatform()) + return; + + QFunctionPointer enable_dxcb = nullptr; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + enable_dxcb = qApp->platformFunction(_enableDxcb); +#endif + + if (enable_dxcb) { + (*reinterpret_cast(enable_dxcb))(d->m_window); + } else if (d->m_window->handle()) { + Q_ASSERT_X(d->m_window->property(_useDxcb).toBool(), "DXCBPlatformWindowInterfacer:", + "Must be called before window handle has been created. See also QWindow::handle()"); + } else { + d->m_window->setProperty(_useDxcb, true); + } +} + +void DXCBPlatformWindowInterface::enableDXcb(bool redirectContent) +{ + D_D(DXCBPlatformWindowInterface); + + d->m_window->setProperty(_redirectContent, redirectContent); + + enableDXcb(); +} + +bool DXCBPlatformWindowInterface::isEnabledDXcb() +{ + D_D(DXCBPlatformWindowInterface); + + if (isEnabledNoTitlebar()) + return true; + + QFunctionPointer is_enable_dxcb = nullptr; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + is_enable_dxcb = qApp->platformFunction(_isEnableDxcb); +#endif + + if (is_enable_dxcb) { + return (*reinterpret_cast(is_enable_dxcb))(d->m_window); + } + + return d->m_window->property(_useDxcb).toBool(); +} + +bool DXCBPlatformWindowInterface::eventFilterForXcb(QObject *obj, QEvent *event) +{ + D_D(DXCBPlatformWindowInterface); + if (obj == d->m_window) { + if (event->type() == QEvent::DynamicPropertyChange) { + QDynamicPropertyChangeEvent *e = static_cast(event); + + if (e->propertyName() == _windowRadius) { + Q_EMIT d->m_platformHandle->windowRadiusChanged(); + } else if (e->propertyName() == _borderWidth) { + Q_EMIT d->m_platformHandle->borderWidthChanged(); + } else if (e->propertyName() == _borderColor) { + Q_EMIT d->m_platformHandle->borderColorChanged(); + } else if (e->propertyName() == _shadowRadius) { + Q_EMIT d->m_platformHandle->shadowRadiusChanged(); + } else if (e->propertyName() == _shadowOffset) { + Q_EMIT d->m_platformHandle->shadowOffsetChanged(); + } else if (e->propertyName() == _shadowColor) { + Q_EMIT d->m_platformHandle->shadowColorChanged(); + } else if (e->propertyName() == _clipPath) { + Q_EMIT d->m_platformHandle->clipPathChanged(); + } else if (e->propertyName() == _frameMask) { + Q_EMIT d->m_platformHandle->frameMaskChanged(); + } else if (e->propertyName() == _frameMargins) { + Q_EMIT d->m_platformHandle->frameMarginsChanged(); + } else if (e->propertyName() == _translucentBackground) { + Q_EMIT d->m_platformHandle->translucentBackgroundChanged(); + } else if (e->propertyName() == _enableSystemResize) { + Q_EMIT d->m_platformHandle->enableSystemResizeChanged(); + } else if (e->propertyName() == _enableSystemMove) { + Q_EMIT d->m_platformHandle->enableSystemMoveChanged(); + } else if (e->propertyName() == _enableBlurWindow) { + Q_EMIT d->m_platformHandle->enableBlurWindowChanged(); + } else if (e->propertyName() == _autoInputMaskByClipPath) { + Q_EMIT d->m_platformHandle->autoInputMaskByClipPathChanged(); + } + } + } + + return false; +} + +static void initWindowRadius(QWindow *window) +{ + if (window->property(_windowRadius).isValid()) + return; + + auto theme = DGuiApplicationHelper::instance()->systemTheme(); + int radius = theme->windowRadius(18); //###(zccrs): 暂时在此处给窗口默认设置为18px的圆角 + + setWindowProperty(window, _windowRadius, radius); + // Qt::UniqueConnection will report a warning + // to `unique connections require a pointer to member function of a QObject subclass`. + const char *uniqueueConnectionFlag("_d_uniqueueConnectionFlag"); + bool connected = window->property(uniqueueConnectionFlag).toBool(); + if (!connected) { + window->setProperty(uniqueueConnectionFlag, true); + window->connect(theme, &DPlatformTheme::windowRadiusChanged, window, [window] (int radius) { + if (!resolved(window, PropRole::WindowRadius)) + setWindowProperty(window, _windowRadius, radius); + }); + } +} + +class Q_DECL_HIDDEN CreatorWindowEventFilter : public QObject { +public: + CreatorWindowEventFilter(QObject *par= nullptr): QObject(par){} + +public: + bool eventFilter(QObject *watched, QEvent *event) override { + if (event->type() == QEvent::PlatformSurface) { + QPlatformSurfaceEvent *se = static_cast(event); + if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { // 若收到此信号, 则 WinID 已被创建 + auto window = qobject_cast(watched); + initWindowRadius(window); + } + } + return QObject::eventFilter(watched, event); + } +}; + +bool DXCBPlatformWindowInterface::isEnabledNoTitlebar() const +{ + D_DC(DXCBPlatformWindowInterface); + QFunctionPointer is_enable_no_titlebar = nullptr; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + is_enable_no_titlebar = qApp->platformFunction(_isEnableNoTitlebar); +#endif + + if (is_enable_no_titlebar) { + return (*reinterpret_cast(is_enable_no_titlebar))(d->m_window); + } + + return false; +} + +bool DXCBPlatformWindowInterface::setEnabledNoTitlebar(bool enable) +{ + D_D(DXCBPlatformWindowInterface); + auto isDWaylandPlatform = [] { + return qApp->platformName() == "dwayland" || qApp->property("_d_isDwayland").toBool(); + }; + if (!(isDXcbPlatform() || isDWaylandPlatform() || DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform))) + return false; + + if (isEnabledNoTitlebar() == enable) + return true; + + QFunctionPointer enable_no_titlear = nullptr; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + enable_no_titlear = qApp->platformFunction(_setEnableNoTitlebar); +#endif + + if (enable_no_titlear) { + bool ok = (*reinterpret_cast(enable_no_titlear))(d->m_window, enable); + if (ok && enable) { + if (d->m_window->handle()) { + initWindowRadius(d->m_window); + } else { + d->m_window->installEventFilter(new CreatorWindowEventFilter(d->m_window)); + } + } + + return ok; + } + + return false; +} + +inline DPlatformHandle::WMBlurArea operator *(const DPlatformHandle::WMBlurArea &area, qreal scale) +{ + if (qFuzzyCompare(scale, 1.0)) + return area; + + DPlatformHandle::WMBlurArea new_area; + + new_area.x = qRound64(area.x * scale); + new_area.y = qRound64(area.y * scale); + new_area.width = qRound64(area.width * scale); + new_area.height = qRound64(area.height * scale); + new_area.xRadius = qRound64(area.xRadius * scale); + new_area.yRaduis = qRound64(area.yRaduis * scale); + + return new_area; +} + +/*! + \brief DXCBPlatformWindowInterface::setWindowBlurAreaByWM + 设置窗口背景的模糊区域,示例: + \code + QWindow w; + QVector area_list; + DXCBPlatformWindowInterface::WMBlurArea area; + + area.x = 50; + area.y = 50; + area.width = 200; + area.height = 200; + area.xRadius = 10; + area.yRaduis = 10; + area_list.append(area); + + DXCBPlatformWindowInterface::setWindowBlurAreaByWM(&w, area_list); + + QSurfaceFormat format = w.format(); + format.setAlphaBufferSize(8); + + w.setFormat(format); + w.resize(300, 300); + w.show(); + + \endcode + \image blur_window_demo1.png + \a window 目标窗口对象 + \a area 模糊区域,此区域范围内的窗口背景将填充为窗口后面内容模糊之后的图像 + \return 如果设置成功则返回 true,否则返回 false + \note 对于需要显示模糊背景的窗口,需要将其 QSurfaceFormat 的 alpha 通道设置为8 + \note 调用此接口设置窗口背景模糊区域后将覆盖之前所设置的区域,包括调用 + setWindowBlurAreaByWM(QWindow *, const QList &) + 所设置的区域 + \note 建议使用 DBlurEffectWidget 实现窗口背景模糊效果 + \note 此功能依赖于窗口管理器的实现,目前仅支持 deepin-wm 和 kwin 这两个窗口管理器 + \sa Dtk::Widget::DBlurEffectWidget + \sa QSurfaceFormat::setAlphaBufferSize + \sa QWindow::setFormat + \sa DWindowManagerHelper::hasBlurWindow + \sa DXCBPlatformWindowInterface::setWindowBlurAreaByWM(QWindow *, const QList &) + */ +bool DXCBPlatformWindowInterface::setWindowBlurArea(const QVector &area) +{ + D_D(DXCBPlatformWindowInterface); + + if (!d->m_window) { + return false; + } + + if (isEnabledDXcb()) { + QVector areas; + for (auto item : area) + areas << item.x << item.y << item.width << item.height << item.xRadius << item.yRaduis; + setWindowProperty(d->m_window, _windowBlurAreas, QVariant::fromValue(areas)); + return true; + } + + QFunctionPointer setWmBlurWindowBackgroundArea = Q_NULLPTR; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + setWmBlurWindowBackgroundArea = qApp->platformFunction(_setWmBlurWindowBackgroundArea); +#endif + + if (!setWmBlurWindowBackgroundArea) { + qWarning("setWindowBlurAreaByWM is not support"); + + return false; + } + + QSurfaceFormat format = d->m_window->format(); + + format.setAlphaBufferSize(8); + d->m_window->setFormat(format); + + const qreal device_ratio = d->m_window->devicePixelRatio(); + + if (qFuzzyCompare(device_ratio, 1.0)) { + return reinterpret_cast&)>(setWmBlurWindowBackgroundArea)(d->m_window->winId(), area); + } + + QVector new_areas; + + new_areas.reserve(area.size()); + + for (const DPlatformHandle::WMBlurArea &a : area) { + new_areas.append(a * device_ratio); + } + + return reinterpret_cast&)>(setWmBlurWindowBackgroundArea)(d->m_window->winId(), new_areas); +} + +inline QPainterPath operator *(const QPainterPath &path, qreal scale) +{ + if (qFuzzyCompare(1.0, scale)) + return path; + + QPainterPath new_path = path; + + for (int i = 0; i < path.elementCount(); ++i) { + const QPainterPath::Element &e = path.elementAt(i); + + new_path.setElementPositionAt(i, qRound(e.x * scale), qRound(e.y * scale)); + } + + return new_path; +} + +bool DXCBPlatformWindowInterface::setWindowBlurArea(const QList &paths) +{ + D_D(DXCBPlatformWindowInterface); + + if (!d->m_window) { + return false; + } + + if (isEnabledDXcb()) { + setWindowProperty(d->m_window, _windowBlurPaths, QVariant::fromValue(paths)); + + return true; + } + + QFunctionPointer setWmBlurWindowBackgroundPathList = Q_NULLPTR; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + setWmBlurWindowBackgroundPathList = qApp->platformFunction(_setWmBlurWindowBackgroundPathList); +#endif + + if (!setWmBlurWindowBackgroundPathList) { + qWarning("setWindowBlurAreaByWM is not support"); + + return false; + } + + QSurfaceFormat format = d->m_window->format(); + + format.setAlphaBufferSize(8); + d->m_window->setFormat(format); + + const qreal device_ratio = d->m_window->devicePixelRatio(); + + if (qFuzzyCompare(device_ratio, 1.0)) { + return reinterpret_cast&)>(setWmBlurWindowBackgroundPathList)(d->m_window->winId(), paths); + } + + QList new_paths; + + new_paths.reserve(paths.size()); + + for (const QPainterPath &p : paths) { + new_paths.append(p * device_ratio); + } + + return reinterpret_cast&)>(setWmBlurWindowBackgroundPathList)(d->m_window->winId(), new_paths); +} + +bool DXCBPlatformWindowInterface::setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode) +{ + D_D(DXCBPlatformWindowInterface); + + if (!d->m_window) { + return false; + } + + QFunctionPointer setWmWallpaperParameter = Q_NULLPTR; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + setWmWallpaperParameter = qApp->platformFunction(_setWmWallpaperParameter); +#endif + + if (!setWmWallpaperParameter) { + qWarning("setWindowWallpaperParaByWM is not support"); + + return false; + } + + QSurfaceFormat format = d->m_window->format(); + + format.setAlphaBufferSize(8); + d->m_window->setFormat(format); + + quint32 bMode = sMode | fMode; + + // 激活 backing store + d->m_window->setProperty("_d_dxcb_wallpaper", QVariant::fromValue(QPair(area, bMode))); + + if (!d->m_window->handle()) { + return true; + } else { + qWarning() << "because the window handle has been created, so 2D mode will have no effect"; + } + + const qreal device_ratio = d->m_window->devicePixelRatio(); + if (qFuzzyCompare(device_ratio, 1.0) || !area.isValid()) { + return reinterpret_cast(setWmWallpaperParameter)(d->m_window->winId(), area, bMode); + } + + QRect new_area(area.x() * device_ratio, + area.y() * device_ratio, + area.width() * device_ratio, + area.height() * device_ratio); + + return reinterpret_cast(setWmWallpaperParameter)(d->m_window->winId(), new_area, bMode); +} + +void DXCBPlatformWindowInterface::setDisableWindowOverrideCursor(bool disable) +{ + D_D(DXCBPlatformWindowInterface); + + d->m_window->setProperty(_disableOverrideCursor, disable); +} + +int DXCBPlatformWindowInterface::windowRadius() const +{ + D_DC(DXCBPlatformWindowInterface); + + return d->m_window->property(_windowRadius).toInt(); +} + +void DXCBPlatformWindowInterface::setWindowRadius(int windowRadius) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _windowRadius, windowRadius); + resolve(d->m_window, PropRole::WindowRadius); +} + +int DXCBPlatformWindowInterface::borderWidth() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_borderWidth).toInt(); +} + +void DXCBPlatformWindowInterface::setBorderWidth(int borderWidth) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _borderWidth, borderWidth); +} + +QColor DXCBPlatformWindowInterface::borderColor() const +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property(_borderColor)); +} + +void DXCBPlatformWindowInterface::setBorderColor(const QColor &borderColor) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _borderColor, QVariant::fromValue(borderColor)); +} + +int DXCBPlatformWindowInterface::shadowRadius() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_shadowRadius).toInt(); +} + +void DXCBPlatformWindowInterface::setShadowRadius(int shadowRadius) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _shadowRadius, shadowRadius); +} + +QPoint DXCBPlatformWindowInterface::shadowOffset() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_shadowOffset).toPoint(); +} + +void DXCBPlatformWindowInterface::setShadowOffset(const QPoint &shadowOffset) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _shadowOffset, shadowOffset); +} + +QColor DXCBPlatformWindowInterface::shadowColor() const +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property(_shadowColor)); +} + +void DXCBPlatformWindowInterface::setShadowColor(const QColor &shadowColor) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _shadowColor, QVariant::fromValue(shadowColor)); +} + +DPlatformHandle::EffectScene DXCBPlatformWindowInterface::windowEffect() +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property(_windowEffect)); +} + +void DXCBPlatformWindowInterface::setWindowEffect(DPlatformHandle::EffectScenes effectScene) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _windowEffect, static_cast(effectScene)); +} + +DPlatformHandle::EffectType DXCBPlatformWindowInterface::windowStartUpEffect() +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property(_windowStartUpEffect)); +} + +void DXCBPlatformWindowInterface::setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _windowStartUpEffect, static_cast(effectType)); +} + +QPainterPath DXCBPlatformWindowInterface::clipPath() const +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property(_clipPath)); +} + +void DXCBPlatformWindowInterface::setClipPath(const QPainterPath &clipPath) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _clipPath, QVariant::fromValue(clipPath)); +} + +QRegion DXCBPlatformWindowInterface::frameMask() const +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property(_frameMask)); +} + +void DXCBPlatformWindowInterface::setFrameMask(const QRegion &frameMask) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _frameMask, QVariant::fromValue(frameMask)); +} + +QMargins DXCBPlatformWindowInterface::frameMargins() const +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property(_frameMargins)); +} + +bool DXCBPlatformWindowInterface::translucentBackground() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_translucentBackground).toBool(); +} + +void DXCBPlatformWindowInterface::setTranslucentBackground(bool translucentBackground) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _translucentBackground, translucentBackground); +} + +bool DXCBPlatformWindowInterface::enableSystemResize() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_enableSystemResize).toBool(); +} + +void DXCBPlatformWindowInterface::setEnableSystemResize(bool enableSystemResize) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _enableSystemResize, enableSystemResize); +} + +bool DXCBPlatformWindowInterface::enableSystemMove() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_enableSystemMove).toBool(); +} + +void DXCBPlatformWindowInterface::setEnableSystemMove(bool enableSystemMove) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _enableSystemMove, enableSystemMove); +} + +bool DXCBPlatformWindowInterface::enableBlurWindow() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_enableBlurWindow).toBool(); +} + +void DXCBPlatformWindowInterface::setEnableBlurWindow(bool enableBlurWindow) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _enableBlurWindow, enableBlurWindow); +} + +bool DXCBPlatformWindowInterface::autoInputMaskByClipPath() const +{ + D_DC(DXCBPlatformWindowInterface); + return d->m_window->property(_autoInputMaskByClipPath).toBool(); +} + +void DXCBPlatformWindowInterface::setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) +{ + D_D(DXCBPlatformWindowInterface); + setWindowProperty(d->m_window, _autoInputMaskByClipPath, autoInputMaskByClipPath); +} + +WId DXCBPlatformWindowInterface::realWindowId() const +{ + D_DC(DXCBPlatformWindowInterface); + return qvariant_cast(d->m_window->property("_d_real_content_window")); +} + +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/xcb/dxcbplatformwindowinterface.h b/src/plugins/platform/xcb/dxcbplatformwindowinterface.h new file mode 100644 index 0000000..3edf0ab --- /dev/null +++ b/src/plugins/platform/xcb/dxcbplatformwindowinterface.h @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DXCBPLATFORMWINDOWINTERFACE_H +#define DXCBPLATFORMWINDOWINTERFACE_H + +#include "private/dplatformwindowinterface_p.h" + +#include + +DGUI_BEGIN_NAMESPACE + +class DXCBPlatformWindowInterfacePrivate; +class DXCBPlatformWindowInterface : public DPlatformWindowInterface +{ + Q_OBJECT + D_DECLARE_PRIVATE(DXCBPlatformWindowInterface) +public: + explicit DXCBPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent); + ~DXCBPlatformWindowInterface(); + + static QString pluginVersion(); + static bool isDXcbPlatform(); + static bool connectWindowManagerChangedSignal(QObject *object, std::function slot); + static bool connectHasBlurWindowChanged(QObject *object, std::function slot); + static WId windowLeader(); + + void enableDXcb(); + void enableDXcb(bool redirectContent); + bool isEnabledDXcb(); + bool eventFilterForXcb(QObject *obj, QEvent *event); + + bool setWindowBlurArea(const QVector &area) override; + bool setWindowBlurArea(const QList &paths) override; + bool setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode) override; + + void setDisableWindowOverrideCursor(bool disable) override; + + bool isEnabledNoTitlebar() const override; + bool setEnabledNoTitlebar(bool enable) override; + + int windowRadius() const override; + void setWindowRadius(int windowRadius) override; + + int borderWidth() const override; + void setBorderWidth(int borderWidth) override; + + QColor borderColor() const override; + void setBorderColor(const QColor &borderColor) override; + + int shadowRadius() const override; + void setShadowRadius(int shadowRadius) override; + + QPoint shadowOffset() const override; + void setShadowOffset(const QPoint &shadowOffset) override; + + QColor shadowColor() const override; + void setShadowColor(const QColor &shadowColor) override; + + DPlatformHandle::EffectScene windowEffect() override; + void setWindowEffect(DPlatformHandle::EffectScenes effectScene) override; + + DPlatformHandle::EffectType windowStartUpEffect() override; + void setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) override; + + QPainterPath clipPath() const override; + void setClipPath(const QPainterPath &clipPath) override; + + QRegion frameMask() const override; + void setFrameMask(const QRegion &frameMask) override; + + QMargins frameMargins() const override; + + bool translucentBackground() const override; + void setTranslucentBackground(bool translucentBackground) override; + + bool enableSystemResize() const override; + void setEnableSystemResize(bool enableSystemResize) override; + + bool enableSystemMove() const override; + void setEnableSystemMove(bool enableSystemMove) override; + + bool enableBlurWindow() const override; + void setEnableBlurWindow(bool enableBlurWindow) override; + + bool autoInputMaskByClipPath() const override; + void setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) override; + + WId realWindowId() const override; +}; + +DGUI_END_NAMESPACE +#endif // DXCBPLATFORMWINDOWINTERFACE_H diff --git a/src/plugins/platform/xcb/dxcbplatformwindowinterface_p.h b/src/plugins/platform/xcb/dxcbplatformwindowinterface_p.h new file mode 100644 index 0000000..8497a74 --- /dev/null +++ b/src/plugins/platform/xcb/dxcbplatformwindowinterface_p.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DXCBPLATFORMWINDOWINTERFACE_P_H +#define DXCBPLATFORMWINDOWINTERFACE_P_H + +#include "dplatformwindowinterface_p_p.h" +#include "dxcbplatformwindowinterface.h" + +DGUI_BEGIN_NAMESPACE + +class DXCBPlatformWindowInterfacePrivate : public DPlatformWindowInterfacePrivate +{ +public: + D_DECLARE_PUBLIC(DXCBPlatformWindowInterface) + DXCBPlatformWindowInterfacePrivate(DXCBPlatformWindowInterface *qq); +}; + +DGUI_END_NAMESPACE + +#endif // DXCBPLATFORMWINDOWINTERFACE_P_H diff --git a/src/private/dplatformwindowinterface_p.h b/src/private/dplatformwindowinterface_p.h new file mode 100644 index 0000000..d627365 --- /dev/null +++ b/src/private/dplatformwindowinterface_p.h @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DPLATFORMWINDOWINTERFACE_P_H +#define DPLATFORMWINDOWINTERFACE_P_H + +#include +#include + +#include "dtkgui_global.h" +#include "dplatformhandle.h" + +DGUI_BEGIN_NAMESPACE + +class DPlatformWindowInterfacePrivate; +class LIBDTKCORESHARED_EXPORT DPlatformWindowInterface : public QObject, public DCORE_NAMESPACE::DObject +{ + Q_OBJECT + D_DECLARE_PRIVATE(DPlatformWindowInterface) +public: + explicit DPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent=nullptr); + virtual ~DPlatformWindowInterface(); + + QWindow* window() const; + + virtual bool setWindowBlurArea(const QVector &area); + virtual bool setWindowBlurArea(const QList &paths); + virtual bool setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode); + + virtual bool isEnabledNoTitlebar() const; + virtual bool setEnabledNoTitlebar(bool enable); + + virtual void setDisableWindowOverrideCursor(bool disable); + + virtual int windowRadius() const; + virtual void setWindowRadius(int windowRadius); + + virtual int borderWidth() const; + virtual void setBorderWidth(int borderWidth); + + virtual QColor borderColor() const; + virtual void setBorderColor(const QColor &borderColor); + + virtual int shadowRadius() const; + virtual void setShadowRadius(int shadowRadius); + + virtual QPoint shadowOffset() const; + virtual void setShadowOffset(const QPoint &shadowOffset); + + virtual QColor shadowColor() const; + virtual void setShadowColor(const QColor &shadowColor); + + virtual DPlatformHandle::EffectScene windowEffect(); + virtual void setWindowEffect(DPlatformHandle::EffectScenes effectScene); + + virtual DPlatformHandle::EffectType windowStartUpEffect(); + virtual void setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType); + + virtual QPainterPath clipPath() const; + virtual void setClipPath(const QPainterPath &clipPath); + + virtual QRegion frameMask() const; + virtual void setFrameMask(const QRegion &frameMask); + + virtual QMargins frameMargins() const; + + virtual bool translucentBackground() const; + virtual void setTranslucentBackground(bool translucentBackground); + + virtual bool enableSystemResize() const; + virtual void setEnableSystemResize(bool enableSystemResize); + + virtual bool enableSystemMove() const; + virtual void setEnableSystemMove(bool enableSystemMove); + + virtual bool enableBlurWindow() const; + virtual void setEnableBlurWindow(bool enableBlurWindow); + + virtual bool autoInputMaskByClipPath() const; + virtual void setAutoInputMaskByClipPath(bool autoInputMaskByClipPath); + + virtual WId realWindowId() const; + +protected: + DPlatformWindowInterface(DPlatformWindowInterfacePrivate &dd, QWindow *window, DPlatformHandle *handle, QObject *parent); +}; + +class LIBDTKCORESHARED_EXPORT DPlatformWindowInterfaceFactory { +public: + using HelperCreator = DPlatformWindowInterface * (*)(QWindow *, DPlatformHandle*); + static void registerInterface(HelperCreator creator); +}; + +DGUI_END_NAMESPACE +#endif // DPLATFORMWINDOWINTERFACE_P_H + diff --git a/src/private/dplatformwindowinterface_p_p.h b/src/private/dplatformwindowinterface_p_p.h new file mode 100644 index 0000000..98e421b --- /dev/null +++ b/src/private/dplatformwindowinterface_p_p.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DPLATFORMINTERFACE_P_P_H +#define DPLATFORMINTERFACE_P_P_H + +#include "dplatformwindowinterface_p.h" + +#include +#include + +class QWindow; + +DGUI_BEGIN_NAMESPACE + +class DPlatformWindowInterfacePrivate : public DCORE_NAMESPACE::DObjectPrivate +{ + D_DECLARE_PUBLIC(DPlatformWindowInterface) +public: + DPlatformWindowInterfacePrivate(DPlatformWindowInterface *qq); + +public: + QWindow *m_window = nullptr; + DPlatformHandle *m_platformHandle = nullptr; +}; + +DGUI_END_NAMESPACE + +#endif // DPLATFORMINTERFACE_P_P_H diff --git a/src/private/private.cmake b/src/private/private.cmake index 6ca2ce9..856e00d 100644 --- a/src/private/private.cmake +++ b/src/private/private.cmake @@ -8,4 +8,5 @@ set(private_SRC ${CMAKE_CURRENT_LIST_DIR}/dtaskbarcontrol_p.h ${CMAKE_CURRENT_LIST_DIR}/dfontmanager_p.h ${CMAKE_CURRENT_LIST_DIR}/dplatforminterface_p.h + ${CMAKE_CURRENT_LIST_DIR}/dplatformwindowinterface_p.h )