Skip to content

Merge flicker-fix branch and README update into fix/security-hardening - #1

Merged
dc0sk merged 10 commits into
fix/security-hardeningfrom
linux-packaging
Sep 2, 2026
Merged

dc0sk merged 10 commits into
fix/security-hardeningfrom
linux-packaging

Conversation

@dc0sk

@dc0sk dc0sk commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

linux-packaging is fix/security-hardening merged with fix/1sec-timer-flicker (the branch backing upstream PR rigexpert#29), plus a README update. It's what both AUR packages (antscope2, antscope2-git) are built from - antscope2-git tracks this branch's tip directly.

Changes

  • Merges in all 8 commits from fix/1sec-timer-flicker (the flickering-popups/title-bar fix and its underlying defects) - clean merge, no conflicts, verified with a full qmake6/make build of the merged tree.
  • Updates README.md: Windows Qt5 → Qt6, and Linux from "to do" to real build instructions plus links to both AUR packages.

Test plan

  • Clean merge (no conflicts)
  • Full qmake6 CONFIG+=release AntScope.pro && make build of the merged tree succeeds
  • This exact tree (plus one Linux-packaging-only patch) is what antscope2-git's PKGBUILD builds - verified via a fresh clone + build before publishing that package

🤖 Generated with Claude Code

dc0sk and others added 10 commits August 31, 2026 18:12
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.
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.
…dback 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.
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 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.
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.
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.
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.
Windows still said Qt5, and Linux said "to do" despite qmake6 building
this cleanly on Linux and two AUR packages (antscope2, antscope2-git)
existing and being actively maintained.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EAiXVpAbBuCAxWNA3mzJY
@dc0sk
dc0sk merged commit 8a24f18 into fix/security-hardening Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant