diff --git a/src/wayland/toplevel_management/qml.cpp b/src/wayland/toplevel_management/qml.cpp index 2042262b..1f0d1fe8 100644 --- a/src/wayland/toplevel_management/qml.cpp +++ b/src/wayland/toplevel_management/qml.cpp @@ -3,6 +3,7 @@ #include #include +#include "../../core/util.hpp" #include "../../core/model.hpp" #include "../../core/proxywindow.hpp" #include "../../core/qmlscreen.hpp" @@ -132,22 +133,49 @@ ObjectModel* ToplevelManager::toplevels() { return &this->mToplevels; void ToplevelManager::onToplevelReady(impl::ToplevelHandle* handle) { auto* toplevel = new Toplevel(handle, this); + + // clang-format off QObject::connect(toplevel, &Toplevel::closed, this, &ToplevelManager::onToplevelClosed); + QObject::connect(toplevel, &Toplevel::activatedChanged, this, &ToplevelManager::onToplevelActiveChanged); + // clang-format on + + if (toplevel->activated()) this->setActiveToplevel(toplevel); this->mToplevels.insertObject(toplevel); } +void ToplevelManager::onToplevelActiveChanged() { + auto* toplevel = qobject_cast(this->sender()); + if (toplevel->activated()) this->setActiveToplevel(toplevel); +} + void ToplevelManager::onToplevelClosed() { auto* toplevel = qobject_cast(this->sender()); + if (toplevel == this->mActiveToplevel) this->setActiveToplevel(nullptr); this->mToplevels.removeObject(toplevel); } +DEFINE_MEMBER_GETSET(ToplevelManager, activeToplevel, setActiveToplevel); + ToplevelManager* ToplevelManager::instance() { static auto* instance = new ToplevelManager(); // NOLINT return instance; } +ToplevelManagerQml::ToplevelManagerQml(QObject* parent): QObject(parent) { + QObject::connect( + ToplevelManager::instance(), + &ToplevelManager::activeToplevelChanged, + this, + &ToplevelManagerQml::activeToplevelChanged + ); +} + ObjectModel* ToplevelManagerQml::toplevels() { return ToplevelManager::instance()->toplevels(); } +Toplevel* ToplevelManagerQml::activeToplevel() { + return ToplevelManager::instance()->activeToplevel(); +} + } // namespace qs::wayland::toplevel_management diff --git a/src/wayland/toplevel_management/qml.hpp b/src/wayland/toplevel_management/qml.hpp index 64951b63..d50713c5 100644 --- a/src/wayland/toplevel_management/qml.hpp +++ b/src/wayland/toplevel_management/qml.hpp @@ -7,6 +7,7 @@ #include "../../core/model.hpp" #include "../../core/proxywindow.hpp" #include "../../core/qmlscreen.hpp" +#include "../../core/util.hpp" namespace qs::wayland::toplevel_management { @@ -111,14 +112,27 @@ public: static ToplevelManager* instance(); +signals: + void activeToplevelChanged(); + private slots: void onToplevelReady(impl::ToplevelHandle* handle); + void onToplevelActiveChanged(); void onToplevelClosed(); private: explicit ToplevelManager(); ObjectModel mToplevels {this}; + Toplevel* mActiveToplevel = nullptr; + + DECLARE_PRIVATE_MEMBER( + ToplevelManager, + activeToplevel, + setActiveToplevel, + mActiveToplevel, + activeToplevelChanged + ); }; ///! Exposes a list of Toplevels. @@ -127,14 +141,24 @@ private: /// wayland protocol. class ToplevelManagerQml: public QObject { Q_OBJECT; + /// All toplevel windows exposed by the compositor. Q_PROPERTY(ObjectModel* toplevels READ toplevels CONSTANT); + /// Active toplevel or null. + /// + /// > [!INFO] If multiple are active, this will be the most recently activated one. + /// > Usually compositors will not report more than one toplevel as active at a time. + Q_PROPERTY(Toplevel* activeToplevel READ activeToplevel NOTIFY activeToplevelChanged); QML_NAMED_ELEMENT(ToplevelManager); QML_SINGLETON; public: - explicit ToplevelManagerQml(QObject* parent = nullptr): QObject(parent) {} + explicit ToplevelManagerQml(QObject* parent = nullptr); [[nodiscard]] static ObjectModel* toplevels(); + [[nodiscard]] static Toplevel* activeToplevel(); + +signals: + void activeToplevelChanged(); }; } // namespace qs::wayland::toplevel_management