diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index e4df45f5d..085c42eb6 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -73,6 +73,7 @@ PRIVATE if (LINUX) target_link_libraries(Telegram PRIVATE + desktop-app::external_glibmm desktop-app::external_glib ) diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 946a452a1..472faf74d 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -31,7 +31,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/platform_specific.h" #include "platform/platform_file_utilities.h" #include "base/platform/base_platform_info.h" -#include "base/platform/base_platform_file_utilities.h" #include "history/history.h" #include "history/history_item.h" #include "history/view/media/history_view_gif.h" @@ -49,6 +48,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "app.h" #include +#include +#include namespace { @@ -1724,7 +1725,10 @@ bool IsIpRevealingName(const QString &filepath) { return ranges::binary_search( kExtensions, FileExtension(filepath).toLower() - ) || base::Platform::IsNonExtensionMimeFrom(filepath, kMimeTypes); + ) || ranges::binary_search( + kMimeTypes, + QMimeDatabase().mimeTypeForFile(QFileInfo(filepath)).name() + ); } base::binary_guard ReadImageAsync( diff --git a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp index 11d264843..2e34a1e19 100644 --- a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp @@ -16,11 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include -extern "C" { -#undef signals -#include -#define signals public -} // extern "C" +#include +#include using Platform::internal::GtkIntegration; @@ -28,12 +25,15 @@ namespace Platform { namespace File { void UnsafeOpenUrl(const QString &url) { - if (!g_app_info_launch_default_for_uri( - url.toUtf8().constData(), - nullptr, - nullptr)) { - QDesktopServices::openUrl(url); + try { + if (Gio::AppInfo::launch_default_for_uri(url.toStdString())) { + return; + } + } catch (const Glib::Error &e) { + LOG(("App Error: %1").arg(QString::fromStdString(e.what()))); } + + QDesktopServices::openUrl(url); } void UnsafeOpenEmailLink(const QString &email) { @@ -46,27 +46,27 @@ bool UnsafeShowOpenWith(const QString &filepath) { } if (const auto integration = GtkIntegration::Instance()) { - const auto absolutePath = QFileInfo(filepath).absoluteFilePath(); - return integration->showOpenWithDialog(absolutePath); + return integration->showOpenWithDialog(filepath); } return false; } void UnsafeLaunch(const QString &filepath) { - const auto absolutePath = QFileInfo(filepath).absoluteFilePath(); - - if (!g_app_info_launch_default_for_uri( - g_filename_to_uri( - absolutePath.toUtf8().constData(), - nullptr, - nullptr), - nullptr, - nullptr)) { - if (!UnsafeShowOpenWith(filepath)) { - QDesktopServices::openUrl(QUrl::fromLocalFile(filepath)); + try { + if (Gio::AppInfo::launch_default_for_uri( + Glib::filename_to_uri(filepath.toStdString()))) { + return; } + } catch (const Glib::Error &e) { + LOG(("App Error: %1").arg(QString::fromStdString(e.what()))); } + + if (UnsafeShowOpenWith(filepath)) { + return; + } + + QDesktopServices::openUrl(QUrl::fromLocalFile(filepath)); } } // namespace File diff --git a/Telegram/SourceFiles/platform/linux/linux_gdk_helper.cpp b/Telegram/SourceFiles/platform/linux/linux_gdk_helper.cpp index 9a067ec80..cf9c1740d 100644 --- a/Telegram/SourceFiles/platform/linux/linux_gdk_helper.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_gdk_helper.cpp @@ -12,9 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION extern "C" { -#undef signals #include -#define signals public } // extern "C" #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION diff --git a/Telegram/SourceFiles/platform/linux/linux_gdk_helper.h b/Telegram/SourceFiles/platform/linux/linux_gdk_helper.h index 6ddee649b..6ca953689 100644 --- a/Telegram/SourceFiles/platform/linux/linux_gdk_helper.h +++ b/Telegram/SourceFiles/platform/linux/linux_gdk_helper.h @@ -10,10 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class QLibrary; extern "C" { -#undef signals #include #include -#define signals public } // extern "C" namespace Platform { diff --git a/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.cpp b/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.cpp index 6ea0c8d14..4151736de 100644 --- a/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.cpp @@ -9,15 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/sandbox.h" #include "media/player/media_player_instance.h" +#include "base/platform/linux/base_linux_glibmm_helper.h" +#include "base/platform/linux/base_linux_dbus_utilities.h" -#include -#include - -extern "C" { -#undef signals -#include -#define signals public -} // extern "C" +#include +#include namespace Platform { namespace internal { @@ -31,149 +27,137 @@ constexpr auto kMATEObjectPath = "/org/mate/SettingsDaemon/MediaKeys"_cs; constexpr auto kInterface = kService; constexpr auto kMATEInterface = "org.mate.SettingsDaemon.MediaKeys"_cs; -void KeyPressed( - GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) { - gchar *appUtf8; - gchar *keyUtf8; - g_variant_get(parameters, "(ss)", &appUtf8, &keyUtf8); - const auto app = QString::fromUtf8(appUtf8); - const auto key = QString::fromUtf8(keyUtf8); - g_free(keyUtf8); - g_free(appUtf8); - - if (app != QCoreApplication::applicationName()) { - return; - } - - Core::Sandbox::Instance().customEnterFromEventLoop([&] { - if (key == qstr("Play")) { - Media::Player::instance()->playPause(); - } else if (key == qstr("Stop")) { - Media::Player::instance()->stop(); - } else if (key == qstr("Next")) { - Media::Player::instance()->next(); - } else if (key == qstr("Previous")) { - Media::Player::instance()->previous(); - } - }); -} - } // namespace -GSDMediaKeys::GSDMediaKeys() { - GError *error = nullptr; - const auto interface = QDBusConnection::sessionBus().interface(); +class GSDMediaKeys::Private : public sigc::trackable { +public: + Glib::RefPtr dbusConnection; - if (!interface) { - return; + Glib::ustring service; + Glib::ustring objectPath; + Glib::ustring interface; + uint signalId = 0; + bool grabbed = false; + + void keyPressed( + const Glib::RefPtr &connection, + const Glib::ustring &sender_name, + const Glib::ustring &object_path, + const Glib::ustring &interface_name, + const Glib::ustring &signal_name, + const Glib::VariantContainerBase ¶meters); +}; + +void GSDMediaKeys::Private::keyPressed( + const Glib::RefPtr &connection, + const Glib::ustring &sender_name, + const Glib::ustring &object_path, + const Glib::ustring &interface_name, + const Glib::ustring &signal_name, + const Glib::VariantContainerBase ¶meters) { + try { + auto parametersCopy = parameters; + + const auto app = base::Platform::GlibVariantCast( + parametersCopy.get_child(0)); + + const auto key = base::Platform::GlibVariantCast( + parametersCopy.get_child(1)); + + if (app != QCoreApplication::applicationName().toStdString()) { + return; + } + + Core::Sandbox::Instance().customEnterFromEventLoop([&] { + if (key == "Play") { + Media::Player::instance()->playPause(); + } else if (key == "Stop") { + Media::Player::instance()->stop(); + } else if (key == "Next") { + Media::Player::instance()->next(); + } else if (key == "Previous") { + Media::Player::instance()->previous(); + } + }); + } catch (...) { } +} - if (interface->isServiceRegistered(kService.utf16())) { - _service = kService.utf16(); - _objectPath = kObjectPath.utf16(); - _interface = kInterface.utf16(); - } else if (interface->isServiceRegistered(kOldService.utf16())) { - _service = kOldService.utf16(); - _objectPath = kObjectPath.utf16(); - _interface = kInterface.utf16(); - } else if (interface->isServiceRegistered(kMATEService.utf16())) { - _service = kMATEService.utf16(); - _objectPath = kMATEObjectPath.utf16(); - _interface = kMATEInterface.utf16(); - } else { - return; +GSDMediaKeys::GSDMediaKeys() +: _private(std::make_unique()) { + try { + _private->dbusConnection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); + + if (base::Platform::DBus::NameHasOwner( + _private->dbusConnection, + std::string(kService))) { + _private->service = std::string(kService); + _private->objectPath = std::string(kObjectPath); + _private->interface = std::string(kInterface); + } else if (base::Platform::DBus::NameHasOwner( + _private->dbusConnection, + std::string(kOldService))) { + _private->service = std::string(kOldService); + _private->objectPath = std::string(kObjectPath); + _private->interface = std::string(kInterface); + } else if (base::Platform::DBus::NameHasOwner( + _private->dbusConnection, + std::string(kMATEService))) { + _private->service = std::string(kMATEService); + _private->objectPath = std::string(kMATEObjectPath); + _private->interface = std::string(kMATEInterface); + } else { + return; + } + + _private->dbusConnection->call_sync( + _private->objectPath, + _private->interface, + "GrabMediaPlayerKeys", + base::Platform::MakeGlibVariant(std::tuple{ + Glib::ustring( + QCoreApplication::applicationName() + .toStdString()), + uint(0), + }), + _private->service); + + _private->grabbed = true; + + _private->signalId = _private->dbusConnection->signal_subscribe( + sigc::mem_fun(_private.get(), &Private::keyPressed), + _private->service, + _private->interface, + "MediaPlayerKeyPressed", + _private->objectPath); + } catch (...) { } - - _dbusConnection = g_bus_get_sync( - G_BUS_TYPE_SESSION, - nullptr, - &error); - - if (error) { - LOG(("GSD Media Keys Error: %1").arg(error->message)); - g_error_free(error); - return; - } - - auto reply = g_dbus_connection_call_sync( - _dbusConnection, - _service.toUtf8().constData(), - _objectPath.toUtf8().constData(), - _interface.toUtf8().constData(), - "GrabMediaPlayerKeys", - g_variant_new( - "(su)", - QCoreApplication::applicationName().toUtf8().constData(), - 0), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); - - if (!error) { - _grabbed = true; - g_variant_unref(reply); - } else { - LOG(("GSD Media Keys Error: %1").arg(error->message)); - g_error_free(error); - } - - _signalId = g_dbus_connection_signal_subscribe( - _dbusConnection, - _service.toUtf8().constData(), - _interface.toUtf8().constData(), - "MediaPlayerKeyPressed", - _objectPath.toUtf8().constData(), - nullptr, - G_DBUS_SIGNAL_FLAGS_NONE, - KeyPressed, - nullptr, - nullptr); } GSDMediaKeys::~GSDMediaKeys() { - GError *error = nullptr; - - if (_signalId != 0) { - g_dbus_connection_signal_unsubscribe( - _dbusConnection, - _signalId); - } - - if (_grabbed) { - auto reply = g_dbus_connection_call_sync( - _dbusConnection, - _service.toUtf8().constData(), - _objectPath.toUtf8().constData(), - _interface.toUtf8().constData(), - "ReleaseMediaPlayerKeys", - g_variant_new( - "(s)", - QCoreApplication::applicationName().toUtf8().constData()), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - &error); - - if (!error) { - _grabbed = false; - g_variant_unref(reply); - } else { - LOG(("GSD Media Keys Error: %1").arg(error->message)); - g_error_free(error); + if (_private->dbusConnection) { + if (_private->signalId != 0) { + _private->dbusConnection->signal_unsubscribe(_private->signalId); } - } - if (_dbusConnection) { - g_object_unref(_dbusConnection); + if (_private->grabbed) { + try { + _private->dbusConnection->call_sync( + _private->objectPath, + _private->interface, + "ReleaseMediaPlayerKeys", + base::Platform::MakeGlibVariant(std::tuple{ + Glib::ustring( + QCoreApplication::applicationName() + .toStdString()) + }), + _private->service); + + _private->grabbed = false; + } catch (...) { + } + } } } diff --git a/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.h b/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.h index f3a87ba81..10b854d6e 100644 --- a/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.h +++ b/Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.h @@ -7,8 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -typedef struct _GDBusConnection GDBusConnection; - namespace Platform { namespace internal { @@ -24,12 +22,8 @@ public: ~GSDMediaKeys(); private: - GDBusConnection *_dbusConnection = nullptr; - QString _service; - QString _objectPath; - QString _interface; - uint _signalId = 0; - bool _grabbed = false; + class Private; + const std::unique_ptr _private; }; } // namespace internal diff --git a/Telegram/SourceFiles/platform/linux/linux_gtk_integration_p.h b/Telegram/SourceFiles/platform/linux/linux_gtk_integration_p.h index d2c9e9207..66ace0eb3 100644 --- a/Telegram/SourceFiles/platform/linux/linux_gtk_integration_p.h +++ b/Telegram/SourceFiles/platform/linux/linux_gtk_integration_p.h @@ -8,10 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once extern "C" { -#undef signals #include #include -#define signals public } // extern "C" // To be able to compile with gtk-2.0 headers as well diff --git a/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp b/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp index 3198eed94..ae7953bc6 100644 --- a/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp @@ -10,16 +10,39 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "main/main_domain.h" #include "window/notifications_manager.h" -#include "platform/linux/specific_linux.h" +#include "base/platform/linux/base_linux_dbus_utilities.h" #include namespace Platform { namespace internal { +namespace { + +constexpr auto kNotificationService = "org.freedesktop.Notifications"_cs; + +bool IsNotificationServiceActivatable() { + static const auto Result = [] { + try { + const auto connection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); + + return ranges::contains( + base::Platform::DBus::ListActivatableNames(connection), + Glib::ustring(std::string(kNotificationService))); + } catch (...) { + } + + return false; + }(); + + return Result; +} + +} // namespace NotificationServiceWatcher::NotificationServiceWatcher() : _dbusWatcher( - qsl("org.freedesktop.Notifications"), + kNotificationService.utf16(), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange) { const auto signal = &QDBusServiceWatcher::serviceOwnerChanged; diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 9028a936a..879ea90ee 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -30,6 +30,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "facades.h" #include "app.h" +#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION +#include "base/platform/linux/base_linux_dbus_utilities.h" +#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION + #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION #include "base/platform/linux/base_linux_xcb_utilities.h" #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION @@ -41,7 +45,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #include #include -#include #include #include #include @@ -52,11 +55,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include -extern "C" { -#undef signals -#include -#define signals public -} // extern "C" +#include +#include #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION namespace Platform { @@ -337,19 +337,23 @@ bool IsIndicatorApplication() { // save the icon to a temp file // and set the icon name to that filename. static const auto Result = [] { - const auto interface = QDBusConnection::sessionBus().interface(); + try { + const auto connection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); - if (!interface) { - return false; + const auto ubuntuIndicator = base::Platform::DBus::NameHasOwner( + connection, + "com.canonical.indicator.application"); + + const auto ayatanaIndicator = base::Platform::DBus::NameHasOwner( + connection, + "org.ayatana.indicator.application"); + + return ubuntuIndicator || ayatanaIndicator; + } catch (...) { } - const auto ubuntuIndicator = interface->isServiceRegistered( - qsl("com.canonical.indicator.application")); - - const auto ayatanaIndicator = interface->isServiceRegistered( - qsl("org.ayatana.indicator.application")); - - return ubuntuIndicator || ayatanaIndicator; + return false; }(); return Result; @@ -461,13 +465,17 @@ quint32 djbStringHash(QString string) { } bool IsAppMenuSupported() { - const auto interface = QDBusConnection::sessionBus().interface(); + try { + const auto connection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); - if (!interface) { - return false; + return base::Platform::DBus::NameHasOwner( + connection, + std::string(kAppMenuService)); + } catch (...) { } - return interface->isServiceRegistered(kAppMenuService.utf16()); + return false; } void RegisterAppMenu(uint winId, const QString &menuPath) { @@ -527,8 +535,16 @@ void ForceDisabled(QAction *action, bool disabled) { } // namespace +class MainWindow::Private { +public: +#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION + Glib::RefPtr dbusConnection; +#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION +}; + MainWindow::MainWindow(not_null controller) -: Window::MainWindow(controller) { +: Window::MainWindow(controller) +, _private(std::make_unique()) { #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION qDBusRegisterMetaType(); qDBusRegisterMetaType(); @@ -540,22 +556,31 @@ void MainWindow::initHook() { #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION _sniAvailable = IsSNIAvailable(); - _sniDBusProxy = g_dbus_proxy_new_for_bus_sync( - G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - nullptr, - kSNIWatcherService.utf8().constData(), - kSNIWatcherObjectPath.utf8().constData(), - kSNIWatcherInterface.utf8().constData(), - nullptr, - nullptr); + try { + _private->dbusConnection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); - if (_sniDBusProxy) { - g_signal_connect( - _sniDBusProxy, - "g-signal", - G_CALLBACK(sniSignalEmitted), - nullptr); + _sniRegisteredSignalId = _private->dbusConnection->signal_subscribe( + []( + const Glib::RefPtr &connection, + const Glib::ustring &sender_name, + const Glib::ustring &object_path, + const Glib::ustring &interface_name, + const Glib::ustring &signal_name, + const Glib::VariantContainerBase ¶meters) { + if (signal_name == "StatusNotifierHostRegistered") { + crl::on_main([] { + if (const auto window = App::wnd()) { + window->handleSNIHostRegistered(); + } + }); + } + }, + std::string(kSNIWatcherService), + std::string(kSNIWatcherInterface), + "StatusNotifierHostRegistered", + std::string(kSNIWatcherObjectPath)); + } catch (...) { } auto sniWatcher = new QDBusServiceWatcher( @@ -689,21 +714,6 @@ void MainWindow::attachToSNITrayIcon() { }); } -void MainWindow::sniSignalEmitted( - GDBusProxy *proxy, - gchar *sender_name, - gchar *signal_name, - GVariant *parameters, - gpointer user_data) { - if (signal_name == qstr("StatusNotifierHostRegistered")) { - crl::on_main([] { - if (const auto window = App::wnd()) { - window->handleSNIHostRegistered(); - } - }); - } -} - void MainWindow::handleSNIHostRegistered() { if (_sniAvailable) { return; @@ -1241,6 +1251,10 @@ void MainWindow::handleVisibleChangedHook(bool visible) { MainWindow::~MainWindow() { #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION + if (_sniRegisteredSignalId != 0) { + _private->dbusConnection->signal_unsubscribe(_sniRegisteredSignalId); + } + delete _sniTrayIcon; if (_appMenuSupported) { @@ -1249,10 +1263,6 @@ MainWindow::~MainWindow() { delete _mainMenuExporter; delete psMainMenu; - - if (_sniDBusProxy) { - g_object_unref(_sniDBusProxy); - } #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION } diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index cc2ca4f16..8f92b35dd 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -18,11 +18,6 @@ class PopupMenu; class QTemporaryFile; class DBusMenuExporter; class StatusNotifierItem; - -typedef void* gpointer; -typedef char gchar; -typedef struct _GVariant GVariant; -typedef struct _GDBusProxy GDBusProxy; #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION namespace Platform { @@ -75,6 +70,8 @@ protected: style::color color) = 0; private: + class Private; + const std::unique_ptr _private; bool _sniAvailable = false; base::unique_qptr _trayIconMenuXEmbed; @@ -82,7 +79,7 @@ private: #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION StatusNotifierItem *_sniTrayIcon = nullptr; - GDBusProxy *_sniDBusProxy = nullptr; + uint _sniRegisteredSignalId = 0; std::unique_ptr _trayIconFile; bool _appMenuSupported = false; @@ -137,13 +134,6 @@ private: void psLinuxStrikeOut(); void psLinuxMonospace(); void psLinuxClearFormat(); - - static void sniSignalEmitted( - GDBusProxy *proxy, - gchar *sender_name, - gchar *signal_name, - GVariant *parameters, - gpointer user_data); #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION }; diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index fc856bfe2..67c819f53 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/notifications_utilities.h" #include "base/platform/base_platform_info.h" +#include "base/platform/linux/base_linux_glibmm_helper.h" +#include "base/platform/linux/base_linux_dbus_utilities.h" #include "platform/linux/specific_linux.h" #include "core/application.h" #include "core/core_settings.h" @@ -19,7 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include -#include #include #include #include @@ -27,11 +28,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include -extern "C" { -#undef signals -#include -#define signals public -} // extern "C" +#include +#include namespace Platform { namespace Notifications { @@ -55,15 +53,25 @@ std::optional CurrentServerInformation; QStringList CurrentCapabilities; bool GetServiceRegistered() { - const auto interface = QDBusConnection::sessionBus().interface(); - const auto activatable = IsNotificationServiceActivatable(); + try { + const auto connection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); - return interface - ? interface->isServiceRegistered(kService.utf16()) || activatable - : activatable; + static const auto activatable = ranges::contains( + base::Platform::DBus::ListActivatableNames(connection), + Glib::ustring(std::string(kService))); + + return base::Platform::DBus::NameHasOwner( + connection, + std::string(kService)) || activatable; + } catch (...) { + } + + return false; } -void GetServerInformation(Fn)> callback) { +void GetServerInformation( + Fn)> callback) { using ServerInformationReply = QDBusPendingReply< QString, QString, @@ -229,24 +237,24 @@ ServerInformation CurrentServerInformationValue() { return CurrentServerInformation.value_or(ServerInformation{}); } -QString GetImageKey(const QVersionNumber &specificationVersion) { +Glib::ustring GetImageKey(const QVersionNumber &specificationVersion) { const auto normalizedVersion = specificationVersion.normalized(); if (normalizedVersion.isNull()) { LOG(("Native Notification Error: specification version is null")); - return QString(); + return {}; } if (normalizedVersion >= QVersionNumber(1, 2)) { - return qsl("image-data"); + return "image-data"; } else if (normalizedVersion == QVersionNumber(1, 1)) { - return qsl("image_data"); + return "image_data"; } - return qsl("icon_data"); + return "icon_data"; } -class NotificationData { +class NotificationData : public sigc::trackable { public: using NotificationId = Window::Notifications::Manager::NotificationId; @@ -270,40 +278,35 @@ public: void setImage(const QString &imagePath); private: - GDBusConnection *_dbusConnection = nullptr; + Glib::RefPtr _dbusConnection; base::weak_ptr _manager; - GCancellable *_cancellable = nullptr; - QString _title; - QString _body; - std::vector _actions; - base::flat_map _hints; - QString _imageKey; - QImage _image; + Glib::ustring _title; + Glib::ustring _body; + std::vector _actions; + std::map _hints; + Glib::ustring _imageKey; uint _notificationId = 0; - guint _actionInvokedSignalId = 0; - guint _notificationRepliedSignalId = 0; - guint _notificationClosedSignalId = 0; + uint _actionInvokedSignalId = 0; + uint _notificationRepliedSignalId = 0; + uint _notificationClosedSignalId = 0; NotificationId _id; void notificationClosed(uint id, uint reason); - void actionInvoked(uint id, const QString &actionName); - void notificationReplied(uint id, const QString &text); + void actionInvoked(uint id, const Glib::ustring &actionName); + void notificationReplied(uint id, const Glib::ustring &text); - static void notificationShown( - GObject *source_object, - GAsyncResult *res, - gpointer user_data); + void notificationShown( + const Glib::RefPtr &result); - static void signalEmitted( - GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data); + void signalEmitted( + const Glib::RefPtr &connection, + const Glib::ustring &sender_name, + const Glib::ustring &object_path, + const Glib::ustring &interface_name, + const Glib::ustring &signal_name, + const Glib::VariantContainerBase ¶meters); }; @@ -317,20 +320,16 @@ NotificationData::NotificationData( NotificationId id, bool hideReplyButton) : _manager(manager) -, _cancellable(g_cancellable_new()) -, _title(title) +, _title(title.toStdString()) , _imageKey(GetImageKey(CurrentServerInformationValue().specVersion)) , _id(id) { - GError *error = nullptr; + try { + _dbusConnection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); + } catch (const Glib::Error &e) { + LOG(("Native Notification Error: %1").arg( + QString::fromStdString(e.what()))); - _dbusConnection = g_bus_get_sync( - G_BUS_TYPE_SESSION, - nullptr, - &error); - - if (error) { - LOG(("Native Notification Error: %1").arg(error->message)); - g_error_free(error); return; } @@ -338,300 +337,236 @@ NotificationData::NotificationData( if (capabilities.contains(qsl("body-markup"))) { _body = subtitle.isEmpty() - ? msg.toHtmlEscaped() + ? msg.toHtmlEscaped().toStdString() : qsl("%1\n%2") .arg(subtitle.toHtmlEscaped()) - .arg(msg.toHtmlEscaped()); + .arg(msg.toHtmlEscaped()).toStdString(); } else { _body = subtitle.isEmpty() - ? msg - : qsl("%1\n%2").arg(subtitle).arg(msg); + ? msg.toStdString() + : qsl("%1\n%2").arg(subtitle).arg(msg).toStdString(); } - if (capabilities.contains(qsl("actions"))) { - _actions.push_back(qsl("default")); - _actions.push_back(QString()); + if (capabilities.contains("actions")) { + _actions.push_back("default"); + _actions.push_back({}); if (!hideReplyButton) { - _actions.push_back(qsl("mail-mark-read")); - _actions.push_back(tr::lng_context_mark_read(tr::now)); + _actions.push_back("mail-mark-read"); + _actions.push_back( + tr::lng_context_mark_read(tr::now).toStdString()); } - if (capabilities.contains(qsl("inline-reply")) && !hideReplyButton) { - _actions.push_back(qsl("inline-reply")); - _actions.push_back(tr::lng_notification_reply(tr::now)); + if (capabilities.contains("inline-reply") && !hideReplyButton) { + _actions.push_back("inline-reply"); + _actions.push_back( + tr::lng_notification_reply(tr::now).toStdString()); - _notificationRepliedSignalId = g_dbus_connection_signal_subscribe( - _dbusConnection, - kService.utf8().constData(), - kInterface.utf8().constData(), + _notificationRepliedSignalId = _dbusConnection->signal_subscribe( + sigc::mem_fun(this, &NotificationData::signalEmitted), + std::string(kService), + std::string(kInterface), "NotificationReplied", - kObjectPath.utf8().constData(), - nullptr, - G_DBUS_SIGNAL_FLAGS_NONE, - signalEmitted, - this, - nullptr); + std::string(kObjectPath)); } else { // icon name according to https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html - _actions.push_back(qsl("mail-reply-sender")); - _actions.push_back(tr::lng_notification_reply(tr::now)); + _actions.push_back("mail-reply-sender"); + _actions.push_back( + tr::lng_notification_reply(tr::now).toStdString()); } - _actionInvokedSignalId = g_dbus_connection_signal_subscribe( - _dbusConnection, - kService.utf8().constData(), - kInterface.utf8().constData(), + _actionInvokedSignalId = _dbusConnection->signal_subscribe( + sigc::mem_fun(this, &NotificationData::signalEmitted), + std::string(kService), + std::string(kInterface), "ActionInvoked", - kObjectPath.utf8().constData(), - nullptr, - G_DBUS_SIGNAL_FLAGS_NONE, - signalEmitted, - this, - nullptr); + std::string(kObjectPath)); } - if (capabilities.contains(qsl("action-icons"))) { - _hints.emplace(qsl("action-icons"), g_variant_new_boolean(true)); + if (capabilities.contains("action-icons")) { + _hints["action-icons"] = Glib::Variant::create(true); } // suppress system sound if telegram sound activated, // otherwise use system sound - if (capabilities.contains(qsl("sound"))) { + if (capabilities.contains("sound")) { if (Core::App().settings().soundNotify()) { - _hints.emplace( - qsl("suppress-sound"), - g_variant_new_boolean(true)); + _hints["suppress-sound"] = Glib::Variant::create(true); } else { // sound name according to http://0pointer.de/public/sound-naming-spec.html - _hints.emplace( - qsl("sound-name"), - g_variant_new_string("message-new-instant")); + _hints["sound-name"] = Glib::Variant::create( + "message-new-instant"); } } - if (capabilities.contains(qsl("x-canonical-append"))) { - _hints.emplace( - qsl("x-canonical-append"), - g_variant_new_string("true")); + if (capabilities.contains("x-canonical-append")) { + _hints["x-canonical-append"] = Glib::Variant::create( + "true"); } - _hints.emplace(qsl("category"), g_variant_new_string("im.received")); + _hints["category"] = Glib::Variant::create("im.received"); - _hints.emplace( - qsl("desktop-entry"), - g_variant_new_string(GetLauncherBasename().toUtf8().constData())); + _hints["desktop-entry"] = Glib::Variant::create( + GetLauncherBasename().toStdString()); - _notificationClosedSignalId = g_dbus_connection_signal_subscribe( - _dbusConnection, - kService.utf8().constData(), - kInterface.utf8().constData(), + _notificationClosedSignalId = _dbusConnection->signal_subscribe( + sigc::mem_fun(this, &NotificationData::signalEmitted), + std::string(kService), + std::string(kInterface), "NotificationClosed", - kObjectPath.utf8().constData(), - nullptr, - G_DBUS_SIGNAL_FLAGS_NONE, - signalEmitted, - this, - nullptr); + std::string(kObjectPath)); } NotificationData::~NotificationData() { if (_dbusConnection) { if (_actionInvokedSignalId != 0) { - g_dbus_connection_signal_unsubscribe( - _dbusConnection, - _actionInvokedSignalId); + _dbusConnection->signal_unsubscribe(_actionInvokedSignalId); } if (_notificationRepliedSignalId != 0) { - g_dbus_connection_signal_unsubscribe( - _dbusConnection, - _notificationRepliedSignalId); + _dbusConnection->signal_unsubscribe(_notificationRepliedSignalId); } if (_notificationClosedSignalId != 0) { - g_dbus_connection_signal_unsubscribe( - _dbusConnection, - _notificationClosedSignalId); - } - - g_object_unref(_dbusConnection); - } - - for (const auto &[key, value] : _hints) { - if (value) { - g_variant_unref(value); + _dbusConnection->signal_unsubscribe(_notificationClosedSignalId); } } - - g_cancellable_cancel(_cancellable); - g_object_unref(_cancellable); } void NotificationData::show() { - GVariantBuilder actionsBuilder, hintsBuilder; - GError *error = nullptr; + try { + const auto iconName = _imageKey.empty() + || _hints.find(_imageKey) == end(_hints) + ? Glib::ustring(GetIconName().toStdString()) + : Glib::ustring(); - g_variant_builder_init(&actionsBuilder, G_VARIANT_TYPE("as")); - for (const auto &value : _actions) { - g_variant_builder_add( - &actionsBuilder, - "s", - value.toUtf8().constData()); - } + _dbusConnection->call( + std::string(kObjectPath), + std::string(kInterface), + "Notify", + base::Platform::MakeGlibVariant(std::tuple{ + Glib::ustring(std::string(AppName)), + uint(0), + iconName, + _title, + _body, + _actions, + _hints, + -1, + }), + sigc::mem_fun(this, &NotificationData::notificationShown), + std::string(kService)); + } catch (const Glib::Error &e) { + LOG(("Native Notification Error: %1").arg( + QString::fromStdString(e.what()))); - g_variant_builder_init(&hintsBuilder, G_VARIANT_TYPE("a{sv}")); - for (auto &[key, value] : _hints) { - g_variant_builder_add( - &hintsBuilder, - "{sv}", - key.toUtf8().constData(), - value); - - value = nullptr; - } - - const auto iconName = _imageKey.isEmpty() || !_hints.contains(_imageKey) - ? GetIconName() - : QString(); - - g_dbus_connection_call( - _dbusConnection, - kService.utf8().constData(), - kObjectPath.utf8().constData(), - kInterface.utf8().constData(), - "Notify", - g_variant_new( - "(susssasa{sv}i)", - AppName.utf8().constData(), - 0, - iconName.toUtf8().constData(), - _title.toUtf8().constData(), - _body.toUtf8().constData(), - &actionsBuilder, - &hintsBuilder, - -1), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - _cancellable, - notificationShown, - this); -} - -void NotificationData::notificationShown( - GObject *source_object, - GAsyncResult *res, - gpointer user_data) { - GError *error = nullptr; - - auto reply = g_dbus_connection_call_finish( - reinterpret_cast(source_object), - res, - &error); - - if (error && error->code == G_IO_ERROR_CANCELLED) { - g_error_free(error); - return; - } - - const auto notificationData = reinterpret_cast( - user_data); - - if (!notificationData) { - return; - } - - if (!error) { - g_variant_get(reply, "(u)", ¬ificationData->_notificationId); - g_variant_unref(reply); - } else { - const auto manager = notificationData->_manager; - const auto my = notificationData->_id; + const auto manager = _manager; + const auto my = _id; crl::on_main(manager, [=] { manager->clearNotification(my); }); - LOG(("Native Notification Error: %1").arg(error->message)); - g_error_free(error); } } +void NotificationData::notificationShown( + const Glib::RefPtr &result) { + try { + auto reply = _dbusConnection->call_finish(result); + _notificationId = base::Platform::GlibVariantCast( + reply.get_child(0)); + + return; + } catch (const Glib::Error &e) { + LOG(("Native Notification Error: %1").arg( + QString::fromStdString(e.what()))); + } catch (const std::exception &e) { + LOG(("Native Notification Error: %1").arg( + QString::fromStdString(e.what()))); + } + + const auto manager = _manager; + const auto my = _id; + crl::on_main(manager, [=] { + manager->clearNotification(my); + }); +} + void NotificationData::close() { - g_dbus_connection_call( - _dbusConnection, - kService.utf8().constData(), - kObjectPath.utf8().constData(), - kInterface.utf8().constData(), - "CloseNotification", - g_variant_new("(u)", _notificationId), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - nullptr, - nullptr, - nullptr); + try { + _dbusConnection->call( + std::string(kObjectPath), + std::string(kInterface), + "CloseNotification", + base::Platform::MakeGlibVariant(std::tuple{ + _notificationId, + }), + {}, + std::string(kService)); + } catch (const Glib::Error &e) { + LOG(("Native Notification Error: %1").arg( + QString::fromStdString(e.what()))); + } } void NotificationData::setImage(const QString &imagePath) { - if (_imageKey.isEmpty()) { + if (_imageKey.empty()) { return; } - _image = QImage(imagePath).convertToFormat(QImage::Format_RGBA8888); + const auto image = QImage(imagePath) + .convertToFormat(QImage::Format_RGBA8888); - _hints.emplace(_imageKey, g_variant_new( - "(iiibii@ay)", - _image.width(), - _image.height(), - _image.bytesPerLine(), + _hints[_imageKey] = base::Platform::MakeGlibVariant(std::tuple{ + image.width(), + image.height(), + image.bytesPerLine(), true, 8, 4, - g_variant_new_from_data( - G_VARIANT_TYPE("ay"), - _image.constBits(), - _image.sizeInBytes(), - true, - nullptr, - nullptr))); + std::vector( + image.constBits(), + image.constBits() + image.sizeInBytes()), + }); } void NotificationData::signalEmitted( - GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) { - const auto notificationData = reinterpret_cast( - user_data); + const Glib::RefPtr &connection, + const Glib::ustring &sender_name, + const Glib::ustring &object_path, + const Glib::ustring &interface_name, + const Glib::ustring &signal_name, + const Glib::VariantContainerBase ¶meters) { + try { + auto parametersCopy = parameters; - if (!notificationData) { - return; - } + if (signal_name == "ActionInvoked") { + const auto id = base::Platform::GlibVariantCast( + parametersCopy.get_child(0)); - if(signal_name == qstr("ActionInvoked")) { - guint32 id; - gchar *actionName; - g_variant_get(parameters, "(us)", &id, &actionName); - notificationData->actionInvoked(id, actionName); - g_free(actionName); - } + const auto actionName = base::Platform::GlibVariantCast< + Glib::ustring>(parametersCopy.get_child(1)); - if(signal_name == qstr("NotificationReplied")) { - guint32 id; - gchar *text; - g_variant_get(parameters, "(us)", &id, &text); - notificationData->notificationReplied(id, text); - g_free(text); - } + actionInvoked(id, actionName); + } else if (signal_name == "NotificationReplied") { + const auto id = base::Platform::GlibVariantCast( + parametersCopy.get_child(0)); - if(signal_name == qstr("NotificationClosed")) { - guint32 id; - guint32 reason; - g_variant_get(parameters, "(uu)", &id, &reason); - notificationData->notificationClosed(id, reason); + const auto text = base::Platform::GlibVariantCast( + parametersCopy.get_child(1)); + + notificationReplied(id, text); + } else if (signal_name == "NotificationClosed") { + const auto id = base::Platform::GlibVariantCast( + parametersCopy.get_child(0)); + + const auto reason = base::Platform::GlibVariantCast( + parametersCopy.get_child(1)); + + notificationClosed(id, reason); + } + } catch (const std::exception &e) { + LOG(("Native Notification Error: %1").arg( + QString::fromStdString(e.what()))); } } @@ -645,19 +580,21 @@ void NotificationData::notificationClosed(uint id, uint reason) { } } -void NotificationData::actionInvoked(uint id, const QString &actionName) { +void NotificationData::actionInvoked( + uint id, + const Glib::ustring &actionName) { if (id != _notificationId) { return; } - if (actionName == qsl("default") - || actionName == qsl("mail-reply-sender")) { + if (actionName == "default" + || actionName == "mail-reply-sender") { const auto manager = _manager; const auto my = _id; crl::on_main(manager, [=] { manager->notificationActivated(my); }); - } else if (actionName == qsl("mail-mark-read")) { + } else if (actionName == "mail-mark-read") { const auto manager = _manager; const auto my = _id; crl::on_main(manager, [=] { @@ -666,12 +603,16 @@ void NotificationData::actionInvoked(uint id, const QString &actionName) { } } -void NotificationData::notificationReplied(uint id, const QString &text) { +void NotificationData::notificationReplied( + uint id, + const Glib::ustring &text) { if (id == _notificationId) { const auto manager = _manager; const auto my = _id; crl::on_main(manager, [=] { - manager->notificationReplied(my, { text, {} }); + manager->notificationReplied( + my, + { QString::fromStdString(text), {} }); }); } } diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 4b1e3fd55..71cc11dd9 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -23,6 +23,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/update_checker.h" #include "window/window_controller.h" +#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION +#include "base/platform/linux/base_linux_dbus_utilities.h" +#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION + #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION #include "base/platform/linux/base_linux_xcb_utilities.h" #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION @@ -41,19 +45,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION #include #include -#include #include #include #include #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION #include - -extern "C" { -#undef signals #include -#define signals public -} // extern "C" +#include +#include #include #include @@ -83,31 +83,6 @@ constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs; #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION std::unique_ptr NSWInstance; -QStringList ListDBusActivatableNames() { - static const auto Result = [&] { - const auto message = QDBusMessage::createMethodCall( - qsl("org.freedesktop.DBus"), - qsl("/org/freedesktop/DBus"), - qsl("org.freedesktop.DBus"), - qsl("ListActivatableNames")); - - const QDBusReply reply = QDBusConnection::sessionBus() - .call(message); - - if (reply.isValid()) { - return reply.value(); - } else if (reply.error().type() != QDBusError::Disconnected) { - LOG(("ListActivatableNames Error: %1: %2") - .arg(reply.error().name()) - .arg(reply.error().message())); - } - - return QStringList{}; - }(); - - return Result; -} - void PortalAutostart(bool start, bool silent = false) { if (cExeName().isEmpty()) { return; @@ -177,17 +152,23 @@ bool IsXDGDesktopPortalKDEPresent() { bool IsIBusPortalPresent() { static const auto Result = [&] { - const auto interface = QDBusConnection::sessionBus().interface(); - const auto activatableNames = ListDBusActivatableNames(); + try { + const auto connection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); - const auto serviceRegistered = interface - && interface->isServiceRegistered( - qsl("org.freedesktop.portal.IBus")); + const auto serviceRegistered = base::Platform::DBus::NameHasOwner( + connection, + "org.freedesktop.portal.IBus"); - const auto serviceActivatable = activatableNames.contains( - qsl("org.freedesktop.portal.IBus")); + const auto serviceActivatable = ranges::contains( + base::Platform::DBus::ListActivatableNames(connection), + "org.freedesktop.portal.IBus"); - return serviceRegistered || serviceActivatable; + return serviceRegistered || serviceActivatable; + } catch (...) { + } + + return false; }(); return Result; @@ -443,17 +424,6 @@ bool CanOpenDirectoryWithPortal() { return false; } -bool IsNotificationServiceActivatable() { -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - static const auto Result = ListDBusActivatableNames().contains( - qsl("org.freedesktop.Notifications")); - - return Result; -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - - return false; -} - QString AppRuntimeDirectory() { static const auto Result = [&] { auto runtimeDir = QStandardPaths::writableLocation( @@ -598,8 +568,7 @@ void psActivateProcess(uint64 pid) { namespace { QString GetHomeDir() { - const auto home = QString(g_get_home_dir()); - + const auto home = QString::fromStdString(Glib::get_home_dir()); if (!home.isEmpty() && !home.endsWith('/')) { return home + '/'; } @@ -682,6 +651,9 @@ void start() { qputenv("PULSE_PROP_application.name", AppName.utf8()); qputenv("PULSE_PROP_application.icon_name", GetIconName().toLatin1()); + Glib::init(); + Gio::init(); + if (const auto integration = BaseGtkIntegration::Instance()) { integration->prepareEnvironment(); } else { @@ -775,75 +747,65 @@ void InstallLauncher(bool force) { } void RegisterCustomScheme(bool force) { - if (cExeName().isEmpty()) { - return; - } - - GError *error = nullptr; - - const auto neededCommandlineBuilder = qsl("%1 -workdir %2 --").arg( - QString(EscapeShell(QFile::encodeName(cExeDir() + cExeName()))), - QString(EscapeShell(QFile::encodeName(cWorkingDir())))); - - const auto neededCommandline = qsl("%1 %u") - .arg(neededCommandlineBuilder); - - auto currentAppInfo = g_app_info_get_default_for_type( - kHandlerTypeName.utf8().constData(), - true); - - if (currentAppInfo) { - const auto currentCommandline = QString( - g_app_info_get_commandline(currentAppInfo)); - - g_object_unref(currentAppInfo); - - if (currentCommandline == neededCommandline) { + try { + if (cExeName().isEmpty()) { return; } - } - auto registeredAppInfoList = g_app_info_get_recommended_for_type( - kHandlerTypeName.utf8().constData()); + const auto neededCommandlineBuilder = qsl("%1 -workdir %2 --").arg( + QString(EscapeShell(QFile::encodeName(cExeDir() + cExeName()))), + QString(EscapeShell(QFile::encodeName(cWorkingDir())))); - for (auto l = registeredAppInfoList; l != nullptr; l = l->next) { - const auto currentRegisteredAppInfo = reinterpret_cast( - l->data); + const auto neededCommandline = qsl("%1 %u") + .arg(neededCommandlineBuilder); - const auto currentAppInfoId = QString( - g_app_info_get_id(currentRegisteredAppInfo)); + const auto currentAppInfo = Gio::AppInfo::get_default_for_type( + std::string(kHandlerTypeName), + true); - const auto currentCommandline = QString( - g_app_info_get_commandline(currentRegisteredAppInfo)); + if (currentAppInfo) { + const auto currentCommandline = QString::fromStdString( + currentAppInfo->get_commandline()); - if (currentCommandline == neededCommandline - && currentAppInfoId.startsWith(qsl("userapp-"))) { - g_app_info_delete(currentRegisteredAppInfo); + if (currentCommandline == neededCommandline) { + return; + } } - } - if (registeredAppInfoList) { - g_list_free_full(registeredAppInfoList, g_object_unref); - } + auto registeredAppInfoList = g_app_info_get_recommended_for_type( + kHandlerTypeName.utf8().constData()); - auto newAppInfo = g_app_info_create_from_commandline( - neededCommandlineBuilder.toUtf8().constData(), - AppName.utf8().constData(), - G_APP_INFO_CREATE_SUPPORTS_URIS, - &error); + for (auto l = registeredAppInfoList; l != nullptr; l = l->next) { + const auto currentRegisteredAppInfo = reinterpret_cast( + l->data); - if (newAppInfo) { - g_app_info_set_as_default_for_type( - newAppInfo, - kHandlerTypeName.utf8().constData(), - &error); + const auto currentAppInfoId = QString( + g_app_info_get_id(currentRegisteredAppInfo)); - g_object_unref(newAppInfo); - } + const auto currentCommandline = QString( + g_app_info_get_commandline(currentRegisteredAppInfo)); - if (error) { - LOG(("App Error: %1").arg(error->message)); - g_error_free(error); + if (currentCommandline == neededCommandline + && currentAppInfoId.startsWith(qsl("userapp-"))) { + g_app_info_delete(currentRegisteredAppInfo); + } + } + + if (registeredAppInfoList) { + g_list_free_full(registeredAppInfoList, g_object_unref); + } + + const auto newAppInfo = Gio::AppInfo::create_from_commandline( + neededCommandlineBuilder.toStdString(), + std::string(AppName), + Gio::AppInfoCreateFlags::APP_INFO_CREATE_SUPPORTS_URIS); + + if (newAppInfo) { + newAppInfo->set_as_default_for_type( + std::string(kHandlerTypeName)); + } + } catch (const Glib::Error &e) { + LOG(("App Error: %1").arg(QString::fromStdString(e.what()))); } } diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.h b/Telegram/SourceFiles/platform/linux/specific_linux.h index 529adb597..38e1b4c33 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.h +++ b/Telegram/SourceFiles/platform/linux/specific_linux.h @@ -20,7 +20,6 @@ bool InSnap(); bool AreQtPluginsBundled(); bool UseXDGDesktopPortal(); bool CanOpenDirectoryWithPortal(); -bool IsNotificationServiceActivatable(); QString AppRuntimeDirectory(); QString GetLauncherBasename(); diff --git a/Telegram/ThirdParty/fcitx-qt5 b/Telegram/ThirdParty/fcitx-qt5 index f95f76d63..77cb995a1 160000 --- a/Telegram/ThirdParty/fcitx-qt5 +++ b/Telegram/ThirdParty/fcitx-qt5 @@ -1 +1 @@ -Subproject commit f95f76d637990f66f056eb099d46e3b5e6e7366f +Subproject commit 77cb995a1ed0c30401e43388842b99610b53569e diff --git a/Telegram/ThirdParty/fcitx5-qt b/Telegram/ThirdParty/fcitx5-qt index 47628ac9f..8543204b9 160000 --- a/Telegram/ThirdParty/fcitx5-qt +++ b/Telegram/ThirdParty/fcitx5-qt @@ -1 +1 @@ -Subproject commit 47628ac9f81b589d8e69f82b121d08773b06e813 +Subproject commit 8543204b9a3792e0dbd4163ee9420e896f4f49d8 diff --git a/Telegram/ThirdParty/qt5ct b/Telegram/ThirdParty/qt5ct index 59be9d1d9..9f60cd235 160000 --- a/Telegram/ThirdParty/qt5ct +++ b/Telegram/ThirdParty/qt5ct @@ -1 +1 @@ -Subproject commit 59be9d1d995348687702a18ce3d653c07389cfa2 +Subproject commit 9f60cd2352a4dcc55c8ca267f29bd8fff5c6a659 diff --git a/Telegram/build/docker/centos_env/Dockerfile b/Telegram/build/docker/centos_env/Dockerfile index f649c9b96..e0aed8658 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -458,6 +458,52 @@ RUN DESTDIR="$LibrariesPath/xkbcommon-cache" meson install -C build WORKDIR .. RUN rm -rf libxkbcommon +FROM builder AS mm-common +RUN git clone -b 1.0.2 --depth=1 $GIT/GNOME/mm-common.git + +WORKDIR mm-common +RUN NOCONFIGURE=1 ./autogen.sh +RUN ./configure --enable-network +RUN make -j$(nproc) +RUN make DESTDIR="$LibrariesPath/mm-common-cache" install + +WORKDIR .. +RUN rm -rf mm-common + +FROM builder AS libsigcplusplus +COPY --from=mm-common ${LibrariesPath}/mm-common-cache / + +RUN git clone -b 2.10.6 --depth=1 $GIT/libsigcplusplus/libsigcplusplus.git + +WORKDIR libsigcplusplus +ENV ACLOCAL_PATH="/usr/local/share/aclocal" +RUN NOCONFIGURE=1 ./autogen.sh +RUN ./configure --enable-maintainer-mode --enable-static --disable-documentation +RUN make -j$(nproc) +RUN make DESTDIR="$LibrariesPath/libsigcplusplus-cache" install + +WORKDIR .. +RUN rm -rf libsigcplusplus + +FROM patches AS glibmm +COPY --from=mm-common ${LibrariesPath}/mm-common-cache / +COPY --from=libsigcplusplus ${LibrariesPath}/libsigcplusplus-cache / +RUN yum -y install perl-XML-Parser + +# equals to glib version of Ubuntu 14.04 +RUN git clone -b 2.40.0 --depth=1 $GIT/GNOME/glibmm.git + +WORKDIR glibmm +RUN git apply ../patches/glibmm.patch +ENV ACLOCAL_PATH="/usr/local/share/aclocal" +RUN NOCONFIGURE=1 ./autogen.sh +RUN ./configure --enable-maintainer-mode --enable-static --disable-documentation +RUN make -j$(nproc) +RUN make DESTDIR="$LibrariesPath/glibmm-cache" install + +WORKDIR .. +RUN rm -rf glibmm + FROM patches AS qt COPY --from=libffi ${LibrariesPath}/libffi-cache / @@ -636,6 +682,8 @@ COPY --from=ffmpeg ${LibrariesPath}/ffmpeg-cache / COPY --from=openal ${LibrariesPath}/openal-cache / COPY --from=openssl ${LibrariesPath}/openssl-cache / COPY --from=xkbcommon ${LibrariesPath}/xkbcommon-cache / +COPY --from=libsigcplusplus ${LibrariesPath}/libsigcplusplus-cache / +COPY --from=glibmm ${LibrariesPath}/glibmm-cache / COPY --from=qt ${LibrariesPath}/qt-cache / COPY --from=kwayland ${LibrariesPath}/kwayland-cache / COPY --from=breakpad ${LibrariesPath}/breakpad breakpad diff --git a/Telegram/lib_base b/Telegram/lib_base index 9005da2a2..06e0afae8 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 9005da2a22740668fc3f16597ca08dffbc4b008b +Subproject commit 06e0afae84d45a8c4587329d56b7c5754190dc97 diff --git a/Telegram/lib_ui b/Telegram/lib_ui index db65fca0a..af41bff7e 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit db65fca0aa6f0e1225d45a0a6eeecfafdab5cce0 +Subproject commit af41bff7e49e2018a905755d8dea60d2d1f7b8f3 diff --git a/cmake b/cmake index ac193a597..2f4cbdd12 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit ac193a597d6b953f9869a240e21e275ce6e388cb +Subproject commit 2f4cbdd1263ad350776413633bb01e8122147274 diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index b0c7b1ae7..cd4a4d385 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -75,6 +75,7 @@ parts: - python - libasound2-dev - libglib2.0-dev + - libglibmm-2.4-dev - libgtk-3-dev - liblzma-dev - libopus-dev @@ -88,6 +89,7 @@ parts: stage-packages: - libasound2 - libglib2.0-0 + - libglibmm-2.4-1v5 - libgtk-3-0 - liblzma5 - libopus0