Skip to content

feat(layout): add maximize_to_edges option - #383

Open
AdityaKr015 wants to merge 8 commits into
noctalia-dev:mainfrom
AdityaKr015:feat/window-maximize-edge
Open

AdityaKr015 wants to merge 8 commits into
noctalia-dev:mainfrom
AdityaKr015:feat/window-maximize-edge

Conversation

@AdityaKr015

Copy link
Copy Markdown
Member

Summary

This PR adds [layout] maximize_to_edges (default false). When enabled, a client's own maximize request fills the usable area without struts, gaps, or borders instead of the full column width.

Motivation

Clicking an app's maximize button currently maximizes to full column width.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring
  • Build / packaging
  • Documentation only

Related Issue

Closes #227

Testing

  • ❯ just format && just test && just lint
  • Tested manually, native session with maximize_to_edges = true: Firefox's maximize button fills the screen edges with no gap or border, unmaximize restores the previous tile.

Manual Coverage>

  • Tested in a nested Umbriel session
  • Tested in a native Umbriel session
  • Tested with multiple monitors
  • Tested with a scaled output
  • Tested with native Wayland applications
  • Tested with X11 applications through Xwayland
  • Tested with the scrolling layout
  • Tested with the dwindle layout

Screenshots / Videos

Checklist

  • This PR is ready for review, or it is marked as Draft.
  • This change fits SCOPE.md, or its scope was agreed in an issue or on Discord first.
  • I read and followed the relevant guidance in CONTRIBUTING.md.
  • I ran just format, or this PR has no C++ changes.
  • I ran the relevant build, test, lint, or verification commands, or explained why they were not run.
  • I functionally verified compositor behavior where automated checks are insufficient.
  • I self-reviewed the changes.
  • I checked for new warnings or errors.
  • I updated docs/ and examples/config.toml, or this PR does not change user-facing configuration or behavior.
  • I used canonical names for config keys, IPC actions, paths, and identifiers.

@AdityaKr015
AdityaKr015 marked this pull request as ready for review October 4, 2026 09:49
@ItsLemmy

ItsLemmy commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Blocking: enabling the policy can make ordinary maximized windows impossible to unmaximize
through the client.

At src/view/view_state.cpp:214-216, maximize_to_edges = true routes both maximize and unmaximize requests to setMaximizedToEdges(). For a column-maximized window, m_maximizedToEdges is false, so setMaximizedToEdges(false) returns immediately at lines 228-229 without clearing column maximization.

Reproduced with a real Wayland client in an isolated headless compositor:

  • Client maximizes with the policy off, config reload enables it, then client unmaximizes.
  • Policy is enabled, window-toggle-maximize maximizes the window, then client unmaximizes.
  • Both honor_restored_maximize and this policy are enabled; a restored-maximized client then unmaximizes.

In each case, the window remained column-maximized at width 1200, rather than restoring to 588.

Proposed fix: apply the configured policy only to maximize requests. Route unmaximize requests according to the active maximize mode. Add transition coverage for these cases;
the boolean-helper tests currently miss them.

Nit: tests/unit/maximize.cpp:13 spells RequestsOnEdges as RequestsonEdges.

@ItsLemmy
ItsLemmy marked this pull request as draft October 7, 2026 02:39
@AdityaKr015
AdityaKr015 marked this pull request as ready for review October 7, 2026 14:42
@AdityaKr015

