Skip to content

Commit 6181234

Browse files
committed
service/tray: account for more edge cases and add placeholder img
1 parent 54bf485 commit 6181234

File tree

7 files changed

+117
-35
lines changed

7 files changed

+117
-35
lines changed

src/core/iconimageprovider.cpp

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

3+
#include <qcolor.h>
34
#include <qicon.h>
5+
#include <qlogging.h>
6+
#include <qpainter.h>
47
#include <qpixmap.h>
58
#include <qsize.h>
69
#include <qstring.h>
@@ -10,8 +13,32 @@ IconImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& re
1013
auto icon = QIcon::fromTheme(id);
1114

1215
auto targetSize = requestedSize.isValid() ? requestedSize : QSize(100, 100);
16+
if (targetSize.width() == 0 || targetSize.height() == 0) targetSize = QSize(2, 2);
1317
auto pixmap = icon.pixmap(targetSize.width(), targetSize.height());
1418

19+
if (pixmap.isNull()) {
20+
qWarning() << "Could not load icon" << id << "at size" << targetSize << "from request";
21+
pixmap = IconImageProvider::missingPixmap(targetSize);
22+
}
23+
1524
if (size != nullptr) *size = pixmap.size();
1625
return pixmap;
1726
}
27+
28+
QPixmap IconImageProvider::missingPixmap(const QSize& size) {
29+
auto width = size.width() % 2 == 0 ? size.width() : size.width() + 1;
30+
auto height = size.height() % 2 == 0 ? size.height() : size.height() + 1;
31+
if (width < 2) width = 2;
32+
if (height < 2) height = 2;
33+
34+
auto pixmap = QPixmap(width, height);
35+
pixmap.fill(QColorConstants::Black);
36+
auto painter = QPainter(&pixmap);
37+
38+
auto halfWidth = width / 2;
39+
auto halfHeight = height / 2;
40+
auto purple = QColor(0xd900d8);
41+
painter.fillRect(halfWidth, 0, halfWidth, halfHeight, purple);
42+
painter.fillRect(0, halfHeight, halfWidth, halfHeight, purple);
43+
return pixmap;
44+
}

src/core/iconimageprovider.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ class IconImageProvider: public QQuickImageProvider {
88
explicit IconImageProvider(): QQuickImageProvider(QQuickImageProvider::Pixmap) {}
99

1010
QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override;
11+
12+
static QPixmap missingPixmap(const QSize& size);
1113
};

