Skip to content

[Bug]: Window snapped to a display's edge reopens on the primary display; saved bounds 1px past the edge are discarded #21563

Closed as duplicate

Description

@jahands

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Related: #4841 (same symptom for a maximized window; the cause there is that mainWindowBounds holds the pre-maximize bounds). This window is not maximized.

Area

apps/desktop

Steps to reproduce

Displays: primary 1920x1280 at (0,0); secondary rotated portrait 1280x1920 at (1920,0).

  1. Snap the T3 Code window to the top half of the portrait display.
  2. Quit T3 Code and relaunch it.

Expected behavior

The window reopens on the top half of the portrait display, as other apps do (ChatGPT, for example).

Actual behavior

It opens at the default size on the primary display every time.

The snapped window is persisted as {"x":1921,"y":30,"width":1280,"height":945}, which extends 1px past the display's right edge (1921 + 1280 = 3201 > 3200). windowFitsWithinDisplay in apps/desktop/src/window/DesktopWindow.ts requires the bounds to lie entirely within one display, so resolveInitialMainWindowBounds discards them and logs saved main window bounds could not be restored; using defaults.

A second problem shows up when the main window is closed and re-created inside the same process: the saved bounds are {"x":1920,"y":30,"width":1280,"height":945}, which pass the check, but the next persisted bounds are {"x":640,"y":30,...}, centered horizontally on the primary display. The window still ends up on the primary display.

Impact

Minor bug or occasional failure

Version or commit

0.1.1-nightly.20261019.3348 (Electron 44.4.5)

Environment

macOS 26 (Darwin 25.5.0), Apple M4 Max, two BenQ displays at scale factor 2, one rotated 270°

Logs or stack traces

Exact lines from ~/.t3/userdata/logs/desktop.trace.ndjson.1, prefixed with their line numbers (rg -n). runId 731a412456ae is one app process; b9161434e657 is the next one after quitting and relaunching.

16786:{"type":"effect-span","name":"desktop.window.createWindow","traceId":"f2cd7b17b6db5b7448aa19725d206e30","spanId":"42f2d94c26985991","parentSpanId":"1f8a728726a69c1b","sampled":true,"kind":"internal","startTimeUnixNano":"1792391261825385750","endTimeUnixNano":"1792391261870378125","durationMs":44.992375,"attributes":{},"events":[{"name":"saved main window bounds could not be restored; using defaults","timeUnixNano":"1792391261826968500","attributes":{"scope":"desktop","runId":"731a412456ae","component":"desktop-window","effect.fiberId":189,"effect.logLevel":"WARN"}}],"links":[],"exit":{"_tag":"Success"}}
17937:{"type":"effect-span","name":"desktop.settings.setMainWindowBounds","traceId":"ad7d86289246174a7be314db4c75b265","spanId":"53952931287083a1","sampled":true,"kind":"internal","startTimeUnixNano":"1792391510280173875","endTimeUnixNano":"1792391510280317750","durationMs":0.143875,"attributes":{"x":1920,"y":30,"width":1280,"height":945,"isMaximized":false},"events":[],"links":[],"exit":{"_tag":"Success"}}
17945:{"type":"effect-span","name":"desktop.window.createWindow","traceId":"f2cd7b17b6db5b7448aa19725d206e30","spanId":"e2d87627a101f5e9","parentSpanId":"81484b4af8cbac92","sampled":true,"kind":"internal","startTimeUnixNano":"1792391512696948292","endTimeUnixNano":"1792391512709797792","durationMs":12.8495,"attributes":{},"events":[],"links":[],"exit":{"_tag":"Success"}}
17946:{"type":"effect-span","name":"desktop.window.createMain","traceId":"f2cd7b17b6db5b7448aa19725d206e30","spanId":"81484b4af8cbac92","parentSpanId":"5b19d2200ef23cea","sampled":true,"kind":"internal","startTimeUnixNano":"1792391512696927667","endTimeUnixNano":"1792391512709909667","durationMs":12.982,"attributes":{},"events":[{"name":"main window created","timeUnixNano":"1792391512709905292","attributes":{"scope":"desktop","runId":"731a412456ae","component":"desktop-window","effect.fiberId":1472,"effect.logLevel":"INFO"}}],"links":[],"exit":{"_tag":"Success"}}
18102:{"type":"effect-span","name":"desktop.settings.setMainWindowBounds","traceId":"4da9ca699931f60f88719a8db78629fa","spanId":"0b05685b82dc209c","sampled":true,"kind":"internal","startTimeUnixNano":"1792391513286035000","endTimeUnixNano":"1792391513286800542","durationMs":0.765542,"attributes":{"x":640,"y":30,"width":1280,"height":945,"isMaximized":false},"events":[],"links":[],"exit":{"_tag":"Success"}}
18181:{"type":"effect-span","name":"desktop.settings.setMainWindowBounds","traceId":"53c6d2c0a4110e63af5bd097fd4ff93c","spanId":"19151d651fd6f0df","sampled":true,"kind":"internal","startTimeUnixNano":"1792391516482122333","endTimeUnixNano":"1792391516482940833","durationMs":0.8185,"attributes":{"x":1921,"y":30,"width":1280,"height":945,"isMaximized":false},"events":[],"links":[],"exit":{"_tag":"Success"}}
18588:{"type":"effect-span","name":"desktop.window.createWindow","traceId":"7d9bdbe056394fc8e7dcbb416dba24c4","spanId":"7d80b9997a4799f7","parentSpanId":"1cd61c3eba37028d","sampled":true,"kind":"internal","startTimeUnixNano":"1792391578900951250","endTimeUnixNano":"1792391578945087166","durationMs":44.135916,"attributes":{},"events":[{"name":"saved main window bounds could not be restored; using defaults","timeUnixNano":"1792391578902404875","attributes":{"scope":"desktop","runId":"b9161434e657","component":"desktop-window","effect.fiberId":189,"effect.logLevel":"WARN"}}],"links":[],"exit":{"_tag":"Success"}}

Workaround

Drag the window back after each launch.

Activity

  1. juliusmarminge commented on Oct 19, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    The first part is confirmed on main and accepted as a bug. This is separate from #4841, which is about a maximized window saving its pre-maximize bounds.

    windowFitsWithinDisplay (DesktopWindow.ts:140-151) requires the saved bounds to sit entirely inside one display, with no tolerance. resolveInitialMainWindowBounds (DesktopWindow.ts:164-176) falls back to the default size when no display passes. A snapped window that ends 1px past the edge is therefore thrown away.

    The second part, a re-created window moving from x=1920 to x=640, is not explained by the app code. Bounds that pass the check go straight into the window constructor (DesktopWindow.ts:374-380), and nothing in DesktopWindow.ts or ElectronWindow.ts moves the window after that. It is not part of what is accepted here.

    Open #13125 changes the same functions. It checks against each display's work area instead of its full bounds, so it does not add any tolerance for this case.

  2. added
    acceptedfeature request accepted
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 19, 2026
  3. jahands commented on Oct 19, 2026

    @jahands
    ContributorAuthor

    @juliusmarminge Thanks. I replaced the log section in the issue body with the exact trace lines, with their line numbers and the file they came from (~/.t3/userdata/logs/desktop.trace.ndjson.1). The previous excerpt was a hand-written summary and named the wrong file.

  4. juliusmarminge commented on Nov 12, 2026

    @juliusmarminge
    Member

    This is the same problem as #28638, so I'm closing it in favour of that one. If it is different, say how and it will be reopened.

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

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions