fix(tray): detect dynamic pixmap updates

This commit is contained in:
Ly-sec
2026-05-09 18:24:12 +02:00
parent 44e85bb630
commit 7eeb715397
2 changed files with 49 additions and 4 deletions
+47 -4
View File
@@ -350,6 +350,20 @@ void TrayWidget::syncState(Renderer& renderer) {
for (const auto& item : next_items) {
stillPresent[item.id] = true;
auto hashVec = [](const std::vector<std::uint8_t>& vec) -> std::size_t {
if (vec.empty()) {
return 0;
}
return std::hash<std::string_view>{}(std::string_view(reinterpret_cast<const char*>(vec.data()), vec.size()));
};
const std::size_t currentHash = hashVec(item.iconArgb32) ^ (hashVec(item.attentionArgb32) << 1);
if (!m_initialPixmaps.contains(item.id)) {
m_initialPixmaps[item.id] = currentHash;
} else if (m_initialPixmaps[item.id] != currentHash) {
m_preferPixmap[item.id] = true;
}
const auto prevIt = previousById.find(item.id);
if (prevIt == previousById.end() || prevIt->second == nullptr) {
continue;
@@ -362,7 +376,10 @@ void TrayWidget::syncState(Renderer& renderer) {
prev.attentionIconName != item.attentionIconName || prev.iconThemePath != item.iconThemePath ||
prev.needsAttention != item.needsAttention || prev.status != item.status ||
prev.overlayWidth != item.overlayWidth || prev.overlayHeight != item.overlayHeight ||
prev.overlayArgb32 != item.overlayArgb32) {
prev.overlayArgb32 != item.overlayArgb32 || prev.iconWidth != item.iconWidth ||
prev.iconHeight != item.iconHeight || prev.iconArgb32 != item.iconArgb32 ||
prev.attentionWidth != item.attentionWidth || prev.attentionHeight != item.attentionHeight ||
prev.attentionArgb32 != item.attentionArgb32) {
kLog.debug("tray widget invalidate icon cache id={} icon='{}'->'{}' overlay='{}'->'{}' attention='{}'->'{}' "
"status={}=>{}",
item.id, prev.iconName, item.iconName, prev.overlayIconName, item.overlayIconName,
@@ -377,6 +394,20 @@ void TrayWidget::syncState(Renderer& renderer) {
++it;
}
}
for (auto it = m_initialPixmaps.begin(); it != m_initialPixmaps.end();) {
if (!stillPresent.contains(it->first)) {
it = m_initialPixmaps.erase(it);
} else {
++it;
}
}
for (auto it = m_preferPixmap.begin(); it != m_preferPixmap.end();) {
if (!stillPresent.contains(it->first)) {
it = m_preferPixmap.erase(it);
} else {
++it;
}
}
m_items = next_items;
m_rebuildPending = true;
@@ -777,13 +808,24 @@ void TrayWidget::buildDesktopIconIndex() {
}
std::string TrayWidget::resolveIconPath(const TrayItemInfo& item) {
if (const auto it = m_preferPixmap.find(item.id); it != m_preferPixmap.end() && it->second) {
kLog.debug("tray widget resolve id={} source=dynamic-pixmap", item.id);
return {};
}
if (const auto it = m_preferredIconPaths.find(item.id); it != m_preferredIconPaths.end() && !it->second.empty()) {
kLog.debug("tray widget resolve id={} source=cached path={}", item.id, it->second);
return it->second;
}
const std::string preferred =
item.needsAttention && !item.attentionIconName.empty() ? item.attentionIconName : item.iconName;
std::string preferred;
if (item.needsAttention && !item.attentionIconName.empty()) {
preferred = item.attentionIconName;
} else if (item.needsAttention && !item.attentionArgb32.empty()) {
preferred = "";
} else {
preferred = item.iconName;
}
if (const auto themed = resolveFromTrayThemePath(item.iconThemePath, preferred); !themed.empty()) {
kLog.debug("tray widget resolve id={} source=theme-path variant='{}' path={}", item.id, preferred, themed);
@@ -847,7 +889,8 @@ std::string TrayWidget::resolveIconPath(const TrayItemInfo& item) {
// When an explicit tray IconName is provided, treat it as authoritative.
// Falling back to generic app-id/title mappings can hide stateful icon
// changes (e.g. indicator on/off variants) behind a constant app icon.
if (preferred.empty()) {
const bool hasTargetPixmap = item.needsAttention ? !item.attentionArgb32.empty() : !item.iconArgb32.empty();
if (preferred.empty() && !hasTargetPixmap) {
candidates.emplace_back("itemName", &item.itemName);
candidates.emplace_back("title", &item.title);
candidates.emplace_back("objectPath", &item.objectPath);
+2
View File
@@ -49,6 +49,8 @@ private:
std::vector<std::string> m_hiddenItems;
std::vector<std::string> m_pinnedItems;
std::vector<Image*> m_loadedImages;
std::unordered_map<std::string, std::size_t> m_initialPixmaps;
std::unordered_map<std::string, bool> m_preferPixmap;
float m_contentHeight = 0.0f;
bool m_isVertical = false;
bool m_rebuildPending = true;