From 6206b6f843626996d1cad0c56f9a181ae93f4a5e Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Thu, 6 Feb 2020 15:34:28 +0400 Subject: [PATCH] Adapt indicator-application check for sandboxed environments Fix quality loss in the tray icon image Fix window showing by clicking on the tray icon on macOS Fix tray icon displaying on KDE --- .github/workflows/linux.yml | 5 +- Telegram/SourceFiles/mainwindow.cpp | 9 +- .../platform/linux/main_window_linux.cpp | 109 +++++++++++------- .../platform/linux/main_window_linux.h | 2 +- .../platform/mac/main_window_mac.mm | 11 +- Telegram/SourceFiles/qt_static_plugins.cpp | 1 + .../statusnotifieritem/statusnotifieritem.cpp | 9 ++ .../statusnotifieritem/statusnotifieritem.h | 6 + docs/building-cmake.md | 3 +- 9 files changed, 98 insertions(+), 57 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 02727c5323..78004ab3be 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,7 +31,7 @@ jobs: CMAKE_VER: "3.16.3" UPLOAD_ARTIFACT: "false" ONLY_CACHE: "false" - MANUAL_CACHING: "2" + MANUAL_CACHING: "3" DOC_PATH: "docs/building-cmake.md" steps: @@ -364,10 +364,11 @@ jobs: git clone git://code.qt.io/qt/qt5.git qt_$QT cd qt_$QT - perl init-repository --module-subset=qtbase,qtimageformats + perl init-repository --module-subset=qtbase,qtimageformats,qtsvg git checkout v5.12.5 git submodule update qtbase git submodule update qtimageformats + git submodule update qtsvg cd qtbase git apply ../../patches/qtbase_$QT.diff cd src/plugins/platforminputcontexts diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 3388cb186d..b404807dc0 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -556,8 +556,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *e) { void MainWindow::updateTrayMenu(bool force) { if (!trayIconMenu || (Platform::IsWindows() && !force)) return; - auto iconMenu = trayIconMenu; - auto actions = iconMenu->actions(); + auto actions = trayIconMenu->actions(); if (Platform::IsLinux()) { auto minimizeAction = actions.at(1); minimizeAction->setEnabled(isVisible()); @@ -571,12 +570,6 @@ void MainWindow::updateTrayMenu(bool force) { toggleAction->setText(active ? tr::lng_minimize_to_tray(tr::now) : tr::lng_open_from_tray(tr::now)); - - // On macOS just remove trayIcon menu if the window is not active. - // So we will activate the window on click instead of showing the menu. - if (!active && Platform::IsMac()) { - iconMenu = nullptr; - } } auto notificationAction = actions.at(Platform::IsLinux() ? 2 : 1); auto notificationActionText = Global::DesktopNotify() diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 83be08f3e7..63a2a5ecbf 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "facades.h" #include "app.h" +#include + #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #include #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION @@ -73,33 +75,49 @@ QImage TrayIconImageGen() { const auto iconThemeName = QIcon::themeName(); const auto iconName = GetTrayIconName(); + const auto desiredSize = QSize(_trayIconSize, _trayIconSize); if (_trayIconImage.isNull() - || _trayIconImage.width() != _trayIconSize + || _trayIconImage.size() != desiredSize || iconThemeName != _trayIconThemeName || iconName != _trayIconName || muted != _trayIconMuted || counterSlice != _trayIconCount) { if (_trayIconImageBack.isNull() - || _trayIconImageBack.width() != _trayIconSize + || _trayIconImageBack.size() != desiredSize || iconThemeName != _trayIconThemeName || iconName != _trayIconName) { - _trayIconImageBack = Core::App().logo(); + const auto hasPanelIcon = QIcon::hasThemeIcon(iconName); - _trayIconImageBack = QIcon::fromTheme( - iconName, - QIcon::fromTheme( - kTrayIconName.utf16(), - QIcon(QPixmap::fromImage(_trayIconImageBack))) - ).pixmap(_trayIconSize, _trayIconSize).toImage(); + if (hasPanelIcon || QIcon::hasThemeIcon(kTrayIconName.utf16())) { + QIcon systemIcon; - auto w = _trayIconImageBack.width(), - h = _trayIconImageBack.height(); + if (hasPanelIcon) { + systemIcon = QIcon::fromTheme(iconName); + } else { + systemIcon = QIcon::fromTheme(kTrayIconName.utf16()); + } - if (w != _trayIconSize || h != _trayIconSize) { + if (systemIcon.actualSize(desiredSize) == desiredSize) { + _trayIconImageBack = systemIcon + .pixmap(desiredSize) + .toImage(); + } else { + const auto biggestSize = systemIcon + .availableSizes() + .last(); + + _trayIconImageBack = systemIcon + .pixmap(biggestSize) + .toImage(); + } + } else { + _trayIconImageBack = Core::App().logo(); + } + + if (_trayIconImageBack.size() != desiredSize) { _trayIconImageBack = _trayIconImageBack.scaled( - _trayIconSize, - _trayIconSize, + desiredSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } @@ -107,8 +125,8 @@ QImage TrayIconImageGen() { _trayIconImageBack = _trayIconImageBack.convertToFormat( QImage::Format_ARGB32); - w = _trayIconImageBack.width(); - h = _trayIconImageBack.height(); + const auto w = _trayIconImageBack.width(); + const auto h = _trayIconImageBack.height(); const auto perline = _trayIconImageBack.bytesPerLine(); auto *bytes = _trayIconImageBack.bits(); @@ -166,26 +184,31 @@ QImage TrayIconImageGen() { return _trayIconImage; } +bool IsAppIndicator() { +#ifdef TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto AppIndicator = false; +#else // TDESKTOP_DISABLE_DBUS_INTEGRATION + static const auto AppIndicator = QDBusInterface( + qsl("com.canonical.indicator.application"), + qsl("/com/canonical/indicator/application/service"), + qsl("com.canonical.indicator.application.service")).isValid() + || QDBusInterface( + qsl("org.ayatana.indicator.application"), + qsl("/org/ayatana/indicator/application/service"), + qsl("org.ayatana.indicator.application.service")).isValid(); +#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION + + return AppIndicator; +} + #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION static bool NeedTrayIconFile() { // Hack for indicator-application, which doesn't handle icons sent across D-Bus: // save the icon to a temp file and set the icon name to that filename. - static const auto TrayIconFileNeeded = [&] { - auto necessary = false; - const auto session = QDBusConnection::sessionBus(); - const auto pid = session.interface() - ->servicePid(kSNIWatcherService.utf16()).value(); - const auto processName = ProcessNameByPID(QString::number(pid)); - necessary = processName.endsWith( - qsl("indicator-application-service")); - if (!necessary) { - // Accessing to process name might be not allowed if the application - // is confined, thus we can just rely on the current desktop in use - necessary = DesktopEnvironment::IsUnity() - || DesktopEnvironment::IsMATE(); - } - return necessary; - }(); + static const auto TrayIconFileNeeded = IsAppIndicator() + // Ubuntu's tray extension doesn't zoom image data, but zooms image file + || DesktopEnvironment::IsGnome(); + return TrayIconFileNeeded; } @@ -196,7 +219,7 @@ static inline QString TrayIconFileTemplate() { } std::unique_ptr TrayIconFile( - const QPixmap &icon, QObject *parent) { + const QImage &icon, QObject *parent) { auto ret = std::make_unique( TrayIconFileTemplate(), parent); @@ -268,7 +291,7 @@ void MainWindow::psTrayMenuUpdated() { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION void MainWindow::setSNITrayIcon( - const QIcon &icon, const QPixmap &iconPixmap) { + const QIcon &icon, const QImage &iconImage) { if (!NeedTrayIconFile()) { _sniTrayIcon->setIconByPixmap(icon); _sniTrayIcon->setToolTipIconByPixmap(icon); @@ -279,7 +302,7 @@ void MainWindow::setSNITrayIcon( _sniTrayIcon->setIconByName(iconName); _sniTrayIcon->setToolTipIconByName(iconName); } else if (NeedTrayIconFile()) { - _trayIconFile = TrayIconFile(iconPixmap, this); + _trayIconFile = TrayIconFile(iconImage, this); if (_trayIconFile) { _sniTrayIcon->setIconByName(_trayIconFile->fileName()); @@ -311,8 +334,8 @@ void MainWindow::attachToSNITrayIcon() { #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION void MainWindow::psSetupTrayIcon() { - const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen()); - const auto icon = QIcon(iconPixmap); + const auto iconImage = TrayIconImageGen(); + const auto icon = QIcon(QPixmap::fromImage(iconImage)); if (IsSNIAvailable()) { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION @@ -322,8 +345,8 @@ void MainWindow::psSetupTrayIcon() { QCoreApplication::applicationName(), this); - _sniTrayIcon->setTitle(QCoreApplication::applicationName()); - setSNITrayIcon(icon, iconPixmap); + _sniTrayIcon->setTitle(AppName.utf16()); + setSNITrayIcon(icon, iconImage); attachToSNITrayIcon(); } @@ -406,13 +429,13 @@ void MainWindow::updateIconCounters() { } #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen()); - const auto icon = QIcon(iconPixmap); + const auto iconImage = TrayIconImageGen(); + const auto icon = QIcon(QPixmap::fromImage(iconImage)); if (IsSNIAvailable()) { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION if (_sniTrayIcon) { - setSNITrayIcon(icon, iconPixmap); + setSNITrayIcon(icon, iconImage); } #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION } else if (trayIcon) { @@ -427,7 +450,7 @@ void MainWindow::LibsLoaded() { qDBusRegisterMetaType(); #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION - if (!IsSNIAvailable()) { + if (!IsSNIAvailable() || IsAppIndicator()) { _trayIconSize = 22; } } diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index b831322805..fa175b2e1a 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -70,7 +70,7 @@ private: StatusNotifierItem *_sniTrayIcon = nullptr; std::unique_ptr _trayIconFile = nullptr; - void setSNITrayIcon(const QIcon &icon, const QPixmap &iconPixmap); + void setSNITrayIcon(const QIcon &icon, const QImage &iconImage); void attachToSNITrayIcon(); #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index ed81efae55..32f6ae0a59 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -548,8 +548,15 @@ void MainWindow::psShowTrayMenu() { } void MainWindow::psTrayMenuUpdated() { - if (trayIcon && trayIconMenu && trayIcon->contextMenu() != trayIconMenu) { - trayIcon->setContextMenu(trayIconMenu); + // On macOS just remove trayIcon menu if the window is not active. + // So we will activate the window on click instead of showing the menu. + if (isActive()) { + if (trayIcon && trayIconMenu + && trayIcon->contextMenu() != trayIconMenu) { + trayIcon->setContextMenu(trayIconMenu); + } + } else { + trayIcon->setContextMenu(0); } } diff --git a/Telegram/SourceFiles/qt_static_plugins.cpp b/Telegram/SourceFiles/qt_static_plugins.cpp index fb68f24398..8d3e03633c 100644 --- a/Telegram/SourceFiles/qt_static_plugins.cpp +++ b/Telegram/SourceFiles/qt_static_plugins.cpp @@ -23,6 +23,7 @@ Q_IMPORT_PLUGIN(QGenericEnginePlugin) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) Q_IMPORT_PLUGIN(QGenericEnginePlugin) Q_IMPORT_PLUGIN(QComposePlatformInputContextPlugin) +Q_IMPORT_PLUGIN(QSvgIconPlugin) #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION Q_IMPORT_PLUGIN(QConnmanEnginePlugin) Q_IMPORT_PLUGIN(QNetworkManagerEnginePlugin) diff --git a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp index 96a3a537b7..a55079740c 100644 --- a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp +++ b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp @@ -42,6 +42,7 @@ StatusNotifierItem::StatusNotifierItem(QString id, QObject *parent) mId(id), mTitle(QLatin1String("Test")), mStatus(QLatin1String("Active")), + mCategory(QLatin1String("ApplicationStatus")), mMenu(nullptr), mMenuPath(QLatin1String("/NO_DBUSMENU")), mMenuExporter(nullptr), @@ -116,6 +117,14 @@ void StatusNotifierItem::setStatus(const QString &status) Q_EMIT mAdaptor->NewStatus(mStatus); } +void StatusNotifierItem::setCategory(const QString &category) +{ + if (mCategory == category) + return; + + mCategory = category; +} + void StatusNotifierItem::setMenuPath(const QString& path) { mMenuPath.setPath(path); diff --git a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h index 3a689d11dc..60739ea53a 100644 --- a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h +++ b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h @@ -43,6 +43,7 @@ class StatusNotifierItem : public QObject { Q_OBJECT + Q_PROPERTY(QString Category READ category) Q_PROPERTY(QString Title READ title) Q_PROPERTY(QString Id READ id) Q_PROPERTY(QString Status READ status) @@ -74,6 +75,10 @@ public: { return mStatus; } void setStatus(const QString &status); + QString category() const + { return mCategory; } + void setCategory(const QString &category); + QDBusObjectPath menu() const { return mMenuPath; } void setMenuPath(const QString &path); @@ -162,6 +167,7 @@ private: QString mId; QString mTitle; QString mStatus; + QString mCategory; // icons QString mIconName, mOverlayIconName, mAttentionIconName; diff --git a/docs/building-cmake.md b/docs/building-cmake.md index f1b4b8763d..2bcdd072a3 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -235,10 +235,11 @@ Go to ***BuildPath*** and run git clone git://code.qt.io/qt/qt5.git qt_5_12_5 cd qt_5_12_5 - perl init-repository --module-subset=qtbase,qtimageformats + perl init-repository --module-subset=qtbase,qtimageformats,qtsvg git checkout v5.12.5 git submodule update qtbase git submodule update qtimageformats + git submodule update qtsvg cd qtbase git apply ../../patches/qtbase_5_12_5.diff cd src/plugins/platforminputcontexts