refactor(cef): address CodeRabbit findings — DRY monitor, sentinel framerate, cleanup
- Extract getPrimaryMonitor() helper to deduplicate GDK monitor lookup between detectHiDPIScale and detectMonitorRefreshRate - Use 0 as sentinel for auto-detect frame rate (previously checked == 60 which silently overrode explicit user config of 60fps) - Round milliHz to nearest Hz instead of truncating (59999 → 60, not 59) - Remove dead enableAudioHandler field — AudioHandler is now always active since it's required for media decoding pipeline - Remove extra blank line in app.go - Update test to reflect always-on AudioHandler
- commit
- 4da3a75a770c7baf71605d0d2cbba59d1c2e5cb3
- author
- brice · · 2026-03-23 19:19 UTC
- committer
- brice · · 2026-03-28 04:38 UTC
- parent
- 73a1699
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
6 files · +29 -37
M internal/infrastructure/cef/app.go +0 -1
| @@ -38,7 +38,6 @@ func (a *dumberApp) OnBeforeCommandLineProcessing(processType string, commandLin | |||
| 38 | 38 | // Chromium blocks them, showing an infinite spinner. | |
| 39 | 39 | commandLine.AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required") | |
| 40 | 40 | ||
| 41 | - | ||
| 42 | 41 | cmdline := commandLine.GetCommandLineString() | |
| 43 | 42 | if len(cmdline) > maxCmdLineLogLen { | |
| 44 | 43 | runes := []rune(cmdline) | |
| @@ -38,7 +38,6 @@ func (a *dumberApp) OnBeforeCommandLineProcessing(processType string, commandLin | |||||
| 38 | // Chromium blocks them, showing an infinite spinner. | 38 | // Chromium blocks them, showing an infinite spinner. | ||
| 39 | commandLine.AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required") | 39 | commandLine.AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required") | ||
| 40 | 40 | ||||
| 41 | - | ||||
| 42 | cmdline := commandLine.GetCommandLineString() | 41 | cmdline := commandLine.GetCommandLineString() | ||
| 43 | if len(cmdline) > maxCmdLineLogLen { | 42 | if len(cmdline) > maxCmdLineLogLen { | ||
| 44 | runes := []rune(cmdline) | 43 | runes := []rune(cmdline) | ||
M internal/infrastructure/cef/engine_init.go +24 -25
| @@ -127,18 +127,20 @@ func wireEngine( | |||
| 127 | 127 | ||
| 128 | 128 | scale := detectHiDPIScale(logger) | |
| 129 | 129 | ||
| 130 | - | // If frame rate is the static default (60), try to match the monitor's | |
| 131 | - | // actual refresh rate for smoother scrolling on high-refresh displays. | |
| 132 | - | if windowlessFrameRate == 60 { | |
| 130 | + | // Auto-detect frame rate from monitor when config uses the default (0 = auto). | |
| 131 | + | // CEFWindowlessFrameRate() returns 0 when the user hasn't explicitly set a value, | |
| 132 | + | // allowing us to match the monitor's refresh rate for smoother scrolling. | |
| 133 | + | if windowlessFrameRate == 0 { | |
| 133 | 134 | if hz := detectMonitorRefreshRate(logger); hz > 0 { | |
| 134 | 135 | windowlessFrameRate = hz | |
| 136 | + | } else { | |
| 137 | + | windowlessFrameRate = 60 // safe fallback | |
| 135 | 138 | } | |
| 136 | 139 | } | |
| 137 | 140 | ||
| 138 | 141 | factory := newWebViewFactory(eng, gl, webViewFactoryOptions{ | |
| 139 | 142 | scale: scale, | |
| 140 | 143 | windowlessFrameRate: windowlessFrameRate, | |
| 141 | - | enableAudioHandler: cfg.EnableAudioHandler, | |
| 142 | 144 | enableContextMenuHandler: cfg.EnableContextMenuHandler, | |
| 143 | 145 | }) | |
| 144 | 146 | pool := newWebViewPool(factory) | |
| @@ -165,25 +167,32 @@ func wireEngine( | |||
| 165 | 167 | return eng, nil | |
| 166 | 168 | } | |
| 167 | 169 | ||
| 168 | - | // detectHiDPIScale queries the primary GDK monitor for its scale factor. | |
| 169 | - | func detectHiDPIScale(logger *zerolog.Logger) int32 { | |
| 170 | + | // getPrimaryMonitor returns the primary GDK monitor, or nil if unavailable. | |
| 171 | + | func getPrimaryMonitor() *gdk.Monitor { | |
| 170 | 172 | display := gdk.DisplayGetDefault() | |
| 171 | 173 | if display == nil { | |
| 172 | - | logger.Debug().Msg("cef: no GDK display available, using scale=1") | |
| 173 | - | return 1 | |
| 174 | + | return nil | |
| 174 | 175 | } | |
| 175 | 176 | monitors := display.GetMonitors() | |
| 176 | 177 | if monitors == nil { | |
| 177 | - | logger.Debug().Msg("cef: no monitors found, using scale=1") | |
| 178 | - | return 1 | |
| 178 | + | return nil | |
| 179 | 179 | } | |
| 180 | 180 | obj := monitors.GetObject(0) | |
| 181 | 181 | if obj == nil { | |
| 182 | - | logger.Debug().Msg("cef: primary monitor not available, using scale=1") | |
| 183 | - | return 1 | |
| 182 | + | return nil | |
| 184 | 183 | } | |
| 185 | 184 | mon := &gdk.Monitor{} | |
| 186 | 185 | mon.SetGoPointer(obj.GoPointer()) | |
| 186 | + | return mon | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | // detectHiDPIScale queries the primary GDK monitor for its scale factor. | |
| 190 | + | func detectHiDPIScale(logger *zerolog.Logger) int32 { | |
| 191 | + | mon := getPrimaryMonitor() | |
| 192 | + | if mon == nil { | |
| 193 | + | logger.Debug().Msg("cef: no primary monitor, using scale=1") | |
| 194 | + | return 1 | |
| 195 | + | } | |
| 187 | 196 | if s := mon.GetScaleFactor(); s > 0 { | |
| 188 | 197 | logger.Info().Int32("scale", int32(s)).Msg("cef: detected HiDPI scale from monitor") | |
| 189 | 198 | return int32(s) | |
| @@ -195,25 +204,15 @@ func detectHiDPIScale(logger *zerolog.Logger) int32 { | |||
| 195 | 204 | // detectMonitorRefreshRate queries the primary GDK monitor for its refresh rate. | |
| 196 | 205 | // Returns the rate in Hz (e.g., 120 for a 120Hz display), or 0 if detection fails. | |
| 197 | 206 | func detectMonitorRefreshRate(logger *zerolog.Logger) int32 { | |
| 198 | - | display := gdk.DisplayGetDefault() | |
| 199 | - | if display == nil { | |
| 200 | - | return 0 | |
| 201 | - | } | |
| 202 | - | monitors := display.GetMonitors() | |
| 203 | - | if monitors == nil { | |
| 207 | + | mon := getPrimaryMonitor() | |
| 208 | + | if mon == nil { | |
| 204 | 209 | return 0 | |
| 205 | 210 | } | |
| 206 | - | obj := monitors.GetObject(0) | |
| 207 | - | if obj == nil { | |
| 208 | - | return 0 | |
| 209 | - | } | |
| 210 | - | mon := &gdk.Monitor{} | |
| 211 | - | mon.SetGoPointer(obj.GoPointer()) | |
| 212 | 211 | milliHz := mon.GetRefreshRate() | |
| 213 | 212 | if milliHz <= 0 { | |
| 214 | 213 | return 0 | |
| 215 | 214 | } | |
| 216 | - | hz := int32(milliHz / 1000) | |
| 215 | + | hz := int32((milliHz + 500) / 1000) // round to nearest Hz | |
| 217 | 216 | logger.Info().Int32("refresh_rate_hz", hz).Msg("cef: detected monitor refresh rate") | |
| 218 | 217 | return hz | |
| 219 | 218 | } | |
| @@ -127,18 +127,20 @@ func wireEngine( | |||||
| 127 | 127 | ||||
| 128 | scale := detectHiDPIScale(logger) | 128 | scale := detectHiDPIScale(logger) | ||
| 129 | 129 | ||||
| 130 | - | // If frame rate is the static default (60), try to match the monitor's | 130 | + | // Auto-detect frame rate from monitor when config uses the default (0 = auto). |
| 131 | - | // actual refresh rate for smoother scrolling on high-refresh displays. | 131 | + | // CEFWindowlessFrameRate() returns 0 when the user hasn't explicitly set a value, |
| 132 | - | if windowlessFrameRate == 60 { | 132 | + | // allowing us to match the monitor's refresh rate for smoother scrolling. |
| 133 | + | if windowlessFrameRate == 0 { | |||
| 133 | if hz := detectMonitorRefreshRate(logger); hz > 0 { | 134 | if hz := detectMonitorRefreshRate(logger); hz > 0 { | ||
| 134 | windowlessFrameRate = hz | 135 | windowlessFrameRate = hz | ||
| 136 | + | } else { | |||
| 137 | + | windowlessFrameRate = 60 // safe fallback | |||
| 135 | } | 138 | } | ||
| 136 | } | 139 | } | ||
| 137 | 140 | ||||
| 138 | factory := newWebViewFactory(eng, gl, webViewFactoryOptions{ | 141 | factory := newWebViewFactory(eng, gl, webViewFactoryOptions{ | ||
| 139 | scale: scale, | 142 | scale: scale, | ||
| 140 | windowlessFrameRate: windowlessFrameRate, | 143 | windowlessFrameRate: windowlessFrameRate, | ||
| 141 | - | enableAudioHandler: cfg.EnableAudioHandler, | |||
| 142 | enableContextMenuHandler: cfg.EnableContextMenuHandler, | 144 | enableContextMenuHandler: cfg.EnableContextMenuHandler, | ||
| 143 | }) | 145 | }) | ||
| 144 | pool := newWebViewPool(factory) | 146 | pool := newWebViewPool(factory) | ||
| @@ -165,25 +167,32 @@ func wireEngine( | |||||
| 165 | return eng, nil | 167 | return eng, nil | ||
| 166 | } | 168 | } | ||
| 167 | 169 | ||||
| 168 | - | // detectHiDPIScale queries the primary GDK monitor for its scale factor. | 170 | + | // getPrimaryMonitor returns the primary GDK monitor, or nil if unavailable. |
| 169 | - | func detectHiDPIScale(logger *zerolog.Logger) int32 { | 171 | + | func getPrimaryMonitor() *gdk.Monitor { |
| 170 | display := gdk.DisplayGetDefault() | 172 | display := gdk.DisplayGetDefault() | ||
| 171 | if display == nil { | 173 | if display == nil { | ||
| 172 | - | logger.Debug().Msg("cef: no GDK display available, using scale=1") | 174 | + | return nil |
| 173 | - | return 1 | |||
| 174 | } | 175 | } | ||
| 175 | monitors := display.GetMonitors() | 176 | monitors := display.GetMonitors() | ||
| 176 | if monitors == nil { | 177 | if monitors == nil { | ||
| 177 | - | logger.Debug().Msg("cef: no monitors found, using scale=1") | 178 | + | return nil |
| 178 | - | return 1 | |||
| 179 | } | 179 | } | ||
| 180 | obj := monitors.GetObject(0) | 180 | obj := monitors.GetObject(0) | ||
| 181 | if obj == nil { | 181 | if obj == nil { | ||
| 182 | - | logger.Debug().Msg("cef: primary monitor not available, using scale=1") | 182 | + | return nil |
| 183 | - | return 1 | |||
| 184 | } | 183 | } | ||
| 185 | mon := &gdk.Monitor{} | 184 | mon := &gdk.Monitor{} | ||
| 186 | mon.SetGoPointer(obj.GoPointer()) | 185 | mon.SetGoPointer(obj.GoPointer()) | ||
| 186 | + | return mon | |||
| 187 | + | } | |||
| 188 | + | ||||
| 189 | + | // detectHiDPIScale queries the primary GDK monitor for its scale factor. | |||
| 190 | + | func detectHiDPIScale(logger *zerolog.Logger) int32 { | |||
| 191 | + | mon := getPrimaryMonitor() | |||
| 192 | + | if mon == nil { | |||
| 193 | + | logger.Debug().Msg("cef: no primary monitor, using scale=1") | |||
| 194 | + | return 1 | |||
| 195 | + | } | |||
| 187 | if s := mon.GetScaleFactor(); s > 0 { | 196 | if s := mon.GetScaleFactor(); s > 0 { | ||
| 188 | logger.Info().Int32("scale", int32(s)).Msg("cef: detected HiDPI scale from monitor") | 197 | logger.Info().Int32("scale", int32(s)).Msg("cef: detected HiDPI scale from monitor") | ||
| 189 | return int32(s) | 198 | return int32(s) | ||
| @@ -195,25 +204,15 @@ func detectHiDPIScale(logger *zerolog.Logger) int32 { | |||||
| 195 | // detectMonitorRefreshRate queries the primary GDK monitor for its refresh rate. | 204 | // detectMonitorRefreshRate queries the primary GDK monitor for its refresh rate. | ||
| 196 | // Returns the rate in Hz (e.g., 120 for a 120Hz display), or 0 if detection fails. | 205 | // Returns the rate in Hz (e.g., 120 for a 120Hz display), or 0 if detection fails. | ||
| 197 | func detectMonitorRefreshRate(logger *zerolog.Logger) int32 { | 206 | func detectMonitorRefreshRate(logger *zerolog.Logger) int32 { | ||
| 198 | - | display := gdk.DisplayGetDefault() | 207 | + | mon := getPrimaryMonitor() |
| 199 | - | if display == nil { | 208 | + | if mon == nil { |
| 200 | - | return 0 | |||
| 201 | - | } | |||
| 202 | - | monitors := display.GetMonitors() | |||
| 203 | - | if monitors == nil { | |||
| 204 | return 0 | 209 | return 0 | ||
| 205 | } | 210 | } | ||
| 206 | - | obj := monitors.GetObject(0) | |||
| 207 | - | if obj == nil { | |||
| 208 | - | return 0 | |||
| 209 | - | } | |||
| 210 | - | mon := &gdk.Monitor{} | |||
| 211 | - | mon.SetGoPointer(obj.GoPointer()) | |||
| 212 | milliHz := mon.GetRefreshRate() | 211 | milliHz := mon.GetRefreshRate() | ||
| 213 | if milliHz <= 0 { | 212 | if milliHz <= 0 { | ||
| 214 | return 0 | 213 | return 0 | ||
| 215 | } | 214 | } | ||
| 216 | - | hz := int32(milliHz / 1000) | 215 | + | hz := int32((milliHz + 500) / 1000) // round to nearest Hz |
| 217 | logger.Info().Int32("refresh_rate_hz", hz).Msg("cef: detected monitor refresh rate") | 216 | logger.Info().Int32("refresh_rate_hz", hz).Msg("cef: detected monitor refresh rate") | ||
| 218 | return hz | 217 | return hz | ||
| 219 | } | 218 | } | ||
M internal/infrastructure/cef/factory.go +0 -4
| @@ -22,7 +22,6 @@ type WebViewFactory struct { | |||
| 22 | 22 | nextID atomic.Uint64 | |
| 23 | 23 | scale int32 | |
| 24 | 24 | windowlessFrameRate int32 | |
| 25 | - | enableAudioHandler bool | |
| 26 | 25 | enableContextMenuHandler bool | |
| 27 | 26 | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | |
| 28 | 27 | } | |
| @@ -30,7 +29,6 @@ type WebViewFactory struct { | |||
| 30 | 29 | type webViewFactoryOptions struct { | |
| 31 | 30 | scale int32 | |
| 32 | 31 | windowlessFrameRate int32 | |
| 33 | - | enableAudioHandler bool | |
| 34 | 32 | enableContextMenuHandler bool | |
| 35 | 33 | } | |
| 36 | 34 | ||
| @@ -48,7 +46,6 @@ func newWebViewFactory(engine *Engine, gl *glLoader, opts webViewFactoryOptions) | |||
| 48 | 46 | gl: gl, | |
| 49 | 47 | scale: opts.scale, | |
| 50 | 48 | windowlessFrameRate: opts.windowlessFrameRate, | |
| 51 | - | enableAudioHandler: opts.enableAudioHandler, | |
| 52 | 49 | enableContextMenuHandler: opts.enableContextMenuHandler, | |
| 53 | 50 | } | |
| 54 | 51 | } | |
| @@ -77,7 +74,6 @@ func (f *WebViewFactory) Create(ctx context.Context) (port.WebView, error) { | |||
| 77 | 74 | ||
| 78 | 75 | handlers := &handlerSet{ | |
| 79 | 76 | wv: wv, | |
| 80 | - | enableAudioHandler: f.enableAudioHandler, | |
| 81 | 77 | enableContextMenuHandler: f.enableContextMenuHandler, | |
| 82 | 78 | } | |
| 83 | 79 | wv.handlers = handlers | |
| @@ -22,7 +22,6 @@ type WebViewFactory struct { | |||||
| 22 | nextID atomic.Uint64 | 22 | nextID atomic.Uint64 | ||
| 23 | scale int32 | 23 | scale int32 | ||
| 24 | windowlessFrameRate int32 | 24 | windowlessFrameRate int32 | ||
| 25 | - | enableAudioHandler bool | |||
| 26 | enableContextMenuHandler bool | 25 | enableContextMenuHandler bool | ||
| 27 | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | 26 | bgColor atomic.Uint32 // packed ARGB for BrowserSettings.BackgroundColor | ||
| 28 | } | 27 | } | ||
| @@ -30,7 +29,6 @@ type WebViewFactory struct { | |||||
| 30 | type webViewFactoryOptions struct { | 29 | type webViewFactoryOptions struct { | ||
| 31 | scale int32 | 30 | scale int32 | ||
| 32 | windowlessFrameRate int32 | 31 | windowlessFrameRate int32 | ||
| 33 | - | enableAudioHandler bool | |||
| 34 | enableContextMenuHandler bool | 32 | enableContextMenuHandler bool | ||
| 35 | } | 33 | } | ||
| 36 | 34 | ||||
| @@ -48,7 +46,6 @@ func newWebViewFactory(engine *Engine, gl *glLoader, opts webViewFactoryOptions) | |||||
| 48 | gl: gl, | 46 | gl: gl, | ||
| 49 | scale: opts.scale, | 47 | scale: opts.scale, | ||
| 50 | windowlessFrameRate: opts.windowlessFrameRate, | 48 | windowlessFrameRate: opts.windowlessFrameRate, | ||
| 51 | - | enableAudioHandler: opts.enableAudioHandler, | |||
| 52 | enableContextMenuHandler: opts.enableContextMenuHandler, | 49 | enableContextMenuHandler: opts.enableContextMenuHandler, | ||
| 53 | } | 50 | } | ||
| 54 | } | 51 | } | ||
| @@ -77,7 +74,6 @@ func (f *WebViewFactory) Create(ctx context.Context) (port.WebView, error) { | |||||
| 77 | 74 | ||||
| 78 | handlers := &handlerSet{ | 75 | handlers := &handlerSet{ | ||
| 79 | wv: wv, | 76 | wv: wv, | ||
| 80 | - | enableAudioHandler: f.enableAudioHandler, | |||
| 81 | enableContextMenuHandler: f.enableContextMenuHandler, | 77 | enableContextMenuHandler: f.enableContextMenuHandler, | ||
| 82 | } | 78 | } | ||
| 83 | wv.handlers = handlers | 79 | wv.handlers = handlers | ||
M internal/infrastructure/cef/webview_handlers.go +0 -2
| @@ -12,7 +12,6 @@ import ( | |||
| 12 | 12 | // methods can return the same receiver, avoiding extra allocations. | |
| 13 | 13 | type handlerSet struct { | |
| 14 | 14 | wv *WebView | |
| 15 | - | enableAudioHandler bool | |
| 16 | 15 | enableContextMenuHandler bool | |
| 17 | 16 | } | |
| 18 | 17 | ||
| @@ -453,7 +452,6 @@ func (h *handlerSet) OnAfterCreated(browser purecef.Browser) { | |||
| 453 | 452 | browserID := browser.GetIdentifier() | |
| 454 | 453 | log.Debug(). | |
| 455 | 454 | Int32("browser_id", browserID). | |
| 456 | - | Bool("audio_handler_enabled", h.enableAudioHandler). | |
| 457 | 455 | Bool("context_menu_handler_enabled", h.enableContextMenuHandler). | |
| 458 | 456 | Msg("cef: OnAfterCreated") | |
| 459 | 457 | if h.wv.engine != nil { | |
| @@ -12,7 +12,6 @@ import ( | |||||
| 12 | // methods can return the same receiver, avoiding extra allocations. | 12 | // methods can return the same receiver, avoiding extra allocations. | ||
| 13 | type handlerSet struct { | 13 | type handlerSet struct { | ||
| 14 | wv *WebView | 14 | wv *WebView | ||
| 15 | - | enableAudioHandler bool | |||
| 16 | enableContextMenuHandler bool | 15 | enableContextMenuHandler bool | ||
| 17 | } | 16 | } | ||
| 18 | 17 | ||||
| @@ -453,7 +452,6 @@ func (h *handlerSet) OnAfterCreated(browser purecef.Browser) { | |||||
| 453 | browserID := browser.GetIdentifier() | 452 | browserID := browser.GetIdentifier() | ||
| 454 | log.Debug(). | 453 | log.Debug(). | ||
| 455 | Int32("browser_id", browserID). | 454 | Int32("browser_id", browserID). | ||
| 456 | - | Bool("audio_handler_enabled", h.enableAudioHandler). | |||
| 457 | Bool("context_menu_handler_enabled", h.enableContextMenuHandler). | 455 | Bool("context_menu_handler_enabled", h.enableContextMenuHandler). | ||
| 458 | Msg("cef: OnAfterCreated") | 456 | Msg("cef: OnAfterCreated") | ||
| 459 | if h.wv.engine != nil { | 457 | if h.wv.engine != nil { | ||
M internal/infrastructure/cef/webview_handlers_test.go +2 -3
| @@ -108,12 +108,11 @@ func TestGetScreenInfoUsesDIPRectAndScale(t *testing.T) { | |||
| 108 | 108 | func TestOptionalHandlersRespectFactoryFlags(t *testing.T) { | |
| 109 | 109 | h := &handlerSet{} | |
| 110 | 110 | ||
| 111 | - | require.Nil(t, h.GetAudioHandler()) | |
| 111 | + | // AudioHandler is always enabled (required for media decoding). | |
| 112 | + | require.Same(t, h, h.GetAudioHandler()) | |
| 112 | 113 | require.Nil(t, h.GetContextMenuHandler()) | |
| 113 | 114 | ||
| 114 | - | h.enableAudioHandler = true | |
| 115 | 115 | h.enableContextMenuHandler = true | |
| 116 | 116 | ||
| 117 | - | require.Same(t, h, h.GetAudioHandler()) | |
| 118 | 117 | require.Same(t, h, h.GetContextMenuHandler()) | |
| 119 | 118 | } | |
| @@ -108,12 +108,11 @@ func TestGetScreenInfoUsesDIPRectAndScale(t *testing.T) { | |||||
| 108 | func TestOptionalHandlersRespectFactoryFlags(t *testing.T) { | 108 | func TestOptionalHandlersRespectFactoryFlags(t *testing.T) { | ||
| 109 | h := &handlerSet{} | 109 | h := &handlerSet{} | ||
| 110 | 110 | ||||
| 111 | - | require.Nil(t, h.GetAudioHandler()) | 111 | + | // AudioHandler is always enabled (required for media decoding). |
| 112 | + | require.Same(t, h, h.GetAudioHandler()) | |||
| 112 | require.Nil(t, h.GetContextMenuHandler()) | 113 | require.Nil(t, h.GetContextMenuHandler()) | ||
| 113 | 114 | ||||
| 114 | - | h.enableAudioHandler = true | |||
| 115 | h.enableContextMenuHandler = true | 115 | h.enableContextMenuHandler = true | ||
| 116 | 116 | ||||
| 117 | - | require.Same(t, h, h.GetAudioHandler()) | |||
| 118 | require.Same(t, h, h.GetContextMenuHandler()) | 117 | require.Same(t, h, h.GetContextMenuHandler()) | ||
| 119 | } | 118 | } | ||
M internal/infrastructure/config/engine.go +3 -2
| @@ -118,12 +118,13 @@ func (c CEFEngineConfig) CEFManualPumpIntervalMs() int64 { | |||
| 118 | 118 | return defaultCEFManualPumpIntervalMs | |
| 119 | 119 | } | |
| 120 | 120 | ||
| 121 | - | // CEFWindowlessFrameRate returns the effective OSR frame rate with default 60. | |
| 121 | + | // CEFWindowlessFrameRate returns the configured OSR frame rate. | |
| 122 | + | // Returns 0 (auto-detect from monitor) when the user hasn't set an explicit value. | |
| 122 | 123 | func (c CEFEngineConfig) CEFWindowlessFrameRate() int32 { | |
| 123 | 124 | if c.WindowlessFrameRate > 0 { | |
| 124 | 125 | return c.WindowlessFrameRate | |
| 125 | 126 | } | |
| 126 | - | return defaultCEFWindowlessFrameRate | |
| 127 | + | return 0 // auto-detect from monitor refresh rate | |
| 127 | 128 | } | |
| 128 | 129 | ||
| 129 | 130 | // PerformanceConfigFromEngine constructs a PerformanceConfig from the | |
| @@ -118,12 +118,13 @@ func (c CEFEngineConfig) CEFManualPumpIntervalMs() int64 { | |||||
| 118 | return defaultCEFManualPumpIntervalMs | 118 | return defaultCEFManualPumpIntervalMs | ||
| 119 | } | 119 | } | ||
| 120 | 120 | ||||
| 121 | - | // CEFWindowlessFrameRate returns the effective OSR frame rate with default 60. | 121 | + | // CEFWindowlessFrameRate returns the configured OSR frame rate. |
| 122 | + | // Returns 0 (auto-detect from monitor) when the user hasn't set an explicit value. | |||
| 122 | func (c CEFEngineConfig) CEFWindowlessFrameRate() int32 { | 123 | func (c CEFEngineConfig) CEFWindowlessFrameRate() int32 { | ||
| 123 | if c.WindowlessFrameRate > 0 { | 124 | if c.WindowlessFrameRate > 0 { | ||
| 124 | return c.WindowlessFrameRate | 125 | return c.WindowlessFrameRate | ||
| 125 | } | 126 | } | ||
| 126 | - | return defaultCEFWindowlessFrameRate | 127 | + | return 0 // auto-detect from monitor refresh rate |
| 127 | } | 128 | } | ||
| 128 | 129 | ||||
| 129 | // PerformanceConfigFromEngine constructs a PerformanceConfig from the | 130 | // PerformanceConfigFromEngine constructs a PerformanceConfig from the | ||