diff --git a/frame/CMakeLists.txt b/frame/CMakeLists.txt index f6a5f7e0e..45790355b 100644 --- a/frame/CMakeLists.txt +++ b/frame/CMakeLists.txt @@ -61,6 +61,7 @@ target_link_libraries(${BIN_NAME} PRIVATE ${DFrameworkDBus_LIBRARIES} ${DtkWidget_LIBRARIES} ${Qt5Widgets_LIBRARIES} + ${Qt5Gui_LIBRARIES} ${Qt5Concurrent_LIBRARIES} ${Qt5X11Extras_LIBRARIES} ${Qt5DBus_LIBRARIES} diff --git a/frame/item/appitem.cpp b/frame/item/appitem.cpp index 43b3783c7..950d1389a 100644 --- a/frame/item/appitem.cpp +++ b/frame/item/appitem.cpp @@ -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 diff --git a/frame/item/appitem.h b/frame/item/appitem.h index 59a1e4bfa..50fccb5b7 100644 --- a/frame/item/appitem.h +++ b/frame/item/appitem.h @@ -121,6 +121,7 @@ private: bool m_active; int m_retryTimes; int m_lastShowDay; + bool m_iconValid; unsigned long m_lastclickTimes; WindowInfoMap m_windowInfos; diff --git a/frame/item/launcheritem.cpp b/frame/item/launcheritem.cpp index cbecb645e..e4cdfedab 100644 --- a/frame/item/launcheritem.cpp +++ b/frame/item/launcheritem.cpp @@ -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(); diff --git a/frame/util/themeappicon.cpp b/frame/util/themeappicon.cpp index 99a17c8c5..325d9cb1b 100644 --- a/frame/util/themeappicon.cpp +++ b/frame/util/themeappicon.cpp @@ -20,6 +20,7 @@ */ #include "themeappicon.h" +#include "imageutil.h" #include #include @@ -31,7 +32,9 @@ #include #include -#include "imageutil.h" +#include +#include +#include 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; } diff --git a/frame/util/themeappicon.h b/frame/util/themeappicon.h index 64bfa6c95..338509cc2 100644 --- a/frame/util/themeappicon.h +++ b/frame/util/themeappicon.h @@ -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 diff --git a/plugins/tray/CMakeLists.txt b/plugins/tray/CMakeLists.txt index c0513ac2e..9fc1bd481 100644 --- a/plugins/tray/CMakeLists.txt +++ b/plugins/tray/CMakeLists.txt @@ -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} diff --git a/plugins/tray/snitraywidget.cpp b/plugins/tray/snitraywidget.cpp index 99530cd8c..dcaa3fe96 100644 --- a/plugins/tray/snitraywidget.cpp +++ b/plugins/tray/snitraywidget.cpp @@ -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; } diff --git a/tests/util/ut_themeappicon.cpp b/tests/util/ut_themeappicon.cpp index 885d94bdb..f17ccc8a1 100644 --- a/tests/util/ut_themeappicon.cpp +++ b/tests/util/ut_themeappicon.cpp @@ -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()); }