diff --git a/src/core/qml/Decoration.qml b/src/core/qml/Decoration.qml index ad421e5ef..37940f973 100644 --- a/src/core/qml/Decoration.qml +++ b/src/core/qml/Decoration.qml @@ -10,7 +10,6 @@ Item { id: root required property SurfaceWrapper surface - readonly property SurfaceItem surfaceItem: surface.surfaceItem visible: surface && surface.visibleDecoration && surface.visible x: shadow.boundingRect.x @@ -19,7 +18,9 @@ Item { height: shadow.boundingRect.height MouseArea { - enabled: surface.type !== SurfaceWrapper.Type.XdgPopup && surface.type !== SurfaceWrapper.Type.Layer + enabled: surface.type !== SurfaceWrapper.Type.XdgPopup + && surface.type !== SurfaceWrapper.Type.Layer + && surface.type !== SurfaceWrapper.Type.Undetermined property int edges: 0 anchors { @@ -73,7 +74,7 @@ Item { Border { visible: surface.visibleDecoration - parent: surfaceItem + parent: surface.surfaceItem ? surface.surfaceItem : surface.prelaunchSplash z: SurfaceItem.ZOrder.ContentItem + 1 anchors.fill: parent radius: surface.radius diff --git a/src/core/qml/PrelaunchSplash.qml b/src/core/qml/PrelaunchSplash.qml index 05c161ce8..0de3deaec 100644 --- a/src/core/qml/PrelaunchSplash.qml +++ b/src/core/qml/PrelaunchSplash.qml @@ -9,18 +9,19 @@ import QtQuick.Controls Item { id: splash - property string logoPath: "" + required property string logoPath + required property real initialRadius property bool destroyAfterFade: false + signal destroyRequested // Fill the entire parent (SurfaceWrapper) anchors.fill: parent Rectangle { - radius: 10 // TODO: use Decoration's radius id: background color: "#ffffff" - // Fill parent; size is dictated by parent anchors.fill: parent + radius: initialRadius // Centered logo Image { @@ -55,12 +56,14 @@ Item { target: splash from: 1.0 to: 0.0 - duration: 500 + duration: 400 onFinished: { splash.visible = false if (splash.destroyAfterFade) { - splash.destroy(); + // Request C++ side to destroy this item to avoid calling destroy() + // on an object owned by C++. + splash.destroyRequested(); } } } diff --git a/src/core/qmlengine.cpp b/src/core/qmlengine.cpp index fe74c2f9a..64940eb6d 100644 --- a/src/core/qmlengine.cpp +++ b/src/core/qmlengine.cpp @@ -244,11 +244,10 @@ QQuickItem *QmlEngine::createWindowPicker(QQuickItem *parent) return createComponent(windowPickerComponent, parent); } -QQuickItem *QmlEngine::createPrelaunchSplash(QQuickItem *parent, const QString &logoPath) +QQuickItem *QmlEngine::createPrelaunchSplash(QQuickItem *parent, const QString &logoPath, qreal initialRadius) { - QVariantMap properties; - if (!logoPath.isEmpty()) { - properties["logoPath"] = logoPath; - } - return createComponent(prelaunchSplashComponent, parent, properties); + return createComponent(prelaunchSplashComponent, parent, { + { "logoPath", QVariant::fromValue(logoPath) }, + { "initialRadius", QVariant::fromValue(initialRadius) }, + }); } diff --git a/src/core/qmlengine.h b/src/core/qmlengine.h index 56d4bf2f6..7a52dad03 100644 --- a/src/core/qmlengine.h +++ b/src/core/qmlengine.h @@ -63,7 +63,9 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createShowDesktopAnimation(SurfaceWrapper *surface, QQuickItem *parent, bool show); QQuickItem *createCaptureSelector(QQuickItem *parent, CaptureManagerV1 *captureManager); QQuickItem *createWindowPicker(QQuickItem *parent); - QQuickItem *createPrelaunchSplash(QQuickItem *parent, const QString &logoPath = QString()); + QQuickItem *createPrelaunchSplash(QQuickItem *parent, + const QString &logoPath, + qreal initialRadius); QQmlComponent *surfaceContentComponent() { diff --git a/src/core/shellhandler.cpp b/src/core/shellhandler.cpp index e5d50bfc4..57ab50c98 100644 --- a/src/core/shellhandler.cpp +++ b/src/core/shellhandler.cpp @@ -85,7 +85,7 @@ void ShellHandler::updateWrapperContainer(SurfaceWrapper *wrapper, if (qobject_cast(oldContainer) == nullptr) { oldContainer->removeSurface(wrapper); m_workspace->addSurface(wrapper); - } + } // else do nothing, already in workspace } else { m_workspace->addSurface(wrapper); diff --git a/src/surface/surfacewrapper.cpp b/src/surface/surfacewrapper.cpp index dc35eb48b..4b36633bf 100644 --- a/src/surface/surfacewrapper.cpp +++ b/src/surface/surfacewrapper.cpp @@ -3,14 +3,12 @@ #include "surface/surfacewrapper.h" -#include "seat/helper.h" -#include "treelandconfig.hpp" +#include "common/treelandlogging.h" #include "core/qmlengine.h" #include "output/output.h" +#include "seat/helper.h" +#include "treelandconfig.hpp" #include "workspace/workspace.h" -#include "common/treelandlogging.h" - -#include #include #include @@ -91,23 +89,21 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, QQuickItem *parent, const Q { QQmlEngine::setContextForObject(this, qmlEngine->rootContext()); if (initialSize.isValid() && initialSize.width() > 0 && initialSize.height() > 0) { - // Also set implicit size to keep QML layout consistent + // Also set implicit size to keep QML layout consistent setImplicitSize(initialSize.width(), initialSize.height()); qInfo() << "Prelaunch Splash: set initial size to" << initialSize; } else { setImplicitSize(800, 600); } - setNoDecoration(false); - - m_prelaunchSplash = m_engine->createPrelaunchSplash(this); - m_prelaunchSplash->setZ(9999999999); + m_prelaunchSplash = m_engine->createPrelaunchSplash(this, QString(), radius()); + m_prelaunchSplash->setZ(99999); + // Connect to QML signal so C++ can destroy the QML item when requested + connect(m_prelaunchSplash, + SIGNAL(destroyRequested()), + this, + SLOT(onPrelaunchSplashDestroyRequested())); - connect(m_prelaunchSplash, &QQuickItem::visibleChanged, - this, [this] { - if (m_surfaceItem) - setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight()); - updateVisible(); - }); + setNoDecoration(false); } SurfaceWrapper::~SurfaceWrapper() @@ -183,53 +179,55 @@ void SurfaceWrapper::setup() requestCancelMinimize(); }); m_shellSurface->safeConnect(&WToplevelSurface::requestMaximize, - this, - &SurfaceWrapper::requestMaximize); + this, + &SurfaceWrapper::requestMaximize); m_shellSurface->safeConnect(&WToplevelSurface::requestCancelMaximize, - this, - &SurfaceWrapper::requestCancelMaximize); + this, + &SurfaceWrapper::requestCancelMaximize); m_shellSurface->safeConnect(&WToplevelSurface::requestMove, - this, - &SurfaceWrapper::requestMove); + this, + &SurfaceWrapper::requestMove); m_shellSurface->safeConnect(&WToplevelSurface::requestResize, - this, - [this](WSeat *, Qt::Edges edge, quint32) { - Q_EMIT requestResize(edge); - }); + this, + [this](WSeat *, Qt::Edges edge, quint32) { + Q_EMIT requestResize(edge); + }); m_shellSurface->safeConnect(&WToplevelSurface::requestFullscreen, - this, - &SurfaceWrapper::requestFullscreen); + this, + &SurfaceWrapper::requestFullscreen); m_shellSurface->safeConnect(&WToplevelSurface::requestCancelFullscreen, - this, - &SurfaceWrapper::requestCancelFullscreen); + this, + &SurfaceWrapper::requestCancelFullscreen); if (m_type == Type::XdgToplevel) { m_shellSurface->safeConnect(&WToplevelSurface::requestShowWindowMenu, - this, - [this](WSeat *, QPoint pos, quint32) { - Q_EMIT requestShowWindowMenu( - { pos.x() + m_surfaceItem->leftPadding(), - pos.y() + m_surfaceItem->topPadding() }); - }); + this, + [this](WSeat *, QPoint pos, quint32) { + Q_EMIT requestShowWindowMenu( + { pos.x() + m_surfaceItem->leftPadding(), + pos.y() + m_surfaceItem->topPadding() }); + }); } } m_shellSurface->surface()->safeConnect(&WSurface::mappedChanged, - this, - &SurfaceWrapper::onMappedChanged); + this, + &SurfaceWrapper::onMappedChanged); - connect(m_surfaceItem, - &WSurfaceItem::boundingRectChanged, - this, - &SurfaceWrapper::updateBoundingRect); - connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { - setImplicitWidth(m_surfaceItem->implicitWidth()); - }); - connect(m_surfaceItem, &WSurfaceItem::implicitHeightChanged, this, [this] { - setImplicitHeight(m_surfaceItem->implicitHeight()); - }); - - if (!m_prelaunchSplash || !m_prelaunchSplash->isVisible()) + Q_EMIT surfaceItemChanged(); + + if (!m_prelaunchSplash || !m_prelaunchSplash->isVisible()) { setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight()); + connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { + setImplicitWidth(m_surfaceItem->implicitWidth()); + }); + connect(m_surfaceItem, &WSurfaceItem::implicitHeightChanged, this, [this] { + setImplicitHeight(m_surfaceItem->implicitHeight()); + }); + connect(m_surfaceItem, + &WSurfaceItem::boundingRectChanged, + this, + &SurfaceWrapper::updateBoundingRect); + } if (auto client = m_shellSurface->waylandClient()) { connect(client->socket(), @@ -322,14 +320,13 @@ void SurfaceWrapper::convertToNormalSurface(WToplevelSurface *shellSurface, Type // Assign new shell surface (QPointer auto-detects destruction) m_shellSurface = shellSurface; - m_type = type; // Call setup() to initialize surfaceItem related features setup(); + // setNoDecoration not called updateTitleBar when type is Undetermined + updateTitleBar(); - // After conversion refresh visibility and bounding rect - updateBoundingRect(); QMetaObject::invokeMethod(m_prelaunchSplash, "hideAndDestroy", Qt::QueuedConnection); } @@ -373,6 +370,32 @@ void SurfaceWrapper::setFocus(bool focus, Qt::FocusReason reason) m_surfaceItem->setFocus(false, reason); } +void SurfaceWrapper::onPrelaunchSplashDestroyRequested() +{ + if (m_surfaceItem) { + setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight()); + connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { + setImplicitWidth(m_surfaceItem->implicitWidth()); + }); + connect(m_surfaceItem, &WSurfaceItem::implicitHeightChanged, this, [this] { + setImplicitHeight(m_surfaceItem->implicitHeight()); + }); + connect(m_surfaceItem, + &WSurfaceItem::boundingRectChanged, + this, + &SurfaceWrapper::updateBoundingRect); + } + if (m_decoration) + m_decoration->stackBefore(m_surfaceItem); + updateVisible(); + + if (!m_prelaunchSplash) + return; + m_prelaunchSplash->deleteLater(); + m_prelaunchSplash = nullptr; + Q_EMIT prelaunchSplashChanged(); +} + WSurface *SurfaceWrapper::surface() const { if (!m_shellSurface) @@ -391,6 +414,11 @@ WSurfaceItem *SurfaceWrapper::surfaceItem() const return m_surfaceItem; } +QQuickItem *SurfaceWrapper::prelaunchSplash() const +{ + return m_prelaunchSplash; +} + bool SurfaceWrapper::resize(const QSizeF &size) { // No surfaceItem in prelaunch mode -> return false @@ -744,7 +772,7 @@ void SurfaceWrapper::setNoDecoration(bool newNoDecoration) return; m_noDecoration = newNoDecoration; - if (m_titleBarState == TitleBarState::Default) + if (m_titleBarState == TitleBarState::Default && m_type != Type::Undetermined) updateTitleBar(); if (m_noDecoration) { @@ -755,7 +783,7 @@ void SurfaceWrapper::setNoDecoration(bool newNoDecoration) } else { Q_ASSERT(!m_decoration); m_decoration = m_engine->createDecoration(this, this); - m_decoration->stackBefore(m_surfaceItem); + m_decoration->stackBefore(m_surfaceItem ? m_surfaceItem : m_prelaunchSplash); connect(m_decoration, &QQuickItem::xChanged, this, &SurfaceWrapper::updateBoundingRect); connect(m_decoration, &QQuickItem::yChanged, this, &SurfaceWrapper::updateBoundingRect); connect(m_decoration, &QQuickItem::widthChanged, this, &SurfaceWrapper::updateBoundingRect); @@ -775,8 +803,7 @@ void SurfaceWrapper::updateTitleBar() return; // No surfaceItem in prelaunch mode -> early return - if (!m_surfaceItem) - return; + Q_ASSERT(m_surfaceItem); if (noTitleBar() == !m_titleBar) return; @@ -951,7 +978,8 @@ void SurfaceWrapper::doSetSurfaceState(State newSurfaceState) if (m_wrapperAboutToRemove) return; - // In prelaunch mode there is no shellSurface; update state only without calling shellSurface methods + // In prelaunch mode there is no shellSurface; update state only without calling shellSurface + // methods if (!m_shellSurface) { m_previousSurfaceState.setValueBypassingBindings(m_surfaceState); m_surfaceState.setValueBypassingBindings(newSurfaceState); @@ -1097,7 +1125,7 @@ void SurfaceWrapper::onMappedChanged() bool mapped = surface()->mapped() && !m_hideByLockScreen; if (!m_isProxy) { if (mapped) { - //createNewOrClose(OPEN_ANIMATION); + // createNewOrClose(OPEN_ANIMATION); if (m_coverContent) { m_coverContent->setVisible(true); } @@ -1202,7 +1230,8 @@ qreal SurfaceWrapper::radius() const qreal radius = m_radius; - // TODO: Handle: XdgToplevel, popup, InputPopup, XWayland (bypass, window type: menu/normal/popup) + // TODO: Handle: XdgToplevel, popup, InputPopup, XWayland (bypass, window type: + // menu/normal/popup) if (radius < 1 && m_type != Type::Layer) { radius = Helper::instance()->config()->windowRadius(); } diff --git a/src/surface/surfacewrapper.h b/src/surface/surfacewrapper.h index bff498c87..21458ef49 100644 --- a/src/surface/surfacewrapper.h +++ b/src/surface/surfacewrapper.h @@ -6,7 +6,6 @@ #include #include -// 交叉淡出需要动画类 #include Q_MOC_INCLUDE() @@ -27,13 +26,14 @@ class SurfaceWrapper : public QQuickItem Q_OBJECT QML_ELEMENT QML_UNCREATABLE("SurfaceWrapper objects are created by c++") - Q_PROPERTY(Type type READ type CONSTANT) + Q_PROPERTY(Type type READ type NOTIFY surfaceItemChanged) // make to read only Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged FINAL) Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged FINAL) Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurface* surface READ surface CONSTANT) Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WToplevelSurface* shellSurface READ shellSurface CONSTANT) - Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurfaceItem* surfaceItem READ surfaceItem CONSTANT) + Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurfaceItem* surfaceItem READ surfaceItem NOTIFY surfaceItemChanged) + Q_PROPERTY(QQuickItem* prelaunchSplash READ prelaunchSplash NOTIFY prelaunchSplashChanged) Q_PROPERTY(QRectF boundingRect READ boundingRect NOTIFY boundingRectChanged) Q_PROPERTY(QRectF geometry READ geometry NOTIFY geometryChanged FINAL) Q_PROPERTY(QRectF normalGeometry READ normalGeometry NOTIFY normalGeometryChanged FINAL) @@ -127,6 +127,7 @@ class SurfaceWrapper : public QQuickItem WSurface *surface() const; WToplevelSurface *shellSurface() const; WSurfaceItem *surfaceItem() const; + QQuickItem *prelaunchSplash() const; bool resize(const QSizeF &size); QRectF titlebarGeometry() const; @@ -307,6 +308,8 @@ public Q_SLOTS: void coverEnabledChanged(); void aboutToBeInvalidated(); void acceptKeyboardFocusChanged(); + void surfaceItemChanged(); + void prelaunchSplashChanged(); private: ~SurfaceWrapper() override; @@ -335,6 +338,7 @@ public Q_SLOTS: void doSetSurfaceState(State newSurfaceState); Q_SLOT void onAnimationReady(); Q_SLOT void onAnimationFinished(); + Q_SLOT void onPrelaunchSplashDestroyRequested(); bool startStateChangeAnimation(SurfaceWrapper::State targetState, const QRectF &targetGeometry); void onWindowAnimationFinished(); Q_SLOT void onShowAnimationFinished();