diff --git a/CMakeLists.txt b/CMakeLists.txt
index e0f4929..2f7da6b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -127,6 +127,7 @@ set(PROJECT_SOURCES
sys/AutoRun.cpp
ui/ThemeManager.cpp
+ ui/TrayIcon.cpp
ui/mainwindow_grpc.cpp
ui/mainwindow.cpp
diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts
index 593330e..852692d 100644
--- a/translations/zh_CN.ts
+++ b/translations/zh_CN.ts
@@ -159,6 +159,26 @@
Include Pre-release when checking update
检查更新时包括 Pre-release
+
+ Set custom icon
+ 自定义图标
+
+
+ Please select a PNG file.
+ 请选择一个 PNG 文件。
+
+
+ Reset
+ 重置
+
+
+ Please select a valid square image.
+ 请选择有效的正方形图像。
+
+
+ Cancel
+ 取消
+
DialogEditGroup
diff --git a/ui/TrayIcon.cpp b/ui/TrayIcon.cpp
new file mode 100644
index 0000000..f0a367a
--- /dev/null
+++ b/ui/TrayIcon.cpp
@@ -0,0 +1,39 @@
+#include "TrayIcon.hpp"
+
+#include
+
+QIcon TrayIcon::GetIcon(TrayIcon::TrayIconStatus status) {
+ auto icon = QIcon::fromTheme("nekoray");
+ auto pixmap = QPixmap("../nekoray.png");
+ if (!pixmap.isNull()) icon = QIcon(pixmap);
+ pixmap = QPixmap("./nekoray.png");
+ if (!pixmap.isNull()) icon = QIcon(pixmap);
+
+ if (status == TrayIconStatus::NONE) return icon;
+
+ pixmap = icon.pixmap(icon.availableSizes().first());
+ auto p = QPainter(&pixmap);
+
+ auto side = pixmap.width();
+ auto radius = side * 0.4;
+ auto d = side * 0.3;
+ auto margin = side * 0.1;
+
+ if (status == TrayIconStatus::RUNNING) {
+ p.setBrush(QBrush(Qt::darkGreen));
+ } else if (status == TrayIconStatus::SYSTEM_PROXY) {
+ p.setBrush(QBrush(Qt::blue));
+ } else if (status == TrayIconStatus::VPN) {
+ p.setBrush(QBrush(Qt::red));
+ }
+ p.drawRoundedRect(
+ QRect(side - d - margin,
+ side - d - margin,
+ d,
+ d),
+ radius,
+ radius);
+ p.end();
+
+ return pixmap;
+}
diff --git a/ui/TrayIcon.hpp b/ui/TrayIcon.hpp
new file mode 100644
index 0000000..00e43ba
--- /dev/null
+++ b/ui/TrayIcon.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+
+namespace TrayIcon {
+
+ enum TrayIconStatus {
+ NONE,
+ RUNNING,
+ SYSTEM_PROXY,
+ VPN,
+ };
+
+ QIcon GetIcon(TrayIconStatus status);
+
+}
diff --git a/ui/dialog_basic_settings.cpp b/ui/dialog_basic_settings.cpp
index 3d9e23f..9fa923b 100644
--- a/ui/dialog_basic_settings.cpp
+++ b/ui/dialog_basic_settings.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
class ExtraCoreWidget : public QWidget {
public:
@@ -223,3 +224,26 @@ void DialogBasicSettings::accept() {
dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore");
QDialog::accept();
}
+
+void DialogBasicSettings::on_set_custom_icon_clicked() {
+ auto title = ui->set_custom_icon->text();
+ auto c = QMessageBox::question(this, title, tr("Please select a PNG file."),
+ tr("Select"), tr("Reset"), tr("Cancel"), 2, 2);
+ if (c == 0) {
+ auto fn = QFileDialog::getOpenFileName(this, QObject::tr("Select"), QDir::currentPath(),
+ "*.png", nullptr, QFileDialog::Option::ReadOnly);
+ if (!fn.isEmpty()) {
+ QImage img(fn);
+ if (img.isNull() || img.height() != img.width()) {
+ MessageBoxWarning(title, tr("Please select a valid square image."));
+ return;
+ }
+ QFile::copy(fn, "./nekoray.png");
+ }
+ } else if (c == 1) {
+ QFile::remove("./nekoray.png");
+ } else {
+ return;
+ }
+ dialog_message(Dialog_DialogBasicSettings, "UpdateIcon");
+}
diff --git a/ui/dialog_basic_settings.h b/ui/dialog_basic_settings.h
index a6c69f1..1b61d69 100644
--- a/ui/dialog_basic_settings.h
+++ b/ui/dialog_basic_settings.h
@@ -28,6 +28,11 @@ private:
QString custom_inbound;
bool needRestart = false;
} CACHE;
+
+private slots:
+
+ void on_set_custom_icon_clicked();
+
};
#endif // DIALOG_BASIC_SETTINGS_H
diff --git a/ui/dialog_basic_settings.ui b/ui/dialog_basic_settings.ui
index 41a33ac..3068d79 100644
--- a/ui/dialog_basic_settings.ui
+++ b/ui/dialog_basic_settings.ui
@@ -264,6 +264,49 @@
Style
+ -
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Theme
+
+
+
+ -
+
+
-
+
+ System
+
+
+ -
+
+ flatgray
+
+
+ -
+
+ lightblue
+
+
+ -
+
+ blacksoft
+
+
+
+
+
+
+
-
@@ -302,6 +345,33 @@
+ -
+
+
+
-
+
+
+ Minimize to tray icon on startup
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ Set custom icon
+
+
+
+
+
+
-
-
@@ -358,62 +428,6 @@
- -
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Theme
-
-
-
- -
-
-
-
-
- System
-
-
- -
-
- flatgray
-
-
- -
-
- lightblue
-
-
- -
-
- blacksoft
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- Minimize to tray icon on startup
-
-
-
-
-
-
diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp
index 167292b..01c2ec3 100644
--- a/ui/mainwindow.cpp
+++ b/ui/mainwindow.cpp
@@ -9,6 +9,7 @@
#include "sys/AutoRun.hpp"
#include "ui/ThemeManager.hpp"
+#include "ui/TrayIcon.hpp"
#include "ui/edit/dialog_edit_profile.h"
#include "ui/dialog_basic_settings.h"
#include "ui/dialog_manage_groups.h"
@@ -228,15 +229,7 @@ MainWindow::MainWindow(QWidget *parent)
this->refresh_groups();
// Setup Tray
- auto icon = QIcon::fromTheme("nekoray");
- auto pixmap = QPixmap("../nekoray.png");
- if (!pixmap.isNull()) icon = QIcon(pixmap);
- pixmap = QPixmap("./nekoray.png");
- if (!pixmap.isNull()) icon = QIcon(pixmap);
- setWindowIcon(icon);
-
tray = new QSystemTrayIcon(this);//初始化托盘对象tray
- tray->setIcon(icon);//设定托盘图标,引号内是自定义的png图片路径
tray->setContextMenu(ui->menu_program);//创建托盘菜单
tray->show();//让托盘图标显示在系统托盘上
connect(tray, &QSystemTrayIcon::activated, this,
@@ -483,6 +476,10 @@ void MainWindow::show_group(int gid) {
// callback
void MainWindow::dialog_message_impl(const QString &sender, const QString &info) {
+ if (info.contains("UpdateIcon")) {
+ icon_status = -1;
+ refresh_status();
+ }
if (info.contains("UpdateDataStore")) {
auto changed = NekoRay::dataStore->Save();
if (info.contains("RouteChanged")) changed = true;
@@ -679,8 +676,24 @@ void MainWindow::refresh_status(const QString &traffic_update) {
return tt.join(isTray ? "\n" : " ");
};
+ auto icon_status_new = TrayIcon::NONE;
+ if (title_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
+ icon_status_new = TrayIcon::SYSTEM_PROXY;
+ } else if (title_spmode == NekoRay::SystemProxyMode::VPN) {
+ icon_status_new = TrayIcon::VPN;
+ } else if (!running.isNull()) {
+ icon_status_new = TrayIcon::RUNNING;
+ }
+
setWindowTitle(make_title(false));
- if (tray != nullptr) tray->setToolTip(make_title(true));
+ if (icon_status_new != icon_status) setWindowIcon(TrayIcon::GetIcon(TrayIcon::NONE));
+
+ if (tray != nullptr) {
+ tray->setToolTip(make_title(true));
+ if (icon_status_new != icon_status) tray->setIcon(TrayIcon::GetIcon(icon_status_new));
+ }
+
+ icon_status = icon_status_new;
}
// table显示
diff --git a/ui/mainwindow.h b/ui/mainwindow.h
index 5fa0f60..46820fd 100644
--- a/ui/mainwindow.h
+++ b/ui/mainwindow.h
@@ -131,6 +131,7 @@ private:
QString title_base;
QString title_error;
int title_spmode = NekoRay::SystemProxyMode::DISABLE;
+ int icon_status = -1;
QSharedPointer running;
QString traffic_update_cache;
QTime last_test_time;