Copy link
Copy Markdown
Member Author
❯ just check-stress client_maximize_to_edges
check · /run/media/aditya/Study/GIT/umbriel/build-debug/umbriel
       · 32 of 32 checks, one compositor instance each, 32 at a time

  PASS layout_client_maximize_to_edges.001        6.73s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.002        6.32s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.003        6.79s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.004        6.54s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.005        6.51s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.006        6.06s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.007        6.72s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.008        6.79s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.009        6.67s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.010        6.50s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.011        6.87s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.012        6.55s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.013        5.78s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.014        6.74s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.015        5.71s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.016        6.87s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.017        6.74s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.018        6.88s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.019        6.50s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.020        6.90s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.021        6.30s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.022        6.47s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.023        6.26s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.024        5.91s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.025        6.82s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.026        6.10s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.027        6.44s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.028        6.72s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.029        6.78s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.030        6.63s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.031        6.48s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…
  PASS layout_client_maximize_to_edges.032        5.67s
       client maximize targets column width by default (1264x704), edges when configured (1280x720),…

  slowest: layout_client_maximize_to_edges.020 6.90s · layout_client_maximize_to_edges.018 6.88s · layout_client_maximize_to_edges.011 6.87s · layout_client_maximize_to_edges.016 6.87s · layout_client_maximize_to_edges.025 6.82s
  32 passed · 6.97s
aditya@adi-fedora /run/media/aditya/Study/GIT/umbriel (feat/window-maximize-edge)
❯

Can you tell if everything alright now?

@ItsLemmy

ItsLemmy commented Oct 7, 2026

Copy link
Copy Markdown
Member

Blocking: a restored maximize lands in a different state depending on client timing.

  • A client that restores maximize before or during map goes through
    view_lifecycle.cpp:375-377. That path calls setMaximized(true) and ignores the policy,
    so the window gets full column width.
  • A client that re-asserts after map, as Firefox does, is accepted at map
    (view_lifecycle.cpp:220). It then goes through handleRequestMaximize and lands in
    edges mode.
  • Throwaway probe with both options on (deleted afterwards):
  • docs/user/layout.md:374 says "Opening state is unaffected". The PR's own check
    (client_maximize_to_edges.sh:131-139) asserts the opposite for the after-map case.
  • Proposed fix, matching the check's stated intent that a restored maximize under the
    policy lands in edges:
    • At map, send restoredMaximized through setMaximizedToEdges(true) when the policy is
      on and the window is tiled. Leave default_maximize rules on setMaximized.
    • Include that case in wantMaximizeToEdges (view_lifecycle.cpp:821-828) so the first
      configure already has the edge size.
    • Change the docs sentence to match, and add a before-map restore case to the check.

Nit: docs say floating windows get the edges behavior, but the code only does it for
tiled windows. layout.md:370 says "a window's own maximize button behaves like
window-toggle-maximize-to-edges". The policy is only checked in the tiled branch
(view_state.cpp:213-220). Floating windows still go to setMaximized at line 221 and keep
their borders. Issue #227 is about tiled layouts, so the fix is to say "tiled window" in
the docs and in the examples/config.toml comment.

Nit: the key-table row is missing. maximize_to_edges was added to the TOML block at
layout.md:30, but there's no row for it in the key table at layout.md:33-37.

Nit: indentation. client_maximize_to_edges.sh:137: await_lines has two extra spaces of
indentation.

@ItsLemmy
ItsLemmy marked this pull request as draft October 7, 2026 21:56
@AdityaKr015
AdityaKr015 marked this pull request as ready for review October 10, 2026 13:07
@ItsLemmy

Copy link
Copy Markdown
Member

Blocking: a default_maximize window lands in a different state depending on client timing when honor_restored_maximize and maximize_to_edges are both on.

Throwaway harness probe (tiled 1280x720 output, default_maximize = true rule matching the client):

Client timing Configures sent Final
ruled, restores before map 1280x720 → 1264x704 1264x704 (column)
ruled, re-asserts after map (Firefox) 1264x704 → 1280x720 1280x720 (edges)
no rule, restores before map 1280x720 → 1280x720 1280x720 (edges)
  • Restore before map: the restore clause added to wantMaximizeToEdges at view_lifecycle.cpp:833-834 doesn't exclude the rule, so the first configure uses the edge size. At map, view_lifecycle.cpp:380 (!ruleMaximized) then calls setMaximized(true). The window opens at one size and is immediately resized to another.
  • Re-assert after map: view_state.cpp:214 sends the re-assert through the policy into edges mode. The same rule produces a different final state depending on client timing, and docs/user/layout.md:376 ("default_maximize rules are unaffected") is wrong for this case.

