Remove unneeded TrayIconFileTemplate function

Use /.flatpak-info instead of deprecated /run/user/$UID/flatpak-info

Improve indentation in UseXDGDesktopPortal and IsAppIndicator

Remove unneeded NeedTrayIconFile and rename IsAppIndicator to IsIndicatorApplication

Include only needed part of QtDBus in main_window_linux.cpp

Remove usage of QDBusInterface from SandboxAutostart and IsSNIAvailable

Don't check dbus activatable services in IsIndicatorApplication

Move XEmbed menu initialization to initTrayMenuHook, tray availability check to initHook

Don't create unneeded file for tooltip icon, since indicator-application doesn't support tooltips

Passthrough counter from updateIconCounters

Suppress log errors for LastUserInputTime on GNOME

Set applcation name and icon name for pulseaudio
This commit is contained in:
Ilya Fedin 2020-03-03 05:24:13 +04:00 committed by John Preston
parent 5c89dfad85
commit 7202ffca76
3 changed files with 118 additions and 93 deletions

View File

@ -24,7 +24,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QSize>
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <QtDBus>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#include <QtDBus/QDBusMetaType>
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
namespace Platform {
@ -35,6 +41,7 @@ constexpr auto kPanelTrayIconName = "telegram-panel"_cs;
constexpr auto kMutePanelTrayIconName = "telegram-mute-panel"_cs;
constexpr auto kAttentionPanelTrayIconName = "telegram-attention-panel"_cs;
constexpr auto kSNIWatcherService = "org.kde.StatusNotifierWatcher"_cs;
constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
constexpr auto kTrayIconFilename = "tdesktop-trayicon-XXXXXX.png"_cs;
bool TrayIconMuted = true;
@ -43,10 +50,7 @@ base::flat_map<int, QImage> TrayIconImageBack;
QIcon TrayIcon;
QString TrayIconThemeName, TrayIconName;
QString GetPanelIconName() {
const auto counter = Core::App().unreadBadge();
const auto muted = Core::App().unreadBadgeMuted();
QString GetPanelIconName(int counter, bool muted) {
return (counter > 0)
? (muted
? kMutePanelTrayIconName.utf16()
@ -54,9 +58,9 @@ QString GetPanelIconName() {
: kPanelTrayIconName.utf16();
}
QString GetTrayIconName() {
QString GetTrayIconName(int counter, bool muted) {
const auto iconName = GetIconName();
const auto panelIconName = GetPanelIconName();
const auto panelIconName = GetPanelIconName(counter, muted);
if (QIcon::hasThemeIcon(panelIconName)) {
return panelIconName;
@ -67,9 +71,9 @@ QString GetTrayIconName() {
return QString();
}
QIcon TrayIconGen() {
QIcon TrayIconGen(int counter, bool muted) {
const auto iconThemeName = QIcon::themeName();
const auto iconName = GetTrayIconName();
const auto iconName = GetTrayIconName(counter, muted);
if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8())
&& !iconName.isEmpty()) {
@ -84,8 +88,6 @@ QIcon TrayIconGen() {
return TrayIcon;
}
const auto counter = Core::App().unreadBadge();
const auto muted = Core::App().unreadBadgeMuted();
const auto counterSlice = (counter >= 1000)
? (1000 + (counter % 100))
: counter;
@ -196,47 +198,40 @@ QIcon TrayIconGen() {
return TrayIcon;
}
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() {
bool IsIndicatorApplication() {
// 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 = IsAppIndicator();
return TrayIconFileNeeded;
}
static const auto IndicatorApplication = [&] {
const auto interface = QDBusConnection::sessionBus().interface();
static inline QString TrayIconFileTemplate() {
static const auto TempFileTemplate = AppRuntimeDirectory()
+ kTrayIconFilename.utf16();
return TempFileTemplate;
const auto ubuntuIndicator = interface->isServiceRegistered(
qsl("com.canonical.indicator.application"));
const auto ayatanaIndicator = interface->isServiceRegistered(
qsl("org.ayatana.indicator.application"));
return ubuntuIndicator || ayatanaIndicator;
}();
return IndicatorApplication;
}
std::unique_ptr<QTemporaryFile> TrayIconFile(
const QIcon &icon,
int size,
QObject *parent) {
static const auto templateName = AppRuntimeDirectory()
+ kTrayIconFilename.utf16();
auto ret = std::make_unique<QTemporaryFile>(
TrayIconFileTemplate(),
templateName,
parent);
ret->open();
icon.pixmap(size).save(ret.get());
ret->close();
return ret;
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
@ -244,15 +239,25 @@ std::unique_ptr<QTemporaryFile> TrayIconFile(
bool IsSNIAvailable() {
static const auto SNIAvailable = [&] {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
QDBusInterface systrayHost(
auto message = QDBusMessage::createMethodCall(
kSNIWatcherService.utf16(),
qsl("/StatusNotifierWatcher"),
kSNIWatcherService.utf16());
kPropertiesInterface.utf16(),
qsl("Get"));
return systrayHost.isValid()
&& systrayHost
.property("IsStatusNotifierHostRegistered")
.toBool();
message.setArguments({
kSNIWatcherService.utf16(),
qsl("IsStatusNotifierHostRegistered")
});
const QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call(
message);
if (reply.isValid()) {
return reply.value().toBool();
} else if (reply.error().type() != QDBusError::ServiceUnknown) {
LOG(("SNI Error: %1").arg(reply.error().message()));
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return false;
@ -288,6 +293,20 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
: Window::MainWindow(controller) {
}
void MainWindow::initHook() {
const auto trayAvailable = IsSNIAvailable()
|| QSystemTrayIcon::isSystemTrayAvailable();
LOG(("System tray available: %1").arg(Logs::b(trayAvailable)));
cSetSupportTray(trayAvailable);
if (UseUnityCounter()) {
LOG(("Using Unity launcher counter."));
} else {
LOG(("Not using Unity launcher counter."));
}
}
bool MainWindow::hasTrayIcon() const {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
return trayIcon || _sniTrayIcon;
@ -313,23 +332,23 @@ void MainWindow::psTrayMenuUpdated() {
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
void MainWindow::setSNITrayIcon(const QIcon &icon) {
const auto iconName = GetTrayIconName();
void MainWindow::setSNITrayIcon(int counter, bool muted) {
const auto iconName = GetTrayIconName(counter, muted);
if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8())
&& !iconName.isEmpty()) {
_sniTrayIcon->setIconByName(iconName);
_sniTrayIcon->setToolTipIconByName(iconName);
} else if (NeedTrayIconFile()) {
} else if (IsIndicatorApplication()) {
const auto icon = TrayIconGen(counter, muted);
_trayIconFile = TrayIconFile(icon, 22, this);
_trayToolTipIconFile = TrayIconFile(icon, 48, this);
if (_trayIconFile) {
// indicator-application doesn't support tooltips
_sniTrayIcon->setIconByName(_trayIconFile->fileName());
_sniTrayIcon->setToolTipIconByName(
_trayToolTipIconFile->fileName());
}
} else {
const auto icon = TrayIconGen(counter, muted);
_sniTrayIcon->setIconByPixmap(icon);
_sniTrayIcon->setToolTipIconByPixmap(icon);
}
@ -358,6 +377,9 @@ void MainWindow::attachToSNITrayIcon() {
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
void MainWindow::psSetupTrayIcon() {
const auto counter = Core::App().unreadBadge();
const auto muted = Core::App().unreadBadgeMuted();
if (IsSNIAvailable()) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
LOG(("Using SNI tray icon."));
@ -367,7 +389,7 @@ void MainWindow::psSetupTrayIcon() {
this);
_sniTrayIcon->setTitle(AppName.utf16());
setSNITrayIcon(TrayIconGen());
setSNITrayIcon(counter, muted);
attachToSNITrayIcon();
}
@ -375,15 +397,9 @@ void MainWindow::psSetupTrayIcon() {
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
} else {
LOG(("Using Qt tray icon."));
if (!_trayIconMenuXEmbed) {
_trayIconMenuXEmbed = new Ui::PopupMenu(nullptr, trayIconMenu);
_trayIconMenuXEmbed->deleteOnHide(false);
}
if (!trayIcon) {
trayIcon = new QSystemTrayIcon(this);
trayIcon->setIcon(TrayIconGen());
trayIcon->setIcon(TrayIconGen(counter, muted));
attachToTrayIcon(trayIcon);
}
@ -423,11 +439,13 @@ void MainWindow::unreadCounterChangedHook() {
}
void MainWindow::updateIconCounters() {
const auto counter = Core::App().unreadBadge();
const auto muted = Core::App().unreadBadgeMuted();
updateWindowIcon();
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
if (UseUnityCounter()) {
const auto counter = Core::App().unreadBadge();
const auto launcherUrl = "application://" + GetLauncherFilename();
QVariantMap dbusUnityProperties;
if (counter > 0) {
@ -455,11 +473,11 @@ void MainWindow::updateIconCounters() {
if (IsSNIAvailable()) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
if (_sniTrayIcon) {
setSNITrayIcon(TrayIconGen());
setSNITrayIcon(counter, muted);
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
} else if (trayIcon) {
trayIcon->setIcon(TrayIconGen());
trayIcon->setIcon(TrayIconGen(counter, muted));
}
}
@ -472,16 +490,9 @@ void MainWindow::LibsLoaded() {
}
void MainWindow::initTrayMenuHook() {
const auto trayAvailable = IsSNIAvailable()
|| QSystemTrayIcon::isSystemTrayAvailable();
LOG(("System tray available: %1").arg(Logs::b(trayAvailable)));
cSetSupportTray(trayAvailable);
if (UseUnityCounter()) {
LOG(("Using Unity launcher counter."));
} else {
LOG(("Not using Unity launcher counter."));
if (!IsSNIAvailable()) {
_trayIconMenuXEmbed = new Ui::PopupMenu(nullptr, trayIconMenu);
_trayIconMenuXEmbed->deleteOnHide(false);
}
}

View File

@ -39,6 +39,7 @@ public slots:
void psShowTrayMenu();
protected:
void initHook() override;
void unreadCounterChangedHook() override;
void initTrayMenuHook() override;
@ -68,9 +69,8 @@ private:
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
StatusNotifierItem *_sniTrayIcon = nullptr;
std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr;
std::unique_ptr<QTemporaryFile> _trayToolTipIconFile = nullptr;
void setSNITrayIcon(const QIcon &icon);
void setSNITrayIcon(int counter, bool muted);
void attachToSNITrayIcon();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION

View File

@ -30,7 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <sys/stat.h>
#include <sys/types.h>
@ -61,23 +61,29 @@ void SandboxAutostart(bool autostart, bool silent = false) {
});
options["dbus-activatable"] = false;
const auto requestBackgroundReply = QDBusInterface(
auto message = QDBusMessage::createMethodCall(
qsl("org.freedesktop.portal.Desktop"),
qsl("/org/freedesktop/portal/desktop"),
qsl("org.freedesktop.portal.Background")
).call(qsl("RequestBackground"), QString(), options);
qsl("org.freedesktop.portal.Background"),
qsl("RequestBackground"));
if (!silent) {
if (requestBackgroundReply.type() == QDBusMessage::ErrorMessage) {
LOG(("Flatpak autostart error: %1")
.arg(requestBackgroundReply.errorMessage()));
} else if (requestBackgroundReply.type()
!= QDBusMessage::ReplyMessage) {
LOG(("Flatpak autostart error: invalid reply"));
message.setArguments({
QString(),
options
});
if (silent) {
QDBusConnection::sessionBus().send(message);
} else {
const QDBusReply<void> reply = QDBusConnection::sessionBus().call(
message);
if (!reply.isValid()) {
LOG(("Flatpak autostart error: %1").arg(reply.error().message()));
}
}
}
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
bool RunShellCommand(const QByteArray &command) {
auto result = system(command.constData());
@ -168,7 +174,7 @@ bool GenerateDesktopFile(
QRegularExpression::MultilineOption),
qsl("Exec=\\1")
+ (args.isEmpty() ? QString() : ' ' + args));
#else
#else // DESKTOP_APP_USE_PACKAGED
fileText = fileText.replace(
QRegularExpression(
qsl("^TryExec=.*$"),
@ -184,7 +190,7 @@ bool GenerateDesktopFile(
+ EscapeShell(QFile::encodeName(cExeDir() + cExeName()))
.replace('\\', qsl("\\\\"))
+ (args.isEmpty() ? QString() : ' ' + args));
#endif
#endif // !DESKTOP_APP_USE_PACKAGED
target.write(fileText.toUtf8());
target.close();
@ -209,9 +215,7 @@ void SetApplicationIcon(const QIcon &icon) {
}
bool InSandbox() {
static const auto Sandbox = QFileInfo::exists(
QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)
+ qsl("/flatpak-info"));
static const auto Sandbox = QFileInfo::exists(qsl("/.flatpak-info"));
return Sandbox;
}
@ -228,12 +232,18 @@ bool IsXDGDesktopPortalPresent() {
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop").isValid();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return XDGDesktopPortalPresent;
}
bool UseXDGDesktopPortal() {
static const auto UsePortal = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL")
&& IsXDGDesktopPortalPresent();
static const auto UsePortal = [&] {
const auto envVar = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL");
const auto portalPresent = IsXDGDesktopPortalPresent();
return envVar && portalPresent;
}();
return UsePortal;
}
@ -360,7 +370,8 @@ std::optional<crl::time> LastUserInputTime() {
if (reply.isValid()) {
return (crl::now() - static_cast<crl::time>(reply.value()));
} else if (reply.error().type() != QDBusError::ServiceUnknown) {
} else if (reply.error().type() != QDBusError::ServiceUnknown
&& reply.error().type() != QDBusError::NotSupported) {
LOG(("Unable to get last user input time: %1: %2")
.arg(reply.error().name())
.arg(reply.error().message()));
@ -488,6 +499,9 @@ void start() {
LOG(("Launcher filename: %1").arg(GetLauncherFilename()));
FallbackFontConfig();
qputenv("PULSE_PROP_application.name", AppName.utf8());
qputenv("PULSE_PROP_application.icon_name", GetIconName().toLatin1());
#ifdef TDESKTOP_FORCE_GTK_FILE_DIALOG
LOG(("Checking for XDG Desktop Portal..."));
// this can give us a chance to use a proper file dialog for current session
@ -622,7 +636,7 @@ void psAutoStart(bool start, bool silent) {
if (InSandbox()) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
SandboxAutostart(start, silent);
#endif
#endif // !DESKTOP_APP_USE_PACKAGED
} else {
const auto autostart = [&] {
if (InSnap()) {