mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-23 02:00:20 +07:00
ref code sort files
This commit is contained in:
@@ -268,6 +268,9 @@ if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
|||||||
${CLIENT_ROOT_DIR}/core/utils/ipcClient.h
|
${CLIENT_ROOT_DIR}/core/utils/ipcClient.h
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.h
|
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.h
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.h
|
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayIconBackend.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/platformTrayTheme.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayIconCommon.h
|
||||||
${CLIENT_ROOT_DIR}/core/protocols/openVpnProtocol.h
|
${CLIENT_ROOT_DIR}/core/protocols/openVpnProtocol.h
|
||||||
${CLIENT_ROOT_DIR}/core/protocols/wireGuardProtocol.h
|
${CLIENT_ROOT_DIR}/core/protocols/wireGuardProtocol.h
|
||||||
${CLIENT_ROOT_DIR}/core/protocols/xrayProtocol.h
|
${CLIENT_ROOT_DIR}/core/protocols/xrayProtocol.h
|
||||||
@@ -280,11 +283,24 @@ if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
|||||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.cpp
|
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.cpp
|
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/platformTrayTheme.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayIconCommon.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/protocols/openVpnProtocol.cpp
|
${CLIENT_ROOT_DIR}/core/protocols/openVpnProtocol.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/protocols/wireGuardProtocol.cpp
|
${CLIENT_ROOT_DIR}/core/protocols/wireGuardProtocol.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/protocols/xrayProtocol.cpp
|
${CLIENT_ROOT_DIR}/core/protocols/xrayProtocol.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/protocols/awgProtocol.cpp
|
${CLIENT_ROOT_DIR}/core/protocols/awgProtocol.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(APPLE AND NOT MACOS_NE)
|
||||||
|
set(HEADERS ${HEADERS}
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/mactrayiconbackend.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/mactraytheme.h
|
||||||
|
)
|
||||||
|
set(SOURCES ${SOURCES}
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/mactrayiconbackend.mm
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/mactraytheme.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE AND MACOS_NE)
|
if(APPLE AND MACOS_NE)
|
||||||
@@ -292,28 +308,49 @@ if(APPLE AND MACOS_NE)
|
|||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.h
|
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.h
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.h
|
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayIconBackend.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/platformTrayTheme.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayIconCommon.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintrayiconbackend.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintraytheme.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayThemeChangeFilter.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.cpp
|
${CLIENT_ROOT_DIR}/ui/utils/systemTrayNotificationHandler.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.cpp
|
${CLIENT_ROOT_DIR}/ui/utils/platformTheme.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/platformTrayTheme.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayIconCommon.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintrayiconbackend.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintraytheme.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayThemeChangeFilter.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CLIENT_ROOT_DIR}/platforms/windows/windowsutils.h
|
${CLIENT_ROOT_DIR}/platforms/windows/windowsutils.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintrayiconbackend.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintraytheme.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayThemeChangeFilter.h
|
||||||
)
|
)
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/platforms/windows/windowsutils.cpp
|
${CLIENT_ROOT_DIR}/platforms/windows/windowsutils.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintrayiconbackend.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/wintraytheme.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/ui/utils/trayThemeChangeFilter.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(LINUX)
|
if(LINUX)
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CLIENT_ROOT_DIR}/platforms/linux/linuxutils.h
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxutils.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxtrayiconbackend.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxtraytheme.h
|
||||||
)
|
)
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/platforms/linux/linuxutils.cpp
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxutils.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxtrayiconbackend.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxtraytheme.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include "linuxtrayiconbackend.h"
|
||||||
|
|
||||||
|
#include "ui/utils/trayIconCommon.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr int kLinuxTrayIconSizes[] = { 16, 22, 24, 32, 48, 64, 128 };
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
LinuxTrayIconBackend::LinuxTrayIconBackend(QObject *parent) : m_trayIcon(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxTrayIconBackend::setMenu(QMenu *menu)
|
||||||
|
{
|
||||||
|
m_trayIcon.setContextMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxTrayIconBackend::setToolTip(const QString &tooltip)
|
||||||
|
{
|
||||||
|
m_trayIcon.setToolTip(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxTrayIconBackend::show()
|
||||||
|
{
|
||||||
|
m_trayIcon.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxTrayIconBackend::applyVisual(const TrayIconVisual &visual)
|
||||||
|
{
|
||||||
|
const qreal opacity = TrayIconCommon::opacityForState(visual.connectionState);
|
||||||
|
const QColor indicatorColor = TrayIconCommon::indicatorColorForState(visual.connectionState);
|
||||||
|
m_trayIcon.setIcon(buildTrayIcon(opacity, visual.darkTheme, indicatorColor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxTrayIconBackend::showMessage(const QString &title, const QString &message, const TrayIconVisual &visual,
|
||||||
|
int timerMsec)
|
||||||
|
{
|
||||||
|
m_trayIcon.showMessage(title, message,
|
||||||
|
buildTrayIcon(TrayIconCommon::kConnectedOpacity, visual.darkTheme,
|
||||||
|
TrayIconCommon::indicatorColorForState(Vpn::ConnectionState::Connected)),
|
||||||
|
timerMsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxTrayIconBackend::rebuildMenu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxTrayIconBackend::setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler)
|
||||||
|
{
|
||||||
|
if (!handler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(&m_trayIcon, &QSystemTrayIcon::activated, m_trayIcon.parent(),
|
||||||
|
[handler](QSystemTrayIcon::ActivationReason reason) { handler(reason); });
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon LinuxTrayIconBackend::buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) const
|
||||||
|
{
|
||||||
|
QIcon icon;
|
||||||
|
for (int size : kLinuxTrayIconSizes) {
|
||||||
|
icon.addPixmap(TrayIconCommon::buildPixmap(size, opacity, darkTheme, indicatorColor));
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<TrayIconBackend> createTrayIconBackend(QObject *parent)
|
||||||
|
{
|
||||||
|
return std::make_unique<LinuxTrayIconBackend>(parent);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef LINUXTRAYICONBACKEND_H
|
||||||
|
#define LINUXTRAYICONBACKEND_H
|
||||||
|
|
||||||
|
#include "ui/utils/trayIconBackend.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QSystemTrayIcon>
|
||||||
|
|
||||||
|
class LinuxTrayIconBackend final : public TrayIconBackend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LinuxTrayIconBackend(QObject *parent);
|
||||||
|
|
||||||
|
void setMenu(QMenu *menu) override;
|
||||||
|
void setToolTip(const QString &tooltip) override;
|
||||||
|
void show() override;
|
||||||
|
void applyVisual(const TrayIconVisual &visual) override;
|
||||||
|
void showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec) override;
|
||||||
|
void rebuildMenu() override;
|
||||||
|
void setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QIcon buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) const;
|
||||||
|
|
||||||
|
QSystemTrayIcon m_trayIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LINUXTRAYICONBACKEND_H
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "linuxtraytheme.h"
|
||||||
|
|
||||||
|
#include "platforms/linux/linuxutils.h"
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStyleHints>
|
||||||
|
|
||||||
|
void LinuxTrayTheme::installThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent)
|
||||||
|
{
|
||||||
|
if (!onThemeChanged || !parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QStyleHints *styleHints = QGuiApplication::styleHints()) {
|
||||||
|
QObject::connect(styleHints, &QStyleHints::colorSchemeChanged, parent, [onThemeChanged]() { onThemeChanged(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
LinuxUtils::installThemeChangeObserver(onThemeChanged);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef LINUXTRAYTHEME_H
|
||||||
|
#define LINUXTRAYTHEME_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
|
||||||
|
namespace LinuxTrayTheme
|
||||||
|
{
|
||||||
|
|
||||||
|
void installThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent);
|
||||||
|
|
||||||
|
} // namespace LinuxTrayTheme
|
||||||
|
|
||||||
|
#endif // LINUXTRAYTHEME_H
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef MACTRAYICONBACKEND_H
|
||||||
|
#define MACTRAYICONBACKEND_H
|
||||||
|
|
||||||
|
#include "ui/utils/trayIconBackend.h"
|
||||||
|
|
||||||
|
#include "macosstatusicon.h"
|
||||||
|
|
||||||
|
class MacTrayIconBackend final : public TrayIconBackend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MacTrayIconBackend(QObject *parent);
|
||||||
|
|
||||||
|
void setMenu(QMenu *menu) override;
|
||||||
|
void setToolTip(const QString &tooltip) override;
|
||||||
|
void show() override;
|
||||||
|
void applyVisual(const TrayIconVisual &visual) override;
|
||||||
|
void showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec) override;
|
||||||
|
void rebuildMenu() override;
|
||||||
|
void setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MacOSStatusIcon m_statusIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MACTRAYICONBACKEND_H
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include "mactrayiconbackend.h"
|
||||||
|
|
||||||
|
#include "ui/utils/trayIconCommon.h"
|
||||||
|
|
||||||
|
MacTrayIconBackend::MacTrayIconBackend(QObject *parent)
|
||||||
|
: m_statusIcon(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacTrayIconBackend::setMenu(QMenu *menu)
|
||||||
|
{
|
||||||
|
m_statusIcon.setMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacTrayIconBackend::setToolTip(const QString &tooltip)
|
||||||
|
{
|
||||||
|
m_statusIcon.setToolTip(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacTrayIconBackend::show()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacTrayIconBackend::applyVisual(const TrayIconVisual &visual)
|
||||||
|
{
|
||||||
|
const qreal opacity = TrayIconCommon::opacityForState(visual.connectionState);
|
||||||
|
m_statusIcon.setIconFromData(TrayIconCommon::buildTemplatePng(opacity));
|
||||||
|
m_statusIcon.setIndicatorColor(TrayIconCommon::indicatorColorForState(visual.connectionState));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacTrayIconBackend::showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec)
|
||||||
|
{
|
||||||
|
Q_UNUSED(visual);
|
||||||
|
Q_UNUSED(timerMsec);
|
||||||
|
m_statusIcon.showMessage(title, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacTrayIconBackend::rebuildMenu()
|
||||||
|
{
|
||||||
|
m_statusIcon.rebuildNativeMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacTrayIconBackend::setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler)
|
||||||
|
{
|
||||||
|
Q_UNUSED(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<TrayIconBackend> createTrayIconBackend(QObject *parent)
|
||||||
|
{
|
||||||
|
return std::make_unique<MacTrayIconBackend>(parent);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include "mactraytheme.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
void MacTrayTheme::installThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(onThemeChanged);
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
// macOS template tray icons follow the menu bar appearance automatically.
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef MACTRAYTHEME_H
|
||||||
|
#define MACTRAYTHEME_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
|
||||||
|
namespace MacTrayTheme
|
||||||
|
{
|
||||||
|
|
||||||
|
void installThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent);
|
||||||
|
|
||||||
|
} // namespace MacTrayTheme
|
||||||
|
|
||||||
|
#endif // MACTRAYTHEME_H
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#include "wintrayiconbackend.h"
|
||||||
|
|
||||||
|
#include "ui/utils/trayIconCommon.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
WinTrayIconBackend::WinTrayIconBackend(QObject *parent) : m_trayIcon(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinTrayIconBackend::setMenu(QMenu *menu)
|
||||||
|
{
|
||||||
|
m_trayIcon.setContextMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinTrayIconBackend::setToolTip(const QString &tooltip)
|
||||||
|
{
|
||||||
|
m_trayIcon.setToolTip(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinTrayIconBackend::show()
|
||||||
|
{
|
||||||
|
m_trayIcon.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinTrayIconBackend::applyVisual(const TrayIconVisual &visual)
|
||||||
|
{
|
||||||
|
const qreal opacity = TrayIconCommon::opacityForState(visual.connectionState);
|
||||||
|
const QColor indicatorColor = TrayIconCommon::indicatorColorForState(visual.connectionState);
|
||||||
|
m_trayIcon.setIcon(buildTrayIcon(opacity, visual.darkTheme, indicatorColor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinTrayIconBackend::showMessage(const QString &title, const QString &message, const TrayIconVisual &visual,
|
||||||
|
int timerMsec)
|
||||||
|
{
|
||||||
|
m_trayIcon.showMessage(title, message,
|
||||||
|
buildTrayIcon(TrayIconCommon::kConnectedOpacity, visual.darkTheme,
|
||||||
|
TrayIconCommon::indicatorColorForState(Vpn::ConnectionState::Connected)),
|
||||||
|
timerMsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinTrayIconBackend::rebuildMenu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinTrayIconBackend::setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler)
|
||||||
|
{
|
||||||
|
if (!handler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(&m_trayIcon, &QSystemTrayIcon::activated, m_trayIcon.parent(),
|
||||||
|
[handler](QSystemTrayIcon::ActivationReason reason) { handler(reason); });
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon WinTrayIconBackend::buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) const
|
||||||
|
{
|
||||||
|
return TrayIconCommon::buildIcon(opacity, darkTheme, indicatorColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<TrayIconBackend> createTrayIconBackend(QObject *parent)
|
||||||
|
{
|
||||||
|
return std::make_unique<WinTrayIconBackend>(parent);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef WINTRAYICONBACKEND_H
|
||||||
|
#define WINTRAYICONBACKEND_H
|
||||||
|
|
||||||
|
#include "ui/utils/trayIconBackend.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QSystemTrayIcon>
|
||||||
|
|
||||||
|
class WinTrayIconBackend final : public TrayIconBackend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit WinTrayIconBackend(QObject *parent);
|
||||||
|
|
||||||
|
void setMenu(QMenu *menu) override;
|
||||||
|
void setToolTip(const QString &tooltip) override;
|
||||||
|
void show() override;
|
||||||
|
void applyVisual(const TrayIconVisual &visual) override;
|
||||||
|
void showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec) override;
|
||||||
|
void rebuildMenu() override;
|
||||||
|
void setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QIcon buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) const;
|
||||||
|
|
||||||
|
QSystemTrayIcon m_trayIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WINTRAYICONBACKEND_H
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include "wintraytheme.h"
|
||||||
|
|
||||||
|
#include "platforms/windows/windowsutils.h"
|
||||||
|
#include "ui/utils/trayThemeChangeFilter.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStyleHints>
|
||||||
|
|
||||||
|
void WinTrayTheme::installThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent)
|
||||||
|
{
|
||||||
|
if (!onThemeChanged || !parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QStyleHints *styleHints = QGuiApplication::styleHints()) {
|
||||||
|
QObject::connect(styleHints, &QStyleHints::colorSchemeChanged, parent, [onThemeChanged]() { onThemeChanged(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
qApp->installEventFilter(new TrayThemeChangeFilter(onThemeChanged, parent));
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
WindowsUtils::installThemeChangeObserver(onThemeChanged);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef WINTRAYTHEME_H
|
||||||
|
#define WINTRAYTHEME_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
|
||||||
|
namespace WinTrayTheme
|
||||||
|
{
|
||||||
|
|
||||||
|
void installThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent);
|
||||||
|
|
||||||
|
} // namespace WinTrayTheme
|
||||||
|
|
||||||
|
#endif // WINTRAYTHEME_H
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include "platformTrayTheme.h"
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
||||||
|
# include "platforms/macos/mactraytheme.h"
|
||||||
|
#elif defined(Q_OS_WIN) || (defined(Q_OS_MAC) && defined(MACOS_NE))
|
||||||
|
# include "platforms/windows/wintraytheme.h"
|
||||||
|
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
|
# include "platforms/linux/linuxtraytheme.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void installTrayThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent)
|
||||||
|
{
|
||||||
|
if (!onThemeChanged || !parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
||||||
|
MacTrayTheme::installThemeObserver(onThemeChanged, parent);
|
||||||
|
#elif defined(Q_OS_WIN) || (defined(Q_OS_MAC) && defined(MACOS_NE))
|
||||||
|
WinTrayTheme::installThemeObserver(onThemeChanged, parent);
|
||||||
|
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
|
LinuxTrayTheme::installThemeObserver(onThemeChanged, parent);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef PLATFORMTRAYTHEME_H
|
||||||
|
#define PLATFORMTRAYTHEME_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
|
||||||
|
void installTrayThemeObserver(const std::function<void()> &onThemeChanged, QObject *parent);
|
||||||
|
|
||||||
|
#endif // PLATFORMTRAYTHEME_H
|
||||||
@@ -6,162 +6,23 @@
|
|||||||
#include "systemTrayNotificationHandler.h"
|
#include "systemTrayNotificationHandler.h"
|
||||||
|
|
||||||
#include "platformTheme.h"
|
#include "platformTheme.h"
|
||||||
|
#include "platformTrayTheme.h"
|
||||||
|
#include "trayIconBackend.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QBuffer>
|
|
||||||
#include <QColor>
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QGuiApplication>
|
|
||||||
#include <QIcon>
|
|
||||||
#include <QPainter>
|
|
||||||
#include <QStyleHints>
|
|
||||||
#include <QSvgRenderer>
|
|
||||||
#include <QEvent>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
|
||||||
# include "platforms/macos/macosstatusicon.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
# include "platforms/windows/windowsutils.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
|
||||||
# include "platforms/linux/linuxutils.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr int kTrayIconSize = 128;
|
|
||||||
constexpr char kTrayTemplateIconPath[] = ":/images/tray/icon.svg";
|
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
|
||||||
constexpr int kLinuxTrayIconSizes[] = {16, 22, 24, 32, 48, 64, 128};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class TrayThemeChangeFilter final : public QObject {
|
|
||||||
public:
|
|
||||||
explicit TrayThemeChangeFilter(std::function<void()> onThemeChanged, QObject *parent = nullptr)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_onThemeChanged(std::move(onThemeChanged))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool eventFilter(QObject *watched, QEvent *event) override
|
|
||||||
{
|
|
||||||
Q_UNUSED(watched);
|
|
||||||
if (event->type() == QEvent::ApplicationPaletteChange || event->type() == QEvent::ThemeChange) {
|
|
||||||
if (m_onThemeChanged) {
|
|
||||||
m_onThemeChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QObject::eventFilter(watched, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::function<void()> m_onThemeChanged;
|
|
||||||
};
|
|
||||||
|
|
||||||
QPixmap renderTrayTemplate(const QString &resourcePath, qreal opacity, int size)
|
|
||||||
{
|
|
||||||
QSvgRenderer renderer(resourcePath);
|
|
||||||
QPixmap pixmap(size, size);
|
|
||||||
pixmap.fill(Qt::transparent);
|
|
||||||
|
|
||||||
if (!renderer.isValid()) {
|
|
||||||
qWarning() << "Failed to load tray icon template:" << resourcePath;
|
|
||||||
return pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPainter painter(&pixmap);
|
|
||||||
painter.setOpacity(opacity);
|
|
||||||
renderer.render(&painter, QRectF(0, 0, size, size));
|
|
||||||
return pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap colorizeTrayTemplate(const QPixmap &mask, const QColor &foreground, int size)
|
|
||||||
{
|
|
||||||
QPixmap result(size, size);
|
|
||||||
result.fill(Qt::transparent);
|
|
||||||
|
|
||||||
QPainter painter(&result);
|
|
||||||
painter.fillRect(result.rect(), foreground);
|
|
||||||
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
|
||||||
painter.drawPixmap(0, 0, mask);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawStatusIndicator(QPainter &painter, const QColor &color, int size)
|
|
||||||
{
|
|
||||||
const qreal dotSize = size * 0.35;
|
|
||||||
const qreal dotOrigin = (size - dotSize) * 0.8;
|
|
||||||
|
|
||||||
painter.setPen(Qt::NoPen);
|
|
||||||
painter.setBrush(color);
|
|
||||||
painter.drawEllipse(QRectF(dotOrigin, dotOrigin, dotSize, dotSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray renderTrayTemplatePng(qreal opacity)
|
|
||||||
{
|
|
||||||
const QPixmap pixmap = renderTrayTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, kTrayIconSize);
|
|
||||||
|
|
||||||
QByteArray bytes;
|
|
||||||
QBuffer buffer(&bytes);
|
|
||||||
buffer.open(QIODevice::WriteOnly);
|
|
||||||
pixmap.save(&buffer, "PNG");
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap buildTrayPixmap(int size, qreal opacity, bool darkTheme, const QColor &indicatorColor)
|
|
||||||
{
|
|
||||||
const QPixmap mask = renderTrayTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, size);
|
|
||||||
const QColor foreground = darkTheme ? Qt::white : Qt::black;
|
|
||||||
QPixmap pixmap = colorizeTrayTemplate(mask, foreground, size);
|
|
||||||
|
|
||||||
if (indicatorColor.isValid()) {
|
|
||||||
QPainter painter(&pixmap);
|
|
||||||
drawStatusIndicator(painter, indicatorColor, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor)
|
|
||||||
{
|
|
||||||
QIcon icon;
|
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
|
||||||
for (int size : kLinuxTrayIconSizes) {
|
|
||||||
icon.addPixmap(buildTrayPixmap(size, opacity, darkTheme, indicatorColor));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
icon.addPixmap(buildTrayPixmap(kTrayIconSize, opacity, darkTheme, indicatorColor));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) :
|
SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) :
|
||||||
NotificationHandler(parent)
|
NotificationHandler(parent)
|
||||||
#if !defined(Q_OS_MAC) || defined(MACOS_NE)
|
|
||||||
, m_systemTrayIcon(parent)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
m_trayIcon = createTrayIconBackend(this);
|
||||||
m_macStatusIcon = new MacOSStatusIcon(this);
|
m_trayIcon->setMenu(&m_menu);
|
||||||
m_macStatusIcon->setMenu(&m_menu);
|
m_trayIcon->setToolTip(APPLICATION_NAME);
|
||||||
m_macStatusIcon->setToolTip(APPLICATION_NAME);
|
m_trayIcon->setActivatedHandler([this](QSystemTrayIcon::ActivationReason reason) {
|
||||||
// Template NSStatusItem icons follow the menu bar appearance automatically.
|
onTrayActivated(reason);
|
||||||
#else
|
});
|
||||||
connect(&m_systemTrayIcon, &QSystemTrayIcon::activated, this, &SystemTrayNotificationHandler::onTrayActivated);
|
|
||||||
m_systemTrayIcon.setContextMenu(&m_menu);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_trayActionShow = m_menu.addAction(tr("Show") + " " + APPLICATION_NAME, this, [this](){
|
m_trayActionShow = m_menu.addAction(tr("Show") + " " + APPLICATION_NAME, this, [this](){
|
||||||
emit raiseRequested();
|
emit raiseRequested();
|
||||||
@@ -180,42 +41,14 @@ SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) :
|
|||||||
this,
|
this,
|
||||||
[&](){ qApp->quit(); });
|
[&](){ qApp->quit(); });
|
||||||
|
|
||||||
#if !defined(Q_OS_MAC) || defined(MACOS_NE)
|
installTrayThemeObserver([this]() { refreshTheme(); }, this);
|
||||||
if (QStyleHints *styleHints = QGuiApplication::styleHints()) {
|
|
||||||
connect(styleHints, &QStyleHints::colorSchemeChanged, this, [this]() {
|
|
||||||
refreshTheme();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
|
|
||||||
qApp->installEventFilter(new TrayThemeChangeFilter([this]() {
|
|
||||||
refreshTheme();
|
|
||||||
}, this));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
WindowsUtils::installThemeChangeObserver([this]() {
|
|
||||||
refreshTheme();
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
|
||||||
LinuxUtils::installThemeChangeObserver([this]() {
|
|
||||||
refreshTheme();
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_isDarkTheme = platformIsDarkTheme();
|
m_isDarkTheme = platformIsDarkTheme();
|
||||||
setTrayState(Vpn::ConnectionState::Disconnected);
|
setTrayState(Vpn::ConnectionState::Disconnected);
|
||||||
|
m_trayIcon->show();
|
||||||
#if !defined(Q_OS_MAC) || defined(MACOS_NE)
|
|
||||||
m_systemTrayIcon.show();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemTrayNotificationHandler::~SystemTrayNotificationHandler() {
|
SystemTrayNotificationHandler::~SystemTrayNotificationHandler() = default;
|
||||||
}
|
|
||||||
|
|
||||||
void SystemTrayNotificationHandler::setConnectionState(Vpn::ConnectionState state)
|
void SystemTrayNotificationHandler::setConnectionState(Vpn::ConnectionState state)
|
||||||
{
|
{
|
||||||
@@ -229,16 +62,15 @@ void SystemTrayNotificationHandler::onTranslationsUpdated()
|
|||||||
m_trayActionConnect->setText(tr("Connect"));
|
m_trayActionConnect->setText(tr("Connect"));
|
||||||
m_trayActionDisconnect->setText(tr("Disconnect"));
|
m_trayActionDisconnect->setText(tr("Disconnect"));
|
||||||
m_trayActionVisitWebSite->setText(tr("Visit Website"));
|
m_trayActionVisitWebSite->setText(tr("Visit Website"));
|
||||||
m_trayActionQuit->setText(tr("Quit")+ " " + APPLICATION_NAME);
|
m_trayActionQuit->setText(tr("Quit") + " " + APPLICATION_NAME);
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
if (m_trayIcon) {
|
||||||
if (m_macStatusIcon) {
|
m_trayIcon->rebuildMenu();
|
||||||
m_macStatusIcon->rebuildNativeMenu();
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemTrayNotificationHandler::updateWebsiteUrl(const QString &newWebsiteUrl) {
|
void SystemTrayNotificationHandler::updateWebsiteUrl(const QString &newWebsiteUrl)
|
||||||
|
{
|
||||||
qDebug() << "Updated website URL:" << newWebsiteUrl;
|
qDebug() << "Updated website URL:" << newWebsiteUrl;
|
||||||
websiteUrl = newWebsiteUrl;
|
websiteUrl = newWebsiteUrl;
|
||||||
}
|
}
|
||||||
@@ -251,52 +83,24 @@ void SystemTrayNotificationHandler::refreshTheme()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_isDarkTheme = isDarkTheme;
|
m_isDarkTheme = isDarkTheme;
|
||||||
|
|
||||||
#if !defined(Q_OS_MAC) || defined(MACOS_NE)
|
|
||||||
updateTrayIcon();
|
updateTrayIcon();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal SystemTrayNotificationHandler::trayIconOpacityForState(Vpn::ConnectionState state) const
|
TrayIconVisual SystemTrayNotificationHandler::currentTrayVisual() const
|
||||||
{
|
{
|
||||||
switch (state) {
|
TrayIconVisual visual;
|
||||||
case Vpn::ConnectionState::Connected:
|
visual.connectionState = m_trayState;
|
||||||
case Vpn::ConnectionState::Error:
|
visual.darkTheme = m_isDarkTheme;
|
||||||
return kConnectedTrayOpacity;
|
return visual;
|
||||||
case Vpn::ConnectionState::Disconnected:
|
|
||||||
case Vpn::ConnectionState::Preparing:
|
|
||||||
case Vpn::ConnectionState::Connecting:
|
|
||||||
case Vpn::ConnectionState::Disconnecting:
|
|
||||||
case Vpn::ConnectionState::Reconnecting:
|
|
||||||
case Vpn::ConnectionState::Unknown:
|
|
||||||
default:
|
|
||||||
return kDisconnectedTrayOpacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QColor SystemTrayNotificationHandler::trayIndicatorColorForState(Vpn::ConnectionState state) const
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case Vpn::ConnectionState::Connected:
|
|
||||||
return QColor(52, 199, 89);
|
|
||||||
case Vpn::ConnectionState::Error:
|
|
||||||
return QColor(235, 87, 87);
|
|
||||||
default:
|
|
||||||
return QColor();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemTrayNotificationHandler::updateTrayIcon()
|
void SystemTrayNotificationHandler::updateTrayIcon()
|
||||||
{
|
{
|
||||||
const qreal opacity = trayIconOpacityForState(m_trayState);
|
if (!m_trayIcon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
m_trayIcon->applyVisual(currentTrayVisual());
|
||||||
Q_ASSERT(m_macStatusIcon);
|
|
||||||
m_macStatusIcon->setIconFromData(renderTrayTemplatePng(opacity));
|
|
||||||
m_macStatusIcon->setIndicatorColor(trayIndicatorColorForState(m_trayState));
|
|
||||||
#else
|
|
||||||
m_systemTrayIcon.setIcon(buildTrayIcon(opacity, m_isDarkTheme, trayIndicatorColorForState(m_trayState)));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
|
void SystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
|
||||||
@@ -350,44 +154,21 @@ void SystemTrayNotificationHandler::setTrayState(Vpn::ConnectionState state)
|
|||||||
|
|
||||||
updateTrayIcon();
|
updateTrayIcon();
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
if (m_trayIcon) {
|
||||||
if (m_macStatusIcon) {
|
m_trayIcon->rebuildMenu();
|
||||||
m_macStatusIcon->rebuildNativeMenu();
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
|
||||||
template<typename> constexpr auto SystemTrayNotificationHandler::qt_create_metaobjectdata()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemTrayNotificationHandler::notify(NotificationHandler::Message type,
|
void SystemTrayNotificationHandler::notify(NotificationHandler::Message type,
|
||||||
const QString& title,
|
const QString& title,
|
||||||
const QString& message,
|
const QString& message,
|
||||||
int timerMsec) {
|
int timerMsec)
|
||||||
Q_UNUSED(type);
|
{
|
||||||
|
Q_UNUSED(type);
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
if (!m_trayIcon) {
|
||||||
Q_ASSERT(m_macStatusIcon);
|
return;
|
||||||
m_macStatusIcon->showMessage(title, message);
|
}
|
||||||
#else
|
|
||||||
m_systemTrayIcon.showMessage(
|
|
||||||
title, message,
|
|
||||||
buildTrayIcon(kConnectedTrayOpacity, m_isDarkTheme, trayIndicatorColorForState(Vpn::ConnectionState::Connected)),
|
|
||||||
timerMsec);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemTrayNotificationHandler::showHideWindow() {
|
m_trayIcon->showMessage(title, message, currentTrayVisual(), timerMsec);
|
||||||
// QmlEngineHolder* engine = QmlEngineHolder::instance();
|
|
||||||
// if (engine->window()->isVisible()) {
|
|
||||||
// engine->hideWindow();
|
|
||||||
//#ifdef MVPN_MACOS
|
|
||||||
// MacOSUtils::hideDockIcon();
|
|
||||||
//#endif
|
|
||||||
// } else {
|
|
||||||
// engine->showWindow();
|
|
||||||
//#ifdef MVPN_MACOS
|
|
||||||
// MacOSUtils::showDockIcon();
|
|
||||||
//#endif
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,21 +6,19 @@
|
|||||||
#define SYSTEMTRAYNOTIFICATIONHANDLER_H
|
#define SYSTEMTRAYNOTIFICATIONHANDLER_H
|
||||||
|
|
||||||
#include "notificationHandler.h"
|
#include "notificationHandler.h"
|
||||||
|
#include "trayIconBackend.h"
|
||||||
|
|
||||||
#include <QColor>
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QSystemTrayIcon>
|
#include <QSystemTrayIcon>
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
#include <memory>
|
||||||
class MacOSStatusIcon;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class SystemTrayNotificationHandler : public NotificationHandler {
|
class SystemTrayNotificationHandler : public NotificationHandler {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SystemTrayNotificationHandler(QObject* parent);
|
explicit SystemTrayNotificationHandler(QObject* parent);
|
||||||
~SystemTrayNotificationHandler();
|
~SystemTrayNotificationHandler() override;
|
||||||
|
|
||||||
void setConnectionState(Vpn::ConnectionState state) override;
|
void setConnectionState(Vpn::ConnectionState state) override;
|
||||||
|
|
||||||
@@ -30,28 +28,19 @@ public slots:
|
|||||||
void updateWebsiteUrl(const QString &newWebsiteUrl);
|
void updateWebsiteUrl(const QString &newWebsiteUrl);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void notify(Message type, const QString& title,
|
void notify(Message type, const QString& title,
|
||||||
const QString& message, int timerMsec) override;
|
const QString& message, int timerMsec) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void showHideWindow();
|
|
||||||
|
|
||||||
void setTrayState(Vpn::ConnectionState state);
|
void setTrayState(Vpn::ConnectionState state);
|
||||||
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
|
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
|
||||||
|
|
||||||
void refreshTheme();
|
void refreshTheme();
|
||||||
void updateTrayIcon();
|
void updateTrayIcon();
|
||||||
qreal trayIconOpacityForState(Vpn::ConnectionState state) const;
|
TrayIconVisual currentTrayVisual() const;
|
||||||
QColor trayIndicatorColorForState(Vpn::ConnectionState state) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMenu m_menu;
|
QMenu m_menu;
|
||||||
|
std::unique_ptr<TrayIconBackend> m_trayIcon;
|
||||||
#if defined(Q_OS_MAC) && !defined(MACOS_NE)
|
|
||||||
MacOSStatusIcon *m_macStatusIcon = nullptr;
|
|
||||||
#else
|
|
||||||
QSystemTrayIcon m_systemTrayIcon;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QAction* m_trayActionShow = nullptr;
|
QAction* m_trayActionShow = nullptr;
|
||||||
QAction* m_trayActionConnect = nullptr;
|
QAction* m_trayActionConnect = nullptr;
|
||||||
@@ -64,9 +53,6 @@ private:
|
|||||||
Vpn::ConnectionState m_trayState = Vpn::ConnectionState::Unknown;
|
Vpn::ConnectionState m_trayState = Vpn::ConnectionState::Unknown;
|
||||||
bool m_isDarkTheme = false;
|
bool m_isDarkTheme = false;
|
||||||
|
|
||||||
static constexpr qreal kDisconnectedTrayOpacity = 0.5;
|
|
||||||
static constexpr qreal kConnectedTrayOpacity = 1.0;
|
|
||||||
|
|
||||||
QString websiteUrl = "https://amnezia.org";
|
QString websiteUrl = "https://amnezia.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef TRAYICONBACKEND_H
|
||||||
|
#define TRAYICONBACKEND_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QString>
|
||||||
|
#include <QSystemTrayIcon>
|
||||||
|
|
||||||
|
#include "core/protocols/vpnProtocol.h"
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
|
||||||
|
struct TrayIconVisual {
|
||||||
|
Vpn::ConnectionState connectionState = Vpn::ConnectionState::Unknown;
|
||||||
|
bool darkTheme = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TrayIconBackend {
|
||||||
|
public:
|
||||||
|
virtual ~TrayIconBackend() = default;
|
||||||
|
|
||||||
|
virtual void setMenu(QMenu *menu) = 0;
|
||||||
|
virtual void setToolTip(const QString &tooltip) = 0;
|
||||||
|
virtual void show() = 0;
|
||||||
|
virtual void applyVisual(const TrayIconVisual &visual) = 0;
|
||||||
|
virtual void showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec) = 0;
|
||||||
|
virtual void rebuildMenu() = 0;
|
||||||
|
virtual void setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<TrayIconBackend> createTrayIconBackend(QObject *parent);
|
||||||
|
|
||||||
|
#endif // TRAYICONBACKEND_H
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
#include "trayIconCommon.h"
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QSvgRenderer>
|
||||||
|
|
||||||
|
namespace TrayIconCommon {
|
||||||
|
|
||||||
|
qreal opacityForState(Vpn::ConnectionState state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case Vpn::ConnectionState::Connected:
|
||||||
|
case Vpn::ConnectionState::Error:
|
||||||
|
return kConnectedOpacity;
|
||||||
|
case Vpn::ConnectionState::Disconnected:
|
||||||
|
case Vpn::ConnectionState::Preparing:
|
||||||
|
case Vpn::ConnectionState::Connecting:
|
||||||
|
case Vpn::ConnectionState::Disconnecting:
|
||||||
|
case Vpn::ConnectionState::Reconnecting:
|
||||||
|
case Vpn::ConnectionState::Unknown:
|
||||||
|
default:
|
||||||
|
return kDisconnectedOpacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor indicatorColorForState(Vpn::ConnectionState state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case Vpn::ConnectionState::Connected:
|
||||||
|
return QColor(52, 199, 89);
|
||||||
|
case Vpn::ConnectionState::Error:
|
||||||
|
return QColor(235, 87, 87);
|
||||||
|
default:
|
||||||
|
return QColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap renderTemplate(const QString &resourcePath, qreal opacity, int size)
|
||||||
|
{
|
||||||
|
QSvgRenderer renderer(resourcePath);
|
||||||
|
QPixmap pixmap(size, size);
|
||||||
|
pixmap.fill(Qt::transparent);
|
||||||
|
|
||||||
|
if (!renderer.isValid()) {
|
||||||
|
qWarning() << "Failed to load tray icon template:" << resourcePath;
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(&pixmap);
|
||||||
|
painter.setOpacity(opacity);
|
||||||
|
renderer.render(&painter, QRectF(0, 0, size, size));
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap colorizeTemplate(const QPixmap &mask, const QColor &foreground, int size)
|
||||||
|
{
|
||||||
|
QPixmap result(size, size);
|
||||||
|
result.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter painter(&result);
|
||||||
|
painter.fillRect(result.rect(), foreground);
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||||
|
painter.drawPixmap(0, 0, mask);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawStatusIndicator(QPainter &painter, const QColor &color, int size)
|
||||||
|
{
|
||||||
|
const qreal dotSize = size * 0.35;
|
||||||
|
const qreal dotOrigin = (size - dotSize) * 0.8;
|
||||||
|
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.setBrush(color);
|
||||||
|
painter.drawEllipse(QRectF(dotOrigin, dotOrigin, dotSize, dotSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap buildPixmap(int size, qreal opacity, bool darkTheme, const QColor &indicatorColor)
|
||||||
|
{
|
||||||
|
const QPixmap mask = renderTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, size);
|
||||||
|
const QColor foreground = darkTheme ? Qt::white : Qt::black;
|
||||||
|
QPixmap pixmap = colorizeTemplate(mask, foreground, size);
|
||||||
|
|
||||||
|
if (indicatorColor.isValid()) {
|
||||||
|
QPainter painter(&pixmap);
|
||||||
|
drawStatusIndicator(painter, indicatorColor, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor)
|
||||||
|
{
|
||||||
|
QIcon icon;
|
||||||
|
icon.addPixmap(buildPixmap(kDefaultTrayIconSize, opacity, darkTheme, indicatorColor));
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray buildTemplatePng(qreal opacity)
|
||||||
|
{
|
||||||
|
const QPixmap pixmap = renderTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, kDefaultTrayIconSize);
|
||||||
|
|
||||||
|
QByteArray bytes;
|
||||||
|
QBuffer buffer(&bytes);
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
pixmap.save(&buffer, "PNG");
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace TrayIconCommon
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef TRAYICONCOMMON_H
|
||||||
|
#define TRAYICONCOMMON_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPixmap>
|
||||||
|
|
||||||
|
#include "core/protocols/vpnProtocol.h"
|
||||||
|
|
||||||
|
namespace TrayIconCommon {
|
||||||
|
|
||||||
|
constexpr int kDefaultTrayIconSize = 128;
|
||||||
|
constexpr char kTrayTemplateIconPath[] = ":/images/tray/icon.svg";
|
||||||
|
|
||||||
|
constexpr qreal kDisconnectedOpacity = 0.5;
|
||||||
|
constexpr qreal kConnectedOpacity = 1.0;
|
||||||
|
|
||||||
|
qreal opacityForState(Vpn::ConnectionState state);
|
||||||
|
QColor indicatorColorForState(Vpn::ConnectionState state);
|
||||||
|
|
||||||
|
QPixmap renderTemplate(const QString &resourcePath, qreal opacity, int size);
|
||||||
|
QPixmap colorizeTemplate(const QPixmap &mask, const QColor &foreground, int size);
|
||||||
|
void drawStatusIndicator(QPainter &painter, const QColor &color, int size);
|
||||||
|
|
||||||
|
QPixmap buildPixmap(int size, qreal opacity, bool darkTheme, const QColor &indicatorColor);
|
||||||
|
QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor);
|
||||||
|
QByteArray buildTemplatePng(qreal opacity);
|
||||||
|
|
||||||
|
} // namespace TrayIconCommon
|
||||||
|
|
||||||
|
#endif // TRAYICONCOMMON_H
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "trayThemeChangeFilter.h"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
|
TrayThemeChangeFilter::TrayThemeChangeFilter(std::function<void()> onThemeChanged, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_onThemeChanged(std::move(onThemeChanged))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TrayThemeChangeFilter::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(watched);
|
||||||
|
if (event->type() == QEvent::ApplicationPaletteChange || event->type() == QEvent::ThemeChange) {
|
||||||
|
if (m_onThemeChanged) {
|
||||||
|
m_onThemeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(watched, event);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef TRAYTHEMECHANGEFILTER_H
|
||||||
|
#define TRAYTHEMECHANGEFILTER_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class TrayThemeChangeFilter final : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TrayThemeChangeFilter(std::function<void()> onThemeChanged, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> m_onThemeChanged;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TRAYTHEMECHANGEFILTER_H
|
||||||
Reference in New Issue
Block a user