Skip to content

Commit e7cfb5c

Browse files
committed
service/tray: move menu access to SystemTrayMenuWatcher
1 parent 3c0456a commit e7cfb5c

File tree

4 files changed

+94
-40
lines changed

4 files changed

+94
-40
lines changed

docs

Submodule docs updated from 0488683 to 149b784

src/dbus/dbusmenu/dbusmenu.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class DBusMenuItem: public QObject {
104104
/// > instead of checking if `children` is empty.
105105
Q_PROPERTY(QQmlListProperty<DBusMenuItem> children READ children NOTIFY childrenChanged);
106106
// clang-format on
107-
QML_NAMED_ELEMENT(DBusMenu);
107+
QML_ELEMENT;
108108
QML_UNCREATABLE("DBusMenus can only be acquired from a DBusMenuHandle");
109109

110110
public:

src/services/status_notifier/qml.cpp

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,8 @@ SystemTrayItem::SystemTrayItem(qs::service::sni::StatusNotifierItem* item, QObje
2929
QObject::connect(this->item, &StatusNotifierItem::iconChanged, this, &SystemTrayItem::iconChanged);
3030
QObject::connect(&this->item->tooltip, &AbstractDBusProperty::changed, this, &SystemTrayItem::tooltipTitleChanged);
3131
QObject::connect(&this->item->tooltip, &AbstractDBusProperty::changed, this, &SystemTrayItem::tooltipDescriptionChanged);
32-
QObject::connect(&this->item->menuPath, &AbstractDBusProperty::changed, this, &SystemTrayItem::onMenuPathChanged);
3332
QObject::connect(&this->item->isMenu, &AbstractDBusProperty::changed, this, &SystemTrayItem::onlyMenuChanged);
3433
// clang-format on
35-
36-
if (!this->item->menuPath.get().path().isEmpty()) this->onMenuPathChanged();
3734
}
3835

3936
QString SystemTrayItem::id() const {
@@ -89,30 +86,14 @@ QString SystemTrayItem::tooltipDescription() const {
8986
return this->item->tooltip.get().description;
9087
}
9188

92-
DBusMenuItem* SystemTrayItem::menu() const {
93-
if (this->mMenu == nullptr) return nullptr;
94-
return &this->mMenu->rootItem;
95-
}
96-
9789
bool SystemTrayItem::onlyMenu() const {
9890
if (this->item == nullptr) return false;
9991
return this->item->isMenu.get();
10092
}
10193

102-
void SystemTrayItem::onMenuPathChanged() {
103-
if (this->mMenu != nullptr) {
104-
this->mMenu->deleteLater();
105-
}
106-
107-
this->mMenu = this->item->createMenu();
108-
emit this->menuChanged();
109-
}
110-
111-
void SystemTrayItem::activate() { this->item->activate(); }
112-
113-
void SystemTrayItem::secondaryActivate() { this->item->secondaryActivate(); }
114-
115-
void SystemTrayItem::scroll(qint32 delta, bool horizontal) {
94+
void SystemTrayItem::activate() const { this->item->activate(); }
95+
void SystemTrayItem::secondaryActivate() const { this->item->secondaryActivate(); }
96+
void SystemTrayItem::scroll(qint32 delta, bool horizontal) const {
11697
this->item->scroll(delta, horizontal);
11798
}
11899

@@ -165,3 +146,49 @@ qsizetype SystemTray::itemsCount(QQmlListProperty<SystemTrayItem>* property) {
165146
SystemTrayItem* SystemTray::itemAt(QQmlListProperty<SystemTrayItem>* property, qsizetype index) {
166147
return reinterpret_cast<SystemTray*>(property->object)->mItems.at(index); // NOLINT
167148
}
149+
150+
SystemTrayItem* SystemTrayMenuWatcher::trayItem() const { return this->item; }
151+
152+
void SystemTrayMenuWatcher::setTrayItem(SystemTrayItem* item) {
153+
if (item == this->item) return;
154+
155+
if (this->item != nullptr) {
156+
QObject::disconnect(this->item, nullptr, this, nullptr);
157+
}
158+
159+
this->item = item;
160+
161+
if (item != nullptr) {
162+
QObject::connect(item, &QObject::destroyed, this, &SystemTrayMenuWatcher::onItemDestroyed);
163+
164+
QObject::connect(
165+
&item->item->menuPath,
166+
&AbstractDBusProperty::changed,
167+
this,
168+
&SystemTrayMenuWatcher::onMenuPathChanged
169+
);
170+
}
171+
172+
this->onMenuPathChanged();
173+
emit this->trayItemChanged();
174+
}
175+
176+
DBusMenuItem* SystemTrayMenuWatcher::menu() const {
177+
if (this->mMenu == nullptr) return nullptr;
178+
return &this->mMenu->rootItem;
179+
}
180+
181+
void SystemTrayMenuWatcher::onItemDestroyed() {
182+
this->item = nullptr;
183+
this->onMenuPathChanged();
184+
emit this->trayItemChanged();
185+
}
186+
187+
void SystemTrayMenuWatcher::onMenuPathChanged() {
188+
if (this->mMenu != nullptr) {
189+
this->mMenu->deleteLater();
190+
}
191+
192+
this->mMenu = this->item == nullptr ? nullptr : this->item->item->createMenu();
193+
emit this->menuChanged();
194+
}

src/services/status_notifier/qml.hpp

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Q_ENUM_NS(Enum);
4545
/// A system tray item, roughly conforming to the [kde/freedesktop spec]
4646
/// (there is no real spec, we just implemented whatever seemed to actually be used).
4747
///
48+
/// The associated context menu can be retrieved using a [SystemTrayMenuWatcher](../systemtraymenuwatcher).
49+
///
4850
/// [kde/freedesktop spec]: https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierItem/
4951
class SystemTrayItem: public QObject {
5052
using DBusMenuItem = qs::dbus::dbusmenu::DBusMenuItem;
@@ -60,8 +62,6 @@ class SystemTrayItem: public QObject {
6062
Q_PROPERTY(QString icon READ icon NOTIFY iconChanged);
6163
Q_PROPERTY(QString tooltipTitle READ tooltipTitle NOTIFY tooltipTitleChanged);
6264
Q_PROPERTY(QString tooltipDescription READ tooltipDescription NOTIFY tooltipDescriptionChanged);
63-
// The context menu provided by the application, generally displayed via a right click.
64-
Q_PROPERTY(DBusMenuItem* menu READ menu NOTIFY menuChanged);
6565
/// If this tray item only offers a menu and activation will do nothing.
6666
Q_PROPERTY(bool onlyMenu READ onlyMenu NOTIFY onlyMenuChanged);
6767
QML_ELEMENT;
@@ -71,13 +71,13 @@ class SystemTrayItem: public QObject {
7171
explicit SystemTrayItem(qs::service::sni::StatusNotifierItem* item, QObject* parent = nullptr);
7272

7373
/// Primary activation action, generally triggered via a left click.
74-
Q_INVOKABLE void activate();
74+
Q_INVOKABLE void activate() const;
7575

7676
/// Secondary activation action, generally triggered via a middle click.
77-
Q_INVOKABLE void secondaryActivate();
77+
Q_INVOKABLE void secondaryActivate() const;
7878

7979
/// Scroll action, such as changing volume on a mixer.
80-
Q_INVOKABLE void scroll(qint32 delta, bool horizontal);
80+
Q_INVOKABLE void scroll(qint32 delta, bool horizontal) const;
8181

8282
[[nodiscard]] QString id() const;
8383
[[nodiscard]] QString title() const;
@@ -86,9 +86,10 @@ class SystemTrayItem: public QObject {
8686
[[nodiscard]] QString icon() const;
8787
[[nodiscard]] QString tooltipTitle() const;
8888
[[nodiscard]] QString tooltipDescription() const;
89-
[[nodiscard]] DBusMenuItem* menu() const;
9089
[[nodiscard]] bool onlyMenu() const;
9190

91+
qs::service::sni::StatusNotifierItem* item = nullptr;
92+
9293
signals:
9394
void idChanged();
9495
void titleChanged();
@@ -97,17 +98,7 @@ class SystemTrayItem: public QObject {
9798
void iconChanged();
9899
void tooltipTitleChanged();
99100
void tooltipDescriptionChanged();
100-
void menuChanged();
101101
void onlyMenuChanged();
102-
103-
private slots:
104-
void onMenuPathChanged();
105-
106-
private:
107-
qs::service::sni::StatusNotifierItem* item = nullptr;
108-
qs::dbus::dbusmenu::DBusMenu* mMenu = nullptr;
109-
110-
friend class SystemTray;
111102
};
112103

113104
///! System tray
@@ -139,3 +130,39 @@ private slots:
139130

140131
QList<SystemTrayItem*> mItems;
141132
};
133+
134+
///! Accessor for SystemTrayItem menus.
135+
/// SystemTrayMenuWatcher provides access to the associated
136+
/// [DBusMenuItem](../../quickshell.dbusmenu/dbusmenuitem) for a tray item.
137+
class SystemTrayMenuWatcher: public QObject {
138+
using DBusMenu = qs::dbus::dbusmenu::DBusMenu;
139+
using DBusMenuItem = qs::dbus::dbusmenu::DBusMenuItem;
140+
141+
Q_OBJECT;
142+
/// The tray item to watch.
143+
Q_PROPERTY(SystemTrayItem* trayItem READ trayItem WRITE setTrayItem NOTIFY trayItemChanged);
144+
/// The menu associated with the tray item. Will be null if `trayItem` is null
145+
/// or has no associated menu.
146+
Q_PROPERTY(DBusMenuItem* menu READ menu NOTIFY menuChanged);
147+
QML_ELEMENT;
148+
149+
public:
150+
explicit SystemTrayMenuWatcher(QObject* parent = nullptr): QObject(parent) {}
151+
152+
[[nodiscard]] SystemTrayItem* trayItem() const;
153+
void setTrayItem(SystemTrayItem* item);
154+
155+
[[nodiscard]] DBusMenuItem* menu() const;
156+
157+
signals:
158+
void menuChanged();
159+
void trayItemChanged();
160+
161+
private slots:
162+
void onItemDestroyed();
163+
void onMenuPathChanged();
164+
165+
private:
166+
SystemTrayItem* item = nullptr;
167+
DBusMenu* mMenu = nullptr;
168+
};

0 commit comments

Comments
 (0)