diff --git a/client/images/images.qrc b/client/images/images.qrc
index 6bbfb6308..51574688d 100644
--- a/client/images/images.qrc
+++ b/client/images/images.qrc
@@ -68,6 +68,7 @@
tray/active.png
tray/default.png
tray/error.png
+ tray/icon.svg
controls/monitor.svg
diff --git a/client/images/tray/icon.svg b/client/images/tray/icon.svg
new file mode 100644
index 000000000..c96c97d98
--- /dev/null
+++ b/client/images/tray/icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/client/main.cpp b/client/main.cpp
index a2c66f828..030c42322 100644
--- a/client/main.cpp
+++ b/client/main.cpp
@@ -15,6 +15,10 @@
#include "platforms/ios/QtAppDelegate-C-Interface.h"
#endif
+#if defined(Q_OS_MAC) && !defined(MACOS_NE)
+ #include "platforms/macos/macosutils.h"
+#endif
+
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
bool isAnotherInstanceRunning()
{
@@ -46,6 +50,10 @@ int main(int argc, char *argv[])
AmneziaApplication app(argc, argv);
OsSignalHandler::setup();
+#if defined(Q_OS_MAC) && !defined(MACOS_NE)
+ MacOSUtils::patchNSStatusBarSetImageForBigSur();
+#endif
+
ssh_init();
QObject::connect(&app, &QCoreApplication::aboutToQuit, []() {
ssh_finalize();
diff --git a/client/ui/utils/systemTrayNotificationHandler.cpp b/client/ui/utils/systemTrayNotificationHandler.cpp
index 8cbcbe67e..bc24e4871 100644
--- a/client/ui/utils/systemTrayNotificationHandler.cpp
+++ b/client/ui/utils/systemTrayNotificationHandler.cpp
@@ -5,18 +5,51 @@
#include
#include "systemTrayNotificationHandler.h"
-
-#ifdef Q_OS_MAC
-# include "platforms/macos/macosutils.h"
-#endif
-
#include
#include
+#include
#include
+#include
+#include
+#include
#include
#include "version.h"
+namespace {
+
+constexpr int kTrayIconSize = 128;
+constexpr char kTrayTemplateIconPath[] = ":/images/tray/icon.svg";
+
+QPixmap renderTrayTemplate(const QString &resourcePath, qreal opacity)
+{
+ QSvgRenderer renderer(resourcePath);
+ QPixmap pixmap(kTrayIconSize, kTrayIconSize);
+ 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, kTrayIconSize, kTrayIconSize));
+ return pixmap;
+}
+
+QIcon buildTrayIcon(qreal opacity)
+{
+ const QPixmap pixmap = renderTrayTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity);
+
+ QIcon icon;
+ icon.addPixmap(pixmap);
+ icon.setIsMask(true);
+ return icon;
+}
+
+} // namespace
+
SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) :
NotificationHandler(parent),
m_systemTrayIcon(parent)
@@ -25,7 +58,7 @@ SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) :
m_systemTrayIcon.show();
connect(&m_systemTrayIcon, &QSystemTrayIcon::activated, this, &SystemTrayNotificationHandler::onTrayActivated);
- m_trayActionShow = m_menu.addAction(QIcon(":/images/tray/application.png"), tr("Show") + " " + APPLICATION_NAME, this, [this](){
+ m_trayActionShow = m_menu.addAction(tr("Show") + " " + APPLICATION_NAME, this, [this](){
emit raiseRequested();
});
m_menu.addSeparator();
@@ -34,17 +67,22 @@ SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) :
m_menu.addSeparator();
- m_trayActionVisitWebSite = m_menu.addAction(QIcon(":/images/tray/link.png"), tr("Visit Website"), [&](){
+ m_trayActionVisitWebSite = m_menu.addAction(tr("Visit Website"), [&](){
QDesktopServices::openUrl(QUrl(websiteUrl));
});
- // Quit action: disconnect VPN first on macOS NE, else quit directly
- m_trayActionQuit = m_menu.addAction(QIcon(":/images/tray/cancel.png"),
- tr("Quit") + " " + APPLICATION_NAME,
+ m_trayActionQuit = m_menu.addAction(tr("Quit") + " " + APPLICATION_NAME,
this,
[&](){ qApp->quit(); });
m_systemTrayIcon.setContextMenu(&m_menu);
+
+ if (QStyleHints *styleHints = QGuiApplication::styleHints()) {
+ connect(styleHints, &QStyleHints::colorSchemeChanged, this, [this]() {
+ updateTrayIcon();
+ });
+ }
+
setTrayState(Vpn::ConnectionState::Disconnected);
}
@@ -71,13 +109,27 @@ void SystemTrayNotificationHandler::updateWebsiteUrl(const QString &newWebsiteUr
websiteUrl = newWebsiteUrl;
}
-void SystemTrayNotificationHandler::setTrayIcon(const QString &iconPath)
+qreal SystemTrayNotificationHandler::trayIconOpacityForState(Vpn::ConnectionState state) const
{
- QIcon trayIconMask(QPixmap(iconPath).scaled(128,128));
-#ifndef Q_OS_MAC
- trayIconMask.setIsMask(true);
-#endif
- m_systemTrayIcon.setIcon(trayIconMask);
+ switch (state) {
+ case Vpn::ConnectionState::Connected:
+ case Vpn::ConnectionState::Error:
+ return kConnectedTrayOpacity;
+ 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;
+ }
+}
+
+void SystemTrayNotificationHandler::updateTrayIcon()
+{
+ const qreal opacity = trayIconOpacityForState(m_trayState);
+ m_systemTrayIcon.setIcon(buildTrayIcon(opacity));
}
void SystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
@@ -91,41 +143,34 @@ void SystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationR
void SystemTrayNotificationHandler::setTrayState(Vpn::ConnectionState state)
{
- QString resourcesPath = ":/images/tray/%1";
+ m_trayState = state;
switch (state) {
case Vpn::ConnectionState::Disconnected:
- setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(true);
m_trayActionDisconnect->setEnabled(false);
break;
case Vpn::ConnectionState::Preparing:
- setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case Vpn::ConnectionState::Connecting:
- setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case Vpn::ConnectionState::Connected:
- setTrayIcon(QString(resourcesPath).arg(ConnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case Vpn::ConnectionState::Disconnecting:
- setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case Vpn::ConnectionState::Reconnecting:
- setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case Vpn::ConnectionState::Error:
- setTrayIcon(QString(resourcesPath).arg(ErrorTrayIconName));
m_trayActionConnect->setEnabled(true);
m_trayActionDisconnect->setEnabled(false);
break;
@@ -133,16 +178,10 @@ void SystemTrayNotificationHandler::setTrayState(Vpn::ConnectionState state)
default:
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
- setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
+ break;
}
- //#ifdef Q_OS_MAC
- // // Get theme from current user (note, this app can be launched as root application and in this case this theme can be different from theme of real current user )
- // bool darkTaskBar = MacOSFunctions::instance().isMenuBarUseDarkTheme();
- // darkTaskBar = forceUseBrightIcons ? true : darkTaskBar;
- // resourcesPath = ":/images_mac/tray_icon/%1";
- // useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png");
- //#endif
+ updateTrayIcon();
}
@@ -152,8 +191,7 @@ void SystemTrayNotificationHandler::notify(NotificationHandler::Message type,
int timerMsec) {
Q_UNUSED(type);
- QIcon icon(ConnectedTrayIconName);
- m_systemTrayIcon.showMessage(title, message, icon, timerMsec);
+ m_systemTrayIcon.showMessage(title, message, buildTrayIcon(kConnectedTrayOpacity), timerMsec);
}
void SystemTrayNotificationHandler::showHideWindow() {
@@ -170,4 +208,3 @@ void SystemTrayNotificationHandler::showHideWindow() {
//#endif
// }
}
-
diff --git a/client/ui/utils/systemTrayNotificationHandler.h b/client/ui/utils/systemTrayNotificationHandler.h
index 309b1d64b..239bc4cfe 100644
--- a/client/ui/utils/systemTrayNotificationHandler.h
+++ b/client/ui/utils/systemTrayNotificationHandler.h
@@ -34,7 +34,8 @@ private:
void setTrayState(Vpn::ConnectionState state);
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
- void setTrayIcon(const QString &iconPath);
+ void updateTrayIcon();
+ qreal trayIconOpacityForState(Vpn::ConnectionState state) const;
private:
QMenu m_menu;
@@ -45,13 +46,15 @@ private:
QAction* m_trayActionDisconnect = nullptr;
QAction* m_trayActionVisitWebSite = nullptr;
QAction* m_trayActionQuit = nullptr;
- QAction* m_statusLabel = nullptr;
+ QAction* m_statusLabel = nullptr;
QAction* m_separator = nullptr;
- const QString ConnectedTrayIconName = "active.png";
- const QString DisconnectedTrayIconName = "default.png";
- const QString ErrorTrayIconName = "error.png";
- QString websiteUrl = "https://amnezia.org";
+ Vpn::ConnectionState m_trayState = Vpn::ConnectionState::Unknown;
+
+ static constexpr qreal kDisconnectedTrayOpacity = 0.5;
+ static constexpr qreal kConnectedTrayOpacity = 1.0;
+
+ QString websiteUrl = "https://amnezia.org";
};
#endif // SYSTEMTRAYNOTIFICATIONHANDLER_H