Skip to content

[BUG] Desktop (Windows): app intermittently becomes an invisible input-eating overlay after display/DPI changes on multi-monitor setups #59229

Open

Description

@ouc3www

Description

Description

On a dual-monitor Windows setup, OpenCode Desktop intermittently enters a state where an invisible window (an app-owned Chrome_WidgetWin_1 window — either the main BrowserWindow with stale bounds or a transparent overlay BrowserWindow) sits on top of other applications and swallows all mouse input. Affected windows stay fully visible but cannot be clicked ("behind glass" feeling). In the worst observed episode, no window on the entire desktop could be interacted with — GetForegroundWindow() returned NULL, i.e. Windows input/foreground routing was wedged system-wide.

Only recoveries that work: lock screen + log back in, killing the OpenCode process, or restarting the graphics driver (Win+Ctrl+Shift+B).

Note: this was observed on an enterprise-customized build of OpenCode Desktop 2.1.4 (custom updater/config; the desktop shell itself appears unmodified). The window-management path involved is upstream packages/desktop, so I believe this is worth reporting here.

Environment

  • OpenCode Desktop 2.1.4 (Electron), bundled opencode-cli 2.1.4
  • Windows 11 Pro 23H2, build 10.0.22631
  • Two monitors; secondary monitor arranged above the primary → negative Y coordinates (OpenCode main window lives at (-128,-1440), size 3440x1440)

Steps to reproduce (probabilistic)

  1. Run OpenCode Desktop on a multi-monitor setup where one monitor has negative coordinates / mixed DPI scale.
  2. Use it across display-state transitions: lock screen / monitors sleep+wake / scale changes. Episodes occurred roughly daily.
  3. At some point after such a transition (suspiciously often right after a task-completion toast appears), other windows become visible-but-unclickable. Sometimes it escalates to the whole desktop being unclickable.

Evidence

Captured with a background watcher sampling WindowFromPoint() at the cursor every 2 s, comparing the top window's owner PID against the foreground window's PID.

During a freeze:

[2026-10-26 10:04:00] GLASS-SIGNATURE cursor=(576,-618)
TOP: class=Chrome_WidgetWin_1 proc=OpenCode(pid 19172) title='OpenCode'
rect=(-112,-1162)-(2661,11)
FG: proc=Idle(pid 0) style=HIDDEN <- NO foreground window exists

[2026-10-26 10:04:11] TOP: same OpenCode window
FG: class=XamlExplorerHostIslandWindow proc=explorer title='任务切换' <- user pressing Alt+Tab, clicks still eaten

Key observations:

  • The topmost window under the cursor during every freeze is OpenCode's own Chrome_WidgetWin_1 window (main BrowserWindow with stale bounds, or a transparent overlay BrowserWindow — they share class/title in the capture).
  • The bounds during the freeze are a stale DPI-scaled rectangle: 2773x1173 ≈ 81% of the window's normal size (3440x1440) — i.e. laid out with a different DPI scale than the monitor's current one. Chromium apparently did not re-run placement / hit-test updates after the display-scale change.
  • GetForegroundWindow() == NULL during the total-freeze episode indicates wedged input/foreground routing, not merely a z-order issue.
  • Not the IME: Sogou IME injects SoBS_* layered topmost windows into the OpenCode process and was initially suspected, but the capture shows the blocker is Chrome_WidgetWin_1; switching IME does not affect recovery.
  • Not a crash: Crashpad has 0 reports, no GPU errors in logs. (Separately: 179 ResizeObserver loop completed with undelivered notifications. renderer errors in one session — consistent with layout thrash around DPI transitions.)

Suspected trigger (hypothesis, A/B test pending)

Episodes appear to coincide with task-completion toast notifications (bottom-right). Hypothesis: the transparent overlay BrowserWindow used for toasts shows/hides across a DPI/display transition, ends up with stale bounds, and stays invisible-but-hit-testable = full-screen invisible input eater. Disabling completion notifications is the pending experiment.

