Repository navigation
Desktop 2.1.1: cursor confined to stale 1280x720 ClipCursor rect on multi-monitor while sessions process #57732
Description
Description
Windows confines the OS cursor to 0,0-1280,720 while sessions are being processed in OpenCode Desktop 2.1.1. This is the 2.x follow-up to #45171 (closed for the 2.0 re-test; I cannot reopen it because I am not the original author and have no triage rights).
With the watchdog disabled the rect stays applied and keeps coming back. Esc/Alt+Tab releases the cursor, but it re-arms shortly after. SendInput (absolute and relative) is ignored while clipped; only physical movement or SetCursorPos sometimes escapes. GetCapture is 0 and the window under the cursor is the OpenCode renderer.
The important detail is the geometry: the clip rect matches the app's hardcoded default window size (1280x800, i.e. a 1280x720 client area), not the current maximized size (2560x1440). That points at a pointer-lock/clip rect captured once at default geometry and never recomputed on resize/maximize.
Environment:
- OpenCode 2.1.1 (Electron 44.4.5), Windows 11 build 26300
- Primary 2560x1440 @100%, secondary 1920x1080 at x=-1920
- IDE/browser panel open, session processing
Evidence (GetClipCursor, 100 ms polling, real capture):
07:58:11.139 clip=-1920,0-2560,1440 (free)
07:58:18.657 clip=0,0-1280,720 (applied by OpenCode)
07:58:18.777 clip=-1920,0-2560,1440 (released by watchdog, ~120 ms later)
window-state-*.json on the same machine:
{"width":1280,"height":800,"x":0,"y":0,"displayBounds":{"x":0,"y":0,"width":2560,"height":1440},"isMaximized":true,"isFullScreen":false}Notes from inspecting the shipped 2.1.1 bundle (may save triage time):
ClipCursor,setIgnoreMouseEventsandrequestPointerLockdo not appear inapp.asarapplication code (only inside bundled caniuse data). The clip is therefore applied by Chromium's native Windows layer (pointer lock / mouse capture), not by app JS.- The default
1280x800is hardcoded in two places:packages/desktop/src/main/windows/index.tsandpackages/desktop/src/main/windows/early.ts, both viaresolveWindowState(..., { width: 1280, height: 800 }, ...). packages/desktop/src/main/windows/window-state.tspersists bounds only while the window is not maximized, storesisMaximizedseparately, and restores by creating the window at the normal bounds and then callingwin.maximize(). Itsresize/movelisteners only debounce a state write; nothing releases or recomputes a clip on resize, maximize, hide or close.- The bundle creates one
WebContentsViewfor popup web content (sandboxed,webviewTag: false), which is the only embedded-web-content surface where a real pointer lock could be requested.
Specific questions:
- Is the clip/pointer-lock rect recomputed when the window is resized or maximized?
- Can the IDE/browser panel leave a stale lock behind after its session ends, or when the panel is hidden/closed?
Workaround: a background watchdog polls GetClipCursor at ~7 Hz and calls ClipCursor(NULL) whenever the rect does not cover the primary display.
Plugins
No response
OpenCode version
2.1.1 (Desktop, Electron 44.4.5)
Steps to reproduce
- Windows 11, two displays (primary 2560x1440 @100%, secondary 1920x1080 at x=-1920).
- Open OpenCode Desktop 2.1.1 with the IDE/browser panel open.
- Start a session and let it process.
- Poll
GetClipCursorat 100 ms: the rect becomes0,0-1280,720and stays/reapplies until released externally.
Screenshot
GetClipCursor log excerpt is inline above. Full multi-hour log available on request.
Operating System
Windows 11 build 26300
Terminal
OpenCode Desktop (not a terminal)
Activity
opencode-agent commentedon Oct 21, 2026
Thanks for the detailed report and the
GetClipCursorlog. It's the right follow-up to #45171, which described the same symptom on v1.We couldn't reproduce this here. Cursor clipping only happens with the Desktop app on Windows, and our test environment can't run that, so a maintainer with a Windows multi-monitor setup will need to look at it.
Some notes that may help with that:
ClipCursoror pointer lock directly, and the 1280x800 window default only affects the window's own size.It would help to know:
gilmarribeiropereira78-stack commentedon Oct 21, 2026
Tested the three questions on 2.1.1:
So the synthetic-mouse-event path is not required for the trigger. The correlation is with the panel merely being open, not with a gesture happening inside it.
One more data point from the shipped 2.1.1 bundle, in case it narrows things down. The panel creates a single
WebContentsView, and the only non-cornersetBoundscall in the wholeapp.asaris:The view is anchored at the origin with a fixed default size before it is handed to the embed manager. That is not
1280x720exactly, so I am not claiming it is the observed rect, but it is the only origin-anchored embedded surface in the app. Later sizing happens insideembeds.create/oe.show, which is not visible in the minified bundle.What would be worth checking on your side:
visible=false) or the view is destroyed?The other candidate geometry is still the one from the window code:
1280x720is the client area of the hardcoded1280x800default window.The
GetClipCursorwatchdog is still required to keep the machine usable on 2.1.1.