Guard the FX-drain busy indicator against silent enum drift and cursor edge cases

Promote drainStateNow's switch to error-on-missing-case locally; set DWLP_MSGRESULT on WM_SETCURSOR; add an HTCLIENT guard; skip refreshBusyCursor during a live drag; mark the docked-dialog WM_SETCURSOR routing premise [verify - DAW].
This commit is contained in:
2026-08-21 15:14:55 -04:00
parent 052fbb0d52
commit bbdeba9dda
3 changed files with 39 additions and 3 deletions
+2 -1
View File
@@ -73,7 +73,8 @@ live in `shell/bank_ops`, a sibling directory, not here.
REAPER's, and the SDK exposes nothing host-wide. A global `SetSystemCursor` or a message
hook would reach further and is rejected — do not reintroduce either. `IDC_APPSTARTING`
is Windows-only (SWELL ships no equivalent), so on mac/Linux the readout is the whole
indicator.
indicator. `[verify — DAW]` whether REAPER's docker even routes `WM_SETCURSOR` to the
docked child dialog at all — the whole Windows half of this rests on that.
- **No hit-test geometry in untestable shell code.** Even when reusing a WDL piece
(e.g. a `vwnd` control for a long scroll list), layout/hit-test math stays in pure
CTest-covered modules — do not import a WDL control's retained-mode object model
+18
View File
@@ -479,6 +479,19 @@ bool g_accelRegistered = false;
// The ONE map from the reclaimer's answer to the pure readout's vocabulary. Name-for-name
// so a divergence reads as one; the decision itself is entirely fxReclaimActivity's.
// This TU compiles straight into the reaper_reasampler MODULE, which carries none of
// reasampler_pure_library's -Werror=switch/we4062 promotion (footer_bar's mirror switch
// over FxDrainState has that; this one didn't) — a fourth FxReclaimActivity enumerator
// would fall through to Idle here with no diagnostic at all. Promoted locally instead of
// widening the target-wide flag, which would need auditing every switch already compiled
// into this MODULE for an intentionally-partial case list.
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(error : 4062)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wswitch"
#endif
FxDrainState drainStateNow() {
switch (fxReclaimActivity()) {
case FxReclaimActivity::Online: return FxDrainState::Online;
@@ -487,6 +500,11 @@ FxDrainState drainStateNow() {
}
return FxDrainState::Idle;
}
#if defined(_MSC_VER)
#pragma warning(pop)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
} // namespace
+19 -2
View File
@@ -100,7 +100,9 @@ void handleDropFiles(HDROP hDrop) {
// cursor at all and the footer readout carries the state alone. The cursor reaches OUR
// windows only; REAPER's arrange and mixer answer their own WM_SETCURSOR and the SDK
// exposes nothing host-wide to ask for. A global SetSystemCursor or a message hook would
// reach further and is deliberately not done.
// reach further and is deliberately not done. [verify — DAW] whether REAPER's docker even
// routes WM_SETCURSOR to the docked child dialog at all — the premise the whole Windows
// half of this feature rests on.
#ifdef _WIN32
HCURSOR busyCursor() { return LoadCursor(nullptr, IDC_APPSTARTING); }
#else
@@ -118,12 +120,24 @@ bool busyCursorApplies() {
WDL_DLGRET dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_SETCURSOR:
// Non-client hits (resize border, etc.) are not ours to answer for; let the
// default handling run. Harmless today (IDD_BANK_PANEL is a bare WS_CHILD
// with no controls or border) but the guard is the conventional one.
if (LOWORD(lParam) != HTCLIENT) return 0;
// Claiming the message (non-zero) is what stops the default arrow from being
// reapplied underneath us — on Win32 via DefDlgProc, on SWELL via the same
// return test in swell-wnd-generic.cpp. Falling through leaves every other
// cursor decision exactly where it was (panel_drag's per-move SetCursor).
if (busyCursorApplies()) {
SetCursor(busyCursor());
// A DLGPROC conveys its result through DWLP_MSGRESULT, not the raw
// return value; WM_SETCURSOR is not on the exception-message list that
// skips this. Without it the bare `return 1` still suppresses
// DefDlgProc's own cursor (SWELL checks the raw return too), but a
// parent or sender reading the result would see "unhandled".
#ifdef _WIN32
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
#endif
return 1;
}
return 0;
@@ -240,7 +254,10 @@ void closePanel() {
} // namespace
void refreshBusyCursor() {
if (!g_panel.hwnd) return;
// Nothing to refresh on mac/Linux (busyCursor() is always null there), and a live
// drag owns the cursor already (panel_drag::applyDragCursor) — forcing IDC_ARROW
// here on a drain edge mid-drag would stomp that cue until the next mouse move.
if (!g_panel.hwnd || !busyCursor() || g_panel.dragArmed || g_panel.dragging) return;
POINT pt{};
GetCursorPos(&pt); // SWELL's returns void, so its result is deliberately not tested
// Only when our own window is the one under the pointer: a menu or another window