detached fdc933d

fix(cef): retry viewport sync after resize

commit
fdc933da07c1d35d06850c51e488bb2189711e73
author
brice · · 2026-06-20 14:16 UTC
parent
09bc82a
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +24 -4
M internal/infrastructure/cef/webview_viewport.go +14 -3
@@ -94,7 +94,11 @@ func (wv *WebView) syncViewportOnGTK(ctx context.Context) {
9494 if wv == nil {
9595 return
9696 }
97- wv.syncViewportNowOnGTK(ctx, wv.takeViewportSyncReason())
97+ reason := wv.takeViewportSyncReason()
98+ ctx = wv.viewportSyncContext(ctx)
99+ if wv.syncViewportNowOnGTK(ctx, reason) {
100+ wv.scheduleResizeRepaintPulse(ctx, reason)
101+ }
98102 }
99103
100104 func (wv *WebView) syncViewportNowOnGTK(ctx context.Context, reason string) bool {
@@ -148,6 +152,12 @@ func (wv *WebView) scheduleResizeRepaintPulse(ctx context.Context, reason string
148152 if wv == nil || wv.destroyed.Load() {
149153 return
150154 }
155+ visible := true
156+ if wv.viewBridge != nil {
157+ if widget := wv.viewBridge.Widget(); widget != nil {
158+ visible = widget.IsVisible()
159+ }
160+ }
151161 seq := wv.viewportResizePulseSeq.Add(1)
152162 for _, delayMs := range [...]int64{16, 48} {
153163 task := cefNewTask(cefTaskFunc(func() {
@@ -160,12 +170,13 @@ func (wv *WebView) scheduleResizeRepaintPulse(ctx context.Context, reason string
160170 if host == nil {
161171 return
162172 }
163- host.Invalidate(purecef.PaintElementTypePetView)
173+ notifyBrowserViewportSync(host, visible)
164174 logging.FromContext(ctx).Debug().
165175 Uint64("webview_id", uint64(wv.id)).
166176 Int64("delay_ms", delayMs).
177+ Bool("visible", visible).
167178 Str("reason", reason).
168- Msg("cef: delayed resize repaint pulse")
179+ Msg("cef: delayed resize viewport sync")
169180 }))
170181 if task == nil {
171182 continue
@@ -94,7 +94,11 @@ func (wv *WebView) syncViewportOnGTK(ctx context.Context) {
94 if wv == nil {94 if wv == nil {
95 return95 return
96 }96 }
97- wv.syncViewportNowOnGTK(ctx, wv.takeViewportSyncReason())97+ reason := wv.takeViewportSyncReason()
98+ ctx = wv.viewportSyncContext(ctx)
99+ if wv.syncViewportNowOnGTK(ctx, reason) {
100+ wv.scheduleResizeRepaintPulse(ctx, reason)
101+ }
98 }102 }
99 103
100 func (wv *WebView) syncViewportNowOnGTK(ctx context.Context, reason string) bool {104 func (wv *WebView) syncViewportNowOnGTK(ctx context.Context, reason string) bool {
@@ -148,6 +152,12 @@ func (wv *WebView) scheduleResizeRepaintPulse(ctx context.Context, reason string
148 if wv == nil || wv.destroyed.Load() {152 if wv == nil || wv.destroyed.Load() {
149 return153 return
150 }154 }
155+ visible := true
156+ if wv.viewBridge != nil {
157+ if widget := wv.viewBridge.Widget(); widget != nil {
158+ visible = widget.IsVisible()
159+ }
160+ }
151 seq := wv.viewportResizePulseSeq.Add(1)161 seq := wv.viewportResizePulseSeq.Add(1)
152 for _, delayMs := range [...]int64{16, 48} {162 for _, delayMs := range [...]int64{16, 48} {
153 task := cefNewTask(cefTaskFunc(func() {163 task := cefNewTask(cefTaskFunc(func() {
@@ -160,12 +170,13 @@ func (wv *WebView) scheduleResizeRepaintPulse(ctx context.Context, reason string
160 if host == nil {170 if host == nil {
161 return171 return
162 }172 }
163- host.Invalidate(purecef.PaintElementTypePetView)173+ notifyBrowserViewportSync(host, visible)
164 logging.FromContext(ctx).Debug().174 logging.FromContext(ctx).Debug().
165 Uint64("webview_id", uint64(wv.id)).175 Uint64("webview_id", uint64(wv.id)).
166 Int64("delay_ms", delayMs).176 Int64("delay_ms", delayMs).
177+ Bool("visible", visible).
167 Str("reason", reason).178 Str("reason", reason).
168- Msg("cef: delayed resize repaint pulse")179+ Msg("cef: delayed resize viewport sync")
169 }))180 }))
170 if task == nil {181 if task == nil {
171 continue182 continue
M internal/infrastructure/cef/webview_viewport_test.go +10 -1
@@ -450,5 +450,14 @@ func TestScheduleResizeRepaintPulse_CoalescesToLatestSequence(t *testing.T) {
450450
451451 scheduled[2].Execute()
452452 scheduled[3].Execute()
453- require.Equal(t, []string{"Invalidate", "Invalidate"}, host.calls)
453+ require.Equal(t, []string{
454+ "WasHidden",
455+ "NotifyScreenInfoChanged",
456+ "WasResized",
457+ "Invalidate",
458+ "WasHidden",
459+ "NotifyScreenInfoChanged",
460+ "WasResized",
461+ "Invalidate",
462+ }, host.calls)
454463 }
@@ -450,5 +450,14 @@ func TestScheduleResizeRepaintPulse_CoalescesToLatestSequence(t *testing.T) {
450 450
451 scheduled[2].Execute()451 scheduled[2].Execute()
452 scheduled[3].Execute()452 scheduled[3].Execute()
453- require.Equal(t, []string{"Invalidate", "Invalidate"}, host.calls)453+ require.Equal(t, []string{
454+ "WasHidden",
455+ "NotifyScreenInfoChanged",
456+ "WasResized",
457+ "Invalidate",
458+ "WasHidden",
459+ "NotifyScreenInfoChanged",
460+ "WasResized",
461+ "Invalidate",
462+ }, host.calls)
454 }463 }

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