Commit Graph

6566 Commits (plot-perf-opt)

Author SHA1 Message Date
Mooneer Salem c88b016655 Add PR #1481 to changelog. 2026-09-06 16:27:39 -07:00
Mooneer Salem 4088153041 Cut waterfall and scalar plot paint cost; fix uninitialised heatmap entry.
On macOS wxGraphicsContext::DrawBitmap(wxBitmap) is far more expensive than the
wxGraphicsBitmap overload: wxBitmapRefData::GetImage() caches nothing, so every
call allocates a fresh NSImage and draws through -[NSImage drawInRect:], where
the wxGraphicsBitmap path goes straight to CGContextDrawImage. The waterfall made
one such call per pixel block -- m_imgHeight/dy of them, ~200 on a 600px tall
plot -- on each of its 10 frames a second.

* Waterfall blocks are now held as {wxBitmap, wxGraphicsBitmap} pairs. The
  wxBitmap stays as the StretchBlit target; the renderer-native copy is made once,
  when the block is filled, rather than on every frame it spends scrolling down
  the screen. Measured 1.648 -> 0.453 ms per paint at 700x600.

* PlotScalar composites its plot area the same way. The conversion is per frame
  here since plotArea_ is redrawn each time, but it still beats the NSImage round
  trip: 0.381 -> 0.205 ms per paint at 700x200 on the data-only repaint path that
  "Frm Mic" and friends actually take.

* Waterfall graticule labels are laid out once per resize instead of per frame.
  wxWindowMac::DoGetTextExtent builds and destroys a wxGraphicsContext per call
  and drawGraticule() was making ~25 of them a frame for text that only moves when
  the control is resized. It also measured every one second tick before checking
  whether that tick gets a label, so most of the measuring was discarded.

* Dropped BeginLayer(1.0)/EndLayer from the waterfall, scalar and spectrum plots.
  At opacity 1.0 the transparency layer allocates and composites an offscreen
  buffer to produce exactly what drawing directly produces.

Separately, the heatmap LUT was filled over 0..254 while plotPixelData() clamps
intensity to 255 and reaches it whenever a bin sits at the top of the current
range -- so the hottest pixels took their colour from indeterminate memory on
essentially every frame carrying signal. Rendering a synthetic spectrum offscreen,
1665 pixels in the peak column came out as RGB(15,0,0), RGB(62,0,0) and
RGB(220,0,0) instead of the intended full-scale red.

Verified by driving draw() offscreen and diffing the output against master over
400 frames, enough to fill the waterfall and exercise block recycling roughly 200
times: the performance changes alone are bit-for-bit identical, and the only
pixels the LUT fix moves are the max-intensity ones described above.

test_rade_loss.sh passes with these changes, though it cannot really speak to
them: it exercises no plotting, and on this machine it fails intermittently on
master too (5 pass / 1 fail on master, 4 pass / 3 fail here across interleaved
runs of the two builds).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADMCssMazpW1igtvMHXNWZ
2026-09-06 15:11:44 -07:00
Mooneer Salem a32c54d1f5 latest user manual PDF 2026-09-06 08:59:43 +00:00
Mooneer Salem 9e803577bc
Equalizer: make sure number of output samples is correct. (#1480)
* Equalizer: make sure number of output samples is correct.

There may be a scenario where `EqualizerStep` doesn't properly set the number of output samples. This ensures that we're always setting the number of output samples to a valid value.

* Add PR #1480 to changelog.
2026-09-06 01:57:26 -07:00
Mooneer Salem 48c007d552 latest user manual PDF 2026-09-03 04:50:01 +00:00
Mooneer Salem fe0986d497
Fix compiler error with Hamlib 5.0. (#1477)
* Fix compiler error with Hamlib 5.0.

* Fix typo.

* Bring back old code for Ubuntu 22.04.

* Update CMake to explicitly look for rig_state.h.

* Add PR #1477 to changelog.

* Fix typo.
2026-09-02 21:46:35 -07:00
Mooneer Salem 1f0b6c19c5 latest user manual PDF 2026-09-03 01:16:13 +00:00
Mooneer Salem 1bfb8f2cb7
CI: Use macos-26 for running tests (#1478)
* Remove deprecated macos-14, test only on macos-26 due to GitHub issues.

* Work around dyld error when enabling sanitizers.

* Readd macOS 14 and 15 to tests.

* Add PR #1478 to changelog.
2026-09-02 18:13:56 -07:00
Mooneer Salem 397e55b069
CI: Add Ubuntu 26.04 LTS to tests. (#1479)
* CI: Add Ubuntu 26.04 LTS to tests.

* Fix misspellings due to switch to 26.04.
2026-09-02 16:29:08 -07:00
Barry Jackson 6a1bf2b999
Fix RX/TX level-meter gauge contamination (#1475)
* Fix RX/TX level-meter gauge contamination -- OnTimer's demod-in branch read a stale txState local instead of g_tx

* Update fix to update txState instead.

* Add PR #1475 to changelog.

---------

Co-authored-by: merge-test <test@test.local>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-08-29 17:24:00 -07:00
Mooneer Salem 4984c7d047 latest user manual PDF 2026-08-27 19:24:23 +00:00
Mooneer Salem 168a6cf3fb
Add logic to prevent FIFO sizes that are too small to allow TX thread to function. (#1474)
* Add logic to prevent FIFO sizes that are too small to allow TX thread to function.

* Add PR #1474 to changelog.
2026-08-27 12:21:02 -07:00
Mooneer Salem 8973e01786 latest user manual PDF 2026-08-26 06:47:14 +00:00
Mooneer Salem 8df2ffd578
Increment version to 2.4.1 to begin development. (#1473)
* Increment version to 2.4.1 to begin development.

* Add changelog section.
2026-08-25 23:43:56 -07:00
Mooneer Salem d4acddf1c5 latest user manual PDF 2026-08-25 04:37:00 +00:00
Mooneer Salem 6eaaebcc05
Release version 2.4.0. (#1471)
* Release version 2.4.0.

* Move old changelog out of user manual.
2026-08-24 21:34:09 -07:00
Barry Jackson fa65961580
Fix waterfall/spectrum filling solid colour during half-duplex TX (#1462)
* Fix waterfall/spectrum filling solid colour during half-duplex TX

The half-duplex-TX "blank the display" path memset() the spectrum
arrays to zero bytes, but this display's dB scale runs 0 (loudest) to
MIN_MAG_DB (quietest) -- zero meant "loudest possible", not silence,
so it painted the waterfall solid instead of blanking it (yellow,
occasionally clamping to red at the top of the colour scale).

Filling with MIN_MAG_DB alone wasn't sufficient either: the
waterfall's colour scale is relative to each row's own peak (peak
minus a fixed 20dB window), so a perfectly flat row -- regardless of
its absolute level -- always reads as "loud relative to itself". This
showed up live as a green-to-red fade as the auto-ranging baseline
(m_max_mag) caught up to the new flat level.

Fixed properly by detecting a row where every bin sits exactly at the
floor (real spectra essentially never do) and rendering it as plain
black directly, bypassing the relative intensity scale and leaving
the auto-ranging baseline untouched, rather than running synthetic
placeholder data through logic designed for real spectra.

Confirmed identical on master and v3.0-dev; tested live against a
real half-duplex TX/RX cycle.

* Add PR #1462 to changelog.

---------

Co-authored-by: Barry Jackson <barjac@mageia.org>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-08-15 13:21:23 -07:00
Mooneer Salem 6f782682ef latest user manual PDF 2026-08-15 18:26:25 +00:00
Mooneer Salem b0acc0b063
Fix issue preventing TX thread from sleeping. (#1465)
* Fix issue preventing TX thread from sleeping.

* Forgot additional change.

* Try 40ms frames.

* 10ms

* Probably still need to feed zeroes as needed.

* Revert frame duration back to 20ms.

* Add PR #1465 to changelog.
2026-08-15 11:23:44 -07:00
Mooneer Salem 86199f747e latest user manual PDF 2026-08-14 08:54:01 +00:00
Mooneer Salem 3888055eeb
Remove CLIP indicator from main window. (#1461)
* Remove CLIP indicator from main window.

* Add PR #1461 to changelog.

* Remove no longer used TOO_HIGH_LABEL constant.
2026-08-14 01:51:24 -07:00
Mooneer Salem 431191c42c
Windows/macOS: Zero audio on startup. (#1463)
* Windows/macOS: Zero audio on startup.

* Add PR #1463 to changelog.
2026-08-14 01:00:36 -07:00
Mooneer Salem 7cbbd85124 latest user manual PDF 2026-08-13 00:46:29 +00:00
Mooneer Salem 52f1b5daf9
Enable CCache to make CI builds run more quickly. (#1328)
* Enable CCache to make CI builds run more quickly.

* Ensure Hamlib is also part of ccache.

* Try creating symlink.

* Increase ccache max size limit.

* Add ccache for Windows builds.

* Add cache for lint as well.

* Make sure PGO is covered by ccache.

* Dummy change to make sure build is cached.

* macOS: Ensure node 24 is used for ccache

* Windows: use node 24.

* Increase max cache size on macOS to 5G.

* Add Windows debugging for ccache.

* Use CMake compiler launcher to launch ccache.

* Use symlinks for PGO builds.

* Don't cache PGO use steps, we can't afford to with only 10GB available.

* Fix issue causing cache misses.

* Forgot that we need to use single quotes.

* Revert previous whitespace change.

* Enable ccache for Linux builds.

* Fix shell command error.

* Add PR #1328 to changelog.
2026-08-12 17:43:22 -07:00
Barry Jackson c3102f4ac5
Fix FreeDV Reporter column-order corruption and Last TX column width (#1458)
* Fix FreeDV Reporter column-order repair to detect gaps, not just trailing entries

If a persisted freedvReporterColumnOrder value was missing an index
from the middle of its range (not just missing new indices appended
after a NUM_COLS increase), the old repair logic never noticed --
it only ever appended indices above the current max element. A
column permanently missing from the list means the wxDataViewCtrl
never creates it, so any later getColumnForModelColId_() lookup for
that column asserts/crashes (e.g. while sorting on it as new spots
arrive).

Reproduced and fixed against a real corrupted config
(ColumnOrder missing index 12/SNR_COL from the middle, confirmed to
crash on assert `item != nullptr` in getColumnForModelColId_ during
live FreeDV Reporter use) -- also explains a previously-unexplained
symptom of an extra empty column appearing when dragging the
rightmost column divider.

* Fix column-order gap detection, sentinel-column drag corruption, and Last TX width

Brings this branch's earlier column-order fix up to the same final
state as testing surfaced on v3.0-dev, since all three are general
bugs unrelated to the LAST_RX_MODE_COL difference between the two
branches:

- Validate/repair the persisted column order unconditionally rather
  than only when its length looks wrong -- a config value can have
  the right length while still containing an out-of-range/duplicate
  entry and missing a genuine one, which the old size()-only check
  never caught.
- OnColumnReordered's save path assumed the trailing sentinel spacer
  column always stays in the last visual position; nothing enforces
  that, so a drag could leave it captured as if it were one of the
  real NUM_COLS columns, silently dropping a real one and persisting
  the sentinel's invalid model ID instead -- the actual cause of an
  "empty column" appearing after reordering.
- Keep the Last TX column at least as wide as Last Update's actual
  current width (both use the same date/time format), checked
  periodically via the dialog's existing timer rather than once at
  construction time, since neither column's real autosized width is
  known reliably that early.

Confirmed working live on the desktop against a real corrupted
config with a real radio.

* Minor style tweak.

* Add PR #1458 to changelog.

---------

Co-authored-by: Barry Jackson <barjac@mageia.org>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-08-11 12:53:52 -07:00
Mooneer Salem 758d03c71b latest user manual PDF 2026-08-10 17:56:29 +00:00
Mooneer Salem dbc770c6fe
Enable PGO for Windows builds. (#1457)
* Enable PGO for Windows builds.

* instrumented prefix wasn't actually being added.

* Port generate_pgo_profiles.sh to PowerShell (thanks Claude).

* Try disabling RX so we can at least debug rest of pipeline.

* Fix profraw path.

* Try enabling RX code again.

* See if we can get some extra debugging.

* Bound process wait.

* Use Reporting sox invocation.

* Redo config file prior to RX run.

* Fix LLVM profile merge error.

* Add PR #1457 to changelog.
2026-08-10 10:53:59 -07:00
Mooneer Salem fc8dec0ffd latest user manual PDF 2026-08-07 23:35:18 +00:00
Mooneer Salem c4881274cf
Enable LTO/PGO for macOS .app build. (#1456)
* Experiment: Enable LTO/PGO for macOS .app build.

* PGO: Fix tab layout to match new encoding.

* Try disabling LTO during instrumented build.

* Revert "Try disabling LTO during instrumented build."

This reverts commit e6b4e1a191.

* Try disabling temporal profiles.

* Need to run profiling on both x86_64 and arm64.

* Disable universal builds for the PGO instrumented build.

* Revert "Try disabling temporal profiles."

This reverts commit 89036a3ed6.

* Add PR #1456 to changelog.

* Fake change to force rebuild.

* Revert "Fake change to force rebuild."

This reverts commit a2a8886377.

* Add Intel checks for .app.

* No torch on Intel anymore.
2026-08-07 16:32:00 -07:00
Mooneer Salem 718c015d66
Prevent PulseAudio/pipewire from quitting during CI tests. (#1455)
* Prevent PulseAudio/pipewire from quitting during CI tests.

* Output tmp.log during test runs.

* Fix typos.
2026-08-05 14:48:45 -07:00
Mooneer Salem e0164750f2 latest user manual PDF 2026-08-05 15:37:16 +00:00
Mooneer Salem 33cea45310
Fix Radio Frequency coloring on dark/light mode transition. (#1453)
* Fix Radio Frequency coloring on dark/light mode transition.

* Fix UBSan warning.

* Add PR #1453 to changelog.
2026-08-05 08:34:41 -07:00
Barry Jackson 9398f589d4
Fix crash and long hang on main window close with an unresponsive rig (#1452)
* Fix crash on repeat main-window close while shutdown is in progress

topFrame_OnClose() unconditionally dereferenced m_reporterDialog, but a
second wxEVT_CLOSE_WINDOW arriving while the async RX/PTT shutdown from
a first close is still running (e.g. during a slow Hamlib rig disconnect
against an unresponsive radio) re-enters the handler after
m_reporterDialog has already been set to null on the first pass --
SIGSEGV in wxWindowBase::GetPosition(). Guard re-entry via terminating_
and null-check m_reporterDialog, matching the pattern already used in
the destructor and setConfiguration_().

* Don't block on rig disconnect against an unresponsive radio when turning modem off

Dropping the last shared_ptr reference to a rig controller runs its
destructor, which blocks until the rig actually finishes disconnecting.
Against an unresponsive radio (e.g. powered off, connected via rigctld)
this can take far longer than Hamlib's own client-side timeout/retry
settings suggest, since those don't bound however long rigctld itself
waits on the physical radio -- observed over a minute with no feedback
to the user. Move the last reference onto a detached thread for both
rig controllers so that wait can't hold up turning the modem off or
app shutdown.

* Bound the wait for rig-disconnect threads during app-close shutdown

The detached rig PTT/frequency controller disconnect threads added in
the previous commit have no upper bound on app-close: MainFrame::Destroy()
fires right after performFreeDVOff_() returns, with nothing joining those
threads, so an unresponsive rig still mid-disconnect when the process
actually exits gets its thread killed outright -- e.g. a queued ptt(false)
might never reach the radio. Have each detached thread signal completion
via a future, and on the terminating path wait up to 3s (shared deadline
across both) before proceeding to Destroy() -- long enough for a merely
slow rig to finish cleanly, still bounded so a truly unresponsive one
can't hang shutdown.

Also expand the terminating_ guard comment in topFrame_OnClose() to note
it prevents more than the m_reporterDialog crash: m_RxRunning stays true
until deep inside the same async shutdown, so a repeat close request
could otherwise re-enter OnTogBtnOnOff() a second time concurrently with
the shutdown already in progress.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* Add PR #1452 to changelog.

---------

Co-authored-by: Barry Jackson <barjac@mageia.org>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-08-04 19:23:04 -07:00
Barry Jackson f1cdc8b262
Fix CMAKE_REQUIRED_DEFINITIONS missing -D prefix in GTK3 wx probe (regression from #1449) (#1450)
* Fix CMAKE_REQUIRED_DEFINITIONS missing -D prefix in GTK3 wx probe (#1449)

wxWidgets_DEFINITIONS is a list of bare macro tokens (correct for the
COMPILE_DEFINITIONS property UsewxWidgets.cmake sets it via), but
CMAKE_REQUIRED_DEFINITIONS requires full "-DFOO" strings. Without the
prefix, check_cxx_symbol_exists()'s probe compile passes each bare
token as a raw command-line argument, which the compiler treats as a
(nonexistent) input filename and errors out on -- silently failing the
whole check closed (WX_BUILT_FOR_GTK3 always false) even against a
genuinely GTK3-built wxWidgets.

With HAS_GTK3 then never defined, topFrame.cpp's GTK3 guard takes the
non-GTK3 fallback branch and creates a stray 1x1 reference wxWindow
directly on the main frame -- disabling wx's "auto-resize sole child
to fill the frame" behaviour and freezing the entire main window's
layout on resize.

Verified on a real GTK3 wxWidgets 3.3.1 build (Mageia 10): reproduced
the false negative on a completely fresh configure (no stale cache
involved), then confirmed the fix resolves it on the first try.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Add PR #1450 to changelog.

* Revert accidental commit.

---------

Co-authored-by: Barry Jackson <barjac@mageia.org>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-08-02 15:25:48 -07:00
Barry Jackson 68043af8a6
Fix heard-stations callsign combo stuck-highlight, right-click behaviour, and a stale-index crash (#1448)
* Fix stale selection index crash in wxListViewComboPopup

OnMouseMove() deselected the previously hot-tracked row (m_value)
without checking it was still a valid index, so any external
DeleteAllItems() on the underlying list left a stale index that
crashed the next mouse-move over the popup.

* Fix heard-stations callsign combo stuck-highlight and right-click behaviour

OnCloseCallsignList/OnRightClickCallsignList moved keyboard focus away
from the read-only combo synchronously, but the popup window overlaps
the combo's own value area while open and GTK doesn't always repaint
that region on dismiss, leaving it showing a stale "focused/selected"
highlight. Defer the focus change via CallAfter and force a repaint
once the popup's dismissal has fully finished.

Also stop OnRightClickCallsignList from clearing the displayed
callsign text on deselect -- it should only remove the selection,
consistent with how right-click deselect works in the FreeDV Reporter
list.

* Add PR #1448 to changelog.

---------

Co-authored-by: Barry Jackson <barjac@mageia.org>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-08-01 22:25:40 -07:00
Mooneer Salem 78910b53b8 latest user manual PDF 2026-08-02 02:03:19 +00:00
Mooneer Salem af3fffa131
Ensure wxWidgets actually uses GTK3 before enabling workarounds. (#1449)
* Ensure wxWidgets actually uses GTK3 before enabling workarounds.

* Add PR #1449 to changelog.
2026-08-01 19:00:09 -07:00
Mooneer Salem 91b1c85805 latest user manual PDF 2026-07-30 21:48:21 +00:00
Mooneer Salem 25f4419aad
Unconditionally add new station to Heard Station list if first heard. (#1444)
* Unconditionally add new station to Heard Station list if first heard.

* Add check for non-zero number of items.

* Add PR #1444 to changelog.
2026-07-30 14:40:57 -07:00
Mooneer Salem 32f02b2c5b latest user manual PDF 2026-07-30 21:01:53 +00:00
Mooneer Salem bebbf9374e
Automatically start decoding on FreeDV startup. (#1436)
* Automatically start decoding on FreeDV startup.

* Fix 22.04 compiler error.
2026-07-30 13:59:17 -07:00
Mooneer Salem 6e93b66d65 latest user manual PDF 2026-07-30 19:09:17 +00:00
Mooneer Salem da560f12d4
Use wxWidgets 3.3 hooks to save/load tab layout. (#1435)
* Use wxWidgets 3.3 hooks to save/load tab layout.

* Re-add previous wxWidgets <= 3.2 implementation of tab save/restore.

* Restore 'Enable Experimental Features' option.

* Restore previous RX tab.

* Add PR #1435 to changelog.
2026-07-30 11:55:40 -07:00
Mooneer Salem a4ae053505 latest user manual PDF 2026-07-21 18:21:56 +00:00
Mooneer Salem 2c423e8d47
Require C++20 support when building FreeDV. (#1440)
* Require C++20 support when building FreeDV.

* Fix Windows compiler errors.

* Add PR #1440 to changelog.

* Fix compiler errors due to wxWidgets 3.0 and C++20.
2026-07-21 11:19:29 -07:00
Mooneer Salem aa83a3a082 latest user manual PDF 2026-07-20 23:50:34 +00:00
Mooneer Salem d60339922f
Upgrade wxWidgets to 3.3.3. (#1439)
* Upgrade wxWidgets to 3.3.3.

* Add PR #1439 to changelog.
2026-07-20 16:45:51 -07:00
Barry Jackson fc8531574e
Fix Voice Keyer/PTT context menu positioning under native Wayland (#1438)
* Fix Voice Keyer/PTT context menu positioning under native Wayland

The manual left-offset used to keep these menus on-screen on X11
(added 2023, commit 98c43d83) doesn't translate to Wayland's
surface-relative xdg_popup anchor model -- it was landing at the
toplevel's origin instead of next to the button. Added
LeftOffsetContextMenuPosition() which detects a Wayland GDK display at
runtime and returns wxDefaultPosition there, letting GTK's own popup
placement handle screen-edge avoidance (as already happens for the
Reporter Send/Clear menus, which never used a manual offset). X11
keeps the original offset unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Add PR #1438 to changelog.

---------

Co-authored-by: Barry Jackson <barjac@mageia.org>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-07-20 12:26:57 -07:00
Barry Jackson 9918843f4f
Fix right-click context menus dismissing before they can be read (GTK) (#1437)
* Defer Voice Keyer right-click menu popup via CallAfter

On GTK, PopupMenu() called synchronously from the wxEVT_CONTEXT_MENU
handler opens the menu while the originating right-click's implicit
pointer grab is still active, so the matching button-up is delivered
straight to the menu, selecting whatever is under the cursor before it
can be read. Deferring via CallAfter lets the initiating click fully
complete first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix Voice Keyer/PTT right-click menu using established RIGHT_UP workaround

The CallAfter approach in the previous commit didn't help: on a fast
click, GDK often has both the button-press and its paired release
already queued and dispatches both before any idle-priority callback
runs, so the menu still opened with the click already spent.

This file already has the correct fix for the identical issue on other
widgets (m_txLevelBox, m_txtTxLevelNum, m_btnTogTune, added earlier):
on wxGTK 3.3+, wxEVT_CONTEXT_MENU is generated from button-press, so
showing a menu from it opens while that click's release is still
pending and GTK delivers the release straight to the menu as a
selection. Bind wxEVT_RIGHT_UP instead for wx>=3.3 (keeping
wxEVT_CONTEXT_MENU on older wx, matching the existing widgets), which
only fires once the click has genuinely finished.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix FreeDV Reporter Send/Clear button right-click menus (same RIGHT_UP fix)

Same class of bug as the Voice Keyer/PTT buttons: wxEVT_CONTEXT_MENU is
generated from button-press on wxGTK 3.3+, so the menu opens while the
click's release is still pending and GTK delivers it straight to the
menu as a selection. Was only visible when the item under the cursor
happened to be enabled -- a disabled item just closes the menu
silently on release, masking the bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Scope the RIGHT_UP context-menu workaround to GTK only

The wxEVT_CONTEXT_MENU-on-button-press behaviour this works around is
GTK-specific: MSW already generates the event on button-up, and OSX
uses ctrl-click. The version-only guard (wxCHECK_VERSION(3,3,0)) would
otherwise apply the same override on Windows/Mac builds using wx 3.3+,
which could drop keyboard-invoked (Menu key/Shift+F10) context menus
on MSW since that only comes through wxEVT_CONTEXT_MENU. Add
defined(__WXGTK__) to all six guard sites, including the pre-existing
one for m_txLevelBox/m_txtTxLevelNum/m_btnTogTune this pattern was
copied from.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Drop version gate: dismiss-on-release bug confirmed present on wx 3.2 too

Direct testing on a wxGTK 3.2 build showed the same context-menu
dismiss-on-release bug the wxCHECK_VERSION(3,3,0) guard assumed was
3.3-specific (copied from the pre-existing txLevel/tune pattern this
was based on). Reading wx 3.2 vs 3.3 source confirmed the press-side
event synthesis is identical in both versions, so the fix now applies
on all wxGTK versions for these real windowed button widgets. The
original txLevel/tune block's version gate is left untouched since its
stated rationale (windowless widgets not generating RIGHT_UP pre-3.3)
is a separate, more specific concern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Add PR #1437 to changelog.

---------

Co-authored-by: Barry Jackson <barjac@mageia.org>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Mooneer Salem <mooneer@gmail.com>
2026-07-19 16:47:16 -07:00
Barry Jackson 4a18367084
Harden experimental tab layout persistence (#1434)
* Harden experimental tab layout persistence

Fix three defect classes found in the AUI tab-layout save/restore feature
(still gated behind Tools->Options->Debugging->Enable Experimental Features):

- SavePerspective()/LoadPerspective() (topFrame.cpp) keyed each saved tab by
  its positional AddPage() index, so any future reordering/insertion/removal
  of a tab silently corrupted previously-saved layouts (this already caused
  a shipped hang, fixed ad hoc in a7aab5d7 when the SNR plot was added). Tabs
  are now keyed by their (stable, unique) caption text instead.
- LoadPerspective() had an assert(dest_tabs != nullptr) that compiles out in
  release builds (NDEBUG), so a saved layout that parses to zero tab groups
  would null-deref instead of failing safely. It now falls back to a single
  default tab group holding every page.
- togglePTT() and OnTogBtnVoiceKeyerClick() each guessed which tab to restore
  by scanning a hardcoded list of 5 plot windows for one sharing "Frm Mic"'s
  tab group, because wxAuiNotebook::GetSelection() is ambiguous once tabs are
  split into multiple simultaneously-visible groups. Replaced both copies
  with a shared captureCurrentMicGroupTab_() helper that asks the specific
  tab group directly (wxAuiTabCtrl::GetActivePage()) instead of guessing.

The Experimental Features gate itself is unchanged; this only hardens the
feature while it's still under that flag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix tab layout being clobbered by off-then-on Experimental Features toggle

Both the load (main.cpp, in loadConfiguration_()) and save (exportConfiguration_())
of the AUI tab layout were independently gated on the live experimentalFeatures
value. LoadPerspective() only ever runs once, at startup, so toggling the checkbox
mid-session has no effect on the current layout. But the exit-time save re-read the
live (possibly since-toggled) flag, so: start with the flag off (load skipped, tabs
render as one flat group), flip it back on, then exit -> the flat layout gets saved
right over a previously-good split layout.

Cache the flag value at the point the load decision is made
(tabLayoutPersistenceEnabledAtStartup_) and use that same cached value to gate the
exit-time save, instead of the live value.

Found via live testing of the previous commit's fixes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix assertion crash dragging a tab near a group left empty by an old saved layout

LoadPerspective() created a live tab-group pane for every '|'-delimited entry in
the saved layout string before this commit's caption fix, even when every one of
that group's saved tokens failed to resolve to a current tab (as happens for any
pre-existing saved layout from before tabs were keyed by caption instead of
position - see 49ec38c1). The result was a zero-page wxAuiTabCtrl left sitting in
the AUI layout. wxAuiNotebook's own drag-and-drop handling doesn't tolerate that:
dragging a tab near the empty group crashed with
"./src/aui/auibook.cpp(371): assert "idx < m_pages.GetCount()" failed in
GetPage(): Invalid Page index" (reported from live testing on the desktop, which
still had an old-format two-group saved layout).

Track the last group known to hold at least one page separately from the group
just created each loop iteration, and sweep up any that ended up empty via
RemoveEmptyTabFrames() (the same cleanup the function already uses for the
previous session's tabs) instead of leaving them in the layout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Update changelog for drag-and-drop crash fix

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 16:24:30 -07:00