Skip to content

Fix window sizing and maximize on Linux (minHeight exceeds 768px displays) - #406

Open
Jonny-O wants to merge 1 commit into
OpenBuilds:masterfrom
Jonny-O:linux-window-management
Open

Fix window sizing and maximize on Linux (minHeight exceeds 768px displays)#406
Jonny-O wants to merge 1 commit into
OpenBuilds:masterfrom
Jonny-O:linux-window-management

Conversation

@Jonny-O

@Jonny-O Jonny-O commented Aug 11, 2026

Copy link
Copy Markdown

The bug

On Ubuntu 26.04 the CONTROL window cannot be resized to fit the screen and does not maximize correctly.

The cause is not Wayland, and it is not the frameless window — those were my first two guesses and measurement disproved both. It is minHeight: 850 in createJogWindow(), against a display that is 768px tall.

The window's minimum height is 82px taller than the entire screen. That makes both symptoms unavoidable: the window cannot be shrunk to fit, and maximize is an unsatisfiable constraint against a 736px work area. Upstream's own comment sits directly above the line:

// 1366 * 768 == minimum to cater for
height: 850,
minHeight: 850,

768px-tall panels are common on the small industrial displays people bolt to a machine. The one I tested against is a Dell W1700 at 1280x768.

Changes

The fix:

  • Lower window minimums from 1000x850 to 800x600.
  • Clamp the initial window size to screen.getPrimaryDisplay().workAreaSize, so it opens at a size that fits.

Linux window decorations — upstream creates a frameless window and draws its own titlebar. A frameless window gets no compositor resize edges under Wayland and does not reliably report maximized state, so on Linux the window manager now draws the titlebar and owns maximize, resize, snapping and tiling. This is gated on process.platform === 'linux'; Windows and macOS keep the existing custom titlebar and are behaviourally unchanged.

Consequences of that, all Linux-only:

  • The in-page titlebar is hidden, before first paint in index.html so no duplicate titlebar flashes on launch, and via a new status.driver.nativeframe flag in websocket.js for the socket path.
  • F11 is bound to toggle fullscreen, since hiding the in-page titlebar removes the only fullscreen control. It was not previously bound anywhere in keyboard.js.
  • Maximized state is tracked from the maximize/unmaximize events rather than isMaximized(), which is not dependable under Wayland.

Two bugs found along the way, both platform-independent:

  • The close handler returned false to cancel the close. That does not work in Electron — it needs event.preventDefault(). Close-to-tray was broken everywhere, not just on Linux.
  • status.driver.operatingsystem was only set inside an argv.length >= 2 check, so it was never set on Linux at all, and not set on Windows when launched without arguments.

Window is now shown from ready-to-show rather than immediately, so an unpainted frame is never put on screen first. There is a 10s fallback timer behind this: if ready-to-show never fires the window is shown anyway, so a failed load cannot leave it permanently invisible. This matters because GNOME hides Electron tray icons without an AppIndicator extension, so there would be no way to recover it. I simulated both paths and confirmed the window becomes visible exactly once in each.

Verification

Measured on the target hardware with xprop, stock 1.0.390 vs. this branch. Ubuntu 26.04, GNOME 50.1, Wayland, 1280x768 display.

stock this branch
WM_NORMAL_HINTS min 1000 x 850 800 x 600
_MOTIF_WM_HINTS decorations 0x0 (none) 0x1 (all)
_NET_FRAME_EXTENTS not present 0, 0, 37, 0
geometry on open 1000x850 @ y=32, 114px off-screen 1000x699 @ y=69, fits

Functional tests via _NET_WM_STATE client messages:

action result
resize to 1000x700 1000x699 pass
resize to 900x500 900x600, clamped at the new minimum pass
maximize 1366x699 pass
unmaximize 900x600 pass

DOM state confirmed over CDP: {titlebarExists: true, computed: "none", visible: false, platform: "linux", bodyH: 699} — the in-page titlebar is present but hidden, not removed, so nothing that queries it breaks.

Note for maintainers

The README section and the notices at the top of the three changed source files are fork bookkeeping — GPL-3.0 §5(a) requires me to mark modified files with a date when I distribute them. They are not meaningful in this repository and should be dropped if you merge this. The functional change is entirely in index.js, plus the two small titlebar-hiding hunks in app/index.html and app/js/websocket.js.

LICENSE and package.json are deliberately untouched. There is a discrepancy between them — LICENSE is GPL-3.0, package.json declares AGPL-3.0, both since the first commit — which I have documented rather than guessed at, since resolving it is yours to do and not mine.

The window could not be resized to fit the screen or maximized on
Ubuntu 26.04. Measured on the target hardware, the cause was
minHeight: 850 against a 768px-tall display - the window's minimum
was 82px taller than the screen, so shrinking it to fit was
impossible and maximize was an unsatisfiable constraint. Upstream's
own comment "1366 * 768 == minimum to cater for" sits directly above
that line.

  - Lower window minimums from 1000x850 to 800x600.
  - Clamp the initial window size to the available work area.
  - Use native window decorations on Linux, so the window manager owns
    maximize, resize, snapping and tiling. A frameless window gets no
    compositor resize edges under Wayland. Windows and macOS keep the
    custom titlebar.
  - Hide the in-page titlebar on Linux, before first paint in
    index.html so no duplicate titlebar flashes on launch, and via the
    new status.driver.nativeframe flag in websocket.js.
  - Bind F11 to toggle fullscreen, since hiding the in-page titlebar
    removes the only fullscreen control.
  - Track maximized state from window events instead of isMaximized(),
    which is not dependable under Wayland.
  - Show the window from ready-to-show, with a 10s fallback timer, so
    an unpainted frame is never put on screen first.
  - Use event.preventDefault() in the close handler; returning false
    does not cancel an Electron close, so close-to-tray was broken.
  - Report status.driver.operatingsystem correctly on Linux and on
    an argument-less Windows launch.

Verified on Ubuntu 26.04 (GNOME 50, Wayland) against a 1280x768
display. WM_NORMAL_HINTS min goes 1000x850 -> 800x600, the window
opens at 1000x699 fully on screen instead of 1000x850 hanging 114px
off the bottom, and maximize/unmaximize/resize all behave.

Add GPL-3.0 section 5(a) modification notices to the three changed
source files, and a README section documenting the fork and the
GPL/AGPL discrepancy inherited from upstream. LICENSE and
package.json are deliberately unmodified.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant