detached 43b8409

fix: defer omnibox auto-open until GTK layout completes

commit
43b84097c708766f3ec5197dec8b35730b1262e7
author
brice · · 2026-01-26 04:40 UTC
parent
9cc8eee
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +35 -5
M internal/ui/app.go +2 -0
@@ -1698,6 +1698,8 @@ func (a *App) createWorkspaceViewWithoutAttach(ctx context.Context, tab *entity.
16981698 wsView.SetOmniboxConfig(a.omniboxCfg)
16991699 // Set find bar config for this workspace view
17001700 wsView.SetFindBarConfig(a.findBarCfg)
1701+ // Set auto-open omnibox on new pane
1702+ wsView.SetAutoOpenOnNewPane(config.Get().Omnibox.AutoOpenOnNewPane)
17011703
17021704 wsView.SetOnPaneFocused(func(paneID entity.PaneID) {
17031705 if a.keyboardHandler != nil && a.keyboardHandler.Mode() == input.ModeResize {
@@ -1698,6 +1698,8 @@ func (a *App) createWorkspaceViewWithoutAttach(ctx context.Context, tab *entity.
1698 wsView.SetOmniboxConfig(a.omniboxCfg)1698 wsView.SetOmniboxConfig(a.omniboxCfg)
1699 // Set find bar config for this workspace view1699 // Set find bar config for this workspace view
1700 wsView.SetFindBarConfig(a.findBarCfg)1700 wsView.SetFindBarConfig(a.findBarCfg)
1701+ // Set auto-open omnibox on new pane
1702+ wsView.SetAutoOpenOnNewPane(config.Get().Omnibox.AutoOpenOnNewPane)
1701 1703
1702 wsView.SetOnPaneFocused(func(paneID entity.PaneID) {1704 wsView.SetOnPaneFocused(func(paneID entity.PaneID) {
1703 if a.keyboardHandler != nil && a.keyboardHandler.Mode() == input.ModeResize {1705 if a.keyboardHandler != nil && a.keyboardHandler.Mode() == input.ModeResize {
M internal/ui/component/workspace_view.go +30 -0
@@ -11,6 +11,7 @@ import (
1111 "github.com/bnema/dumber/internal/domain/entity"
1212 "github.com/bnema/dumber/internal/logging"
1313 "github.com/bnema/dumber/internal/ui/layout"
14+ "github.com/jwijenbergh/puregotk/v4/glib"
1415 "github.com/rs/zerolog"
1516 )
1617
@@ -55,6 +56,9 @@ type WorkspaceView struct {
5556 // Prevents hover focus from overriding keyboard-initiated focus changes
5657 hoverSuppressedUntil time.Time
5758
59+ // Auto-open omnibox on new pane creation
60+ autoOpenOnNewPane bool
61+
5862 mu sync.RWMutex
5963 }
6064
@@ -547,6 +551,32 @@ func (wv *WorkspaceView) SetFindBarConfig(cfg FindBarConfig) {
547551 wv.findBarCfg = cfg
548552 }
549553
554+// SetAutoOpenOnNewPane configures whether to show omnibox when a new pane is created.
555+func (wv *WorkspaceView) SetAutoOpenOnNewPane(enabled bool) {
556+ wv.mu.Lock()
557+ defer wv.mu.Unlock()
558+ wv.autoOpenOnNewPane = enabled
559+}
560+
561+// NotifyNewPaneCreated handles new pane creation events.
562+// If auto-open is enabled, shows the omnibox after GTK layout completes.
563+func (wv *WorkspaceView) NotifyNewPaneCreated(ctx context.Context) {
564+ wv.mu.RLock()
565+ autoOpen := wv.autoOpenOnNewPane
566+ wv.mu.RUnlock()
567+
568+ if !autoOpen {
569+ return
570+ }
571+
572+ // Defer omnibox show until after GTK layout allocation completes
573+ cb := glib.SourceFunc(func(uintptr) bool {
574+ wv.ShowOmnibox(ctx, "")
575+ return false
576+ })
577+ glib.IdleAdd(&cb, 0)
578+}
579+
550580 // ShowOmnibox creates and shows the omnibox in the active pane.
551581 func (wv *WorkspaceView) ShowOmnibox(ctx context.Context, query string) {
552582 wv.mu.Lock()
@@ -11,6 +11,7 @@ import (
11 "github.com/bnema/dumber/internal/domain/entity"11 "github.com/bnema/dumber/internal/domain/entity"
12 "github.com/bnema/dumber/internal/logging"12 "github.com/bnema/dumber/internal/logging"
13 "github.com/bnema/dumber/internal/ui/layout"13 "github.com/bnema/dumber/internal/ui/layout"
14+ "github.com/jwijenbergh/puregotk/v4/glib"
14 "github.com/rs/zerolog"15 "github.com/rs/zerolog"
15 )16 )
16 17
@@ -55,6 +56,9 @@ type WorkspaceView struct {
55 // Prevents hover focus from overriding keyboard-initiated focus changes56 // Prevents hover focus from overriding keyboard-initiated focus changes
56 hoverSuppressedUntil time.Time57 hoverSuppressedUntil time.Time
57 58
59+ // Auto-open omnibox on new pane creation
60+ autoOpenOnNewPane bool
61+
58 mu sync.RWMutex62 mu sync.RWMutex
59 }63 }
60 64
@@ -547,6 +551,32 @@ func (wv *WorkspaceView) SetFindBarConfig(cfg FindBarConfig) {
547 wv.findBarCfg = cfg551 wv.findBarCfg = cfg
548 }552 }
549 553
554+// SetAutoOpenOnNewPane configures whether to show omnibox when a new pane is created.
555+func (wv *WorkspaceView) SetAutoOpenOnNewPane(enabled bool) {
556+ wv.mu.Lock()
557+ defer wv.mu.Unlock()
558+ wv.autoOpenOnNewPane = enabled
559+}
560+
561+// NotifyNewPaneCreated handles new pane creation events.
562+// If auto-open is enabled, shows the omnibox after GTK layout completes.
563+func (wv *WorkspaceView) NotifyNewPaneCreated(ctx context.Context) {
564+ wv.mu.RLock()
565+ autoOpen := wv.autoOpenOnNewPane
566+ wv.mu.RUnlock()
567+
568+ if !autoOpen {
569+ return
570+ }
571+
572+ // Defer omnibox show until after GTK layout allocation completes
573+ cb := glib.SourceFunc(func(uintptr) bool {
574+ wv.ShowOmnibox(ctx, "")
575+ return false
576+ })
577+ glib.IdleAdd(&cb, 0)
578+}
579+
550 // ShowOmnibox creates and shows the omnibox in the active pane.580 // ShowOmnibox creates and shows the omnibox in the active pane.
551 func (wv *WorkspaceView) ShowOmnibox(ctx context.Context, query string) {581 func (wv *WorkspaceView) ShowOmnibox(ctx context.Context, query string) {
552 wv.mu.Lock()582 wv.mu.Lock()
M internal/ui/coordinator/workspace.go +3 -5
@@ -145,8 +145,8 @@ func (c *WorkspaceCoordinator) Split(ctx context.Context, direction usecase.Spli
145145 c.applySplitToView(ctx, splitCtx.wsView, splitCtx.ws, output, direction, splitCtx.existingWidget, splitCtx.isStackSplit, oldActivePaneID)
146146 }
147147
148- if splitCtx.wsView != nil && config.Get().Omnibox.AutoOpenOnNewPane {
149- splitCtx.wsView.ShowOmnibox(ctx, "")
148+ if splitCtx.wsView != nil {
149+ splitCtx.wsView.NotifyNewPaneCreated(ctx)
150150 }
151151
152152 // Notify state change for session snapshots
@@ -1377,9 +1377,7 @@ func (c *WorkspaceCoordinator) StackPane(ctx context.Context) error {
13771377 log.Warn().Err(err).Msg("failed to set active pane")
13781378 }
13791379
1380- if config.Get().Omnibox.AutoOpenOnNewPane {
1381- stackCtx.wsView.ShowOmnibox(ctx, "")
1382- }
1380+ stackCtx.wsView.NotifyNewPaneCreated(ctx)
13831381
13841382 // Set up title bar click and close callbacks
13851383 tr := stackCtx.wsView.TreeRenderer()
@@ -145,8 +145,8 @@ func (c *WorkspaceCoordinator) Split(ctx context.Context, direction usecase.Spli
145 c.applySplitToView(ctx, splitCtx.wsView, splitCtx.ws, output, direction, splitCtx.existingWidget, splitCtx.isStackSplit, oldActivePaneID)145 c.applySplitToView(ctx, splitCtx.wsView, splitCtx.ws, output, direction, splitCtx.existingWidget, splitCtx.isStackSplit, oldActivePaneID)
146 }146 }
147 147
148- if splitCtx.wsView != nil && config.Get().Omnibox.AutoOpenOnNewPane {148+ if splitCtx.wsView != nil {
149- splitCtx.wsView.ShowOmnibox(ctx, "")149+ splitCtx.wsView.NotifyNewPaneCreated(ctx)
150 }150 }
151 151
152 // Notify state change for session snapshots152 // Notify state change for session snapshots
@@ -1377,9 +1377,7 @@ func (c *WorkspaceCoordinator) StackPane(ctx context.Context) error {
1377 log.Warn().Err(err).Msg("failed to set active pane")1377 log.Warn().Err(err).Msg("failed to set active pane")
1378 }1378 }
1379 1379
1380- if config.Get().Omnibox.AutoOpenOnNewPane {1380+ stackCtx.wsView.NotifyNewPaneCreated(ctx)
1381- stackCtx.wsView.ShowOmnibox(ctx, "")
1382- }
1383 1381
1384 // Set up title bar click and close callbacks1382 // Set up title bar click and close callbacks
1385 tr := stackCtx.wsView.TreeRenderer()1383 tr := stackCtx.wsView.TreeRenderer()

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close