detached 40b8fb0

Delay cef2gtk GL preparation

commit
40b8fb03a0ce2d32011768797692e1d331b09470
author
brice · · 2026-04-30 02:45 UTC
parent
1d14237
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +15 -16
M internal/infrastructure/cef/factory.go +15 -16
@@ -123,17 +123,6 @@ func (f *WebViewFactory) newWebView(ctx context.Context) (*WebView, error) {
123123 wv.handlers = handlers
124124 wv.findCtrl = newFindController()
125125
126- var prepareErr error
127- wv.runOnGTKSync(func() {
128- prepareErr = viewBridge.PrepareOnGTKThread()
129- })
130- if prepareErr != nil {
131- if ctx != nil {
132- logging.FromContext(ctx).Error().Err(prepareErr).Uint64("webview_id", uint64(id)).Msg("cef: failed to prepare cef2gtk view")
133- }
134- return nil, fmt.Errorf("prepare cef2gtk view: %w", prepareErr)
135- }
136-
137126 // Build a CEF client backed by our handlerSet.
138127 // Store on WebView to prevent GC collection before CEF AddRef's it.
139128 wv.client = purecef.NewClient(wv.handlers)
@@ -159,17 +148,27 @@ func (f *WebViewFactory) configureInitialBrowserCreation(
159148 if wv.viewBridge == nil {
160149 return
161150 }
162- firstResize := true
151+ browserCreateScheduled := false
163152 wv.runOnGTKSync(func() {
164153 wv.removeSizeObserver = wv.viewBridge.AddSizeObserver(func(w, h int32) {
165- if firstResize {
166- firstResize = false
154+ // Size observers run on the GTK thread. Prepare the GtkGLArea only after it
155+ // has been packed and allocated; preparing at WebView construction time can
156+ // run before GTK has created a GL context.
157+ if !browserCreateScheduled {
158+ if err := wv.viewBridge.PrepareOnGTKThread(); err != nil {
159+ logging.FromContext(ctx).Warn().
160+ Err(err).
161+ Uint64("webview_id", uint64(wv.id)).
162+ Int32("resize_width", w).
163+ Int32("resize_height", h).
164+ Msg("cef: cef2gtk view not ready after resize, will retry")
165+ return
166+ }
167+ browserCreateScheduled = true
167168 onFirstResize(w, h)
168169 return
169170 }
170171
171- // Size observers run on the GTK thread; the captured firstResize state is
172- // therefore single-threaded.
173172 wv.mu.RLock()
174173 host := wv.host
175174 wv.mu.RUnlock()
@@ -123,17 +123,6 @@ func (f *WebViewFactory) newWebView(ctx context.Context) (*WebView, error) {
123 wv.handlers = handlers123 wv.handlers = handlers
124 wv.findCtrl = newFindController()124 wv.findCtrl = newFindController()
125 125
126- var prepareErr error
127- wv.runOnGTKSync(func() {
128- prepareErr = viewBridge.PrepareOnGTKThread()
129- })
130- if prepareErr != nil {
131- if ctx != nil {
132- logging.FromContext(ctx).Error().Err(prepareErr).Uint64("webview_id", uint64(id)).Msg("cef: failed to prepare cef2gtk view")
133- }
134- return nil, fmt.Errorf("prepare cef2gtk view: %w", prepareErr)
135- }
136-
137 // Build a CEF client backed by our handlerSet.126 // Build a CEF client backed by our handlerSet.
138 // Store on WebView to prevent GC collection before CEF AddRef's it.127 // Store on WebView to prevent GC collection before CEF AddRef's it.
139 wv.client = purecef.NewClient(wv.handlers)128 wv.client = purecef.NewClient(wv.handlers)
@@ -159,17 +148,27 @@ func (f *WebViewFactory) configureInitialBrowserCreation(
159 if wv.viewBridge == nil {148 if wv.viewBridge == nil {
160 return149 return
161 }150 }
162- firstResize := true151+ browserCreateScheduled := false
163 wv.runOnGTKSync(func() {152 wv.runOnGTKSync(func() {
164 wv.removeSizeObserver = wv.viewBridge.AddSizeObserver(func(w, h int32) {153 wv.removeSizeObserver = wv.viewBridge.AddSizeObserver(func(w, h int32) {
165- if firstResize {154+ // Size observers run on the GTK thread. Prepare the GtkGLArea only after it
166- firstResize = false155+ // has been packed and allocated; preparing at WebView construction time can
156+ // run before GTK has created a GL context.
157+ if !browserCreateScheduled {
158+ if err := wv.viewBridge.PrepareOnGTKThread(); err != nil {
159+ logging.FromContext(ctx).Warn().
160+ Err(err).
161+ Uint64("webview_id", uint64(wv.id)).
162+ Int32("resize_width", w).
163+ Int32("resize_height", h).
164+ Msg("cef: cef2gtk view not ready after resize, will retry")
165+ return
166+ }
167+ browserCreateScheduled = true
167 onFirstResize(w, h)168 onFirstResize(w, h)
168 return169 return
169 }170 }
170 171
171- // Size observers run on the GTK thread; the captured firstResize state is
172- // therefore single-threaded.
173 wv.mu.RLock()172 wv.mu.RLock()
174 host := wv.host173 host := wv.host
175 wv.mu.RUnlock()174 wv.mu.RUnlock()

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