From cc55ea066f8aca42d3e03360d4317301ffaa02b6 Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 18:12:09 +0200 Subject: [PATCH 1/8] Fix m_1secTimer firing at 10Hz instead of 1Hz m_1secTimer->start(100) started the timer with a 100ms interval despite its name and its handler, on_1secTimerTick(), being written for a once-per-second cadence: it toggles the graph hint popups' visibility based on cursor position every tick. At 10Hz instead of 1Hz this causes visibly flickering popups during normal use. --- mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 680f693..102c866 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -536,7 +536,7 @@ MainWindow::MainWindow(QWidget *parent) : m_1secTimer = new QTimer(this); connect(m_1secTimer, SIGNAL(timeout()), this, SLOT(on_1secTimerTick())); - m_1secTimer->start(100); + m_1secTimer->start(1000); loadLanguage(languages_small[m_languageNumber]); ui->tableWidget_presets->horizontalHeader()->show(); From e68f123d9f4b6cd6e8d9a893d6fbc2e64c17c1e5 Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 19:19:08 +0200 Subject: [PATCH 2/8] Remove dead include/declaration referencing nonexistent screeninfo.h analyzer/ble_analyzer.h includes "screeninfo.h" and declares a setScreenInfo(ScreenInfo&) signal; screeninfo.h does not exist anywhere in this repository at any commit reachable from master, and setScreenInfo is never defined or called anywhere either. This breaks any build on any platform. --- analyzer/ble_analyzer.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/analyzer/ble_analyzer.h b/analyzer/ble_analyzer.h index 6fc0f9d..88f98fe 100644 --- a/analyzer/ble_analyzer.h +++ b/analyzer/ble_analyzer.h @@ -11,7 +11,6 @@ #include #include #include "baseanalyzer.h" -#include "screeninfo.h" enum { BLE_VER_CMD = (quint8)0xE6, @@ -194,7 +193,6 @@ private slots: void measuringChanged(); void aliveChanged(); void statsChanged(); - void setScreenInfo(ScreenInfo& screen); private: QString m_error; From ccca77c4c7265b9e96c96a1527252f63b6c43ba4 Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 19:19:20 +0200 Subject: [PATCH 3/8] Fix flickering popups caused by a WindowActivate/WindowDeactivate feedback loop MainWindow::event() reacted to every single WindowActivate/WindowDeactivate by showing/hiding two always-on-top Qt::Tool popups (the graph 'Hint' and 'BriefHint' hints, and the markers popup). On some Wayland compositors (observed on COSMIC/cosmic-comp), unmapping/remapping those Qt::Tool surfaces itself triggers a spurious WindowActivate/WindowDeactivate on the parent window - which re-fires the same show/hide logic, creating a self-sustaining feedback loop that reads as rapidly flickering popups and a flickering main window title bar. Two changes, together: - MainWindow now debounces WindowActivate/WindowDeactivate symmetrically: neither is acted on immediately: only once the window's activation state has held steady for 300ms is focus() actually emitted, and only if it differs from the last emitted state. - PopUp::focusShow()/focusHide() and MarkersPopUp::focusShow()/focusHide() no longer map/unmap the underlying window at all; they move it on/off-screen instead. This keeps the Wayland surface continuously mapped, so showing/hiding these popups can no longer perturb the parent window's activation state, breaking the feedback loop at its root rather than just slowing it down. Also adds Qt::WindowDoesNotAcceptFocus to both classes' window flags as defense in depth. Separately, mainwindow.cpp already had m_1secTimer - a timer whose handler toggles the same hint popups based on cursor position - started with a 100ms interval despite its name and intent; that is a distinct, already-fixed bug (see previous commit) that made the same popups flash on every mouse-cursor check instead of once a second. --- mainwindow.cpp | 26 +++++++++++++++++++++----- mainwindow.h | 3 +++ markerspopup.cpp | 15 ++++++++++----- popup.cpp | 18 +++++++++++++++--- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 102c866..4471395 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -538,6 +538,10 @@ MainWindow::MainWindow(QWidget *parent) : connect(m_1secTimer, SIGNAL(timeout()), this, SLOT(on_1secTimerTick())); m_1secTimer->start(1000); + m_focusDebounceTimer = new QTimer(this); + m_focusDebounceTimer->setSingleShot(true); + connect(m_focusDebounceTimer, &QTimer::timeout, this, &MainWindow::onFocusDebounceTimeout); + loadLanguage(languages_small[m_languageNumber]); ui->tableWidget_presets->horizontalHeader()->show(); if(!m_isRange) @@ -761,12 +765,15 @@ void MainWindow::closeEvent(QCloseEvent *event) bool MainWindow::event(QEvent * e) { - if(e->type() == QEvent::WindowActivate) - { - emit focus(true); - }else if (e->type() == QEvent::WindowDeactivate) + if(e->type() == QEvent::WindowActivate || e->type() == QEvent::WindowDeactivate) { - emit focus(false); + // Some window managers/compositors send rapid, sometimes + // continuous, Activate/Deactivate churn (e.g. triggered by an + // always-on-top Qt::Tool child being mapped/unmapped, which is + // itself a reaction to a previous Activate here - a feedback + // loop). Do not react to any single event; only act once the + // window's activation state has held steady for a while. + m_focusDebounceTimer->start(300); }else if (e->type() == QEvent::WindowStateChange) { updateGraph(); @@ -774,6 +781,15 @@ bool MainWindow::event(QEvent * e) return QMainWindow::event(e) ; } +void MainWindow::onFocusDebounceTimeout() +{ + bool active = isActiveWindow(); + if (active != m_lastEmittedFocus) { + m_lastEmittedFocus = active; + emit focus(active); + } +} + void MainWindow::setWidgetsSettings() { QPen pen; diff --git a/mainwindow.h b/mainwindow.h index 5728d36..0533483 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -160,6 +160,8 @@ class MainWindow : public QMainWindow // QTimer *m_redrawTimer; QTimer *m_1secTimer; + QTimer *m_focusDebounceTimer; + bool m_lastEmittedFocus = true; double m_cableVelFactor; double m_cableResistance; @@ -338,6 +340,7 @@ private slots: void on_firmwareAutoUpdateStateChanged( bool state); void on_antScopeAutoUpdateStateChanged( bool state); void on_1secTimerTick(); + void onFocusDebounceTimeout(); void on_calibrationChanged(); void on_SaveFile(int row, QString path); void on_mouseDoubleClick(QMouseEvent* e); diff --git a/markerspopup.cpp b/markerspopup.cpp index 9274a04..e8b2fb3 100644 --- a/markerspopup.cpp +++ b/markerspopup.cpp @@ -22,7 +22,8 @@ MarkersPopUp::MarkersPopUp(QWidget *parent) : QWidget(parent), { setWindowFlags(Qt::FramelessWindowHint | // Отключаем оформление окна Qt::Tool | // Отменяем показ в качестве отдельного окна - Qt::WindowStaysOnTopHint); // Устанавливаем поверх всех окон + Qt::WindowStaysOnTopHint | // Устанавливаем поверх всех окон + Qt::WindowDoesNotAcceptFocus); // Никогда не становится активным окном setAttribute(Qt::WA_TranslucentBackground); // Указываем, что фон будет прозрачным setAttribute(Qt::WA_ShowWithoutActivating); // При показе, виджет не получается фокуса автоматически @@ -177,18 +178,22 @@ void MarkersPopUp::show() void MarkersPopUp::focusShow() { - //qDebug() << "MarkersPopUp::focusShow()" << m_menuVisible; - QWidget::show(); + move(m_x, m_y); + if (!isVisible()) { + QWidget::show(); + } } void MarkersPopUp::focusHide() { - //qDebug() << "MarkersPopUp::focusHide()" << m_menuVisible; if (m_menuVisible) { setVisible(true); return; } - QWidget::hide(); + // Park off-screen instead of QWidget::hide(): see PopUp::focusHide() + // for why unmapping this Qt::Tool surface causes a feedback loop on + // some Wayland compositors. + move(-32000, -32000); } void MarkersPopUp::hideAnimation() diff --git a/popup.cpp b/popup.cpp index 0eff1ac..9e07d7a 100644 --- a/popup.cpp +++ b/popup.cpp @@ -49,7 +49,8 @@ void PopUp::init() { setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | - Qt::WindowStaysOnTopHint); + Qt::WindowStaysOnTopHint | + Qt::WindowDoesNotAcceptFocus); setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_ShowWithoutActivating); @@ -185,12 +186,23 @@ void PopUp::show() void PopUp::focusShow() { - QWidget::show(); + move(m_x, m_y); + if (!isVisible()) { + QWidget::show(); + } } void PopUp::focusHide() { - QWidget::hide(); + // Park off-screen instead of QWidget::hide(): unmapping this + // Qt::Tool top-level surface causes some Wayland compositors + // (observed on COSMIC/cosmic-comp) to send a spurious + // WindowActivate/WindowDeactivate event to the parent window. Since + // that event drives this same show/hide logic (via MainWindow::event + // -> focus() -> showHideHints()), unmapping creates a self-sustaining + // feedback loop ("flickering popups"). Moving off-screen is visually + // equivalent while keeping the surface continuously mapped. + move(-32000, -32000); } void PopUp::hideAnimation() From db3c4ae7526a99517b712e16d8e5ee4c2b821fa2 Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 19:26:34 +0200 Subject: [PATCH 4/8] Fix missing semicolon in PopUp's default label stylesheet label.setStyleSheet("QLabel { color : " + m_textColor + "margin-top: ...") concatenates the text color directly onto the next CSS property with no separating semicolon, producing an invalid declaration like 'color : whitemargin-top: 6px' - the color is silently dropped by Qt's stylesheet parser. PopUp::setTextColor() already builds the equivalent string correctly (with a ';' after the color); this makes the default built in init() match it, so any PopUp that never calls setTextColor() still gets a valid, visible label color instead of relying on it being overwritten later. --- popup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/popup.cpp b/popup.cpp index 9e07d7a..b1972c6 100644 --- a/popup.cpp +++ b/popup.cpp @@ -59,7 +59,7 @@ void PopUp::init() connect(&animation, &QAbstractAnimation::finished, this, &PopUp::hide); label.setAlignment(Qt::AlignLeft | Qt::AlignVCenter); - label.setStyleSheet("QLabel { color : " + m_textColor + + label.setStyleSheet("QLabel { color : " + m_textColor + ";" "margin-top: 6px;" "margin-bottom: 6px;" "margin-left: 10px;" From b1ea88d2f37a3facd6357c5dc84a275735b87b70 Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 20:21:57 +0200 Subject: [PATCH 5/8] Convert graph/marker hint popups to embedded child widgets PopUp and MarkersPopUp were always separate Qt::Tool top-level windows. The previous fix (park off-screen instead of unmapping) stopped them causing flicker, but left them permanently registered as real windows with the window manager/task switcher, since they are never truly unmapped once shown. Add an 'embedded' constructor parameter: when true, the widget is a plain child of its parent instead of a separate top-level window, so there is no window for a window manager/compositor to ever see - no flicker risk, and nothing to show up in any window/task list either. All existing position-tracking code (setName/setPosition/ MainWindowPos/mouseMoveEvent) keeps computing m_x/m_y as global screen coordinates exactly as before; only the final geometry application (a new applyGeometry() helper) translates through parentWidget()->mapFromGlobal() when embedded, so none of that math needed to change. m_graphHint, m_graphBriefHint (Measurements) and m_markersHint (Markers) are now constructed embedded, parented to MainWindow. --- markers.cpp | 2 +- markerspopup.cpp | 60 ++++++++++++++++++++++++++++++++---------------- markerspopup.h | 8 ++++++- measurements.cpp | 4 ++-- popup.cpp | 58 +++++++++++++++++++++++++++++++++++++--------- popup.h | 8 +++++-- 6 files changed, 103 insertions(+), 37 deletions(-) diff --git a/markers.cpp b/markers.cpp index 663011f..55f9960 100644 --- a/markers.cpp +++ b/markers.cpp @@ -24,7 +24,7 @@ Markers::Markers(QObject *parent) : QObject(parent), if(m_markersHint == NULL) { - m_markersHint = new MarkersPopUp(); + m_markersHint = new MarkersPopUp(MainWindow::m_mainWindow, true); m_markersHint->setHiding(false); if(m_markersHintEnabled && !m_markersList.isEmpty()) m_markersHint->focusShow(); diff --git a/markerspopup.cpp b/markerspopup.cpp index e8b2fb3..d4d9138 100644 --- a/markerspopup.cpp +++ b/markerspopup.cpp @@ -5,7 +5,7 @@ QMap MarkersHeaderColumn::m_mapHeader; -MarkersPopUp::MarkersPopUp(QWidget *parent) : QWidget(parent), +MarkersPopUp::MarkersPopUp(QWidget *parent, bool embedded) : QWidget(parent), m_durability(2000), m_hiding(true), m_x(0), @@ -16,16 +16,23 @@ MarkersPopUp::MarkersPopUp(QWidget *parent) : QWidget(parent), m_mainY(0), m_mainBiasX(0), m_mainBiasY(0), + m_embedded(embedded), m_bgColor(0,0,0,180), m_penColor(255,255,255,180), m_textColor("white") { - setWindowFlags(Qt::FramelessWindowHint | // Отключаем оформление окна - Qt::Tool | // Отменяем показ в качестве отдельного окна - Qt::WindowStaysOnTopHint | // Устанавливаем поверх всех окон - Qt::WindowDoesNotAcceptFocus); // Никогда не становится активным окном + if (m_embedded) { + // A plain child widget of its parent, not a separate top-level + // window - see PopUp::init() in popup.cpp for the full + // rationale (same fix, same class of bug). + } else { + setWindowFlags(Qt::FramelessWindowHint | // Отключаем оформление окна + Qt::Tool | // Отменяем показ в качестве отдельного окна + Qt::WindowStaysOnTopHint | // Устанавливаем поверх всех окон + Qt::WindowDoesNotAcceptFocus); // Никогда не становится активным окном + setAttribute(Qt::WA_ShowWithoutActivating); // При показе, виджет не получается фокуса автоматически + } setAttribute(Qt::WA_TranslucentBackground); // Указываем, что фон будет прозрачным - setAttribute(Qt::WA_ShowWithoutActivating); // При показе, виджет не получается фокуса автоматически animation.setTargetObject(this); // Устанавливаем целевой объект анимации animation.setPropertyName("popupOpacity"); // Устанавливаем анимируемое свойство @@ -70,7 +77,20 @@ void MarkersPopUp::setName(QString name) m_settings->endGroup(); - setGeometry(m_x,m_y,width(),height()); + applyGeometry(); +} + +void MarkersPopUp::applyGeometry() +{ + // m_x/m_y are tracked as global screen coordinates throughout this + // class (mirrors PopUp::applyGeometry() in popup.cpp - see there for + // the full rationale). + if (m_embedded && parentWidget()) { + QPoint local = parentWidget()->mapFromGlobal(QPoint(m_x, m_y)); + setGeometry(local.x(), local.y(), width(), height()); + } else { + setGeometry(m_x, m_y, width(), height()); + } } MarkersPopUp::~MarkersPopUp() @@ -178,10 +198,13 @@ void MarkersPopUp::show() void MarkersPopUp::focusShow() { - move(m_x, m_y); + applyGeometry(); if (!isVisible()) { QWidget::show(); } + if (m_embedded) { + raise(); + } } void MarkersPopUp::focusHide() @@ -190,6 +213,12 @@ void MarkersPopUp::focusHide() setVisible(true); return; } + if (m_embedded) { + // A plain child widget: hiding it does not touch any top-level + // window, so there is no compositor feedback-loop risk here. + QWidget::hide(); + return; + } // Park off-screen instead of QWidget::hide(): see PopUp::focusHide() // for why unmapping this Qt::Tool surface causes a feedback loop on // some Wayland compositors. @@ -235,10 +264,7 @@ void MarkersPopUp::mouseMoveEvent(QMouseEvent * ) { m_x = QCursor::pos().x() - m_biasX; m_y = QCursor::pos().y() - m_biasY; - setGeometry(m_x, - m_y, - width(), - height()); + applyGeometry(); m_mainBiasX = m_x - m_mainX; m_mainBiasY = m_y - m_mainY; } @@ -250,20 +276,14 @@ void MarkersPopUp::MainWindowPos(int x, int y) m_x = x + m_mainBiasX; m_y = y + m_mainBiasY; - setGeometry(m_x, - m_y, - width(), - height()); + applyGeometry(); } void MarkersPopUp::setPosition(int x, int y) { m_x = x; m_y = y; - setGeometry(m_x, - m_y, - width(), - height()); + applyGeometry(); } void MarkersPopUp::setTextColor(QString color) diff --git a/markerspopup.h b/markerspopup.h index 1e01476..fffcece 100644 --- a/markerspopup.h +++ b/markerspopup.h @@ -43,7 +43,7 @@ class MarkersPopUp : public QWidget float getPopupOpacity() const; public: - explicit MarkersPopUp(QWidget *parent = 0); + explicit MarkersPopUp(QWidget *parent = 0, bool embedded = false); ~MarkersPopUp(); void setName(QString name); int getDurability (void) const {return m_durability;} @@ -125,6 +125,12 @@ private slots: int m_parentX; int m_parentY; + // When true, this MarkersPopUp is a plain child widget of its parent + // rather than a separate Qt::Tool top-level window - see + // markerspopup.cpp for why. + bool m_embedded; + void applyGeometry(); + QColor m_bgColor; QColor m_penColor; QString m_textColor; diff --git a/measurements.cpp b/measurements.cpp index 1cccef7..fe2d204 100644 --- a/measurements.cpp +++ b/measurements.cpp @@ -89,7 +89,7 @@ Measurements::Measurements(QObject *parent) : QObject(parent), if(m_graphHint == NULL) { - m_graphHint = new PopUp(); + m_graphHint = new PopUp(MainWindow::m_mainWindow, true); m_graphHint->setHiding(false); m_settings->beginGroup("Settings"); bool darkTheme = m_settings->value("darkColorTheme", true).toBool(); @@ -116,7 +116,7 @@ Measurements::Measurements(QObject *parent) : QObject(parent), if(m_graphBriefHint == NULL) { - m_graphBriefHint = new PopUp(); + m_graphBriefHint = new PopUp(MainWindow::m_mainWindow, true); m_graphBriefHint->setHiding(false); //m_graphBriefHint->setPopupText("0\n0"); m_graphBriefHint->setName(tr("BriefHint")); diff --git a/popup.cpp b/popup.cpp index b1972c6..a8c772e 100644 --- a/popup.cpp +++ b/popup.cpp @@ -5,7 +5,7 @@ #include #include -PopUp::PopUp(QWidget *parent) : QWidget(parent), +PopUp::PopUp(QWidget *parent, bool embedded) : QWidget(parent), m_bgColor(0,0,0,180), m_penColor(255,155,255,180), m_textColor("white"), @@ -19,12 +19,13 @@ PopUp::PopUp(QWidget *parent) : QWidget(parent), m_mainX(177), m_mainY(131), m_mainBiasX(0), - m_mainBiasY(0) + m_mainBiasY(0), + m_embedded(embedded) { init(); } -PopUp::PopUp(QString buttonName, QWidget *parent) : QWidget(parent), +PopUp::PopUp(QString buttonName, QWidget *parent, bool embedded) : QWidget(parent), m_bgColor(0,0,0,180), m_penColor(255,155,255,180), m_textColor("white"), @@ -40,19 +41,28 @@ PopUp::PopUp(QString buttonName, QWidget *parent) : QWidget(parent), m_mainBiasX(0), m_mainBiasY(0), m_buttonName(buttonName), - m_showButton(true) + m_showButton(true), + m_embedded(embedded) { init(); } void PopUp::init() { - setWindowFlags(Qt::FramelessWindowHint | - Qt::Tool | - Qt::WindowStaysOnTopHint | - Qt::WindowDoesNotAcceptFocus); + if (m_embedded) { + // A plain child widget of its parent, not a separate top-level + // window: there is no window for a window manager/compositor to + // ever see, so this cannot perturb the parent's activation state + // (see focusShow()/focusHide()) and it cannot show up in any + // window/task list either. + } else { + setWindowFlags(Qt::FramelessWindowHint | + Qt::Tool | + Qt::WindowStaysOnTopHint | + Qt::WindowDoesNotAcceptFocus); + setAttribute(Qt::WA_ShowWithoutActivating); + } setAttribute(Qt::WA_TranslucentBackground); - setAttribute(Qt::WA_ShowWithoutActivating); animation.setTargetObject(this); animation.setPropertyName("popupOpacity"); @@ -120,7 +130,23 @@ void PopUp::setName(QString name) m_settings->endGroup(); - setGeometry(m_x,m_y,width(),height()); + applyGeometry(); +} + +void PopUp::applyGeometry() +{ + // m_x/m_y are tracked as global screen coordinates throughout this + // class (MainWindowPos(), mouseMoveEvent() and every caller of + // setPosition() all compute them that way, matching the original + // Qt::Tool top-level design). When embedded as a child widget, + // translate to parent-relative coordinates right here instead of + // touching that positioning math anywhere else. + if (m_embedded && parentWidget()) { + QPoint local = parentWidget()->mapFromGlobal(QPoint(m_x, m_y)); + setGeometry(local.x(), local.y(), width(), height()); + } else { + setGeometry(m_x, m_y, width(), height()); + } } PopUp::~PopUp() @@ -186,14 +212,24 @@ void PopUp::show() void PopUp::focusShow() { - move(m_x, m_y); + applyGeometry(); if (!isVisible()) { QWidget::show(); } + if (m_embedded) { + raise(); + } } void PopUp::focusHide() { + if (m_embedded) { + // A plain child widget: hiding it does not touch any top-level + // window, so there is no compositor feedback-loop risk here - + // see the Qt::Tool branch below for what that risk was. + QWidget::hide(); + return; + } // Park off-screen instead of QWidget::hide(): unmapping this // Qt::Tool top-level surface causes some Wayland compositors // (observed on COSMIC/cosmic-comp) to send a spurious diff --git a/popup.h b/popup.h index b8a48e3..dcda853 100644 --- a/popup.h +++ b/popup.h @@ -21,8 +21,8 @@ class PopUp : public QWidget float getPopupOpacity() const; public: - explicit PopUp(QWidget *parent = 0); - explicit PopUp(QString button, QWidget *parent = 0); + explicit PopUp(QWidget *parent = 0, bool embedded = false); + explicit PopUp(QString button, QWidget *parent = 0, bool embedded = false); ~PopUp(); void init(); void setName(QString name); @@ -104,6 +104,10 @@ protected slots: int m_parentX; int m_parentY; + // When true, this PopUp is a plain child widget of its parent rather + // than a separate Qt::Tool top-level window - see popup.cpp for why. + bool m_embedded; + void applyGeometry(); QString m_name; From 2dd37bd41050c93c5144ae6f7e8e8e39c9269224 Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 20:22:03 +0200 Subject: [PATCH 6/8] Initialize Measurements::m_focus and Markers::m_focus Both were declared but never initialized, and only ever assigned inside on_focus(bool). Previously the first WindowActivate at startup emitted focus(true) essentially immediately, setting it before anything read it. The new debounced focus() emission (see the previous commit on this branch fixing the WindowActivate/Deactivate feedback loop) can now legitimately not emit at all during startup if the window starts active, leaving m_focus read before it is ever written - undefined behavior. Default-initialize both to true, matching the normal case of an app that starts with the main window focused. --- markers.h | 2 +- measurements.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/markers.h b/markers.h index 663d78f..06942bb 100644 --- a/markers.h +++ b/markers.h @@ -103,7 +103,7 @@ class Markers : public QObject Measurements *m_measurements; - bool m_focus; + bool m_focus = true; double interpolate(double fq1, double fq2, double fq3, double param1, double param2); diff --git a/measurements.h b/measurements.h index 41be83b..318ba37 100644 --- a/measurements.h +++ b/measurements.h @@ -216,7 +216,7 @@ class Measurements : public QObject qint32 m_farEndMeasurement; QCPItemEllipse * m_smithTracer; - bool m_focus; + bool m_focus = true; bool m_oneFqMode = false; qint64 m_oneFqStartTime; From 178f681552fc8fce67f02ceeaff20263e7c6ff3b Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 20:22:09 +0200 Subject: [PATCH 7/8] Fix missing semicolon in OneFqWidget's default label stylesheet Same bug as db3c4ae (popup.cpp): the color declaration runs straight into the next CSS property with no separating semicolon ('color : #RRGGBBmargin-top: 6px'), silently dropping the color. The class's own setTextColor() builds the equivalent string correctly. --- onefqwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onefqwidget.cpp b/onefqwidget.cpp index b83bf1d..e93011d 100644 --- a/onefqwidget.cpp +++ b/onefqwidget.cpp @@ -28,7 +28,7 @@ OneFqWidget::OneFqWidget(int _points, QWidget *parent) : setAttribute(Qt::WA_ShowWithoutActivating); m_label.setAlignment(Qt::AlignLeft | Qt::AlignVCenter); - m_label.setStyleSheet("QLabel { color : " + m_textColor.name() + + m_label.setStyleSheet("QLabel { color : " + m_textColor.name() + ";" "margin-top: 6px;" "margin-bottom: 6px;" "margin-left: 10px;" From 6f8486a54b450b76447e3f321602ce5ecabc7834 Mon Sep 17 00:00:00 2001 From: Simon Keimer Date: Mon, 31 Aug 2026 20:22:14 +0200 Subject: [PATCH 8/8] Guard against stacking multiple SelectDeviceDialog instances on_selectDeviceDialog() runs a nested event loop via dlg.exec(). A pending QTimer::singleShot call to the same slot (e.g. from on_refreshConnection()) would still fire while that nested loop is running, stacking a second real top-level SelectDeviceDialog on top of the first. No live path currently re-enters it, but the pattern is fragile against future changes and costs nothing to guard directly. --- mainwindow.cpp | 10 ++++++++++ mainwindow.h | 1 + 2 files changed, 11 insertions(+) diff --git a/mainwindow.cpp b/mainwindow.cpp index 4471395..0f9f767 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -6822,6 +6822,15 @@ void MainWindow::on_selectDeviceDialog() return; } + // dlg.exec() below runs a nested event loop, during which any other + // queued call to this same slot (e.g. a pending QTimer::singleShot + // from on_refreshConnection()) would still fire and stack a second + // SelectDeviceDialog on top of the first. Guard against that. + if (m_selectDeviceDialogOpen) { + return; + } + m_selectDeviceDialogOpen = true; + SelectDeviceDialog dlg(false, this); if (dlg.exec() == QDialog::Accepted) { SelectionParameters sel_par = SelectionParameters::selected; @@ -6831,6 +6840,7 @@ void MainWindow::on_selectDeviceDialog() emit m_analyzer->analyzerFound(selected->index()); } } + m_selectDeviceDialogOpen = false; closeSettingsDialog(); ui->settingsBtn->setEnabled(true); } diff --git a/mainwindow.h b/mainwindow.h index 0533483..0354177 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -201,6 +201,7 @@ class MainWindow : public QMainWindow bool m_addingMarker; bool m_isMouseClick; bool m_bInterrupted; + bool m_selectDeviceDialogOpen = false; QMap m_BandsMap; bool m_darkColorTheme = true; QPalette m_lightPalette;