fix(GODT-1374): Fix tray icon DPI change handling.

This commit is contained in:
Xavier Michelon
2023-04-27 12:05:40 +02:00
parent fbbd0245de
commit 06f710a9b1
2 changed files with 61 additions and 8 deletions

View File

@ -33,6 +33,8 @@ QColor const errorColor(220, 50, 81); ///< The error state color.
QColor const warnColor(255, 153, 0); ///< The warn state color.
QColor const updateColor(35, 158, 206); ///< The warn state color.
QColor const greyColor(112, 109, 107); ///< The grey color.
qint64 const iconRefreshTimerIntervalMs = 1000; ///< The interval for the refresh timer when switching DPI / screen config, in milliseconds.
qint64 const iconRefreshDurationSecs = 10; ///< The total number of seconds during wich we periodically refresh the icon after a DPI change.
//****************************************************************************************************************************************************
@ -112,6 +114,17 @@ TrayIcon::TrayIcon()
this->show();
this->setState(State::Normal, QString(), QString());
// TrayIcon does not expose its screen, so we connect relevant screen events to our DPI change handler.
for (QScreen *screen: QGuiApplication::screens()) {
connect(screen, &QScreen::logicalDotsPerInchChanged, this, &TrayIcon::handleDPIChange);
}
connect(qApp, &QApplication::screenAdded, [&](QScreen *screen) { connect(screen, &QScreen::logicalDotsPerInchChanged, this, &TrayIcon::handleDPIChange); });
connect(qApp, &QApplication::primaryScreenChanged, [&](QScreen *screen) { connect(screen, &QScreen::logicalDotsPerInchChanged, this, &TrayIcon::handleDPIChange); });
iconRefreshTimer_.setSingleShot(false);
iconRefreshTimer_.setInterval(iconRefreshTimerIntervalMs);
connect(&iconRefreshTimer_, &QTimer::timeout, this, &TrayIcon::onIconRefreshTimer);
}
@ -155,6 +168,46 @@ void TrayIcon::onActivated(QSystemTrayIcon::ActivationReason reason) {
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void TrayIcon::handleDPIChange() {
this->setIcon();
// Windows forces us to apply a hack. Tray icon does not redraw by itself, so we use the Qt signal that detects screen and DPI changes.
// But the moment we get the signal the DPI change is not yet in effect. so redrawing now will have no effect, and we don't really
// know when we can safely redraw. So we will redraw the icon every second for some time.
iconRefreshDeadline_ = QDateTime::currentDateTime().addSecs(iconRefreshDurationSecs);
if (!iconRefreshTimer_.isActive()) {
iconRefreshTimer_.start();
}
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void TrayIcon::setIcon() {
QString const style = onMacOS() ? "mono" : "color";
QString const text = stateText(state_);
QIcon icon = loadIconFromImage(QString(":/qml/icons/systray-%1-%2.png").arg(style, text));
icon.setIsMask(true);
QSystemTrayIcon::setIcon(icon);
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void TrayIcon::onIconRefreshTimer() {
this->setIcon();
if (QDateTime::currentDateTime() > iconRefreshDeadline_) {
iconRefreshTimer_.stop();
}
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
@ -184,14 +237,7 @@ void TrayIcon::generateDotIcons() {
void TrayIcon::setState(TrayIcon::State state, QString const &stateString, QString const &statusIconPath) {
stateString_ = stateString;
state_ = state;
QString const style = onMacOS() ? "mono" : "color";
QString const text = stateText(state);
QIcon icon = loadIconFromImage(QString(":/qml/icons/systray-%1-%2.png").arg(style, text));
icon.setIsMask(true);
this->setIcon(icon);
this->setIcon();
this->generateStatusIcon(statusIconPath, stateColor(state));
}

View File

@ -41,6 +41,7 @@ public: // data members
TrayIcon& operator=(TrayIcon const&) = delete; ///< Disabled assignment operator.
TrayIcon& operator=(TrayIcon&&) = delete; ///< Disabled move assignment operator.
void setState(State state, QString const& stateString, QString const &statusIconPath); ///< Set the state of the icon
void showNotificationPopup(QString const& title, QString const &message, QString const& iconPath); ///< Display a pop up notification.
signals:
void selectUser(QString const& userID); ///< Signal for selecting a user with a given userID
@ -49,6 +50,9 @@ private slots:
void onMenuAboutToShow(); ///< Slot called before the context menu is shown.
void onUserClicked(); ///< Slot triggered when clicking on a user in the context menu.
static void onActivated(QSystemTrayIcon::ActivationReason reason); ///< Slot for the activation of the system tray icon.
void handleDPIChange(); ///< Handles DPI change.
void setIcon(); ///< set the tray icon.
void onIconRefreshTimer(); ///< Timer for icon refresh.
private: // member functions.
void generateDotIcons(); ///< generate the colored dot icons used for user status.
@ -63,6 +67,9 @@ private: // data members
QIcon greenDot_; ///< The green dot icon.
QIcon greyDot_; ///< The grey dot icon.
QIcon orangeDot_; ///< The orange dot icon.
QTimer iconRefreshTimer_; ///< The timer used to periodically refresh the icon when DPI changes.
QDateTime iconRefreshDeadline_; ///< The deadline for refreshing the icon
};