diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index eea381f1b..fb32be384 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1334,7 +1334,6 @@ else() if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION) target_link_libraries(Telegram PRIVATE - desktop-app::external_statusnotifieritem desktop-app::external_dbusmenu_qt desktop-app::external_glibmm desktop-app::external_glib diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index cffa63a4f..3d465403a 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "base/platform/base_platform_info.h" #include "base/event_filter.h" +#include "base/unique_qptr.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/input_fields.h" #include "ui/ui_utility.h" @@ -41,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION #include -#include #include #include @@ -49,9 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include #include -#include -#include #include #include @@ -69,13 +67,6 @@ constexpr auto kMutePanelTrayIconName = "telegram-mute-panel"_cs; constexpr auto kAttentionPanelTrayIconName = "telegram-attention-panel"_cs; #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION -constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs; -constexpr auto kTrayIconFilename = "tdesktop-trayicon-XXXXXX.png"_cs; - -constexpr auto kSNIWatcherService = "org.kde.StatusNotifierWatcher"_cs; -constexpr auto kSNIWatcherObjectPath = "/StatusNotifierWatcher"_cs; -constexpr auto kSNIWatcherInterface = kSNIWatcherService; - constexpr auto kAppMenuService = "com.canonical.AppMenu.Registrar"_cs; constexpr auto kAppMenuObjectPath = "/com/canonical/AppMenu/Registrar"_cs; constexpr auto kAppMenuInterface = kAppMenuService; @@ -390,88 +381,6 @@ void ForceDisabled(QAction *action, bool disabled) { } #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION -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 Result = [] { - try { - const auto connection = Gio::DBus::Connection::get_sync( - Gio::DBus::BusType::BUS_TYPE_SESSION); - - 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 (...) { - } - - return false; - }(); - - return Result; -} - -std::unique_ptr TrayIconFile( - const QIcon &icon, - QObject *parent = nullptr) { - static const auto templateName = AppRuntimeDirectory() - + kTrayIconFilename.utf16(); - - static const auto dprSize = [](const QPixmap &pixmap) { - return pixmap.size() / pixmap.devicePixelRatio(); - }; - - static const auto desiredSize = QSize(22, 22); - - static const auto scalePixmap = [=](const QPixmap &pixmap) { - if (dprSize(pixmap) != desiredSize) { - return pixmap.scaled( - desiredSize * pixmap.devicePixelRatio(), - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation); - } else { - return pixmap; - } - }; - - auto ret = std::make_unique( - templateName, - parent); - - ret->open(); - - const auto firstAttempt = icon.pixmap(desiredSize); - const auto firstAttemptSize = dprSize(firstAttempt); - - if (firstAttemptSize.width() < desiredSize.width()) { - const auto availableSizes = icon.availableSizes(); - - const auto biggestSize = ranges::max_element( - availableSizes, - std::less<>(), - &QSize::width); - - if (biggestSize->width() > firstAttemptSize.width()) { - scalePixmap(icon.pixmap(*biggestSize)).save(ret.get()); - } else { - scalePixmap(firstAttempt).save(ret.get()); - } - } else { - scalePixmap(firstAttempt).save(ret.get()); - } - - ret->close(); - - return ret; -} - bool UseUnityCounter() { static const auto Result = [&] { try { @@ -490,54 +399,6 @@ bool UseUnityCounter() { return Result; } -bool IsSNIAvailable() { - try { - const auto connection = [] { - try { - return Gio::DBus::Connection::get_sync( - Gio::DBus::BusType::BUS_TYPE_SESSION); - } catch (...) { - return Glib::RefPtr(); - } - }(); - - if (!connection) { - return false; - } - - auto reply = connection->call_sync( - std::string(kSNIWatcherObjectPath), - std::string(kPropertiesInterface), - "Get", - base::Platform::MakeGlibVariant(std::tuple{ - Glib::ustring(std::string(kSNIWatcherInterface)), - Glib::ustring("IsStatusNotifierHostRegistered"), - }), - std::string(kSNIWatcherService)); - - return base::Platform::GlibVariantCast( - base::Platform::GlibVariantCast( - reply.get_child(0))); - } catch (const Glib::Error &e) { - static const auto NotSupportedErrors = { - "org.freedesktop.DBus.Error.ServiceUnknown", - }; - - const auto errorName = Gio::DBus::ErrorUtils::get_remote_error(e); - 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()))); - } - - return false; -} - uint djbStringHash(const std::string &string) { uint hash = 5381; for (const auto &curChar : string) { @@ -608,162 +469,50 @@ void UnregisterAppMenu(QWindow *window) { } // namespace -class MainWindow::Private { +class MainWindow::Private : public QObject { public: explicit Private(not_null window) : _public(window) { + QCoreApplication::instance()->installEventFilter(this); } + base::unique_qptr trayIconMenuXEmbed; + #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION Glib::RefPtr dbusConnection; - StatusNotifierItem *sniTrayIcon = nullptr; - uint sniRegisteredSignalId = 0; - uint sniWatcherId = 0; - std::unique_ptr trayIconFile; - bool appMenuSupported = false; uint appMenuWatcherId = 0; DBusMenuExporter *mainMenuExporter = nullptr; - void setSNITrayIcon(int counter, bool muted); - void attachToSNITrayIcon(); - void handleSNIHostRegistered(); - - void handleSNIOwnerChanged( - const QString &service, - const QString &oldOwner, - const QString &newOwner); - void handleAppMenuOwnerChanged( const QString &service, const QString &oldOwner, const QString &newOwner); #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION +protected: + bool eventFilter(QObject *obj, QEvent *e) override; + private: not_null _public; }; +bool MainWindow::Private::eventFilter(QObject *obj, QEvent *e) { + if (obj->objectName() == qstr("QSystemTrayIconSys") + && e->type() == QEvent::MouseButtonPress) { + const auto ee = static_cast(e); + if (ee->button() == Qt::RightButton) { + Core::Sandbox::Instance().customEnterFromEventLoop([&] { + _public->handleTrayIconActication(QSystemTrayIcon::Context); + }); + return true; + } + } + return QObject::eventFilter(obj, e); +} + #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION -void MainWindow::Private::setSNITrayIcon(int counter, bool muted) { - const auto iconName = GetTrayIconName(counter, muted); - const auto panelIconName = GetPanelIconName(counter, muted); - - if (iconName == panelIconName) { - if (sniTrayIcon->iconName() == iconName) { - return; - } - - sniTrayIcon->setIconByName(iconName); - sniTrayIcon->setToolTipIconByName(iconName); - } else if (IsIndicatorApplication()) { - if (!IsIconRegenerationNeeded(counter, muted) - && trayIconFile - && sniTrayIcon->iconName() == trayIconFile->fileName()) { - return; - } - - const auto icon = TrayIconGen(counter, muted); - trayIconFile = TrayIconFile(icon, _public); - - if (trayIconFile) { - // indicator-application doesn't support tooltips - sniTrayIcon->setIconByName(trayIconFile->fileName()); - } - } else { - if (!IsIconRegenerationNeeded(counter, muted) - && !sniTrayIcon->iconPixmap().isEmpty() - && sniTrayIcon->iconName().isEmpty()) { - return; - } - - const auto icon = TrayIconGen(counter, muted); - sniTrayIcon->setIconByPixmap(icon); - sniTrayIcon->setToolTipIconByPixmap(icon); - } -} - -void MainWindow::Private::attachToSNITrayIcon() { - sniTrayIcon->setToolTipTitle(AppName.utf16()); - connect(sniTrayIcon, - &StatusNotifierItem::activateRequested, - [=](const QPoint &) { - Core::Sandbox::Instance().customEnterFromEventLoop([&] { - _public->handleTrayIconActication(QSystemTrayIcon::Trigger); - }); - }); - connect(sniTrayIcon, - &StatusNotifierItem::secondaryActivateRequested, - [=](const QPoint &) { - Core::Sandbox::Instance().customEnterFromEventLoop([&] { - _public->handleTrayIconActication(QSystemTrayIcon::MiddleClick); - }); - }); -} - -void MainWindow::Private::handleSNIHostRegistered() { - if (_public->_sniAvailable) { - return; - } - - _public->_sniAvailable = true; - - if (Core::App().settings().workMode() == WorkMode::WindowOnly) { - return; - } - - LOG(("Switching to SNI tray icon...")); - - if (_public->trayIcon) { - _public->trayIcon->setContextMenu(nullptr); - _public->trayIcon->deleteLater(); - } - _public->trayIcon = nullptr; - - _public->psSetupTrayIcon(); - - SkipTaskbar( - _public->windowHandle(), - Core::App().settings().workMode() == WorkMode::TrayOnly); -} - -void MainWindow::Private::handleSNIOwnerChanged( - const QString &service, - const QString &oldOwner, - const QString &newOwner) { - _public->_sniAvailable = IsSNIAvailable(); - - if (Core::App().settings().workMode() == WorkMode::WindowOnly) { - return; - } - - if (oldOwner.isEmpty() && !newOwner.isEmpty() && _public->_sniAvailable) { - LOG(("Switching to SNI tray icon...")); - } else if (!oldOwner.isEmpty() && newOwner.isEmpty()) { - LOG(("Switching to Qt tray icon...")); - } else { - return; - } - - if (_public->trayIcon) { - _public->trayIcon->setContextMenu(0); - _public->trayIcon->deleteLater(); - } - _public->trayIcon = nullptr; - - if (_public->trayAvailable()) { - _public->psSetupTrayIcon(); - } else { - LOG(("System tray is not available.")); - } - - SkipTaskbar( - _public->windowHandle(), - (Core::App().settings().workMode() == WorkMode::TrayOnly) - && _public->trayAvailable()); -} - void MainWindow::Private::handleAppMenuOwnerChanged( const QString &service, const QString &oldOwner, @@ -787,11 +536,6 @@ void MainWindow::Private::handleAppMenuOwnerChanged( MainWindow::MainWindow(not_null controller) : Window::MainWindow(controller) , _private(std::make_unique(this)) { -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION } void MainWindow::initHook() { @@ -817,47 +561,12 @@ void MainWindow::initHook() { }); #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - _sniAvailable = IsSNIAvailable(); _private->appMenuSupported = IsAppMenuSupported(); try { _private->dbusConnection = Gio::DBus::Connection::get_sync( Gio::DBus::BusType::BUS_TYPE_SESSION); - _private->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->_private->handleSNIHostRegistered(); - } - }); - } - }, - std::string(kSNIWatcherService), - std::string(kSNIWatcherInterface), - "StatusNotifierHostRegistered", - std::string(kSNIWatcherObjectPath)); - - _private->sniWatcherId = base::Platform::DBus::RegisterServiceWatcher( - _private->dbusConnection, - std::string(kSNIWatcherService), - [=]( - const Glib::ustring &service, - const Glib::ustring &oldOwner, - const Glib::ustring &newOwner) { - _private->handleSNIOwnerChanged( - QString::fromStdString(service), - QString::fromStdString(oldOwner), - QString::fromStdString(newOwner)); - }); - _private->appMenuWatcherId = base::Platform::DBus::RegisterServiceWatcher( _private->dbusConnection, std::string(kAppMenuService), @@ -890,15 +599,11 @@ void MainWindow::initHook() { XCBSetDesktopFileName(windowHandle()); #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION - LOG(("System tray available: %1").arg(Logs::b(trayAvailable()))); + LOG(("System tray available: %1").arg(Logs::b(TrayIconSupported()))); } bool MainWindow::hasTrayIcon() const { -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - return trayIcon || (_sniAvailable && _private->sniTrayIcon); -#else return trayIcon; -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION } bool MainWindow::isActiveForTrayMenu() { @@ -907,44 +612,19 @@ bool MainWindow::isActiveForTrayMenu() { } void MainWindow::psShowTrayMenu() { - _trayIconMenuXEmbed->popup(QCursor::pos()); + _private->trayIconMenuXEmbed->popup(QCursor::pos()); } void MainWindow::psTrayMenuUpdated() { } void MainWindow::psSetupTrayIcon() { - const auto counter = Core::App().unreadBadge(); - const auto muted = Core::App().unreadBadgeMuted(); - -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - if (_sniAvailable) { - LOG(("Using SNI tray icon.")); - if (!_private->sniTrayIcon) { - _private->sniTrayIcon = new StatusNotifierItem( - QCoreApplication::applicationName(), - this); - - _private->sniTrayIcon->setTitle(AppName.utf16()); - _private->sniTrayIcon->setCategory(qsl("Communications")); - _private->sniTrayIcon->setContextMenu(trayIconMenu); - _private->setSNITrayIcon(counter, muted); - - _private->attachToSNITrayIcon(); - } - updateIconCounters(); - - return; - } -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - - LOG(("Using Qt tray icon.")); if (!trayIcon) { trayIcon = new QSystemTrayIcon(this); - if (_sniAvailable) { - trayIcon->setContextMenu(trayIconMenu); - } - trayIcon->setIcon(TrayIconGen(counter, muted)); + trayIcon->setContextMenu(trayIconMenu); + trayIcon->setIcon(TrayIconGen( + Core::App().unreadBadge(), + Core::App().unreadBadgeMuted())); attachToTrayIcon(trayIcon); } @@ -954,17 +634,9 @@ void MainWindow::psSetupTrayIcon() { } void MainWindow::workmodeUpdated(Core::Settings::WorkMode mode) { - if (!trayAvailable()) { + if (!TrayIconSupported()) { return; } else if (mode == WorkMode::WindowOnly) { -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - if (_private->sniTrayIcon) { - _private->sniTrayIcon->setContextMenu(0); - _private->sniTrayIcon->deleteLater(); - } - _private->sniTrayIcon = nullptr; -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - if (trayIcon) { trayIcon->setContextMenu(0); trayIcon->deleteLater(); @@ -1024,10 +696,6 @@ void MainWindow::updateIconCounters() { } catch (...) { } } - - if (_private->sniTrayIcon) { - _private->setSNITrayIcon(counter, muted); - } #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION if (trayIcon && IsIconRegenerationNeeded(counter, muted)) { @@ -1036,8 +704,8 @@ void MainWindow::updateIconCounters() { } void MainWindow::initTrayMenuHook() { - _trayIconMenuXEmbed.emplace(nullptr, trayIconMenu); - _trayIconMenuXEmbed->deleteOnHide(false); + _private->trayIconMenuXEmbed.emplace(nullptr, trayIconMenu); + _private->trayIconMenuXEmbed->deleteOnHide(false); } void MainWindow::createGlobalMenu() { @@ -1310,7 +978,7 @@ void MainWindow::handleNativeSurfaceChanged(bool exist) { SkipTaskbar( windowHandle(), (Core::App().settings().workMode() == WorkMode::TrayOnly) - && trayAvailable()); + && TrayIconSupported()); } #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION @@ -1327,16 +995,6 @@ void MainWindow::handleNativeSurfaceChanged(bool exist) { MainWindow::~MainWindow() { #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION if (_private->dbusConnection) { - if (_private->sniRegisteredSignalId != 0) { - _private->dbusConnection->signal_unsubscribe( - _private->sniRegisteredSignalId); - } - - if (_private->sniWatcherId != 0) { - _private->dbusConnection->signal_unsubscribe( - _private->sniWatcherId); - } - if (_private->appMenuWatcherId != 0) { _private->dbusConnection->signal_unsubscribe( _private->appMenuWatcherId); diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index d6f9839e0..11f19b2cb 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -8,11 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "platform/platform_main_window.h" -#include "base/unique_qptr.h" - -namespace Ui { -class PopupMenu; -} // namespace Ui namespace Platform { @@ -22,10 +17,6 @@ public: void psShowTrayMenu(); - bool trayAvailable() { - return _sniAvailable || QSystemTrayIcon::isSystemTrayAvailable(); - } - bool isActiveForTrayMenu() override; ~MainWindow(); @@ -52,9 +43,6 @@ private: friend class Private; const std::unique_ptr _private; - bool _sniAvailable = false; - base::unique_qptr _trayIconMenuXEmbed; - QMenu *psMainMenu = nullptr; QAction *psLogout = nullptr; QAction *psUndo = nullptr; diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 31e575bc3..1f3744d46 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -592,9 +592,7 @@ bool AutostartSkip() { } bool TrayIconSupported() { - return App::wnd() - ? App::wnd()->trayAvailable() - : false; + return QSystemTrayIcon::isSystemTrayAvailable(); } bool SkipTaskbarSupported() { diff --git a/Telegram/ThirdParty/statusnotifieritem/dbustypes.cpp b/Telegram/ThirdParty/statusnotifieritem/dbustypes.cpp deleted file mode 100644 index fbb63804e..000000000 --- a/Telegram/ThirdParty/statusnotifieritem/dbustypes.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* BEGIN_COMMON_COPYRIGHT_HEADER - * (c)LGPL2+ - * - * LXQt - a lightweight, Qt based, desktop toolset - * https://lxqt.org - * - * Copyright: 2015 LXQt team - * Authors: - * Balázs Béla - * Paulo Lieuthier - * - * This program or library is free software; you can redistribute it - * and/or modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - * - * END_COMMON_COPYRIGHT_HEADER */ - -#include "dbustypes.h" - -// Marshall the IconPixmap data into a D-Bus argument -QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon) -{ - argument.beginStructure(); - argument << icon.width; - argument << icon.height; - argument << icon.bytes; - argument.endStructure(); - return argument; -} - -// Retrieve the ImageStruct data from the D-Bus argument -const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon) -{ - argument.beginStructure(); - argument >> icon.width; - argument >> icon.height; - argument >> icon.bytes; - argument.endStructure(); - return argument; -} - -// Marshall the ToolTip data into a D-Bus argument -QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip) -{ - argument.beginStructure(); - argument << toolTip.iconName; - argument << toolTip.iconPixmap; - argument << toolTip.title; - argument << toolTip.description; - argument.endStructure(); - return argument; -} - -// Retrieve the ToolTip data from the D-Bus argument -const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip) -{ - argument.beginStructure(); - argument >> toolTip.iconName; - argument >> toolTip.iconPixmap; - argument >> toolTip.title; - argument >> toolTip.description; - argument.endStructure(); - return argument; -} diff --git a/Telegram/ThirdParty/statusnotifieritem/dbustypes.h b/Telegram/ThirdParty/statusnotifieritem/dbustypes.h deleted file mode 100644 index af5fa5ce2..000000000 --- a/Telegram/ThirdParty/statusnotifieritem/dbustypes.h +++ /dev/null @@ -1,60 +0,0 @@ -/* BEGIN_COMMON_COPYRIGHT_HEADER - * (c)LGPL2+ - * - * LXQt - a lightweight, Qt based, desktop toolset - * https://lxqt.org - * - * Copyright: 2015 LXQt team - * Authors: - * Balázs Béla - * Paulo Lieuthier - * - * This program or library is free software; you can redistribute it - * and/or modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - * - * END_COMMON_COPYRIGHT_HEADER */ - -#include - -#ifndef DBUSTYPES_H -#define DBUSTYPES_H - -struct IconPixmap { - int width; - int height; - QByteArray bytes; -}; - -typedef QList IconPixmapList; - -Q_DECLARE_METATYPE(IconPixmap) -Q_DECLARE_METATYPE(IconPixmapList) - -struct ToolTip { - QString iconName; - QList iconPixmap; - QString title; - QString description; -}; - -Q_DECLARE_METATYPE(ToolTip) - -QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon); -const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon); - -QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip); -const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip); - -#endif // DBUSTYPES_H diff --git a/Telegram/ThirdParty/statusnotifieritem/org.kde.StatusNotifierItem.xml b/Telegram/ThirdParty/statusnotifieritem/org.kde.StatusNotifierItem.xml deleted file mode 100644 index 0a563c549..000000000 --- a/Telegram/ThirdParty/statusnotifieritem/org.kde.StatusNotifierItem.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp deleted file mode 100644 index afbe2c36a..000000000 --- a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* BEGIN_COMMON_COPYRIGHT_HEADER - * (c)LGPL2+ - * - * LXQt - a lightweight, Qt based, desktop toolset - * https://lxqt.org/ - * - * Copyright: 2015 LXQt team - * Authors: - * Paulo Lieuthier - * - * This program or library is free software; you can redistribute it - * and/or modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - * - * END_COMMON_COPYRIGHT_HEADER */ - -#include "statusnotifieritem.h" -#include "statusnotifieritemadaptor.h" -#include -#include -#include -#include - -int StatusNotifierItem::mServiceCounter = 0; - -StatusNotifierItem::StatusNotifierItem(QString id, QObject *parent) - : QObject(parent), - mAdaptor(new StatusNotifierItemAdaptor(this)), - mService(QString::fromLatin1("org.freedesktop.StatusNotifierItem-%1-%2") - .arg(QCoreApplication::applicationPid()) - .arg(++mServiceCounter)), - mId(std::move(id)), - mTitle(QLatin1String("Test")), - mStatus(QLatin1String("Active")), - mCategory(QLatin1String("ApplicationStatus")), - mMenu(nullptr), - mMenuPath(QLatin1String("/NO_DBUSMENU")), - mMenuExporter(nullptr), - mSessionBus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, mService)) -{ - // Separate DBus connection to the session bus is created, because QDbus does not provide - // a way to register different objects for different services with the same paths. - // For status notifiers we need different /StatusNotifierItem for each service. - - // register service - - mSessionBus.registerObject(QLatin1String("/StatusNotifierItem"), this); - - registerToHost(); - - // monitor the watcher service in case the host restarts - QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QLatin1String("org.kde.StatusNotifierWatcher"), - mSessionBus, - QDBusServiceWatcher::WatchForOwnerChange, - this); - connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, - this, &StatusNotifierItem::onServiceOwnerChanged); -} - -StatusNotifierItem::~StatusNotifierItem() -{ - mSessionBus.unregisterObject(QLatin1String("/StatusNotifierItem")); - QDBusConnection::disconnectFromBus(mService); -} - -void StatusNotifierItem::registerToHost() -{ - QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.kde.StatusNotifierWatcher"), - QLatin1String("/StatusNotifierWatcher"), - QLatin1String("org.kde.StatusNotifierWatcher"), - QLatin1String("RegisterStatusNotifierItem")); - - message.setArguments({ - mSessionBus.baseService() - }); - - mSessionBus.send(message); -} - -void StatusNotifierItem::onServiceOwnerChanged(const QString& service, const QString& oldOwner, - const QString& newOwner) -{ - Q_UNUSED(service); - Q_UNUSED(oldOwner); - - if (!newOwner.isEmpty()) - registerToHost(); -} - -void StatusNotifierItem::onMenuDestroyed() -{ - mMenu = nullptr; - setMenuPath(QLatin1String("/NO_DBUSMENU")); - mMenuExporter = nullptr; //mMenu is a QObject parent of the mMenuExporter -} - -void StatusNotifierItem::setTitle(const QString &title) -{ - if (mTitle == title) - return; - - mTitle = title; - Q_EMIT mAdaptor->NewTitle(); -} - -void StatusNotifierItem::setStatus(const QString &status) -{ - if (mStatus == status) - return; - - mStatus = status; - Q_EMIT mAdaptor->NewStatus(mStatus); -} - -void StatusNotifierItem::setCategory(const QString &category) -{ - if (mCategory == category) - return; - - mCategory = category; -} - -void StatusNotifierItem::setMenuPath(const QString& path) -{ - mMenuPath.setPath(path); -} - -void StatusNotifierItem::setIconByName(const QString &name) -{ - if (mIconName == name) - return; - - mIconName = name; - Q_EMIT mAdaptor->NewIcon(); -} - -void StatusNotifierItem::setIconByPixmap(const QIcon &icon) -{ - if (mIconCacheKey == icon.cacheKey()) - return; - - mIconCacheKey = icon.cacheKey(); - mIcon = iconToPixmapList(icon); - mIconName.clear(); - Q_EMIT mAdaptor->NewIcon(); -} - -void StatusNotifierItem::setOverlayIconByName(const QString &name) -{ - if (mOverlayIconName == name) - return; - - mOverlayIconName = name; - Q_EMIT mAdaptor->NewOverlayIcon(); -} - -void StatusNotifierItem::setOverlayIconByPixmap(const QIcon &icon) -{ - if (mOverlayIconCacheKey == icon.cacheKey()) - return; - - mOverlayIconCacheKey = icon.cacheKey(); - mOverlayIcon = iconToPixmapList(icon); - mOverlayIconName.clear(); - Q_EMIT mAdaptor->NewOverlayIcon(); -} - -void StatusNotifierItem::setAttentionIconByName(const QString &name) -{ - if (mAttentionIconName == name) - return; - - mAttentionIconName = name; - Q_EMIT mAdaptor->NewAttentionIcon(); -} - -void StatusNotifierItem::setAttentionIconByPixmap(const QIcon &icon) -{ - if (mAttentionIconCacheKey == icon.cacheKey()) - return; - - mAttentionIconCacheKey = icon.cacheKey(); - mAttentionIcon = iconToPixmapList(icon); - mAttentionIconName.clear(); - Q_EMIT mAdaptor->NewAttentionIcon(); -} - -void StatusNotifierItem::setToolTipTitle(const QString &title) -{ - if (mTooltipTitle == title) - return; - - mTooltipTitle = title; - Q_EMIT mAdaptor->NewToolTip(); -} - -void StatusNotifierItem::setToolTipSubTitle(const QString &subTitle) -{ - if (mTooltipSubtitle == subTitle) - return; - - mTooltipSubtitle = subTitle; - Q_EMIT mAdaptor->NewToolTip(); -} - -void StatusNotifierItem::setToolTipIconByName(const QString &name) -{ - if (mTooltipIconName == name) - return; - - mTooltipIconName = name; - Q_EMIT mAdaptor->NewToolTip(); -} - -void StatusNotifierItem::setToolTipIconByPixmap(const QIcon &icon) -{ - if (mTooltipIconCacheKey == icon.cacheKey()) - return; - - mTooltipIconCacheKey = icon.cacheKey(); - mTooltipIcon = iconToPixmapList(icon); - mTooltipIconName.clear(); - Q_EMIT mAdaptor->NewToolTip(); -} - -void StatusNotifierItem::setContextMenu(QMenu* menu) -{ - if (mMenu == menu) - return; - - if (nullptr != mMenu) - { - disconnect(mMenu, &QObject::destroyed, this, &StatusNotifierItem::onMenuDestroyed); - } - mMenu = menu; - - if (nullptr != mMenu) - setMenuPath(QLatin1String("/MenuBar")); - else - setMenuPath(QLatin1String("/NO_DBUSMENU")); - - //Note: we need to destroy menu exporter before creating new one -> to free the DBus object path for new menu - delete mMenuExporter; - if (nullptr != mMenu) - { - connect(mMenu, &QObject::destroyed, this, &StatusNotifierItem::onMenuDestroyed); - mMenuExporter = new DBusMenuExporter{this->menu().path(), mMenu, mSessionBus}; - } -} - -void StatusNotifierItem::Activate(int x, int y) -{ - if (mStatus == QLatin1String("NeedsAttention")) - mStatus = QLatin1String("Active"); - - Q_EMIT activateRequested(QPoint(x, y)); -} - -void StatusNotifierItem::SecondaryActivate(int x, int y) -{ - if (mStatus == QLatin1String("NeedsAttention")) - mStatus = QLatin1String("Active"); - - Q_EMIT secondaryActivateRequested(QPoint(x, y)); -} - -void StatusNotifierItem::ContextMenu(int x, int y) -{ - if (mMenu != nullptr) - { - if (mMenu->isVisible()) - mMenu->popup(QPoint(x, y)); - else - mMenu->hide(); - } -} - -void StatusNotifierItem::Scroll(int delta, const QString &orientation) -{ - Qt::Orientation orient = Qt::Vertical; - if (orientation.toLower() == QLatin1String("horizontal")) - orient = Qt::Horizontal; - - Q_EMIT scrollRequested(delta, orient); -} - -void StatusNotifierItem::showMessage(const QString& title, const QString& msg, - const QString& iconName, int secs) -{ - QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.Notifications"), - QLatin1String("/org/freedesktop/Notifications"), - QLatin1String("org.freedesktop.Notifications"), - QLatin1String("Notify")); - - message.setArguments({ - mTitle, - (uint) 0, - iconName, - title, - msg, - QStringList(), - QVariantMap(), - secs - }); - - mSessionBus.send(message); -} - -IconPixmapList StatusNotifierItem::iconToPixmapList(const QIcon& icon) -{ - IconPixmapList pixmapList; - - // long live KDE! - const QList sizes = icon.availableSizes(); - for (const QSize &size : sizes) - { - QImage image = icon.pixmap(size).toImage(); - - IconPixmap pix; - pix.height = image.height(); - pix.width = image.width(); - - if (image.format() != QImage::Format_ARGB32) - image = image.convertToFormat(QImage::Format_ARGB32); - - pix.bytes = QByteArray((char *) image.bits(), image.sizeInBytes()); - - // swap to network byte order if we are little endian - if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) - { - quint32 *uintBuf = (quint32 *) pix.bytes.data(); - for (uint i = 0; i < pix.bytes.size() / sizeof(quint32); ++i) - { - *uintBuf = qToBigEndian(*uintBuf); - ++uintBuf; - } - } - - pixmapList.append(pix); - } - - return pixmapList; -} diff --git a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h b/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h deleted file mode 100644 index 60739ea53..000000000 --- a/Telegram/ThirdParty/statusnotifieritem/statusnotifieritem.h +++ /dev/null @@ -1,191 +0,0 @@ -/* BEGIN_COMMON_COPYRIGHT_HEADER - * (c)LGPL2+ - * - * LXQt - a lightweight, Qt based, desktop toolset - * https://lxqt.org/ - * - * Copyright: 2015 LXQt team - * Authors: - * Paulo Lieuthier - * - * This program or library is free software; you can redistribute it - * and/or modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - * - * END_COMMON_COPYRIGHT_HEADER */ - - -#ifndef STATUS_NOTIFIER_ITEM_H -#define STATUS_NOTIFIER_ITEM_H - -#include -#include -#include -#include - -#include "dbustypes.h" - -class StatusNotifierItemAdaptor; -class DBusMenuExporter; - -class StatusNotifierItem : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QString Category READ category) - Q_PROPERTY(QString Title READ title) - Q_PROPERTY(QString Id READ id) - Q_PROPERTY(QString Status READ status) - Q_PROPERTY(QDBusObjectPath Menu READ menu) - - Q_PROPERTY(QString IconName READ iconName) - Q_PROPERTY(IconPixmapList IconPixmap READ iconPixmap) - - Q_PROPERTY(QString OverlayIconName READ overlayIconName) - Q_PROPERTY(IconPixmapList OverlayIconPixmap READ overlayIconPixmap) - - Q_PROPERTY(QString AttentionIconName READ attentionIconName) - Q_PROPERTY(IconPixmapList AttentionIconPixmap READ attentionIconPixmap) - - Q_PROPERTY(ToolTip ToolTip READ toolTip) - -public: - StatusNotifierItem(QString id, QObject *parent = nullptr); - ~StatusNotifierItem() override; - - QString id() const - { return mId; } - - QString title() const - { return mTitle; } - void setTitle(const QString &title); - - QString status() const - { return mStatus; } - void setStatus(const QString &status); - - QString category() const - { return mCategory; } - void setCategory(const QString &category); - - QDBusObjectPath menu() const - { return mMenuPath; } - void setMenuPath(const QString &path); - - QString iconName() const - { return mIconName; } - void setIconByName(const QString &name); - - IconPixmapList iconPixmap() const - { return mIcon; } - void setIconByPixmap(const QIcon &icon); - - QString overlayIconName() const - { return mOverlayIconName; } - void setOverlayIconByName(const QString &name); - - IconPixmapList overlayIconPixmap() const - { return mOverlayIcon; } - void setOverlayIconByPixmap(const QIcon &icon); - - QString attentionIconName() const - { return mAttentionIconName; } - void setAttentionIconByName(const QString &name); - - IconPixmapList attentionIconPixmap() const - { return mAttentionIcon; } - void setAttentionIconByPixmap(const QIcon &icon); - - QString toolTipTitle() const - { return mTooltipTitle; } - void setToolTipTitle(const QString &title); - - QString toolTipSubTitle() const - { return mTooltipSubtitle; } - void setToolTipSubTitle(const QString &subTitle); - - QString toolTipIconName() const - { return mTooltipIconName; } - void setToolTipIconByName(const QString &name); - - IconPixmapList toolTipIconPixmap() const - { return mTooltipIcon; } - void setToolTipIconByPixmap(const QIcon &icon); - - ToolTip toolTip() const - { - ToolTip tt; - tt.title = mTooltipTitle; - tt.description = mTooltipSubtitle; - tt.iconName = mTooltipIconName; - tt.iconPixmap = mTooltipIcon; - return tt; - } - - /*! - * \Note: we don't take ownership for the \param menu - */ - void setContextMenu(QMenu *menu); - -public Q_SLOTS: - void Activate(int x, int y); - void SecondaryActivate(int x, int y); - void ContextMenu(int x, int y); - void Scroll(int delta, const QString &orientation); - - void showMessage(const QString &title, const QString &msg, const QString &iconName, int secs); - -private: - void registerToHost(); - IconPixmapList iconToPixmapList(const QIcon &icon); - -private Q_SLOTS: - void onServiceOwnerChanged(const QString &service, const QString &oldOwner, - const QString &newOwner); - void onMenuDestroyed(); - -Q_SIGNALS: - void activateRequested(const QPoint &pos); - void secondaryActivateRequested(const QPoint &pos); - void scrollRequested(int delta, Qt::Orientation orientation); - -private: - StatusNotifierItemAdaptor *mAdaptor; - - QString mService; - QString mId; - QString mTitle; - QString mStatus; - QString mCategory; - - // icons - QString mIconName, mOverlayIconName, mAttentionIconName; - IconPixmapList mIcon, mOverlayIcon, mAttentionIcon; - qint64 mIconCacheKey, mOverlayIconCacheKey, mAttentionIconCacheKey; - - // tooltip - QString mTooltipTitle, mTooltipSubtitle, mTooltipIconName; - IconPixmapList mTooltipIcon; - qint64 mTooltipIconCacheKey; - - // menu - QMenu *mMenu; - QDBusObjectPath mMenuPath; - DBusMenuExporter *mMenuExporter; - QDBusConnection mSessionBus; - - static int mServiceCounter; -}; - -#endif