mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 20:44:38 +03:00
optmize start stop
This commit is contained in:
@@ -359,6 +359,7 @@ namespace NekoRay {
|
|||||||
|
|
||||||
bool JsonStore::Save() {
|
bool JsonStore::Save() {
|
||||||
if (callback_before_save != nullptr) callback_before_save();
|
if (callback_before_save != nullptr) callback_before_save();
|
||||||
|
if (save_control_no_save) return false;
|
||||||
|
|
||||||
auto save_content = ToJsonBytes();
|
auto save_content = ToJsonBytes();
|
||||||
auto changed = last_save_content != save_content;
|
auto changed = last_save_content != save_content;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace NekoRay {
|
|||||||
QString fn;
|
QString fn;
|
||||||
bool load_control_must = false; // must load from file
|
bool load_control_must = false; // must load from file
|
||||||
bool save_control_compact = false;
|
bool save_control_compact = false;
|
||||||
|
bool save_control_no_save = false;
|
||||||
QByteArray last_save_content;
|
QByteArray last_save_content;
|
||||||
|
|
||||||
JsonStore() = default;
|
JsonStore() = default;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace NekoRay {
|
|||||||
int core_port = 19810;
|
int core_port = 19810;
|
||||||
int started_id = -1919;
|
int started_id = -1919;
|
||||||
bool core_running = false;
|
bool core_running = false;
|
||||||
bool core_prepare_exit = false;
|
bool prepare_exit = false;
|
||||||
bool spmode_vpn = false;
|
bool spmode_vpn = false;
|
||||||
bool spmode_system_proxy = false;
|
bool spmode_system_proxy = false;
|
||||||
bool need_keep_vpn_off = false;
|
bool need_keep_vpn_off = false;
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ namespace NekoRay::rpc {
|
|||||||
|
|
||||||
QString Client::Start(bool *rpcOK, const libcore::LoadConfigReq &request) {
|
QString Client::Start(bool *rpcOK, const libcore::LoadConfigReq &request) {
|
||||||
libcore::ErrorResp reply;
|
libcore::ErrorResp reply;
|
||||||
auto status = default_grpc_channel->Call("Start", request, &reply, 3000);
|
auto status = default_grpc_channel->Call("Start", request, &reply);
|
||||||
|
|
||||||
if (status == QNetworkReply::NoError) {
|
if (status == QNetworkReply::NoError) {
|
||||||
*rpcOK = true;
|
*rpcOK = true;
|
||||||
@@ -234,7 +234,7 @@ namespace NekoRay::rpc {
|
|||||||
QString Client::Stop(bool *rpcOK) {
|
QString Client::Stop(bool *rpcOK) {
|
||||||
libcore::EmptyReq request;
|
libcore::EmptyReq request;
|
||||||
libcore::ErrorResp reply;
|
libcore::ErrorResp reply;
|
||||||
auto status = default_grpc_channel->Call("Stop", request, &reply, 3000);
|
auto status = default_grpc_channel->Call("Stop", request, &reply);
|
||||||
|
|
||||||
if (status == QNetworkReply::NoError) {
|
if (status == QNetworkReply::NoError) {
|
||||||
*rpcOK = true;
|
*rpcOK = true;
|
||||||
|
|||||||
@@ -97,12 +97,12 @@ namespace NekoRay::sys {
|
|||||||
connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
|
connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) {
|
||||||
NekoRay::dataStore->core_running = state == QProcess::Running;
|
NekoRay::dataStore->core_running = state == QProcess::Running;
|
||||||
|
|
||||||
if (!dataStore->core_prepare_exit && state == QProcess::NotRunning) {
|
if (!dataStore->prepare_exit && state == QProcess::NotRunning) {
|
||||||
if (failed_to_start) return; // no retry
|
if (failed_to_start) return; // no retry
|
||||||
|
|
||||||
restart_id = NekoRay::dataStore->started_id;
|
restart_id = NekoRay::dataStore->started_id;
|
||||||
MW_dialog_message("ExternalProcess", "Crashed");
|
MW_dialog_message("ExternalProcess", "Crashed");
|
||||||
MW_show_log("[Error] core exited, restarting.\n");
|
MW_show_log("[Error] " + QObject::tr("Core exited, restarting."));
|
||||||
|
|
||||||
// Restart
|
// Restart
|
||||||
setTimeout(
|
setTimeout(
|
||||||
|
|||||||
@@ -1454,6 +1454,22 @@ End: %2</source>
|
|||||||
<source>Restart Proxy</source>
|
<source>Restart Proxy</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>If there is no response for a long time, it is recommended to restart the software.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to start profile %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to stop, please restart the program.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Core exits too frequently, stop automatic restart this profile.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ProxyItem</name>
|
<name>ProxyItem</name>
|
||||||
@@ -1586,6 +1602,10 @@ Direct: %2</source>
|
|||||||
<source>Subscription request fininshed: %1</source>
|
<source>Subscription request fininshed: %1</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Core exited, restarting.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>
|
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>
|
||||||
|
|||||||
@@ -1461,6 +1461,22 @@ Split by line.</source>
|
|||||||
<source>Restart Proxy</source>
|
<source>Restart Proxy</source>
|
||||||
<translation>重启代理</translation>
|
<translation>重启代理</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to start profile %1</source>
|
||||||
|
<translation>启动配置失败: %1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to stop, please restart the program.</source>
|
||||||
|
<translation>停止失败,请重启程序。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>If there is no response for a long time, it is recommended to restart the software.</source>
|
||||||
|
<translation>如果长时间没有反应,建议重启软件。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Core exits too frequently, stop automatic restart this profile.</source>
|
||||||
|
<translation>Core 退出太频繁,停止自动重启。</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ProxyItem</name>
|
<name>ProxyItem</name>
|
||||||
@@ -1592,6 +1608,10 @@ Release note:
|
|||||||
<source>Subscription request fininshed: %1</source>
|
<source>Subscription request fininshed: %1</source>
|
||||||
<translation>订阅请求完成: %1</translation>
|
<translation>订阅请求完成: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Core exited, restarting.</source>
|
||||||
|
<translation>Core 退出,正在重新启动。</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>
|
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>
|
||||||
|
|||||||
@@ -46,6 +46,8 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
QElapsedTimer coreRestartTimer;
|
||||||
|
|
||||||
void UI_InitMainWindow() {
|
void UI_InitMainWindow() {
|
||||||
mainwindow = new MainWindow;
|
mainwindow = new MainWindow;
|
||||||
}
|
}
|
||||||
@@ -564,6 +566,16 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info)
|
|||||||
if (info == "Crashed") {
|
if (info == "Crashed") {
|
||||||
neko_stop();
|
neko_stop();
|
||||||
} else if (info.startsWith("CoreRestarted")) {
|
} else if (info.startsWith("CoreRestarted")) {
|
||||||
|
if (coreRestartTimer.isValid()) {
|
||||||
|
auto elasped = coreRestartTimer.restart();
|
||||||
|
if (elasped < 10 * 1000) {
|
||||||
|
coreRestartTimer = QElapsedTimer();
|
||||||
|
show_log_impl("[Error] " + tr("Core exits too frequently, stop automatic restart this profile."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
coreRestartTimer.start();
|
||||||
|
}
|
||||||
neko_start(info.split(",")[1].toInt());
|
neko_start(info.split(",")[1].toInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,7 +627,6 @@ void MainWindow::on_commitDataRequest() {
|
|||||||
NekoRay::dataStore->splitter_state = ui->splitter->saveState().toBase64();
|
NekoRay::dataStore->splitter_state = ui->splitter->saveState().toBase64();
|
||||||
//
|
//
|
||||||
auto last_id = NekoRay::dataStore->started_id;
|
auto last_id = NekoRay::dataStore->started_id;
|
||||||
neko_stop();
|
|
||||||
if (NekoRay::dataStore->remember_enable && last_id >= 0) {
|
if (NekoRay::dataStore->remember_enable && last_id >= 0) {
|
||||||
NekoRay::dataStore->remember_id = last_id;
|
NekoRay::dataStore->remember_id = last_id;
|
||||||
}
|
}
|
||||||
@@ -625,16 +636,32 @@ void MainWindow::on_commitDataRequest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_menu_exit_triggered() {
|
void MainWindow::on_menu_exit_triggered() {
|
||||||
|
if (mu_exit.tryLock()) {
|
||||||
|
NekoRay::dataStore->prepare_exit = true;
|
||||||
|
//
|
||||||
neko_set_spmode_system_proxy(false, false);
|
neko_set_spmode_system_proxy(false, false);
|
||||||
neko_set_spmode_vpn(false, false);
|
neko_set_spmode_vpn(false, false);
|
||||||
if (NekoRay::dataStore->spmode_vpn) return;
|
if (NekoRay::dataStore->spmode_vpn) {
|
||||||
|
mu_exit.unlock(); // retry
|
||||||
|
return;
|
||||||
|
}
|
||||||
RegisterHotkey(true);
|
RegisterHotkey(true);
|
||||||
//
|
//
|
||||||
on_commitDataRequest();
|
on_commitDataRequest();
|
||||||
//
|
//
|
||||||
NekoRay::dataStore->core_prepare_exit = true;
|
NekoRay::dataStore->save_control_no_save = true; // don't change datastore after this line
|
||||||
|
neko_stop(false, true);
|
||||||
|
//
|
||||||
hide();
|
hide();
|
||||||
|
runOnNewThread([=] {
|
||||||
|
sem_stopped.acquire();
|
||||||
stop_core_daemon();
|
stop_core_daemon();
|
||||||
|
runOnUiThread([=] {
|
||||||
|
on_menu_exit_triggered(); // continue exit progress
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
MF_release_runguard();
|
MF_release_runguard();
|
||||||
if (exit_reason == 1) {
|
if (exit_reason == 1) {
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
|
#include <QSemaphore>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
#include "GroupSort.hpp"
|
#include "GroupSort.hpp"
|
||||||
|
|
||||||
@@ -49,7 +51,7 @@ public:
|
|||||||
|
|
||||||
void neko_start(int _id = -1);
|
void neko_start(int _id = -1);
|
||||||
|
|
||||||
void neko_stop(bool crash = false);
|
void neko_stop(bool crash = false, bool sem = false);
|
||||||
|
|
||||||
void neko_set_spmode_system_proxy(bool enable, bool save = true);
|
void neko_set_spmode_system_proxy(bool enable, bool save = true);
|
||||||
|
|
||||||
@@ -153,6 +155,10 @@ private:
|
|||||||
//
|
//
|
||||||
int proxy_last_order = -1;
|
int proxy_last_order = -1;
|
||||||
bool select_mode = false;
|
bool select_mode = false;
|
||||||
|
QMutex mu_starting;
|
||||||
|
QMutex mu_stopping;
|
||||||
|
QMutex mu_exit;
|
||||||
|
QSemaphore sem_stopped;
|
||||||
int exit_reason = 0;
|
int exit_reason = 0;
|
||||||
|
|
||||||
QMap<int, QSharedPointer<NekoRay::ProxyEntity>> get_now_selected();
|
QMap<int, QSharedPointer<NekoRay::ProxyEntity>> get_now_selected();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "db/ConfigBuilder.hpp"
|
#include "db/ConfigBuilder.hpp"
|
||||||
#include "db/TrafficLooper.hpp"
|
#include "db/TrafficLooper.hpp"
|
||||||
#include "rpc/gRPC.h"
|
#include "rpc/gRPC.h"
|
||||||
|
#include "ui/widget/MessageBoxTimer.h"
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
@@ -194,6 +195,8 @@ void MainWindow::stop_core_daemon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::neko_start(int _id) {
|
void MainWindow::neko_start(int _id) {
|
||||||
|
if (NekoRay::dataStore->prepare_exit) return;
|
||||||
|
|
||||||
auto ents = get_now_selected();
|
auto ents = get_now_selected();
|
||||||
auto ent = (_id < 0 && !ents.isEmpty()) ? ents.first() : NekoRay::profileManager->GetProfile(_id);
|
auto ent = (_id < 0 && !ents.isEmpty()) ? ents.first() : NekoRay::profileManager->GetProfile(_id);
|
||||||
if (ent == nullptr) return;
|
if (ent == nullptr) return;
|
||||||
@@ -214,9 +217,7 @@ void MainWindow::neko_start(int _id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NekoRay::dataStore->started_id >= 0) neko_stop();
|
auto neko_start_stage2 = [=] {
|
||||||
show_log_impl(">>>>>>>> " + tr("Starting profile %1").arg(ent->bean->DisplayTypeAndName()));
|
|
||||||
|
|
||||||
#ifndef NKR_NO_GRPC
|
#ifndef NKR_NO_GRPC
|
||||||
libcore::LoadConfigReq req;
|
libcore::LoadConfigReq req;
|
||||||
req.set_core_config(QJsonObject2QString(result->coreConfig, true).toStdString());
|
req.set_core_config(QJsonObject2QString(result->coreConfig, true).toStdString());
|
||||||
@@ -229,8 +230,8 @@ void MainWindow::neko_start(int _id) {
|
|||||||
bool rpcOK;
|
bool rpcOK;
|
||||||
QString error = defaultClient->Start(&rpcOK, req);
|
QString error = defaultClient->Start(&rpcOK, req);
|
||||||
if (rpcOK && !error.isEmpty()) {
|
if (rpcOK && !error.isEmpty()) {
|
||||||
MessageBoxWarning("LoadConfig return error", error);
|
runOnUiThread([=] { MessageBoxWarning("LoadConfig return error", error); });
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
NekoRay::traffic::trafficLooper->proxy = result->outboundStat.get();
|
NekoRay::traffic::trafficLooper->proxy = result->outboundStat.get();
|
||||||
@@ -246,15 +247,52 @@ void MainWindow::neko_start(int _id) {
|
|||||||
|
|
||||||
NekoRay::dataStore->UpdateStartedId(ent->id);
|
NekoRay::dataStore->UpdateStartedId(ent->id);
|
||||||
running = ent;
|
running = ent;
|
||||||
|
|
||||||
|
runOnUiThread([=] {
|
||||||
refresh_status();
|
refresh_status();
|
||||||
refresh_proxy_list(ent->id);
|
refresh_proxy_list(ent->id);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!mu_starting.tryLock()) return;
|
||||||
|
|
||||||
|
// timeout message
|
||||||
|
auto restartMsgbox = new QMessageBox(QMessageBox::Question, software_name, tr("If there is no response for a long time, it is recommended to restart the software."),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, this);
|
||||||
|
connect(restartMsgbox, &QMessageBox::accepted, this, [=] { MW_dialog_message("", "RestartProgram"); });
|
||||||
|
auto restartMsgboxTimer = new MessageBoxTimer(this, restartMsgbox, 5000);
|
||||||
|
|
||||||
|
runOnNewThread([=] {
|
||||||
|
// stop current running
|
||||||
|
if (NekoRay::dataStore->started_id >= 0) {
|
||||||
|
runOnUiThread([=] { neko_stop(false, true); });
|
||||||
|
sem_stopped.acquire();
|
||||||
|
}
|
||||||
|
// do start
|
||||||
|
MW_show_log(">>>>>>>> " + tr("Starting profile %1").arg(ent->bean->DisplayTypeAndName()));
|
||||||
|
if (!neko_start_stage2()) {
|
||||||
|
MW_show_log("<<<<<<<< " + tr("Failed to start profile %1").arg(ent->bean->DisplayTypeAndName()));
|
||||||
|
}
|
||||||
|
mu_starting.unlock();
|
||||||
|
// cancel timeout
|
||||||
|
runOnUiThread([=] {
|
||||||
|
restartMsgboxTimer->cancel();
|
||||||
|
restartMsgboxTimer->deleteLater();
|
||||||
|
restartMsgbox->deleteLater();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::neko_stop(bool crash) {
|
void MainWindow::neko_stop(bool crash, bool sem) {
|
||||||
auto id = NekoRay::dataStore->started_id;
|
auto id = NekoRay::dataStore->started_id;
|
||||||
if (id < 0) return;
|
if (id < 0) {
|
||||||
show_log_impl(">>>>>>>> " + tr("Stopping profile %1").arg(running->bean->DisplayTypeAndName()));
|
if (sem) sem_stopped.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto neko_stop_stage2 = [=] {
|
||||||
while (!NekoRay::sys::running_ext.isEmpty()) {
|
while (!NekoRay::sys::running_ext.isEmpty()) {
|
||||||
auto extC = NekoRay::sys::running_ext.takeFirst();
|
auto extC = NekoRay::sys::running_ext.takeFirst();
|
||||||
extC->Kill();
|
extC->Kill();
|
||||||
@@ -267,7 +305,7 @@ void MainWindow::neko_stop(bool crash) {
|
|||||||
NekoRay::traffic::trafficLooper->UpdateAll();
|
NekoRay::traffic::trafficLooper->UpdateAll();
|
||||||
for (const auto &item: NekoRay::traffic::trafficLooper->items) {
|
for (const auto &item: NekoRay::traffic::trafficLooper->items) {
|
||||||
NekoRay::profileManager->GetProfile(item->id)->Save();
|
NekoRay::profileManager->GetProfile(item->id)->Save();
|
||||||
refresh_proxy_list(item->id);
|
runOnUiThread([=] { refresh_proxy_list(item->id); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NekoRay::traffic::trafficLooper->loop_mutex.unlock();
|
NekoRay::traffic::trafficLooper->loop_mutex.unlock();
|
||||||
@@ -276,8 +314,8 @@ void MainWindow::neko_stop(bool crash) {
|
|||||||
bool rpcOK;
|
bool rpcOK;
|
||||||
QString error = defaultClient->Stop(&rpcOK);
|
QString error = defaultClient->Stop(&rpcOK);
|
||||||
if (rpcOK && !error.isEmpty()) {
|
if (rpcOK && !error.isEmpty()) {
|
||||||
MessageBoxWarning("Stop return error", error);
|
runOnUiThread([=] { MessageBoxWarning("Stop return error", error); });
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -285,8 +323,41 @@ void MainWindow::neko_stop(bool crash) {
|
|||||||
NekoRay::dataStore->UpdateStartedId(-1919);
|
NekoRay::dataStore->UpdateStartedId(-1919);
|
||||||
NekoRay::dataStore->need_keep_vpn_off = false;
|
NekoRay::dataStore->need_keep_vpn_off = false;
|
||||||
running = nullptr;
|
running = nullptr;
|
||||||
|
|
||||||
|
runOnUiThread([=] {
|
||||||
refresh_status();
|
refresh_status();
|
||||||
refresh_proxy_list(id);
|
refresh_proxy_list(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!mu_stopping.tryLock()) {
|
||||||
|
if (sem) sem_stopped.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeout message
|
||||||
|
auto restartMsgbox = new QMessageBox(QMessageBox::Question, software_name, tr("If there is no response for a long time, it is recommended to restart the software."),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, this);
|
||||||
|
connect(restartMsgbox, &QMessageBox::accepted, this, [=] { MW_dialog_message("", "RestartProgram"); });
|
||||||
|
auto restartMsgboxTimer = new MessageBoxTimer(this, restartMsgbox, 5000);
|
||||||
|
|
||||||
|
runOnNewThread([=] {
|
||||||
|
// do stop
|
||||||
|
MW_show_log(">>>>>>>> " + tr("Stopping profile %1").arg(running->bean->DisplayTypeAndName()));
|
||||||
|
if (!neko_stop_stage2()) {
|
||||||
|
MW_show_log("<<<<<<<< " + tr("Failed to stop, please restart the program."));
|
||||||
|
}
|
||||||
|
mu_stopping.unlock();
|
||||||
|
if (sem) sem_stopped.release();
|
||||||
|
// cancel timeout
|
||||||
|
runOnUiThread([=] {
|
||||||
|
restartMsgboxTimer->cancel();
|
||||||
|
restartMsgboxTimer->deleteLater();
|
||||||
|
restartMsgbox->deleteLater();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::CheckUpdate() {
|
void MainWindow::CheckUpdate() {
|
||||||
|
|||||||
33
ui/widget/MessageBoxTimer.h
Normal file
33
ui/widget/MessageBoxTimer.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
class MessageBoxTimer : public QTimer {
|
||||||
|
public:
|
||||||
|
QMessageBox *msgbox = nullptr;
|
||||||
|
bool showed = false;
|
||||||
|
|
||||||
|
explicit MessageBoxTimer(QObject *parent, QMessageBox *msgbox, int delayMs) : QTimer(parent) {
|
||||||
|
connect(this, &QTimer::timeout, this, &MessageBoxTimer::timeoutFunc, Qt::ConnectionType::QueuedConnection);
|
||||||
|
this->msgbox = msgbox;
|
||||||
|
setSingleShot(true);
|
||||||
|
setInterval(delayMs);
|
||||||
|
start();
|
||||||
|
};
|
||||||
|
|
||||||
|
void cancel() {
|
||||||
|
QTimer::stop();
|
||||||
|
if (msgbox != nullptr && showed) {
|
||||||
|
msgbox->reject(); // return the timeoutFunc
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void timeoutFunc() {
|
||||||
|
if (msgbox == nullptr) return;
|
||||||
|
showed = true;
|
||||||
|
msgbox->exec();
|
||||||
|
msgbox = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user