/* * Copyright (C) 2016 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TOPLEVELSURFACELIST_H #define TOPLEVELSURFACELIST_H #include #include #include Q_DECLARE_LOGGING_CATEGORY(UNITY_TOPSURFACELIST) namespace unity { namespace shell { namespace application { class ApplicationInfoInterface; class MirSurfaceInterface; } } } /** * @brief A model of top-level surfaces * * It's an abstraction of top-level application windows. * * When an entry first appears, it normaly doesn't have a surface yet, meaning that the application is * still starting up. A shell should then display a splash screen or saved screenshot of the application * until its surface comes up. * * As applications can have multiple surfaces and you can also have entries without surfaces at all, * the only way to unambiguously refer to an entry in this model is through its id. */ class TopLevelSurfaceList : public QAbstractListModel { Q_OBJECT /** * @brief A list model of applications. * * It's expected to have a role called "application" which returns a ApplicationInfoInterface */ Q_PROPERTY(QAbstractListModel* applicationsModel READ applicationsModel WRITE setApplicationsModel NOTIFY applicationsModelChanged) /** * @brief Number of top-level surfaces in this model * * This is the same as rowCount, added in order to keep compatibility with QML ListModels. */ Q_PROPERTY(int count READ rowCount NOTIFY countChanged) /** The id to be used on the next entry created Useful for tests */ Q_PROPERTY(int nextId READ nextId NOTIFY nextIdChanged) public: /** * @brief The Roles supported by the model * * SurfaceRole - A MirSurfaceInterface. It will be null if the application is still starting up * ApplicationRole - An ApplicationInfoInterface * IdRole - A unique identifier for this entry. Useful to unambiguosly track elements as they move around in the list */ enum Roles { SurfaceRole = Qt::UserRole, ApplicationRole = Qt::UserRole + 1, IdRole = Qt::UserRole + 2, }; explicit TopLevelSurfaceList(QObject *parent = nullptr); virtual ~TopLevelSurfaceList(); // QAbstractItemModel methods int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; QHash roleNames() const override { QHash roleNames { {SurfaceRole, "surface"}, {ApplicationRole, "application"}, {IdRole, "id"} }; return roleNames; } int nextId() const { return m_nextId; } QAbstractListModel *applicationsModel() const; void setApplicationsModel(QAbstractListModel*); public Q_SLOTS: /** * @brief Returns the surface at the given index * * It will be a nullptr if the application is still starting up and thus hasn't yet created * and drawn into a surface. */ unity::shell::application::MirSurfaceInterface *surfaceAt(int index) const; /** * @brief Returns the application at the given index */ unity::shell::application::ApplicationInfoInterface *applicationAt(int index) const; /** * @brief Returns the unique id of the element at the given index */ int idAt(int index) const; /** * @brief Returns the index where the row with the given id is located * * Returns -1 if there's no row with the given id. */ int indexForId(int id) const; /** * @brief Raises the row with the given id to index 0 */ void raiseId(int id); void doRaiseId(int id); Q_SIGNALS: void countChanged(); /** * @brief Emitted when the list changes * * Emitted when model gains an element, loses an element or when elements exchange positions. */ void listChanged(); void nextIdChanged(); void applicationsModelChanged(); private: void addApplication(unity::shell::application::ApplicationInfoInterface *application); void removeApplication(unity::shell::application::ApplicationInfoInterface *application); int indexOf(unity::shell::application::MirSurfaceInterface *surface); void raise(unity::shell::application::MirSurfaceInterface *surface); void move(int from, int to); void appendSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface, unity::shell::application::ApplicationInfoInterface *application); void connectSurface(unity::shell::application::MirSurfaceInterface *surface); int generateId(); int nextFreeId(int candidateId); QString toString(); void onSurfaceDestroyed(unity::shell::application::MirSurfaceInterface *surface); void onSurfaceDied(unity::shell::application::MirSurfaceInterface *surface); void removeAt(int index); void findApplicationRole(); unity::shell::application::ApplicationInfoInterface *getApplicationFromModelAt(int index); /* Placeholder for a future surface from a starting or running application. Enables shell to give immediate feedback to the user by showing, eg, a splash screen. It's a model row containing a null surface and the given application. */ void appendPlaceholder(unity::shell::application::ApplicationInfoInterface *application); /* Adds a model row with the given surface and application Alternatively, if a placeholder exists for the given application it's filled with the given surface instead. */ void appendSurface(unity::shell::application::MirSurfaceInterface *surface, unity::shell::application::ApplicationInfoInterface *application); struct ModelEntry { ModelEntry(unity::shell::application::MirSurfaceInterface *surface, unity::shell::application::ApplicationInfoInterface *application, int id) : surface(surface), application(application), id(id) {} unity::shell::application::MirSurfaceInterface *surface; unity::shell::application::ApplicationInfoInterface *application; int id; bool removeOnceSurfaceDestroyed{false}; }; QList m_surfaceList; int m_nextId{1}; static const int m_maxId{1000000}; // applications that are being monitored QList m_applications; QAbstractListModel* m_applicationsModel{nullptr}; int m_applicationRole{-1}; enum ModelState { IdleState, InsertingState, RemovingState, MovingState, ResettingState }; ModelState m_modelState{IdleState}; }; Q_DECLARE_METATYPE(TopLevelSurfaceList*) Q_DECLARE_METATYPE(QAbstractListModel*) #endif // TOPLEVELSURFACELIST_H