Skip to content

Commit b43b4a0

Browse files
committed
service/tray: adopt bindable properties
1 parent 0e9e593 commit b43b4a0

File tree

4 files changed

+201
-136
lines changed

4 files changed

+201
-136
lines changed

src/services/status_notifier/dbus_item_types.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "dbus_item_types.hpp"
22

33
#include <qdbusargument.h>
4-
#include <qdbusextratypes.h>
54
#include <qdebug.h>
65
#include <qendian.h>
76
#include <qimage.h>
@@ -10,6 +9,15 @@
109
#include <qsysinfo.h>
1110
#include <qtypes.h>
1211

12+
bool DBusSniIconPixmap::operator==(const DBusSniIconPixmap& other) const {
13+
return this->width == other.width && this->height == other.height && this->data == other.data;
14+
}
15+
16+
bool DBusSniTooltip::operator==(const DBusSniTooltip& other) const {
17+
return this->icon == other.icon && this->title == other.title
18+
&& this->description == other.description && this->iconPixmaps == other.iconPixmaps;
19+
}
20+
1321
QImage DBusSniIconPixmap::createImage() const {
1422
// fix byte order if on a little endian machine
1523
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
@@ -113,9 +121,3 @@ QDebug operator<<(QDebug debug, const DBusSniTooltip& tooltip) {
113121

114122
return debug;
115123
}
116-
117-
QDebug operator<<(QDebug debug, const QDBusObjectPath& path) {
118-
debug.nospace() << "QDBusObjectPath(" << path.path() << ")";
119-
120-
return debug;
121-
}

src/services/status_notifier/dbus_item_types.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#pragma once
22

33
#include <qdbusargument.h>
4-
#include <qdbusextratypes.h>
54
#include <qdebug.h>
65
#include <qlist.h>
76

@@ -12,6 +11,8 @@ struct DBusSniIconPixmap {
1211

1312
// valid only for the lifetime of the pixmap
1413
[[nodiscard]] QImage createImage() const;
14+
15+
bool operator==(const DBusSniIconPixmap& other) const;
1516
};
1617

1718
using DBusSniIconPixmapList = QList<DBusSniIconPixmap>;
@@ -21,6 +22,8 @@ struct DBusSniTooltip {
2122
DBusSniIconPixmapList iconPixmaps;
2223
QString title;
2324
QString description;
25+
26+
bool operator==(const DBusSniTooltip& other) const;
2427
};
2528

2629
const QDBusArgument& operator>>(const QDBusArgument& argument, DBusSniIconPixmap& pixmap);
@@ -32,4 +35,3 @@ const QDBusArgument& operator<<(QDBusArgument& argument, const DBusSniTooltip& t
3235

3336
QDebug operator<<(QDebug debug, const DBusSniIconPixmap& pixmap);
3437
QDebug operator<<(QDebug debug, const DBusSniTooltip& tooltip);
35-
QDebug operator<<(QDebug debug, const QDBusObjectPath& path);

src/services/status_notifier/item.cpp

Lines changed: 100 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "item.hpp"
2-
#include <utility>
32

3+
#include <qdbuserror.h>
44
#include <qdbusextratypes.h>
55
#include <qdbusmetatype.h>
66
#include <qdbuspendingcall.h>
@@ -16,6 +16,7 @@
1616
#include <qrect.h>
1717
#include <qsize.h>
1818
#include <qstring.h>
19+
#include <qstringliteral.h>
1920
#include <qtmetamacros.h>
2021
#include <qtypes.h>
2122

@@ -58,59 +59,80 @@ StatusNotifierItem::StatusNotifierItem(const QString& address, QObject* parent)
5859
}
5960

6061
// clang-format off
61-
QObject::connect(this->item, &DBusStatusNotifierItem::NewTitle, &this->pTitle, &AbstractDBusProperty::update);
62-
QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, &this->pIconName, &AbstractDBusProperty::update);
63-
QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, &this->pIconPixmaps, &AbstractDBusProperty::update);
64-
QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, &this->pIconThemePath, &AbstractDBusProperty::update);
65-
QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, &this->pOverlayIconName, &AbstractDBusProperty::update);
66-
QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, &this->pOverlayIconPixmaps, &AbstractDBusProperty::update);
67-
QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, &this->pIconThemePath, &AbstractDBusProperty::update);
68-
QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, &this->pAttentionIconName, &AbstractDBusProperty::update);
69-
QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, &this->pAttentionIconPixmaps, &AbstractDBusProperty::update);
70-
QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, &this->pIconThemePath, &AbstractDBusProperty::update);
71-
QObject::connect(this->item, &DBusStatusNotifierItem::NewToolTip, &this->pTooltip, &AbstractDBusProperty::update);
72-
73-
QObject::connect(&this->pIconThemePath, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon);
74-
QObject::connect(&this->pIconName, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon);
75-
QObject::connect(&this->pAttentionIconName, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon);
76-
QObject::connect(&this->pOverlayIconName, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon);
77-
QObject::connect(&this->pIconPixmaps, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon);
78-
QObject::connect(&this->pAttentionIconPixmaps, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon);
79-
QObject::connect(&this->pOverlayIconPixmaps, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon);
62+
QObject::connect(this->item, &DBusStatusNotifierItem::NewTitle, this, [this]() {
63+
this->pTitle.requestUpdate();
64+
});
65+
66+
QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, this, [this]() {
67+
this->pIconName.requestUpdate();
68+
this->pIconPixmaps.requestUpdate();
69+
this->pIconThemePath.requestUpdate();
70+
});
71+
72+
QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, this, [this]() {
73+
this->pOverlayIconName.requestUpdate();
74+
this->pOverlayIconPixmaps.requestUpdate();
75+
this->pIconThemePath.requestUpdate();
76+
});
77+
78+
QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, this, [this]() {
79+
this->pAttentionIconName.requestUpdate();
80+
this->pAttentionIconPixmaps.requestUpdate();
81+
this->pIconThemePath.requestUpdate();
82+
});
83+
84+
QObject::connect(this->item, &DBusStatusNotifierItem::NewToolTip, this, [this]() {
85+
this->pTooltip.requestUpdate();
86+
});
8087

