Skip to content

fix(window): clamp restored window size to the work area - #4317

Open
jamesfredley wants to merge 2 commits into
marktext:developfrom
jamesfredley:fix/window-size-clamp
Open

jamesfredley wants to merge 2 commits into
marktext:developfrom
jamesfredley:fix/window-size-clamp

Conversation

@jamesfredley

@jamesfredley jamesfredley commented May 29, 2026 •

Copy link
Copy Markdown

Refs #2928, #1947

Summary

On high or fractional-DPI displays the editor window can open larger than the screen, spilling past the screen edges and covering the taskbar until it is manually maximized.

ensureWindowPosition already intends to clamp the restored window size to the screen (its comment reads "check whether window size is larger than screen size"), but that clamp only runs on the first-start path, when the saved x/y are undefined. For a returning user (saved coordinates present) the saved size is used unclamped. When the work area measured in DIP is smaller than the saved size, for example the default 1200x800 on a 4K panel at 337.5% scaling (work area ~1138x608), or after the window was last used on a larger display, the window opens bigger than the screen.

This makes the function restore the window safely on every launch:

  • It picks the display that contains the saved position, using half-open bounds ([x, x + width), [y, y + height)) so a point on a shared monitor edge is attributed to the correct neighbouring display. It falls back to the primary display on first start, or when the saved position is off every display.
  • It clamps the restored size to that display's work area.
  • It keeps the saved position but nudges it so the window stays fully within the work area; with no saved position the window is centered.

Type of change

  • Bug fix (non-breaking, fixes an issue)
  • New feature (non-breaking, adds functionality)
  • Breaking change (causes existing functionality to change)
  • Documentation update

Test plan

  • New unit tests added: packages/desktop/test/unit/specs/ensure-window-position.spec.ts covering the returning-user clamp, the first-start clamp, an already-fitting window left untouched, an off-screen saved position being centered, multi-monitor clamping against the correct display, half-open boundary selection at a shared edge, and an edge-overflow position nudge.
  • Manually tested on: Linux (Ubuntu). pnpm lint, pnpm typecheck, pnpm test:unit (558 passing), pnpm build, and pnpm test:e2e (73 passing) all green locally.

Notes for reviewers [optional]

  • Size and position are clamped against the work area of the display that contains the saved top-left corner, so multi-monitor setups with a larger secondary display keep their restored size, and a window is never restored partially off-screen or under the taskbar.
  • Display selection uses half-open bounds to avoid attributing a point on a shared monitor edge to the wrong display.

By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

ensureWindowPosition only clamped the restored window size to the screen
on first start (when the saved x/y are undefined). For returning users the
saved size was used unclamped, so when the display work area is smaller
than the saved size (for example after moving from a larger display, or a
display scale-factor change) the window opened larger than the screen and
covered the taskbar.

Clamp the size on every launch, against the work area of the display that
contains the saved position (falling back to the primary display on a
first run or an off-screen saved position) so a window restored on a
larger secondary monitor is not shrunk. Saved coordinates are left
unchanged.

Add unit tests for ensureWindowPosition covering the returning-user clamp,
the first-start clamp, an already-fitting window, an off-screen saved
position, and the multi-monitor cases.

Refs marktext#2928, marktext#1947
Copilot AI review requested due to automatic review settings May 29, 2026 19:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds robust window restore behavior so reopened windows never exceed the target display’s usable area (work area / bounds on Linux), and introduces unit tests to prevent regressions (incl. #2928).

Changes:

  • Update ensureWindowPosition to choose the appropriate display (saved-position display or primary) and clamp restored size against that display.
  • Center windows when no saved coordinates exist or when the saved position is off-screen.
  • Add Vitest unit coverage for clamping/centering behavior across single- and multi-display setups.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
packages/desktop/src/main/windows/utils.ts Selects a target display for restoration and clamps restored window size to that display’s work area/bounds.
packages/desktop/test/unit/specs/ensure-window-position.spec.ts Adds unit tests validating clamping and centering logic across common scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/desktop/src/main/windows/utils.ts
Comment thread packages/desktop/src/main/windows/utils.ts
Comment thread packages/desktop/test/unit/specs/ensure-window-position.spec.ts
…-screen

Address review feedback on the display selection and clamping:

- Locate the display that holds the saved position using half-open bounds
  ([x, x+width), [y, y+height)) so a point on a shared monitor edge is
  attributed to the neighbouring display instead of whichever display
  find() happens to return first.
- Keep the saved position but clamp it to the target display's work area, so
  a window saved near an edge is no longer restored partially off-screen or
  under the taskbar (previously only the size was clamped).
- Extend the unit tests with half-open boundary selection and edge-overflow
  nudge cases.
niyo-oyin added a commit to niyo-oyin/marktext-ja that referenced this pull request Jul 30, 2026
Upstream PRs applied (all diff-reviewed, tests included and passing):
- marktext#4776: preserve ordered-list source markers — opening and saving no
  longer rewrites 1./1./1. to 1./2./3. (marktext#4772, silent doc mutation)
- marktext#4788: UNC/WSL paths become valid file:// authority URLs
  (file://server/share/…, not file:////…) so network images load
  (marktext#4577, marktext#4563)
- marktext#4952: table columns size to content (min-width 10em → 2em, marktext#4894)
- marktext#4773: malformed percent-escape in a clicked link no longer throws an
  unhandled URIError (marktext#4749)
- marktext#4873: Shift+digit/punctuation keybindings recordable and matchable
  again (patch-package fix for @hfelix/electron-localshortcut, marktext#4863)
- marktext#4910: sidebar icons match by extension first, so Dockerfile-Notes.md
  gets the markdown icon (marktext#4890)
- marktext#4317: restored windows are clamped to the target display's work area
  (multi-monitor / DPI, marktext#2928, marktext#1947)

Found while integrating marktext#4776: cloneStateTree shallow-copied meta, so
array-valued fields (order-list sourceMarkers, table aligns) stayed
SHARED between a getState() clone and the live document — mutating a
returned tree corrupted the document. Meta arrays are now copied, and
the clone walks an explicit work list instead of recursing, so
pathological nesting (600-level lists, marktext#4747) can no longer overflow
the call stack (10k-depth regression test).

Also: folder search debounces its per-keystroke ripgrep run (300ms,
Enter searches immediately, IME-composing keys ignored) (marktext#3556), and a
new undoFloor spec pins that undoing past the opened baseline never
empties the document (marktext#5028 — legacy-engine bug, does not reproduce on
@muyajs/core).

muya 1536/1536, desktop 783/783, lint/tsc/madge clean. PLANS.md gains a
prioritized backlog from the full 563-item issue/PR survey.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants