feat: 修复应用升级后任务栏驻留的图标可能显示异常的问题

应用升级后,其desktop文件中对应的Icon字段可能发生变更,任务栏会重新获取当前的Icon,
当这个Icon对应的图片还没有放到指定的位置时,此时获取的图标就是异常的,且后续再获取时,及时图标已经正常,
但因为qt的缓存机制,也会导致获取的图标仍然是第一次获取的异常图标

Log: 修复应用升级后任务栏驻留的图标可能显示异常的问题
Task: https://pms.uniontech.com/zentao/task-view-64795.html
Change-Id: I955108d04af65b2ca9cc1e6347a4c390b9ec9d77
This commit is contained in:
Fan PengCheng 2021-04-22 09:56:28 +08:00
parent 0eb877e733
commit ed5ae88ae2
9 changed files with 83 additions and 40 deletions

View File

@ -61,6 +61,7 @@ target_link_libraries(${BIN_NAME} PRIVATE
${DFrameworkDBus_LIBRARIES}
${DtkWidget_LIBRARIES}
${Qt5Widgets_LIBRARIES}
${Qt5Gui_LIBRARIES}
${Qt5Concurrent_LIBRARIES}
${Qt5X11Extras_LIBRARIES}
${Qt5DBus_LIBRARIES}

View File

@ -61,6 +61,7 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti
, m_dragging(false)
, m_retryTimes(0)
, m_lastShowDay(0)
, m_iconValid(false)
, m_lastclickTimes(0)
, m_appIcon(QPixmap())
, m_updateIconGeometryTimer(new QTimer(this))
@ -600,20 +601,27 @@ void AppItem::refreshIcon()
const int iconSize = qMin(width(), height());
if (DockDisplayMode == Efficient)
m_appIcon = ThemeAppIcon::getIcon(icon, iconSize * 0.7, devicePixelRatioF());
m_iconValid = ThemeAppIcon::getIcon(m_appIcon, icon, iconSize * 0.7, devicePixelRatioF(), !m_iconValid);
else
m_appIcon = ThemeAppIcon::getIcon(icon, iconSize * 0.8, devicePixelRatioF());
m_iconValid = ThemeAppIcon::getIcon(m_appIcon, icon, iconSize * 0.8, devicePixelRatioF(), !m_iconValid);
if (!m_refershIconTimer->isActive() && m_itemEntryInter->icon() == "dde-calendar") {
m_refershIconTimer->start();
}
if (m_appIcon.isNull()) {
if (!m_iconValid) {
if (m_retryTimes < 5) {
m_retryTimes++;
qDebug() << m_itemEntryInter->name() << "obtain app icon(" << icon << ")failed, retry times:" << m_retryTimes;
m_retryObtainIconTimer->start();
} else {
// 如果图标获取失败没隔10秒刷新一次
if (!m_iconValid)
QTimer::singleShot(10 * 1000, this, [ = ] { m_retryObtainIconTimer->start(); });
}
update();
return;
} else if (m_retryTimes > 0) {
// reset times

View File

@ -121,6 +121,7 @@ private:
bool m_active;
int m_retryTimes;
int m_lastShowDay;
bool m_iconValid;
unsigned long m_lastclickTimes;
WindowInfoMap m_windowInfos;

View File

@ -51,11 +51,10 @@ LauncherItem::LauncherItem(QWidget *parent)
void LauncherItem::refreshIcon()
{
const int iconSize = qMin(width(), height());
if (DockDisplayMode == Efficient)
{
m_icon = ThemeAppIcon::getIcon("deepin-launcher", iconSize * 0.7, devicePixelRatioF());
if (DockDisplayMode == Efficient) {
ThemeAppIcon::getIcon(m_icon, "deepin-launcher", iconSize * 0.7, devicePixelRatioF());
} else {
m_icon = ThemeAppIcon::getIcon("deepin-launcher", iconSize * 0.8, devicePixelRatioF());
ThemeAppIcon::getIcon(m_icon, "deepin-launcher", iconSize * 0.8, devicePixelRatioF());
}
update();

View File

@ -20,6 +20,7 @@
*/
#include "themeappicon.h"
#include "imageutil.h"
#include <QIcon>
#include <QFile>
@ -31,7 +32,9 @@
#include <QLabel>
#include <QDate>
#include "imageutil.h"
#include <private/qguiapplication_p.h>
#include <private/qiconloader_p.h>
#include <qpa/qplatformtheme.h>
ThemeAppIcon::ThemeAppIcon(QObject *parent) : QObject(parent)
{
@ -43,11 +46,33 @@ ThemeAppIcon::~ThemeAppIcon()
}
const QPixmap ThemeAppIcon::getIcon(const QString iconName, const int size, const qreal ratio)
/**
* @brief ThemeAppIcon::getIcon \a name
* @param name
* @return
* @note 使QIcon::fromTheme是因为这个函数中有缓存机制
*/
QIcon ThemeAppIcon::getIcon(const QString &name)
{
QIcon icon;
QPlatformTheme * const platformTheme = QGuiApplicationPrivate::platformTheme();
bool hasUserTheme = QIconLoader::instance()->hasUserTheme();
if (!platformTheme || hasUserTheme)
return QIcon::fromTheme(name);
QIconEngine * const engine = platformTheme->createIconEngine(name);
QIcon *cachedIcon = new QIcon(engine);
icon = *cachedIcon;
return icon;
}
bool ThemeAppIcon::getIcon(QPixmap &pix, const QString iconName, const int size, const qreal ratio, bool reObtain)
{
QPixmap pixmap;
QString key;
QIcon icon;
bool ret = true;
// 把size改为小于size的最大偶数 :)
const int s = int(size * ratio) & ~1;
const float iconZoom = size / 64.0 * 0.8;
@ -95,15 +120,15 @@ const QPixmap ThemeAppIcon::getIcon(const QString iconName, const int size, cons
layout->setSpacing(0);
layout->setContentsMargins(0, 10 * iconZoom, 0, 10 * iconZoom);
calendar->setLayout(layout);
pixmap = calendar->grab(calendar->rect());
pix = calendar->grab(calendar->rect());
delete calendar;
calendar = nullptr;
if (pixmap.size().width() != s) {
pixmap = pixmap.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (pix.size().width() != s) {
pix = pix.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
return pixmap;
return ret;
}
do {
@ -115,7 +140,7 @@ const QPixmap ThemeAppIcon::getIcon(const QString iconName, const int size, cons
// that is ~2M on HiDPI enabled machine with 9 icons loaded,
// but I don't know why since QIcon has its own cache and all of the
// icons loaded are loaded by QIcon::fromTheme, really strange here.
if (QPixmapCache::find(key, &pixmap))
if (QPixmapCache::find(key, &pix))
break;
}
@ -123,40 +148,39 @@ const QPixmap ThemeAppIcon::getIcon(const QString iconName, const int size, cons
if (iconName.startsWith("data:image/")) {
const QStringList strs = iconName.split("base64,");
if (strs.size() == 2)
pixmap.loadFromData(QByteArray::fromBase64(strs.at(1).toLatin1()));
pix.loadFromData(QByteArray::fromBase64(strs.at(1).toLatin1()));
if (!pixmap.isNull())
if (!pix.isNull())
break;
}
// load pixmap from File
if (QFile::exists(iconName)) {
pixmap = QPixmap(iconName);
if (!pixmap.isNull())
pix = QPixmap(iconName);
if (!pix.isNull())
break;
}
icon = QIcon::fromTheme(iconName);
if (icon.isNull()) {
//手动更新图标缓存
system("gtk-update-icon-cache /usr/share/icons/hicolor/");
// 重新从主题中获取一次
if (reObtain)
icon = getIcon(iconName);
else
icon = QIcon::fromTheme(iconName);
}
if(icon.isNull()) {
icon = QIcon::fromTheme("application-x-desktop");
ret = false;
}
// load pixmap from Icon-Theme
const int fakeSize = std::max(48, s); // cannot use 16x16, cause 16x16 is label icon
pixmap = icon.pixmap(QSize(fakeSize, fakeSize));
if (!pixmap.isNull())
pix = icon.pixmap(QSize(fakeSize, fakeSize));
if (!pix.isNull())
break;
// fallback to a Default pixmap
pixmap = QPixmap(":/icons/resources/application-x-desktop.svg");
if (!pixmap.isNull())
pix = QPixmap(":/icons/resources/application-x-desktop.svg");
if (!pix.isNull())
break;
Q_UNREACHABLE();
@ -164,12 +188,13 @@ const QPixmap ThemeAppIcon::getIcon(const QString iconName, const int size, cons
} while (false);
if (!key.isEmpty()) {
QPixmapCache::insert(key, pixmap);
QPixmapCache::insert(key, pix);
}
if (pixmap.size().width() != s) {
pixmap = pixmap.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (pix.size().width() != s) {
pix = pix.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
pixmap.setDevicePixelRatio(ratio);
return pixmap;
pix.setDevicePixelRatio(ratio);
return ret;
}

View File

@ -31,7 +31,8 @@ public:
explicit ThemeAppIcon(QObject *parent = 0);
~ThemeAppIcon();
static const QPixmap getIcon(const QString iconName, const int size, const qreal ratio);
static QIcon getIcon(const QString &name);
static bool getIcon(QPixmap &pix, const QString iconName, const int size, const qreal ratio, bool reObtain = false);
};
#endif // THEMEAPPICON_H

View File

@ -34,6 +34,7 @@ add_library(${PLUGIN_NAME} SHARED ${SRCS} tray.qrc)
set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../)
target_include_directories(${PLUGIN_NAME} PUBLIC ${DtkWidget_INCLUDE_DIRS}
${Qt5DBus_INCLUDE_DIRS}
${Qt5Gui_PRIVATE_INCLUDE_DIRS}
${XCB_LIBS_INCLUDE_DIRS}
${DDE-Network-Utils_INCLUDE_DIRS}
${DFrameworkDBus_INCLUDE_DIRS}

View File

@ -542,7 +542,7 @@ QPixmap SNITrayWidget::newIconPixmap(IconType iconType)
// so, it should be the last fallback
if (!iconName.isEmpty()) {
// ThemeAppIcon::getIcon 会处理高分屏缩放问题
pixmap = ThemeAppIcon::getIcon(iconName, IconSize, devicePixelRatioF());
ThemeAppIcon::getIcon(pixmap, iconName, IconSize, devicePixelRatioF());
if (!pixmap.isNull()) {
break;
}

View File

@ -44,11 +44,18 @@ void Ut_ThemeAppIcon::TearDown()
TEST_F(Ut_ThemeAppIcon, getIcon_test)
{
ThemeAppIcon appIcon;
const QPixmap &pix1 = appIcon.getIcon("", 50, 1.0);
QPixmap pix1;
appIcon.getIcon(pix1, "", 50, 1.0);
ASSERT_FALSE(pix1.isNull());
appIcon.getIcon("dde-calendar", 50, 1.0);
const QPixmap &pix2 = appIcon.getIcon("data:image/test", 50, 1.0);
QPixmap pix;
appIcon.getIcon(pix, "dde-calendar", 50, 1.0);
QPixmap pix2;
appIcon.getIcon(pix2, "data:image/test", 50, 1.0);
ASSERT_FALSE(pix2.isNull());
const QPixmap &pix3 = appIcon.getIcon(":/res/all_settings_on.png", 50, 1.0);
QPixmap pix3;
appIcon.getIcon(pix3, ":/res/all_settings_on.png", 50, 1.0);
ASSERT_FALSE(pix3.isNull());
}