Proposed fix, pick one:

  • (a) The rule wins. Exclude !openingParented() && rule.defaultMaximize from the clause at line 834. Also stop handleRequestMaximize from escalating a maximize request on a tiled window that is already column-maximized. This keeps the docs sentence true.
  • (b) The restore follows the policy. Drop !ruleMaximized from the map-time condition, keep line 834 as it is, and reword the docs sentence. This is the smaller change and matches "a client's own maximize request follows the policy".

Either way, add a ruled before-map case and a ruled after-map case to client_maximize_to_edges.sh.

Nit: at view_lifecycle.cpp:383, requestedMaximized() is always true and m_maximizedToEdges is false at that point, so the helper call reduces to config().layout.maximizeToEdges. Using that directly would be easier to read.

@ItsLemmy
ItsLemmy marked this pull request as draft October 11, 2026 00:55
@AdityaKr015 AdityaKr015 added the talia-review Ask Talia for a preliminary AI review (removed once posted) label Oct 14, 2026
@AdityaKr015
AdityaKr015 marked this pull request as ready for review October 15, 2026 04:12

@talia-review talia-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Talia preliminary review

Check Result
Merge score 🟡 3/5 — Minor changes needed before merging
Findings 🟡 1 medium
Review depth 4/5 — how thoroughly the changed code could be checked by reading it
Coverage 12 of 12 changed files reviewed

What Talia checked: Read the changed helper and its only call site, both opening-state paths (handleMap/handleCommit), the config registry wiring, unit/harness expectations, and the rule paths that apply default_maximize; code paths are self-consistent, and the remaining defect is the added window-rules doc claim, which is unchecked at runtime.

Findings

# Severity Finding Location
1 🟡 P2 window-rules doc claims [layout] maximize_to_edges chooses a rule-opened window's mode docs/user/window-rules.md:63

Each finding is explained in a review comment on its line.

Run details
  • Commit reviewed: d7be0e2
  • Source lookups: 36 file reads, 28 searches
  • Prompt version: 859b7490ca3d

Preliminary automated review: Talia read the changed code and related source; nothing was built, run or tested, and AI can make mistakes. It is not a scope acceptance or a promise to merge; a human reviewer makes the final call. See our ethos.

Comment thread docs/user/window-rules.md Outdated
Later identity changes refresh only the settings that update while a window is
open.

This rule decides *that* a window opens maximized [`maximize_to_edges`](layout.md#maximize-and-fullscreen)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 P2 (medium) · window-rules doc claims [layout] maximize_to_edges chooses a rule-opened window's mode

The added sentence says `default_maximize` decides *that* a window opens maximized and `maximize_to_edges` decides *whether* that is the column or the edges. The implementation only consults `maximizeToEdges` for a window whose client itself requests/restores maximize: the edges branch in `src/view/view_lifecycle.cpp:378` requires `restoredMaximized`, and every rule-only path calls `setMaximized(true)` (column) (`src/view/view_lifecycle.cpp:381`, `:387` for `default_maximize_to_edges`, `src/view/view_rules.cpp:535`). The PR's own `docs/user/layout.md:378-379` says "A `default_maximize` window that never sees a client request still opens the column", so a user with only `default_maximize` rules and `maximize_to_edges = true` still gets the column, contradicting this sentence. Fix: state that the option governs the client's own/restored maximize request, and that a rule-only maximize stays on the column unless `default_maximize_to_edges` is set.

Talia preliminary review · maintainability

@talia-review talia-review Bot removed the talia-review Ask Talia for a preliminary AI review (removed once posted) label Oct 15, 2026
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.

[FEATURE] An option for windows to maximize to edges by default

2 participants