Close the bridged-process hole in the drag-out hand-off gate

OsHandoff now needs the window-ownership proof AND a hit-test that named
nothing, so a bridged plugin's UI can't read as off-REAPER.
This commit is contained in:
2026-08-03 16:42:59 -04:00
parent 9599e96e0c
commit b71a05fbef
12 changed files with 113 additions and 64 deletions
+7 -5
View File
@@ -199,11 +199,9 @@ LiveDrop resolveLiveDrop(int x, int y) {
const DropProbe probe = probeDropTarget(sp.x, sp.y);
ctx.surface = probe.surface;
ctx.haveTrack = probe.track != nullptr;
// Two independent probes because they answer two independent questions: REAPER's
// hit-test names the surface, window ownership decides whether we are still in REAPER
// at all. The SDK hit-test cannot answer the second — GetThingFromPoint documents no
// off-REAPER return, so its silence over the transport or the toolbar used to read as
// "the user left" and gave the live drag away to OLE.
// Two probes because they answer two independent questions: what REAPER named, and
// whether we are still inside REAPER at all. The law's hand-off gate reads both — see
// ui::DropContext::pointerOffHost.
ctx.pointerOffHost = !pointerOverHostWindow(sp.x, sp.y);
out.track = probe.track;
out.screenX = sp.x;
@@ -249,6 +247,10 @@ void handOffToOs() {
invalidatePanel();
initiateDragOut(g_panel.hwnd, paths); // COPY-ONLY; blocking on Windows
// The drag state was reset above, so the WM_LBUTTONUP that ends the modal loop takes
// onLBtnUp's not-dragging branch and never restores the arrow — do it here instead.
SetCursor(LoadCursor(nullptr, IDC_ARROW));
}
// Resolves the topmost INTERACTIVE element under client (x, y) for hover feedback,