8188
QObject::connect(&this->properties, &DBusPropertyGroup::getAllFinished, this, &StatusNotifierItem::onGetAllFinished);
8289
QObject::connect(&this->properties, &DBusPropertyGroup::getAllFailed, this, &StatusNotifierItem::onGetAllFailed);
83-
QObject::connect(&this->pMenuPath, &AbstractDBusProperty::changed, this, &StatusNotifierItem::onMenuPathChanged);
8490
// clang-format on
8591

86-
QObject::connect(this->item, &DBusStatusNotifierItem::NewStatus, this, [this](QString value) {
87-
qCDebug(logStatusNotifierItem) << "Received update for" << this->pStatus.toString() << value;
88-
this->pStatus.set(std::move(value));
92+
this->bIcon.setBinding([this]() -> QString {
93+
if (this->bStatus.value() == Status::NeedsAttention) {
94+
auto name = this->bAttentionIconName.value();
95+
if (!name.isEmpty())
96+
return IconImageProvider::requestString(name, this->bIconThemePath.value());
97+
} else {
98+
auto name = this->bIconName.value();
99+
auto overlayName = this->bOverlayIconName.value();
100+
if (!name.isEmpty() && overlayName.isEmpty())
101+
return IconImageProvider::requestString(name, this->bIconThemePath.value());
102+
}
103+
104+
return this->imageHandle.url() % "/" % QString::number(this->pixmapIndex);
89105
});
90106

107+
this->bHasMenu.setBinding([this]() { return !this->bMenuPath.value().path().isEmpty(); });
108+
109+
QObject::connect(
110+
this->item,
111+
&DBusStatusNotifierItem::NewStatus,
112+
this,
113+
[this](const QString& value) {
114+
auto result = DBusDataTransform<Status::Enum>::fromWire(value);
115+
116+
if (result.isValid()) {
117+
this->bStatus = result.value;
118+
qCDebug(logStatusNotifierItem)
119+
<< "Received status update for" << this->properties.toString() << result.value;
120+
} else {
121+
qCWarning(logStatusNotifierItem)
122+
<< "Received invalid status update for" << this->properties.toString() << value;
123+
}
124+
}
125+
);
126+
91127
this->properties.setInterface(this->item);
92128
this->properties.updateAllViaGetAll();
93129
}
94130

95131
bool StatusNotifierItem::isValid() const { return this->item->isValid(); }
96132
bool StatusNotifierItem::isReady() const { return this->mReady; }
97133

98-
QString StatusNotifierItem::iconId() const {
99-
if (this->pStatus.get() == "NeedsAttention") {
100-
auto name = this->pAttentionIconName.get();
101-
if (!name.isEmpty()) return IconImageProvider::requestString(name, this->pIconThemePath.get());
102-
} else {
103-
auto name = this->pIconName.get();
104-
auto overlayName = this->pOverlayIconName.get();
105-
if (!name.isEmpty() && overlayName.isEmpty())
106-
return IconImageProvider::requestString(name, this->pIconThemePath.get());
107-
}
108-
109-
return this->imageHandle.url() + "/" + QString::number(this->iconIndex);
110-
}
111-
112134
QPixmap StatusNotifierItem::createPixmap(const QSize& size) const {
113-
auto needsAttention = this->pStatus.get() == "NeedsAttention";
135+
auto needsAttention = this->bStatus.value() == Status::NeedsAttention;
114136

115137
auto closestPixmap = [](const QSize& size, const DBusSniIconPixmapList& pixmaps) {
116138
const DBusSniIconPixmap* ret = nullptr;
@@ -135,11 +157,11 @@ QPixmap StatusNotifierItem::createPixmap(const QSize& size) const {
135157

136158
QPixmap pixmap;
137159
if (needsAttention) {
138-
if (!this->pAttentionIconName.get().isEmpty()) {
139-
auto icon = QIcon::fromTheme(this->pAttentionIconName.get());
160+
if (!this->bAttentionIconName.value().isEmpty()) {
161+
auto icon = QIcon::fromTheme(this->bAttentionIconName.value());
140162
pixmap = icon.pixmap(size.width(), size.height());
141163
} else {
142-
const auto* icon = closestPixmap(size, this->pAttentionIconPixmaps.get());
164+
const auto* icon = closestPixmap(size, this->bAttentionIconPixmaps.value());
143165

144166
if (icon != nullptr) {
145167
const auto image =
@@ -149,11 +171,11 @@ QPixmap StatusNotifierItem::createPixmap(const QSize& size) const {
149171
}
150172
}
151173
} else {
152-
if (!this->pIconName.get().isEmpty()) {
153-
auto icon = QIcon::fromTheme(this->pIconName.get());
174+
if (!this->bIconName.value().isEmpty()) {
175+
auto icon = QIcon::fromTheme(this->bIconName.value());
154176
pixmap = icon.pixmap(size.width(), size.height());
155177
} else {
156-
const auto* icon = closestPixmap(size, this->pIconPixmaps.get());
178+
const auto* icon = closestPixmap(size, this->bIconPixmaps.value());
157179

158180
if (icon != nullptr) {
159181
const auto image =
@@ -164,11 +186,11 @@ QPixmap StatusNotifierItem::createPixmap(const QSize& size) const {
164186
}
165187

166188
QPixmap overlay;
167-
if (!this->pOverlayIconName.get().isEmpty()) {
168-
auto icon = QIcon::fromTheme(this->pOverlayIconName.get());
189+
if (!this->bOverlayIconName.value().isEmpty()) {
190+
auto icon = QIcon::fromTheme(this->bOverlayIconName.value());
169191
overlay = icon.pixmap(pixmap.width(), pixmap.height());
170192
} else {
171-
const auto* icon = closestPixmap(pixmap.size(), this->pOverlayIconPixmaps.get());
193+
const auto* icon = closestPixmap(pixmap.size(), this->bOverlayIconPixmaps.value());
172194

173195
if (icon != nullptr) {
174196
const auto image =
@@ -231,17 +253,14 @@ void StatusNotifierItem::scroll(qint32 delta, bool horizontal) const {
231253
this->item->Scroll(delta, horizontal ? "horizontal" : "vertical");
232254
}
233255

234-
void StatusNotifierItem::updateIcon() {
235-
this->iconIndex++;
236-
emit this->iconChanged();
237-
}
256+
void StatusNotifierItem::updatePixmapIndex() { this->pixmapIndex = this->pixmapIndex + 1; }
238257

239258
DBusMenuHandle* StatusNotifierItem::menuHandle() {
240-
return this->pMenuPath.get().path().isEmpty() ? nullptr : &this->mMenuHandle;
259+
return this->bMenuPath.value().path().isEmpty() ? nullptr : &this->mMenuHandle;
241260
}
242261

243262
void StatusNotifierItem::onMenuPathChanged() {
244-
this->mMenuHandle.setAddress(this->item->service(), this->pMenuPath.get().path());
263+
this->mMenuHandle.setAddress(this->item->service(), this->bMenuPath.value().path());
245264
}
246265

247266
void StatusNotifierItem::onGetAllFinished() {
@@ -282,41 +301,6 @@ TrayImageHandle::requestPixmap(const QString& /*unused*/, QSize* size, const QSi
282301
return pixmap;
283302
}
284303

285-
QString StatusNotifierItem::id() const { return this->pId.get(); }
286-
QString StatusNotifierItem::title() const { return this->pTitle.get(); }
287-
288-
Status::Enum StatusNotifierItem::status() const {
289-
auto status = this->pStatus.get();
290-
291-
if (status == "Passive") return Status::Passive;
292-
if (status == "Active") return Status::Active;
293-
if (status == "NeedsAttention") return Status::NeedsAttention;
294-
295-
qCWarning(logStatusNotifierItem) << "Nonconformant StatusNotifierItem status" << status
296-
<< "returned for" << this->properties.toString();
297-
298-
return Status::Passive;
299-
}
300-
301-
Category::Enum StatusNotifierItem::category() const {
302-
auto category = this->pCategory.get();
303-
304-
if (category == "ApplicationStatus") return Category::ApplicationStatus;
305-
if (category == "SystemServices") return Category::SystemServices;
306-
if (category == "Hardware") return Category::Hardware;
307-
308-
qCWarning(logStatusNotifierItem) << "Nonconformant StatusNotifierItem category" << category
309-
<< "returned for" << this->properties.toString();
310-
311-
return Category::ApplicationStatus;
312-
}
313-
314-
QString StatusNotifierItem::tooltipTitle() const { return this->pTooltip.get().title; }
315-
QString StatusNotifierItem::tooltipDescription() const { return this->pTooltip.get().description; }
316-
317-
bool StatusNotifierItem::hasMenu() const { return !this->pMenuPath.get().path().isEmpty(); }
318-
bool StatusNotifierItem::onlyMenu() const { return this->pIsMenu.get(); }
319-
320304
void StatusNotifierItem::display(QObject* parentWindow, qint32 relativeX, qint32 relativeY) {
321305
if (!this->menuHandle()) {
322306
qCritical() << "No menu present for" << this;
@@ -352,3 +336,30 @@ void StatusNotifierItem::display(QObject* parentWindow, qint32 relativeX, qint32
352336
}
353337

354338
} // namespace qs::service::sni
339+
340+
namespace qs::dbus {
341+
using namespace qs::service::sni;
342+
343+
DBusResult<Status::Enum> DBusDataTransform<Status::Enum>::fromWire(const QString& wire) {
344+
if (wire == QStringLiteral("Passive")) return DBusResult(Status::Passive);
345+
if (wire == QStringLiteral("Active")) return DBusResult(Status::Active);
346+
if (wire == QStringLiteral("NeedsAttention")) return DBusResult(Status::NeedsAttention);
347+
348+
return DBusResult<Status::Enum>(QDBusError(
349+
QDBusError::InvalidArgs,
350+
QString("Nonconformant StatusNotifierItem Status: %1").arg(wire)
351+
));
352+
}
353+
354+
DBusResult<Category::Enum> DBusDataTransform<Category::Enum>::fromWire(const QString& wire) {
355+
if (wire == "ApplicationStatus") return DBusResult(Category::ApplicationStatus);
356+
if (wire == "SystemServices") return DBusResult(Category::SystemServices);
357+
if (wire == "Hardware") return DBusResult(Category::Hardware);
358+
359+
return DBusResult<Category::Enum>(QDBusError(
360+
QDBusError::InvalidArgs,
361+
QString("Nonconformant StatusNotifierItem Category: %1").arg(wire)
362+
));
363+
}
364+
365+
} // namespace qs::dbus

0 commit comments

Comments
 (0)