* Address PR 242 follow-ups for titlebar and browser background
* Restore titlebar border per follow-up scope
* Refresh browser under-page color with Ghostty opacity
* Browser: theme blank page fallback for about:blank
* Browser: keep new tabs webview-less until first nav
* Remove border below titlebar
Remove the 1px separator line overlay at the bottom of the custom
titlebar and its associated fakeTitlebarSeparatorColor computed property.
* Remove tab hover background in bonsplit
Update bonsplit submodule to remove the background fill on hovered
non-selected tabs.
* Restore titlebar border with system separator color, hover bg on all tabs, browser theme bg
- Add back 1px bottom border on titlebar using NSColor.separatorColor
(matches bonsplit tab separator color)
- Tab hover background now applies to all tabs including the selected one
- Browser address bar and under-page background now use Ghostty theme
background color instead of window background
* Fix file drag-and-drop and file input in browser panel (#194)
Two fixes for the browser panel:
1. File drag-and-drop from Finder: CmuxWebView previously suppressed ALL
drag type registration as a no-op to prevent bonsplit tab drags from
being intercepted. Now it selectively filters out only the text-based
types that conflict with bonsplit (public.text, public.utf8-plain-text,
public.plain-text) and the custom tab transfer types, while allowing
file URL types through so Finder drops work.
2. File <input> elements: Added the WKUIDelegate runOpenPanelWith method
to BrowserUIDelegate so clicking a file input opens the native macOS
file picker (NSOpenPanel), with support for multiple selection and
directory picking as specified by the HTML element.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(claude-opus-4-6): take a look at https://github.com/manaflow-ai/cmux/issues...
* ok
* wok
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds a configurable host allowlist in Settings > Browser that controls
which terminal links open in the cmux embedded browser vs the system
default browser. Supports exact match and wildcard prefix patterns
(e.g. localhost, 127.0.0.1, *.localtest.me). Empty list preserves
existing behavior of opening all web links in cmux.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Sidebar ports on own line, wider sidebar, CMUX_PORT env vars
- Move listening ports to dedicated sidebar row (removed from branch/directory line)
- Allow sidebar to resize up to 2/3 of screen width (was capped at 360px)
- Add CMUX_PORT, CMUX_PORT_END, CMUX_PORT_RANGE env vars per workspace
- Each workspace gets a dedicated port range (default: base 9100, range 10)
- Add settings UI for port base and range size
- Add portOrdinal to Workspace, monotonic counter in TabManager
Closes#129
* Make port ordinal counter static to avoid overlap across windows
Each window creates its own TabManager, so a per-instance counter
would reset and reuse port ranges. Making it static ensures unique
ranges across all windows.
* Fix portOrdinal race: pass through Workspace init instead of setting after
The first TerminalPanel is created inside Workspace.init, so setting
portOrdinal after init returns meant the initial terminal always got
ordinal 0. Pass portOrdinal as an init parameter and set it before
the TerminalPanel is created.
* Fix P2/P3: snapshot port settings at surface creation, use window screen for sidebar cap
P2: Port base/range are now snapshotted on TerminalSurface when the
panel is created, so changing settings mid-session won't cause
inconsistent CMUX_PORT values across terminals in the same workspace.
P3: Sidebar max width now uses NSApp.keyWindow?.screen instead of
NSScreen.main, so multi-monitor setups get the correct 2/3 cap for
the display the window is actually on.
* Fix P1: snapshot port base/range once per app session, not per panel
Port base and range size are now static properties on TerminalSurface,
initialized once from UserDefaults at first access. This prevents
overlapping port ranges across workspaces when settings are changed
mid-session (e.g., workspace 1 with range=10 at 9110-9119, then
range changed to 5, workspace 2 would overlap at 9110).
Replace @ObservedObject notificationStore in TerminalPanelView and
PanelContentView with a plain `let hasUnreadNotification: Bool`.
The parent WorkspaceContentView already subscribes to the store
via @EnvironmentObject; it now computes the per-panel Bool and
passes it down, so child views only re-render when their own
notification state actually changes.
TerminalPanelView and PanelContentView held notificationStore as a
plain `let` property. Since it's a reference type (class), SwiftUI's
structural diffing saw no change when notifications were added and
skipped re-evaluating the view body. Changed to @ObservedObject var
so the views properly subscribe to the store's @Published changes.
Closes#126
Handle multi-button mouse events in the browser panel's WKWebView:
- Mouse back button (button 3) triggers goBack(), forward button
(button 4) triggers goForward(), enabling side-button navigation
on mice like Logitech
- Middle-click (button 2) on a link opens it in a new browser tab
by hit-testing the click position via JavaScript and routing through
the existing openLinkInNewTab mechanism
The browser omnibar's updateNSView and controlTextDidEndEditing
were both dispatching makeFirstResponder calls without any guard
against re-dispatch. Each makeFirstResponder triggers SwiftUI's
FirstResponderObserver, which re-evaluates the view graph, which
calls updateNSView again, creating an infinite loop via the main
dispatch queue.
Fix: Add a pendingFocusRequest flag on the coordinator to prevent
re-dispatching while a focus/blur request is already in flight.
Also add nsView.currentEditor() != nil to the isFirstResponder
check so the field is recognized as focused during the transition
when the field editor (not the field itself) is first responder.