From 4243fde9874d81d53aebfee4d8911ae68639eb3e Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Wed, 12 Aug 2026 18:24:26 +0000 Subject: [PATCH 3/4] Qt4: convert new-style connect() calls to SIGNAL/SLOT macros Qt4's QObject::connect() only accepts the old string-based SIGNAL()/SLOT() form; it cannot bind a pointer-to-member-function or a functor/lambda slot (both Qt5+ additions). Converts every PMF-style connect()/disconnect() across mainwindow, logdialog, FileLogger and main.cpp to the old-style macros, which work unchanged under Qt5/6 too. Lambda slots are replaced with named slots on MainWindow, since Qt4 cannot connect a signal directly to a functor: - onActionQuitTriggered, onStateMachineStarted, onMinimizedWindowEntered/ Exited, onServerProfileTriggered, onSingleInstanceModeToggled, onLogDialogFinished, onSingleAppMessageReceived (the last also needed by main.cpp, which is outside the class and so cannot see a lambda's captures either way). - onStateMachineStarted uses a new m_profileName member instead of a lambda capture of the constructor's profileName argument. - onServerProfileTriggered identifies which per-profile QAction fired via sender() instead of a per-action lambda capture. - LogDialog gained a showAndActivate() slot combining show()/raise()/ activateWindow(), since activateWindow() is not itself a registered Qt slot and so can't be named in a SLOT() macro directly. Signal/slot signatures with a Qt type parameter (Logger::Message, QString) are spelled with the exact const-reference form used in their declarations, since the old-style macros match by literal normalized signature text. Part of Qt4 buildability work for the macOS PowerPC port. --- src/FileLogger.cpp | 3 +- src/dialog/logdialog.cpp | 19 ++- src/dialog/logdialog.h | 4 + src/dialog/mainwindow.cpp | 267 +++++++++++++++++++++----------------- src/dialog/mainwindow.h | 21 ++- src/main.cpp | 6 +- 6 files changed, 192 insertions(+), 128 deletions(-) diff --git a/src/FileLogger.cpp b/src/FileLogger.cpp index 8585454..c2063a1 100644 --- a/src/FileLogger.cpp +++ b/src/FileLogger.cpp @@ -35,7 +35,8 @@ FileLogger::FileLogger(QObject* parent, const QString& logPath, const size_t log throw; } - connect(&Logger::instance(), &Logger::newLogMessage, this, &FileLogger::addLogMessage); + connect(&Logger::instance(), SIGNAL(newLogMessage(const Logger::Message&)), + this, SLOT(addLogMessage(const Logger::Message&))); } FileLogger::~FileLogger() diff --git a/src/dialog/logdialog.cpp b/src/dialog/logdialog.cpp index b9406d1..759e294 100644 --- a/src/dialog/logdialog.cpp +++ b/src/dialog/logdialog.cpp @@ -44,23 +44,30 @@ LogDialog::LogDialog(QWidget* parent) ui->listWidget->scrollToBottom(); } - connect(&Logger::instance(), &Logger::newLogMessage, - this, &LogDialog::append, Qt::QueuedConnection); + connect(&Logger::instance(), SIGNAL(newLogMessage(const Logger::Message&)), + this, SLOT(append(const Logger::Message&)), Qt::QueuedConnection); m_timer->setSingleShot(true); m_timer->setInterval(100); - connect(m_timer.get(), &QTimer::timeout, - ui->listWidget, &QListWidget::scrollToBottom); + connect(m_timer.get(), SIGNAL(timeout()), + ui->listWidget, SLOT(scrollToBottom())); } LogDialog::~LogDialog() { - disconnect(&Logger::instance(), &Logger::newLogMessage, - this, &LogDialog::append); + disconnect(&Logger::instance(), SIGNAL(newLogMessage(const Logger::Message&)), + this, SLOT(append(const Logger::Message&))); delete ui; } +void LogDialog::showAndActivate() +{ + show(); + raise(); + activateWindow(); +} + void LogDialog::on_pushButtonSelectAll_clicked() { ui->listWidget->selectAll(); diff --git a/src/dialog/logdialog.h b/src/dialog/logdialog.h index 1024a5d..e7110e4 100644 --- a/src/dialog/logdialog.h +++ b/src/dialog/logdialog.h @@ -40,6 +40,10 @@ signals: public slots: void append(const Logger::Message& message); + /* combines show()/raise()/activateWindow() behind a single real Qt + * slot, since QWidget::activateWindow() is not itself a registered + * slot and so cannot be named in a SIGNAL/SLOT-macro connect() */ + void showAndActivate(); private slots: void on_pushButtonClear_clicked(); diff --git a/src/dialog/mainwindow.cpp b/src/dialog/mainwindow.cpp index 297a3bb..7c17e41 100644 --- a/src/dialog/mainwindow.cpp +++ b/src/dialog/mainwindow.cpp @@ -48,7 +48,9 @@ extern "C" { #include #include #include -#include +/* Qt4's QtConcurrent module does not provide the "QtConcurrent/QtConcurrentRun" + * submodule-prefixed header; use the flat form that works on every Qt version. */ +#include #include #include #include @@ -96,11 +98,12 @@ static int app_loglevel_rtab[] = { MainWindow::MainWindow(QWidget* parent, bool useTray, const QString profileName) : QMainWindow(parent) , ui(new Ui::MainWindow) + , m_profileName(profileName) { ui->setupUi(this); - connect(ui->viewLogButton, &QPushButton::clicked, - this, &MainWindow::createLogDialog); + connect(ui->viewLogButton, SIGNAL(clicked()), + this, SLOT(createLogDialog())); timer = new QTimer(this); blink_timer = new QTimer(this); @@ -109,34 +112,26 @@ MainWindow::MainWindow(QWidget* parent, bool useTray, const QString profileName) downloadProgress = nullptr; manager = new QNetworkAccessManager(); - connect(ui->actionQuit, &QAction::triggered, - [=]() { - if (m_trayIcon && m_disconnectAction->isEnabled()) { - connect(this, &MainWindow::readyToShutdown, - qApp, &QApplication::quit); - on_disconnectClicked(); - } else { - qApp->quit(); - } - }); + connect(ui->actionQuit, SIGNAL(triggered()), + this, SLOT(onActionQuitTriggered())); - connect(blink_timer, &QTimer::timeout, - this, &MainWindow::blink_ui, + connect(blink_timer, SIGNAL(timeout()), + this, SLOT(blink_ui()), Qt::QueuedConnection); - connect(timer, &QTimer::timeout, - this, &MainWindow::request_update_stats, + connect(timer, SIGNAL(timeout()), + this, SLOT(request_update_stats()), Qt::QueuedConnection); - connect(ui->serverList->lineEdit(), &QLineEdit::returnPressed, - this, &MainWindow::on_connectClicked, + connect(ui->serverList->lineEdit(), SIGNAL(returnPressed()), + this, SLOT(on_connectClicked()), Qt::QueuedConnection); - connect(this, &MainWindow::vpn_status_changed_sig, - this, &MainWindow::changeStatus, + connect(this, SIGNAL(vpn_status_changed_sig(int)), + this, SLOT(changeStatus(int)), Qt::QueuedConnection); - connect(ui->connectionButton, &QPushButton::clicked, - this, &MainWindow::on_connectClicked, + connect(ui->connectionButton, SIGNAL(clicked()), + this, SLOT(on_connectClicked()), Qt::QueuedConnection); - connect(this, &MainWindow::stats_changed_sig, - this, &MainWindow::statsChanged, + connect(this, SIGNAL(stats_changed_sig(QString, QString, QString)), + this, SLOT(statsChanged(QString, QString, QString)), Qt::QueuedConnection); ui->iconLabel->setPixmap(OFF_ICON); @@ -146,8 +141,8 @@ MainWindow::MainWindow(QWidget* parent, bool useTray, const QString profileName) if (useTray) { createTrayIcon(); - connect(m_trayIcon, &QSystemTrayIcon::activated, - this, &MainWindow::iconActivated); + connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); QFileSelector selector; QIcon icon(selector.select(QStringLiteral(":/images/network-disconnected.png"))); @@ -219,30 +214,8 @@ MainWindow::MainWindow(QWidget* parent, bool useTray, const QString profileName) machine->setInitialState(s1_noProfiles); machine->start(); - connect(machine, &QStateMachine::started, [=]() { - // LCA: find better way to load/fill combobox... - this->reload_settings(); - - if (!profileName.isEmpty()) { - // TODO: better place when refactor SM... - const int profileIndex = ui->serverList->findText(profileName); - if (profileIndex != -1) { - ui->serverList->setCurrentIndex(profileIndex); - emit on_connectClicked(); - return; - } else { - QMessageBox::warning(this, - tr("Connection failed"), - tr("Selected VPN profile '%1' does not exist.").arg(profileName)); - } - } - - OcSettings settings; - const int currentIndex = settings.value("Profiles/currentIndex", -1).toInt(); - if (currentIndex != -1 && currentIndex < ui->serverList->count()) { - ui->serverList->setCurrentIndex(currentIndex); - } - }); + connect(machine, SIGNAL(started()), + this, SLOT(onStateMachineStarted())); QMenu* serverProfilesMenu = new QMenu(this); serverProfilesMenu->addAction(ui->actionNewProfile); @@ -262,20 +235,10 @@ MainWindow::MainWindow(QWidget* parent, bool useTray, const QString profileName) QState* s112_minimizedWindow = new QState(); m_appWindowStateMachine->addState(s112_minimizedWindow); - connect(s112_minimizedWindow, &QState::entered, [=]() { - showMinimized(); - if (ui->actionMinimizeToTheNotificationArea->isChecked()) { - QTimer::singleShot(10, this, SLOT(hide())); - } - }); - connect(s112_minimizedWindow, &QState::exited, [=]() { - this->showNormal(); - if (ui->actionMinimizeToTheNotificationArea->isChecked()) { - show(); - raise(); - activateWindow(); - } - }); + connect(s112_minimizedWindow, SIGNAL(entered()), + this, SLOT(onMinimizedWindowEntered())); + connect(s112_minimizedWindow, SIGNAL(exited()), + this, SLOT(onMinimizedWindowExited())); s112_minimizedWindow->assignProperty(ui->actionRestore, "enabled", true); s112_minimizedWindow->assignProperty(ui->actionMinimize, "enabled", false); @@ -349,11 +312,97 @@ MainWindow::MainWindow(QWidget* parent, bool useTray, const QString profileName) s112_minimizedWindow->addTransition(restoreEvent); // start timer to check latest version - QTimer::singleShot(4000, this, &MainWindow::tryCheckLatestVersion); + QTimer::singleShot(4000, this, SLOT(tryCheckLatestVersion())); m_appWindowStateMachine->start(); } +void MainWindow::onActionQuitTriggered() +{ + if (m_trayIcon && m_disconnectAction->isEnabled()) { + connect(this, SIGNAL(readyToShutdown()), + qApp, SLOT(quit())); + on_disconnectClicked(); + } else { + qApp->quit(); + } +} + +void MainWindow::onStateMachineStarted() +{ + // LCA: find better way to load/fill combobox... + this->reload_settings(); + + if (!m_profileName.isEmpty()) { + // TODO: better place when refactor SM... + const int profileIndex = ui->serverList->findText(m_profileName); + if (profileIndex != -1) { + ui->serverList->setCurrentIndex(profileIndex); + emit on_connectClicked(); + return; + } else { + QMessageBox::warning(this, + tr("Connection failed"), + tr("Selected VPN profile '%1' does not exist.").arg(m_profileName)); + } + } + + OcSettings settings; + const int currentIndex = settings.value("Profiles/currentIndex", -1).toInt(); + if (currentIndex != -1 && currentIndex < ui->serverList->count()) { + ui->serverList->setCurrentIndex(currentIndex); + } +} + +void MainWindow::onMinimizedWindowEntered() +{ + showMinimized(); + if (ui->actionMinimizeToTheNotificationArea->isChecked()) { + QTimer::singleShot(10, this, SLOT(hide())); + } +} + +void MainWindow::onMinimizedWindowExited() +{ + this->showNormal(); + if (ui->actionMinimizeToTheNotificationArea->isChecked()) { + show(); + raise(); + activateWindow(); + } +} + +void MainWindow::onServerProfileTriggered() +{ + QAction* act = qobject_cast(sender()); + if (act == nullptr) { + return; + } + + int idx = ui->serverList->findText(act->text()); + if (idx != -1) { + ui->serverList->setCurrentIndex(idx); + on_connectClicked(); + } +} + +void MainWindow::onSingleInstanceModeToggled(bool checked) +{ + OcSettings settings; + settings.setValue("Settings/singleInstanceMode", checked); +} + +void MainWindow::onLogDialogFinished() +{ + connect(ui->viewLogButton, SIGNAL(clicked()), + this, SLOT(createLogDialog())); +} + +void MainWindow::onSingleAppMessageReceived(const QString& message) +{ + Logger::instance().addMessage(message); +} + static void term_thread(MainWindow* m, SOCKET* fd) { char cmd = OC_CMD_CANCEL; @@ -400,8 +449,8 @@ void MainWindow::checkLatestVersion() const req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy); - connect(manager, &QNetworkAccessManager::finished, - this, &MainWindow::gotLatestVersion); + connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(gotLatestVersion(QNetworkReply*))); Logger::instance().addMessage(QObject::tr("Checking for current version")); manager->get(req); @@ -514,13 +563,8 @@ void MainWindow::reload_settings() if (m_trayIcon) { QAction* act = m_trayIconMenuConnections->addAction(str); - connect(act, &QAction::triggered, [act, this]() { - int idx = ui->serverList->findText(act->text()); - if (idx != -1) { - ui->serverList->setCurrentIndex(idx); - on_connectClicked(); - } - }); + connect(act, SIGNAL(triggered()), + this, SLOT(onServerProfileTriggered())); } } } @@ -606,10 +650,10 @@ void MainWindow::changeStatus(int val) ui->connectionButton->setText(tr("Cancel")); blink_timer->start(1500); - disconnect(ui->connectionButton, &QPushButton::clicked, - this, &MainWindow::on_connectClicked); - connect(ui->connectionButton, &QPushButton::clicked, - this, &MainWindow::on_disconnectClicked, + disconnect(ui->connectionButton, SIGNAL(clicked()), + this, SLOT(on_connectClicked())); + connect(ui->connectionButton, SIGNAL(clicked()), + this, SLOT(on_disconnectClicked()), Qt::QueuedConnection); } else if (val == STATUS_DISCONNECTED) { blink_timer->stop(); @@ -652,10 +696,10 @@ void MainWindow::changeStatus(int val) m_trayIcon->setToolTip(QLatin1String("Disconnected")); } - disconnect(ui->connectionButton, &QPushButton::clicked, - this, &MainWindow::on_disconnectClicked); - connect(ui->connectionButton, &QPushButton::clicked, - this, &MainWindow::on_connectClicked, + disconnect(ui->connectionButton, SIGNAL(clicked()), + this, SLOT(on_disconnectClicked())); + connect(ui->connectionButton, SIGNAL(clicked()), + this, SLOT(on_connectClicked()), Qt::QueuedConnection); emit readyToShutdown(); @@ -892,8 +936,8 @@ void MainWindow::closeEvent(QCloseEvent* event) event->accept(); if (m_trayIcon && m_disconnectAction->isEnabled()) { - connect(this, &MainWindow::readyToShutdown, - qApp, &QApplication::quit); + connect(this, SIGNAL(readyToShutdown()), + qApp, SLOT(quit())); on_disconnectClicked(); } else { qApp->quit(); @@ -942,10 +986,8 @@ void MainWindow::readSettings() ui->actionStartMinimized->setChecked(settings.value("startMinimized", false).toBool()); ui->actionSingleInstanceMode->setChecked(settings.value("singleInstanceMode", true).toBool()); - connect(ui->actionSingleInstanceMode, &QAction::toggled, [](bool checked) { - OcSettings settings; - settings.setValue("Settings/singleInstanceMode", checked); - }); + connect(ui->actionSingleInstanceMode, SIGNAL(toggled(bool)), + this, SLOT(onSingleInstanceModeToggled(bool))); int loglevel = settings.value("logLevel", PRG_INFO).toInt(); int action_idx = app_loglevel_tab(loglevel); @@ -982,23 +1024,16 @@ void MainWindow::createLogDialog() { auto dialog{ new LogDialog() }; - disconnect(ui->viewLogButton, &QPushButton::clicked, - this, &MainWindow::createLogDialog); + disconnect(ui->viewLogButton, SIGNAL(clicked()), + this, SLOT(createLogDialog())); - connect(ui->viewLogButton, &QPushButton::clicked, - dialog, &QDialog::show); - connect(ui->viewLogButton, &QPushButton::clicked, - dialog, &QDialog::raise); - connect(ui->viewLogButton, &QPushButton::clicked, - dialog, &QDialog::activateWindow); + connect(ui->viewLogButton, SIGNAL(clicked()), + dialog, SLOT(showAndActivate())); - connect(dialog, &QDialog::finished, - [this]() { - connect(ui->viewLogButton, &QPushButton::clicked, - this, &MainWindow::createLogDialog); - }); - connect(dialog, &QDialog::finished, - dialog, &QDialog::deleteLater); + connect(dialog, SIGNAL(finished(int)), + this, SLOT(onLogDialogFinished())); + connect(dialog, SIGNAL(finished(int)), + dialog, SLOT(deleteLater())); dialog->show(); dialog->raise(); @@ -1013,8 +1048,8 @@ void MainWindow::createTrayIcon() m_trayIconMenu->addMenu(m_trayIconMenuConnections); m_disconnectAction = new QAction(tr("Disconnect"), this); m_trayIconMenu->addAction(m_disconnectAction); - connect(m_disconnectAction, &QAction::triggered, - this, &MainWindow::on_disconnectClicked); + connect(m_disconnectAction, SIGNAL(triggered()), + this, SLOT(on_disconnectClicked())); m_trayIconMenu->addSeparator(); m_trayIconMenu->addAction(ui->actionLogWindow); @@ -1051,8 +1086,8 @@ void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) void MainWindow::on_actionNewProfile_triggered() { NewProfileDialog dialog(this); - connect(&dialog, &NewProfileDialog::connect, - this, &MainWindow::on_connectClicked, + connect(&dialog, SIGNAL(connect()), + this, SLOT(on_connectClicked()), Qt::QueuedConnection); if (dialog.exec() != QDialog::Accepted) { return; @@ -1113,10 +1148,10 @@ void MainWindow::on_actionAbout_triggered() QString txt = QLatin1String("

") + QLatin1String(PRODUCT_NAME_LONG) + QLatin1String("

"); if (QLatin1String(PROJECT_VERSION).contains(QLatin1String("-g"))) { - txt += tr("Development snapshot %1 (%2 bit)
").arg(PROJECT_VERSION).arg(QSysInfo::buildCpuArchitecture() == QLatin1String("i386") ? 32 : 64); + txt += tr("Development snapshot %1 (%2 bit)
").arg(PROJECT_VERSION).arg(sizeof(void*) == 4 ? 32 : 64); txt += tr("Built at %1
").arg(QLatin1String(appBuildOn)); } else { - txt += tr("Version %1 (%2 bit)
").arg(PROJECT_VERSION).arg(QSysInfo::buildCpuArchitecture() == QLatin1String("i386") ? 32 : 64); + txt += tr("Version %1 (%2 bit)
").arg(PROJECT_VERSION).arg(sizeof(void*) == 4 ? 32 : 64); } txt += tr("
%1 is free software developed by the OpenConnect GUI project community. See the license for more information.
").arg(APP_NAME); @@ -1129,8 +1164,8 @@ void MainWindow::on_actionAbout_triggered() void MainWindow::checkForUpdatesDialog() { if (downloadProgress != nullptr) { - disconnect(this, &MainWindow::version_download_completed_sig, - this, &MainWindow::checkForUpdatesDialog); + disconnect(this, SIGNAL(version_download_completed_sig()), + this, SLOT(checkForUpdatesDialog())); this->downloadProgress->setValue(100); downloadProgress->done(0); delete downloadProgress; @@ -1146,10 +1181,10 @@ void MainWindow::checkForUpdatesDialog() txt += tr("

Current version

"); if (QLatin1String(PROJECT_VERSION).contains(QLatin1String("-g"))) { - txt += tr("Development snapshot %1 (%2 bit)
").arg(PROJECT_VERSION).arg(QSysInfo::buildCpuArchitecture() == QLatin1String("i386") ? 32 : 64); + txt += tr("Development snapshot %1 (%2 bit)
").arg(PROJECT_VERSION).arg(sizeof(void*) == 4 ? 32 : 64); txt += tr("Built at %1
").arg(QLatin1String(appBuildOn)); } else { - txt += tr("Version %1 (%2 bit)
").arg(PROJECT_VERSION).arg(QSysInfo::buildCpuArchitecture() == QLatin1String("i386") ? 32 : 64); + txt += tr("Version %1 (%2 bit)
").arg(PROJECT_VERSION).arg(sizeof(void*) == 4 ? 32 : 64); } txt += tr("

Latest version

"); @@ -1190,8 +1225,8 @@ void MainWindow::on_actionCheckForUpdates_triggered() downloadProgress = new QProgressDialog("Checking for latest version...", "Abort", 0, progress_max_value, this); // ensure that this is called when download is complete - connect(this, &MainWindow::version_download_completed_sig, - this, &MainWindow::checkForUpdatesDialog, + connect(this, SIGNAL(version_download_completed_sig()), + this, SLOT(checkForUpdatesDialog()), Qt::QueuedConnection); downloadProgress->setValue(25); diff --git a/src/dialog/mainwindow.h b/src/dialog/mainwindow.h index 20d224e..7567b99 100644 --- a/src/dialog/mainwindow.h +++ b/src/dialog/mainwindow.h @@ -102,6 +102,9 @@ public slots: void on_actionReport_an_issue_triggered(); void on_actionWebSite_triggered(); + /* connected from main.cpp to QtSingleApplication::messageReceived */ + void onSingleAppMessageReceived(const QString& message); + signals: void stats_changed_sig(QString, QString, QString); void vpn_status_changed_sig(int); @@ -114,8 +117,20 @@ private slots: void tryCheckLatestVersion(); void checkForUpdatesDialog(); + /* Named slots standing in for lambdas that used to be passed straight + * to connect(); Qt4's connect() cannot bind a functor/lambda slot. */ + void onActionQuitTriggered(); + void onStateMachineStarted(); + void onMinimizedWindowEntered(); + void onMinimizedWindowExited(); + void onServerProfileTriggered(); + void onSingleInstanceModeToggled(bool checked); + void onLogDialogFinished(); + + /* connected via old-style SIGNAL/SLOT macro, so must be a real slot */ + void gotLatestVersion(QNetworkReply* reply); + private: - void gotLatestVersion(QNetworkReply *reply); void checkLatestVersion() const; static QString normalize_byte_size(uint64_t bytes); @@ -143,6 +158,10 @@ private: time_t last_check_time; QProgressDialog *downloadProgress; + /* copy of the ctor's profileName arg, needed by onStateMachineStarted() + * since Qt4's connect() cannot capture it via a lambda */ + QString m_profileName; + QNetworkAccessManager *manager; QStateMachine* m_appWindowStateMachine; diff --git a/src/main.cpp b/src/main.cpp index e18a76e..50c37b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -205,9 +205,7 @@ int main(int argc, char* argv[]) mainWindow.show(); mainWindow.setWindowTitle(APP_NAME); - QObject::connect(&app, &QtSingleApplication::messageReceived, - [&mainWindow](const QString& message) { - Logger::instance().addMessage(message); - }); + QObject::connect(&app, SIGNAL(messageReceived(const QString&)), + &mainWindow, SLOT(onSingleAppMessageReceived(const QString&))); return app.exec(); } -- 2.43.0