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:
@@ -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
|
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`
|
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
|
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
|
- **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
|
(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
|
CTest-covered modules — do not import a WDL control's retained-mode object model
|
||||||
|
|||||||
@@ -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
|
// 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.
|
// 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() {
|
FxDrainState drainStateNow() {
|
||||||
switch (fxReclaimActivity()) {
|
switch (fxReclaimActivity()) {
|
||||||
case FxReclaimActivity::Online: return FxDrainState::Online;
|
case FxReclaimActivity::Online: return FxDrainState::Online;
|
||||||
@@ -487,6 +500,11 @@ FxDrainState drainStateNow() {
|
|||||||
}
|
}
|
||||||
return FxDrainState::Idle;
|
return FxDrainState::Idle;
|
||||||
}
|
}
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,9 @@ void handleDropFiles(HDROP hDrop) {
|
|||||||
// cursor at all and the footer readout carries the state alone. The cursor reaches OUR
|
// 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
|
// 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
|
// 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
|
#ifdef _WIN32
|
||||||
HCURSOR busyCursor() { return LoadCursor(nullptr, IDC_APPSTARTING); }
|
HCURSOR busyCursor() { return LoadCursor(nullptr, IDC_APPSTARTING); }
|
||||||
#else
|
#else
|
||||||
@@ -118,12 +120,24 @@ bool busyCursorApplies() {
|
|||||||
WDL_DLGRET dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
WDL_DLGRET dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_SETCURSOR:
|
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
|
// 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
|
// reapplied underneath us — on Win32 via DefDlgProc, on SWELL via the same
|
||||||
// return test in swell-wnd-generic.cpp. Falling through leaves every other
|
// return test in swell-wnd-generic.cpp. Falling through leaves every other
|
||||||
// cursor decision exactly where it was (panel_drag's per-move SetCursor).
|
// cursor decision exactly where it was (panel_drag's per-move SetCursor).
|
||||||
if (busyCursorApplies()) {
|
if (busyCursorApplies()) {
|
||||||
SetCursor(busyCursor());
|
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 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -240,7 +254,10 @@ void closePanel() {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void refreshBusyCursor() {
|
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{};
|
POINT pt{};
|
||||||
GetCursorPos(&pt); // SWELL's returns void, so its result is deliberately not tested
|
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
|
// Only when our own window is the one under the pointer: a menu or another window
|
||||||
|
|||||||
Reference in New Issue
Block a user