Expected behavior

Windows/overlays belonging to OpenCode must never intercept mouse input while invisible, and window bounds must be re-asserted after DPI/display changes.

Workarounds found

Action Result
Lock screen → log back in Always recovers (resets display/input state)
Kill OpenCode.exe Always recovers
Win+Ctrl+Shift+B (restart graphics driver) Recovers, fastest
Switch IME / click elsewhere No effect

Suggestions

  1. Re-assert window bounds and setIgnoreMouseEvents state on WM_DPICHANGED, WM_DISPLAYCHANGE, and session-unlock events.
  2. Fully destroy toast/overlay BrowserWindows on dismissal (or mark them click-through whenever not actively showing), never leave them hidden at alpha 0 but hit-testable.
  3. Handle windows on negative-coordinate monitors in the window-placement path.

Happy to provide the full watcher script, complete logs, or additional captures on request.

Plugins

No response

OpenCode version

OpenCode Desktop 2.1.4 (Electron), bundled opencode-cli 2.1.4

Steps to reproduce

No response

Screenshot

No response

Operating System

win11

Terminal

win terminal

Activity

  1. opencode-agent commented on Oct 26, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed capture, it helps a lot.

    A few things would help us narrow this down before we try to reproduce it:

    1. Official build: does this also happen with the official OpenCode Desktop (2.1.4 or later, from opencode.ai or GitHub releases) instead of the enterprise-customized build? This matters because upstream Desktop doesn't create a transparent toast or overlay window. Completion notifications are native Windows toasts, and the only app windows are the normal main windows. Your capture also shows the main OpenCode window, so if the custom build adds its own overlay or notification window, that could be the cause.
    2. Monitors: the resolution and Windows display scale (e.g. 100% / 125% / 150%) of each monitor, and which one OpenCode is usually on.
    3. Notifications test: the result of your test with completion notifications turned off. Does it still happen?
    4. Window state: is the OpenCode window maximized, snapped or freely sized when it happens? And does it start after a specific event (unlocking, monitors waking, changing the scale)?

    You can reply here with the details, or edit the issue. If you edit it, please also leave a comment saying you've updated it so we know when you're done.

    I didn't find any existing issue that reports this same problem.

  2. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Answers to your questions:

    2. Monitors (hard data):

    Monitor Physical res Windows scale Position
    DISPLAY1 (primary, laptop panel) 3120x2080 200% (0,0)
    DISPLAY2 (secondary, external, arranged above) 3440x1440 125% (-102,-1152) — negative Y

    OpenCode's main window is maximized on the secondary 125% monitor.

    4. Window state + triggering events: the main window is maximized on the secondary monitor. Every episode we've captured followed a display-state transition: workstation lock/unlock or monitor sleep/wake. Never spontaneously.

    New smoking gun (exact arithmetic match): the culprit window rect captured during the freeze, (-112,-1162)-(2661,11) (2773x1173), is exactly the secondary monitor's DPI-virtualized logical bounds (-102,-1152) 2752x1152 (= 3440x1440 / 1.25) plus standard window border padding (-10px top-left, +21px bottom-right):

    • -102 - 10 = -112, -1152 - 10 = -1162
    • -102 - 10 + 2752 + 21 = 2661, -1152 - 10 + 1152 + 21 = 11

    So at freeze time the maximized window had been re-laid-out using the monitor's DPI-virtualized (logical) coordinates as if they were physical pixels, covering the entire secondary monitor. Combined with the wedged foreground state (GetForegroundWindow() == NULL), this looks like a mixed-DPI (200% vs 125%) coordinate confusion in the Electron/Chromium window placement path, triggered by lock/unlock or monitor wake while the window is maximized on the lower-DPI monitor.

    1. Official build: not tested yet — I'll install the official OpenCode Desktop 2.1.4+ side-by-side and report whether it reproduces.

    3. Notifications test: in progress. One note: our enterprise build renders completion toasts in-app, so I'm also testing with notifications disabled entirely. Will follow up here with the result.

    I've also automated evidence capture: a watcher samples WindowFromPoint() at the cursor every 2 s and logs any state where the top window under the cursor belongs to OpenCode while the foreground window belongs to another process. Happy to attach the script and full logs if useful.

  3. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Second episode captured by the background watcher, ~40 minutes after the first — reproducible and deterministic:

    Episode 2 timeline (2026-10-26, local time):

    10:39:19-10:40:06  renderer.log: burst of 37 "ResizeObserver loop completed with
                       undelivered notifications." errors  <- layout thrash, wrong re-layout
    10:41:29  first GLASS-SIGNATURE:
              TOP: class=Chrome_WidgetWin_1 proc=OpenCode(pid 19172) title='OpenCode'
                   rect=(-112,-1162)-(2661,11)
              FG:  class=Chrome_WidgetWin_1 proc=WeLinkPC (another app was foreground)
    10:44:58  FG becomes Idle(pid 0)  <- foreground routing wedged
    10:45:00-10:45:17  six consecutive samples: same frozen rect, FG=NULL
              -> whole desktop unclickable
    

    Key points:

    1. Identical frozen rect across both episodes: (-112,-1162)-(2661,11) — exactly the secondary monitor's DPI-virtualized logical bounds ((-102,-1152) 2752x1152 = 3440x1440 / 1.25) plus window border padding. This is not a random misplacement; it is the same deterministic wrong re-layout every time: the maximized-on-125%-monitor window gets re-laid-out using logical coordinates as physical pixels, covering the whole monitor as an invisible input eater.
    2. The ResizeObserver error storm in renderer.log immediately precedes the freeze — consistent with the bad re-layout happening then.
    3. The wedge progresses in two stages: first other windows become unclickable while OpenCode still works (10:41:29, FG still normal), then ~3.5 min later foreground routing fully wedges (FG=NULL) and the entire desktop is unclickable until lock-screen/logon.

    Will report back with the official-build test and the notifications-off test as promised.

  4. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Correction / answer to Q1: the build in question is the official OpenCode Desktop 2.1.4 — not a modified binary. electron-updater in this install points to the official feed https://opencode.ai/update/api/latest/desktop/opencode/, and its latest.yml (fetched today) lists 2.1.4 (releaseDate 2026-10-23) as the current version, matching the installed OpenCode.exe FileVersion 2.1.4.0. The only "enterprise customization" is at the config layer (opencode.json with internal model providers); the app shell is stock.

    So the side-by-side test is moot: this happens on the official build, current version.

    That also makes your note the key insight: since upstream Desktop doesn't create a transparent toast/overlay window, the Chrome_WidgetWin_1 captured in both freezes is most likely the main BrowserWindow itself — maximized on the 125% secondary monitor — whose bounds/hit-test got re-laid-out using the monitor's DPI-virtualized logical coordinates (exact arithmetic match documented above) after a lock/unlock or monitor-wake transition. I'm downgrading the notification-trigger hypothesis accordingly; the display-state transition remains the common factor in every captured episode, and the ResizeObserver error storm in renderer.log immediately precedes each freeze.

    Still to come: the notifications-off test (in progress, though given the above it may well be independent of notifications).

  5. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Answer to Q3 (notifications-off test): still reproduces with notifications disabled.

    Third episode captured at 10:50:46-10:50:56 local time, with completion notifications turned off:

    [10:50:46] TOP: class=Chrome_WidgetWin_1 proc=OpenCode(pid 19172) title='OpenCode'
               rect=(-112,-1162)-(2661,11)        <- same frozen rect, 3rd time
               FG:  class=Chrome_WidgetWin_1 proc=chrome (Google Chrome was foreground)
    [10:50:46-10:50:56] six consecutive samples, same signature
    

    So the experiment matrix is now:

    Episode Notifications Trigger context Frozen rect
    #1 (10:04) on after lock/unlog (-112,-1162)-(2661,11)
    #2 (10:41) on after display transition (-112,-1162)-(2661,11)
    #3 (10:50) off after display transition (-112,-1162)-(2661,11)

    Conclusion: notifications are not the trigger. The common factor in all three episodes is a display-state transition (workstation lock/unlock, monitor sleep/wake) with the main window maximized on the 125% secondary monitor of a 200%/125% mixed-DPI setup. The DPI-virtualized-coordinate re-layout (exact arithmetic match documented earlier) remains the core defect, and (-112,-1162)-(2661,11) is its deterministic signature.

  6. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Additional recovery-experiment data point (negative result):

    Remote ShowWindow re-layout does NOT recover the freeze; session lock/unlock does.

    During the ongoing third episode (notifications off, ~10:50–11:30 local), while the desktop was frozen, I executed a remote repair from an external process against the OpenCode main window:

    ShowWindow(hwnd, SW_MINIMIZE)  -> succeeded
    ShowWindow(hwnd, SW_RESTORE)   -> succeeded
    ShowWindow(hwnd, SW_MAXIMIZE)  -> succeeded
    

    All three calls succeeded at the Win32 level (no error, window re-laid out). At that moment the main window's DWM rect read as the correct physical-coordinate fullscreen rect (-128,-1440)-(3312,0) (3440x1440 on the secondary monitor), not the frozen signature rect (-112,-1162)-(2661,11).

    Result: mouse input to other applications remained swallowed. The freeze only cleared after the user locked the workstation and logged back in.

    Implications:

    1. The wedge is not (only) stale window bounds — re-asserting placement via ShowWindow while frozen does not restore input routing. Either the hit-test/foreground wedge lives deeper (DWM / input routing), or the app must re-process an actual display/session transition to reset its internal state.
    2. This narrows the fix: suggestion feat: compact and other improvements #1 from my earlier comment (re-assert bounds on WM_DPICHANGED/WM_DISPLAYCHANGE) may not be sufficient on its own — whatever state wedges WindowFromPoint() hit-testing and GetForegroundWindow() survives a full ShowWindow cycle.
    3. Updated recovery matrix:
    Action Result
    Remote ShowWindow minimize/restore/maximize No effect (new)
    Lock screen → log back in Always recovers
    Kill OpenCode.exe Always recovers
    Win+Ctrl+Shift+B Recovers, fastest

    Watcher is still running; I'll keep posting signatures as episodes occur.

  7. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    One more fine-grained symptom observation from the third episode, which further narrows where the input wedge lives:

    During the freeze: mouse wheel scrolling still worked on the other, visible-but-unclickable windows (e.g. Chrome, Explorer content scrolled normally), while mouse clicks and text selection were completely swallowed.

    This splits the input routing into two paths with different behavior:

    Input path Mechanism State during freeze
    Mouse clicks / selection hit-test based (WindowFromPoint → WM_NCHITTEST → WM_LBUTTONDOWN) Dead — swallowed by the invisible Chrome_WidgetWin_1
    Mouse wheel (WM_MOUSEWHEEL) routed to the window under the cursor / focus window, does not require foreground Alive — passes through to the visible windows behind
    Foreground routing GetForegroundWindow() Wedged (NULL during total freeze)

    So the invisible window intercepts the hit-test path (clicks) but wheel messages still reach the underlying windows. That means the wedge is not a wholesale message-queue failure — it is specific to the hit-test/click path, consistent with an invisible-but-hit-testable window sitting on top, while queued/routed messages (wheel) bypass it.

    One caveat I can't confirm: the wheel may have been reaching the underlying windows via per-monitor cursor routing ("scroll inactive windows") rather than focus routing, since GetForegroundWindow() was NULL part of the time. Either way, the clicks-vs-wheel asymmetry seems like a strong fingerprint for whoever debugs the hit-test layer.

    Next episode I'll also test the keyboard path (Alt+Tab, typing) to complete the matrix. Watcher keeps running.

  8. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Keyboard-path results from the latest episode, completing the input matrix:

    • Alt+Tab works (task switcher appears; per an earlier capture the foreground during a freeze even showed XamlExplorerHostIslandWindow '任务切换' while clicks were still eaten)
    • Win+L works — which also explains why lock screen → log back in reliably clears the state

    Updated input-path matrix during a freeze:

    Input path Mechanism State
    Mouse clicks / selection / hover targets hit-test (WindowFromPoint → WM_NCHITTEST) Dead
    Mouse wheel (WM_MOUSEWHEEL) routed/queued, no hit-test Alive (reaches underlying windows)
    Keyboard shortcuts (Alt+Tab, Win+L) system key routing Alive
    Typing into OpenCode itself focus routing Alive

    Everything except the hit-test path stays functional. The whole wedge is confined to WindowFromPoint-based hit-testing — i.e. there is an invisible but hit-testable top-level window (OpenCode's Chrome_WidgetWin_1 with the stale DPI-virtualized rect (-112,-1162)-(2661,11), documented earlier) that captures pointer-button routing while all queued/routed input (wheel, keys) continues to work.

    Not tested yet (will try next episode): right-click and middle-click (predicted dead, same hit-test path).

  9. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Two new observations from the latest episodes that significantly refine the mechanism:

    1. The wedge is spatially partial — consistent with an overlapping invisible window, not a global input failure.

    In one episode, Windows Explorer's left navigation pane remained clickable while the right file pane was dead (wheel worked everywhere, clicks/selection dead on the covered area). This matches the frozen rect documented earlier: (-112,-1162)-(2661,11) covers only part of the desktop — clicks die exactly where the invisible Chrome_WidgetWin_1 overlaps, and work elsewhere.

    2. Opening a right-click context menu sometimes CLEARS the wedge.

    In the episode above, right-clicking the (still clickable) nav pane popped a context menu — and after the menu was dismissed, the previously dead area became clickable again. No lock screen needed.

    Recovery methods now:

    Action Result
    Right-click context menu somewhere clickable Sometimes recovers (new)
    Remote ShowWindow minimize/restore/maximize No effect
    Lock screen → log back in Always recovers
    Kill OpenCode.exe Always recovers
    Win+Ctrl+Shift+B Recovers, fastest

    Refined hypothesis: stuck mouse capture. A context menu runs a modal menu loop that seizes mouse capture (SetCapture / SetForegroundWindow internals) and then releases it properly on dismissal. If the invisible OpenCode window was holding a stuck capture (or a stale capture/hit-test state after the DPI-transition re-layout), the menu loop forcibly breaks that state. This also fits the earlier observation that a full ShowWindow re-layout does not clear the wedge (capture state is independent of placement), while events that reset capture/foreground (menu loop, session lock) do.

    Next episode I'll query GetGUIThreadInfo() from an external process during the freeze to check hwndCapture — if it points at the invisible OpenCode window, the capture hypothesis is confirmed, and posting WM_CANCELMODE to that window should be a targeted remote fix.

  10. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Update: the bug reproduces with the main window on the PRIMARY (200%) monitor — the 125% secondary is not a necessary condition.

    Experiment performed: moved OpenCode's main window from the secondary monitor to the primary (200%, 3120x2080). Shortly after, a new episode occurred (user working in Outlook on the primary screen: clicks/selection dead in part of the window, wheel fine; a few right-clicks popping context menus restored clicking again — the context-menu recovery reproduced a second time).

    Watcher capture during the episode (all rects below are DWM physical-pixel rects read from an external process):

    12:00:08  TOP under cursor: class=Chrome_WidgetWin_1 proc=OpenCode
              rect=(-7,-7)-(1566,998)          <- STALE: primary monitor LOGICAL bounds
                                                  (1560x992 = 3120x1984 / 2) + border padding
              FG: ShellExperienceHost '新通知'
    12:01:52  TOP under cursor: same OpenCode window, same stale rect
              FG: XLMAIN proc=EXCEL rect=(-109,-1159)-(2657,7)   <- Excel on the secondary monitor,
                                                                     rect correct/unchanged
    

    Healthy state of the same window (captured minutes earlier): rect=(0,0)-(3120,1984) = full primary workarea in physical pixels.

    So during this episode the window was laid out at 50% of its correct size — the 200% monitor's DPI-virtualized logical coordinates used as physical pixels — same defect shape as the earlier secondary-monitor episodes (there the factor was 1.25), while windows of other processes were unaffected. The "glass" only covered part of the primary screen, which again matches the spatially-partial click dead zones the user experiences.

    Consequences for the reproduction recipe:

    • Monitor choice (secondary 125% vs primary 200%) is not the necessary condition.
    • The common denominator across all episodes: mixed-DPI multi-monitor setup + a display-state transition (lock/unlock, monitor wake, and possibly the cross-DPI move itself — this episode began right after dragging the window from the 125% monitor to the 200% monitor, which fires WM_DPICHANGED; the watcher also briefly saw the old stale secondary-monitor rect during the move window, suggesting the bad re-layout can trigger on the DPI change of a cross-monitor move alone, no lock/unlock required).
    • Trigger candidates now: lock/unlock, monitor sleep/wake, and cross-DPI window moves. All are WM_DPICHANGED/WM_DISPLAYCHANGE class events.

    Context-menu recovery has now worked twice (Explorer nav pane, Outlook). Still pending: GetGUIThreadInfo capture dump + WM_CANCELMODE targeted fix during an active freeze (script ready, waiting for the next episode).

  11. ouc3www commented on Oct 26, 2026

    @ouc3www
    Author

    Correction to my previous comment (the "stale 50% layout on the primary" claim): that inference was a measurement artifact. Comparing rects across two processes with different DPI-awareness mixes coordinate frames — in the watcher's (virtualized) frame, a healthy maximized-on-primary window reads exactly (-7,-7)-(1566,998) (verified against another app's window). So episode 4's rect was not demonstrably stale; what remains solid is the symptom: clicks dead in parts of the primary screen while the top window under the cursor was OpenCode's main window, wheel/keyboard fine, right-click menus recovering it.

    Meanwhile, a window enumeration during a healthy period surfaced two relevant facts:

    1. OpenCode has only one visible top-level window (Chrome_WidgetWin_1); there is no separate permanent overlay window in the process. (Several SoBS_* Sogou-IME windows also live in the process but are HIDDEN — the IME is ruled out, consistent with earlier findings.)
    2. The shell (explorer.exe) keeps a LockScreenInputOcclusionFrame ("Input Occlusion Window") — TOPMOST, visible, covering the entire secondary monitor — even in a healthy, unlocked state. WindowFromPoint on secondary-screen points returns this window, not the app windows below it. Presumably it normally passes input through (returns HTTRANSPARENT), but its presence right after lock/unlock episodes makes it a suspect worth ruling in or out.

    Current leading hypothesis: DWM cloaking. To explain "an invisible window that still hit-tests and eats clicks, while the visible windows below it receive wheel/keyboard": a window that is cloaked (DWM stops rendering it but it stays marked visible, keeps its z-order, and remains hit-testable) fits every observed symptom. Electron/Chromium cloaks windows for occlusion/power-saving tracking, and the episodes all follow DPI/display transitions — exactly where occlusion detection could mis-fire. A cloaked OpenCode window sitting maximized (last-foreground z-order) over a monitor = the invisible glass.

    To test this, the watcher now records DWMWA_CLOAKED for every sampled window (TOP and FG) every 2 s. The next freeze should show either CLOAKED≠0 on the OpenCode window, or implicate the shell occlusion window, or rule both out. Will report with data.

  12. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for all the detailed captures and experiments. They narrow this down a lot.

    I couldn't reproduce this here: it needs the Windows desktop app on two real monitors at different scales, and the automated environment I run in can't provide that. A maintainer with a similar setup will need to look at it.

    What they'll try, based on your comments:

    • OpenCode Desktop 2.1.4 on Windows 11, with a 200% primary monitor and a 125% secondary monitor arranged above it (negative Y), and the main window maximized.
    • Lock and unlock, monitor sleep and wake, and dragging the window between the two monitors.
    • Checking whether clicks on other apps get swallowed where OpenCode's window overlaps them, while the mouse wheel and keyboard keep working.

    If your watcher catches another episode, the DWMWA_CLOAKED and GetGUIThreadInfo (hwndCapture) data you mentioned would be very useful to post here. So would a note on whether a cross-monitor drag alone, with no lock/unlock, is enough to trigger it.

  13. ouc3www commented on Oct 28, 2026

    @ouc3www
    Author

    Update: still reproduces on 2.2.0 (released after 2.1.4). Upgraded this morning; OpenCode.exe FileVersion = 2.2.0.0 — and an episode occurred ~20 min later on the new version:

    09:35:17-19  TOP under cursor: Chrome_WidgetWin_1 proc=OpenCode (pid started today, v2.2.0)
                 DWM rect=(-128,-1440)-(3312,0)   <- physically covering the ENTIRE secondary
                                                     monitor (3440x1440 @ 125%, negative Y)
                                                     while visibly not rendered at all
                 FG (user's actual app): WeLinkPC / Explorer / Outlook
    

    The frozen rect signature is identical to the 2.1.4 episodes (same monitor geometry, same border padding) — so whatever computes this bad re-layout is unchanged in 2.2.0.

    New live diagnostic from this episode (ran GetGUIThreadInfo from an external process while the wedge was active):

    FG-THREAD active:  hwnd=<OpenCode glass window> class=Chrome_WidgetWin_1
                       rect=(-128,-1440)-(3312,0)    <- physical, full secondary monitor
    FG-THREAD capture: (none)
    FG-THREAD focus:   hwnd=<same OpenCode glass window>
    All 11 GUI threads of OpenCode: no capture held
    

    Two conclusions:

    1. Capture hypothesis refuted (my own earlier hypothesis): during the wedge, no thread holds mouse capture. The invisible window doesn't hold a stuck capture — it is simply hit-testable and on top.
    2. The invisible window is the foreground thread's ACTIVE window while the user believes they are working in another app. So during the wedge, the glass window isn't just overlapping the monitor — it has foreground/active status, which explains why clicks land in it. (Keyboard still reaching the other app is consistent with focus living in a different window/thread than "active".)

    DWMWA_CLOAKED read 0 when I queried it ~1 min after the episode (timing caveat: possibly after the wedge self-resolved, so cloak is not yet ruled out — the dedicated CLOAKED watcher sampled too coarsely and missed this episode; I'm tightening it).

    Also relevant for the maintainer trying to reproduce: episodes continued across an app process restart with the identical rect — the frozen rect is a deterministic function of the monitor geometry (secondary 3440x1440@125% at negative Y), not of process state. And it reproduces on the primary 200% monitor too (previous comment).

    Continuing to watch on 2.2.0; will post DWMWA_CLOAKED from the improved watcher on the next episode.

  14. Hona commented on Oct 30, 2026

    @Hona
    Member

    Thanks for the detailed captures. Your 2.2.0 data changes the picture: the window keeps its correct maximized rect (-128,-1440)-(3312,0) but is not drawn, while it still takes clicks. OpenCode only creates a standard frameless Electron window, so the next step is to find which layer breaks: Electron's frameless window, Chromium in general, or Windows.

    Could you run these three windows on the same setup, one at a time? For each one, maximize it on the 125% monitor, run the watcher, and lock/unlock and sleep/wake the monitors as usual.

    1. Minimal Electron repro, frameless (same frame as OpenCode): https://gist.github.com/Hona/3fada661ce6ede8aaa561102c08acc11
      • Electron Fiddle: File › Load Fiddle from Gist, select Electron 44.9.1 (the version OpenCode ships), and run it.
      • Or with Node: clone the gist and run npx [email protected] . in that folder.
      • It opens a maximized magenta window titled repro-59229 on the first non-primary display.
    2. Same repro with a standard Windows frame: set FRAMELESS = false in main.js, or run npx [email protected] . --framed.
    3. Google Chrome: open this URL in a new Chrome window and maximize that window on the 125% monitor:
      data:text/html,<title>repro-59229</title><body style="background:%23f0f">
      

    Watcher: https://gist.github.com/Hona/d21d6d622bc2bba77d5a873229641cdf

    powershell -ExecutionPolicy Bypass -File glass-watch.ps1
    • It finds the window whose title starts with repro-59229 and checks four points inside it every 250 ms, in physical pixels.
    • A point where WindowFromPoint returns the window but the screen pixel is not magenta is logged as GLASS. It also logs the rect, DWMWA_CLOAKED, DPI, monitor handle and foreground state.
    • Output goes to glass-watch.jsonl next to the script.

    Results that would help most:

    Window GLASS seen? First GLASS line
    1. Electron, frameless
    2. Electron, framed
    3. Chrome

    Please also include the output of:

    Get-CimInstance Win32_VideoController | Select-Object Name, DriverVersion
    • Only window 1 breaks: the bug is in Electron's frameless window code.
    • Windows 1 and 2 break, Chrome does not: most likely Electron.
    • Chrome breaks too: Chromium or Windows. We will take it to Chromium with this repro.
  15. ouc3www commented on Oct 30, 2026

    @ouc3www
    Author

    Repro harness is running on the exact setup. Status update:

    Setup (all on Windows 11, primary 3120x2080 @ 200% at (0,0), secondary 3440x1440 @ 125% at negative Y):

    • Window 1 (frameless + WCO, Electron 44.9.1, from the gist): running since 09:10, maximized on the secondary monitor. Confirmed the physical frame rect is (-128,-1440)-(3312,0) — pixel-identical to the OpenCode glass-window rects we captured during real episodes, so the repro geometry matches the bug exactly.
    • Your glass-watch.ps1 runs at 250 ms; OpenCode-side watchers (DWMWA_CLOAKED + rect sampling) continue in parallel.

    Trigger cycles attempted so far (all negative):

    Cycle Result
    Lock → unlock x1 window stayed drawn (glass=false), clicks normal
    Monitor power off 30 s → wake x1 window stayed drawn, clicks normal

    The only GLASS lines logged are lock-screen/screen-off cover (black/lock-screen pixels over the window for < 2 s, recovering immediately) — expected, not the bug. DWMWA_CLOAKED stayed 0 throughout.

    Also of note: since upgrading the real app to 2.2.0 the user reports episodes have become noticeably rarer (though at least one episode did occur on 2.2.0, documented above). So the trigger is strongly intermittent — short forced cycles may simply not hit it.

    GPU: Intel(R) Arc(TM) Graphics, driver 31.0.101.5382 (2024-03-27) — single GPU, both monitors on it.

    Plan: keep the frameless repro window maximized on the 125% monitor during normal work (with the watcher), repeat lock/unlock + sleep/wake cycles over the coming days, and run windows 2 (framed) and 3 (Chrome) for comparable exposure. I'll post the matrix as soon as any cell produces data — positive or after meaningful exposure. If you'd rather we prioritize a specific window, say the word.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions