Move remaining usage of dbus to glibmm in main_window_linux

This commit is contained in:
Ilya Fedin 2021-03-02 08:01:04 +04:00 committed by John Preston
parent a2f8546033
commit b08c33cf8a
2 changed files with 123 additions and 92 deletions

View file

@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "app.h" #include "app.h"
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include "base/platform/linux/base_linux_glibmm_helper.h"
#include "base/platform/linux/base_linux_dbus_utilities.h" #include "base/platform/linux/base_linux_dbus_utilities.h"
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
@ -43,12 +44,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QWindow> #include <QtGui/QWindow>
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection> #include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusServiceWatcher>
#include <QtDBus/QDBusMessage> #include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#include <QtDBus/QDBusObjectPath> #include <QtDBus/QDBusObjectPath>
#include <QtDBus/QDBusMetaType> #include <QtDBus/QDBusMetaType>
@ -414,50 +411,65 @@ std::unique_ptr<QTemporaryFile> TrayIconFile(
} }
bool UseUnityCounter() { bool UseUnityCounter() {
static const auto Result = QDBusInterface( static const auto Result = [&] {
"com.canonical.Unity", try {
"/").isValid(); const auto connection = Gio::DBus::Connection::get_sync(
Gio::DBus::BusType::BUS_TYPE_SESSION);
return base::Platform::DBus::NameHasOwner(
connection,
"com.canonical.Unity");
} catch (...) {
}
return false;
}();
return Result; return Result;
} }
bool IsSNIAvailable() { bool IsSNIAvailable() {
auto message = QDBusMessage::createMethodCall( try {
kSNIWatcherService.utf16(), const auto connection = Gio::DBus::Connection::get_sync(
kSNIWatcherObjectPath.utf16(), Gio::DBus::BusType::BUS_TYPE_SESSION);
kPropertiesInterface.utf16(),
qsl("Get"));
message.setArguments({ auto reply = connection->call_sync(
kSNIWatcherInterface.utf16(), std::string(kSNIWatcherObjectPath),
qsl("IsStatusNotifierHostRegistered") std::string(kPropertiesInterface),
}); "Get",
base::Platform::MakeGlibVariant(std::tuple{
Glib::ustring(std::string(kSNIWatcherInterface)),
Glib::ustring("IsStatusNotifierHostRegistered"),
}),
std::string(kSNIWatcherService));
const QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call( return base::Platform::GlibVariantCast<bool>(
message); base::Platform::GlibVariantCast<Glib::VariantBase>(
reply.get_child(0)));
} catch (const Glib::Error &e) {
static const auto NotSupportedErrors = {
"org.freedesktop.DBus.Error.Disconnected",
"org.freedesktop.DBus.Error.ServiceUnknown",
};
if (reply.isValid()) { const auto errorName = Gio::DBus::ErrorUtils::get_remote_error(e);
return reply.value().toBool(); if (ranges::contains(NotSupportedErrors, errorName)) {
return false;
}
LOG(("SNI Error: %1")
.arg(QString::fromStdString(e.what())));
} catch (const std::exception &e) {
LOG(("SNI Error: %1")
.arg(QString::fromStdString(e.what())));
} }
switch (reply.error().type()) {
case QDBusError::Disconnected:
case QDBusError::ServiceUnknown:
return false;
default:
break;
}
LOG(("SNI Error: %1: %2")
.arg(reply.error().name())
.arg(reply.error().message()));
return false; return false;
} }
quint32 djbStringHash(QString string) { uint djbStringHash(const std::string &string) {
quint32 hash = 5381; uint hash = 5381;
QByteArray chars = string.toLatin1(); const auto chars = QByteArray::fromStdString(string.data());
for(int i = 0; i < chars.length(); i++){ for(int i = 0; i < chars.length(); i++){
hash = (hash << 5) + hash + chars[i]; hash = (hash << 5) + hash + chars[i];
} }
@ -478,6 +490,8 @@ bool IsAppMenuSupported() {
return false; return false;
} }
// This call must be made from the same bus connection as DBusMenuExporter
// So it must use QDBusConnection
void RegisterAppMenu(uint winId, const QString &menuPath) { void RegisterAppMenu(uint winId, const QString &menuPath) {
auto message = QDBusMessage::createMethodCall( auto message = QDBusMessage::createMethodCall(
kAppMenuService.utf16(), kAppMenuService.utf16(),
@ -493,6 +507,8 @@ void RegisterAppMenu(uint winId, const QString &menuPath) {
QDBusConnection::sessionBus().send(message); QDBusConnection::sessionBus().send(message);
} }
// This call must be made from the same bus connection as DBusMenuExporter
// So it must use QDBusConnection
void UnregisterAppMenu(uint winId) { void UnregisterAppMenu(uint winId) {
auto message = QDBusMessage::createMethodCall( auto message = QDBusMessage::createMethodCall(
kAppMenuService.utf16(), kAppMenuService.utf16(),
@ -555,6 +571,7 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
void MainWindow::initHook() { void MainWindow::initHook() {
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
_sniAvailable = IsSNIAvailable(); _sniAvailable = IsSNIAvailable();
_appMenuSupported = IsAppMenuSupported();
try { try {
_private->dbusConnection = Gio::DBus::Connection::get_sync( _private->dbusConnection = Gio::DBus::Connection::get_sync(
@ -580,45 +597,35 @@ void MainWindow::initHook() {
std::string(kSNIWatcherInterface), std::string(kSNIWatcherInterface),
"StatusNotifierHostRegistered", "StatusNotifierHostRegistered",
std::string(kSNIWatcherObjectPath)); std::string(kSNIWatcherObjectPath));
_sniWatcherId = base::Platform::DBus::RegisterServiceWatcher(
_private->dbusConnection,
std::string(kSNIWatcherService),
[=](
const Glib::ustring &service,
const Glib::ustring &oldOwner,
const Glib::ustring &newOwner) {
handleSNIOwnerChanged(
QString::fromStdString(service),
QString::fromStdString(oldOwner),
QString::fromStdString(newOwner));
});
_appMenuWatcherId = base::Platform::DBus::RegisterServiceWatcher(
_private->dbusConnection,
std::string(kAppMenuService),
[=](
const Glib::ustring &service,
const Glib::ustring &oldOwner,
const Glib::ustring &newOwner) {
handleAppMenuOwnerChanged(
QString::fromStdString(service),
QString::fromStdString(oldOwner),
QString::fromStdString(newOwner));
});
} catch (...) { } catch (...) {
} }
auto sniWatcher = new QDBusServiceWatcher(
kSNIWatcherService.utf16(),
QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForOwnerChange,
this);
connect(
sniWatcher,
&QDBusServiceWatcher::serviceOwnerChanged,
this,
[=](
const QString &service,
const QString &oldOwner,
const QString &newOwner) {
handleSNIOwnerChanged(service, oldOwner, newOwner);
});
_appMenuSupported = IsAppMenuSupported();
auto appMenuWatcher = new QDBusServiceWatcher(
kAppMenuService.utf16(),
QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForOwnerChange,
this);
connect(
appMenuWatcher,
&QDBusServiceWatcher::serviceOwnerChanged,
this,
[=](
const QString &service,
const QString &oldOwner,
const QString &newOwner) {
handleAppMenuOwnerChanged(service, oldOwner, newOwner);
});
if (_appMenuSupported) { if (_appMenuSupported) {
LOG(("Using D-Bus global menu.")); LOG(("Using D-Bus global menu."));
} else { } else {
@ -866,30 +873,39 @@ void MainWindow::updateIconCounters() {
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (UseUnityCounter()) { if (UseUnityCounter()) {
const auto launcherUrl = "application://" + GetLauncherFilename(); const auto launcherUrl = Glib::ustring(
// Gnome requires that count is a 64bit integer "application://" + GetLauncherFilename().toStdString());
const qint64 counterSlice = std::min(counter, 9999); const auto counterSlice = std::min(counter, 9999);
QVariantMap dbusUnityProperties; std::map<Glib::ustring, Glib::VariantBase> dbusUnityProperties;
if (counterSlice > 0) { if (counterSlice > 0) {
dbusUnityProperties["count"] = counterSlice; // According to the spec, it should be of 'x' D-Bus signature,
dbusUnityProperties["count-visible"] = true; // which corresponds to gint64 (signed long) type with glib
// https://wiki.ubuntu.com/Unity/LauncherAPI#Low_level_DBus_API:_com.canonical.Unity.LauncherEntry
dbusUnityProperties["count"] = Glib::Variant<long>::create(
counterSlice);
dbusUnityProperties["count-visible"] =
Glib::Variant<bool>::create(true);
} else { } else {
dbusUnityProperties["count-visible"] = false; dbusUnityProperties["count-visible"] =
Glib::Variant<bool>::create(false);
} }
auto signal = QDBusMessage::createSignal( try {
"/com/canonical/unity/launcherentry/" if (_private->dbusConnection) {
+ QString::number(djbStringHash(launcherUrl)), _private->dbusConnection->emit_signal(
"com.canonical.Unity.LauncherEntry", "/com/canonical/unity/launcherentry/"
"Update"); + std::to_string(djbStringHash(launcherUrl)),
"com.canonical.Unity.LauncherEntry",
signal.setArguments({ "Update",
launcherUrl, {},
dbusUnityProperties base::Platform::MakeGlibVariant(std::tuple{
}); launcherUrl,
dbusUnityProperties,
QDBusConnection::sessionBus().send(signal); }));
}
} catch (...) {
}
} }
if (_sniTrayIcon) { if (_sniTrayIcon) {
@ -1251,8 +1267,21 @@ void MainWindow::handleVisibleChangedHook(bool visible) {
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (_sniRegisteredSignalId != 0) { if (_private->dbusConnection) {
_private->dbusConnection->signal_unsubscribe(_sniRegisteredSignalId); if (_sniRegisteredSignalId != 0) {
_private->dbusConnection->signal_unsubscribe(
_sniRegisteredSignalId);
}
if (_sniWatcherId != 0) {
_private->dbusConnection->signal_unsubscribe(
_sniWatcherId);
}
if (_appMenuWatcherId != 0) {
_private->dbusConnection->signal_unsubscribe(
_appMenuWatcherId);
}
} }
delete _sniTrayIcon; delete _sniTrayIcon;

View file

@ -80,6 +80,8 @@ private:
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
StatusNotifierItem *_sniTrayIcon = nullptr; StatusNotifierItem *_sniTrayIcon = nullptr;
uint _sniRegisteredSignalId = 0; uint _sniRegisteredSignalId = 0;
uint _sniWatcherId = 0;
uint _appMenuWatcherId = 0;
std::unique_ptr<QTemporaryFile> _trayIconFile; std::unique_ptr<QTemporaryFile> _trayIconFile;
bool _appMenuSupported = false; bool _appMenuSupported = false;