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
This commit is contained in:
Ilya Fedin 2020-02-06 15:34:28 +04:00 committed by John Preston
parent 9e3fa2e4bc
commit 6206b6f843
9 changed files with 98 additions and 57 deletions

View File

@ -31,7 +31,7 @@ jobs:
CMAKE_VER: "3.16.3" CMAKE_VER: "3.16.3"
UPLOAD_ARTIFACT: "false" UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false" ONLY_CACHE: "false"
MANUAL_CACHING: "2" MANUAL_CACHING: "3"
DOC_PATH: "docs/building-cmake.md" DOC_PATH: "docs/building-cmake.md"
steps: steps:
@ -364,10 +364,11 @@ jobs:
git clone git://code.qt.io/qt/qt5.git qt_$QT git clone git://code.qt.io/qt/qt5.git qt_$QT
cd 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 checkout v5.12.5
git submodule update qtbase git submodule update qtbase
git submodule update qtimageformats git submodule update qtimageformats
git submodule update qtsvg
cd qtbase cd qtbase
git apply ../../patches/qtbase_$QT.diff git apply ../../patches/qtbase_$QT.diff
cd src/plugins/platforminputcontexts cd src/plugins/platforminputcontexts

View File

@ -556,8 +556,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *e) {
void MainWindow::updateTrayMenu(bool force) { void MainWindow::updateTrayMenu(bool force) {
if (!trayIconMenu || (Platform::IsWindows() && !force)) return; if (!trayIconMenu || (Platform::IsWindows() && !force)) return;
auto iconMenu = trayIconMenu; auto actions = trayIconMenu->actions();
auto actions = iconMenu->actions();
if (Platform::IsLinux()) { if (Platform::IsLinux()) {
auto minimizeAction = actions.at(1); auto minimizeAction = actions.at(1);
minimizeAction->setEnabled(isVisible()); minimizeAction->setEnabled(isVisible());
@ -571,12 +570,6 @@ void MainWindow::updateTrayMenu(bool force) {
toggleAction->setText(active toggleAction->setText(active
? tr::lng_minimize_to_tray(tr::now) ? tr::lng_minimize_to_tray(tr::now)
: tr::lng_open_from_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 notificationAction = actions.at(Platform::IsLinux() ? 2 : 1);
auto notificationActionText = Global::DesktopNotify() auto notificationActionText = Global::DesktopNotify()

View File

@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "facades.h" #include "facades.h"
#include "app.h" #include "app.h"
#include <QtCore/QSize>
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <QtDBus> #include <QtDBus>
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
@ -73,33 +75,49 @@ QImage TrayIconImageGen() {
const auto iconThemeName = QIcon::themeName(); const auto iconThemeName = QIcon::themeName();
const auto iconName = GetTrayIconName(); const auto iconName = GetTrayIconName();
const auto desiredSize = QSize(_trayIconSize, _trayIconSize);
if (_trayIconImage.isNull() if (_trayIconImage.isNull()
|| _trayIconImage.width() != _trayIconSize || _trayIconImage.size() != desiredSize
|| iconThemeName != _trayIconThemeName || iconThemeName != _trayIconThemeName
|| iconName != _trayIconName || iconName != _trayIconName
|| muted != _trayIconMuted || muted != _trayIconMuted
|| counterSlice != _trayIconCount) { || counterSlice != _trayIconCount) {
if (_trayIconImageBack.isNull() if (_trayIconImageBack.isNull()
|| _trayIconImageBack.width() != _trayIconSize || _trayIconImageBack.size() != desiredSize
|| iconThemeName != _trayIconThemeName || iconThemeName != _trayIconThemeName
|| iconName != _trayIconName) { || iconName != _trayIconName) {
_trayIconImageBack = Core::App().logo(); const auto hasPanelIcon = QIcon::hasThemeIcon(iconName);
_trayIconImageBack = QIcon::fromTheme( if (hasPanelIcon || QIcon::hasThemeIcon(kTrayIconName.utf16())) {
iconName, QIcon systemIcon;
QIcon::fromTheme(
kTrayIconName.utf16(),
QIcon(QPixmap::fromImage(_trayIconImageBack)))
).pixmap(_trayIconSize, _trayIconSize).toImage();
auto w = _trayIconImageBack.width(), if (hasPanelIcon) {
h = _trayIconImageBack.height(); 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( _trayIconImageBack = _trayIconImageBack.scaled(
_trayIconSize, desiredSize,
_trayIconSize,
Qt::IgnoreAspectRatio, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation); Qt::SmoothTransformation);
} }
@ -107,8 +125,8 @@ QImage TrayIconImageGen() {
_trayIconImageBack = _trayIconImageBack.convertToFormat( _trayIconImageBack = _trayIconImageBack.convertToFormat(
QImage::Format_ARGB32); QImage::Format_ARGB32);
w = _trayIconImageBack.width(); const auto w = _trayIconImageBack.width();
h = _trayIconImageBack.height(); const auto h = _trayIconImageBack.height();
const auto perline = _trayIconImageBack.bytesPerLine(); const auto perline = _trayIconImageBack.bytesPerLine();
auto *bytes = _trayIconImageBack.bits(); auto *bytes = _trayIconImageBack.bits();
@ -166,26 +184,31 @@ QImage TrayIconImageGen() {
return _trayIconImage; 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 #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
static bool NeedTrayIconFile() { static bool NeedTrayIconFile() {
// Hack for indicator-application, which doesn't handle icons sent across D-Bus: // 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. // save the icon to a temp file and set the icon name to that filename.
static const auto TrayIconFileNeeded = [&] { static const auto TrayIconFileNeeded = IsAppIndicator()
auto necessary = false; // Ubuntu's tray extension doesn't zoom image data, but zooms image file
const auto session = QDBusConnection::sessionBus(); || DesktopEnvironment::IsGnome();
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;
}();
return TrayIconFileNeeded; return TrayIconFileNeeded;
} }
@ -196,7 +219,7 @@ static inline QString TrayIconFileTemplate() {
} }
std::unique_ptr<QTemporaryFile> TrayIconFile( std::unique_ptr<QTemporaryFile> TrayIconFile(
const QPixmap &icon, QObject *parent) { const QImage &icon, QObject *parent) {
auto ret = std::make_unique<QTemporaryFile>( auto ret = std::make_unique<QTemporaryFile>(
TrayIconFileTemplate(), TrayIconFileTemplate(),
parent); parent);
@ -268,7 +291,7 @@ void MainWindow::psTrayMenuUpdated() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
void MainWindow::setSNITrayIcon( void MainWindow::setSNITrayIcon(
const QIcon &icon, const QPixmap &iconPixmap) { const QIcon &icon, const QImage &iconImage) {
if (!NeedTrayIconFile()) { if (!NeedTrayIconFile()) {
_sniTrayIcon->setIconByPixmap(icon); _sniTrayIcon->setIconByPixmap(icon);
_sniTrayIcon->setToolTipIconByPixmap(icon); _sniTrayIcon->setToolTipIconByPixmap(icon);
@ -279,7 +302,7 @@ void MainWindow::setSNITrayIcon(
_sniTrayIcon->setIconByName(iconName); _sniTrayIcon->setIconByName(iconName);
_sniTrayIcon->setToolTipIconByName(iconName); _sniTrayIcon->setToolTipIconByName(iconName);
} else if (NeedTrayIconFile()) { } else if (NeedTrayIconFile()) {
_trayIconFile = TrayIconFile(iconPixmap, this); _trayIconFile = TrayIconFile(iconImage, this);
if (_trayIconFile) { if (_trayIconFile) {
_sniTrayIcon->setIconByName(_trayIconFile->fileName()); _sniTrayIcon->setIconByName(_trayIconFile->fileName());
@ -311,8 +334,8 @@ void MainWindow::attachToSNITrayIcon() {
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
void MainWindow::psSetupTrayIcon() { void MainWindow::psSetupTrayIcon() {
const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen()); const auto iconImage = TrayIconImageGen();
const auto icon = QIcon(iconPixmap); const auto icon = QIcon(QPixmap::fromImage(iconImage));
if (IsSNIAvailable()) { if (IsSNIAvailable()) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
@ -322,8 +345,8 @@ void MainWindow::psSetupTrayIcon() {
QCoreApplication::applicationName(), QCoreApplication::applicationName(),
this); this);
_sniTrayIcon->setTitle(QCoreApplication::applicationName()); _sniTrayIcon->setTitle(AppName.utf16());
setSNITrayIcon(icon, iconPixmap); setSNITrayIcon(icon, iconImage);
attachToSNITrayIcon(); attachToSNITrayIcon();
} }
@ -406,13 +429,13 @@ void MainWindow::updateIconCounters() {
} }
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen()); const auto iconImage = TrayIconImageGen();
const auto icon = QIcon(iconPixmap); const auto icon = QIcon(QPixmap::fromImage(iconImage));
if (IsSNIAvailable()) { if (IsSNIAvailable()) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
if (_sniTrayIcon) { if (_sniTrayIcon) {
setSNITrayIcon(icon, iconPixmap); setSNITrayIcon(icon, iconImage);
} }
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
} else if (trayIcon) { } else if (trayIcon) {
@ -427,7 +450,7 @@ void MainWindow::LibsLoaded() {
qDBusRegisterMetaType<IconPixmapList>(); qDBusRegisterMetaType<IconPixmapList>();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
if (!IsSNIAvailable()) { if (!IsSNIAvailable() || IsAppIndicator()) {
_trayIconSize = 22; _trayIconSize = 22;
} }
} }

View File

@ -70,7 +70,7 @@ private:
StatusNotifierItem *_sniTrayIcon = nullptr; StatusNotifierItem *_sniTrayIcon = nullptr;
std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr; std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr;
void setSNITrayIcon(const QIcon &icon, const QPixmap &iconPixmap); void setSNITrayIcon(const QIcon &icon, const QImage &iconImage);
void attachToSNITrayIcon(); void attachToSNITrayIcon();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION #endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION

View File

@ -548,8 +548,15 @@ void MainWindow::psShowTrayMenu() {
} }
void MainWindow::psTrayMenuUpdated() { void MainWindow::psTrayMenuUpdated() {
if (trayIcon && trayIconMenu && trayIcon->contextMenu() != trayIconMenu) { // On macOS just remove trayIcon menu if the window is not active.
trayIcon->setContextMenu(trayIconMenu); // 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);
} }
} }

View File

@ -23,6 +23,7 @@ Q_IMPORT_PLUGIN(QGenericEnginePlugin)
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
Q_IMPORT_PLUGIN(QGenericEnginePlugin) Q_IMPORT_PLUGIN(QGenericEnginePlugin)
Q_IMPORT_PLUGIN(QComposePlatformInputContextPlugin) Q_IMPORT_PLUGIN(QComposePlatformInputContextPlugin)
Q_IMPORT_PLUGIN(QSvgIconPlugin)
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
Q_IMPORT_PLUGIN(QConnmanEnginePlugin) Q_IMPORT_PLUGIN(QConnmanEnginePlugin)
Q_IMPORT_PLUGIN(QNetworkManagerEnginePlugin) Q_IMPORT_PLUGIN(QNetworkManagerEnginePlugin)

View File

@ -42,6 +42,7 @@ StatusNotifierItem::StatusNotifierItem(QString id, QObject *parent)
mId(id), mId(id),
mTitle(QLatin1String("Test")), mTitle(QLatin1String("Test")),
mStatus(QLatin1String("Active")), mStatus(QLatin1String("Active")),
mCategory(QLatin1String("ApplicationStatus")),
mMenu(nullptr), mMenu(nullptr),
mMenuPath(QLatin1String("/NO_DBUSMENU")), mMenuPath(QLatin1String("/NO_DBUSMENU")),
mMenuExporter(nullptr), mMenuExporter(nullptr),
@ -116,6 +117,14 @@ void StatusNotifierItem::setStatus(const QString &status)
Q_EMIT mAdaptor->NewStatus(mStatus); Q_EMIT mAdaptor->NewStatus(mStatus);
} }
void StatusNotifierItem::setCategory(const QString &category)
{
if (mCategory == category)
return;
mCategory = category;
}
void StatusNotifierItem::setMenuPath(const QString& path) void StatusNotifierItem::setMenuPath(const QString& path)
{ {
mMenuPath.setPath(path); mMenuPath.setPath(path);

View File

@ -43,6 +43,7 @@ class StatusNotifierItem : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString Category READ category)
Q_PROPERTY(QString Title READ title) Q_PROPERTY(QString Title READ title)
Q_PROPERTY(QString Id READ id) Q_PROPERTY(QString Id READ id)
Q_PROPERTY(QString Status READ status) Q_PROPERTY(QString Status READ status)
@ -74,6 +75,10 @@ public:
{ return mStatus; } { return mStatus; }
void setStatus(const QString &status); void setStatus(const QString &status);
QString category() const
{ return mCategory; }
void setCategory(const QString &category);
QDBusObjectPath menu() const QDBusObjectPath menu() const
{ return mMenuPath; } { return mMenuPath; }
void setMenuPath(const QString &path); void setMenuPath(const QString &path);
@ -162,6 +167,7 @@ private:
QString mId; QString mId;
QString mTitle; QString mTitle;
QString mStatus; QString mStatus;
QString mCategory;
// icons // icons
QString mIconName, mOverlayIconName, mAttentionIconName; QString mIconName, mOverlayIconName, mAttentionIconName;

View File

@ -235,10 +235,11 @@ Go to ***BuildPath*** and run
git clone git://code.qt.io/qt/qt5.git qt_5_12_5 git clone git://code.qt.io/qt/qt5.git qt_5_12_5
cd 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 checkout v5.12.5
git submodule update qtbase git submodule update qtbase
git submodule update qtimageformats git submodule update qtimageformats
git submodule update qtsvg
cd qtbase cd qtbase
git apply ../../patches/qtbase_5_12_5.diff git apply ../../patches/qtbase_5_12_5.diff
cd src/plugins/platforminputcontexts cd src/plugins/platforminputcontexts