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 <iostream> unneeded include

* incorporating suggestions

* incorporated SonarCloud suggestions, changed timer

* additional suggestion -applied on legacy base

* added a const version of appConfig
This commit is contained in:
Ignacio Rodríguez 2021-01-10 20:31:56 +07:00 committed by GitHub
parent 30b2fdc4e3
commit c06cdda15f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 45 deletions

View file

@ -1,5 +1,6 @@
v1.13.1-snapshot v1.13.1-snapshot
=========== ===========
- #6889 Systray Icon on Ubuntu Auto Start (take 2)
=========== ===========
v1.13.0-stable v1.13.0-stable

View file

@ -19,7 +19,7 @@
#define DOWNLOAD_URL "http://symless.com/?source=gui" #define DOWNLOAD_URL "http://symless.com/?source=gui"
#define HELP_URL "http://symless.com/help?source=gui" #define HELP_URL "http://symless.com/help?source=gui"
#include <iostream> #include <array>
#include "MainWindow.h" #include "MainWindow.h"
@ -112,8 +112,6 @@ MainWindow::MainWindow (AppConfig& appConfig,
m_pSynergy(NULL), m_pSynergy(NULL),
m_SynergyState(synergyDisconnected), m_SynergyState(synergyDisconnected),
m_ServerConfig(5, 3, m_AppConfig->screenName(), this), m_ServerConfig(5, 3, m_AppConfig->screenName(), this),
m_pTrayIcon(NULL),
m_pTrayIconMenu(NULL),
m_AlreadyHidden(false), m_AlreadyHidden(false),
m_pMenuBar(NULL), m_pMenuBar(NULL),
m_pMenuFile(NULL), m_pMenuFile(NULL),
@ -228,7 +226,20 @@ MainWindow::~MainWindow()
void MainWindow::open() void MainWindow::open()
{ {
createTrayIcon(); std::array<QAction *, 7> 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()) { if (appConfig().getAutoHide()) {
hide(); hide();
@ -251,31 +262,6 @@ void MainWindow::setStatus(const QString &status)
m_pStatusLabel->setText(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() void MainWindow::retranslateMenuBar()
{ {
m_pMenuFile->setTitle(tr("&File")); m_pMenuFile->setTitle(tr("&File"));
@ -366,7 +352,8 @@ void MainWindow::zeroConfToggled() {
updateAutoConfigWidgets(); updateAutoConfigWidgets();
#endif #endif
} }
void MainWindow::setIcon(qSynergyState state)
void MainWindow::setIcon(qSynergyState state) const
{ {
QIcon icon; QIcon icon;
@ -379,8 +366,7 @@ void MainWindow::setIcon(qSynergyState state)
icon.addFile(synergyDefaultIconFiles[state]); icon.addFile(synergyDefaultIconFiles[state]);
#endif #endif
if (m_pTrayIcon) m_trayIcon.set(icon);
m_pTrayIcon->setIcon(icon);
} }
void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
@ -847,7 +833,7 @@ QString MainWindow::configFilename()
return filename; return filename;
} }
QString MainWindow::address() QString MainWindow::address() const
{ {
QString i = appConfig().networkInterface(); QString i = appConfig().networkInterface();
return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port()); return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port());

View file

@ -23,6 +23,7 @@
#include <QSettings> #include <QSettings>
#include <QProcess> #include <QProcess>
#include <QThread> #include <QThread>
#include <QMutex>
#include "ui_MainWindowBase.h" #include "ui_MainWindowBase.h"
@ -34,7 +35,7 @@
#include "ActivationDialog.h" #include "ActivationDialog.h"
#include "ConfigWriter.h" #include "ConfigWriter.h"
#include <QMutex> #include "TrayIcon.h"
class QAction; class QAction;
class QMenu; class QMenu;
@ -108,7 +109,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
int synergyState() const { return m_SynergyState; } int synergyState() const { return m_SynergyState; }
QString hostname() const { return m_pLineEditHostname->text(); } QString hostname() const { return m_pLineEditHostname->text(); }
QString configFilename(); QString configFilename();
QString address(); QString address() const;
QString appPath(const QString& name); QString appPath(const QString& name);
void open(); void open();
void clearLog(); void clearLog();
@ -166,6 +167,7 @@ public slots:
// TODO This should be properly using the ConfigWriter system. // TODO This should be properly using the ConfigWriter system.
QSettings& settings() { return GUI::Config::ConfigWriter::make()->settings(); } QSettings& settings() { return GUI::Config::ConfigWriter::make()->settings(); }
AppConfig& appConfig() { return *m_AppConfig; } AppConfig& appConfig() { return *m_AppConfig; }
AppConfig const& appConfig() const { return *m_AppConfig; }
QProcess* synergyProcess() { return m_pSynergy; } QProcess* synergyProcess() { return m_pSynergy; }
void setSynergyProcess(QProcess* p) { m_pSynergy = p; } void setSynergyProcess(QProcess* p) { m_pSynergy = p; }
void initConnections(); void initConnections();
@ -173,7 +175,7 @@ public slots:
void createStatusBar(); void createStatusBar();
void createTrayIcon(); void createTrayIcon();
void loadSettings(); void loadSettings();
void setIcon(qSynergyState state); void setIcon(qSynergyState state) const;
void setSynergyState(qSynergyState state); void setSynergyState(qSynergyState state);
bool checkForApp(int which, QString& app); bool checkForApp(int which, QString& app);
bool clientArgs(QStringList& args, QString& app); bool clientArgs(QStringList& args, QString& app);
@ -221,8 +223,6 @@ public slots:
QProcess* m_pSynergy; QProcess* m_pSynergy;
int m_SynergyState; int m_SynergyState;
ServerConfig m_ServerConfig; ServerConfig m_ServerConfig;
QSystemTrayIcon* m_pTrayIcon;
QMenu* m_pTrayIconMenu;
bool m_AlreadyHidden; bool m_AlreadyHidden;
VersionChecker m_VersionChecker; VersionChecker m_VersionChecker;
IpcClient m_IpcClient; IpcClient m_IpcClient;
@ -232,6 +232,7 @@ public slots:
QMenu* m_pMenuWindow; QMenu* m_pMenuWindow;
QMenu* m_pMenuHelp; QMenu* m_pMenuHelp;
QAbstractButton* m_pCancelButton; QAbstractButton* m_pCancelButton;
TrayIcon m_trayIcon;
qRuningState m_ExpectedRunningState; qRuningState m_ExpectedRunningState;
QMutex m_StopDesktopMutex; QMutex m_StopDesktopMutex;
SslCertificate* m_pSslCertificate; SslCertificate* m_pSslCertificate;

View file

@ -43,14 +43,14 @@ class ScreenSetupView : public QTableView
ScreenSetupModel* model() const; ScreenSetupModel* model() const;
protected: protected:
void mouseDoubleClickEvent(QMouseEvent*); void mouseDoubleClickEvent(QMouseEvent*) override;
void setTableSize(); void setTableSize();
void resizeEvent(QResizeEvent*); void resizeEvent(QResizeEvent*) override;
void dragEnterEvent(QDragEnterEvent* event); void dragEnterEvent(QDragEnterEvent* event) override;
void dragMoveEvent(QDragMoveEvent* event); void dragMoveEvent(QDragMoveEvent* event) override;
void startDrag(Qt::DropActions supportedActions); void startDrag(Qt::DropActions supportedActions) override;
QStyleOptionViewItem viewOptions() const; QStyleOptionViewItem viewOptions() const override;
void scrollTo(const QModelIndex&, ScrollHint) {} void scrollTo(const QModelIndex&, ScrollHint) override {}
}; };
#endif #endif

19
src/gui/src/TrayIcon.cpp Normal file
View file

@ -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);
}

45
src/gui/src/TrayIcon.h Normal file
View file

@ -0,0 +1,45 @@
#pragma once
#include <QObject>
#include <QTimer>
#include <QSystemTrayIcon>
#include <QMenu>
#include <functional>
#include <memory>
class TrayIcon : public QObject
{
Q_OBJECT
public:
using TConnector = std::function<void(QObject const *, const char *)>;
template<typename TActionContainer>
void create(TActionContainer const &actionContainer, TConnector const &connector)
{
m_connector = connector;
m_pTrayIconMenu = std::make_unique<QMenu>();
for (auto action: actionContainer) {
if (action) {
m_pTrayIconMenu->addAction(action);
}
else {
m_pTrayIconMenu->addSeparator();
}
}
m_pTrayIcon = std::make_unique<QSystemTrayIcon>();
m_pTrayIcon->setContextMenu(m_pTrayIconMenu.get());
m_pTrayIcon->setToolTip("Synergy");
tryCreate();
}
void tryCreate() const;
void set(const QIcon& icon) const;
private:
std::unique_ptr<QSystemTrayIcon> m_pTrayIcon {};
std::unique_ptr<QMenu> m_pTrayIconMenu {};
TConnector m_connector;
};