diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index d7248e7d3..ded4e7f86 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -210,12 +210,12 @@ void Preferences::setHideZeroComboValues(const int n) // In Mac OS X the dock is sufficient for our needs so we disable the sys tray functionality. // See extensive discussion in https://github.com/qbittorrent/qBittorrent/pull/3018 #ifndef Q_OS_MACOS -bool Preferences::systrayIntegration() const +bool Preferences::systemTrayEnabled() const { return value("Preferences/General/SystrayEnabled", true); } -void Preferences::setSystrayIntegration(const bool enabled) +void Preferences::setSystemTrayEnabled(const bool enabled) { setValue("Preferences/General/SystrayEnabled", enabled); } diff --git a/src/base/preferences.h b/src/base/preferences.h index d41bf12f7..ad0d2235d 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -315,8 +315,8 @@ public: bool confirmRemoveAllTags() const; void setConfirmRemoveAllTags(bool enabled); #ifndef Q_OS_MACOS - bool systrayIntegration() const; - void setSystrayIntegration(bool enabled); + bool systemTrayEnabled() const; + void setSystemTrayEnabled(bool enabled); bool minimizeToTrayNotified() const; void setMinimizeToTrayNotified(bool b); bool minimizeToTray() const; diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index f86c1922f..1b0f3d6d6 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -179,6 +179,8 @@ MainWindow::MainWindow(QWidget *parent) m_ui->actionLock->setMenu(lockMenu); // Creating Bittorrent session + updateAltSpeedsBtn(BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled()); + connect(BitTorrent::Session::instance(), &BitTorrent::Session::fullDiskError, this, &MainWindow::fullDiskError); connect(BitTorrent::Session::instance(), &BitTorrent::Session::loadTorrentFailed, this, &MainWindow::addTorrentFailed); connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentAdded,this, &MainWindow::torrentNew); @@ -319,7 +321,7 @@ MainWindow::MainWindow(QWidget *parent) connect(m_preventTimer, &QTimer::timeout, this, &MainWindow::updatePowerManagementState); // Configure BT session according to options - loadPreferences(false); + loadPreferences(); connect(BitTorrent::Session::instance(), &BitTorrent::Session::statsUpdated, this, &MainWindow::reloadSessionStats); connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentsUpdated, this, &MainWindow::reloadTorrentStats); @@ -380,7 +382,19 @@ MainWindow::MainWindow(QWidget *parent) // Load Window state and sizes readSettings(); -#ifndef Q_OS_MACOS +#ifdef Q_OS_MACOS + // Make sure the Window is visible if we don't have a tray icon + if (pref->startMinimized()) + { + showMinimized(); + } + else + { + show(); + activateWindow(); + raise(); + } +#else if (m_systrayIcon) { if (!(pref->startMinimized() || m_uiLocked)) @@ -405,7 +419,6 @@ MainWindow::MainWindow(QWidget *parent) } else { -#endif // Make sure the Window is visible if we don't have a tray icon if (pref->startMinimized()) { @@ -417,7 +430,6 @@ MainWindow::MainWindow(QWidget *parent) activateWindow(); raise(); } -#ifndef Q_OS_MACOS } #endif @@ -456,7 +468,8 @@ MainWindow::MainWindow(QWidget *parent) #endif #ifdef Q_OS_MACOS setupDockClickHandler(); - trayIconMenu()->setAsDockMenu(); + createTrayIconMenu(); + m_trayIconMenu->setAsDockMenu(); #endif } @@ -785,10 +798,6 @@ void MainWindow::cleanup() delete m_rssWidget; delete m_executableWatcher; -#ifndef Q_OS_MACOS - if (m_systrayCreator) - m_systrayCreator->stop(); -#endif m_preventTimer->stop(); @@ -1469,50 +1478,33 @@ void MainWindow::showStatusBar(bool show) } } -void MainWindow::loadPreferences(const bool configureSession) +void MainWindow::loadPreferences() { - const Preferences *const pref = Preferences::instance(); -#ifdef Q_OS_MACOS - Q_UNUSED(configureSession); -#else - const bool newSystrayIntegration = pref->systrayIntegration(); - m_ui->actionLock->setVisible(newSystrayIntegration); - if (newSystrayIntegration != (m_systrayIcon != nullptr)) + const Preferences *pref = Preferences::instance(); + +#ifndef Q_OS_MACOS + // system tray icon + const bool useSystray = pref->systemTrayEnabled(); + m_ui->actionLock->setVisible(useSystray); + if (useSystray) { - if (newSystrayIntegration) + if (m_systrayIcon) { - // create the trayicon - if (!QSystemTrayIcon::isSystemTrayAvailable()) - { - if (!configureSession) - { // Program startup - m_systrayCreator = new QTimer(this); - connect(m_systrayCreator.data(), &QTimer::timeout, this, &MainWindow::createSystrayDelayed); - m_systrayCreator->setSingleShot(true); - m_systrayCreator->start(2000); - qDebug("Info: System tray is unavailable, trying again later."); - } - else - { - qDebug("Warning: System tray is unavailable."); - } - } - else - { - createTrayIcon(); - } + // Reload systray icon + m_systrayIcon->setIcon(UIThemeManager::instance()->getSystrayIcon()); } else { - // Destroy trayicon - delete m_systrayIcon; - delete m_trayIconMenu; + createTrayIcon(20); } } - // Reload systray icon - if (newSystrayIntegration && m_systrayIcon) - m_systrayIcon->setIcon(getSystrayIcon()); + else + { + delete m_systrayIcon; + delete m_trayIconMenu; + } #endif + // General if (pref->isToolbarDisplayed()) { @@ -1621,7 +1613,7 @@ void MainWindow::reloadSessionStats() #else if (m_systrayIcon) { - const QString toolTip = QString::fromLatin1("%1\n%2").arg( + const auto toolTip = QString::fromLatin1("%1\n%2").arg( tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadDownloadRate, true)) , tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadUploadRate, true))); m_systrayIcon->setToolTip(toolTip); // tray icon @@ -1705,86 +1697,81 @@ void MainWindow::downloadFromURLList(const QStringList &urlList) *****************************************************/ #ifndef Q_OS_MACOS -void MainWindow::createSystrayDelayed() +void MainWindow::createTrayIcon(const int retries) { - static int timeout = 20; + if (m_systrayIcon) + return; + if (QSystemTrayIcon::isSystemTrayAvailable()) { - // Ok, systray integration is now supported - // Create systray icon - createTrayIcon(); - delete m_systrayCreator; + m_systrayIcon = new QSystemTrayIcon(UIThemeManager::instance()->getSystrayIcon(), this); + + createTrayIconMenu(); + m_systrayIcon->setContextMenu(m_trayIconMenu); + + connect(m_systrayIcon, &QSystemTrayIcon::activated, this, &MainWindow::toggleVisibility); + connect(m_systrayIcon, &QSystemTrayIcon::messageClicked, this, &MainWindow::balloonClicked); + + m_systrayIcon->show(); } else { - if (timeout) + if (retries > 0) { - // Retry a bit later - m_systrayCreator->start(2000); - --timeout; + LogMsg("System tray icon is not available, retrying...", Log::WARNING); + QTimer::singleShot(std::chrono::seconds(2), this, [this, retries]() + { + if (Preferences::instance()->systemTrayEnabled()) + createTrayIcon(retries - 1); + }); } else { - // Timed out, apparently system really does not - // support systray icon - delete m_systrayCreator; - // Disable it in program preferences to - // avoid trying at each startup - Preferences::instance()->setSystrayIntegration(false); + LogMsg("System tray icon is still not available after retries. Disabling it.", Log::WARNING); + Preferences::instance()->setSystemTrayEnabled(false); } } } - -void MainWindow::updateTrayIconMenu() -{ - m_ui->actionToggleVisibility->setText(isVisible() ? tr("Hide") : tr("Show")); -} - -void MainWindow::createTrayIcon() -{ - // Tray icon - m_systrayIcon = new QSystemTrayIcon(getSystrayIcon(), this); - - m_systrayIcon->setContextMenu(trayIconMenu()); - connect(m_systrayIcon.data(), &QSystemTrayIcon::messageClicked, this, &MainWindow::balloonClicked); - // End of Icon Menu - connect(m_systrayIcon.data(), &QSystemTrayIcon::activated, this, &MainWindow::toggleVisibility); - m_systrayIcon->show(); -} #endif // Q_OS_MACOS -QMenu *MainWindow::trayIconMenu() +void MainWindow::createTrayIconMenu() { - if (m_trayIconMenu) return m_trayIconMenu; + if (m_trayIconMenu) + return; m_trayIconMenu = new QMenu(this); + #ifndef Q_OS_MACOS - connect(m_trayIconMenu.data(), &QMenu::aboutToShow, this, &MainWindow::updateTrayIconMenu); + connect(m_trayIconMenu, &QMenu::aboutToShow, this, [this]() + { + m_ui->actionToggleVisibility->setText(isVisible() ? tr("Hide") : tr("Show")); + }); + m_trayIconMenu->addAction(m_ui->actionToggleVisibility); m_trayIconMenu->addSeparator(); #endif + m_trayIconMenu->addAction(m_ui->actionOpen); m_trayIconMenu->addAction(m_ui->actionDownloadFromURL); m_trayIconMenu->addSeparator(); - const bool isAltBWEnabled = BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled(); - updateAltSpeedsBtn(isAltBWEnabled); - m_ui->actionUseAlternativeSpeedLimits->setChecked(isAltBWEnabled); + m_trayIconMenu->addAction(m_ui->actionUseAlternativeSpeedLimits); m_trayIconMenu->addAction(m_ui->actionSetGlobalSpeedLimits); m_trayIconMenu->addSeparator(); + m_trayIconMenu->addAction(m_ui->actionStartAll); m_trayIconMenu->addAction(m_ui->actionPauseAll); + #ifndef Q_OS_MACOS m_trayIconMenu->addSeparator(); m_trayIconMenu->addAction(m_ui->actionExit); #endif + if (m_uiLocked) m_trayIconMenu->setEnabled(false); - - return m_trayIconMenu; } -void MainWindow::updateAltSpeedsBtn(bool alternative) +void MainWindow::updateAltSpeedsBtn(const bool alternative) { m_ui->actionUseAlternativeSpeedLimits->setChecked(alternative); } @@ -2072,42 +2059,6 @@ void MainWindow::updatePowerManagementState() m_pwr->setActivityState(inhibitSuspend); } -#ifndef Q_OS_MACOS -QIcon MainWindow::getSystrayIcon() const -{ - const TrayIcon::Style style = Preferences::instance()->trayIconStyle(); - // on Linux we use theme icons, and icons from resources everywhere else -#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) - switch (style) - { - case TrayIcon::Style::Normal: - return QIcon::fromTheme(QLatin1String("qbittorrent-tray")); - case TrayIcon::Style::MonoDark: - return QIcon::fromTheme(QLatin1String("qbittorrent-tray-dark")); - case TrayIcon::Style::MonoLight: - return QIcon::fromTheme(QLatin1String("qbittorrent-tray-light")); - default: - break; - } -#else - switch (style) - { - case TrayIcon::Style::Normal: - return UIThemeManager::instance()->getIcon(QLatin1String("qbittorrent-tray")); - case TrayIcon::Style::MonoDark: - return UIThemeManager::instance()->getIcon(QLatin1String("qbittorrent-tray-dark")); - case TrayIcon::Style::MonoLight: - return UIThemeManager::instance()->getIcon(QLatin1String("qbittorrent-tray-light")); - default: - break; - } -#endif - - // As a failsafe in case the enum is invalid - return UIThemeManager::instance()->getIcon(QLatin1String("qbittorrent-tray")); -} -#endif // Q_OS_MACOS - #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) void MainWindow::checkProgramUpdate(const bool invokedByUser) { diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index 4e75fa561..075a8408d 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -82,7 +82,6 @@ public: QWidget *currentTabWidget() const; TransferListWidget *transferListWidget() const; PropertiesWidget *propertiesWidget() const; - QMenu *trayIconMenu(); // ExecutionLog properties bool isExecutionLogEnabled() const; @@ -132,7 +131,7 @@ private slots: void focusSearchFilter(); void reloadSessionStats(); void reloadTorrentStats(const QVector &torrents); - void loadPreferences(bool configureSession = true); + void loadPreferences(); void addTorrentFailed(const QString &error) const; void torrentNew(BitTorrent::Torrent *const torrent) const; void finishedTorrent(BitTorrent::Torrent *const torrent) const; @@ -189,16 +188,14 @@ private slots: void on_actionCloseWindow_triggered(); #else void toggleVisibility(const QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Trigger); - void createSystrayDelayed(); - void updateTrayIconMenu(); #endif private: + void createTrayIconMenu(); #ifdef Q_OS_MACOS void setupDockClickHandler(); #else - void createTrayIcon(); - QIcon getSystrayIcon() const; + void createTrayIcon(int retries); #endif #ifdef Q_OS_WIN void installPython(); @@ -227,11 +224,12 @@ private: QPointer m_statsDlg; QPointer m_createTorrentDlg; QPointer m_downloadFromURLDialog; + #ifndef Q_OS_MACOS QPointer m_systrayIcon; - QPointer m_systrayCreator; #endif QPointer m_trayIconMenu; + TransferListWidget *m_transferListWidget; TransferListFiltersWidget *m_transferListFiltersWidget; PropertiesWidget *m_propertiesWidget; diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index 5a6dae4f6..c87957a43 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -677,7 +677,7 @@ void OptionsDialog::saveOptions() pref->setHideZeroValues(m_ui->checkHideZero->isChecked()); pref->setHideZeroComboValues(m_ui->comboHideZero->currentIndex()); #ifndef Q_OS_MACOS - pref->setSystrayIntegration(systrayIntegration()); + pref->setSystemTrayEnabled(systemTrayEnabled()); pref->setTrayIconStyle(TrayIcon::Style(m_ui->comboTrayIcon->currentIndex())); pref->setCloseToTray(closeToTray()); pref->setMinimizeToTray(minimizeToTray()); @@ -936,7 +936,7 @@ void OptionsDialog::loadOptions() m_ui->checkProgramAutoExitConfirm->setChecked(!pref->dontConfirmAutoExit()); #ifndef Q_OS_MACOS - m_ui->checkShowSystray->setChecked(pref->systrayIntegration()); + m_ui->checkShowSystray->setChecked(pref->systemTrayEnabled()); if (m_ui->checkShowSystray->isChecked()) { m_ui->checkMinimizeToSysTray->setChecked(pref->minimizeToTray()); @@ -1346,10 +1346,11 @@ bool OptionsDialog::startMinimized() const } #ifndef Q_OS_MACOS -bool OptionsDialog::systrayIntegration() const +bool OptionsDialog::systemTrayEnabled() const { - if (!QSystemTrayIcon::isSystemTrayAvailable()) return false; - return m_ui->checkShowSystray->isChecked(); + return QSystemTrayIcon::isSystemTrayAvailable() + ? m_ui->checkShowSystray->isChecked() + : false; } bool OptionsDialog::minimizeToTray() const diff --git a/src/gui/optionsdialog.h b/src/gui/optionsdialog.h index d921bd380..00eb8cdef 100644 --- a/src/gui/optionsdialog.h +++ b/src/gui/optionsdialog.h @@ -122,7 +122,7 @@ private: // General options QString getLocale() const; #ifndef Q_OS_MACOS - bool systrayIntegration() const; + bool systemTrayEnabled() const; bool minimizeToTray() const; bool closeToTray() const; #endif diff --git a/src/gui/uithememanager.cpp b/src/gui/uithememanager.cpp index fa5017777..cf19c75b1 100644 --- a/src/gui/uithememanager.cpp +++ b/src/gui/uithememanager.cpp @@ -157,6 +157,36 @@ QColor UIThemeManager::getColor(const QString &id, const QColor &defaultColor) c return m_colors.value(id, defaultColor); } +#ifndef Q_OS_MACOS +QIcon UIThemeManager::getSystrayIcon() const +{ + const TrayIcon::Style style = Preferences::instance()->trayIconStyle(); + switch (style) + { +#if defined(Q_OS_UNIX) + case TrayIcon::Style::Normal: + return QIcon::fromTheme(QLatin1String("qbittorrent-tray")); + case TrayIcon::Style::MonoDark: + return QIcon::fromTheme(QLatin1String("qbittorrent-tray-dark")); + case TrayIcon::Style::MonoLight: + return QIcon::fromTheme(QLatin1String("qbittorrent-tray-light")); +#else + case TrayIcon::Style::Normal: + return getIcon(QLatin1String("qbittorrent-tray")); + case TrayIcon::Style::MonoDark: + return getIcon(QLatin1String("qbittorrent-tray-dark")); + case TrayIcon::Style::MonoLight: + return getIcon(QLatin1String("qbittorrent-tray-light")); +#endif + default: + break; + } + + // As a failsafe in case the enum is invalid + return getIcon(QLatin1String("qbittorrent-tray")); +} +#endif + QString UIThemeManager::getIconPath(const QString &iconId) const { #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) diff --git a/src/gui/uithememanager.h b/src/gui/uithememanager.h index becb13b62..3fececb8b 100644 --- a/src/gui/uithememanager.h +++ b/src/gui/uithememanager.h @@ -29,6 +29,7 @@ #pragma once +#include #include #include #include @@ -51,6 +52,10 @@ public: QColor getColor(const QString &id, const QColor &defaultColor) const; +#ifndef Q_OS_MACOS + QIcon getSystrayIcon() const; +#endif + private: UIThemeManager(); // singleton class QString getIconPathFromResources(const QString &iconId, const QString &fallback = {}) const;