forked from quickshell/quickshell
service/tray!: redesign menus / dbusmenu and add native menu support
Reworks dbusmenu menus to be displayable with a system context menu. Breaks the entire DBusMenu api.
This commit is contained in:
parent
c31bbea837
commit
ec362637b8
18 changed files with 898 additions and 191 deletions
|
@ -14,32 +14,18 @@
|
|||
#include <qtypes.h>
|
||||
|
||||
#include "../../core/imageprovider.hpp"
|
||||
#include "../../core/qsmenu.hpp"
|
||||
#include "../properties.hpp"
|
||||
#include "dbus_menu_types.hpp"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(logDbusMenu);
|
||||
|
||||
namespace ToggleButtonType { // NOLINT
|
||||
Q_NAMESPACE;
|
||||
QML_ELEMENT;
|
||||
|
||||
enum Enum {
|
||||
/// This menu item does not have a checkbox or a radiobutton associated with it.
|
||||
None = 0,
|
||||
/// This menu item should draw a checkbox.
|
||||
CheckBox = 1,
|
||||
/// This menu item should draw a radiobutton.
|
||||
RadioButton = 2,
|
||||
};
|
||||
Q_ENUM_NS(Enum);
|
||||
|
||||
} // namespace ToggleButtonType
|
||||
|
||||
class DBusMenuInterface;
|
||||
|
||||
namespace qs::dbus::dbusmenu {
|
||||
|
||||
QDebug operator<<(QDebug debug, const ToggleButtonType::Enum& toggleType);
|
||||
// hack because docgen can't take namespaces in superclasses
|
||||
using menu::QsMenuEntry;
|
||||
|
||||
class DBusMenu;
|
||||
class DBusMenuPngImage;
|
||||
|
@ -47,113 +33,56 @@ 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 QObject {
|
||||
class DBusMenuItem: public QsMenuEntry {
|
||||
Q_OBJECT;
|
||||
// clang-format off
|
||||
/// Handle to the root of this menu.
|
||||
Q_PROPERTY(DBusMenu* menuHandle READ menuHandle CONSTANT);
|
||||
/// Text of the menu item, including hotkey markup.
|
||||
Q_PROPERTY(QString label READ label NOTIFY labelChanged);
|
||||
/// Text of the menu item without hotkey markup.
|
||||
Q_PROPERTY(QString cleanLabel READ cleanLabel NOTIFY labelChanged);
|
||||
/// If the menu item should be shown as enabled.
|
||||
///
|
||||
/// > [!INFO] Disabled menu items are often used as headers in addition
|
||||
/// > to actual disabled entries.
|
||||
Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged);
|
||||
/// Url of the menu item's icon or `""` if it doesn't have one.
|
||||
///
|
||||
/// This can be passed to [Image.source](https://doc.qt.io/qt-6/qml-qtquick-image.html#source-prop)
|
||||
/// as shown below.
|
||||
///
|
||||
/// ```qml
|
||||
/// Image {
|
||||
/// source: menuItem.icon
|
||||
/// // To get the best image quality, set the image source size to the same size
|
||||
/// // as the rendered image.
|
||||
/// sourceSize.width: width
|
||||
/// sourceSize.height: height
|
||||
/// }
|
||||
/// ```
|
||||
Q_PROPERTY(QString icon READ icon NOTIFY iconChanged);
|
||||
/// If this menu item has an associated checkbox or radiobutton.
|
||||
///
|
||||
/// > [!INFO] It is the responsibility of the remote application to update the state of
|
||||
/// > checkboxes and radiobuttons via [checkState](#prop.checkState).
|
||||
Q_PROPERTY(ToggleButtonType::Enum toggleType READ toggleType NOTIFY toggleTypeChanged);
|
||||
/// The check state of the checkbox or radiobutton if applicable, as a
|
||||
/// [Qt.CheckState](https://doc.qt.io/qt-6/qt.html#CheckState-enum).
|
||||
Q_PROPERTY(Qt::CheckState checkState READ checkState NOTIFY checkStateChanged);
|
||||
/// If this menu item should be rendered as a separator between other items.
|
||||
///
|
||||
/// No other properties have a meaningful value when `isSeparator` is true.
|
||||
Q_PROPERTY(bool isSeparator READ isSeparator NOTIFY separatorChanged);
|
||||
/// If this menu item reveals a submenu containing more items.
|
||||
///
|
||||
/// Any submenu items must be requested by setting [showChildren](#prop.showChildren).
|
||||
Q_PROPERTY(bool hasChildren READ hasChildren NOTIFY hasChildrenChanged);
|
||||
/// If submenu entries of this item should be shown.
|
||||
///
|
||||
/// When true, children of this menu item will be exposed via [children](#prop.children).
|
||||
/// Setting this property will additionally send the `opened` and `closed` events to the
|
||||
/// process that provided the menu.
|
||||
Q_PROPERTY(bool showChildren READ isShowingChildren WRITE setShowChildren NOTIFY showingChildrenChanged);
|
||||
/// Children of this menu item. Only populated when [showChildren](#prop.showChildren) is true.
|
||||
///
|
||||
/// > [!INFO] Use [hasChildren](#prop.hasChildren) to check if this item should reveal a submenu
|
||||
/// > instead of checking if `children` is empty.
|
||||
Q_PROPERTY(QQmlListProperty<DBusMenuItem> children READ children NOTIFY childrenChanged);
|
||||
// clang-format on
|
||||
QML_ELEMENT;
|
||||
QML_UNCREATABLE("DBusMenus can only be acquired from a DBusMenuHandle");
|
||||
|
||||
public:
|
||||
explicit DBusMenuItem(qint32 id, DBusMenu* menu, DBusMenuItem* parentMenu);
|
||||
|
||||
/// Send a `clicked` event to the remote application for this menu item.
|
||||
Q_INVOKABLE void click();
|
||||
|
||||
/// Send a `hovered` event to the remote application for this menu item.
|
||||
/// Refreshes the menu contents.
|
||||
///
|
||||
/// Note: we are not aware of any programs that use this in any meaningful way.
|
||||
Q_INVOKABLE void hover() const;
|
||||
/// 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` signal will be sent when a response is received.
|
||||
Q_INVOKABLE void updateLayout() const;
|
||||
|
||||
[[nodiscard]] DBusMenu* menuHandle() const;
|
||||
[[nodiscard]] QString label() const;
|
||||
[[nodiscard]] QString cleanLabel() const;
|
||||
[[nodiscard]] bool enabled() const;
|
||||
[[nodiscard]] QString icon() const;
|
||||
[[nodiscard]] ToggleButtonType::Enum toggleType() const;
|
||||
[[nodiscard]] Qt::CheckState checkState() const;
|
||||
[[nodiscard]] bool isSeparator() const;
|
||||
[[nodiscard]] bool hasChildren() 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 setShowChildren(bool showChildren);
|
||||
void setShowChildrenRecursive(bool showChildren);
|
||||
|
||||
[[nodiscard]] QQmlListProperty<DBusMenuItem> children();
|
||||
[[nodiscard]] QQmlListProperty<menu::QsMenuEntry> children() override;
|
||||
|
||||
void updateProperties(const QVariantMap& properties, const QStringList& removed = {});
|
||||
void onChildrenUpdated();
|
||||
|
||||
qint32 id = 0;
|
||||
QString mLabel;
|
||||
QString mText;
|
||||
QVector<qint32> mChildren;
|
||||
bool mShowChildren = false;
|
||||
bool childrenLoaded = false;
|
||||
DBusMenu* menu = nullptr;
|
||||
|
||||
signals:
|
||||
void labelChanged();
|
||||
//void mnemonicChanged();
|
||||
void enabledChanged();
|
||||
void iconChanged();
|
||||
void separatorChanged();
|
||||
void toggleTypeChanged();
|
||||
void checkStateChanged();
|
||||
void hasChildrenChanged();
|
||||
void showingChildrenChanged();
|
||||
void childrenChanged();
|
||||
void layoutUpdated();
|
||||
|
||||
private slots:
|
||||
void sendOpened() const;
|
||||
void sendClosed() const;
|
||||
void sendTriggered() const;
|
||||
|
||||
private:
|
||||
QString mCleanLabel;
|
||||
|
@ -163,14 +92,14 @@ private:
|
|||
bool mSeparator = false;
|
||||
QString iconName;
|
||||
DBusMenuPngImage* image = nullptr;
|
||||
ToggleButtonType::Enum mToggleType = ToggleButtonType::None;
|
||||
Qt::CheckState mCheckState = Qt::Checked;
|
||||
menu::QsMenuButtonType::Enum mButtonType = menu::QsMenuButtonType::None;
|
||||
Qt::CheckState mCheckState = Qt::Unchecked;
|
||||
bool displayChildren = false;
|
||||
QVector<qint32> enabledChildren;
|
||||
DBusMenuItem* parentMenu = nullptr;
|
||||
|
||||
static qsizetype childrenCount(QQmlListProperty<DBusMenuItem>* property);
|
||||
static DBusMenuItem* childAt(QQmlListProperty<DBusMenuItem>* property, qsizetype index);
|
||||
static qsizetype childrenCount(QQmlListProperty<menu::QsMenuEntry>* property);
|
||||
static menu::QsMenuEntry* childAt(QQmlListProperty<menu::QsMenuEntry>* property, qsizetype index);
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, DBusMenuItem* item);
|
||||
|
@ -192,7 +121,7 @@ public:
|
|||
dbus::DBusProperty<QString> status {this->properties, "Status"};
|
||||
dbus::DBusProperty<QStringList> iconThemePath {this->properties, "IconThemePath", {}, false};
|
||||
|
||||
void prepareToShow(qint32 item, bool sendOpened);
|
||||
void prepareToShow(qint32 item, qint32 depth);
|
||||
void updateLayout(qint32 parent, qint32 depth);
|
||||
void removeRecursive(qint32 id);
|
||||
void sendEvent(qint32 item, const QString& event);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue