From c06cdda15fb8efd77b58593489882dbcbe5624e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rodr=C3=ADguez?= Date: Sun, 10 Jan 2021 20:31:56 +0700 Subject: [PATCH] Ubuntu Tray Icon at Start Up (#6889) * refactored and setup retries * undoing suggested change, due to older qt on CI * ensuring a fresh connection for checking tray icon * cleaning debug messages * Update ChangeLog * removed unneeded include * incorporating suggestions * incorporated SonarCloud suggestions, changed timer * additional suggestion -applied on legacy base * added a const version of appConfig --- ChangeLog | 1 + src/gui/src/MainWindow.cpp | 52 +++++++++++++---------------------- src/gui/src/MainWindow.h | 11 ++++---- src/gui/src/ScreenSetupView.h | 14 +++++----- src/gui/src/TrayIcon.cpp | 19 +++++++++++++ src/gui/src/TrayIcon.h | 45 ++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 src/gui/src/TrayIcon.cpp create mode 100644 src/gui/src/TrayIcon.h diff --git a/ChangeLog b/ChangeLog index ef5f6cee2..0e4c5e57c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ v1.13.1-snapshot =========== +- #6889 Systray Icon on Ubuntu Auto Start (take 2) =========== v1.13.0-stable diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 728d7c50d..e1a06ddf8 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -19,7 +19,7 @@ #define DOWNLOAD_URL "http://symless.com/?source=gui" #define HELP_URL "http://symless.com/help?source=gui" -#include +#include #include "MainWindow.h" @@ -112,8 +112,6 @@ MainWindow::MainWindow (AppConfig& appConfig, m_pSynergy(NULL), m_SynergyState(synergyDisconnected), m_ServerConfig(5, 3, m_AppConfig->screenName(), this), - m_pTrayIcon(NULL), - m_pTrayIconMenu(NULL), m_AlreadyHidden(false), m_pMenuBar(NULL), m_pMenuFile(NULL), @@ -228,7 +226,20 @@ MainWindow::~MainWindow() void MainWindow::open() { - createTrayIcon(); + std::array trayMenu = { + m_pActionStartSynergy, + m_pActionStopSynergy, + nullptr, + m_pActionMinimize, + m_pActionRestore, + nullptr, + m_pActionQuit + }; + + m_trayIcon.create(trayMenu, [this](QObject const *o, const char *s) { + connect(o, s, this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); + setIcon(synergyDisconnected); + }); if (appConfig().getAutoHide()) { hide(); @@ -251,31 +262,6 @@ void MainWindow::setStatus(const QString &status) m_pStatusLabel->setText(status); } -void MainWindow::createTrayIcon() -{ - m_pTrayIconMenu = new QMenu(this); - - m_pTrayIconMenu->addAction(m_pActionStartSynergy); - m_pTrayIconMenu->addAction(m_pActionStopSynergy); - m_pTrayIconMenu->addSeparator(); - - m_pTrayIconMenu->addAction(m_pActionMinimize); - m_pTrayIconMenu->addAction(m_pActionRestore); - m_pTrayIconMenu->addSeparator(); - m_pTrayIconMenu->addAction(m_pActionQuit); - - m_pTrayIcon = new QSystemTrayIcon(this); - m_pTrayIcon->setContextMenu(m_pTrayIconMenu); - m_pTrayIcon->setToolTip("Synergy"); - - connect(m_pTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), - this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); - - setIcon(synergyDisconnected); - - m_pTrayIcon->show(); -} - void MainWindow::retranslateMenuBar() { m_pMenuFile->setTitle(tr("&File")); @@ -366,7 +352,8 @@ void MainWindow::zeroConfToggled() { updateAutoConfigWidgets(); #endif } -void MainWindow::setIcon(qSynergyState state) + +void MainWindow::setIcon(qSynergyState state) const { QIcon icon; @@ -379,8 +366,7 @@ void MainWindow::setIcon(qSynergyState state) icon.addFile(synergyDefaultIconFiles[state]); #endif - if (m_pTrayIcon) - m_pTrayIcon->setIcon(icon); + m_trayIcon.set(icon); } void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) @@ -847,7 +833,7 @@ QString MainWindow::configFilename() return filename; } -QString MainWindow::address() +QString MainWindow::address() const { QString i = appConfig().networkInterface(); return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port()); diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index ae0e72f61..cb626f08f 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "ui_MainWindowBase.h" @@ -34,7 +35,7 @@ #include "ActivationDialog.h" #include "ConfigWriter.h" -#include +#include "TrayIcon.h" class QAction; class QMenu; @@ -108,7 +109,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase int synergyState() const { return m_SynergyState; } QString hostname() const { return m_pLineEditHostname->text(); } QString configFilename(); - QString address(); + QString address() const; QString appPath(const QString& name); void open(); void clearLog(); @@ -166,6 +167,7 @@ public slots: // TODO This should be properly using the ConfigWriter system. QSettings& settings() { return GUI::Config::ConfigWriter::make()->settings(); } AppConfig& appConfig() { return *m_AppConfig; } + AppConfig const& appConfig() const { return *m_AppConfig; } QProcess* synergyProcess() { return m_pSynergy; } void setSynergyProcess(QProcess* p) { m_pSynergy = p; } void initConnections(); @@ -173,7 +175,7 @@ public slots: void createStatusBar(); void createTrayIcon(); void loadSettings(); - void setIcon(qSynergyState state); + void setIcon(qSynergyState state) const; void setSynergyState(qSynergyState state); bool checkForApp(int which, QString& app); bool clientArgs(QStringList& args, QString& app); @@ -221,8 +223,6 @@ public slots: QProcess* m_pSynergy; int m_SynergyState; ServerConfig m_ServerConfig; - QSystemTrayIcon* m_pTrayIcon; - QMenu* m_pTrayIconMenu; bool m_AlreadyHidden; VersionChecker m_VersionChecker; IpcClient m_IpcClient; @@ -232,6 +232,7 @@ public slots: QMenu* m_pMenuWindow; QMenu* m_pMenuHelp; QAbstractButton* m_pCancelButton; + TrayIcon m_trayIcon; qRuningState m_ExpectedRunningState; QMutex m_StopDesktopMutex; SslCertificate* m_pSslCertificate; diff --git a/src/gui/src/ScreenSetupView.h b/src/gui/src/ScreenSetupView.h index 38eae2a4f..865a6c558 100644 --- a/src/gui/src/ScreenSetupView.h +++ b/src/gui/src/ScreenSetupView.h @@ -43,14 +43,14 @@ class ScreenSetupView : public QTableView ScreenSetupModel* model() const; protected: - void mouseDoubleClickEvent(QMouseEvent*); + void mouseDoubleClickEvent(QMouseEvent*) override; void setTableSize(); - void resizeEvent(QResizeEvent*); - void dragEnterEvent(QDragEnterEvent* event); - void dragMoveEvent(QDragMoveEvent* event); - void startDrag(Qt::DropActions supportedActions); - QStyleOptionViewItem viewOptions() const; - void scrollTo(const QModelIndex&, ScrollHint) {} + void resizeEvent(QResizeEvent*) override; + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void startDrag(Qt::DropActions supportedActions) override; + QStyleOptionViewItem viewOptions() const override; + void scrollTo(const QModelIndex&, ScrollHint) override {} }; #endif diff --git a/src/gui/src/TrayIcon.cpp b/src/gui/src/TrayIcon.cpp new file mode 100644 index 000000000..aa494bd8c --- /dev/null +++ b/src/gui/src/TrayIcon.cpp @@ -0,0 +1,19 @@ +#include "TrayIcon.h" + +void TrayIcon::tryCreate() const +{ + QSystemTrayIcon trayIcon; // by creating a new tray icon, we actually make the DBus implementation refresh the connection (DBus) + trayIcon.hide(); // we ony hide it in order for the compiler to not optimise-out the object (make some use of it) + if (QSystemTrayIcon::isSystemTrayAvailable()) { // this ends up calling the underlying DBus connection (on DBus) + m_pTrayIcon->show(); + m_connector(m_pTrayIcon.get(), SIGNAL(activated(QSystemTrayIcon::ActivationReason))); + } + else { + QTimer::singleShot(2500, this, &TrayIcon::tryCreate); + } +} + +void TrayIcon::set(const QIcon& icon) const +{ + m_pTrayIcon->setIcon(icon); +} diff --git a/src/gui/src/TrayIcon.h b/src/gui/src/TrayIcon.h new file mode 100644 index 000000000..c708270c8 --- /dev/null +++ b/src/gui/src/TrayIcon.h @@ -0,0 +1,45 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +class TrayIcon : public QObject +{ + Q_OBJECT +public: + using TConnector = std::function; + + template + void create(TActionContainer const &actionContainer, TConnector const &connector) + { + m_connector = connector; + m_pTrayIconMenu = std::make_unique(); + + for (auto action: actionContainer) { + if (action) { + m_pTrayIconMenu->addAction(action); + } + else { + m_pTrayIconMenu->addSeparator(); + } + } + + m_pTrayIcon = std::make_unique(); + m_pTrayIcon->setContextMenu(m_pTrayIconMenu.get()); + m_pTrayIcon->setToolTip("Synergy"); + + tryCreate(); + } + + void tryCreate() const; + + void set(const QIcon& icon) const; + +private: + std::unique_ptr m_pTrayIcon {}; + std::unique_ptr m_pTrayIconMenu {}; + TConnector m_connector; +};