core/icon: stop reusing image ids (dbusmenu, notifications)

Fixes issues caused by the QML engine caching old pixmaps using the
same IDs as new ones, notably dbusmenu icons.
This commit is contained in:
outfoxxed 2025-01-22 23:10:49 -08:00
parent c6791cf1f2
commit cdaff2967f
Signed by untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
8 changed files with 75 additions and 58 deletions

View file

@ -59,8 +59,8 @@ QString DBusMenuItem::icon() const {
this->iconName,
this->menu->iconThemePath.value().join(':')
);
} else if (this->image != nullptr) {
return this->image->url();
} else if (this->image.hasData()) {
return this->image.url();
} else return nullptr;
}
@ -113,7 +113,7 @@ void DBusMenuItem::updateProperties(const QVariantMap& properties, const QString
auto originalEnabled = this->mEnabled;
auto originalVisible = this->visible;
auto originalIconName = this->iconName;
auto* originalImage = this->image;
auto imageChanged = false;
auto originalIsSeparator = this->mSeparator;
auto originalButtonType = this->mButtonType;
auto originalToggleState = this->mCheckState;
@ -173,12 +173,16 @@ void DBusMenuItem::updateProperties(const QVariantMap& properties, const QString
if (iconData.canConvert<QByteArray>()) {
auto data = iconData.value<QByteArray>();
if (data.isEmpty()) {
this->image = nullptr;
} else if (this->image == nullptr || this->image->data != data) {
this->image = new DBusMenuPngImage(data, this);
imageChanged = this->image.hasData();
this->image.data.clear();
} else if (!this->image.hasData() || this->image.data != data) {
imageChanged = true;
this->image.data = data;
this->image.imageChanged();
}
} else if (removed.isEmpty() || removed.contains("icon-data")) {
this->image = nullptr;
imageChanged = this->image.hasData();
image.data.clear();
}
auto type = properties.value("type");
@ -239,17 +243,13 @@ void DBusMenuItem::updateProperties(const QVariantMap& properties, const QString
if (this->mSeparator != originalIsSeparator) emit this->isSeparatorChanged();
if (this->displayChildren != originalDisplayChildren) emit this->hasChildrenChanged();
if (this->iconName != originalIconName || this->image != originalImage) {
if (this->image != originalImage) {
delete originalImage;
}
if (this->iconName != originalIconName || imageChanged) {
emit this->iconChanged();
}
qCDebug(logDbusMenu).nospace() << "Updated properties of " << this << " { label=" << this->mText
<< ", enabled=" << this->mEnabled << ", visible=" << this->visible
<< ", iconName=" << this->iconName << ", iconData=" << this->image
<< ", iconName=" << this->iconName << ", iconData=" << &this->image
<< ", separator=" << this->mSeparator
<< ", toggleType=" << this->mButtonType
<< ", toggleState=" << this->mCheckState

View file

@ -30,7 +30,17 @@ namespace qs::dbus::dbusmenu {
using menu::QsMenuEntry;
class DBusMenu;
class DBusMenuPngImage;
class DBusMenuItem;
class DBusMenuPngImage: public QsIndexedImageHandle {
public:
explicit DBusMenuPngImage(): QsIndexedImageHandle(QQuickImageProvider::Image) {}
[[nodiscard]] bool hasData() const { return !data.isEmpty(); }
QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override;
QByteArray data;
};
///! Menu item shared by an external program.
/// Menu item shared by an external program via the
@ -93,7 +103,7 @@ private:
bool visible = true;
bool mSeparator = false;
QString iconName;
DBusMenuPngImage* image = nullptr;
DBusMenuPngImage image;
menu::QsMenuButtonType::Enum mButtonType = menu::QsMenuButtonType::None;
Qt::CheckState mCheckState = Qt::Unchecked;
bool displayChildren = false;
@ -156,17 +166,6 @@ private:
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);