From db47c62c2b0acd6e5cf8f413a7839b092ed25cb7 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:47:53 +0100 Subject: [PATCH 1/9] Implement deterministic colored default logos for Friend Nodes, Channels, Boards, and Wikis --- .../src/gui/Posted/PostedDialog.cpp | 3 +- .../src/gui/WikiPoos/WikiDialog.cpp | 3 +- retroshare-gui/src/gui/common/AvatarDefs.cpp | 8 +- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 119 ++++++++++++++++++ retroshare-gui/src/gui/gxs/GxsIdDetails.h | 3 + .../src/gui/gxschannels/GxsChannelDialog.cpp | 3 +- retroshare-gui/src/gui/icons.qrc | 4 + retroshare-gui/src/gui/icons/board.png | Bin 0 -> 5285 bytes retroshare-gui/src/gui/icons/channel.png | Bin 0 -> 3816 bytes retroshare-gui/src/gui/icons/person.png | Bin 0 -> 2457 bytes retroshare-gui/src/gui/icons/wiki.png | Bin 0 -> 6168 bytes 11 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 retroshare-gui/src/gui/icons/board.png create mode 100644 retroshare-gui/src/gui/icons/channel.png create mode 100644 retroshare-gui/src/gui/icons/person.png create mode 100644 retroshare-gui/src/gui/icons/wiki.png diff --git a/retroshare-gui/src/gui/Posted/PostedDialog.cpp b/retroshare-gui/src/gui/Posted/PostedDialog.cpp index 733878810..590c3e77d 100644 --- a/retroshare-gui/src/gui/Posted/PostedDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedDialog.cpp @@ -24,6 +24,7 @@ #include "PostedListWidgetWithModel.h" #include "PostedUserNotify.h" #include "gui/gxs/GxsGroupShareKey.h" +#include "gui/gxs/GxsIdDetails.h" #include "gui/settings/rsharesettings.h" #include "gui/common/GroupTreeWidget.h" #include "util/misc.h" @@ -236,7 +237,7 @@ void PostedDialog::groupInfoToGroupItemInfo(const RsGxsGenericGroupData *groupDa groupItemInfo.icon = image; } else - groupItemInfo.icon = FilesDefs::getIconFromQtResourcePath(":icons/png/postedlinks.png"); + groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(RsGxsId(postedGroupData->mMeta.mGroupId), ":icons/board.png", GxsIdDetails::ORIGINAL); groupItemInfo.description = QString::fromUtf8(postedGroupData->mDescription.c_str()); } diff --git a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp index 084c9a808..105e33034 100644 --- a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp +++ b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp @@ -30,6 +30,7 @@ #include "gui/WikiPoos/WikiEditDialog.h" #include "gui/settings/rsharesettings.h" #include "gui/gxs/WikiGroupDialog.h" +#include "gui/gxs/GxsIdDetails.h" #include "util/DateTime.h" #include @@ -730,7 +731,7 @@ void WikiDialog::GroupMetaDataToGroupItemInfo(const RsGroupMetaData &groupInfo, groupItemInfo.lastpost = DateTime::DateTimeFromTime_t(groupInfo.mLastPost); groupItemInfo.subscribeFlags = groupInfo.mSubscribeFlags; - groupItemInfo.icon = QIcon(IMAGE_WIKI); + groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(RsGxsId(groupInfo.mGroupId), IMAGE_WIKI, GxsIdDetails::ORIGINAL); } diff --git a/retroshare-gui/src/gui/common/AvatarDefs.cpp b/retroshare-gui/src/gui/common/AvatarDefs.cpp index 608e6e285..e5390b0c4 100644 --- a/retroshare-gui/src/gui/common/AvatarDefs.cpp +++ b/retroshare-gui/src/gui/common/AvatarDefs.cpp @@ -55,7 +55,7 @@ bool AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, cons rsChats->getAvatarData(RsPeerId(sslId), data, size); if (size == 0) { if (!defaultImage.isEmpty()) { - avatar = FilesDefs::getPixmapFromQtResourcePath(defaultImage); + avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(sslId.toStdString()), ":icons/png/person.png", GxsIdDetails::LARGE); } return false; } @@ -110,12 +110,14 @@ bool AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const } if (size == 0) { - avatar = FilesDefs::getPixmapFromQtResourcePath(defaultImage); + if (!defaultImage.isEmpty()) { + avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(gpgId.toStdString()), ":icons/png/person.png", GxsIdDetails::LARGE); + } return false; } /* load image */ - GxsIdDetails::loadPixmapFromData(data, size, avatar); + GxsIdDetails::loadPixmapFromData(data, size, avatar, GxsIdDetails::LARGE); free(data); diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 5c1c11b49..7f647b2c1 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -447,6 +447,125 @@ const QPixmap GxsIdDetails::makeDefaultIcon(const RsGxsId& id, AvatarSize size) return image; } +QPixmap GxsIdDetails::generateColoredIcon(const QString& idStr, const QString& iconPath, int size) +{ + // Generate a color from the ID hash + uint hash = qHash(idStr); + + // Use hash to determine hue (0-359), with fixed saturation and lightness for pastel look + int hue = hash % 360; + int saturation = 150; // Mid saturation for pastel colors + int lightness = 180; // Light for pastel colors + + QColor backgroundColor = QColor::fromHsl(hue, saturation, lightness); + + // Create the pixmap + QPixmap pixmap(size, size); + pixmap.fill(Qt::transparent); + + QPainter painter(&pixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setRenderHint(QPainter::SmoothPixmapTransform, true); + + // Draw colored circle + painter.setPen(Qt::NoPen); + painter.setBrush(backgroundColor); + painter.drawEllipse(0, 0, size, size); + + // Load and overlay the category icon + QPixmap categoryIcon(iconPath); + if (!categoryIcon.isNull()) + { + // Scale icon to ~70% of total size + int iconSize = static_cast(size * 0.7); + QPixmap scaledIcon = categoryIcon.scaled(iconSize, iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + + // Center the icon + int x = (size - scaledIcon.width()) / 2; + int y = (size - scaledIcon.height()) / 2; + painter.drawPixmap(x, y, scaledIcon); + } + + painter.end(); + + return pixmap; +} + +const QPixmap GxsIdDetails::makeDefaultGroupIcon(const RsGxsId& id, const QString& iconPath, AvatarSize size) +{ + checkCleanImagesCache(); + + time_t now = time(NULL); + + if(id.isNull()) + std::cerr << "Weird: null ID" << std::endl; + + QMutexLocker lock(&mIconCacheMutex); + auto& it = mDefaultIconCache[id]; + + if(it[(int)size].second.width() > 0) + { + it[(int)size].first = now; + return it[(int)size].second; + } + + int S = 0; + + switch(size) + { + case SMALL: S = 48 ; break; + default: + case MEDIUM: S = 96 ; break; + case ORIGINAL: + case LARGE: S = 192 ; break; + } + + QPixmap pixmap = generateColoredIcon(QString::fromStdString(id.toStdString()), iconPath, S); + + it[(int)size] = std::make_pair(now, pixmap); + + return pixmap; +} + +const QPixmap GxsIdDetails::makeDefaultGroupIcon(const QString& idStr, const QString& iconPath, AvatarSize size) +{ + checkCleanImagesCache(); + + time_t now = time(NULL); + + // Convert QString to RsGxsId for caching purposes + RsGxsId id(idStr.toStdString()); + + if(id.isNull()) + std::cerr << "Weird: null ID" << std::endl; + + QMutexLocker lock(&mIconCacheMutex); + auto& it = mDefaultIconCache[id]; + + if(it[(int)size].second.width() > 0) + { + it[(int)size].first = now; + return it[(int)size].second; + } + + int S = 0; + + switch(size) + { + case SMALL: S = 48 ; break; + default: + case MEDIUM: S = 96 ; break; + case ORIGINAL: + case LARGE: S = 192 ; break; + } + + QPixmap pixmap = generateColoredIcon(idStr, iconPath, S); + + it[(int)size] = std::make_pair(now, pixmap); + + return pixmap; +} + void GxsIdDetails::debug_dumpImagesCache() { QMutexLocker lock(&mIconCacheMutex); diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.h b/retroshare-gui/src/gui/gxs/GxsIdDetails.h index 122b5e089..776036576 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.h +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.h @@ -113,6 +113,8 @@ public: // These two methods use a cache so as to minimize the memory impact of avatars. static const QPixmap makeDefaultIcon(const RsGxsId& id, AvatarSize size = MEDIUM); + static const QPixmap makeDefaultGroupIcon(const RsGxsId& id, const QString& iconPath, AvatarSize size = MEDIUM); + static const QPixmap makeDefaultGroupIcon(const QString& idStr, const QString& iconPath, AvatarSize size = MEDIUM); static bool loadPixmapFromData(const unsigned char *data, size_t data_len, QPixmap& pix, AvatarSize size = MEDIUM); static void checkCleanImagesCache(); static void debug_dumpImagesCache(); @@ -140,6 +142,7 @@ private: qreal shapeangle, qreal angle, quint16 size, QColor fillColor); static QPixmap drawIdentIcon(QString hash, quint16 width, bool rotate); + static QPixmap generateColoredIcon(const QString& idStr, const QString& iconPath, int size); private slots: void objectDestroyed(QObject *object); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 31dcc25a1..ec756ba17 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -30,6 +30,7 @@ #include "CreateGxsChannelMsg.h" #include "GxsChannelUserNotify.h" #include "gui/gxs/GxsGroupShareKey.h" +#include "gui/gxs/GxsIdDetails.h" #include "gui/feeds/GxsChannelPostItem.h" #include "gui/settings/rsharesettings.h" #include "gui/common/GroupTreeWidget.h" @@ -426,7 +427,7 @@ void GxsChannelDialog::groupInfoToGroupItemInfo(const RsGxsGenericGroupData *gro groupItemInfo.icon = image; } else - groupItemInfo.icon = FilesDefs::getIconFromQtResourcePath(":icons/png/channel.png"); + groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(RsGxsId(channelGroupData->mMeta.mGroupId), ":icons/channel.png", GxsIdDetails::ORIGINAL); groupItemInfo.description = QString::fromUtf8(channelGroupData->mDescription.c_str()); } diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 4d7c2e46e..58819ecdc 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -267,6 +267,10 @@ icons/yahoo.png icons/yandex.png icons/png/markdown-mark.png + icons/board.png + icons/channel.png + icons/person.png + icons/wiki.png icons/png/channel.png icons/png/circles-black.png icons/png/circles-gray.png diff --git a/retroshare-gui/src/gui/icons/board.png b/retroshare-gui/src/gui/icons/board.png new file mode 100644 index 0000000000000000000000000000000000000000..ab6baa466f26fb14c5540bfe0cef4214933c6281 GIT binary patch literal 5285 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 QW{VN9IBx@1n_NozAJ^ZONB{r; literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/icons/channel.png b/retroshare-gui/src/gui/icons/channel.png new file mode 100644 index 0000000000000000000000000000000000000000..b26cd02edda828343cb7f61392531006fd1c2859 GIT binary patch literal 3816 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 OfK!%^7PTk6;{OAy!UUWE literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/icons/person.png b/retroshare-gui/src/gui/icons/person.png new file mode 100644 index 0000000000000000000000000000000000000000..2404a95202feccb2f0b5bed8beecdee98a358eb7 GIT binary patch literal 2457 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 XmN&5poZHJp(N$6^sf10H}_(y7Au;`>#=u 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 Date: Wed, 14 Jan 2026 15:59:54 +0100 Subject: [PATCH 2/9] Update retroshare-gui/src/gui/gxs/GxsIdDetails.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 36 ++------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 7f647b2c1..2607d5f9e 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -529,41 +529,9 @@ const QPixmap GxsIdDetails::makeDefaultGroupIcon(const RsGxsId& id, const QStrin const QPixmap GxsIdDetails::makeDefaultGroupIcon(const QString& idStr, const QString& iconPath, AvatarSize size) { - checkCleanImagesCache(); - - time_t now = time(NULL); - - // Convert QString to RsGxsId for caching purposes + // Delegate to the RsGxsId overload to avoid duplicating caching logic RsGxsId id(idStr.toStdString()); - - if(id.isNull()) - std::cerr << "Weird: null ID" << std::endl; - - QMutexLocker lock(&mIconCacheMutex); - auto& it = mDefaultIconCache[id]; - - if(it[(int)size].second.width() > 0) - { - it[(int)size].first = now; - return it[(int)size].second; - } - - int S = 0; - - switch(size) - { - case SMALL: S = 48 ; break; - default: - case MEDIUM: S = 96 ; break; - case ORIGINAL: - case LARGE: S = 192 ; break; - } - - QPixmap pixmap = generateColoredIcon(idStr, iconPath, S); - - it[(int)size] = std::make_pair(now, pixmap); - - return pixmap; + return makeDefaultGroupIcon(id, iconPath, size); } void GxsIdDetails::debug_dumpImagesCache() From 24911bf6ba765c2c013135a8860ce813d4ed4c48 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:11:40 +0100 Subject: [PATCH 3/9] Fix icon paths for new colored default avatars --- _codeql_detected_source_root | 1 + retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp | 2 +- retroshare-gui/src/gui/common/AvatarDefs.cpp | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 000000000..945c9b46d --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp index 105e33034..1effae298 100644 --- a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp +++ b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp @@ -77,7 +77,7 @@ #define IMAGE_NEWFORUM ":/images/new_forum16.png" #define IMAGE_FORUMAUTHD ":/images/konv_message2.png" #define IMAGE_COPYLINK ":/images/copyrslink.png" -#define IMAGE_WIKI ":/icons/png/wiki.png" +#define IMAGE_WIKI ":icons/wiki.png" #define IMAGE_EDIT ":/icons/png/pencil-edit-button.png" diff --git a/retroshare-gui/src/gui/common/AvatarDefs.cpp b/retroshare-gui/src/gui/common/AvatarDefs.cpp index e5390b0c4..01299e482 100644 --- a/retroshare-gui/src/gui/common/AvatarDefs.cpp +++ b/retroshare-gui/src/gui/common/AvatarDefs.cpp @@ -55,7 +55,7 @@ bool AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, cons rsChats->getAvatarData(RsPeerId(sslId), data, size); if (size == 0) { if (!defaultImage.isEmpty()) { - avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(sslId.toStdString()), ":icons/png/person.png", GxsIdDetails::LARGE); + avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(sslId.toStdString()), ":icons/person.png", GxsIdDetails::LARGE); } return false; } @@ -111,7 +111,7 @@ bool AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const if (size == 0) { if (!defaultImage.isEmpty()) { - avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(gpgId.toStdString()), ":icons/png/person.png", GxsIdDetails::LARGE); + avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(gpgId.toStdString()), ":icons/person.png", GxsIdDetails::LARGE); } return false; } From 32cad564fe604d7acbe9b3c25d0802ac94cdb607 Mon Sep 17 00:00:00 2001 From: Akinniranye Samuel Tomiwa Date: Fri, 16 Jan 2026 00:46:54 +0100 Subject: [PATCH 4/9] Improve friend avatar fallbacks --- retroshare-gui/src/gui/common/FriendListModel.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendListModel.cpp b/retroshare-gui/src/gui/common/FriendListModel.cpp index 5c9d3a43b..8ab179e1a 100644 --- a/retroshare-gui/src/gui/common/FriendListModel.cpp +++ b/retroshare-gui/src/gui/common/FriendListModel.cpp @@ -1027,7 +1027,19 @@ QVariant RsFriendListModel::decorationRole(const EntryIndex& entry,int col) cons } if (!foundAvatar || sslAvatar.isNull()) { - sslAvatar = FilesDefs::getPixmapFromQtResourcePath(AVATAR_DEFAULT_IMAGE); + if (hn && !hn->child_node_indices.empty()) { + // Use first child node if available + std::string sslIdStr = mLocations[hn->child_node_indices[0]].node_info.id.toStdString(); + sslAvatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(sslIdStr), ":icons/person.png", GxsIdDetails::LARGE); + } + else if (bestNodeInformation != nullptr) { + // Fallback: Use the bestNodeInformation ID if no children exist + std::string bestSslIdStr = bestNodeInformation->node_info.id.toStdString(); + sslAvatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(bestSslIdStr), ":icons/person.png", GxsIdDetails::LARGE); + } + else { + sslAvatar = FilesDefs::getPixmapFromQtResourcePath(AVATAR_DEFAULT_IMAGE); + } } if (mDisplayStatusIcon) { @@ -1489,4 +1501,3 @@ bool RsFriendListModel::isProfileExpanded(const EntryIndex& e) const return mExpandedProfiles.find(s) != mExpandedProfiles.end(); } - From a259b1c110b5651a7434af1f2965e4cb6144f0b5 Mon Sep 17 00:00:00 2001 From: Akinniranye Samuel Tomiwa Date: Fri, 16 Jan 2026 18:07:50 +0100 Subject: [PATCH 5/9] Fix group icon cache keys and add separate cache for generated group avatars * Fix group icon cache keys * Update retroshare-gui/src/gui/gxs/GxsIdDetails.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 125 +++++++++++++------- retroshare-gui/src/gui/gxs/GxsIdDetails.h | 3 + 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 2607d5f9e..d67fdc7fd 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -74,6 +74,7 @@ uint32_t GxsIdDetails::mImagesAllocated = 0; time_t GxsIdDetails::mLastIconCacheCleaning = time(NULL); std::map[4] > GxsIdDetails::mDefaultIconCache ; +std::map[4] > GxsIdDetails::mDefaultGroupIconCache ; QMutex GxsIdDetails::mMutex; QMutex GxsIdDetails::mIconCacheMutex; @@ -81,6 +82,62 @@ QMutex GxsIdDetails::mIconCacheMutex; #define ICON_CACHE_STORAGE_TIME 240 #define DELAY_BETWEEN_ICON_CACHE_CLEANING 120 +static std::string groupIconCacheKey(const RsGxsId& id, const QString& iconPath) +{ + std::string key = id.toStdString(); + key.append("|"); + key.append(iconPath.toStdString()); + return key; +} + +template +static void cleanupIconCache(CacheMap& cache, time_t now, int& nb_deleted, uint32_t& size_deleted, uint32_t& total_size, const char* label) +{ + for(auto it(cache.begin());it!=cache.end();) + { + bool all_empty = true ; +#ifdef DEBUG_GXSIDDETAILS + std::cerr << " Examining pixmaps sizes for " << label << " " << it->first << "." << std::endl; +#endif + + for(int i=0;i<4;++i) + if(it->second[i].first>0) + { + if(it->second[i].first + ICON_CACHE_STORAGE_TIME < now && it->second[i].second.isDetached()) + { + int s = it->second[i].second.width()*it->second[i].second.height()*4; + +#ifdef DEBUG_GXSIDDETAILS + std::cerr << " Deleting pixmap " << it->first << " size " << i << " " << s << " bytes." << std::endl; +#endif + + it->second[i].second = QPixmap(); + it->second[i].first = 0; + ++nb_deleted; + size_deleted += s; + } + else + { + all_empty = false; + total_size += it->second[i].second.width()*it->second[i].second.height()*4; +#ifdef DEBUG_GXSIDDETAILS + std::cerr << " Keeping " << it->first << " size " << i << std::endl; +#endif + } + } + + if(all_empty) + { +#ifdef DEBUG_GXSIDDETAILS + std::cerr << " Deleting entry " << it->first << " because no pixmaps are stored here. " << std::endl; +#endif + it = cache.erase(it); + } + else + ++it; + } +} + void ReputationItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_ASSERT(index.isValid()); @@ -501,7 +558,7 @@ const QPixmap GxsIdDetails::makeDefaultGroupIcon(const RsGxsId& id, const QStrin std::cerr << "Weird: null ID" << std::endl; QMutexLocker lock(&mIconCacheMutex); - auto& it = mDefaultIconCache[id]; + auto& it = mDefaultGroupIconCache[groupIconCacheKey(id, iconPath)]; if(it[(int)size].second.width() > 0) { @@ -557,6 +614,24 @@ void GxsIdDetails::debug_dumpImagesCache() std::cerr << " None." << std::endl; } } + + for(const auto& it:mDefaultGroupIconCache) + { + std::cerr << " Group " << it.first << ":" << std::endl; + + for(uint32_t i=0;i<4;++i) + { + std::cerr << " Size #" << i << ": " ; + + if(it.second[i].first>0) + { + int s = it.second[i].second.width()*it.second[i].second.height()*4; + std::cerr << " Present. Size=" << s << " bytes. Age: " << time(nullptr)-it.second[i].first << " secs. ago. Used: " << !it.second[i].second.isDetached() << std::endl; + } + else + std::cerr << " None." << std::endl; + } + } } void GxsIdDetails::checkCleanImagesCache() @@ -576,52 +651,12 @@ void GxsIdDetails::checkCleanImagesCache() QMutexLocker lock(&mIconCacheMutex); - for(auto it(mDefaultIconCache.begin());it!=mDefaultIconCache.end();) - { - bool all_empty = true ; -#ifdef DEBUG_GXSIDDETAILS - std::cerr << " Examining pixmaps sizes for " << it->first << "." << std::endl; -#endif - - for(int i=0;i<4;++i) - if(it->second[i].first>0) - { - if(it->second[i].first + ICON_CACHE_STORAGE_TIME < now && it->second[i].second.isDetached()) - { - int s = it->second[i].second.width()*it->second[i].second.height()*4; - -#ifdef DEBUG_GXSIDDETAILS - std::cerr << " Deleting pixmap " << it->first << " size " << i << " " << s << " bytes." << std::endl; -#endif - - it->second[i].second = QPixmap(); - it->second[i].first = 0; - ++nb_deleted; - size_deleted += s; - } - else - { - all_empty = false; - total_size += it->second[i].second.width()*it->second[i].second.height()*4; -#ifdef DEBUG_GXSIDDETAILS - std::cerr << " Keeking " << it->first << " size " << i << std::endl; -#endif - } - } - - if(all_empty) - { -#ifdef DEBUG_GXSIDDETAILS - std::cerr << " Deleting entry " << it->first << " because no pixmaps are stored here. " << std::endl; -#endif - it = mDefaultIconCache.erase(it); - } - else - ++it; - } + cleanupIconCache(mDefaultIconCache, now, nb_deleted, size_deleted, total_size, "identity"); + cleanupIconCache(mDefaultGroupIconCache, now, nb_deleted, size_deleted, total_size, "group"); mLastIconCacheCleaning = now; - std::cerr << "(II) Removed " << nb_deleted << " (" << size_deleted << " bytes) unused icons. Cache contains " << mDefaultIconCache.size() << " icons (" << total_size << " bytes)"<< std::endl; + std::cerr << "(II) Removed " << nb_deleted << " (" << size_deleted << " bytes) unused icons. Cache contains " + << (mDefaultIconCache.size() + mDefaultGroupIconCache.size()) << " icons (" << total_size << " bytes)"<< std::endl; } } diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.h b/retroshare-gui/src/gui/gxs/GxsIdDetails.h index 776036576..60718a365 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.h +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.h @@ -28,6 +28,8 @@ #include #include +#include + #include class QLabel; @@ -175,6 +177,7 @@ protected: static uint32_t mImagesAllocated; static std::map[4] > mDefaultIconCache; + static std::map[4] > mDefaultGroupIconCache; static time_t mLastIconCacheCleaning; int mCheckTimerId; From a55fe09455c8291795c53d4935126efb1536ee06 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 17 Jan 2026 07:35:05 +0100 Subject: [PATCH 6/9] Fix type correctness and add safety checks for group icon generation * Initial plan * Fix type correctness and add safety checks for avatar icon generation - Change parameter type from RsGxsId to RsGxsGroupId in makeDefaultGroupIcon methods - Add NUM_AVATAR_SIZES constant to clarify array size meaning - Add bounds checking for array access to prevent crashes - Remove unnecessary RsGxsId casts in dialog classes Co-authored-by: samuel-asleep <210051637+samuel-asleep@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: samuel-asleep <210051637+samuel-asleep@users.noreply.github.com> --- .../src/gui/Posted/PostedDialog.cpp | 2 +- .../src/gui/WikiPoos/WikiDialog.cpp | 2 +- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 23 +++++++++++++++---- retroshare-gui/src/gui/gxs/GxsIdDetails.h | 2 +- .../src/gui/gxschannels/GxsChannelDialog.cpp | 2 +- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/Posted/PostedDialog.cpp b/retroshare-gui/src/gui/Posted/PostedDialog.cpp index 590c3e77d..3bd30264c 100644 --- a/retroshare-gui/src/gui/Posted/PostedDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedDialog.cpp @@ -237,7 +237,7 @@ void PostedDialog::groupInfoToGroupItemInfo(const RsGxsGenericGroupData *groupDa groupItemInfo.icon = image; } else - groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(RsGxsId(postedGroupData->mMeta.mGroupId), ":icons/board.png", GxsIdDetails::ORIGINAL); + groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(postedGroupData->mMeta.mGroupId, ":icons/board.png", GxsIdDetails::ORIGINAL); groupItemInfo.description = QString::fromUtf8(postedGroupData->mDescription.c_str()); } diff --git a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp index 1effae298..02ce7d978 100644 --- a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp +++ b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp @@ -731,7 +731,7 @@ void WikiDialog::GroupMetaDataToGroupItemInfo(const RsGroupMetaData &groupInfo, groupItemInfo.lastpost = DateTime::DateTimeFromTime_t(groupInfo.mLastPost); groupItemInfo.subscribeFlags = groupInfo.mSubscribeFlags; - groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(RsGxsId(groupInfo.mGroupId), IMAGE_WIKI, GxsIdDetails::ORIGINAL); + groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(groupInfo.mGroupId, IMAGE_WIKI, GxsIdDetails::ORIGINAL); } diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index d67fdc7fd..84f35b53a 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -81,8 +81,9 @@ QMutex GxsIdDetails::mIconCacheMutex; #define ICON_CACHE_STORAGE_TIME 240 #define DELAY_BETWEEN_ICON_CACHE_CLEANING 120 +#define NUM_AVATAR_SIZES 4 // Number of AvatarSize enum values (SMALL, MEDIUM, LARGE, ORIGINAL) -static std::string groupIconCacheKey(const RsGxsId& id, const QString& iconPath) +static std::string groupIconCacheKey(const RsGxsGroupId& id, const QString& iconPath) { std::string key = id.toStdString(); key.append("|"); @@ -477,6 +478,13 @@ const QPixmap GxsIdDetails::makeDefaultIcon(const RsGxsId& id, AvatarSize size) if(id.isNull()) std::cerr << "Weird: null ID" << std::endl; + // Bounds check to prevent array overflow + if((int)size >= NUM_AVATAR_SIZES || (int)size < 0) + { + std::cerr << "Warning: invalid avatar size " << (int)size << ", using MEDIUM" << std::endl; + size = MEDIUM; + } + QMutexLocker lock(&mIconCacheMutex); auto& it = mDefaultIconCache[id]; @@ -548,7 +556,7 @@ QPixmap GxsIdDetails::generateColoredIcon(const QString& idStr, const QString& i return pixmap; } -const QPixmap GxsIdDetails::makeDefaultGroupIcon(const RsGxsId& id, const QString& iconPath, AvatarSize size) +const QPixmap GxsIdDetails::makeDefaultGroupIcon(const RsGxsGroupId& id, const QString& iconPath, AvatarSize size) { checkCleanImagesCache(); @@ -557,6 +565,13 @@ const QPixmap GxsIdDetails::makeDefaultGroupIcon(const RsGxsId& id, const QStrin if(id.isNull()) std::cerr << "Weird: null ID" << std::endl; + // Bounds check to prevent array overflow + if((int)size >= NUM_AVATAR_SIZES || (int)size < 0) + { + std::cerr << "Warning: invalid avatar size " << (int)size << ", using MEDIUM" << std::endl; + size = MEDIUM; + } + QMutexLocker lock(&mIconCacheMutex); auto& it = mDefaultGroupIconCache[groupIconCacheKey(id, iconPath)]; @@ -586,8 +601,8 @@ const QPixmap GxsIdDetails::makeDefaultGroupIcon(const RsGxsId& id, const QStrin const QPixmap GxsIdDetails::makeDefaultGroupIcon(const QString& idStr, const QString& iconPath, AvatarSize size) { - // Delegate to the RsGxsId overload to avoid duplicating caching logic - RsGxsId id(idStr.toStdString()); + // Delegate to the RsGxsGroupId overload to avoid duplicating caching logic + RsGxsGroupId id(idStr.toStdString()); return makeDefaultGroupIcon(id, iconPath, size); } diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.h b/retroshare-gui/src/gui/gxs/GxsIdDetails.h index 60718a365..e8f4fe10e 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.h +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.h @@ -115,7 +115,7 @@ public: // These two methods use a cache so as to minimize the memory impact of avatars. static const QPixmap makeDefaultIcon(const RsGxsId& id, AvatarSize size = MEDIUM); - static const QPixmap makeDefaultGroupIcon(const RsGxsId& id, const QString& iconPath, AvatarSize size = MEDIUM); + static const QPixmap makeDefaultGroupIcon(const RsGxsGroupId& id, const QString& iconPath, AvatarSize size = MEDIUM); static const QPixmap makeDefaultGroupIcon(const QString& idStr, const QString& iconPath, AvatarSize size = MEDIUM); static bool loadPixmapFromData(const unsigned char *data, size_t data_len, QPixmap& pix, AvatarSize size = MEDIUM); static void checkCleanImagesCache(); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index ec756ba17..035d2778e 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -427,7 +427,7 @@ void GxsChannelDialog::groupInfoToGroupItemInfo(const RsGxsGenericGroupData *gro groupItemInfo.icon = image; } else - groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(RsGxsId(channelGroupData->mMeta.mGroupId), ":icons/channel.png", GxsIdDetails::ORIGINAL); + groupItemInfo.icon = GxsIdDetails::makeDefaultGroupIcon(channelGroupData->mMeta.mGroupId, ":icons/channel.png", GxsIdDetails::ORIGINAL); groupItemInfo.description = QString::fromUtf8(channelGroupData->mDescription.c_str()); } From 722f2e542090f7ecaa5c29d3567233dbc373ee1c Mon Sep 17 00:00:00 2001 From: Akinniranye Samuel Tomiwa Date: Sat, 17 Jan 2026 07:39:38 +0100 Subject: [PATCH 7/9] Add new board icon --- retroshare-gui/src/gui/icons/board.png | Bin 5285 -> 6359 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/retroshare-gui/src/gui/icons/board.png b/retroshare-gui/src/gui/icons/board.png index ab6baa466f26fb14c5540bfe0cef4214933c6281..034d656672a4c2760528888a25a7be96c56738b5 100644 GIT binary patch delta 6322 zcmXX~c|25q*uBGyU1qY&FI*wn_oWD3WC@KWTXsXHB9bM#L#eTwvW={xv4l`0ON^8h zVQLzMEG>vEWy=!peBSrH|K88{xyy5&^PF?2iX$3X=V7q`E6CI-x^S^5=98p(^BuS{ zs4b-P$gk4VgocMECL1~gf(bgShH!3+37o{ad2dbIAuZ6zbM{J{glke8d@+w7iqK;ht}?*33E{ z4NP*XbN{T|gxRB2cS8>l_R;j?KnnQS0h*Af{74SwqGb_lxqO5O&E^5@FgOZa8qkKc z>#)^@?ni|xsF%v`tx?%r@hu{xZ-68~xZ7z7)u;B^V#uWaABX#9SNEY(U{SNzy&XZg zWFEjq;0BnN8q+zU@7i_ii(JDa_!~lm;VR_j3C_taOTb>`|4REr5l3Fg-(Ef^>9nUr^Tk(5q ztW`F`V=}NC0|d!zE&sBmGLTK`>F)U1#4fTu(ufD`cy*{yNW22GE{kP!s)02R>v5RG$X zsc}Oq2euB(EGsL^yFIDVTWb#u$^Y_ujGZrV`N0O@7iYjfCjsMoU)MDWQpc!+CZeLr zUtEAobw-v@=jZ7gdk?cm4-*cl`pk@EU92#0P>l3fDiZhK04b}$#qomt#_{TGLnN(B zGq^_a{0_Hz??u{xz*XNBgwOr3-0GPmexp0}^NW&xcv)x9YI2$Hwx;jJAu7K=I$ zlz1FifCVXTb4!X7H%LPff*q@z055i}IW8qiLW5}#mD#+}kTzCV_Kn9U?enBTlpZ0+ z@XI+Js0sIdb%EQf9SrnVtBk4Vj={91k-Nqcp5_goMKv%FTR?hjVj)keMWOEpL3rC6 zDXMw~mNE}G`=ILc)(ai$>idpwH^bg;7MKEq4b0-3B6g5RnLme2*-UZ92CBrTq1g3ncjHRl_UwvmR)x-H8 zbI~x?)sq3zK@;vfDZ~!7n@=UKG-Kx-0-l{2*i|5qPufGXIL7!BQun#ud|C2V=)gtt zmK)C41aIW57@36)kpm7XQJ(!xW-qO|$Xw)Tf$`EZ|%N!vzR*vi2v5ASG%>`gPjCAw+(9RL&nHmGPzs z{X*=C6y{6X;PRteF!8`@{Qkphhu%WNevSI9wkpMH{RPxJC)kHpUChHS?Y0r)Djiwi za9b9=JpUUA)zV|YV7z$i!m)nWr&=PibhG_6ep1F=i%Q|?6kK=OE5CYY}&kT{Zf@g z93V}pg(aANGfMPcmv)r|R(E6?J}>CFovHh;$Njh)bmMbE#imZLHYHCf{qYvqV@3>K(Q6+}4-6ff`0Momx2V!%Hp^?^jc zx-W1BIrJdO4Qh(G)4p01Au9W7<9H66n7{FDnp3-!>s(>`gAp@6M`e)_znL-f@1{+` zAIIhIi}`1StW&kyfmZ{Wh`$asYB-uKs9Ei)+I4SewuPg?7<0zi+KA5X7IHMN|M>CQ z%Vx_WR9>Z=x4j>k4)21uG>PO)(@+j6U;-X?KUvevLFiPkdDLsLd1mdJrKWsde-Wp2 z2%lqKE{=e$)*f8#P#7+IWoy55IZxM4(xpc zZm^e*UfWZkVlNb_z8&TXq%x*~$DKjJ+~D?=uWeRAgkiy%7{IX3r_KbL-RgvuVFC~E zn0fiYld&wz|XXsE}9h>4lPn zQdi}ScR#`_WyOY{)s>*>B4_(${Rdjic9N%!b~CfF3g+_{O(0IN;l^m2-HuLlaZ7}8 zNeR8m4n+CPI0BNQiZ^&^d5B%rWc9`(!G8mr|H_9gCmvronqv)r3vV5-mFM)2I!ZM@ zyh$MI36o@#gNw2AuY;%DoQ~x%*H0|l9`X1&S)Dyvc{b??&(tA*FB!^5@JD5G-#;k( z+VPEAY>41mpMt7QZSzTC(*9*9g*PpYs1vvw?C(_S%pv2d=0^*{AFqnCXi@>U^4a}* z!fXs)4y`K!8gjxm-Bav@h)16X=N|EKO7-R&A!_qWk74Md63)R70qE*!+uzHUnTL(+ zq4&pV_|9c-@}DoAvU&aIGdLDl1!QVE^S1!7jr&bzzJlJvFI+CKF(!*$h=kASe0VD(Ipo`){< zgpHNK>)O9BoMtF%P2SSI?43O4!)V>S(8TLXCeO-JSPas-yz}G~er(?3nQQ;JU*j{J zYFEi7Zp|9hNz5VshZt7-{H=)I=t8pJqE!NlepJ9*1+5v!= zghXr-c@ohe3Fyym8(#L}TuIkx7o^+408@t22x>}--9!v1Q1Xf*)Yzguq2i-LJP~O9 zZch{Fl7KPm%r*8bPXrWT52oZgPpUgB(SBETQ3a8mTlW!1Z|_I+vl(l_9#BU0gvIN3 z&%nfK7!R^(iQeqODy2TZjixUFcB#1|&Hz||c65pF*Qo^}a9^j`rNF1a>RuSC37X)axv`L3@&WtqdiWF7pUz z2wp(?9{ooOyds| zKi4ryXG7DyWz8cno+vnxyr1Y3JBgrKTUQ4Uuy)T4ZdS z??EcI`h@d8GI6PT`p$%^>0R)+EjssBqM ze+vl+vYvaei7AUqkYJ6yPI(~UWj?TX9{bkIJ=Cfxi&Yy(?d8M#3K?5G}qt630+4xAOJQe{!zd zyB|0scGX3QWNX&6PQ-Yx=%cC({u3fqh^s>Z`o~A^P>Ph#i1{BdFL`w&g!F&+-CknO zen1G5^m@7uOFCD0n7bitEmMsVP@7bdqbTXyuy%c`F2GOmlBP)95Oh`s>B(je>KrDkjIHi}hYe zc3B`E-srEfx;y^n;MvHz_iDg1D+u=^yfu&f*%d#_63+fJQXcr03uo5$qz7R22I#fk zl7h7Ad;rBJ!&&h7Xc9@8oKp6e77XN2{5mnT+bmyuY2WN@Bo0_GDt3*rWui z%IVmZJcDGRQir1*z?7v5*ONQM6E6lv4h*OHAS4sFQzk~BP&{6UrMX0#MNihqmRY7? z=WT(Or_%R0ry@YjRPugE-M@o|K0;(U>uUI=eg_|tzMI^bA#(*b*nk3hEH3wAa{XsG z(aVOpxAYLZW{Qy_7Nas7f&q2UZ6ISN-qhVB8>=++DTcO+XxIvQLMJVe#AlNuStAr=`+AGS-6zt2F#$!7HL-_7epApmUlva zA?>+^;yM!Z52lQSA4wwaiL2C90&u2c>Jy=iR|cE>0ryG29B`e8_~@6vcJ>sj-r6&U z^k?rXnyBWbj?FNlc|M+kzSgFU26lzX&*|-D@fnPVCzn zkc_nWsl#jjU|Hyi1Xxg?{m^YphX;Knw8;e8uzOD?Ue$C8LD1^yK|v_r(a+z8D+lYr za4Ellni>GoR;l>=?R100h`YUI+K|cZG=cJq8#x*k*m-T1LyK;6`*PVa=)@rlt~VO1 zY>+CP2n8%3u@X(!IH^FXZ&AL$d+YbD%*$R+7NVU^WuBU4*@g=vE2{&6Rm?NyI~j^- zVMM)jL)$2kn1NE)#V5RoP8fpv4{@Xf%q#$LhVO^X-4|GVmqmUpd*e7+5e#SPPYj&&wsV z*MdK-cK8oVaUOx7J0AG1_jpqY85qO|(GOtGr^s&zB@0P6-Mp@WEmWX<6YSha6O`^U z77sqRzMjVgzI`#B&C;)K?~cj6lfWg<4dnkhb?;GI4)%3Q-y!au1?|i=cY+0)o_}o& zO{(EZdNGb$KUkU0@)nwm+qYJs?~Ge#lvhru=@wqplc8*NE>8~Q4GM>SznBaq7EXyI46y)$FAOf;Z<}BsOg3O7kBq<9Zo=v zX_e8G(X4y+>09;dz3VC)_hD{G8x?Q-7bwk+JxKeSU0+gsbtU2I=N^o_y1q2lbK}Hv z`BvQC9&Y(g%*tU)QGTO)^4MRZX&N7rk5(fF)rXE!bx-k%`qvEtKyLKDg^u=eVY>+T zW4EL(`~AF%Gv{HdJg7tS&0lVZF?F=#u=RDxYRJZ!iNvrX@ z=N=qdT?+o4vv3c`Cq=ifQR8Dx>mk}ez9r`&|AHAYruz_-XUCa5cSo#2GRZeKPv3q~ z-z#v&=}k3O2>=!fca#Ydp?;uYzt{)m@ELfxXcv(u5S;NslW=5mE@d{RE&{|XdRv$w-JcjmO=(+;x_;*3j1S1MFc08qDH z=ex0RR0;U&&&oi~Eq^)v^7jB&ghXh4_O>dA&)7KuDx)Yk3~vQR-ML*=ZPm=5)~(lT zo7%61oD#<`s+L=37K^T4qz(%j@Rp}1f#G$tF`{yCqoWvFTk9mdw5s{C4RiF;=sTNF z8+>TLW+ta}?>ZOlHVZ2M@jD*=Q$b|toU`te#28p8Hs><8@iz3S%%{wWl)v5kdW2;0 zBh-P5902hD@zO~_lkukgMB=aN=EKvmUMwBY>g0tcV_q)I`Kg_~sK&KG@H|~C0`>@Y zIZU04nJBh8Fn%}dBOf456zB7idijeFsI`G$zZuNsnQ5~>k44(uSxR-M^CZgV^OTzB zvz7RPxX_|*wbZ_DH-6)+MmC_^Ko_&f>*G7{tr5UkgbEZzRLaEYUJ)VLU#MHY?8xZ6 zNq((F#Q~pA%rv6u7?z)Y@=FVjKmm!oQsC%$=qsC@iape#v1-+WI(6!l8oR!M@2Wzj z!SDH~{H+MCM{o7gVm#$3YCD~_a{KVV=}%DS@=0## z!3{LQ7^UlRc#fa__z`@)x=u$n8gFiMA|kCHCv_0|TZwXz7ZGI>s^ zDs<09hQgbT_1Ny*57P@o#;ypW%0LsYl38&`3almpwmp^Afar^!tz(>wcT(>0{lPK0Kv zJFH#i@;jt3tpbR$LcvqJ@m3>0^-y9KZg_>%zD?lb@Yi-;U_6u7=%-7l%*GDMeo@wV z>%QZQ*+LW2fjBYRHNgGP1WO|l=i;a^BWdp9T2t=Nb0{(S*8}$e$#m&am*X8AQ;|qa z+n!M&e-3d%g!Ch^>peO#*sDhR^xa1J(N&*VQ%IHJ?tRNR(sCgR_d3jX23yhD?!eFGQ?9SIK_a-{htyMH8d&SAM_Qx8iO%&yI&cO&}({x9>wME5K6$ zd5wlV9IBmWM0t|VX_P8W{(7LS#ItfZa_-G}+VwSoWks6i;6D51ps9|dpDQH*)@5aG K2R$~Ab6%Y5KIePipZiX=voYsACVmV60A7m=paXNp z|7V=+%(49}wwpO|UBBQK2>?Pw zs(Jbc-^Y(k*8=3+VuLp2#J)#pB5lH-RS{P|nKwNjT{iV8!;_E$PNQ=yw8cD1L9+@O#t&g>@x}tD*|x z8r&d2Dgh+#&=aOnF{a>8x#AHFE&1B#r^+rm&RRGpjEsFmu)$CrHiO9H!g@nMWxYolLyN)xV@B6rdD{{Q|4Z8FY2lpjICcja zkv$YEj_=oV8t93a!GH1Xngcv*$a*4eX?lJQ88)Z!WVF9Hynqc+?l7c6rOW(158d}! zQoxE{V~mb2F>z zZDIXQ24_-zwA3@A4qXzPfh(u~T1jOT z^cgU!xyb?~P8Qjm z66}{ThP6yg9oc-pdjg+<7D;1_Umx28uFK(%1L~Xl;cVyU8tOSEB_;FmbO~wTl`yHP zr^QE5BftOWiMD`+6^LYx6I+vKXnXi9{T6`FJ;QTY+uy!3d2PO#d zgHaO26g=8rwzznw572c~z9BVJcE19F+y%ZiLB=g*;7tRfwfBY&I{4-Wt@UGpCzLfK z-%NhwLGRZU5{a~(i5Ah^oPE1y+vi`~phVT?Z@(^rJP3ucDjxs#dh9DV+|3NsSD{v) zFUaHvMnZO60NKnXA3mgB4#hT7zNY%MhXFgnzc6{BaGxL69|FXsGq8Zuy8wO_>W*?` zR$tF15CTQ0BIAOqq_3H9i29-kr4`kjsY~Su&d_M3S`{@dJnP#!2NUYRsFK@_+MyFC zk^A`nXlK(6kHkeEgCOE2(0>NMSwIu)*^4&|8kRP&4|G$*Xu8jJq{$e@US=*E{>0+(K&#=%^x83)>c4`Jz0Ls|`TofocFb$z8{d%zUr(A-?Oq3W9cgEbcamVupFlkBVogkk-* zNr=V{l9i&U?@ifaRY-_Oj2HNpR-X{z=jR8V+zo(!Et#4<$Mg+$A(8dEFn*jgNy|tk zgz_a#xuz^H&cD_Me0%!AsNi>0V;~(epy}GhqTAsf*WK1;MD?*B6FqU_&t)H<$&hebyjMq;mbPDJ(GO4^vAy^H%pL2=56%(_UKHHJihfsK>J_g%z4!gpHhAdUALeCa5rJrcUpWmFsxPE`#^$Y1dcd#kjnn=evbjP zExWwRkQh`%Ow-i_{QqdfW#bP>nn5^{gGZ*g>KMvLV*fio z3*KSb8u^+wRd`N!K=Gfuk(z)vb9d&Ou-@dG+GL3;@ z;t#>OXu$3g5T;E1crtP_*!NW3P-1wwttEjyTAd!BO5ig}`1n^oen+*J#nl8%hqS05 zH`~=cXK)iuO6M{w(+EExZJo44%gkshk5z-a=0W}~*$gBA{&h{IU5Ey=1=!n&5 zZ0FZw#D|_7P(LaAZC@wy1nl2?%()e(p$i@8qS(V|cq@FYR9n*%&o2 z;q~4tZZCIUO`p{GyVq5{el$pmiH)=+BQCN(5ALLvaeLP&B3147hmVxuy=>1J$*3y1 z$Gv}`cr*4y>o3E@4VK#uT8wZR*8LDqRj&5+ktJ$YJZlf=KjEXi-H2WY2DiMQMwSw+ z(m&T%y4=OaC=1+-$i${EpMN&n1sschCWq-}nUjWYk|sGCb13lhi}^|M2U-Br(OJZ; zK(V3GHI}axUfU^H-KJRDa$^i@BveFL9c`ZM&iXxB-**laVE_I1}=7` zL;qMwrJ((V;j5oQ4ezhv9`ArbqriLhlU-DEP&!-rkr2rjZq0jMZUdhp_k5_(8Z@u- z$U>W$nFaOwx{^wH@q`1*i5xG1LHAbPDGOj}WyNEa2Ty60M~c*YWSPWIhK&l1Cqs@a z%OJx&nz$i|oNoDLkOIsChXPuSq4ffNn|d>FyJz5s#b&~xR_qztNUTR{{f^)191$gW zM3d+5IA(apG;gN0K6ue+h#dWI--4V{BzX0}e)+PnU0tFr7~c7iUP?&e z83|?Un*ROgQmsawH`j5}y9eL&g#=~Tjn|blHSt_Dr)7KJ9!X@ZbX!W{;w>_U>TN!! z`U%?tHRnEs;%a~XeXZ+*Y|#ZSxSL|>-Z8*8-NccwWB?398+CZv7jtn<=!Frb%1Xfq zQDXm3=hl}@GTD(ZqFCpDz1HQ4(&5b(RQwHY-GDb0P!=V8iMM@EeKoVg^ukC@t3xH^ zKY#v|>U{FFf{Ns{WNG1*lx70Sw%@%O!eEr3X6v;o!!SR;e+FLEWoMXi8x_pe?8!*R z*y>yZn23|ymwyg+4?7q@by(g7x4wv1e6<4;mVf`z?};~6cxZu~s#C$xbRhX(h_6-G z?{UkZ3TuViFkvTGz$hek2sv8mIzi4i5y-MZVA4$FNg z)-z~;I`EM3yEW^D>}BD*bwj5fk;BO0$cO+>FN^yaYN2fLE4gT53?I>7t~wUa#N4-2 zxAG{hLXHV+zd9v2X-i2ueez+9p)C6Y! z{M^vzm?Q;VA|*%r`jVq#U{x6Fb$!h>6jC2osH3ch*RTW?c-lVz!h-$Hg^Ox^^AR3` z{Zu95(~!G=ue$7_^W_OlWsRj^8()gRNLSofcymg5Q-A zlma3&X`zpls0#0TWe3J%)p=@eIwv|UVtWqr&bJz6tEYub@lmIH=63q& zy_2Bz2NqxSl0LsO0DS(w6$c#Sw^o>QeCo^$2Nk5ruNMTQ+irqeC4tH#7Ou{Mr}IqK z*vs4zw+(mIdD4G=YC5-e65{|JM zBLD|v1ooRDhUTU=5f=TDIKeu*^5!; z38w|Z6bIvFF#8@`^dKt8#VHY!jc~xl3(-H6C4&l zEQp4X|2_O^(5El-awZx>0|QQ4G#kT0^VMC5+PNf#`HU+bKIn28QYVNo`V-dymb02nKk<~7!P zgnq&Wm#U~w(77t_E)f5etS2R(i2;Y5^n|PaZ732mgB+gZOp?}pu=s%E^4Vq;&ZK6K zr(idccxB-fG&f~tc97k$Z%i{ABc#T{%g0yEL}-q{c*!=TM#pB0Ww)g4m~x=McUt_? zKBo9ZSM`PU@; zi~15xHaZu9^=g9TU16=WpAKecu^DHOquQv`Z|AY1KOfqZU9`z!vT!P+yS(>8EqK~c z&!=WQ-M|^Upb2;qlf2#qdc-#%IK3-kd|B!Y0LS245_nAv%9dIAJXM-E01%u>`}XvW zAf9xFw=v8UKUlPpiC%;@vV8D(FUw^7Ru`SKpGrABsRKO7JePHRmqzjUC${`T;V zFqWw)cK)D1Ehs&=xhqDHAF5mad^cGB8uvTCq)U4EhjuOK8R#CR{-!n_LLKlB`Zx~- zn6(Yn>097yS>~H!7ZwRiQ}0*6y3;)EZ@%Hm%XAOJl1;t*gxD4?UL#Mk(Sy*P%-Q|1`!O zaO-+!K#elBw9c&k0K3o&c&2CsK++hV@H0xkih@+7NXe$bM}erEF}@1=w{3{-9YQE7 za_qgvupZ=E)e#py=S9#gH=g3Y;-&v|<2D}}Ks?bkQLZl|QX1^#M$(#3STE_N0gmskh#8t$Akm^JGuOq9yu(t%T2v5kgF(w9G}wMbVBOsjT%>s4Zjtm z)1{Fb9>J?B!^Yii1-wP~A^wGFhb?jZbNm%ixAJn>)_LHD0{5n6`*llZb)G!iz@hQT zdnqZymQ;skAlG0=5&6(QZurlMU;U=s#fgjNXK-c@J~b4?qj(YbwmyBbOH|1gUpELd zLFKH7knAUSQ$W89%Jq`_;kRq|e%q9d@f4YJ6}%GoTJqul*IfJG-M7CS4y$8@dd15G QW{VN9IBx@1n_NozAJ^ZONB{r; From e2633dd7de8339dd4ddf9e946919864c3db7590a Mon Sep 17 00:00:00 2001 From: Akinniranye Samuel Tomiwa Date: Sat, 17 Jan 2026 21:09:06 +0100 Subject: [PATCH 8/9] Fix icon cache macro order, use `NUM_AVATAR_SIZES` and add string-based group icon generator * Fix NUM_AVATAR_SIZES define order * Update retroshare-gui/src/gui/gxs/GxsIdDetails.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update retroshare-gui/src/gui/gxs/GxsIdDetails.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update retroshare-gui/src/gui/gxs/GxsIdDetails.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- retroshare-gui/src/gui/common/AvatarDefs.cpp | 10 ++--- .../src/gui/common/FriendListModel.cpp | 4 +- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 37 +++++++++++++------ retroshare-gui/src/gui/gxs/GxsIdDetails.h | 19 ++++++++++ 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/retroshare-gui/src/gui/common/AvatarDefs.cpp b/retroshare-gui/src/gui/common/AvatarDefs.cpp index 01299e482..ac6017fa5 100644 --- a/retroshare-gui/src/gui/common/AvatarDefs.cpp +++ b/retroshare-gui/src/gui/common/AvatarDefs.cpp @@ -55,7 +55,7 @@ bool AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, cons rsChats->getAvatarData(RsPeerId(sslId), data, size); if (size == 0) { if (!defaultImage.isEmpty()) { - avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(sslId.toStdString()), ":icons/person.png", GxsIdDetails::LARGE); + avatar = GxsIdDetails::makeDefaultGroupIconFromString(QString::fromStdString(sslId.toStdString()), ":icons/person.png", GxsIdDetails::LARGE); } return false; } @@ -109,12 +109,12 @@ bool AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const } } - if (size == 0) { + if (size == 0) { if (!defaultImage.isEmpty()) { - avatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(gpgId.toStdString()), ":icons/person.png", GxsIdDetails::LARGE); + avatar = GxsIdDetails::makeDefaultGroupIconFromString(QString::fromStdString(gpgId.toStdString()), ":icons/person.png", GxsIdDetails::LARGE); } - return false; - } + return false; + } /* load image */ GxsIdDetails::loadPixmapFromData(data, size, avatar, GxsIdDetails::LARGE); diff --git a/retroshare-gui/src/gui/common/FriendListModel.cpp b/retroshare-gui/src/gui/common/FriendListModel.cpp index 8ab179e1a..0f8c30d35 100644 --- a/retroshare-gui/src/gui/common/FriendListModel.cpp +++ b/retroshare-gui/src/gui/common/FriendListModel.cpp @@ -1030,12 +1030,12 @@ QVariant RsFriendListModel::decorationRole(const EntryIndex& entry,int col) cons if (hn && !hn->child_node_indices.empty()) { // Use first child node if available std::string sslIdStr = mLocations[hn->child_node_indices[0]].node_info.id.toStdString(); - sslAvatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(sslIdStr), ":icons/person.png", GxsIdDetails::LARGE); + sslAvatar = GxsIdDetails::makeDefaultGroupIconFromString(QString::fromStdString(sslIdStr), ":icons/person.png", GxsIdDetails::LARGE); } else if (bestNodeInformation != nullptr) { // Fallback: Use the bestNodeInformation ID if no children exist std::string bestSslIdStr = bestNodeInformation->node_info.id.toStdString(); - sslAvatar = GxsIdDetails::makeDefaultGroupIcon(QString::fromStdString(bestSslIdStr), ":icons/person.png", GxsIdDetails::LARGE); + sslAvatar = GxsIdDetails::makeDefaultGroupIconFromString(QString::fromStdString(bestSslIdStr), ":icons/person.png", GxsIdDetails::LARGE); } else { sslAvatar = FilesDefs::getPixmapFromQtResourcePath(AVATAR_DEFAULT_IMAGE); diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 84f35b53a..af14551c2 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -71,18 +71,18 @@ //const int kRecognTagType_Dev_Patcher = 4; //const int kRecognTagType_Dev_Developer = 5; -uint32_t GxsIdDetails::mImagesAllocated = 0; -time_t GxsIdDetails::mLastIconCacheCleaning = time(NULL); -std::map[4] > GxsIdDetails::mDefaultIconCache ; -std::map[4] > GxsIdDetails::mDefaultGroupIconCache ; - -QMutex GxsIdDetails::mMutex; -QMutex GxsIdDetails::mIconCacheMutex; - #define ICON_CACHE_STORAGE_TIME 240 #define DELAY_BETWEEN_ICON_CACHE_CLEANING 120 #define NUM_AVATAR_SIZES 4 // Number of AvatarSize enum values (SMALL, MEDIUM, LARGE, ORIGINAL) +uint32_t GxsIdDetails::mImagesAllocated = 0; +time_t GxsIdDetails::mLastIconCacheCleaning = time(NULL); +std::map[NUM_AVATAR_SIZES] > GxsIdDetails::mDefaultIconCache ; +std::map[NUM_AVATAR_SIZES] > GxsIdDetails::mDefaultGroupIconCache ; + +QMutex GxsIdDetails::mMutex; +QMutex GxsIdDetails::mIconCacheMutex; + static std::string groupIconCacheKey(const RsGxsGroupId& id, const QString& iconPath) { std::string key = id.toStdString(); @@ -91,6 +91,14 @@ static std::string groupIconCacheKey(const RsGxsGroupId& id, const QString& icon return key; } +static std::string groupIconCacheKeyFromString(const QString& idStr, const QString& iconPath) +{ + std::string key = idStr.toStdString(); + key.append("|"); + key.append(iconPath.toStdString()); + return key; +} + template static void cleanupIconCache(CacheMap& cache, time_t now, int& nb_deleted, uint32_t& size_deleted, uint32_t& total_size, const char* label) { @@ -101,7 +109,7 @@ static void cleanupIconCache(CacheMap& cache, time_t now, int& nb_deleted, uint3 std::cerr << " Examining pixmaps sizes for " << label << " " << it->first << "." << std::endl; #endif - for(int i=0;i<4;++i) + for(int i=0;isecond[i].first>0) { if(it->second[i].first + ICON_CACHE_STORAGE_TIME < now && it->second[i].second.isDetached()) @@ -606,6 +614,13 @@ const QPixmap GxsIdDetails::makeDefaultGroupIcon(const QString& idStr, const QSt return makeDefaultGroupIcon(id, iconPath, size); } +const QPixmap GxsIdDetails::makeDefaultGroupIconFromString(const QString& idStr, const QString& iconPath, AvatarSize size) +{ + // Delegate to the existing QString overload so that all string-based + // calls share the same cache keys and entries. + return makeDefaultGroupIcon(idStr, iconPath, size); +} + void GxsIdDetails::debug_dumpImagesCache() { QMutexLocker lock(&mIconCacheMutex); @@ -616,7 +631,7 @@ void GxsIdDetails::debug_dumpImagesCache() { std::cerr << " Identity " << it.first << ":" << std::endl; - for(uint32_t i=0;i<4;++i) + for(uint32_t i=0;i Date: Sat, 17 Jan 2026 21:32:10 +0100 Subject: [PATCH 9/9] Delete _codeql_detected_source_root --- _codeql_detected_source_root | 1 - 1 file changed, 1 deletion(-) delete mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root deleted file mode 120000 index 945c9b46d..000000000 --- a/_codeql_detected_source_root +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file