Redesign top bar + sidebar, add settings (#5) - #62
Conversation
|
@am-will Apologies for the big PR, adding a top bar is opinionated design wise, considering you don't have one, but since I really felt the need for it, I added it as an optional UI part. So, for people who like the no top bar, they can keep the dock only, with slight improvements. There's also some other quality of life things like closing tabs with middle mouse button, making the pane bars drag the window also, some button designs, etc, so if you see anything you'd like me to separate into a different PR let me know. |
|
I will take a look when I can ty |
|
Hi @am-will, did you end up taking a look? |
|
My fault dude I got sick. I'll check later
…On Tue, May 5, 2026, 11:42 AM MVB.Mir ***@***.***> wrote:
*mvbmir* left a comment (am-will/limux#62)
<#62 (comment)>
Hi @am-will <https://github.com/am-will>, did you end up taking a look?
—
Reply to this email directly, view it on GitHub
<#62 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AKD57ZFEDUN6BQ2I62NDW6D4ZIRXDAVCNFSM6AAAAACX5DIATSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DGOBRGYZTAOJQGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
let me merge some other issues and i'll get to this. looks interesting for sure |
bvolpato
left a comment
There was a problem hiding this comment.
Great redesign and implementation quality. I ran local verification after fixing the missing ghostty dependency artifact (git submodule update --init --recursive ghostty and cd ghostty && zig build -Dapp-runtime=none -Doptimize=ReleaseFast), then reran gates: cargo test and cargo clippy --release -- -D warnings, both clean. Left 3 inline non-blocking suggestions for maintainability/resilience. Approving.
0202f70 to
dfdff7d
Compare
bvolpato
left a comment
There was a problem hiding this comment.
Strong UI direction. Config compatibility, centralized layout handling, indicator lifecycle, and settings rollback look solid.
Current head needs attention before merge:
split_tree.rs:463enables child shrinking, then immediately disables both flags. Saved ratios still lose against child minimums.split_tree.rs:503consumes size changes inposition-notify, preventing tick callback from reapplying ratio afterward. Resize-driven drift remains when GTK emits that notification.window.rs:1771leaves drag/drop controller on hidden sidebar button. Visible top-bar+has click handling only, breaking tab drag into new workspace and workspace drag-delete target.window.rs:1694always renders custom top bar, removing current Waylandxdg-decorationguard and causing stacked compositor/app chrome on affected desktops.
PR also conflicts with current main in config, settings, and window code. Rebase must retain newer interface-scale, terminal shortcut, browser lifecycle, session shutdown, and tab-rename fixes.
Latest GitHub quality check is green. Reviewed all five changed files; isolated Ghostty build passed. Full local gate was interrupted before completion.
Recommendation: COMMENT. Rebase and fix blockers before approval.
(Review assisted by gpt-5.6-sol)
48365a8 to
04b934e
Compare
bvolpato
left a comment
There was a problem hiding this comment.
Latest commits fix both split-ratio findings: child shrinking stays enabled and resize notifications no longer consume size changes before tick reapply. Two blockers remain:
window.rs:1766-1792attaches drag/drop only to hidden sidebarnew_ws_btn; visible top-bar+has click handling only, so tab-drop-to-new-workspace and workspace drag-delete lose their target- custom
WindowHandleheader is now unconditional, removing current main's Waylandzxdg_decoration_manager_v1guard and causing duplicate app/compositor chrome where server-side decorations exist
Branch also conflicts with newer unread-tab, tab-rename, Unicode-title, and tab-drop work. Please rebase and preserve those behaviors.
Quality check is green.
(assisted by gpt-5.6-sol)
Top bar: - Custom top bar at the top of the window with the sidebar toggle, settings cog, "+" new-workspace button, a row of workspace indicator pills, and the window controls (minimize/maximize/close). - macOS-style indicator pills: subtle hover/active backgrounds, pill shows a small dot + bold when the workspace has unread activity. - Empty header space drags the window via gtk::WindowHandle. - Custom buttons replace gtk::WindowControls so hover shape, padding, and border-radius match the pane action icons exactly. - Pane action icons (new terminal, split, close pane) reworked to the same compact visual language; tab close X the same. - Settings cog moved out of the per-pane action row into the top bar, freeing horizontal tab space. Pane header: - Empty space between the last tab and the action icons is a WindowHandle filler, so it drags the window without conflicting with the tabs' DragSource. - Middle-click on a tab closes it. Sidebar: - Cleaner workspace rows with a close X on the top-right (replaces the star's old position). The favorite star moved below next to the folder path; both are hover-to-reveal 20×20 buttons. - Double-click a row to inline-rename. - Row selection paints the inner row box with an accent-tinted background; Adwaita's default ListBox row styling is suppressed. - First-row top margin bumped so the gap above the first workspace matches the between-workspace gap. - Drops the "WORKSPACES" title and the big "+" button at the bottom. New-workspace behavior: - "+" clones the active workspace's folder instead of opening the folder picker. The picker only appears on first run / when no workspace exists. Settings (General tab): - Top bar (switch) — when off, removes the top bar entirely and relocates its buttons: dock toggle, settings cog, "+", and window controls move into a new sidebar header (with an hexpand spacer between the left group and the right group). When the sidebar is collapsed, the dock toggle parks on the active workspace's leading pane via a new `leading_box` slot on every pane; the rest of the controls stay hidden. - Window controls side (Left/Right) — moves minimize/maximize/close between the two ends of whichever header is active. Applies live. - Workspace indicators on the top bar (switch) — hides the per- workspace pills without hiding the top bar. Implementation hides each pill individually so `indicator_box` keeps its hexpand role between the left group and the window controls. - All three persist under `interface.*` in settings.json. Split ratio fix: - shrink_start_child / shrink_end_child on every Paned so the saved ratio wins over larger child minimums (e.g. wide tab strips). - position-notify tracks `last_size`; width-changed notifies are auto-adjusts (skip ratio update), same-width notifies are real user drags (update ratio). Without this, sidebar toggles and window resizes silently drifted the ratio because GtkPaned's position is absolute pixels. - Per-frame tick callback observes the paned's actual width and re- applies `position = ratio × new_width` on size changes. GtkWidget's width/height properties don't reliably emit notify across GTK 4.x versions, so polling is intentional; the check is O(1). - Startup uses a one-shot tick callback to apply the ratio once the paned first has a non-zero allocation. Structural: - Extracted handle_config_change() to dedupe appearance + top-bar side-effect + save/revert logic that ran from two config-change sites. - apply_top_bar_mode() is the single source of truth for how the dock toggle, settings cog, +, indicator pills, and window controls are laid out. Respects both the persistent `show_top_bar` setting and the transient keyboard toggle. - Dropped the unused on_config_changed field from PaneCallbacks; the pane no longer opens the Settings dialog. - Widget tree walkers (is_pane_widget, find_leaf_focused_pane) unwrap gtk::WindowHandle so the dock-parked-on-pane case still resolves panes correctly. Defaults: `show_top_bar = true`, `show_workspace_indicators = true`, `window_controls_side = Right`. Existing users without these fields in settings.json get the familiar layout. Closes #5 (notifications explicitly out of scope per the issue).
…, jitter probe - apply_top_bar_mode: group resolved widgets into TopBarWidgets and split the three layout branches into layout_top_bar_visible / layout_sidebar_header / layout_collapsed_dock helpers (behavior unchanged). - Collapsed-sidebar layout retries once on idle when the active workspace leading pane is momentarily unavailable during a rebuild, so the dock toggle no longer briefly disappears. - split_tree resize tick logs a debug-only line per ratio re-apply to surface any size oscillation on deep split trees; compiled out in release.
- split_tree: keep shrink_start/end_child enabled (the builder set them, then set_shrink_*_child(false) immediately undid it), so a saved 50/50 ratio is honored instead of losing to the wider pane's minimum width. - split_tree: stop position-notify from consuming width changes by writing last_size; only the tick callback updates it, so the tick still re-applies position = ratio * width after a resize instead of drifting.
…ls guard - The workspace drag-and-drop drop target (tab drag -> new workspace, workspace drag -> delete) lived only on the hidden sidebar '+' button, so it was unreachable while the top bar was shown. Extract install_workspace_dnd_target and wire it onto the visible top-bar '+' too. - Restore an xdg-decoration guard: on Wayland compositors that provide server-side decorations, hide the custom minimize/maximize/close so they don't stack on top of the compositor's window controls.
603e33d to
53bc197
Compare
|
@bvolpato rebased onto latest main and fixed all four blockers
retained the newer interface-scale / show-workspace-path / tab-rename / etc from main, ui_scale + path visibility now live-apply through mind taking another look when you get a sec? |
|
@bvolpato bumping, all 4 blockers fixed + rebased onto latest main, CI green, ready for another look when you get a sec |
|
Got any screenshots? |
bvolpato
left a comment
There was a problem hiding this comment.
The Aug 7 update fixes all four previous blockers: split shrink flags, resize-ratio handling, top-bar workspace DnD, and the decoration guard. Exact-head quality and GTK smoke checks pass. Two current P1s remain:
-
window.rs sync_top_bar_visibility() uses only transient top_bar_visible plus fullscreen state. It ignores config.interface.show_top_bar. With the Top bar setting disabled, leaving fullscreen can make the WindowHandle visible again without restoring its reparented controls, producing a blank or incorrect top bar. Include persisted visibility or rerun apply_top_bar_mode() on fullscreen transitions.
-
split_tree.rs persistent tick callback is owned by paned but captures paned.clone() as paned_for_resize. That creates a strong self-cycle and leaks every old GtkPaned after split-tree rebuilds. Use the callback paned argument at apply_ratio_value(), or capture a weak reference.
Nonblocking: the three new settings controls do not resync from the effective config after save failure, so widgets can display rejected values after state and layout roll back.
After these fixes, rebase or adapt the decoration path after #142 because both branches currently conflict in window.rs. Thanks for addressing the previous review thoroughly.
Summary
Implements the cmux-style top bar and sidebar redesign plus three related settings and the split-ratio fix. Single commit against
main.Top bar
Custom top bar at the top of the window: sidebar toggle, settings cog, "+" new-workspace button, a row of workspace indicator pills, and the window controls (minimize/maximize/close). Empty space drags the window via
gtk::WindowHandle. The window controls are plaingtk::Buttons rather thangtk::WindowControlsso their hover shape and sizing match the rest of the icons.Pane header
WindowHandlefiller — drags the window without conflicting with the tabs' DragSource.Sidebar
New-workspace UX
Settings → General (three new rows)
indicator_boxkeeps its hexpand spacer role.interface.*insettings.json. Defaults:show_top_bar = true,show_workspace_indicators = true,window_controls_side = Right— upgrading users see the familiar layout.Split ratio fix
shrink_start_child / shrink_end_childon everygtk::Panedso the saved ratio wins over larger child minimums (e.g. a wide tab strip).position-notifynow trackslast_size: width changed → auto-adjust (don't touch ratio); width unchanged → real user drag (update ratio). Fixes the silent 0.5 → 0.6 drift that happened when the sidebar toggled or the window resized —GtkPaned::positionis absolute pixels, so the old handler computed a different ratio each time the paned's width changed.position = ratio × new_widthon size changes.GtkWidget::width/heightdon't reliably emit notify across GTK 4.x versions, so polling is intentional; the check is O(1) with early return.Structural
handle_config_change()dedupes the appearance + top-bar side-effect + save/revert logic that ran from two config-change sites.apply_top_bar_mode()is the single source of truth for how the dock toggle, settings cog, +, indicator pills, and window controls are laid out — respects both the persistentshow_top_barsetting and the transient keyboard toggle.is_pane_widget,find_leaf_focused_pane) unwrapgtk::WindowHandleso the dock-parked-on-pane layout still resolves panes correctly.Closes #5 (notifications explicitly out of scope per the issue).
Notes for reviewers
add_tick_callbackpolling insplit_tree.rsis intentional. GTK 4.x doesn't reliably emit notify onwidth/height, so the signal-driven approach silently misses resize events; the tick loop catches them at the cost of one integer compare per frame.gtk::WindowControlsis replaced by three plaingtk::Buttons wired towindow.minimize()/maximize()/close(). Adwaita's default 24 px circular styling couldn't be cleanly overridden to match the other top-bar icons.Test plan
cargo fmtcleancargo clippy --release -- -D warningscleancargo test— all 181 unit tests pass