#16125

Stop the bar's sections overprinting on a bar too short for them

OpenTripleU613wants to merge intofrom

The problem

One bar layout is drawn on every screen, and nothing holds its sections apart.

LeftModules is anchored to the bar's left edge, RightModules to its right, and the centered group — centerBegin, the center box, centerEnd — is placed in the middle and grows outward from there. Three independent placements, no shared budget. On a bar with room to spare that is fine. On one without, they are drawn on top of each other.

I hit this on a handheld with a 1280px internal panel beside a 5120px display. The same 25 widgets that sit comfortably on the wide bar need 1706px, so the narrow one overruns by 426px and the clock disappears under the window title and the widgets either side of it:

Nothing is misconfigured here — it is the same layout the wide screen renders correctly. Any laptop undocking from an external display, or any second screen smaller than the first, lands in the same place.

What this changes

The centered group is held within the room the edge sections leave. It stays centered while it fits there, so every bar with room to spare is placed exactly as it is today, and slides along that room instead of across a neighbour once it does not. The notch path already laid the group out non-centered; this reuses that idea rather than adding a second mechanism.

That stops the corruption, but it cannot invent room — a layout that needs 1706px on a 1280px bar still runs past the end.

So a widget entry may also carry minBarWidth: the shortest bar worth drawing it on, measured along the bar's run (its width on a top or bottom bar, its height on a left or right one).

{ "id": "omarchy.active-window", "minBarWidth": 1600 }

Bars shorter than that leave the widget off; every wider bar is untouched. It is opt-in, so a widget without it is never dropped. A widget left off a bar is never built there either — widgets load only once a slot holds them — so it costs that screen nothing in processes or timers.

The second image above is the same 25-widget layout with minBarWidth: 1600 on five text-heavy widgets.

The wide screen is unchanged

The point of the setting is that it changes nothing where there is room. Same layout, same session, before and after:

Verified rather than eyeballed — via debugBarGeometry, the five tagged widgets are drawn on exactly one bar and the other twenty on both, with no anomalies.

Tests

Both decisions are pure functions in BarModel and covered by test/shell.d/bar-overflow-test.sh (27 assertions): centering preserved while the group fits, sliding when it does not, the deterministic fallback when the group is wider than the room at all, unusable insets falling back to centering, and for the filter — opt-in behaviour, exact-match widths, malformed values ignored rather than hiding a widget, string entries, and an unmeasured bar filtering nothing. It also guards that the engine actually consults both, so the model cannot become dead code.

bar-notch-test.sh asserted that CenterModules ends immediately after drawn:. It now asserts that binding and allows the properties carrying the room through; the rest of the assertion is unchanged.

Run against this branch: every bar-* test plus clock-test passes. The graphical acceptance suite was not run — no disposable VM here.

A prerequisite fix

Dropping a widget from one bar made an existing latent bug easy to hit, so it is the first commit.

The weather panel deferred its refresh with Qt.callLater(), which holds no tie to the object that asked for it. A panel destroyed before the call ran left it firing into a dead context — attempted to evaluate a function in an invalid context, then a TypeError naming a function defined ten lines below. A Timer is a child of the panel and dies with it.

It is reachable today without any of this: unplug a monitor, or move the bar to another edge, with a location change in flight. I only found it because the filter destroys widgets more often.

Verification

Checked in the running shell, not just in tests, per agents/skills/visual-verification.md — both screens, bar on top and moved to the left edge and back twice, with and without the setting. No binding loops and no QML warnings beyond ones already present on an unmodified shell.

🤖 Generated with Claude Code

Activity

5
greptile-apps[bot]17h ago

Confidence Score: 5/5

[Medium impact] The PR appears safe to merge, with both earlier findings addressed and no new actionable issues found.

Summary

The PR keeps the centered bar group between the edge sections and adds per-screen widget filtering through minBarWidth.

  • The center group slides clear of edge widgets when space runs short.
  • Each bar can leave out widgets that need more room.
  • Weather refreshes now wait on a timer owned by the panel.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Configured widgets] --> B[Filter by bar length]
  B --> C[Shown widgets]
  D[Configured drop positions] --> E[Map gaps to shown widgets]
  C --> E
  E --> F[Draw slots and drag gaps]

Reviews (3) · Last reviewed commit: "Open a drag's gaps against the widgets a..." · Reviewed by Greptile

greptile-apps[bot]reviewed17h ago