mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-21 19:30:26 +08:00
[fix] Some UI fixes, and added a Singleapplication model, Fixed #139
Former-commit-id: 7ea337d1f2
This commit is contained in:
parent
90ccfea5a1
commit
0af45dc678
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -7,3 +7,6 @@
|
|||||||
[submodule "3rdparty/qhttpserver"]
|
[submodule "3rdparty/qhttpserver"]
|
||||||
path = 3rdparty/qhttpserver
|
path = 3rdparty/qhttpserver
|
||||||
url = https://github.com/nikhilm/qhttpserver
|
url = https://github.com/nikhilm/qhttpserver
|
||||||
|
[submodule "3rdparty/SingleApplication"]
|
||||||
|
path = 3rdparty/SingleApplication
|
||||||
|
url = https://github.com/itay-grudev/SingleApplication
|
||||||
|
1
3rdparty/SingleApplication
vendored
Submodule
1
3rdparty/SingleApplication
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 16ea64b2548b02f59bf49b255466278c3ff0ace8
|
@ -1 +1 @@
|
|||||||
1776
|
1796
|
||||||
|
19
Qv2ray.pro
19
Qv2ray.pro
@ -9,20 +9,21 @@ QT += core gui widgets network charts
|
|||||||
TARGET = qv2ray
|
TARGET = qv2ray
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
# Don't merge those configs with below.
|
|
||||||
CONFIG += enable_decoder_qr_code enable_encoder_qr_code qt c++11 openssl-linked
|
|
||||||
include(3rdparty/qzxing_noTests/QZXing-components.pri)
|
|
||||||
|
|
||||||
# Main config
|
|
||||||
CONFIG += lrelease embed_translations
|
|
||||||
|
|
||||||
# Now read build number file.
|
# Now read build number file.
|
||||||
_BUILD_NUMBER=$$cat(Build.Counter)
|
_BUILD_NUMBER=$$cat(Build.Counter)
|
||||||
VERSION = 1.99.2.$$_BUILD_NUMBER
|
VERSION = 1.99.2.$$_BUILD_NUMBER
|
||||||
_BUILD_NUMBER = $$num_add($$_BUILD_NUMBER, 1)
|
_BUILD_NUMBER = $$num_add($$_BUILD_NUMBER, 1)
|
||||||
write_file("Build.Counter", _BUILD_NUMBER)
|
write_file("Build.Counter", _BUILD_NUMBER)
|
||||||
|
|
||||||
DEFINES += QT_DEPRECATED_WARNINGS QV2RAY_VERSION_STRING=\"\\\"v$${VERSION}\\\"\"
|
DEFINES += QT_DEPRECATED_WARNINGS QV2RAY_VERSION_STRING=\"\\\"v$${VERSION}\\\"\" QAPPLICATION_CLASS=QApplication
|
||||||
|
|
||||||
|
# Don't merge those configs with below.
|
||||||
|
CONFIG += enable_decoder_qr_code enable_encoder_qr_code qt c++11 openssl-linked
|
||||||
|
include(3rdparty/qzxing_noTests/QZXing-components.pri)
|
||||||
|
include(3rdparty/SingleApplication/singleapplication.pri)
|
||||||
|
|
||||||
|
# Main config
|
||||||
|
CONFIG += lrelease embed_translations
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
src/components/QvComponentsHandler.cpp \
|
src/components/QvComponentsHandler.cpp \
|
||||||
@ -39,7 +40,6 @@ SOURCES += \
|
|||||||
src/QvCoreConfigOperations_Convertion.cpp \
|
src/QvCoreConfigOperations_Convertion.cpp \
|
||||||
src/QvCoreConfigOperations_Generation.cpp \
|
src/QvCoreConfigOperations_Generation.cpp \
|
||||||
src/QvUtils.cpp \
|
src/QvUtils.cpp \
|
||||||
src/utils/QvRunguard.cpp \
|
|
||||||
src/utils/QJsonModel.cpp \
|
src/utils/QJsonModel.cpp \
|
||||||
src/ui/w_ExportConfig.cpp \
|
src/ui/w_ExportConfig.cpp \
|
||||||
src/ui/w_InboundEditor.cpp \
|
src/ui/w_InboundEditor.cpp \
|
||||||
@ -89,7 +89,6 @@ HEADERS += \
|
|||||||
src/utils/QvTinyLog.hpp \
|
src/utils/QvTinyLog.hpp \
|
||||||
src/utils/QJsonModel.hpp \
|
src/utils/QJsonModel.hpp \
|
||||||
src/utils/QJsonObjectInsertMacros.h \
|
src/utils/QJsonObjectInsertMacros.h \
|
||||||
src/utils/QvRunguard.hpp \
|
|
||||||
libs/gen/v2ray_api_commands.pb.h \
|
libs/gen/v2ray_api_commands.pb.h \
|
||||||
libs/gen/v2ray_api_commands.grpc.pb.h
|
libs/gen/v2ray_api_commands.grpc.pb.h
|
||||||
|
|
||||||
|
31
src/main.cpp
31
src/main.cpp
@ -3,10 +3,13 @@
|
|||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
#include <QObject>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <singleapplication.h>
|
||||||
|
|
||||||
#include "w_MainWindow.hpp"
|
#include "w_MainWindow.hpp"
|
||||||
#include "QvRunguard.hpp"
|
|
||||||
|
|
||||||
bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
|
bool verifyConfigAvaliability(QString path, bool checkExistingConfig)
|
||||||
{
|
{
|
||||||
@ -157,7 +160,13 @@ bool initialiseQv2ray()
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// This line must be called before any other ones.
|
// This line must be called before any other ones.
|
||||||
QApplication _qApp(argc, argv);
|
// ----------------------------> For debug build...
|
||||||
|
SingleApplication _qApp(argc, argv);
|
||||||
|
// Early initialisation
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
_qApp.setApplicationName(_qApp.applicationName() + " - DEBUG");
|
||||||
|
#endif
|
||||||
|
//
|
||||||
//
|
//
|
||||||
// Install a default translater. From the OS/DE
|
// Install a default translater. From the OS/DE
|
||||||
auto _lang = QLocale::system().name().replace("_", "-");
|
auto _lang = QLocale::system().name().replace("_", "-");
|
||||||
@ -208,18 +217,6 @@ int main(int argc, char *argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
|
||||||
RunGuard guard("Qv2ray-Instance-Identifier-DEBUG_VERSION");
|
|
||||||
#else
|
|
||||||
RunGuard guard("Qv2ray-Instance-Identifier");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!guard.isSingleInstance()) {
|
|
||||||
LOG(MODULE_INIT, "Another Instance running, Quit.")
|
|
||||||
QvMessageBox(nullptr, "Qv2ray", QObject::tr("Another instance of Qv2ray is already running."));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto conf = CONFIGROOT(JsonFromString(StringFromFile(new QFile(QV2RAY_CONFIG_FILE))));
|
auto conf = CONFIGROOT(JsonFromString(StringFromFile(new QFile(QV2RAY_CONFIG_FILE))));
|
||||||
//
|
//
|
||||||
auto confVersion = conf["config_version"].toVariant().toString();
|
auto confVersion = conf["config_version"].toVariant().toString();
|
||||||
@ -322,6 +319,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
QStringList themes = QStyleFactory::keys();
|
QStringList themes = QStyleFactory::keys();
|
||||||
|
//_qApp.setDesktopFileName("qv2ray.desktop");
|
||||||
|
|
||||||
if (themes.contains(QSTRING(confObject.uiConfig.theme))) {
|
if (themes.contains(QSTRING(confObject.uiConfig.theme))) {
|
||||||
_qApp.setStyle(QSTRING(confObject.uiConfig.theme));
|
_qApp.setStyle(QSTRING(confObject.uiConfig.theme));
|
||||||
@ -335,6 +333,11 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
#endif
|
#endif
|
||||||
|
QObject::connect(&_qApp, &SingleApplication::instanceStarted, [&w]() {
|
||||||
|
w.show();
|
||||||
|
w.raise();
|
||||||
|
w.activateWindow();
|
||||||
|
});
|
||||||
auto rcode = _qApp.exec();
|
auto rcode = _qApp.exec();
|
||||||
LOG(MODULE_INIT, "Quitting normally")
|
LOG(MODULE_INIT, "Quitting normally")
|
||||||
return rcode;
|
return rcode;
|
||||||
|
@ -306,7 +306,6 @@ void MainWindow::VersionUpdate(QByteArray &data)
|
|||||||
} else if (result == QMessageBox::Ignore) {
|
} else if (result == QMessageBox::Ignore) {
|
||||||
currentConfig.ignoredVersion = newversion.toString().toStdString();
|
currentConfig.ignoredVersion = newversion.toString().toStdString();
|
||||||
SetGlobalConfig(currentConfig);
|
SetGlobalConfig(currentConfig);
|
||||||
OnConfigListChanged(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +313,16 @@ void MainWindow::ReloadConnections()
|
|||||||
{
|
{
|
||||||
LOG(MODULE_UI, "Loading new GlobalConfig")
|
LOG(MODULE_UI, "Loading new GlobalConfig")
|
||||||
currentConfig = GetGlobalConfig();
|
currentConfig = GetGlobalConfig();
|
||||||
|
//
|
||||||
|
// Store the latency test value.
|
||||||
|
QMap<QString, double> latencyValueCache;
|
||||||
|
|
||||||
|
for (auto i = 0; i < connections.count(); i++) {
|
||||||
|
latencyValueCache[connections.keys()[i]] = connections.values()[i].latency;
|
||||||
|
}
|
||||||
|
|
||||||
connections.clear();
|
connections.clear();
|
||||||
|
SetEditWidgetEnable(false);
|
||||||
//
|
//
|
||||||
connectionListWidget->clear();
|
connectionListWidget->clear();
|
||||||
auto _regularConnections = GetRegularConnections(currentConfig.configs);
|
auto _regularConnections = GetRegularConnections(currentConfig.configs);
|
||||||
@ -325,7 +333,8 @@ void MainWindow::ReloadConnections()
|
|||||||
_o.subscriptionName = "";
|
_o.subscriptionName = "";
|
||||||
_o.connectionName = _regularConnections.keys()[i];
|
_o.connectionName = _regularConnections.keys()[i];
|
||||||
_o.config = _regularConnections.values()[i];
|
_o.config = _regularConnections.values()[i];
|
||||||
_o.latency = 0;
|
// Restore latency from cache.
|
||||||
|
_o.latency = latencyValueCache.contains(_o.connectionName) ? latencyValueCache[_o.connectionName] : 0;
|
||||||
connections[_o.connectionName] = _o;
|
connections[_o.connectionName] = _o;
|
||||||
connectionListWidget->addTopLevelItem(new QTreeWidgetItem(QStringList() << _o.connectionName));
|
connectionListWidget->addTopLevelItem(new QTreeWidgetItem(QStringList() << _o.connectionName));
|
||||||
}
|
}
|
||||||
@ -343,17 +352,16 @@ void MainWindow::ReloadConnections()
|
|||||||
_o.subscriptionName = subName;
|
_o.subscriptionName = subName;
|
||||||
_o.connectionName = _subsConnections.values()[i].keys()[j];
|
_o.connectionName = _subsConnections.values()[i].keys()[j];
|
||||||
_o.config = _subsConnections.values()[i].values()[j];
|
_o.config = _subsConnections.values()[i].values()[j];
|
||||||
_o.latency = 0;
|
//
|
||||||
auto connName = _o.connectionName + " (" + tr("Subscription:") + " " + _o.subscriptionName + ")";
|
auto connName = _o.connectionName + " (" + tr("Subscription:") + " " + _o.subscriptionName + ")";
|
||||||
|
_o.latency = latencyValueCache.contains(connName) ? latencyValueCache[connName] : 0;
|
||||||
connections[connName] = _o;
|
connections[connName] = _o;
|
||||||
subTopLevel->addChild(new QTreeWidgetItem(QStringList() << connName));
|
subTopLevel->addChild(new QTreeWidgetItem(QStringList() << connName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEditWidgetEnable(false);
|
|
||||||
|
|
||||||
//// We set the current item back...
|
//// We set the current item back...
|
||||||
if (!CurrentConnectionName.isEmpty()) {
|
if (!CurrentConnectionName.isEmpty() && connections.contains(CurrentConnectionName)) {
|
||||||
auto items = connectionListWidget->findItems(CurrentConnectionName, Qt::MatchExactly | Qt::MatchRecursive);
|
auto items = connectionListWidget->findItems(CurrentConnectionName, Qt::MatchExactly | Qt::MatchRecursive);
|
||||||
|
|
||||||
if (items.count() > 0 && IsConnectableItem(items.first())) {
|
if (items.count() > 0 && IsConnectableItem(items.first())) {
|
||||||
@ -516,7 +524,7 @@ void MainWindow::on_startButton_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (canSetSystemProxy) {
|
if (canSetSystemProxy) {
|
||||||
LOG(MODULE_UI, "Setting system proxy for simple config")
|
LOG(MODULE_UI, "Setting system proxy for simple config, HTTP only")
|
||||||
// --------------------We only use HTTP here->>|=========|
|
// --------------------We only use HTTP here->>|=========|
|
||||||
SetSystemProxy(proxyAddress, currentConfig.inboundConfig.http_port, usePAC);
|
SetSystemProxy(proxyAddress, currentConfig.inboundConfig.http_port, usePAC);
|
||||||
}
|
}
|
||||||
@ -532,6 +540,8 @@ void MainWindow::on_startButton_clicked()
|
|||||||
//
|
//
|
||||||
startButton->setEnabled(!startFlag);
|
startButton->setEnabled(!startFlag);
|
||||||
stopButton->setEnabled(startFlag);
|
stopButton->setEnabled(startFlag);
|
||||||
|
} else {
|
||||||
|
LOG(MODULE_UI, "vCore already started.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,18 +885,20 @@ void MainWindow::on_importConfigButton_clicked()
|
|||||||
ImportConfigWindow *w = new ImportConfigWindow(this);
|
ImportConfigWindow *w = new ImportConfigWindow(this);
|
||||||
auto configs = w->OpenImport();
|
auto configs = w->OpenImport();
|
||||||
|
|
||||||
for (auto conf : configs) {
|
if (!configs.isEmpty()) {
|
||||||
auto name = configs.key(conf, "");
|
for (auto conf : configs) {
|
||||||
|
auto name = configs.key(conf, "");
|
||||||
|
|
||||||
if (name.isEmpty())
|
if (name.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SaveConnectionConfig(conf, &name, false);
|
SaveConnectionConfig(conf, &name, false);
|
||||||
currentConfig.configs.push_back(name.toStdString());
|
currentConfig.configs.push_back(name.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
SetGlobalConfig(currentConfig);
|
||||||
|
OnConfigListChanged(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetGlobalConfig(currentConfig);
|
|
||||||
OnConfigListChanged(false);
|
|
||||||
}
|
}
|
||||||
void MainWindow::on_editConfigButton_clicked()
|
void MainWindow::on_editConfigButton_clicked()
|
||||||
{
|
{
|
||||||
@ -897,6 +909,8 @@ void MainWindow::on_editConfigButton_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto alias = connectionListWidget->selectedItems().first()->text(0);
|
auto alias = connectionListWidget->selectedItems().first()->text(0);
|
||||||
|
SUBSCRIPTION_CONFIG_MODIFY_ASK(alias)
|
||||||
|
//
|
||||||
auto outBoundRoot = connections[alias].config;
|
auto outBoundRoot = connections[alias].config;
|
||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
bool isChanged = false;
|
bool isChanged = false;
|
||||||
@ -917,11 +931,15 @@ void MainWindow::on_editConfigButton_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isChanged) {
|
if (isChanged) {
|
||||||
connections[alias].config = root;
|
if (IsSubscription(alias)) {
|
||||||
// true indicates the alias will NOT change
|
SaveSubscriptionConfig(root, connections[alias].subscriptionName, connections[alias].connectionName);
|
||||||
SaveConnectionConfig(root, &alias, true);
|
} else {
|
||||||
|
connections[alias].config = root;
|
||||||
|
// true indicates the alias will NOT change
|
||||||
|
SaveConnectionConfig(root, &alias, true);
|
||||||
|
}
|
||||||
|
|
||||||
OnConfigListChanged(alias == CurrentConnectionName);
|
OnConfigListChanged(alias == CurrentConnectionName);
|
||||||
ShowAndSetConnection(CurrentConnectionName, false, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MainWindow::on_reconnectButton_clicked()
|
void MainWindow::on_reconnectButton_clicked()
|
||||||
@ -939,16 +957,8 @@ void MainWindow::on_action_RCM_ConvToComplex_triggered()
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto alias = connectionListWidget->currentItem()->text(0);
|
auto alias = connectionListWidget->currentItem()->text(0);
|
||||||
|
SUBSCRIPTION_CONFIG_MODIFY_ASK(alias)
|
||||||
if (connections[alias].configType == CON_SUBSCRIPTION) {
|
//
|
||||||
if (QvMessageBoxAsk(this, tr("Editing a subscription config"), tr("You are trying to edit a config loaded from subscription.") +
|
|
||||||
NEWLINE + tr("All changes will be overwritten when the subscriptions are updated next time.") +
|
|
||||||
NEWLINE + tr("Are you still going to do so?")) != QMessageBox::Yes) {
|
|
||||||
// Not changing, return
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto outBoundRoot = connections[alias].config;
|
auto outBoundRoot = connections[alias].config;
|
||||||
CONFIGROOT root;
|
CONFIGROOT root;
|
||||||
bool isChanged = false;
|
bool isChanged = false;
|
||||||
@ -1004,9 +1014,9 @@ void MainWindow::on_pingTestBtn_clicked()
|
|||||||
latencyLabel->setText(tr("Testing..."));
|
latencyLabel->setText(tr("Testing..."));
|
||||||
// We get data from UI?
|
// We get data from UI?
|
||||||
auto alias = connectionListWidget->currentItem()->text(0);
|
auto alias = connectionListWidget->currentItem()->text(0);
|
||||||
int port = -1;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
int port = -1;
|
||||||
port = stoi(_portLabel->text().isEmpty() ? "0" : _portLabel->text().toStdString());
|
port = stoi(_portLabel->text().isEmpty() ? "0" : _portLabel->text().toStdString());
|
||||||
tcpingModel->StartPing(alias, _hostLabel->text(), port);
|
tcpingModel->StartPing(alias, _hostLabel->text(), port);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -1133,6 +1143,7 @@ void MainWindow::on_connectionListWidget_itemSelectionChanged()
|
|||||||
_OutBoundTypeLabel->setText(tr("N/A"));
|
_OutBoundTypeLabel->setText(tr("N/A"));
|
||||||
_hostLabel->setText(tr("N/A"));
|
_hostLabel->setText(tr("N/A"));
|
||||||
_portLabel->setText(tr("N/A"));
|
_portLabel->setText(tr("N/A"));
|
||||||
|
latencyLabel->setText(tr("N/A"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
|
|||||||
#if QV2RAY_USE_BUILTIN_DARKTHEME
|
#if QV2RAY_USE_BUILTIN_DARKTHEME
|
||||||
// If we use built in theme, it should always be fusion.
|
// If we use built in theme, it should always be fusion.
|
||||||
themeCombo->setEnabled(!CurrentConfig.uiConfig.useDarkTheme);
|
themeCombo->setEnabled(!CurrentConfig.uiConfig.useDarkTheme);
|
||||||
darkThemeLabel->setText(tr("Use Dark Theme"));
|
darkThemeLabel->setText(tr("Use Darkmode Theme"));
|
||||||
#endif
|
#endif
|
||||||
languageComboBox->setCurrentText(QSTRING(CurrentConfig.uiConfig.language));
|
languageComboBox->setCurrentText(QSTRING(CurrentConfig.uiConfig.language));
|
||||||
logLevelComboBox->setCurrentIndex(CurrentConfig.logLevel);
|
logLevelComboBox->setCurrentIndex(CurrentConfig.logLevel);
|
||||||
|
@ -135,14 +135,14 @@
|
|||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLabel" name="darkThemeLabel">
|
<widget class="QLabel" name="darkThemeLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Dark UI Icons</string>
|
<string>Darkmode UI Icons</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QLabel" name="label_36">
|
<widget class="QLabel" name="label_36">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Dark Tray Icon</string>
|
<string>Darkmode Tray Icon</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -1042,7 +1042,14 @@
|
|||||||
<string>Network Toolbar Settings</string>
|
<string>Network Toolbar Settings</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
<item row="1" column="0" rowspan="3">
|
<item row="3" column="1">
|
||||||
|
<widget class="QPushButton" name="applyNSBarSettingsBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Apply Network Speed Bar UI Settings</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" rowspan="3">
|
||||||
<widget class="QGroupBox" name="groupBox_6">
|
<widget class="QGroupBox" name="groupBox_6">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Items</string>
|
<string>Items</string>
|
||||||
@ -1187,7 +1194,14 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_33">
|
||||||
|
<property name="text">
|
||||||
|
<string>You can config how the network speed toolbar looks like in this panel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
<widget class="QFrame" name="nsBarVerticalLayout">
|
<widget class="QFrame" name="nsBarVerticalLayout">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
@ -1356,17 +1370,20 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_33">
|
<widget class="QLabel" name="label_64">
|
||||||
<property name="text">
|
<property name="font">
|
||||||
<string>You can config how the network speed toolbar looks like in this panel</string>
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<italic>true</italic>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: red</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QPushButton" name="applyNSBarSettingsBtn">
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Apply Network Speed Bar UI Settings</string>
|
<string>This feature for Windows is not stable yet.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
#include <QCryptographicHash>
|
|
||||||
|
|
||||||
#include "QvRunguard.hpp"
|
|
||||||
namespace Qv2ray
|
|
||||||
{
|
|
||||||
|
|
||||||
//from https://stackoverflow.com/a/28172162
|
|
||||||
QString RunGuard::generateKeyHash(const QString &key, const QString &salt)
|
|
||||||
{
|
|
||||||
QByteArray data;
|
|
||||||
data.append(key.toUtf8());
|
|
||||||
data.append(salt.toUtf8());
|
|
||||||
data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
RunGuard::RunGuard(const QString &key)
|
|
||||||
: key(key)
|
|
||||||
, memLockKey(generateKeyHash(key, "_memLockKey"))
|
|
||||||
, sharedmemKey(generateKeyHash(key, "_sharedmemKey"))
|
|
||||||
, sharedMem(sharedmemKey)
|
|
||||||
, memLock(memLockKey, 1)
|
|
||||||
{
|
|
||||||
memLock.acquire();
|
|
||||||
{
|
|
||||||
QSharedMemory fix(sharedmemKey); // Fix for *nix: http://habrahabr.ru/post/173281/
|
|
||||||
fix.attach();
|
|
||||||
}
|
|
||||||
memLock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
RunGuard::~RunGuard()
|
|
||||||
{
|
|
||||||
release();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RunGuard::isAnotherRunning()
|
|
||||||
{
|
|
||||||
if (sharedMem.isAttached()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memLock.acquire();
|
|
||||||
const bool isRunning = sharedMem.attach();
|
|
||||||
|
|
||||||
if (isRunning) {
|
|
||||||
sharedMem.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
memLock.release();
|
|
||||||
return isRunning;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RunGuard::isSingleInstance()
|
|
||||||
{
|
|
||||||
if (isAnotherRunning()) { // Extra check
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memLock.acquire();
|
|
||||||
const bool result = sharedMem.create(sizeof(quint64));
|
|
||||||
memLock.release();
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
release();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunGuard::release()
|
|
||||||
{
|
|
||||||
memLock.acquire();
|
|
||||||
|
|
||||||
if (sharedMem.isAttached()) {
|
|
||||||
sharedMem.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
memLock.release();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef RUNGUARD_H
|
|
||||||
#define RUNGUARD_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSharedMemory>
|
|
||||||
#include <QSystemSemaphore>
|
|
||||||
|
|
||||||
namespace Qv2ray
|
|
||||||
{
|
|
||||||
// From https://stackoverflow.com/a/28172162
|
|
||||||
class RunGuard
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit RunGuard(const QString &key);
|
|
||||||
~RunGuard();
|
|
||||||
|
|
||||||
bool isAnotherRunning();
|
|
||||||
bool isSingleInstance();
|
|
||||||
void release();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString generateKeyHash(const QString &key, const QString &salt);
|
|
||||||
const QString key;
|
|
||||||
const QString memLockKey;
|
|
||||||
const QString sharedmemKey;
|
|
||||||
|
|
||||||
QSharedMemory sharedMem;
|
|
||||||
QSystemSemaphore memLock;
|
|
||||||
|
|
||||||
Q_DISABLE_COPY(RunGuard)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif // RUNGUARD_H
|
|
Loading…
Reference in New Issue
Block a user