src/services/status_notifier/item.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ Q_LOGGING_CATEGORY(logStatusNotifierItem, "quickshell.service.sni.item", QtWarni
2525

2626
namespace qs::service::sni {
2727

28-
StatusNotifierItem::StatusNotifierItem(const QString& address, QObject* parent): QObject(parent) {
29-
// spec is unclear about what exactly an item address is, so split off anything but the connection path
30-
auto conn = address.split("/").value(0);
31-
this->item =
32-
new DBusStatusNotifierItem(conn, "/StatusNotifierItem", QDBusConnection::sessionBus(), this);
28+
StatusNotifierItem::StatusNotifierItem(const QString& address, QObject* parent)
29+
: QObject(parent)
30+
, watcherId(address) {
31+
// spec is unclear about what exactly an item address is, so account for both combinations
32+
auto splitIdx = address.indexOf('/');
33+
auto conn = splitIdx == -1 ? address : address.sliced(0, splitIdx);
34+
auto path = splitIdx == -1 ? "/StatusNotifierItem" : address.sliced(splitIdx);
35+
36+
this->item = new DBusStatusNotifierItem(conn, path, QDBusConnection::sessionBus(), this);
3337

3438
if (!this->item->isValid()) {
3539
qCWarning(logStatusNotifierHost).noquote() << "Cannot create StatusNotifierItem for" << conn;
@@ -85,8 +89,7 @@ QString StatusNotifierItem::iconId() const {
8589
if (!name.isEmpty() && overlayName.isEmpty()) return QString("image://icon/") + name;
8690
}
8791

88-
return QString("image://service.sni/") + this->item->service() + "/"
89-
+ QString::number(this->iconIndex);
92+
return QString("image://service.sni/") + this->watcherId + "/" + QString::number(this->iconIndex);
9093
}
9194

9295
QPixmap StatusNotifierItem::createPixmap(const QSize& size) const {

src/services/status_notifier/item.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ private slots:
6161

6262
// bumped to inhibit caching
6363
quint32 iconIndex = 0;
64+
QString watcherId;
6465
};
6566

6667
} // namespace qs::service::sni

src/services/status_notifier/trayimageprovider.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,37 @@
66
#include <qsize.h>
77
#include <qstring.h>
88

9+
#include "../../core/iconimageprovider.hpp"
910
#include "host.hpp"
1011

1112
namespace qs::service::sni {
1213

1314
QPixmap
1415
TrayImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) {
15-
auto split = id.split('/');
16-
if (split.size() != 2) {
16+
QPixmap pixmap;
17+
18+
auto targetSize = requestedSize.isValid() ? requestedSize : QSize(100, 100);
19+
if (targetSize.width() == 0 || targetSize.height() == 0) targetSize = QSize(2, 2);
20+
21+
auto lastSplit = id.lastIndexOf('/');
22+
if (lastSplit == -1) {
1723
qCWarning(logStatusNotifierHost) << "Invalid image request:" << id;
18-
return QPixmap();
19-
}
24+
} else {
25+
auto path = id.sliced(0, lastSplit);
2026

21-
auto* item = StatusNotifierHost::instance()->itemByService(split[0]);
27+
auto* item = StatusNotifierHost::instance()->itemByService(path);
28+
29+
if (item == nullptr) {
30+
qCWarning(logStatusNotifierHost) << "Image requested for nonexistant service" << path;
31+
} else {
32+
pixmap = item->createPixmap(targetSize);
33+
}
34+
}
2235

23-
if (item == nullptr) {
24-
qCWarning(logStatusNotifierHost) << "Image requested for nonexistant service" << split[0];
25-
return QPixmap();
36+
if (pixmap.isNull()) {
37+
pixmap = IconImageProvider::missingPixmap(targetSize);
2638
}
2739

28-
auto pixmap = item->createPixmap(requestedSize);
2940
if (size != nullptr) *size = pixmap.size();
3041
return pixmap;
3142
}

src/services/status_notifier/watcher.cpp

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,29 @@ void StatusNotifierWatcher::onServiceUnregistered(const QString& service) {
6868
<< "Active StatusNotifierWatcher unregistered, attempting registration";
6969
this->tryRegister();
7070
return;
71-
} else if (this->items.removeAll(service) != 0) {
72-
qCDebug(logStatusNotifierWatcher).noquote()
73-
<< "Unregistered StatusNotifierItem" << service << "from watcher";
74-
emit this->StatusNotifierItemUnregistered(service);
75-
} else if (this->hosts.removeAll(service) != 0) {
76-
qCDebug(logStatusNotifierWatcher).noquote()
77-
<< "Unregistered StatusNotifierHost" << service << "from watcher";
78-
emit this->StatusNotifierHostUnregistered();
71+
;
7972
} else {
80-
qCWarning(logStatusNotifierWatcher).noquote()
81-
<< "Got service unregister event for untracked service" << service;
73+
QString qualifiedItem;
74+
this->items.removeIf([&](const QString& item) {
75+
if (item.startsWith(service)) {
76+
qualifiedItem = item;
77+
return true;
78+
} else return false;
79+
});
80+
81+
if (!qualifiedItem.isEmpty()) {
82+
qCDebug(logStatusNotifierWatcher).noquote()
83+
<< "Unregistered StatusNotifierItem" << qualifiedItem << "from watcher";
84+
85+
emit this->StatusNotifierItemUnregistered(qualifiedItem);
86+
} else if (this->hosts.removeAll(service) != 0) {
87+
qCDebug(logStatusNotifierWatcher).noquote()
88+
<< "Unregistered StatusNotifierHost" << service << "from watcher";
89+
emit this->StatusNotifierHostUnregistered();
90+
} else {
91+
qCWarning(logStatusNotifierWatcher).noquote()
92+
<< "Got service unregister event for untracked service" << service;
93+
}
8294
}
8395

8496
this->serviceWatcher.removeWatchedService(service);
@@ -112,23 +124,44 @@ void StatusNotifierWatcher::RegisterStatusNotifierHost(const QString& host) {
112124
}
113125

114126
void StatusNotifierWatcher::RegisterStatusNotifierItem(const QString& item) {
115-
if (this->items.contains(item)) {
127+
auto qualifiedItem = this->qualifiedItem(item);
128+
auto service = qualifiedItem.split("/").at(0);
129+
130+
if (this->items.contains(qualifiedItem)) {
116131
qCDebug(logStatusNotifierWatcher).noquote()
117-
<< "Skipping duplicate registration of StatusNotifierItem" << item << "to watcher";
132+
<< "Skipping duplicate registration of StatusNotifierItem" << qualifiedItem << "to watcher";
118133
return;
119134
}
120135

121-
if (!QDBusConnection::sessionBus().interface()->serviceOwner(item).isValid()) {
136+
if (!QDBusConnection::sessionBus().interface()->serviceOwner(service).isValid()) {
122137
qCWarning(logStatusNotifierWatcher).noquote()
123-
<< "Ignoring invalid StatusNotifierItem registration of" << item << "to watcher";
138+
<< "Ignoring invalid StatusNotifierItem registration of" << qualifiedItem << "to watcher";
124139
return;
125140
}
126141

127-
this->serviceWatcher.addWatchedService(item);
128-
this->items.push_back(item);
142+
this->serviceWatcher.addWatchedService(service);
143+
this->items.push_back(qualifiedItem);
144+
129145
qCDebug(logStatusNotifierWatcher).noquote()
130-
<< "Registered StatusNotifierItem" << item << "to watcher";
131-
emit this->StatusNotifierItemRegistered(item);
146+
<< "Registered StatusNotifierItem" << qualifiedItem << "to watcher";
147+
148+
emit this->StatusNotifierItemRegistered(qualifiedItem);
149+
}
150+
151+
QString StatusNotifierWatcher::qualifiedItem(const QString& item) {
152+
// Registered items are often missing either the service id or the path.
153+
QString qualifiedItem;
154+
if (item.startsWith("/")) {
155+
qualifiedItem = this->message().service() + item;
156+
} else {
157+
qualifiedItem = item;
158+
}
159+
160+
if (!qualifiedItem.contains("/")) {
161+
qualifiedItem += "/StatusNotifierItem";
162+
}
163+
164+
return qualifiedItem;
132165
}
133166

134167
StatusNotifierWatcher* StatusNotifierWatcher::instance() {

src/services/status_notifier/watcher.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <qdbuscontext.h>
34
#include <qdbusinterface.h>
45
#include <qdbusservicewatcher.h>
56
#include <qlist.h>
@@ -12,7 +13,9 @@ Q_DECLARE_LOGGING_CATEGORY(logStatusNotifierWatcher);
1213

1314
namespace qs::service::sni {
1415

15-
class StatusNotifierWatcher: public QObject {
16+
class StatusNotifierWatcher
17+
: public QObject
18+
, protected QDBusContext {
1619
Q_OBJECT;
1720
Q_PROPERTY(qint32 ProtocolVersion READ protocolVersion);
1821
Q_PROPERTY(bool IsStatusNotifierHostRegistered READ isHostRegistered);
@@ -46,6 +49,8 @@ private slots:
4649
void onServiceUnregistered(const QString& service);
4750

4851
private:
52+
QString qualifiedItem(const QString& item);
53+
4954
QDBusServiceWatcher serviceWatcher;
5055
QList<QString> hosts;
5156
QList<QString> items;

0 commit comments

Comments
 (0)