2012-06-10 16:50:54 +00:00
|
|
|
/*
|
2024-09-17 19:00:25 +00:00
|
|
|
* Deskflow -- mouse and keyboard sharing utility
|
2026-01-02 18:06:33 +00:00
|
|
|
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
|
|
|
|
* SPDX-FileCopyrightText: (C) 2024 - 2026 Chris Rizzitello <sithord48@gmail.com>
|
2026-06-08 20:37:23 +00:00
|
|
|
* SPDX-FileCopyrightText: (C) 2012 - 2024 Synergy App Ltd
|
2025-01-24 00:11:17 +00:00
|
|
|
* SPDX-FileCopyrightText: (C) 2008 Volker Lanz <vl@fidra.de>
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
2012-06-10 16:50:54 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "MainWindow.h"
|
2024-10-18 21:58:00 +00:00
|
|
|
#include "ui_MainWindow.h"
|
2015-04-15 12:09:22 +00:00
|
|
|
|
2025-03-21 00:40:37 +00:00
|
|
|
#include "Diagnostic.h"
|
2025-03-21 00:13:22 +00:00
|
|
|
#include "StyleUtils.h"
|
|
|
|
|
|
2024-10-31 02:49:24 +00:00
|
|
|
#include "dialogs/AboutDialog.h"
|
2026-02-13 16:30:34 +00:00
|
|
|
#include "dialogs/ClientConfigDialog.h"
|
2025-02-09 16:16:15 +00:00
|
|
|
#include "dialogs/FingerprintDialog.h"
|
2024-11-07 05:12:32 +00:00
|
|
|
#include "dialogs/ServerConfigDialog.h"
|
2024-11-07 04:17:03 +00:00
|
|
|
#include "dialogs/SettingsDialog.h"
|
2024-11-07 05:12:32 +00:00
|
|
|
|
2025-11-05 20:53:29 +00:00
|
|
|
#include "common/PlatformInfo.h"
|
2025-03-08 15:10:42 +00:00
|
|
|
#include "common/Settings.h"
|
2025-03-21 12:24:35 +00:00
|
|
|
#include "common/UrlConstants.h"
|
2025-12-30 15:43:12 +00:00
|
|
|
#include "common/VersionInfo.h"
|
2025-03-19 21:47:24 +00:00
|
|
|
#include "gui/Messages.h"
|
2025-11-22 17:49:09 +00:00
|
|
|
#include "gui/TlsUtility.h"
|
2024-08-07 14:05:18 +00:00
|
|
|
#include "gui/core/CoreProcess.h"
|
2025-02-06 12:03:51 +00:00
|
|
|
#include "gui/ipc/DaemonIpcClient.h"
|
2025-09-04 03:22:58 +00:00
|
|
|
#include "gui/widgets/LogDock.h"
|
2025-02-08 19:10:39 +00:00
|
|
|
#include "net/FingerprintDatabase.h"
|
2026-02-22 04:09:19 +00:00
|
|
|
#include "widgets/StatusBar.h"
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2026-03-30 18:38:03 +00:00
|
|
|
#include <QCheckBox>
|
2025-08-22 00:12:26 +00:00
|
|
|
#include <QCloseEvent>
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <QDesktopServices>
|
|
|
|
|
#include <QFileDialog>
|
2025-01-03 05:00:10 +00:00
|
|
|
#include <QLocalServer>
|
|
|
|
|
#include <QLocalSocket>
|
2014-02-14 16:21:02 +00:00
|
|
|
#include <QMenu>
|
|
|
|
|
#include <QMenuBar>
|
|
|
|
|
#include <QMessageBox>
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <QNetworkAccessManager>
|
2024-10-21 03:26:16 +00:00
|
|
|
#include <QNetworkInterface>
|
2024-07-22 16:48:02 +00:00
|
|
|
#include <QPushButton>
|
2024-07-08 14:37:51 +00:00
|
|
|
#include <QRegularExpression>
|
2025-01-12 06:48:23 +00:00
|
|
|
#include <QRegularExpressionValidator>
|
2025-08-22 00:12:26 +00:00
|
|
|
#include <QScreen>
|
2024-08-07 14:05:18 +00:00
|
|
|
#include <QScrollBar>
|
2024-10-21 03:26:16 +00:00
|
|
|
|
2024-10-18 21:58:00 +00:00
|
|
|
#include <memory>
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2025-11-20 02:07:38 +00:00
|
|
|
#if defined(Q_OS_MACOS)
|
2012-06-10 16:50:54 +00:00
|
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-09-17 19:00:25 +00:00
|
|
|
using namespace deskflow::gui;
|
2024-07-26 22:53:52 +00:00
|
|
|
|
2025-03-15 03:03:59 +00:00
|
|
|
MainWindow::MainWindow()
|
2024-10-18 21:58:00 +00:00
|
|
|
: ui{std::make_unique<Ui::MainWindow>()},
|
2025-03-09 06:01:41 +00:00
|
|
|
m_coreProcess(m_serverConfig),
|
2025-01-07 05:11:58 +00:00
|
|
|
m_trayIcon{new QSystemTrayIcon(this)},
|
2025-01-03 05:00:10 +00:00
|
|
|
m_guiDupeChecker{new QLocalServer(this)},
|
2025-02-06 12:03:51 +00:00
|
|
|
m_daemonIpcClient{new ipc::DaemonIpcClient(this)},
|
2025-09-04 03:22:58 +00:00
|
|
|
m_logDock{new LogDock(this)},
|
2026-02-22 04:09:19 +00:00
|
|
|
m_statusBar{new StatusBar(this)},
|
2025-10-28 00:33:26 +00:00
|
|
|
m_menuFile{new QMenu(this)},
|
|
|
|
|
m_menuEdit{new QMenu(this)},
|
|
|
|
|
m_menuView{new QMenu(this)},
|
|
|
|
|
m_menuHelp{new QMenu(this)},
|
2024-12-18 22:51:03 +00:00
|
|
|
m_actionAbout{new QAction(this)},
|
2025-10-28 00:20:52 +00:00
|
|
|
m_actionClearSettings{new QAction(this)},
|
|
|
|
|
m_actionReportBug{new QAction(this)},
|
|
|
|
|
m_actionMinimize{new QAction(this)},
|
|
|
|
|
m_actionQuit{new QAction(this)},
|
|
|
|
|
m_actionTrayQuit{new QAction(this)},
|
|
|
|
|
m_actionRestore{new QAction(this)},
|
|
|
|
|
m_actionSettings{new QAction(this)},
|
|
|
|
|
m_actionStartCore{new QAction(this)},
|
|
|
|
|
m_actionRestartCore{new QAction(this)},
|
2025-12-11 14:07:26 +00:00
|
|
|
m_actionStopCore{new QAction(this)},
|
2025-12-30 22:21:33 +00:00
|
|
|
m_networkMonitor{new NetworkMonitor(this)}
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-01-13 03:51:24 +00:00
|
|
|
ui->setupUi(this);
|
2025-01-19 04:37:15 +00:00
|
|
|
|
2025-10-25 14:56:04 +00:00
|
|
|
setWindowIcon(QIcon::fromTheme(kRevFqdnName));
|
2025-07-19 00:20:51 +00:00
|
|
|
|
2025-09-04 03:22:58 +00:00
|
|
|
addDockWidget(Qt::BottomDockWidgetArea, m_logDock);
|
2025-07-14 13:56:21 +00:00
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
// Setup Actions
|
|
|
|
|
m_actionAbout->setMenuRole(QAction::AboutRole);
|
2025-01-19 04:37:15 +00:00
|
|
|
m_actionAbout->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::HelpAbout));
|
2024-12-18 22:51:03 +00:00
|
|
|
|
2025-09-04 16:26:25 +00:00
|
|
|
m_actionMinimize->setIcon(QIcon::fromTheme(QStringLiteral("window-minimize-pip")));
|
|
|
|
|
m_actionRestore->setIcon(QIcon::fromTheme(QStringLiteral("window-restore-pip")));
|
|
|
|
|
|
2025-11-05 20:55:51 +00:00
|
|
|
if (!deskflow::platform::isWindows()) {
|
|
|
|
|
m_actionQuit->setShortcut(QKeySequence::Quit);
|
|
|
|
|
m_actionTrayQuit->setShortcut(QKeySequence::Quit);
|
|
|
|
|
}
|
2024-12-18 22:51:03 +00:00
|
|
|
|
2026-01-16 02:37:34 +00:00
|
|
|
m_actionQuit->setIcon(QIcon::fromTheme("application-exit"));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionQuit->setMenuRole(QAction::QuitRole);
|
|
|
|
|
|
2026-01-16 02:37:34 +00:00
|
|
|
m_actionTrayQuit->setIcon(QIcon::fromTheme("application-exit"));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionTrayQuit->setMenuRole(QAction::NoRole);
|
2025-01-18 16:47:05 +00:00
|
|
|
|
2025-01-19 04:23:15 +00:00
|
|
|
m_actionClearSettings->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-all")));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionClearSettings->setMenuRole(QAction::NoRole);
|
2025-01-19 04:23:15 +00:00
|
|
|
|
2025-01-19 04:07:52 +00:00
|
|
|
m_actionSettings->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionSettings->setMenuRole(QAction::PreferencesRole);
|
2025-01-19 03:51:44 +00:00
|
|
|
|
2025-01-19 05:04:28 +00:00
|
|
|
m_actionStartCore->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionStartCore->setMenuRole(QAction::NoRole);
|
2025-01-19 04:50:47 +00:00
|
|
|
|
2025-06-04 02:48:03 +00:00
|
|
|
m_actionRestartCore->setVisible(false);
|
|
|
|
|
m_actionRestartCore->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionRestartCore->setMenuRole(QAction::NoRole);
|
2025-06-04 02:48:03 +00:00
|
|
|
|
2025-01-19 04:50:47 +00:00
|
|
|
m_actionStopCore->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ProcessStop));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionStopCore->setMenuRole(QAction::NoRole);
|
2024-12-18 22:51:03 +00:00
|
|
|
|
2026-01-16 02:37:34 +00:00
|
|
|
m_actionReportBug->setIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug")));
|
2025-11-29 15:03:14 +00:00
|
|
|
m_actionReportBug->setMenuRole(QAction::NoRole);
|
2025-01-18 16:36:12 +00:00
|
|
|
|
2025-01-03 05:00:10 +00:00
|
|
|
// Setup the Instance Checking
|
|
|
|
|
// In case of a previous crash remove first
|
2025-08-14 23:50:25 +00:00
|
|
|
QLocalServer::removeServer(m_guiSocketName);
|
2025-01-03 05:00:10 +00:00
|
|
|
m_guiDupeChecker->listen(m_guiSocketName);
|
|
|
|
|
|
2024-08-10 23:58:24 +00:00
|
|
|
createMenuBar();
|
2024-08-01 00:13:01 +00:00
|
|
|
setupControls();
|
2025-10-28 00:20:52 +00:00
|
|
|
updateText();
|
2024-07-26 22:53:52 +00:00
|
|
|
connectSlots();
|
2025-01-07 05:22:48 +00:00
|
|
|
setupTrayIcon();
|
2024-12-19 04:44:50 +00:00
|
|
|
updateScreenName();
|
|
|
|
|
|
2025-03-15 03:03:59 +00:00
|
|
|
qDebug().noquote() << "active settings path:" << Settings::settingsPath();
|
2024-12-05 21:32:01 +00:00
|
|
|
|
2025-11-22 17:15:23 +00:00
|
|
|
// Force generation of a certificate on the host
|
2025-11-22 13:32:00 +00:00
|
|
|
if (TlsUtility::isEnabled()) {
|
2025-06-16 01:21:16 +00:00
|
|
|
if (Settings::value(Settings::Security::KeySize).toInt() < 2048) {
|
|
|
|
|
QMessageBox::information(
|
|
|
|
|
this, kAppName,
|
|
|
|
|
tr("Your current TLS key is smaller than the minimum allowed size, A new key 2048-bit key will be generated.")
|
|
|
|
|
);
|
2025-11-22 15:06:20 +00:00
|
|
|
Settings::setValue(Settings::Security::KeySize, 2048);
|
|
|
|
|
}
|
|
|
|
|
if (!TlsUtility::isCertValid()) {
|
2025-11-22 16:38:07 +00:00
|
|
|
generateCertificate();
|
2025-11-22 17:15:23 +00:00
|
|
|
} else {
|
2025-11-25 02:01:03 +00:00
|
|
|
m_fingerprint = {QCryptographicHash::Sha256, TlsUtility::certFingerprint()};
|
2025-02-11 15:17:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-02-17 13:44:20 +00:00
|
|
|
|
|
|
|
|
applyConfig();
|
2026-02-26 12:46:06 +00:00
|
|
|
m_statusBar->setSecurityIcon(TlsUtility::isEnabled());
|
2026-02-17 13:44:20 +00:00
|
|
|
restoreWindow();
|
2024-08-01 00:13:01 +00:00
|
|
|
}
|
2024-10-17 18:04:35 +00:00
|
|
|
MainWindow::~MainWindow()
|
|
|
|
|
{
|
2025-12-11 14:07:26 +00:00
|
|
|
// Stop network monitoring
|
|
|
|
|
if (m_networkMonitor) {
|
|
|
|
|
m_networkMonitor->stopMonitoring();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-03 05:00:10 +00:00
|
|
|
m_guiDupeChecker->close();
|
2025-02-04 00:30:00 +00:00
|
|
|
m_coreProcess.cleanup();
|
2024-10-17 18:04:35 +00:00
|
|
|
}
|
2024-08-01 00:13:01 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::restoreWindow()
|
|
|
|
|
{
|
2025-08-30 13:46:43 +00:00
|
|
|
auto windowGeometry = Settings::value(Settings::Gui::WindowGeometry).toRect();
|
|
|
|
|
const auto totalGeometry = QGuiApplication::primaryScreen()->availableGeometry();
|
2025-03-05 05:28:05 +00:00
|
|
|
if (!windowGeometry.isValid()) {
|
2025-08-30 13:46:43 +00:00
|
|
|
adjustSize();
|
|
|
|
|
windowGeometry = geometry();
|
|
|
|
|
} else {
|
|
|
|
|
setGeometry(windowGeometry);
|
2025-03-05 05:28:05 +00:00
|
|
|
}
|
2025-08-30 13:46:43 +00:00
|
|
|
m_expandedSize = geometry().size();
|
2025-03-05 05:28:05 +00:00
|
|
|
|
2025-08-30 13:46:43 +00:00
|
|
|
if (!totalGeometry.contains(windowGeometry)) {
|
|
|
|
|
QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
|
|
|
|
|
move(screenGeometry.center() - rect().center());
|
2024-08-01 00:13:01 +00:00
|
|
|
}
|
2025-08-30 13:46:43 +00:00
|
|
|
|
|
|
|
|
if (!Settings::value(Settings::Gui::LogExpanded).toBool())
|
|
|
|
|
setFixedSize(size());
|
2024-08-01 00:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::setupControls()
|
|
|
|
|
{
|
2024-07-26 22:53:52 +00:00
|
|
|
secureSocket(false);
|
|
|
|
|
|
2025-03-14 16:09:29 +00:00
|
|
|
ui->btnConfigureServer->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
|
2026-02-13 16:30:34 +00:00
|
|
|
ui->btnConfigureClient->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
|
2025-08-07 16:17:19 +00:00
|
|
|
|
2025-03-07 02:11:19 +00:00
|
|
|
if (Settings::value(Settings::Core::LastVersion).toString() != kVersion) {
|
|
|
|
|
Settings::setValue(Settings::Core::LastVersion, kVersion);
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-30 13:46:43 +00:00
|
|
|
if (!Settings::value(Settings::Gui::LogExpanded).toBool()) {
|
2025-09-04 03:22:58 +00:00
|
|
|
m_logDock->hide();
|
2025-02-18 12:52:25 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-23 21:28:53 +00:00
|
|
|
ui->serverOptions->setVisible(false);
|
|
|
|
|
ui->clientOptions->setVisible(false);
|
|
|
|
|
|
2025-03-10 02:50:44 +00:00
|
|
|
const auto coreMode = Settings::value(Settings::Core::CoreMode).value<Settings::CoreMode>();
|
|
|
|
|
ui->rbModeClient->setChecked(coreMode == Settings::CoreMode::Client);
|
|
|
|
|
ui->rbModeServer->setChecked(coreMode == Settings::CoreMode::Server);
|
|
|
|
|
|
2025-01-12 06:48:23 +00:00
|
|
|
ui->lineEditName->setValidator(new QRegularExpressionValidator(m_nameRegEx, this));
|
|
|
|
|
ui->lineEditName->setVisible(false);
|
2026-02-24 01:35:40 +00:00
|
|
|
ui->lineEditName->installEventFilter(this);
|
2025-01-12 06:48:23 +00:00
|
|
|
|
2025-11-05 21:34:53 +00:00
|
|
|
if (deskflow::platform::isMac()) {
|
|
|
|
|
ui->rbModeServer->setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
|
|
|
ui->rbModeClient->setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
|
|
|
ui->btnSaveServerConfig->setFixedWidth(ui->btnSaveServerConfig->height());
|
|
|
|
|
} else {
|
|
|
|
|
ui->btnSaveServerConfig->setIconSize(QSize(22, 22));
|
|
|
|
|
}
|
2026-02-22 04:09:19 +00:00
|
|
|
setStatusBar(m_statusBar);
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Begin slots
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// remember: using queued connection allows the render loop to run before
|
|
|
|
|
// executing the slot. the default is to instantly call the slot when the
|
|
|
|
|
// signal is emitted from the thread that owns the receiver's object.
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::connectSlots()
|
|
|
|
|
{
|
2025-03-15 02:17:08 +00:00
|
|
|
connect(Settings::instance(), &Settings::serverSettingsChanged, this, &MainWindow::serverConfigSaving);
|
2025-03-07 00:26:17 +00:00
|
|
|
connect(Settings::instance(), &Settings::settingsChanged, this, &MainWindow::settingsChanged);
|
|
|
|
|
|
2025-02-04 01:22:17 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::error, this, &MainWindow::coreProcessError);
|
2025-02-04 01:03:31 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::logLine, this, &MainWindow::handleLogLine);
|
2025-05-15 23:18:57 +00:00
|
|
|
connect(
|
|
|
|
|
&m_coreProcess, &CoreProcess::processStateChanged, this, &MainWindow::coreProcessStateChanged,
|
|
|
|
|
Qt::QueuedConnection
|
|
|
|
|
);
|
2025-02-04 01:22:17 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::connectionStateChanged, this, &MainWindow::coreConnectionStateChanged);
|
2025-02-11 02:14:39 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::secureSocket, this, &MainWindow::secureSocket);
|
2025-04-18 12:56:37 +00:00
|
|
|
connect(
|
|
|
|
|
&m_coreProcess, &CoreProcess::daemonIpcClientConnectionFailed, this, &MainWindow::daemonIpcClientConnectionFailed
|
|
|
|
|
);
|
2026-02-22 04:09:19 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::securityLevelChanged, m_statusBar, &StatusBar::setSecurityLevel);
|
2024-08-07 14:05:18 +00:00
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
connect(m_actionAbout, &QAction::triggered, this, &MainWindow::openAboutDialog);
|
|
|
|
|
connect(m_actionClearSettings, &QAction::triggered, this, &MainWindow::clearSettings);
|
2025-01-18 16:36:12 +00:00
|
|
|
connect(m_actionReportBug, &QAction::triggered, this, &MainWindow::openHelpUrl);
|
2024-12-18 22:51:03 +00:00
|
|
|
connect(m_actionMinimize, &QAction::triggered, this, &MainWindow::hide);
|
2024-07-26 22:53:52 +00:00
|
|
|
|
2025-01-02 19:04:49 +00:00
|
|
|
connect(m_actionQuit, &QAction::triggered, this, &MainWindow::close);
|
2025-01-09 14:47:04 +00:00
|
|
|
connect(m_actionTrayQuit, &QAction::triggered, this, &MainWindow::close);
|
2024-12-18 22:51:03 +00:00
|
|
|
connect(m_actionRestore, &QAction::triggered, this, &MainWindow::showAndActivate);
|
|
|
|
|
connect(m_actionSettings, &QAction::triggered, this, &MainWindow::openSettings);
|
|
|
|
|
connect(m_actionStartCore, &QAction::triggered, this, &MainWindow::startCore);
|
2025-06-04 02:48:03 +00:00
|
|
|
connect(m_actionRestartCore, &QAction::triggered, this, &MainWindow::resetCore);
|
2024-12-18 22:51:03 +00:00
|
|
|
connect(m_actionStopCore, &QAction::triggered, this, &MainWindow::stopCore);
|
|
|
|
|
|
2025-11-05 21:34:53 +00:00
|
|
|
// Mac os tray will only show a menu
|
|
|
|
|
if (!deskflow::platform::isMac())
|
|
|
|
|
connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
|
2024-08-07 14:05:18 +00:00
|
|
|
|
2026-03-26 12:34:18 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::connectedClientsChanged, this, &MainWindow::serverClientsChanged);
|
2026-03-26 14:17:56 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::unrecognisedClient, this, &MainWindow::handleUnrecognisedClient);
|
|
|
|
|
connect(&m_coreProcess, &CoreProcess::connectionRefused, this, &MainWindow::handleConnectionRefused);
|
|
|
|
|
connect(&m_coreProcess, &CoreProcess::retryIn, this, &MainWindow::updateTimeoutDelay);
|
|
|
|
|
connect(&m_coreProcess, &CoreProcess::peerFingerprint, this, &MainWindow::handlePeerFingerprint);
|
2026-03-30 18:38:03 +00:00
|
|
|
connect(&m_coreProcess, &CoreProcess::missingKeyboardLayouts, this, &MainWindow::handleMissingKeyboardLayouts);
|
2024-12-18 23:10:22 +00:00
|
|
|
|
2025-11-30 19:51:14 +00:00
|
|
|
if (Settings::value(Settings::Gui::AutoStartCore).toBool()) {
|
|
|
|
|
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStopCore, &QAction::trigger, Qt::UniqueConnection);
|
|
|
|
|
} else {
|
|
|
|
|
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStartCore, &QAction::trigger, Qt::UniqueConnection);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 02:53:03 +00:00
|
|
|
connect(ui->btnRestartCore, &QPushButton::clicked, this, &MainWindow::resetCore);
|
2024-12-19 00:05:51 +00:00
|
|
|
|
2025-08-19 23:53:39 +00:00
|
|
|
connect(ui->lineHostname, &QLineEdit::returnPressed, ui->btnRestartCore, &QPushButton::click);
|
2025-04-19 17:26:41 +00:00
|
|
|
connect(ui->lineHostname, &QLineEdit::textChanged, this, &MainWindow::remoteHostChanged);
|
2024-12-19 00:05:51 +00:00
|
|
|
|
2025-03-14 16:03:24 +00:00
|
|
|
connect(ui->btnSaveServerConfig, &QPushButton::clicked, this, &MainWindow::saveServerConfig);
|
2024-12-19 00:26:36 +00:00
|
|
|
connect(ui->btnConfigureServer, &QPushButton::clicked, this, [this] { showConfigureServer(""); });
|
2026-02-13 16:30:34 +00:00
|
|
|
connect(ui->btnConfigureClient, &QPushButton::clicked, this, [this] { showConfigureClient(); });
|
2024-12-19 00:33:05 +00:00
|
|
|
connect(ui->lblComputerName, &QLabel::linkActivated, this, &MainWindow::openSettings);
|
2024-12-19 00:47:50 +00:00
|
|
|
|
2025-02-23 21:28:53 +00:00
|
|
|
connect(ui->rbModeServer, &QRadioButton::toggled, this, &MainWindow::coreModeToggled);
|
|
|
|
|
connect(ui->rbModeClient, &QRadioButton::toggled, this, &MainWindow::coreModeToggled);
|
2024-12-05 21:32:01 +00:00
|
|
|
|
2025-09-04 03:22:58 +00:00
|
|
|
connect(m_logDock->toggleViewAction(), &QAction::toggled, this, &MainWindow::toggleLogVisible);
|
2025-01-03 05:00:10 +00:00
|
|
|
|
2026-02-22 04:09:19 +00:00
|
|
|
connect(m_statusBar, &StatusBar::requestShowMyFingerprints, this, &MainWindow::showMyFingerprint);
|
|
|
|
|
connect(m_statusBar, &StatusBar::requestUpdateVersion, this, &MainWindow::openGetNewVersionUrl);
|
|
|
|
|
connect(&m_versionChecker, &VersionChecker::updateFound, m_statusBar, &StatusBar::updateFound);
|
2025-02-19 23:54:43 +00:00
|
|
|
|
2025-01-03 05:00:10 +00:00
|
|
|
connect(m_guiDupeChecker, &QLocalServer::newConnection, this, &MainWindow::showAndActivate);
|
2025-01-12 06:48:23 +00:00
|
|
|
|
|
|
|
|
connect(ui->btnEditName, &QPushButton::clicked, this, &MainWindow::showHostNameEditor);
|
|
|
|
|
|
|
|
|
|
connect(ui->lineEditName, &QLineEdit::editingFinished, this, &MainWindow::setHostName);
|
2025-12-11 14:07:26 +00:00
|
|
|
|
|
|
|
|
connect(m_networkMonitor, &NetworkMonitor::ipAddressesChanged, this, &MainWindow::updateIpLabel);
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
2016-10-15 14:30:28 +00:00
|
|
|
|
2024-12-05 21:32:01 +00:00
|
|
|
void MainWindow::toggleLogVisible(bool visible)
|
|
|
|
|
{
|
2025-11-25 15:35:00 +00:00
|
|
|
// When the main window is hidden e.g. close to tray / minimized), this also triggers the log visibility toggle,
|
2025-09-10 08:56:37 +00:00
|
|
|
// but we don't want to hide the log in this case since we would need to un-hide it when the window is shown again.
|
2025-11-25 15:35:00 +00:00
|
|
|
if (!isVisible() || isMinimized()) {
|
2025-09-10 08:56:37 +00:00
|
|
|
qDebug() << "not toggling log, window not visible";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-30 13:46:43 +00:00
|
|
|
setFixedSize(16777215, 16777215);
|
|
|
|
|
Settings::setValue(Settings::Gui::LogExpanded, visible);
|
2024-12-05 21:32:01 +00:00
|
|
|
if (visible) {
|
2025-09-04 03:22:58 +00:00
|
|
|
if (m_logDock->isFloating()) {
|
|
|
|
|
adjustSize();
|
|
|
|
|
setFixedSize(size());
|
|
|
|
|
} else {
|
|
|
|
|
QTimer::singleShot(15, this, [&] { resize(m_expandedSize); });
|
|
|
|
|
}
|
2024-12-05 21:32:01 +00:00
|
|
|
} else {
|
2025-09-04 03:22:58 +00:00
|
|
|
if (!m_logDock->isFloating()) {
|
|
|
|
|
m_expandedSize = geometry().size();
|
|
|
|
|
}
|
|
|
|
|
m_logDock->hide();
|
|
|
|
|
if (!m_logDock->isFloating()) {
|
|
|
|
|
adjustSize();
|
|
|
|
|
}
|
2025-08-30 13:46:43 +00:00
|
|
|
setFixedSize(size());
|
2024-12-05 21:32:01 +00:00
|
|
|
}
|
2025-08-30 13:46:43 +00:00
|
|
|
Settings::setValue(Settings::Gui::WindowGeometry, geometry());
|
2024-12-05 21:32:01 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-07 00:26:17 +00:00
|
|
|
void MainWindow::settingsChanged(const QString &key)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-03-09 01:13:26 +00:00
|
|
|
if (key == Settings::Log::Level) {
|
|
|
|
|
m_coreProcess.applyLogLevel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 15:44:38 +00:00
|
|
|
if (key == Settings::Core::ComputerName)
|
2025-03-09 03:09:38 +00:00
|
|
|
updateScreenName();
|
|
|
|
|
|
2025-03-07 00:26:17 +00:00
|
|
|
if ((key == Settings::Security::Certificate) || (key == Settings::Security::KeySize) ||
|
2025-03-07 00:42:16 +00:00
|
|
|
(key == Settings::Security::TlsEnabled) || (key == Settings::Security::CheckPeers)) {
|
2025-11-22 15:06:20 +00:00
|
|
|
if (TlsUtility::isEnabled() && !TlsUtility::isCertValid()) {
|
|
|
|
|
qWarning() << tr("invalid certificate, generating a new one");
|
2025-11-22 17:35:41 +00:00
|
|
|
TlsUtility::generateCertificate();
|
2025-03-07 00:26:17 +00:00
|
|
|
}
|
2026-02-22 04:09:19 +00:00
|
|
|
updateSecurityIcon(m_statusBar->securityIconVisible());
|
2025-03-09 01:13:26 +00:00
|
|
|
return;
|
2025-03-07 00:26:17 +00:00
|
|
|
}
|
2024-10-17 18:04:35 +00:00
|
|
|
}
|
2024-07-26 22:53:52 +00:00
|
|
|
|
2025-03-15 02:17:08 +00:00
|
|
|
void MainWindow::serverConfigSaving()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-03-07 00:26:17 +00:00
|
|
|
m_serverConfig.commit();
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-04 01:22:17 +00:00
|
|
|
void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-12-06 23:30:38 +00:00
|
|
|
if (reason != QSystemTrayIcon::Trigger)
|
|
|
|
|
return;
|
|
|
|
|
isVisible() ? hide() : showAndActivate();
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-04 01:22:17 +00:00
|
|
|
void MainWindow::coreProcessError(CoreProcess::Error error)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-07 14:05:18 +00:00
|
|
|
if (error == CoreProcess::Error::AddressMissing) {
|
|
|
|
|
QMessageBox::warning(
|
2024-12-19 04:28:46 +00:00
|
|
|
this, tr("Address missing"), tr("Please enter the hostname or IP address of the other computer.")
|
2024-10-17 18:04:35 +00:00
|
|
|
);
|
2024-08-07 14:05:18 +00:00
|
|
|
} else if (error == CoreProcess::Error::StartFailed) {
|
|
|
|
|
show();
|
2026-02-21 17:18:07 +00:00
|
|
|
auto message = tr("The Core executable could not be started.\n"
|
|
|
|
|
"Please check if you have sufficient permissions to run %1.")
|
|
|
|
|
.arg(kCoreBinName);
|
|
|
|
|
|
|
|
|
|
if (Settings::value(Settings::Core::CoreMode) == Settings::CoreMode::Server) {
|
|
|
|
|
const auto mode =
|
|
|
|
|
Settings::value(Settings::Server::ExternalConfigFile).toBool() ? tr("read") : tr("read and write");
|
|
|
|
|
message.append(tr("\nAdditionally, check you are able to %1 the server config file: %2")
|
|
|
|
|
.arg(mode, Settings::serverConfigFile()));
|
|
|
|
|
}
|
|
|
|
|
QMessageBox::warning(this, kAppName, message);
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
void MainWindow::startCore()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-12-11 14:07:26 +00:00
|
|
|
// Save current IP state when server starts
|
2026-01-18 14:23:50 +00:00
|
|
|
if (m_coreProcess.mode() == CoreMode::Server && Settings::value(Settings::Core::Interface).toString().isEmpty()) {
|
2026-02-24 02:07:10 +00:00
|
|
|
m_serverStartIPs = NetworkMonitor::validAddresses();
|
2026-01-02 21:12:53 +00:00
|
|
|
m_serverStartSuggestedIP = m_serverStartIPs.isEmpty() ? "" : m_serverStartIPs.first();
|
2025-12-11 14:07:26 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-04 02:48:03 +00:00
|
|
|
m_actionStartCore->setVisible(false);
|
|
|
|
|
m_actionRestartCore->setVisible(true);
|
2026-02-26 21:47:12 +00:00
|
|
|
m_coreProcess.start();
|
2024-08-09 13:03:48 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
void MainWindow::stopCore()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-12-19 04:19:28 +00:00
|
|
|
qDebug() << "stopping core process";
|
2025-02-04 00:30:00 +00:00
|
|
|
m_coreProcess.stop();
|
2025-06-04 02:48:03 +00:00
|
|
|
m_actionStartCore->setVisible(true);
|
|
|
|
|
m_actionRestartCore->setVisible(false);
|
2024-08-09 13:03:48 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
void MainWindow::clearSettings()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-10 23:58:24 +00:00
|
|
|
if (!messages::showClearSettings(this)) {
|
2024-12-19 04:19:28 +00:00
|
|
|
qDebug() << "clear settings cancelled";
|
2024-08-10 23:58:24 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-20 12:25:30 +00:00
|
|
|
m_networkMonitor->stopMonitoring();
|
|
|
|
|
|
|
|
|
|
disconnect(&m_coreProcess, nullptr, this, nullptr);
|
|
|
|
|
disconnect(&m_versionChecker, nullptr, this, nullptr);
|
|
|
|
|
disconnect(m_guiDupeChecker, nullptr, this, nullptr);
|
|
|
|
|
disconnect(m_trayIcon, nullptr, this, nullptr);
|
|
|
|
|
disconnect(m_logDock->toggleViewAction(), nullptr, this, nullptr);
|
|
|
|
|
|
2025-02-04 00:30:00 +00:00
|
|
|
m_coreProcess.stop();
|
2025-03-03 18:01:32 +00:00
|
|
|
m_coreProcess.clearSettings();
|
2024-08-10 23:58:24 +00:00
|
|
|
|
2025-02-04 00:30:00 +00:00
|
|
|
m_saveOnExit = false;
|
2025-03-15 02:48:13 +00:00
|
|
|
diagnostic::clearSettings(true);
|
2024-08-10 23:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 16:03:24 +00:00
|
|
|
bool MainWindow::saveServerConfig()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-03-14 16:03:24 +00:00
|
|
|
QString fileName = QFileDialog::getSaveFileName(this, tr("Save server configuration as..."));
|
2024-07-26 22:53:52 +00:00
|
|
|
|
2025-02-04 00:30:00 +00:00
|
|
|
if (!fileName.isEmpty() && !m_serverConfig.save(fileName)) {
|
2025-03-14 16:03:24 +00:00
|
|
|
QMessageBox::warning(this, tr("Save failed"), tr("Could not save server configuration to file."));
|
2024-07-26 22:53:52 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
void MainWindow::openAboutDialog()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-08-03 00:17:29 +00:00
|
|
|
AboutDialog about(this);
|
|
|
|
|
about.exec();
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
void MainWindow::openHelpUrl() const
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-10-01 13:30:24 +00:00
|
|
|
QDesktopServices::openUrl(QUrl(kUrlHelp));
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-19 23:54:43 +00:00
|
|
|
void MainWindow::openGetNewVersionUrl() const
|
|
|
|
|
{
|
2026-01-16 02:37:34 +00:00
|
|
|
QDesktopServices::openUrl(QUrl(kUrlDownload));
|
2025-02-19 23:54:43 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-18 22:51:03 +00:00
|
|
|
void MainWindow::openSettings()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-02-16 19:11:32 +00:00
|
|
|
auto dialog = SettingsDialog(this, m_serverConfig);
|
2024-08-08 17:41:59 +00:00
|
|
|
|
|
|
|
|
if (dialog.exec() == QDialog::Accepted) {
|
2025-03-15 02:17:08 +00:00
|
|
|
Settings::save();
|
2024-08-03 00:17:29 +00:00
|
|
|
|
|
|
|
|
applyConfig();
|
|
|
|
|
|
2025-02-04 00:30:00 +00:00
|
|
|
if (m_coreProcess.isStarted()) {
|
|
|
|
|
m_coreProcess.restart();
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-18 23:49:10 +00:00
|
|
|
void MainWindow::resetCore()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-02-04 00:30:00 +00:00
|
|
|
m_coreProcess.restart();
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-19 00:39:07 +00:00
|
|
|
void MainWindow::showMyFingerprint()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-11-22 17:15:23 +00:00
|
|
|
FingerprintDialog fingerprintDialog(this, m_fingerprint);
|
2025-02-09 16:16:15 +00:00
|
|
|
fingerprintDialog.exec();
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-14 16:00:07 +00:00
|
|
|
void MainWindow::coreModeToggled(bool checked)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-02-14 16:00:07 +00:00
|
|
|
// this method is called when rbClient or rbServer toggles
|
|
|
|
|
// with both being in the same group one must be turned on if the other is turned off
|
|
|
|
|
// only react to toggle on to avoid calling everything twice when the user switches modes
|
|
|
|
|
if (!checked)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-02-14 16:09:58 +00:00
|
|
|
Settings::CoreMode mode = Settings::CoreMode::None;
|
2025-02-23 21:28:53 +00:00
|
|
|
|
2026-02-14 16:09:58 +00:00
|
|
|
if (ui->rbModeServer->isChecked())
|
|
|
|
|
mode = Settings::CoreMode::Server;
|
|
|
|
|
if (ui->rbModeClient->isChecked())
|
|
|
|
|
mode = Settings::CoreMode::Client;
|
2025-02-23 21:28:53 +00:00
|
|
|
|
2026-02-14 16:09:58 +00:00
|
|
|
qDebug() << QStringLiteral("change mode to: %1").arg(QVariant::fromValue(mode).toString());
|
|
|
|
|
|
2026-02-14 16:11:31 +00:00
|
|
|
if (m_coreProcess.isStarted() && m_coreProcess.mode() != mode)
|
|
|
|
|
m_coreProcess.stop();
|
|
|
|
|
m_coreProcess.setMode(mode);
|
|
|
|
|
|
2026-02-14 16:09:58 +00:00
|
|
|
Settings::setValue(Settings::Core::CoreMode, mode);
|
2025-03-15 02:17:08 +00:00
|
|
|
Settings::save();
|
2026-02-14 16:09:58 +00:00
|
|
|
|
2026-02-14 17:05:14 +00:00
|
|
|
updateModeControls();
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-14 17:05:14 +00:00
|
|
|
void MainWindow::updateModeControls()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-02-14 17:05:14 +00:00
|
|
|
const auto mode = m_coreProcess.mode();
|
|
|
|
|
const bool isServer = mode == Settings::CoreMode::Server;
|
|
|
|
|
const bool isClient = mode == Settings::CoreMode::Client;
|
2026-04-20 14:52:14 +00:00
|
|
|
|
2026-02-14 17:05:14 +00:00
|
|
|
ui->serverOptions->setVisible(isServer);
|
|
|
|
|
ui->clientOptions->setVisible(isClient);
|
|
|
|
|
ui->lblNoMode->setVisible(!isServer && !isClient);
|
2026-02-24 01:34:41 +00:00
|
|
|
toggleCanRunCore(canRunCore());
|
2026-02-14 17:05:14 +00:00
|
|
|
|
2026-04-20 14:52:14 +00:00
|
|
|
ui->lblIpAddresses->setVisible(
|
|
|
|
|
(isClient && !Settings::value(Settings::Core::Interface).toString().isEmpty()) || isServer
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (ui->lblIpAddresses->isVisible())
|
2025-12-11 14:07:26 +00:00
|
|
|
updateNetworkInfo();
|
2026-04-20 14:52:14 +00:00
|
|
|
|
|
|
|
|
if (isServer) {
|
2025-12-11 14:07:26 +00:00
|
|
|
m_networkMonitor->startMonitoring();
|
|
|
|
|
} else {
|
|
|
|
|
m_networkMonitor->stopMonitoring();
|
|
|
|
|
}
|
2026-02-14 17:05:14 +00:00
|
|
|
|
|
|
|
|
if (isServer || isClient)
|
|
|
|
|
updateModeControlLabels();
|
2024-07-26 22:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-19 23:53:39 +00:00
|
|
|
void MainWindow::updateModeControlLabels()
|
|
|
|
|
{
|
|
|
|
|
const bool isServer = m_coreProcess.mode() == CoreMode::Server;
|
|
|
|
|
const bool isStarted = m_coreProcess.isStarted();
|
|
|
|
|
|
|
|
|
|
QString startText;
|
|
|
|
|
QString stopText;
|
|
|
|
|
QIcon startIcon;
|
|
|
|
|
QIcon stopIcon;
|
|
|
|
|
|
|
|
|
|
if (isServer) {
|
|
|
|
|
startText = tr("Start");
|
|
|
|
|
stopText = tr("Stop");
|
|
|
|
|
startIcon = QIcon::fromTheme(QStringLiteral("system-run"));
|
|
|
|
|
stopIcon = QIcon::fromTheme(QIcon::ThemeIcon::ProcessStop);
|
|
|
|
|
} else {
|
|
|
|
|
startText = tr("Connect");
|
|
|
|
|
stopText = tr("Disconnect");
|
2025-08-22 02:19:05 +00:00
|
|
|
startIcon = QIcon::fromTheme(QStringLiteral("network-connect"));
|
|
|
|
|
stopIcon = QIcon::fromTheme(QStringLiteral("network-disconnect"));
|
2025-08-19 23:53:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_actionStartCore->setText(startText);
|
|
|
|
|
m_actionStartCore->setIcon(startIcon);
|
|
|
|
|
m_actionStopCore->setText(stopText);
|
|
|
|
|
m_actionStopCore->setIcon(stopIcon);
|
|
|
|
|
|
|
|
|
|
if (isStarted) {
|
|
|
|
|
ui->btnToggleCore->setText(stopText);
|
|
|
|
|
ui->btnToggleCore->setIcon(stopIcon);
|
|
|
|
|
} else {
|
|
|
|
|
ui->btnToggleCore->setText(startText);
|
|
|
|
|
ui->btnToggleCore->setIcon(startIcon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 11:40:00 +00:00
|
|
|
void MainWindow::updateSecurityIcon(bool visible)
|
|
|
|
|
{
|
2026-02-22 04:09:19 +00:00
|
|
|
m_statusBar->setSecurityIconVisible(visible);
|
2025-02-14 11:40:00 +00:00
|
|
|
if (!visible)
|
|
|
|
|
return;
|
2026-02-22 04:09:19 +00:00
|
|
|
m_statusBar->setSecurityIcon(TlsUtility::isEnabled());
|
2025-02-14 11:40:00 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-07 16:17:19 +00:00
|
|
|
void MainWindow::updateNetworkInfo()
|
|
|
|
|
{
|
2026-04-20 14:52:14 +00:00
|
|
|
const auto mode = m_coreProcess.mode();
|
|
|
|
|
if (mode == CoreMode::None) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mode == CoreMode::Server)
|
|
|
|
|
updateIpLabel(NetworkMonitor::validAddresses());
|
|
|
|
|
else
|
|
|
|
|
updateIpLabel({Settings::value(Settings::Core::Interface).toString()});
|
2025-08-07 16:17:19 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-04 01:22:17 +00:00
|
|
|
void MainWindow::serverConnectionConfigureClient(const QString &clientName)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-03-26 14:17:56 +00:00
|
|
|
m_serverConfigDialogVisible = true;
|
2025-03-10 03:15:32 +00:00
|
|
|
ServerConfigDialog dialog(this, m_serverConfig);
|
2024-08-07 14:05:18 +00:00
|
|
|
if (dialog.addClient(clientName) && dialog.exec() == QDialog::Accepted) {
|
2025-02-04 00:30:00 +00:00
|
|
|
m_coreProcess.restart();
|
2024-08-07 14:05:18 +00:00
|
|
|
}
|
2026-03-26 14:17:56 +00:00
|
|
|
m_serverConfigDialogVisible = false;
|
2024-08-07 14:05:18 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-26 22:53:52 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// End slots
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::open()
|
|
|
|
|
{
|
2026-02-27 03:41:58 +00:00
|
|
|
if (!Settings::value(Settings::Gui::Autohide).toBool())
|
|
|
|
|
showAndActivate();
|
|
|
|
|
else if (deskflow::platform::isMac())
|
|
|
|
|
// macOS to call hide after this function ends
|
|
|
|
|
QTimer::singleShot(1, this, &MainWindow::hide);
|
|
|
|
|
else
|
|
|
|
|
hide();
|
2025-06-01 12:56:09 +00:00
|
|
|
|
|
|
|
|
// if a critical error was shown just before the main window (i.e. on app
|
|
|
|
|
// load), it will be hidden behind the main window. therefore we need to raise
|
|
|
|
|
// it up in front of the main window.
|
|
|
|
|
// HACK: because the `onShown` event happens just as the window is shown, the
|
|
|
|
|
// message box has a chance of being raised under the main window. to solve
|
|
|
|
|
// this we delay the error dialog raise by a split second. this seems a bit
|
|
|
|
|
// hacky and fragile, so maybe there's a better approach.
|
|
|
|
|
const auto kCriticalDialogDelay = 100;
|
|
|
|
|
QTimer::singleShot(kCriticalDialogDelay, this, &messages::raiseCriticalDialog);
|
|
|
|
|
|
|
|
|
|
if (!Settings::value(Settings::Gui::AutoUpdateCheck).isValid()) {
|
|
|
|
|
Settings::setValue(Settings::Gui::AutoUpdateCheck, messages::showUpdateCheckOption(this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Settings::value(Settings::Gui::AutoUpdateCheck).toBool()) {
|
|
|
|
|
m_versionChecker.checkLatest();
|
|
|
|
|
} else {
|
2025-11-21 09:49:30 +00:00
|
|
|
qDebug() << "skipping check for new version, disabled";
|
2025-06-01 12:56:09 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-30 19:51:14 +00:00
|
|
|
if (Settings::value(Settings::Gui::AutoStartCore).toBool()) {
|
2025-06-01 12:56:09 +00:00
|
|
|
if (ui->rbModeClient->isChecked() && ui->lineHostname->text().isEmpty())
|
|
|
|
|
return;
|
2025-06-04 02:48:03 +00:00
|
|
|
startCore();
|
2025-06-01 12:56:09 +00:00
|
|
|
}
|
2012-07-13 14:38:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::createMenuBar()
|
|
|
|
|
{
|
2025-10-28 00:33:26 +00:00
|
|
|
m_menuFile->addAction(m_actionStartCore);
|
|
|
|
|
m_menuFile->addAction(m_actionRestartCore);
|
|
|
|
|
m_menuFile->addAction(m_actionStopCore);
|
|
|
|
|
m_menuFile->addSeparator();
|
|
|
|
|
m_menuFile->addAction(m_actionQuit);
|
2024-12-19 04:52:55 +00:00
|
|
|
|
2025-10-28 00:33:26 +00:00
|
|
|
m_menuEdit->addAction(m_actionSettings);
|
2024-12-19 04:52:55 +00:00
|
|
|
|
2025-10-28 00:33:26 +00:00
|
|
|
m_menuView->addAction(m_logDock->toggleViewAction());
|
2025-08-30 13:46:43 +00:00
|
|
|
|
2025-10-28 00:33:26 +00:00
|
|
|
m_menuHelp->addAction(m_actionAbout);
|
|
|
|
|
m_menuHelp->addAction(m_actionReportBug);
|
|
|
|
|
m_menuHelp->addSeparator();
|
|
|
|
|
m_menuHelp->addAction(m_actionClearSettings);
|
2024-12-19 04:52:55 +00:00
|
|
|
|
|
|
|
|
auto menuBar = new QMenuBar(this);
|
2025-10-28 00:33:26 +00:00
|
|
|
menuBar->addMenu(m_menuFile);
|
|
|
|
|
menuBar->addMenu(m_menuEdit);
|
|
|
|
|
menuBar->addMenu(m_menuView);
|
|
|
|
|
menuBar->addMenu(m_menuHelp);
|
2024-10-01 13:30:24 +00:00
|
|
|
|
2024-12-19 04:52:55 +00:00
|
|
|
setMenuBar(menuBar);
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-07 05:22:48 +00:00
|
|
|
void MainWindow::setupTrayIcon()
|
|
|
|
|
{
|
|
|
|
|
auto trayMenu = new QMenu(this);
|
2025-06-04 02:48:03 +00:00
|
|
|
trayMenu->addActions(
|
|
|
|
|
{m_actionStartCore, m_actionRestartCore, m_actionStopCore, m_actionMinimize, m_actionRestore, m_actionTrayQuit}
|
|
|
|
|
);
|
2025-01-09 14:47:04 +00:00
|
|
|
trayMenu->insertSeparator(m_actionMinimize);
|
|
|
|
|
trayMenu->insertSeparator(m_actionTrayQuit);
|
|
|
|
|
m_trayIcon->setContextMenu(trayMenu);
|
2025-01-07 05:22:48 +00:00
|
|
|
|
2025-10-19 13:20:26 +00:00
|
|
|
setTrayIcon();
|
2025-01-07 05:22:48 +00:00
|
|
|
m_trayIcon->show();
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::applyConfig()
|
|
|
|
|
{
|
2026-01-17 22:26:47 +00:00
|
|
|
if (Settings::value(Settings::Gui::ShowVersionInTitle).toBool()) {
|
|
|
|
|
setWindowTitle(QStringLiteral("%1 - %2").arg(kAppName, kDisplayVersion));
|
|
|
|
|
} else {
|
|
|
|
|
setWindowTitle(kAppName);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-18 14:23:50 +00:00
|
|
|
if (const auto host = Settings::value(Settings::Client::RemoteHost).toString(); !host.isEmpty())
|
|
|
|
|
ui->lineHostname->setText(host);
|
2026-01-17 22:26:47 +00:00
|
|
|
|
2026-07-10 13:37:28 +00:00
|
|
|
updateFingerprintButton();
|
2025-10-19 13:20:26 +00:00
|
|
|
setTrayIcon();
|
2025-02-23 21:28:53 +00:00
|
|
|
|
2026-01-03 00:17:56 +00:00
|
|
|
if (const auto ip = Settings::value(Settings::Core::Interface).toString(); !ip.isEmpty()) {
|
|
|
|
|
m_serverStartIPs = {ip};
|
|
|
|
|
m_serverStartSuggestedIP = ip;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 16:50:01 +00:00
|
|
|
coreModeToggled(true);
|
2024-08-03 00:17:29 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-20 02:19:19 +00:00
|
|
|
void MainWindow::saveSettings() const
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-03-10 02:50:44 +00:00
|
|
|
if (ui->rbModeClient->isChecked()) {
|
|
|
|
|
Settings::setValue(Settings::Core::CoreMode, Settings::CoreMode::Client);
|
|
|
|
|
} else if (ui->rbModeServer->isChecked()) {
|
|
|
|
|
Settings::setValue(Settings::Core::CoreMode, Settings::CoreMode::Server);
|
|
|
|
|
}
|
2025-04-21 21:56:47 +00:00
|
|
|
if (!ui->lineHostname->text().isEmpty())
|
2025-04-16 15:55:01 +00:00
|
|
|
Settings::setValue(Settings::Client::RemoteHost, ui->lineHostname->text());
|
2025-03-15 02:17:08 +00:00
|
|
|
Settings::save();
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2025-10-19 13:20:26 +00:00
|
|
|
void MainWindow::setTrayIcon()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-10-29 16:01:04 +00:00
|
|
|
static const auto fallbackPath = QStringLiteral(":/icons/%1-%2/apps/64/%3");
|
2025-10-29 18:31:18 +00:00
|
|
|
|
|
|
|
|
QString themeIcon = kRevFqdnName;
|
|
|
|
|
if (!Settings::value(Settings::Gui::SymbolicTrayIcon).toBool()) {
|
2025-12-03 17:05:41 +00:00
|
|
|
if (deskflow::platform::isMac())
|
|
|
|
|
m_trayIcon->setIcon(QIcon::fromTheme(themeIcon));
|
|
|
|
|
else
|
|
|
|
|
m_trayIcon->setIcon(QIcon(fallbackPath.arg(kAppId, QStringLiteral("dark"), themeIcon)));
|
2025-10-29 18:31:18 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
themeIcon.append(QStringLiteral("-symbolic"));
|
|
|
|
|
|
2025-11-05 20:55:51 +00:00
|
|
|
if (deskflow::platform::isWindows()) {
|
|
|
|
|
QSettings settings(
|
|
|
|
|
QStringLiteral("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"),
|
|
|
|
|
QSettings::NativeFormat
|
|
|
|
|
);
|
|
|
|
|
const QString theme = settings.value(QStringLiteral("SystemUsesLightTheme"), 1).toBool() ? QStringLiteral("light")
|
|
|
|
|
: QStringLiteral("dark");
|
|
|
|
|
m_trayIcon->setIcon(QIcon(fallbackPath.arg(kAppId, theme, themeIcon)));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-29 16:01:04 +00:00
|
|
|
auto icon = QIcon::fromTheme(themeIcon, QIcon(fallbackPath.arg(kAppId, iconMode(), themeIcon)));
|
2025-10-25 14:48:01 +00:00
|
|
|
icon.setIsMask(true);
|
|
|
|
|
m_trayIcon->setIcon(icon);
|
2012-07-04 23:27:03 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::handleLogLine(const QString &line)
|
|
|
|
|
{
|
2025-09-04 03:22:58 +00:00
|
|
|
m_logDock->appendLine(line);
|
2021-05-27 08:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 14:17:56 +00:00
|
|
|
void MainWindow::handleUnrecognisedClient(const QString &clientName)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-03-26 14:17:56 +00:00
|
|
|
if (m_ignoredClients.contains(clientName)) {
|
|
|
|
|
qDebug("ignoring %s:", qPrintable(clientName));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-06-01 18:57:43 +00:00
|
|
|
|
2026-03-26 14:17:56 +00:00
|
|
|
if (m_newClientPromptShowing || m_serverConfigDialogVisible)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (Settings::value(Settings::Server::ExternalConfig).toBool())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (m_serverConfig.isFull() || m_serverConfig.screenExists(clientName))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_newClientPromptShowing = true;
|
|
|
|
|
|
|
|
|
|
showAndActivate();
|
|
|
|
|
|
|
|
|
|
if (deskflow::gui::messages::showNewClientPrompt(this, clientName)) {
|
|
|
|
|
serverConnectionConfigureClient(clientName);
|
2024-07-02 19:07:06 +00:00
|
|
|
} else {
|
2026-03-26 14:17:56 +00:00
|
|
|
m_ignoredClients.insert(clientName);
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2026-03-26 14:17:56 +00:00
|
|
|
|
|
|
|
|
m_newClientPromptShowing = false;
|
2015-04-15 12:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 14:17:56 +00:00
|
|
|
void MainWindow::handleConnectionRefused(deskflow::core::ConnectionRefusal reason)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-03-26 14:17:56 +00:00
|
|
|
if (reason != deskflow::core::ConnectionRefusal::AlreadyConnected)
|
|
|
|
|
return;
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2026-03-26 14:17:56 +00:00
|
|
|
if (!isVisible() || m_clientErrorVisible)
|
2025-05-13 00:23:00 +00:00
|
|
|
return;
|
2025-02-08 19:10:39 +00:00
|
|
|
|
2026-03-26 14:17:56 +00:00
|
|
|
m_clientErrorVisible = true;
|
|
|
|
|
showAndActivate();
|
|
|
|
|
|
|
|
|
|
const auto address = Settings::value(Settings::Client::RemoteHost).toString();
|
|
|
|
|
QMessageBox::warning(
|
|
|
|
|
this, tr("%1 Connection Error").arg(kAppName),
|
|
|
|
|
tr("<p>Failed to connect to the server '%1'.</p>"
|
|
|
|
|
"<p>A Client with your name is already connected to the server.</p>"
|
|
|
|
|
"Please ensure that you're using a unique name and that only a "
|
|
|
|
|
"single instance of the client process is running.</p>")
|
|
|
|
|
.arg(address)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
m_clientErrorVisible = false;
|
|
|
|
|
}
|
2025-02-26 17:06:22 +00:00
|
|
|
|
2026-03-30 18:38:03 +00:00
|
|
|
void MainWindow::handleMissingKeyboardLayouts(const QString &layouts)
|
|
|
|
|
{
|
|
|
|
|
if (Settings::value(Settings::Gui::IgnoreMissingKeyboardLayouts).toBool())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QMessageBox msgBox(this);
|
|
|
|
|
msgBox.setIcon(QMessageBox::Warning);
|
|
|
|
|
msgBox.setWindowTitle(tr("Missing Keyboard Layouts"));
|
|
|
|
|
msgBox.setText(tr("<p>Keyboard layout support requires matching layouts on all computers. "
|
|
|
|
|
"The following layouts from the other computer are not installed on this computer:</p>"
|
|
|
|
|
"<p><b>%1</b></p>"
|
|
|
|
|
"<p>Please install them to enable support for these layouts.</p>")
|
|
|
|
|
.arg(layouts));
|
|
|
|
|
|
|
|
|
|
auto *checkBox = new QCheckBox(tr("Don't show this again"), &msgBox);
|
|
|
|
|
msgBox.setCheckBox(checkBox);
|
|
|
|
|
msgBox.exec();
|
|
|
|
|
|
|
|
|
|
if (checkBox->isChecked()) {
|
|
|
|
|
Settings::setValue(Settings::Gui::IgnoreMissingKeyboardLayouts, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 14:17:56 +00:00
|
|
|
void MainWindow::handlePeerFingerprint(const QString &fingerprint)
|
|
|
|
|
{
|
|
|
|
|
const auto sha256Text = QString(fingerprint).remove(':');
|
2025-11-25 02:01:03 +00:00
|
|
|
const Fingerprint sha256 = {QCryptographicHash::Sha256, QByteArray::fromHex(sha256Text.toLatin1())};
|
2025-02-09 02:42:19 +00:00
|
|
|
|
2025-02-27 17:11:54 +00:00
|
|
|
const bool isClient = m_coreProcess.mode() == CoreMode::Client;
|
|
|
|
|
if ((isClient && m_checkedServers.contains(sha256Text)) || (!isClient && m_checkedClients.contains(sha256Text))) {
|
2025-02-26 17:06:22 +00:00
|
|
|
qDebug("ignoring fingerprint, already handled");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-02-27 17:11:54 +00:00
|
|
|
|
2025-03-28 03:43:04 +00:00
|
|
|
FingerprintDatabase db;
|
|
|
|
|
db.read(trustedFingerprintDatabase());
|
2025-02-26 17:06:22 +00:00
|
|
|
|
2025-02-09 02:42:19 +00:00
|
|
|
if (db.isTrusted(sha256)) {
|
2025-02-26 17:06:22 +00:00
|
|
|
qDebug("fingerprint is trusted");
|
2024-07-02 19:07:06 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2025-03-01 13:51:31 +00:00
|
|
|
if (isClient) {
|
|
|
|
|
m_checkedServers.append(sha256Text);
|
|
|
|
|
m_coreProcess.stop();
|
|
|
|
|
} else {
|
|
|
|
|
m_checkedClients.append(sha256Text);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 04:33:06 +00:00
|
|
|
auto mode = isClient ? FingerprintDialogMode::Client : FingerprintDialogMode::Server;
|
2025-11-22 17:15:23 +00:00
|
|
|
FingerprintDialog fingerprintDialog(this, m_fingerprint, mode, sha256);
|
2025-02-17 19:48:56 +00:00
|
|
|
|
2025-02-09 16:16:15 +00:00
|
|
|
if (fingerprintDialog.exec() == QDialog::Accepted) {
|
|
|
|
|
db.addTrusted(sha256);
|
2025-05-22 13:41:00 +00:00
|
|
|
if (!db.write(trustedFingerprintDatabase())) {
|
|
|
|
|
qCritical().noquote() << "unable to write fingerprint to db:" << trustedFingerprintDatabase();
|
|
|
|
|
m_coreProcess.stop();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-02-27 17:11:54 +00:00
|
|
|
if (isClient) {
|
|
|
|
|
m_checkedServers.removeAll(sha256Text);
|
2025-03-01 13:51:31 +00:00
|
|
|
m_coreProcess.start();
|
2025-02-27 17:11:54 +00:00
|
|
|
} else {
|
|
|
|
|
m_checkedClients.removeAll(sha256Text);
|
|
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
|
|
|
{
|
2025-03-05 04:45:14 +00:00
|
|
|
if (Settings::value(Settings::Gui::CloseToTray).toBool() && event->spontaneous()) {
|
2025-03-05 05:11:41 +00:00
|
|
|
if (Settings::value(Settings::Gui::CloseReminder).toBool()) {
|
2025-01-02 19:04:49 +00:00
|
|
|
messages::showCloseReminder(this);
|
2025-03-05 05:11:41 +00:00
|
|
|
Settings::setValue(Settings::Gui::CloseReminder, false);
|
2025-01-02 19:04:49 +00:00
|
|
|
}
|
2025-11-11 20:10:51 +00:00
|
|
|
Settings::setValue(Settings::Gui::WindowGeometry, geometry());
|
2025-01-02 19:04:49 +00:00
|
|
|
qDebug() << "hiding to tray";
|
|
|
|
|
hide();
|
|
|
|
|
event->ignore();
|
2024-08-03 00:17:29 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-04 00:30:00 +00:00
|
|
|
if (m_saveOnExit) {
|
2025-07-07 20:39:40 +00:00
|
|
|
Settings::setValue(Settings::Gui::WindowGeometry, geometry());
|
2025-11-30 19:51:14 +00:00
|
|
|
Settings::setValue(Settings::Gui::AutoStartCore, m_coreProcess.isStarted());
|
2025-01-08 00:23:16 +00:00
|
|
|
}
|
2025-01-02 19:04:49 +00:00
|
|
|
qDebug() << "quitting application";
|
2025-08-30 13:46:43 +00:00
|
|
|
|
|
|
|
|
// any connected dock view acitons will be triggered
|
|
|
|
|
// disconnect them before accepting the event
|
2025-09-04 03:22:58 +00:00
|
|
|
disconnect(m_logDock->toggleViewAction(), &QAction::toggled, nullptr, nullptr);
|
2025-08-30 13:46:43 +00:00
|
|
|
|
2025-01-02 19:04:49 +00:00
|
|
|
event->accept();
|
|
|
|
|
QApplication::quit();
|
2024-08-03 00:17:29 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::showFirstConnectedMessage()
|
|
|
|
|
{
|
2025-11-30 19:06:46 +00:00
|
|
|
if (Settings::value(Settings::Gui::ShownFirstConnectedMessage).toBool())
|
2024-08-03 00:17:29 +00:00
|
|
|
return;
|
2025-11-30 19:06:46 +00:00
|
|
|
Settings::setValue(Settings::Gui::ShownFirstConnectedMessage, true);
|
2026-04-04 17:12:21 +00:00
|
|
|
messages::showFirstConnectedMessage(this);
|
2024-08-03 00:17:29 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::updateStatus()
|
|
|
|
|
{
|
2026-02-22 04:09:19 +00:00
|
|
|
using enum ProcessState;
|
2025-02-04 00:30:00 +00:00
|
|
|
const auto connection = m_coreProcess.connectionState();
|
|
|
|
|
const auto process = m_coreProcess.processState();
|
2025-06-15 11:52:41 +00:00
|
|
|
const bool isServer = (m_coreProcess.mode() == CoreMode::Server);
|
2026-02-24 02:18:38 +00:00
|
|
|
if (process == Stopped || process == Started) {
|
2025-12-11 14:07:26 +00:00
|
|
|
updateNetworkInfo();
|
2026-02-24 02:18:38 +00:00
|
|
|
ui->btnEditName->setVisible(process == Stopped);
|
|
|
|
|
}
|
2026-02-22 04:09:19 +00:00
|
|
|
m_statusBar->setStatus(connection, process, isServer);
|
2012-07-28 22:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-22 04:34:23 +00:00
|
|
|
void MainWindow::coreProcessStateChanged(ProcessState state)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-02-22 04:34:23 +00:00
|
|
|
using enum ProcessState;
|
2024-08-07 14:05:18 +00:00
|
|
|
updateStatus();
|
2026-02-22 04:34:23 +00:00
|
|
|
if (state == Started) {
|
2024-12-19 04:19:28 +00:00
|
|
|
qDebug() << "recording that core has started";
|
2025-11-30 19:51:14 +00:00
|
|
|
Settings::setValue(Settings::Gui::AutoStartCore, true);
|
2025-11-30 19:20:32 +00:00
|
|
|
if (m_coreProcess.mode() == CoreMode::Server &&
|
|
|
|
|
!Settings::value(Settings::Gui::ShownServerFirstStartMessage).toBool()) {
|
|
|
|
|
qDebug() << "starting core server for first time";
|
2025-05-15 16:25:58 +00:00
|
|
|
messages::showFirstServerStartMessage(this);
|
2025-11-30 19:20:32 +00:00
|
|
|
Settings::setValue(Settings::Gui::ShownServerFirstStartMessage, true);
|
2025-05-15 16:25:58 +00:00
|
|
|
}
|
2024-08-12 15:39:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-22 04:34:23 +00:00
|
|
|
if (state == Started || state == Starting || state == RetryPending) {
|
2024-12-18 23:10:22 +00:00
|
|
|
disconnect(ui->btnToggleCore, &QPushButton::clicked, m_actionStartCore, &QAction::trigger);
|
|
|
|
|
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStopCore, &QAction::trigger, Qt::UniqueConnection);
|
2024-07-22 16:48:02 +00:00
|
|
|
|
2025-06-04 02:53:03 +00:00
|
|
|
ui->btnRestartCore->setEnabled(true);
|
2025-06-04 02:48:03 +00:00
|
|
|
m_actionStartCore->setVisible(false);
|
|
|
|
|
m_actionRestartCore->setVisible(true);
|
2024-12-18 22:51:03 +00:00
|
|
|
m_actionStopCore->setEnabled(true);
|
2024-07-22 16:48:02 +00:00
|
|
|
|
2026-02-22 04:34:23 +00:00
|
|
|
if (state == Starting) {
|
2025-10-10 23:03:32 +00:00
|
|
|
saveSettings();
|
2025-10-10 22:54:57 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-07 14:05:18 +00:00
|
|
|
} else {
|
2024-12-18 23:10:22 +00:00
|
|
|
disconnect(ui->btnToggleCore, &QPushButton::clicked, m_actionStopCore, &QAction::trigger);
|
|
|
|
|
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStartCore, &QAction::trigger, Qt::UniqueConnection);
|
2024-07-22 16:48:02 +00:00
|
|
|
|
2025-06-04 02:53:03 +00:00
|
|
|
ui->btnRestartCore->setEnabled(false);
|
2025-06-04 02:48:03 +00:00
|
|
|
m_actionStartCore->setVisible(true);
|
|
|
|
|
m_actionRestartCore->setVisible(false);
|
2024-12-18 22:51:03 +00:00
|
|
|
m_actionStopCore->setEnabled(false);
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2025-08-19 23:53:39 +00:00
|
|
|
updateModeControlLabels();
|
2024-08-07 14:05:18 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
|
2026-02-22 04:23:21 +00:00
|
|
|
void MainWindow::coreConnectionStateChanged(ConnectionState state)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2025-12-05 16:31:30 +00:00
|
|
|
qDebug() << "core connection state changed:" << static_cast<int>(state);
|
2024-07-26 22:53:52 +00:00
|
|
|
|
2024-08-07 14:05:18 +00:00
|
|
|
updateStatus();
|
2024-07-02 19:07:06 +00:00
|
|
|
|
2024-08-07 14:05:18 +00:00
|
|
|
// always assume connection is not secure when connection changes
|
|
|
|
|
// to anything except connected. the only way the padlock shows is
|
|
|
|
|
// when the correct TLS version string is detected.
|
2026-02-22 04:23:21 +00:00
|
|
|
if (state != ConnectionState::Connected) {
|
2024-08-07 14:05:18 +00:00
|
|
|
secureSocket(false);
|
|
|
|
|
} else if (isVisible()) {
|
2024-08-12 15:39:18 +00:00
|
|
|
showFirstConnectedMessage();
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-10 13:37:28 +00:00
|
|
|
void MainWindow::updateFingerprintButton()
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2026-02-22 04:09:19 +00:00
|
|
|
m_statusBar->setBtnFingerprintVisible(TlsUtility::isEnabled() && !m_fingerprint.data.isEmpty());
|
2015-04-21 16:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-09 14:47:04 +00:00
|
|
|
void MainWindow::hide()
|
|
|
|
|
{
|
2025-11-20 02:07:38 +00:00
|
|
|
#ifdef Q_OS_MACOS
|
2025-01-09 14:47:04 +00:00
|
|
|
macOSNativeHide();
|
|
|
|
|
#else
|
|
|
|
|
QMainWindow::hide();
|
|
|
|
|
#endif
|
|
|
|
|
m_actionRestore->setVisible(true);
|
|
|
|
|
m_actionMinimize->setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-19 12:46:00 +00:00
|
|
|
void MainWindow::changeEvent(QEvent *e)
|
|
|
|
|
{
|
|
|
|
|
QMainWindow::changeEvent(e);
|
|
|
|
|
if (e->type() == QEvent::PaletteChange) {
|
|
|
|
|
updateIconTheme();
|
2025-10-28 02:18:00 +00:00
|
|
|
setWindowIcon(QIcon::fromTheme(kRevFqdnName));
|
2025-10-19 12:46:00 +00:00
|
|
|
setTrayIcon();
|
2025-10-28 00:20:52 +00:00
|
|
|
} else if (e->type() == QEvent::LanguageChange) {
|
|
|
|
|
ui->retranslateUi(this);
|
|
|
|
|
updateModeControlLabels();
|
|
|
|
|
updateNetworkInfo();
|
|
|
|
|
updateStatus();
|
2026-03-26 14:17:56 +00:00
|
|
|
serverClientsChanged({});
|
2025-10-28 00:20:52 +00:00
|
|
|
updateText();
|
2025-10-19 12:46:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 01:35:40 +00:00
|
|
|
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
|
|
|
|
|
{
|
|
|
|
|
if (obj != ui->lineEditName || event->type() != QEvent::KeyPress)
|
|
|
|
|
return false;
|
2026-02-27 03:35:19 +00:00
|
|
|
if (const auto keyEvent = static_cast<QKeyEvent *>(event); keyEvent->key() != Qt::Key_Escape)
|
2026-02-24 01:35:40 +00:00
|
|
|
return false;
|
|
|
|
|
ui->lineEditName->hide();
|
|
|
|
|
ui->lblComputerName->show();
|
|
|
|
|
ui->btnEditName->show();
|
|
|
|
|
ui->lineEditName->setText(Settings::value(Settings::Core::ComputerName).toString());
|
|
|
|
|
toggleCanRunCore(canRunCore());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-28 00:20:52 +00:00
|
|
|
void MainWindow::updateText()
|
|
|
|
|
{
|
|
|
|
|
m_menuFile->setTitle(tr("&File"));
|
|
|
|
|
m_menuEdit->setTitle(tr("&Edit"));
|
|
|
|
|
m_menuView->setTitle(tr("&View"));
|
|
|
|
|
m_menuHelp->setTitle(tr("&Help"));
|
|
|
|
|
|
|
|
|
|
m_actionClearSettings->setText(tr("Clear settings"));
|
|
|
|
|
m_actionReportBug->setText(tr("Report a Bug"));
|
|
|
|
|
m_actionMinimize->setText(tr("&Minimize to tray"));
|
|
|
|
|
m_actionQuit->setText(tr("&Quit"));
|
|
|
|
|
m_actionTrayQuit->setText(tr("&Quit"));
|
|
|
|
|
//: %1 will be the replaced with the appname
|
|
|
|
|
m_actionRestore->setText(tr("&Open %1").arg(kAppName));
|
|
|
|
|
m_actionSettings->setText(tr("&Preferences"));
|
|
|
|
|
m_actionStartCore->setText(tr("&Start"));
|
|
|
|
|
m_actionRestartCore->setText(tr("Rest&art"));
|
|
|
|
|
m_actionStopCore->setText(tr("S&top"));
|
|
|
|
|
//: %1 will be the replaced with the appname
|
|
|
|
|
m_actionAbout->setText(tr("About %1...").arg(kAppName));
|
|
|
|
|
|
|
|
|
|
//: start / restart core shortcut
|
|
|
|
|
m_actionStartCore->setShortcut(QKeySequence(tr("Ctrl+S")));
|
|
|
|
|
m_actionRestartCore->setShortcut(QKeySequence(tr("Ctrl+S")));
|
|
|
|
|
|
|
|
|
|
//: stop core shortcut
|
|
|
|
|
m_actionStopCore->setShortcut(QKeySequence(tr("Ctrl+T")));
|
|
|
|
|
|
2025-11-05 20:55:51 +00:00
|
|
|
if (deskflow::platform::isWindows()) {
|
|
|
|
|
//: Quit shortcut
|
|
|
|
|
m_actionQuit->setShortcut(QKeySequence(tr("Ctrl+Q")));
|
|
|
|
|
m_actionTrayQuit->setShortcut(QKeySequence(tr("Ctrl+Q")));
|
|
|
|
|
}
|
2025-10-28 00:20:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::showConfigureServer(const QString &message)
|
|
|
|
|
{
|
2025-03-10 03:15:32 +00:00
|
|
|
ServerConfigDialog dialog(this, serverConfig());
|
2024-08-03 00:17:29 +00:00
|
|
|
dialog.message(message);
|
2025-02-04 00:30:00 +00:00
|
|
|
if ((dialog.exec() == QDialog::Accepted) && m_coreProcess.isStarted()) {
|
|
|
|
|
m_coreProcess.restart();
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-13 16:30:34 +00:00
|
|
|
void MainWindow::showConfigureClient()
|
|
|
|
|
{
|
|
|
|
|
ClientConfigDialog dialog(this);
|
|
|
|
|
if ((dialog.exec() == QDialog::Accepted) && m_coreProcess.isStarted()) {
|
|
|
|
|
m_coreProcess.restart();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::secureSocket(bool secureSocket)
|
|
|
|
|
{
|
2025-02-04 00:30:00 +00:00
|
|
|
m_secureSocket = secureSocket;
|
2026-02-22 04:09:19 +00:00
|
|
|
updateSecurityIcon(m_statusBar->securityIconVisible());
|
2018-07-28 00:52:56 +00:00
|
|
|
}
|
2018-08-08 15:47:45 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::updateScreenName()
|
|
|
|
|
{
|
2026-02-01 15:44:38 +00:00
|
|
|
const auto screenName = Settings::value(Settings::Core::ComputerName).toString();
|
2025-03-09 03:09:38 +00:00
|
|
|
ui->lblComputerName->setText(screenName);
|
|
|
|
|
ui->lineEditName->setText(screenName);
|
2025-02-04 00:30:00 +00:00
|
|
|
m_serverConfig.updateServerName();
|
2021-02-04 17:10:27 +00:00
|
|
|
}
|
2021-04-12 09:03:37 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void MainWindow::showAndActivate()
|
|
|
|
|
{
|
2025-11-30 16:42:08 +00:00
|
|
|
const auto wasVisible = isVisible();
|
2025-11-20 02:07:38 +00:00
|
|
|
#ifdef Q_OS_MACOS
|
2024-12-18 01:45:22 +00:00
|
|
|
forceAppActive();
|
|
|
|
|
#endif
|
2024-12-22 21:30:52 +00:00
|
|
|
showNormal();
|
2024-08-09 18:20:10 +00:00
|
|
|
raise();
|
2024-08-08 17:41:59 +00:00
|
|
|
activateWindow();
|
2025-01-09 14:47:04 +00:00
|
|
|
m_actionRestore->setVisible(false);
|
|
|
|
|
m_actionMinimize->setVisible(true);
|
2025-11-30 16:42:08 +00:00
|
|
|
if (!wasVisible)
|
|
|
|
|
restoreWindow();
|
2024-08-08 17:41:59 +00:00
|
|
|
}
|
2025-02-08 19:10:39 +00:00
|
|
|
|
2025-01-12 06:48:23 +00:00
|
|
|
void MainWindow::showHostNameEditor()
|
|
|
|
|
{
|
|
|
|
|
ui->lineEditName->show();
|
|
|
|
|
ui->lblComputerName->hide();
|
|
|
|
|
ui->btnEditName->hide();
|
2026-02-24 01:35:40 +00:00
|
|
|
toggleCanRunCore(false);
|
2025-01-12 06:48:23 +00:00
|
|
|
ui->lineEditName->setFocus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::setHostName()
|
|
|
|
|
{
|
|
|
|
|
ui->lineEditName->hide();
|
|
|
|
|
ui->lblComputerName->show();
|
|
|
|
|
ui->btnEditName->show();
|
2026-02-24 01:35:40 +00:00
|
|
|
toggleCanRunCore(canRunCore());
|
2025-01-12 06:48:23 +00:00
|
|
|
|
|
|
|
|
QString text = ui->lineEditName->text();
|
2026-02-01 15:44:38 +00:00
|
|
|
const auto screenName = Settings::value(Settings::Core::ComputerName).toString();
|
2025-08-07 23:25:41 +00:00
|
|
|
|
|
|
|
|
if (text == screenName)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const bool isServer = ui->rbModeServer->isChecked();
|
|
|
|
|
bool existingScreen = false;
|
|
|
|
|
if (isServer)
|
|
|
|
|
existingScreen = serverConfig().screenExists(text);
|
2025-01-12 06:48:23 +00:00
|
|
|
|
|
|
|
|
if (!ui->lineEditName->hasAcceptableInput() || text.isEmpty() || existingScreen) {
|
|
|
|
|
blockSignals(true);
|
2025-03-09 03:09:38 +00:00
|
|
|
ui->lineEditName->setText(screenName);
|
2025-01-12 06:48:23 +00:00
|
|
|
blockSignals(false);
|
|
|
|
|
|
|
|
|
|
const auto title = tr("Invalid Screen Name");
|
|
|
|
|
QString body;
|
|
|
|
|
if (existingScreen) {
|
|
|
|
|
body = tr("Screen name already exists");
|
|
|
|
|
} else {
|
2025-03-11 00:21:57 +00:00
|
|
|
body =
|
|
|
|
|
tr("The name you have chosen is invalid.\n\n"
|
|
|
|
|
"Valid names:\n"
|
|
|
|
|
"• Use letters and numbers\n"
|
|
|
|
|
"• May also use _ or -\n"
|
|
|
|
|
"• Are between 1 and 255 characters");
|
2025-01-12 06:48:23 +00:00
|
|
|
}
|
|
|
|
|
QMessageBox::information(this, title, body);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ui->lblComputerName->setText(ui->lineEditName->text());
|
2026-02-01 15:44:38 +00:00
|
|
|
Settings::setValue(Settings::Core::ComputerName, ui->lineEditName->text());
|
2025-08-07 23:25:41 +00:00
|
|
|
if (isServer)
|
|
|
|
|
serverConfig().updateServerName();
|
2025-01-12 06:48:23 +00:00
|
|
|
applyConfig();
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-20 02:19:19 +00:00
|
|
|
QString MainWindow::trustedFingerprintDatabase() const
|
2025-02-17 19:11:49 +00:00
|
|
|
{
|
|
|
|
|
const bool isClient = m_coreProcess.mode() == CoreMode::Client;
|
2025-03-18 01:47:21 +00:00
|
|
|
return isClient ? Settings::tlsTrustedServersDb() : Settings::tlsTrustedClientsDb();
|
2025-02-17 19:11:49 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-22 16:38:07 +00:00
|
|
|
bool MainWindow::generateCertificate()
|
2025-02-09 02:42:19 +00:00
|
|
|
{
|
2025-03-07 00:04:55 +00:00
|
|
|
const auto certificate = Settings::value(Settings::Security::Certificate).toString();
|
2025-11-22 17:35:41 +00:00
|
|
|
if (!QFile::exists(certificate) && !TlsUtility::generateCertificate()) {
|
2025-02-17 16:40:11 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-25 02:01:03 +00:00
|
|
|
m_fingerprint = {QCryptographicHash::Sha256, TlsUtility::certFingerprint()};
|
2025-02-14 14:03:56 +00:00
|
|
|
|
2026-07-10 13:37:28 +00:00
|
|
|
updateFingerprintButton();
|
2025-02-09 02:42:19 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2025-04-15 20:52:36 +00:00
|
|
|
|
2025-06-15 11:52:41 +00:00
|
|
|
void MainWindow::serverClientsChanged(const QStringList &clients)
|
|
|
|
|
{
|
|
|
|
|
if (m_coreProcess.mode() != CoreMode::Server || !m_coreProcess.isStarted())
|
|
|
|
|
return;
|
2026-02-22 04:09:19 +00:00
|
|
|
m_statusBar->setServerClients(clients);
|
2025-06-15 11:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-18 12:56:37 +00:00
|
|
|
void MainWindow::daemonIpcClientConnectionFailed()
|
2025-04-15 20:52:36 +00:00
|
|
|
{
|
|
|
|
|
if (deskflow::gui::messages::showDaemonOffline(this)) {
|
|
|
|
|
m_coreProcess.retryDaemon();
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-19 17:26:41 +00:00
|
|
|
|
|
|
|
|
void MainWindow::toggleCanRunCore(bool enableButtons)
|
|
|
|
|
{
|
2026-02-14 17:01:37 +00:00
|
|
|
const bool isStarted = m_coreProcess.isStarted();
|
2025-04-19 17:26:41 +00:00
|
|
|
ui->btnToggleCore->setEnabled(enableButtons);
|
2026-02-14 17:01:37 +00:00
|
|
|
ui->btnRestartCore->setEnabled(enableButtons && isStarted);
|
2025-04-19 17:26:41 +00:00
|
|
|
m_actionStartCore->setEnabled(enableButtons);
|
2026-02-14 17:01:37 +00:00
|
|
|
m_actionStopCore->setEnabled(enableButtons && isStarted);
|
2025-04-19 17:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-08 10:38:55 +00:00
|
|
|
void MainWindow::remoteHostChanged(const QString &newRemoteHost)
|
2025-04-19 17:26:41 +00:00
|
|
|
{
|
|
|
|
|
m_coreProcess.setAddress(newRemoteHost);
|
|
|
|
|
toggleCanRunCore(!newRemoteHost.isEmpty() && ui->rbModeClient->isChecked());
|
|
|
|
|
if (newRemoteHost.isEmpty()) {
|
2026-01-18 14:32:19 +00:00
|
|
|
Settings::setValue(Settings::Client::RemoteHost);
|
2025-10-15 04:08:02 +00:00
|
|
|
} else {
|
|
|
|
|
Settings::setValue(Settings::Client::RemoteHost, newRemoteHost);
|
2025-04-19 17:26:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-11-28 18:37:01 +00:00
|
|
|
|
2026-01-02 18:06:33 +00:00
|
|
|
void MainWindow::updateIpLabel(const QStringList &addresses)
|
2025-12-11 14:07:26 +00:00
|
|
|
{
|
2026-04-20 14:52:14 +00:00
|
|
|
const auto mode = m_coreProcess.mode();
|
|
|
|
|
if (mode == CoreMode::None) {
|
2025-12-11 14:07:26 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const auto colorText = QStringLiteral(R"(<span style="color:%1;">%2</span>)");
|
2026-01-02 22:10:30 +00:00
|
|
|
const bool serverStarted = m_coreProcess.isStarted();
|
2026-01-18 14:23:50 +00:00
|
|
|
const bool fixedIP = !Settings::value(Settings::Core::Interface).toString().isEmpty();
|
2025-12-11 14:07:26 +00:00
|
|
|
|
2026-01-03 00:17:56 +00:00
|
|
|
if (!fixedIP && addresses.isEmpty() && !serverStarted || (serverStarted && m_serverStartSuggestedIP.isEmpty())) {
|
2025-12-11 14:07:26 +00:00
|
|
|
ui->lblIpAddresses->setText(colorText.arg(palette().linkVisited().color().name(), tr("No IP Detected")));
|
|
|
|
|
ui->lblIpAddresses->setToolTip(tr("Unable to detect an IP address. Check your network connection is active."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-03 00:17:56 +00:00
|
|
|
QString labelText = fixedIP ? tr("Using IP: ") : tr("Suggested IP: ");
|
|
|
|
|
QString toolTipText = tr("<p>If connecting via the hostname fails, try %1</p>");
|
2025-12-31 14:21:12 +00:00
|
|
|
|
2026-01-03 00:17:56 +00:00
|
|
|
const bool filterIpList = (serverStarted || fixedIP);
|
|
|
|
|
const QRegularExpression ipListFilter(filterIpList ? QStringLiteral("(%1)").arg(m_serverStartIPs.join("|")) : "");
|
|
|
|
|
const QStringList ipList = addresses.filter(ipListFilter);
|
2026-01-02 18:06:33 +00:00
|
|
|
|
2026-01-02 22:55:56 +00:00
|
|
|
bool IPValid = true;
|
2026-01-03 00:17:56 +00:00
|
|
|
if (filterIpList && (m_serverStartSuggestedIP != m_currentIpAddress) || !ipList.contains(m_serverStartSuggestedIP)) {
|
|
|
|
|
IPValid = !ipList.isEmpty();
|
2026-01-02 22:55:56 +00:00
|
|
|
}
|
2025-12-11 14:07:26 +00:00
|
|
|
|
2026-01-02 22:55:56 +00:00
|
|
|
if (IPValid) {
|
2026-01-02 21:12:53 +00:00
|
|
|
m_currentIpAddress = ipList.first();
|
|
|
|
|
labelText.append(m_currentIpAddress);
|
2026-01-02 22:55:56 +00:00
|
|
|
} else {
|
|
|
|
|
labelText.append(colorText.arg(palette().linkVisited().color().name(), m_serverStartSuggestedIP));
|
|
|
|
|
toolTipText.append(tr("\nA bound IP is now invalid, you may need to restart the server."));
|
2025-12-31 14:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-03 00:17:56 +00:00
|
|
|
if (ipList.count() < 2 || fixedIP) {
|
2025-12-31 15:10:48 +00:00
|
|
|
toolTipText = toolTipText.arg(tr("the suggested IP."));
|
2025-12-31 14:21:12 +00:00
|
|
|
} else {
|
2025-12-31 15:10:48 +00:00
|
|
|
toolTipText = toolTipText.arg(tr("one of the following IPs:<br/>%1").arg(ipList.join("<br/>")));
|
2025-12-11 14:07:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ui->lblIpAddresses->setText(labelText);
|
2026-04-20 14:52:14 +00:00
|
|
|
ui->lblIpAddresses->setToolTip(mode == CoreMode::Server ? toolTipText : QString());
|
2025-12-11 14:07:26 +00:00
|
|
|
}
|
2026-02-24 01:34:41 +00:00
|
|
|
|
2026-03-25 04:28:37 +00:00
|
|
|
void MainWindow::updateTimeoutDelay(int newDelay)
|
|
|
|
|
{
|
|
|
|
|
m_statusBar->setConnectionInterval(newDelay);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 01:34:41 +00:00
|
|
|
bool MainWindow::canRunCore() const
|
|
|
|
|
{
|
|
|
|
|
const auto mode = m_coreProcess.mode();
|
|
|
|
|
const bool isServer = mode == Settings::CoreMode::Server;
|
|
|
|
|
const bool isClient = mode == Settings::CoreMode::Client;
|
|
|
|
|
return ((isServer || isClient) && (isClient && !ui->lineHostname->text().isEmpty()) || isServer);
|
|
|
|
|
}
|