From 2a8f8a234602fc7a131e70aeb76e61f2b3422c26 Mon Sep 17 00:00:00 2001 From: Tsic Liu Date: Tue, 29 Oct 2024 20:04:53 +0800 Subject: [PATCH] feat: treeland weak area implement log: as title --- panels/dock/CMakeLists.txt | 3 + panels/dock/dockhelper.cpp | 216 +++++++++++++++++++++++++++++- panels/dock/dockhelper.h | 48 ++++++- panels/dock/dockpanel.cpp | 14 +- panels/dock/waylanddockhelper.cpp | 120 +++++++++++++++-- panels/dock/waylanddockhelper.h | 55 +++++++- panels/dock/x11dockhelper.cpp | 23 +--- panels/dock/x11dockhelper.h | 6 +- 8 files changed, 430 insertions(+), 55 deletions(-) diff --git a/panels/dock/CMakeLists.txt b/panels/dock/CMakeLists.txt index e82c732cc..1318717d2 100644 --- a/panels/dock/CMakeLists.txt +++ b/panels/dock/CMakeLists.txt @@ -64,11 +64,14 @@ add_library(dockpanel SHARED qt_generate_wayland_protocol_client_sources(dockpanel FILES ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-wallpaper-color-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-dde-shell-v1.xml ) target_link_libraries(dockpanel PRIVATE PkgConfig::WaylandClient Qt${QT_VERSION_MAJOR}::WaylandClient + Qt${QT_VERSION_MAJOR}::WaylandClientPrivate + Qt${QT_VERSION_MAJOR}::Widgets dde-shell-frame ) diff --git a/panels/dock/dockhelper.cpp b/panels/dock/dockhelper.cpp index 40a662f63..d42d99f16 100644 --- a/panels/dock/dockhelper.cpp +++ b/panels/dock/dockhelper.cpp @@ -3,21 +3,225 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "dockhelper.h" +#include "constants.h" #include "dockpanel.h" -#include "dsglobal.h" #include -namespace dock { - -DockHelper::DockHelper(DockPanel* parent) +namespace dock +{ +DockHelper::DockHelper(DockPanel *parent) : QObject(parent) - , m_panel(parent) + , m_hideTimer(new QTimer(this)) + , m_showTimer(new QTimer(this)) +{ + m_hideTimer->setInterval(400); + m_showTimer->setInterval(400); + m_hideTimer->setSingleShot(true); + m_showTimer->setSingleShot(true); + + connect(m_hideTimer, &QTimer::timeout, this, [this, parent]() { + if (parent->hideMode() == KeepShowing) + return; + + for (auto enter : m_enters) { + if (enter) + return; + } + + parent->setHideState(Hide); + }); + + connect(m_showTimer, &QTimer::timeout, this, [this, parent]() { + bool res = false; + for (auto enter : m_enters) { + res |= enter; + } + + if (res) + parent->setHideState(Show); + }); + + auto initAreas = [this, parent]() { + // clear old area + for (auto area : m_areas) { + area->close(); + delete area; + } + + m_areas.clear(); + qApp->disconnect(this); + + if (!parent->rootObject()) + return; + + // init areas + for (auto screen : qApp->screens()) { + m_areas.insert(screen, createArea(screen)); + } + + connect(qApp, &QGuiApplication::screenAdded, this, [this](QScreen *screen) { + if (m_areas.contains(screen)) + return; + m_areas.insert(screen, createArea(screen)); + }); + + connect(qApp, &QGuiApplication::screenRemoved, this, [this](QScreen *screen) { + if (!m_areas.contains(screen)) + return; + + destroyArea(m_areas.value(screen)); + m_areas.remove(screen); + }); + + // init state + updateAllDockWakeArea(); + }; + + connect(parent, &DockPanel::rootObjectChanged, this, initAreas); + connect(parent, &DockPanel::showInPrimaryChanged, this, &DockHelper::updateAllDockWakeArea); + connect(parent, &DockPanel::hideStateChanged, this, &DockHelper::updateAllDockWakeArea); + connect(parent, &DockPanel::positionChanged, this, [this](Position pos) { + for (auto area : m_areas) { + if (!area) + continue; + + area->updateDockWakeArea(pos); + } + }); + + qApp->installEventFilter(this); + QMetaObject::invokeMethod(this, initAreas); +} + +bool DockHelper::eventFilter(QObject *watched, QEvent *event) +{ + if (!watched->isWindowType()) { + return false; + } + + auto window = static_cast(watched); + if (!window) { + return false; + } + + switch (event->type()) { + case QEvent::Enter: { + m_enters.insert(window, true); + if (m_hideTimer->isActive()) { + m_hideTimer->stop(); + } + + m_showTimer->start(); + break; + } + case QEvent::Leave: { + m_enters.insert(window, false); + if (m_showTimer->isActive()) { + m_showTimer->stop(); + } + + m_hideTimer->start(); + break; + } + + case QEvent::Hide: { + m_enters.remove(window); + break; + } + default: { + } + } + + return false; +} + +bool DockHelper::wakeUpAreaNeedShowOnThisScreen(QScreen *screen) +{ + auto isDockAllowedShownOnThisScreen = [this, screen]() -> bool { + return (parent()->showInPrimary() && screen == qApp->primaryScreen()) || !parent()->showInPrimary(); + }; + + auto isDockShownThisScreen = [this, screen]() -> bool { + return parent()->dockScreen() == screen && parent()->hideState() == Show; + }; + + return (isDockAllowedShownOnThisScreen() && !isDockShownThisScreen()); +} + +void DockHelper::enterScreen(QScreen *screen) +{ + auto nowScreen = parent()->dockScreen(); + + if (nowScreen == screen) { + parent()->setHideState(Show); + return; + } + + QTimer::singleShot(200, [this, screen]() { + parent()->setDockScreen(screen); + parent()->setHideState(Show); + updateAllDockWakeArea(); + }); +} + +void DockHelper::leaveScreen() +{ + m_hideTimer->start(); +} + +DockWakeUpArea *DockHelper::createArea(QScreen *screen) { + return new DockWakeUpArea(screen, this); +} + +void DockHelper::destroyArea(DockWakeUpArea *area) +{ + if (area) { + area->close(); + delete area; + } +} + +void DockHelper::updateAllDockWakeArea() +{ + for (auto screen : m_areas.keys()) { + auto area = m_areas.value(screen); + if (nullptr == area) + continue; + + area->updateDockWakeArea(parent()->position()); + if (wakeUpAreaNeedShowOnThisScreen(screen)) { + area->open(); + } else { + area->close(); + } + } } DockPanel* DockHelper::parent() { - return m_panel; + return static_cast(QObject::parent()); +} + +DockWakeUpArea::DockWakeUpArea(QScreen *screen, DockHelper *helper) + : m_screen(screen) + , m_helper(helper) +{ +} + +void DockWakeUpArea::open() +{ + qDebug() << "create wake up area at " << m_screen->name(); +} + +void DockWakeUpArea::close() +{ + qDebug() << "close wake up area at " << m_screen->name(); +} + +void DockWakeUpArea::updateDockWakeArea(Position pos) +{ + qDebug() << "update wake up area pos to " << pos; } } diff --git a/panels/dock/dockhelper.h b/panels/dock/dockhelper.h index 9becdec79..a97cabb26 100644 --- a/panels/dock/dockhelper.h +++ b/panels/dock/dockhelper.h @@ -4,35 +4,69 @@ #pragma once +#include "constants.h" #include "dockpanel.h" -#include "dsglobal.h" #include - namespace dock { +class DockWakeUpArea; class DockHelper : public QObject { Q_OBJECT - Q_PROPERTY(HideState hideState READ hideState NOTIFY hideStateChanged FINAL) public: [[nodiscard]] DockHelper* getHelper(DockPanel* parent); - virtual HideState hideState() = 0; + virtual HideState hideState() + { + return Show; + } -Q_SIGNALS: - void hideStateChanged(); + bool eventFilter(QObject *watched, QEvent *event) override; public Q_SLOTS: + void enterScreen(QScreen *screen); + void leaveScreen(); + virtual void updateDockTriggerArea() = 0; +Q_SIGNALS: + void hideStateChanged(); + +protected: + bool wakeUpAreaNeedShowOnThisScreen(QScreen *screen); + [[nodiscard]] virtual DockWakeUpArea *createArea(QScreen *screen); + virtual void destroyArea(DockWakeUpArea *area); + +private: + void updateAllDockWakeArea(); + protected: DockHelper(DockPanel* parent); DockPanel* parent(); private: - DockPanel* m_panel; + QHash m_areas; + QHash m_enters; + QTimer *m_hideTimer; + QTimer *m_showTimer; +}; + +class DockWakeUpArea +{ +public: + virtual void open(); + virtual void close(); + +protected: + explicit DockWakeUpArea(QScreen *screen, DockHelper *helper); + virtual void updateDockWakeArea(Position pos); + +protected: + friend class DockHelper; + QScreen *m_screen; + DockHelper *m_helper; }; } diff --git a/panels/dock/dockpanel.cpp b/panels/dock/dockpanel.cpp index 240b0406d..7642ad31c 100644 --- a/panels/dock/dockpanel.cpp +++ b/panels/dock/dockpanel.cpp @@ -2,15 +2,14 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -#include "panel.h" -#include "constants.h" #include "dockpanel.h" +#include "constants.h" #include "dockadaptor.h" -#include "environments.h" #include "docksettings.h" +#include "panel.h" #include "pluginfactory.h" -#include "x11dockhelper.h" #include "waylanddockhelper.h" +#include "x11dockhelper.h" // for old api compatible #include "dockdbusproxy.h" @@ -101,6 +100,7 @@ bool DockPanel::init() connect(SETTINGS, &DockSettings::showInPrimaryChanged, this, [this, dockDaemonAdaptor](){ updateDockScreen(); Q_EMIT dockDaemonAdaptor->FrontendWindowRectChanged(frontendWindowRect()); + Q_EMIT showInPrimaryChanged(showInPrimary()); }); connect(this, &DockPanel::frontendWindowRectChanged, dockDaemonAdaptor, &DockDaemonAdaptor::FrontendWindowRectChanged); @@ -126,7 +126,7 @@ bool DockPanel::init() QObject::connect(this, &DApplet::rootObjectChanged, this, [this]() { if (rootObject()) { // those connections need connect after DPanel::init() which create QQuickWindow - // xChanged yChanged not woker on wayland, so use above positionChanged instead + // xChanged yChanged not worked on wayland, so use above positionChanged instead // connect(window(), &QQuickWindow::xChanged, this, &DockPanel::onWindowGeometryChanged); // connect(window(), &QQuickWindow::yChanged, this, &DockPanel::onWindowGeometryChanged); connect(window(), &QQuickWindow::widthChanged, this, &DockPanel::onWindowGeometryChanged); @@ -134,6 +134,9 @@ bool DockPanel::init() QMetaObject::invokeMethod(this, &DockPanel::onWindowGeometryChanged); if (showInPrimary()) updateDockScreen(); + else { + m_dockScreen = window()->screen(); + } } }); @@ -369,7 +372,6 @@ void DockPanel::setShowInPrimary(bool newShowInPrimary) connect(qApp, &QGuiApplication::primaryScreenChanged, this, &DockPanel::updateDockScreen, Qt::UniqueConnection); else disconnect(qApp, &QGuiApplication::primaryScreenChanged, this, &DockPanel::updateDockScreen); - Q_EMIT showInPrimaryChanged(showInPrimary()); } D_APPLET_CLASS(DockPanel) diff --git a/panels/dock/waylanddockhelper.cpp b/panels/dock/waylanddockhelper.cpp index ffcd5448d..2f1685066 100644 --- a/panels/dock/waylanddockhelper.cpp +++ b/panels/dock/waylanddockhelper.cpp @@ -4,7 +4,14 @@ #include "waylanddockhelper.h" #include "constants.h" +#include "dockhelper.h" #include "dockpanel.h" +#include "layershell/dlayershellwindow.h" +#include "wayland-treeland-dde-shell-v1-client-protocol.h" + +#include +#include +#include namespace dock { WaylandDockHelper::WaylandDockHelper(DockPanel *panel) @@ -17,10 +24,6 @@ WaylandDockHelper::WaylandDockHelper(DockPanel *panel) m_wallpaperColorManager->watchScreen(dockScreenName()); }); - connect(m_panel, &DockPanel::dockScreenChanged, this, [this]() { - m_wallpaperColorManager->watchScreen(dockScreenName()); - }); - connect(m_wallpaperColorManager.get(), &WallpaperColorManager::activeChanged, this, [this]() { if (m_panel->rootObject() != nullptr) { m_wallpaperColorManager->watchScreen(dockScreenName()); @@ -32,14 +35,13 @@ WaylandDockHelper::WaylandDockHelper(DockPanel *panel) } } -void WaylandDockHelper::updateDockTriggerArea() +DockWakeUpArea *WaylandDockHelper::createArea(QScreen *screen) { - + return new TreeLandDockWakeUpArea(screen, this, m_panel); } -HideState WaylandDockHelper::hideState() +void WaylandDockHelper::updateDockTriggerArea() { - return Show; } QString WaylandDockHelper::dockScreenName() @@ -74,4 +76,106 @@ void WallpaperColorManager::watchScreen(const QString &screeName) watch(screeName); } } + +TreeLandDDEShellManager::TreeLandDDEShellManager() + : QWaylandClientExtensionTemplate(treeland_dde_shell_manager_v1_interface.version) +{ +} + +TreeLandWindowOverlapChecker::TreeLandWindowOverlapChecker(QtWaylandClient::QWaylandWindow *window, struct ::treeland_window_overlap_checker *checker) + : QWaylandClientExtensionTemplate(treeland_dde_shell_manager_v1_interface.version) +{ + init(checker); + auto waylandScreen = dynamic_cast(window->window()->screen()->handle()); + update(100, 100, anchor_right | anchor_left | anchor_bottom, waylandScreen->output()); +} + +void TreeLandWindowOverlapChecker::treeland_window_overlap_checker_enter() +{ +} + +void TreeLandWindowOverlapChecker::treeland_window_overlap_checker_leave() +{ +} + +TreeLandDockWakeUpArea::TreeLandDockWakeUpArea(QScreen *screen, WaylandDockHelper *helper, DockPanel *panel) + : QWidget() + , DockWakeUpArea(screen, helper) +{ + winId(); + window()->setScreen(screen); + window()->resize(QSize(15, 15)); + + auto window = ds::DLayerShellWindow::get(windowHandle()); + window->setLayer(ds::DLayerShellWindow::LayerOverlay); + window->setAnchors({ds::DLayerShellWindow::AnchorBottom | ds::DLayerShellWindow::AnchorLeft | ds::DLayerShellWindow::AnchorRight}); + window->setExclusiveZone(-1); +} + +void TreeLandDockWakeUpArea::open() +{ + show(); +} + +void TreeLandDockWakeUpArea::close() +{ + hide(); +} + +void TreeLandDockWakeUpArea::updateDockWakeArea(Position pos) +{ + m_pos = pos; + ds::DLayerShellWindow::Anchors anchors = {0 | ds::DLayerShellWindow::AnchorNone}; + switch (pos) { + case Top: { + anchors = {ds::DLayerShellWindow::AnchorLeft | ds::DLayerShellWindow::AnchorRight | ds::DLayerShellWindow::AnchorTop}; + break; + } + case Right: { + anchors = {ds::DLayerShellWindow::AnchorRight | ds::DLayerShellWindow::AnchorTop | ds::DLayerShellWindow::AnchorBottom}; + break; + } + case Bottom: { + anchors = {ds::DLayerShellWindow::AnchorLeft | ds::DLayerShellWindow::AnchorRight | ds::DLayerShellWindow::AnchorBottom}; + break; + } + case Left: { + anchors = {ds::DLayerShellWindow::AnchorLeft | ds::DLayerShellWindow::AnchorTop | ds::DLayerShellWindow::AnchorBottom}; + break; + } + } + + window()->resize(QSize(15, 15)); + auto window = ds::DLayerShellWindow::get(windowHandle()); + window->setAnchors(anchors); +} + +TreeLandWindowOverlapChecker::~TreeLandWindowOverlapChecker() +{ + destroy(); +} + +void TreeLandDockWakeUpArea::enterEvent(QEnterEvent *event) +{ + m_helper->enterScreen(screen()); +} + +void TreeLandDockWakeUpArea::leaveEvent(QEvent *event) +{ + m_helper->leaveScreen(); +} + +void TreeLandDockWakeUpArea::resizeEvent(QResizeEvent *event) +{ + auto size = event->size(); + if (m_pos == Left || m_pos == Right) { + size.setHeight(m_screen->size().height()); + size.setWidth(15); + } else { + size.setHeight(15); + size.setWidth(m_screen->size().width()); + } + + window()->resize(size); +} } diff --git a/panels/dock/waylanddockhelper.h b/panels/dock/waylanddockhelper.h index 10342577a..8c0613acf 100644 --- a/panels/dock/waylanddockhelper.h +++ b/panels/dock/waylanddockhelper.h @@ -1,26 +1,35 @@ // SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later +#pragma once +#include "constants.h" #include "dockhelper.h" #include "dockpanel.h" +#include "qwayland-treeland-dde-shell-v1.h" #include "qwayland-treeland-wallpaper-color-v1.h" +#include + #include +#include namespace dock { class WallpaperColorManager; +class TreeLandDockTriggerArea; class WaylandDockHelper : public DockHelper { Q_OBJECT public: - WaylandDockHelper(DockPanel* panel); - HideState hideState() override; + WaylandDockHelper(DockPanel *panel); void setDockColorTheme(const ColorTheme &theme); QString dockScreenName(); +protected: + [[nodiscard]] virtual DockWakeUpArea *createArea(QScreen *screen) override; + public Q_SLOTS: void updateDockTriggerArea() override; @@ -44,4 +53,46 @@ class WallpaperColorManager : public QWaylandClientExtensionTemplate, public QtWayland::treeland_dde_shell_manager_v1 +{ + Q_OBJECT + +public: + explicit TreeLandDDEShellManager(); +}; + +class TreeLandWindowOverlapChecker : public QWaylandClientExtensionTemplate, public QtWayland::treeland_window_overlap_checker +{ + Q_OBJECT + +public: + TreeLandWindowOverlapChecker(QtWaylandClient::QWaylandWindow *window, struct ::treeland_window_overlap_checker *); + ~TreeLandWindowOverlapChecker(); + +protected: + void treeland_window_overlap_checker_enter() override; + void treeland_window_overlap_checker_leave() override; +}; + +class TreeLandDockWakeUpArea : public QWidget, public DockWakeUpArea +{ + Q_OBJECT +public: + explicit TreeLandDockWakeUpArea(QScreen *screen, WaylandDockHelper *helper, DockPanel *panel); + +public: + void open() override; + void close() override; + + void updateDockWakeArea(Position pos) override; + +protected: + void enterEvent(QEnterEvent *event) override; + void leaveEvent(QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + +private: + Position m_pos; +}; } diff --git a/panels/dock/x11dockhelper.cpp b/panels/dock/x11dockhelper.cpp index 2f1787ec3..0974d62c4 100644 --- a/panels/dock/x11dockhelper.cpp +++ b/panels/dock/x11dockhelper.cpp @@ -2,10 +2,9 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +#include "x11dockhelper.h" #include "constants.h" -#include "dsglobal.h" #include "dockpanel.h" -#include "x11dockhelper.h" #include #include @@ -363,16 +362,6 @@ X11DockHelper::X11DockHelper(DockPanel* panel) connect(panel, &DockPanel::geometryChanged, this, &X11DockHelper::updateDockArea); connect(panel, &DockPanel::showInPrimaryChanged, this, &X11DockHelper::updateDockArea); connect(panel, &DockPanel::dockScreenChanged, this, &X11DockHelper::updateDockArea); - connect(panel, &DockPanel::rootObjectChanged, this, [ this, panel ] { - connect(panel->window(), &QWindow::visibleChanged, this, &X11DockHelper::updateWindowState, Qt::UniqueConnection); - updateWindowState(); - }); - - if (panel->rootObject()) { - connect(panel->window(), &QWindow::visibleChanged, this, &X11DockHelper::updateWindowState, Qt::UniqueConnection); - updateDockArea(); - updateWindowState(); - } qGuiApp->installNativeEventFilter(m_xcbHelper); onHideModeChanged(panel->hideMode()); @@ -565,16 +554,6 @@ void X11DockHelper::updateDockArea() } } -void X11DockHelper::updateWindowState() -{ - if (parent()->window()->isVisible()) { - xcb_atom_t atoms[] = { - m_xcbHelper->getAtomByName("_NET_WM_STATE_ABOVE") - }; - m_xcbHelper->setWindowState(parent()->window()->winId(), sizeof(atoms) / sizeof(atoms[0]), atoms); - } -} - HideState X11DockHelper::hideState() { return m_hideState; diff --git a/panels/dock/x11dockhelper.h b/panels/dock/x11dockhelper.h index dc1aa2a33..883a19860 100644 --- a/panels/dock/x11dockhelper.h +++ b/panels/dock/x11dockhelper.h @@ -1,13 +1,12 @@ // SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #include "dockhelper.h" -#include "dsglobal.h" #include -#include #include - +#include namespace dock { class X11DockHelper; @@ -116,7 +115,6 @@ private Q_SLOTS: void updateDockHideState(); void delayedUpdateState(); void updateDockArea(); - void updateWindowState(); private: inline void updateWakeArea();