forked from quickshell/quickshell
Exposes QsMenuOpener.children as an ObjectModel instead of a list to allow smoother layout change handling in custom menu renderers. Fixes QsMenuAnchor/platform menus closing whenever menu content changes.
197 lines
5.4 KiB
C++
197 lines
5.4 KiB
C++
#pragma once
|
|
|
|
#include <qbytearray.h>
|
|
#include <qcontainerfwd.h>
|
|
#include <qdebug.h>
|
|
#include <qhash.h>
|
|
#include <qloggingcategory.h>
|
|
#include <qnamespace.h>
|
|
#include <qobject.h>
|
|
#include <qqmlintegration.h>
|
|
#include <qqmllist.h>
|
|
#include <qquickimageprovider.h>
|
|
#include <qtmetamacros.h>
|
|
#include <qtypes.h>
|
|
|
|
#include "../../core/doc.hpp"
|
|
#include "../../core/imageprovider.hpp"
|
|
#include "../../core/model.hpp"
|
|
#include "../../core/qsmenu.hpp"
|
|
#include "../properties.hpp"
|
|
#include "dbus_menu_types.hpp"
|
|
|
|
Q_DECLARE_LOGGING_CATEGORY(logDbusMenu);
|
|
|
|
class DBusMenuInterface;
|
|
|
|
namespace qs::dbus::dbusmenu {
|
|
|
|
// hack because docgen can't take namespaces in superclasses
|
|
using menu::QsMenuEntry;
|
|
|
|
class DBusMenu;
|
|
class DBusMenuPngImage;
|
|
|
|
///! Menu item shared by an external program.
|
|
/// Menu item shared by an external program via the
|
|
/// [DBusMenu specification](https://github.com/AyatanaIndicators/libdbusmenu/blob/master/libdbusmenu-glib/dbus-menu.xml).
|
|
class DBusMenuItem: public QsMenuEntry {
|
|
Q_OBJECT;
|
|
/// Handle to the root of this menu.
|
|
Q_PROPERTY(qs::dbus::dbusmenu::DBusMenu* menuHandle READ menuHandle CONSTANT);
|
|
QML_ELEMENT;
|
|
QML_UNCREATABLE("DBusMenus can only be acquired from a DBusMenuHandle");
|
|
|
|
public:
|
|
explicit DBusMenuItem(qint32 id, DBusMenu* menu, DBusMenuItem* parentMenu);
|
|
|
|
/// Refreshes the menu contents.
|
|
///
|
|
/// Usually you shouldn't need to call this manually but some applications providing
|
|
/// menus do not update them correctly. Call this if menus don't update their state.
|
|
///
|
|
/// The @@layoutUpdated(s) signal will be sent when a response is received.
|
|
Q_INVOKABLE void updateLayout() const;
|
|
|
|
[[nodiscard]] DBusMenu* menuHandle() const;
|
|
|
|
[[nodiscard]] bool isSeparator() const override;
|
|
[[nodiscard]] bool enabled() const override;
|
|
[[nodiscard]] QString text() const override;
|
|
[[nodiscard]] QString icon() const override;
|
|
[[nodiscard]] menu::QsMenuButtonType::Enum buttonType() const override;
|
|
[[nodiscard]] Qt::CheckState checkState() const override;
|
|
[[nodiscard]] bool hasChildren() const override;
|
|
|
|
[[nodiscard]] bool isShowingChildren() const;
|
|
void setShowChildrenRecursive(bool showChildren);
|
|
|
|
[[nodiscard]] ObjectModel<QsMenuEntry>* children() override;
|
|
|
|
void updateProperties(const QVariantMap& properties, const QStringList& removed = {});
|
|
void onChildrenUpdated();
|
|
|
|
qint32 id = 0;
|
|
QString mText;
|
|
QVector<qint32> mChildren;
|
|
bool mShowChildren = false;
|
|
bool childrenLoaded = false;
|
|
DBusMenu* menu = nullptr;
|
|
|
|
signals:
|
|
void layoutUpdated();
|
|
|
|
private slots:
|
|
void sendOpened() const;
|
|
void sendClosed() const;
|
|
void sendTriggered() const;
|
|
|
|
private:
|
|
QString mCleanLabel;
|
|
//QChar mnemonic;
|
|
bool mEnabled = true;
|
|
bool visible = true;
|
|
bool mSeparator = false;
|
|
QString iconName;
|
|
DBusMenuPngImage* image = nullptr;
|
|
menu::QsMenuButtonType::Enum mButtonType = menu::QsMenuButtonType::None;
|
|
Qt::CheckState mCheckState = Qt::Unchecked;
|
|
bool displayChildren = false;
|
|
ObjectModel<DBusMenuItem> enabledChildren {this};
|
|
DBusMenuItem* parentMenu = nullptr;
|
|
};
|
|
|
|
QDebug operator<<(QDebug debug, DBusMenuItem* item);
|
|
|
|
///! Handle to a DBusMenu tree.
|
|
/// Handle to a menu tree provided by a remote process.
|
|
class DBusMenu: public QObject {
|
|
Q_OBJECT;
|
|
Q_PROPERTY(qs::dbus::dbusmenu::DBusMenuItem* menu READ menu CONSTANT);
|
|
QML_NAMED_ELEMENT(DBusMenuHandle);
|
|
QML_UNCREATABLE("Menu handles cannot be directly created");
|
|
|
|
public:
|
|
explicit DBusMenu(const QString& service, const QString& path, QObject* parent = nullptr);
|
|
|
|
QS_DBUS_BINDABLE_PROPERTY_GROUP(DBusMenu, properties);
|
|
|
|
signals:
|
|
QSDOC_HIDE void iconThemePathChanged();
|
|
|
|
public:
|
|
Q_OBJECT_BINDABLE_PROPERTY(DBusMenu, QStringList, iconThemePath, &DBusMenu::iconThemePathChanged);
|
|
|
|
void prepareToShow(qint32 item, qint32 depth);
|
|
void updateLayout(qint32 parent, qint32 depth);
|
|
void removeRecursive(qint32 id);
|
|
void sendEvent(qint32 item, const QString& event);
|
|
|
|
DBusMenuItem rootItem {0, this, nullptr};
|
|
QHash<qint32, DBusMenuItem*> items {std::make_pair(0, &this->rootItem)};
|
|
|
|
[[nodiscard]] DBusMenuItem* menu();
|
|
|
|
private slots:
|
|
void onLayoutUpdated(quint32 revision, qint32 parent);
|
|
void onItemPropertiesUpdated(
|
|
const DBusMenuItemPropertiesList& updatedProps,
|
|
const DBusMenuItemPropertyNamesList& removedProps
|
|
);
|
|
|
|
private:
|
|
void updateLayoutRecursive(const DBusMenuLayout& layout, DBusMenuItem* parent, qint32 depth);
|
|
|
|
QS_DBUS_PROPERTY_BINDING(
|
|
DBusMenu,
|
|
pIconThemePath,
|
|
iconThemePath,
|
|
properties,
|
|
"IconThemePath",
|
|
false
|
|
);
|
|
|
|
DBusMenuInterface* interface = nullptr;
|
|
};
|
|
|
|
QDebug operator<<(QDebug debug, DBusMenu* menu);
|
|
|
|
class DBusMenuPngImage: public QsImageHandle {
|
|
public:
|
|
explicit DBusMenuPngImage(QByteArray data, DBusMenuItem* parent)
|
|
: QsImageHandle(QQuickImageProvider::Image, parent)
|
|
, data(std::move(data)) {}
|
|
|
|
QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override;
|
|
|
|
QByteArray data;
|
|
};
|
|
|
|
class DBusMenuHandle;
|
|
|
|
QDebug operator<<(QDebug debug, const DBusMenuHandle* handle);
|
|
|
|
class DBusMenuHandle: public menu::QsMenuHandle {
|
|
public:
|
|
explicit DBusMenuHandle(QObject* parent): menu::QsMenuHandle(parent) {}
|
|
|
|
void setAddress(const QString& service, const QString& path);
|
|
|
|
void refHandle() override;
|
|
void unrefHandle() override;
|
|
|
|
[[nodiscard]] QsMenuEntry* menu() override;
|
|
|
|
private:
|
|
void onMenuPathChanged();
|
|
|
|
QString service;
|
|
QString path;
|
|
DBusMenu* mMenu = nullptr;
|
|
bool loaded = false;
|
|
quint32 refcount = 0;
|
|
|
|
friend QDebug operator<<(QDebug debug, const DBusMenuHandle* handle);
|
|
};
|
|
|
|
} // namespace qs::dbus::dbusmenu
|