fix(cef): stabilize standalone omnibox startup
- commit
- 3b3765d837e680e751252a3ece2d268483665b14
- author
- brice · · 2026-04-09 03:29 UTC
- parent
- f0280fa
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
10 files · +88 -15
M cmd/dumber/main.go +18 -5
| @@ -147,13 +147,10 @@ func runGUI() int { | |||
| 147 | 147 | } | |
| 148 | 148 | timer.MarkDuration("parallel_phase", initResult.Duration) | |
| 149 | 149 | ||
| 150 | - | if cfg.Engine.ResolveEngineType() == config.EngineTypeCEF { | |
| 150 | + | preInitializeAdwaitaForCEF(cfg, initResult, func() { | |
| 151 | 151 | logging.FromContext(ctx).Info().Msg("pre-initializing libadwaita before CEF multi-threaded loop") | |
| 152 | 152 | ui.EnsureAdwaitaInitialized() | |
| 153 | - | if initResult.AdwaitaDetector != nil { | |
| 154 | - | initResult.AdwaitaDetector.MarkAvailable() | |
| 155 | - | } | |
| 156 | - | } | |
| 153 | + | }) | |
| 157 | 154 | ||
| 158 | 155 | needsEagerDB := restoreSessionID != "" || cfg.Session.AutoRestore | |
| 159 | 156 | ||
| @@ -213,6 +210,8 @@ func runStandaloneOmnibox() int { | |||
| 213 | 210 | return 1 | |
| 214 | 211 | } | |
| 215 | 212 | ||
| 213 | + | preInitializeAdwaitaForCEF(cfg, initResult, ui.EnsureAdwaitaInitialized) | |
| 214 | + | ||
| 216 | 215 | engine, repos, dbCleanup, err := initStackAndRepos(ctx, cfg, initResult, false) | |
| 217 | 216 | if err != nil { | |
| 218 | 217 | logging.FromContext(ctx).Error().Err(err).Msg("failed to initialize standalone omnibox runtime") | |
| @@ -245,6 +244,20 @@ func runStandaloneOmnibox() int { | |||
| 245 | 244 | return ui.RunStandaloneOmnibox(ctx, runtimeCfg) | |
| 246 | 245 | } | |
| 247 | 246 | ||
| 247 | + | func preInitializeAdwaitaForCEF(cfg *config.Config, initResult *bootstrap.ParallelInitResult, initAdwaita func()) { | |
| 248 | + | if cfg == nil || initResult == nil || initAdwaita == nil { | |
| 249 | + | return | |
| 250 | + | } | |
| 251 | + | if cfg.Engine.ResolveEngineType() != config.EngineTypeCEF { | |
| 252 | + | return | |
| 253 | + | } | |
| 254 | + | ||
| 255 | + | initAdwaita() | |
| 256 | + | if initResult.AdwaitaDetector != nil { | |
| 257 | + | initResult.AdwaitaDetector.MarkAvailable() | |
| 258 | + | } | |
| 259 | + | } | |
| 260 | + | ||
| 248 | 261 | func maybeReexecStandaloneOmniboxWithLayerShell() { | |
| 249 | 262 | env := bootstrap.CurrentEnvMap() | |
| 250 | 263 | if !bootstrap.ShouldPreloadLayerShell(env) { | |
| @@ -147,13 +147,10 @@ func runGUI() int { | |||||
| 147 | } | 147 | } | ||
| 148 | timer.MarkDuration("parallel_phase", initResult.Duration) | 148 | timer.MarkDuration("parallel_phase", initResult.Duration) | ||
| 149 | 149 | ||||
| 150 | - | if cfg.Engine.ResolveEngineType() == config.EngineTypeCEF { | 150 | + | preInitializeAdwaitaForCEF(cfg, initResult, func() { |
| 151 | logging.FromContext(ctx).Info().Msg("pre-initializing libadwaita before CEF multi-threaded loop") | 151 | logging.FromContext(ctx).Info().Msg("pre-initializing libadwaita before CEF multi-threaded loop") | ||
| 152 | ui.EnsureAdwaitaInitialized() | 152 | ui.EnsureAdwaitaInitialized() | ||
| 153 | - | if initResult.AdwaitaDetector != nil { | 153 | + | }) |
| 154 | - | initResult.AdwaitaDetector.MarkAvailable() | |||
| 155 | - | } | |||
| 156 | - | } | |||
| 157 | 154 | ||||
| 158 | needsEagerDB := restoreSessionID != "" || cfg.Session.AutoRestore | 155 | needsEagerDB := restoreSessionID != "" || cfg.Session.AutoRestore | ||
| 159 | 156 | ||||
| @@ -213,6 +210,8 @@ func runStandaloneOmnibox() int { | |||||
| 213 | return 1 | 210 | return 1 | ||
| 214 | } | 211 | } | ||
| 215 | 212 | ||||
| 213 | + | preInitializeAdwaitaForCEF(cfg, initResult, ui.EnsureAdwaitaInitialized) | |||
| 214 | + | ||||
| 216 | engine, repos, dbCleanup, err := initStackAndRepos(ctx, cfg, initResult, false) | 215 | engine, repos, dbCleanup, err := initStackAndRepos(ctx, cfg, initResult, false) | ||
| 217 | if err != nil { | 216 | if err != nil { | ||
| 218 | logging.FromContext(ctx).Error().Err(err).Msg("failed to initialize standalone omnibox runtime") | 217 | logging.FromContext(ctx).Error().Err(err).Msg("failed to initialize standalone omnibox runtime") | ||
| @@ -245,6 +244,20 @@ func runStandaloneOmnibox() int { | |||||
| 245 | return ui.RunStandaloneOmnibox(ctx, runtimeCfg) | 244 | return ui.RunStandaloneOmnibox(ctx, runtimeCfg) | ||
| 246 | } | 245 | } | ||
| 247 | 246 | ||||
| 247 | + | func preInitializeAdwaitaForCEF(cfg *config.Config, initResult *bootstrap.ParallelInitResult, initAdwaita func()) { | |||
| 248 | + | if cfg == nil || initResult == nil || initAdwaita == nil { | |||
| 249 | + | return | |||
| 250 | + | } | |||
| 251 | + | if cfg.Engine.ResolveEngineType() != config.EngineTypeCEF { | |||
| 252 | + | return | |||
| 253 | + | } | |||
| 254 | + | ||||
| 255 | + | initAdwaita() | |||
| 256 | + | if initResult.AdwaitaDetector != nil { | |||
| 257 | + | initResult.AdwaitaDetector.MarkAvailable() | |||
| 258 | + | } | |||
| 259 | + | } | |||
| 260 | + | ||||
| 248 | func maybeReexecStandaloneOmniboxWithLayerShell() { | 261 | func maybeReexecStandaloneOmniboxWithLayerShell() { | ||
| 249 | env := bootstrap.CurrentEnvMap() | 262 | env := bootstrap.CurrentEnvMap() | ||
| 250 | if !bootstrap.ShouldPreloadLayerShell(env) { | 263 | if !bootstrap.ShouldPreloadLayerShell(env) { | ||
M cmd/dumber/main_test.go +44 -0
| @@ -3,6 +3,10 @@ package main | |||
| 3 | 3 | import ( | |
| 4 | 4 | "errors" | |
| 5 | 5 | "testing" | |
| 6 | + | ||
| 7 | + | "github.com/bnema/dumber/internal/bootstrap" | |
| 8 | + | "github.com/bnema/dumber/internal/infrastructure/colorscheme" | |
| 9 | + | "github.com/bnema/dumber/internal/infrastructure/config" | |
| 6 | 10 | ) | |
| 7 | 11 | ||
| 8 | 12 | func TestLaunchModeFromArgs_DetectsStandaloneOmnibox(t *testing.T) { | |
| @@ -87,3 +91,43 @@ func TestResolveCurrentExecutable_PropagatesError(t *testing.T) { | |||
| 87 | 91 | t.Fatalf("expected error %v, got %v", wantErr, err) | |
| 88 | 92 | } | |
| 89 | 93 | } | |
| 94 | + | ||
| 95 | + | func TestPreInitializeAdwaitaForCEF_InitializesAndMarksDetector(t *testing.T) { | |
| 96 | + | initResult := &bootstrap.ParallelInitResult{ | |
| 97 | + | AdwaitaDetector: colorscheme.NewAdwaitaDetector(), | |
| 98 | + | } | |
| 99 | + | cfg := &config.Config{} | |
| 100 | + | cfg.Engine.Type = config.EngineTypeCEF | |
| 101 | + | ||
| 102 | + | called := false | |
| 103 | + | preInitializeAdwaitaForCEF(cfg, initResult, func() { | |
| 104 | + | called = true | |
| 105 | + | }) | |
| 106 | + | ||
| 107 | + | if !called { | |
| 108 | + | t.Fatal("expected libadwaita initialization for CEF") | |
| 109 | + | } | |
| 110 | + | if !initResult.AdwaitaDetector.Available() { | |
| 111 | + | t.Fatal("expected adwaita detector to be marked available") | |
| 112 | + | } | |
| 113 | + | } | |
| 114 | + | ||
| 115 | + | func TestPreInitializeAdwaitaForCEF_SkipsNonCEF(t *testing.T) { | |
| 116 | + | initResult := &bootstrap.ParallelInitResult{ | |
| 117 | + | AdwaitaDetector: colorscheme.NewAdwaitaDetector(), | |
| 118 | + | } | |
| 119 | + | cfg := &config.Config{} | |
| 120 | + | cfg.Engine.Type = config.EngineTypeWebKit | |
| 121 | + | ||
| 122 | + | called := false | |
| 123 | + | preInitializeAdwaitaForCEF(cfg, initResult, func() { | |
| 124 | + | called = true | |
| 125 | + | }) | |
| 126 | + | ||
| 127 | + | if called { | |
| 128 | + | t.Fatal("expected libadwaita initialization to be skipped for non-CEF") | |
| 129 | + | } | |
| 130 | + | if initResult.AdwaitaDetector.Available() { | |
| 131 | + | t.Fatal("expected adwaita detector to remain unavailable") | |
| 132 | + | } | |
| 133 | + | } | |
| @@ -3,6 +3,10 @@ package main | |||||
| 3 | import ( | 3 | import ( | ||
| 4 | "errors" | 4 | "errors" | ||
| 5 | "testing" | 5 | "testing" | ||
| 6 | + | ||||
| 7 | + | "github.com/bnema/dumber/internal/bootstrap" | |||
| 8 | + | "github.com/bnema/dumber/internal/infrastructure/colorscheme" | |||
| 9 | + | "github.com/bnema/dumber/internal/infrastructure/config" | |||
| 6 | ) | 10 | ) | ||
| 7 | 11 | ||||
| 8 | func TestLaunchModeFromArgs_DetectsStandaloneOmnibox(t *testing.T) { | 12 | func TestLaunchModeFromArgs_DetectsStandaloneOmnibox(t *testing.T) { | ||
| @@ -87,3 +91,43 @@ func TestResolveCurrentExecutable_PropagatesError(t *testing.T) { | |||||
| 87 | t.Fatalf("expected error %v, got %v", wantErr, err) | 91 | t.Fatalf("expected error %v, got %v", wantErr, err) | ||
| 88 | } | 92 | } | ||
| 89 | } | 93 | } | ||
| 94 | + | ||||
| 95 | + | func TestPreInitializeAdwaitaForCEF_InitializesAndMarksDetector(t *testing.T) { | |||
| 96 | + | initResult := &bootstrap.ParallelInitResult{ | |||
| 97 | + | AdwaitaDetector: colorscheme.NewAdwaitaDetector(), | |||
| 98 | + | } | |||
| 99 | + | cfg := &config.Config{} | |||
| 100 | + | cfg.Engine.Type = config.EngineTypeCEF | |||
| 101 | + | ||||
| 102 | + | called := false | |||
| 103 | + | preInitializeAdwaitaForCEF(cfg, initResult, func() { | |||
| 104 | + | called = true | |||
| 105 | + | }) | |||
| 106 | + | ||||
| 107 | + | if !called { | |||
| 108 | + | t.Fatal("expected libadwaita initialization for CEF") | |||
| 109 | + | } | |||
| 110 | + | if !initResult.AdwaitaDetector.Available() { | |||
| 111 | + | t.Fatal("expected adwaita detector to be marked available") | |||
| 112 | + | } | |||
| 113 | + | } | |||
| 114 | + | ||||
| 115 | + | func TestPreInitializeAdwaitaForCEF_SkipsNonCEF(t *testing.T) { | |||
| 116 | + | initResult := &bootstrap.ParallelInitResult{ | |||
| 117 | + | AdwaitaDetector: colorscheme.NewAdwaitaDetector(), | |||
| 118 | + | } | |||
| 119 | + | cfg := &config.Config{} | |||
| 120 | + | cfg.Engine.Type = config.EngineTypeWebKit | |||
| 121 | + | ||||
| 122 | + | called := false | |||
| 123 | + | preInitializeAdwaitaForCEF(cfg, initResult, func() { | |||
| 124 | + | called = true | |||
| 125 | + | }) | |||
| 126 | + | ||||
| 127 | + | if called { | |||
| 128 | + | t.Fatal("expected libadwaita initialization to be skipped for non-CEF") | |||
| 129 | + | } | |||
| 130 | + | if initResult.AdwaitaDetector.Available() { | |||
| 131 | + | t.Fatal("expected adwaita detector to remain unavailable") | |||
| 132 | + | } | |||
| 133 | + | } | |||
M go.mod +1 -1
| @@ -3,7 +3,7 @@ module github.com/bnema/dumber | |||
| 3 | 3 | go 1.26.1 | |
| 4 | 4 | ||
| 5 | 5 | require ( | |
| 6 | - | github.com/bnema/purego-cef v0.0.0-00010101000000-000000000000 | |
| 6 | + | github.com/bnema/purego-cef v0.8.0 | |
| 7 | 7 | github.com/bnema/purego-ffmpeg v0.3.0 | |
| 8 | 8 | github.com/bnema/purego-sqlite v0.1.1 | |
| 9 | 9 | github.com/bnema/puregotk v0.3.0 | |
| @@ -3,7 +3,7 @@ module github.com/bnema/dumber | |||||
| 3 | go 1.26.1 | 3 | go 1.26.1 | ||
| 4 | 4 | ||||
| 5 | require ( | 5 | require ( | ||
| 6 | - | github.com/bnema/purego-cef v0.0.0-00010101000000-000000000000 | 6 | + | github.com/bnema/purego-cef v0.8.0 |
| 7 | github.com/bnema/purego-ffmpeg v0.3.0 | 7 | github.com/bnema/purego-ffmpeg v0.3.0 | ||
| 8 | github.com/bnema/purego-sqlite v0.1.1 | 8 | github.com/bnema/purego-sqlite v0.1.1 | ||
| 9 | github.com/bnema/puregotk v0.3.0 | 9 | github.com/bnema/puregotk v0.3.0 | ||
M go.sum +0 -2
| @@ -8,8 +8,6 @@ github.com/bnema/purego v0.0.0-20260323095903-91aa177a2704 h1:0GaiO4102gOdp0es0M | |||
| 8 | 8 | github.com/bnema/purego v0.0.0-20260323095903-91aa177a2704/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= | |
| 9 | 9 | github.com/bnema/purego-sqlite v0.1.1 h1:lH/F6/xxaI+LwWNHv3zof83bDJWQnib9OlNnBo/JnII= | |
| 10 | 10 | github.com/bnema/purego-sqlite v0.1.1/go.mod h1:nRVrkBt8dFOlSGGOOFM/ynlk34TOU1RlOvH4T9KM91s= | |
| 11 | - | github.com/bnema/puregotk v0.2.2 h1:lt9iOwOCHS0X9R4y+SK+zJsbQPGfsfPTyYTuBPWpBKM= | |
| 12 | - | github.com/bnema/puregotk v0.2.2/go.mod h1:Sl24sbCl02M/HLCNUgaYVCckkYcGOi8yxMuGuQVWsL8= | |
| 13 | 11 | github.com/bnema/puregotk v0.3.0 h1:lKdRHkQBxUxE6lmiUJAYYdiUhV0uDq6UoQrVE7a562E= | |
| 14 | 12 | github.com/bnema/puregotk v0.3.0/go.mod h1:Sl24sbCl02M/HLCNUgaYVCckkYcGOi8yxMuGuQVWsL8= | |
| 15 | 13 | github.com/bnema/puregotk-webkit v0.0.16 h1:fYYtRLK3N4YgYmPkHpGZT6W+Mxu4EPu5I25H8nUv9oY= | |
| @@ -8,8 +8,6 @@ github.com/bnema/purego v0.0.0-20260323095903-91aa177a2704 h1:0GaiO4102gOdp0es0M | |||||
| 8 | github.com/bnema/purego v0.0.0-20260323095903-91aa177a2704/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= | 8 | github.com/bnema/purego v0.0.0-20260323095903-91aa177a2704/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= | ||
| 9 | github.com/bnema/purego-sqlite v0.1.1 h1:lH/F6/xxaI+LwWNHv3zof83bDJWQnib9OlNnBo/JnII= | 9 | github.com/bnema/purego-sqlite v0.1.1 h1:lH/F6/xxaI+LwWNHv3zof83bDJWQnib9OlNnBo/JnII= | ||
| 10 | github.com/bnema/purego-sqlite v0.1.1/go.mod h1:nRVrkBt8dFOlSGGOOFM/ynlk34TOU1RlOvH4T9KM91s= | 10 | github.com/bnema/purego-sqlite v0.1.1/go.mod h1:nRVrkBt8dFOlSGGOOFM/ynlk34TOU1RlOvH4T9KM91s= | ||
| 11 | - | github.com/bnema/puregotk v0.2.2 h1:lt9iOwOCHS0X9R4y+SK+zJsbQPGfsfPTyYTuBPWpBKM= | |||
| 12 | - | github.com/bnema/puregotk v0.2.2/go.mod h1:Sl24sbCl02M/HLCNUgaYVCckkYcGOi8yxMuGuQVWsL8= | |||
| 13 | github.com/bnema/puregotk v0.3.0 h1:lKdRHkQBxUxE6lmiUJAYYdiUhV0uDq6UoQrVE7a562E= | 11 | github.com/bnema/puregotk v0.3.0 h1:lKdRHkQBxUxE6lmiUJAYYdiUhV0uDq6UoQrVE7a562E= | ||
| 14 | github.com/bnema/puregotk v0.3.0/go.mod h1:Sl24sbCl02M/HLCNUgaYVCckkYcGOi8yxMuGuQVWsL8= | 12 | github.com/bnema/puregotk v0.3.0/go.mod h1:Sl24sbCl02M/HLCNUgaYVCckkYcGOi8yxMuGuQVWsL8= | ||
| 15 | github.com/bnema/puregotk-webkit v0.0.16 h1:fYYtRLK3N4YgYmPkHpGZT6W+Mxu4EPu5I25H8nUv9oY= | 13 | github.com/bnema/puregotk-webkit v0.0.16 h1:fYYtRLK3N4YgYmPkHpGZT6W+Mxu4EPu5I25H8nUv9oY= | ||
M internal/infrastructure/cef/engine_init.go +6 -2
| @@ -63,6 +63,7 @@ func prepareCEFSettings(cfg config.CEFEngineConfig, logger *zerolog.Logger) pure | |||
| 63 | 63 | settings := purecef.DefaultSettings() | |
| 64 | 64 | settings.MultiThreadedMessageLoop = true | |
| 65 | 65 | settings.ExternalMessagePump = false | |
| 66 | + | settings.RootCachePath = defaultCEFUserDataDir() | |
| 66 | 67 | if cfg.CEFDir != "" { | |
| 67 | 68 | settings.CEFDir = cfg.CEFDir | |
| 68 | 69 | } | |
| @@ -92,6 +93,10 @@ func prepareCEFSettings(cfg config.CEFEngineConfig, logger *zerolog.Logger) pure | |||
| 92 | 93 | return settings | |
| 93 | 94 | } | |
| 94 | 95 | ||
| 96 | + | func defaultCEFUserDataDir() string { | |
| 97 | + | return filepath.Clean(filepath.Join(os.Getenv("HOME"), ".config", "cef_user_data")) | |
| 98 | + | } | |
| 99 | + | ||
| 95 | 100 | // initializeCEF calls cef_initialize with the App to register custom schemes | |
| 96 | 101 | // and browser-process callbacks (OnBeforeCommandLineProcessing, etc.). | |
| 97 | 102 | func initializeCEF(eng *Engine, settings purecef.Settings, logger *zerolog.Logger) error { | |
| @@ -299,8 +304,7 @@ func appendIfMissing(args []string, flag string) []string { | |||
| 299 | 304 | // unclean shutdown (SIGKILL, SIGSEGV) and the next instance crashes trying | |
| 300 | 305 | // to connect to the dead process. | |
| 301 | 306 | func cleanStaleSingletonLocks(logger *zerolog.Logger) { | |
| 302 | - | // CEF defaults to ~/.config/cef_user_data when no root_cache_path is set. | |
| 303 | - | dir := filepath.Clean(filepath.Join(os.Getenv("HOME"), ".config", "cef_user_data")) | |
| 307 | + | dir := defaultCEFUserDataDir() | |
| 304 | 308 | ||
| 305 | 309 | lockPath := filepath.Join(dir, "SingletonLock") | |
| 306 | 310 | target, err := os.Readlink(lockPath) | |
| @@ -63,6 +63,7 @@ func prepareCEFSettings(cfg config.CEFEngineConfig, logger *zerolog.Logger) pure | |||||
| 63 | settings := purecef.DefaultSettings() | 63 | settings := purecef.DefaultSettings() | ||
| 64 | settings.MultiThreadedMessageLoop = true | 64 | settings.MultiThreadedMessageLoop = true | ||
| 65 | settings.ExternalMessagePump = false | 65 | settings.ExternalMessagePump = false | ||
| 66 | + | settings.RootCachePath = defaultCEFUserDataDir() | |||
| 66 | if cfg.CEFDir != "" { | 67 | if cfg.CEFDir != "" { | ||
| 67 | settings.CEFDir = cfg.CEFDir | 68 | settings.CEFDir = cfg.CEFDir | ||
| 68 | } | 69 | } | ||
| @@ -92,6 +93,10 @@ func prepareCEFSettings(cfg config.CEFEngineConfig, logger *zerolog.Logger) pure | |||||
| 92 | return settings | 93 | return settings | ||
| 93 | } | 94 | } | ||
| 94 | 95 | ||||
| 96 | + | func defaultCEFUserDataDir() string { | |||
| 97 | + | return filepath.Clean(filepath.Join(os.Getenv("HOME"), ".config", "cef_user_data")) | |||
| 98 | + | } | |||
| 99 | + | ||||
| 95 | // initializeCEF calls cef_initialize with the App to register custom schemes | 100 | // initializeCEF calls cef_initialize with the App to register custom schemes | ||
| 96 | // and browser-process callbacks (OnBeforeCommandLineProcessing, etc.). | 101 | // and browser-process callbacks (OnBeforeCommandLineProcessing, etc.). | ||
| 97 | func initializeCEF(eng *Engine, settings purecef.Settings, logger *zerolog.Logger) error { | 102 | func initializeCEF(eng *Engine, settings purecef.Settings, logger *zerolog.Logger) error { | ||
| @@ -299,8 +304,7 @@ func appendIfMissing(args []string, flag string) []string { | |||||
| 299 | // unclean shutdown (SIGKILL, SIGSEGV) and the next instance crashes trying | 304 | // unclean shutdown (SIGKILL, SIGSEGV) and the next instance crashes trying | ||
| 300 | // to connect to the dead process. | 305 | // to connect to the dead process. | ||
| 301 | func cleanStaleSingletonLocks(logger *zerolog.Logger) { | 306 | func cleanStaleSingletonLocks(logger *zerolog.Logger) { | ||
| 302 | - | // CEF defaults to ~/.config/cef_user_data when no root_cache_path is set. | 307 | + | dir := defaultCEFUserDataDir() |
| 303 | - | dir := filepath.Clean(filepath.Join(os.Getenv("HOME"), ".config", "cef_user_data")) | |||
| 304 | 308 | ||||
| 305 | lockPath := filepath.Join(dir, "SingletonLock") | 309 | lockPath := filepath.Join(dir, "SingletonLock") | ||
| 306 | target, err := os.Readlink(lockPath) | 310 | target, err := os.Readlink(lockPath) | ||
M internal/infrastructure/cef/engine_init_test.go +11 -0
| @@ -5,6 +5,7 @@ import ( | |||
| 5 | 5 | "testing" | |
| 6 | 6 | ||
| 7 | 7 | "github.com/bnema/dumber/internal/infrastructure/config" | |
| 8 | + | "github.com/rs/zerolog" | |
| 8 | 9 | "github.com/stretchr/testify/require" | |
| 9 | 10 | ) | |
| 10 | 11 | ||
| @@ -27,3 +28,13 @@ func TestPrepareCEFInitTraceFile_EnabledViaEnv(t *testing.T) { | |||
| 27 | 28 | require.Equal(t, filepath.Join(filepath.Dir(cfg.LogFile), "cef_runtime.bootstrap.log"), path) | |
| 28 | 29 | require.FileExists(t, path) | |
| 29 | 30 | } | |
| 31 | + | ||
| 32 | + | func TestPrepareCEFSettings_SetsRootCachePath(t *testing.T) { | |
| 33 | + | homeDir := filepath.Join(t.TempDir(), "home") | |
| 34 | + | t.Setenv("HOME", homeDir) | |
| 35 | + | ||
| 36 | + | logger := zerolog.Nop() | |
| 37 | + | settings := prepareCEFSettings(config.CEFEngineConfig{}, &logger) | |
| 38 | + | ||
| 39 | + | require.Equal(t, filepath.Join(homeDir, ".config", "cef_user_data"), settings.RootCachePath) | |
| 40 | + | } | |
| @@ -5,6 +5,7 @@ import ( | |||||
| 5 | "testing" | 5 | "testing" | ||
| 6 | 6 | ||||
| 7 | "github.com/bnema/dumber/internal/infrastructure/config" | 7 | "github.com/bnema/dumber/internal/infrastructure/config" | ||
| 8 | + | "github.com/rs/zerolog" | |||
| 8 | "github.com/stretchr/testify/require" | 9 | "github.com/stretchr/testify/require" | ||
| 9 | ) | 10 | ) | ||
| 10 | 11 | ||||
| @@ -27,3 +28,13 @@ func TestPrepareCEFInitTraceFile_EnabledViaEnv(t *testing.T) { | |||||
| 27 | require.Equal(t, filepath.Join(filepath.Dir(cfg.LogFile), "cef_runtime.bootstrap.log"), path) | 28 | require.Equal(t, filepath.Join(filepath.Dir(cfg.LogFile), "cef_runtime.bootstrap.log"), path) | ||
| 28 | require.FileExists(t, path) | 29 | require.FileExists(t, path) | ||
| 29 | } | 30 | } | ||
| 31 | + | ||||
| 32 | + | func TestPrepareCEFSettings_SetsRootCachePath(t *testing.T) { | |||
| 33 | + | homeDir := filepath.Join(t.TempDir(), "home") | |||
| 34 | + | t.Setenv("HOME", homeDir) | |||
| 35 | + | ||||
| 36 | + | logger := zerolog.Nop() | |||
| 37 | + | settings := prepareCEFSettings(config.CEFEngineConfig{}, &logger) | |||
| 38 | + | ||||
| 39 | + | require.Equal(t, filepath.Join(homeDir, ".config", "cef_user_data"), settings.RootCachePath) | |||
| 40 | + | } | |||
M internal/ui/standalone_omnibox.go +1 -2
| @@ -9,7 +9,6 @@ import ( | |||
| 9 | 9 | "github.com/bnema/dumber/internal/logging" | |
| 10 | 10 | "github.com/bnema/dumber/internal/ui/component" | |
| 11 | 11 | "github.com/bnema/dumber/internal/ui/layout" | |
| 12 | - | "github.com/bnema/puregotk/v4/adw" | |
| 13 | 12 | "github.com/bnema/puregotk/v4/gdk" | |
| 14 | 13 | "github.com/bnema/puregotk/v4/gio" | |
| 15 | 14 | "github.com/bnema/puregotk/v4/glib" | |
| @@ -345,7 +344,7 @@ func RunStandaloneOmnibox(ctx context.Context, runtimeCfg *StandaloneOmniboxRunt | |||
| 345 | 344 | return 1 | |
| 346 | 345 | } | |
| 347 | 346 | ||
| 348 | - | adw.Init() | |
| 347 | + | EnsureAdwaitaInitialized() | |
| 349 | 348 | windowCfg := DefaultStandaloneOmniboxWindowConfig() | |
| 350 | 349 | appID := windowCfg.Namespace | |
| 351 | 350 | gtkApp := gtk.NewApplication(&appID, gtkApplicationFlags()) | |
| @@ -9,7 +9,6 @@ import ( | |||||
| 9 | "github.com/bnema/dumber/internal/logging" | 9 | "github.com/bnema/dumber/internal/logging" | ||
| 10 | "github.com/bnema/dumber/internal/ui/component" | 10 | "github.com/bnema/dumber/internal/ui/component" | ||
| 11 | "github.com/bnema/dumber/internal/ui/layout" | 11 | "github.com/bnema/dumber/internal/ui/layout" | ||
| 12 | - | "github.com/bnema/puregotk/v4/adw" | |||
| 13 | "github.com/bnema/puregotk/v4/gdk" | 12 | "github.com/bnema/puregotk/v4/gdk" | ||
| 14 | "github.com/bnema/puregotk/v4/gio" | 13 | "github.com/bnema/puregotk/v4/gio" | ||
| 15 | "github.com/bnema/puregotk/v4/glib" | 14 | "github.com/bnema/puregotk/v4/glib" | ||
| @@ -345,7 +344,7 @@ func RunStandaloneOmnibox(ctx context.Context, runtimeCfg *StandaloneOmniboxRunt | |||||
| 345 | return 1 | 344 | return 1 | ||
| 346 | } | 345 | } | ||
| 347 | 346 | ||||
| 348 | - | adw.Init() | 347 | + | EnsureAdwaitaInitialized() |
| 349 | windowCfg := DefaultStandaloneOmniboxWindowConfig() | 348 | windowCfg := DefaultStandaloneOmniboxWindowConfig() | ||
| 350 | appID := windowCfg.Namespace | 349 | appID := windowCfg.Namespace | ||
| 351 | gtkApp := gtk.NewApplication(&appID, gtkApplicationFlags()) | 350 | gtkApp := gtk.NewApplication(&appID, gtkApplicationFlags()) | ||
M internal/ui/theme/css.go +0 -2
| @@ -442,8 +442,6 @@ entry.omnibox-entry.omnibox-entry-bang-active:focus-visible > text { | |||
| 442 | 442 | color: var(--muted); | |
| 443 | 443 | margin-top: -0.0625em; /* Nudge up 1px to align with entry text baseline */ | |
| 444 | 444 | background-color: transparent; | |
| 445 | - | /* Allow clicks to pass through to entry below */ | |
| 446 | - | pointer-events: none; | |
| 447 | 445 | } | |
| 448 | 446 | ` | |
| 449 | 447 | } | |
| @@ -442,8 +442,6 @@ entry.omnibox-entry.omnibox-entry-bang-active:focus-visible > text { | |||||
| 442 | color: var(--muted); | 442 | color: var(--muted); | ||
| 443 | margin-top: -0.0625em; /* Nudge up 1px to align with entry text baseline */ | 443 | margin-top: -0.0625em; /* Nudge up 1px to align with entry text baseline */ | ||
| 444 | background-color: transparent; | 444 | background-color: transparent; | ||
| 445 | - | /* Allow clicks to pass through to entry below */ | |||
| 446 | - | pointer-events: none; | |||
| 447 | } | 445 | } | ||
| 448 | ` | 446 | ` | ||
| 449 | } | 447 | } | ||
M internal/ui/theme/css_test.go +7 -0
| @@ -104,3 +104,10 @@ func TestGenerateCSSWithScale_UsesMediumWeightForOmniboxSuggestionTitle(t *testi | |||
| 104 | 104 | assert.Contains(t, css, "font-weight: 500;") | |
| 105 | 105 | assert.NotContains(t, css, ".omnibox-suggestion-title {\n\tfont-size: 0.875em;\n\tcolor: var(--text);\n\tfont-weight: 400;") | |
| 106 | 106 | } | |
| 107 | + | ||
| 108 | + | func TestGenerateCSS_DoesNotEmitUnsupportedGTKProperties(t *testing.T) { | |
| 109 | + | css := GenerateCSS(DefaultDarkPalette()) | |
| 110 | + | ||
| 111 | + | assert.NotContains(t, css, "pointer-events:") | |
| 112 | + | assert.NotContains(t, css, "text-align:") | |
| 113 | + | } | |
| @@ -104,3 +104,10 @@ func TestGenerateCSSWithScale_UsesMediumWeightForOmniboxSuggestionTitle(t *testi | |||||
| 104 | assert.Contains(t, css, "font-weight: 500;") | 104 | assert.Contains(t, css, "font-weight: 500;") | ||
| 105 | assert.NotContains(t, css, ".omnibox-suggestion-title {\n\tfont-size: 0.875em;\n\tcolor: var(--text);\n\tfont-weight: 400;") | 105 | assert.NotContains(t, css, ".omnibox-suggestion-title {\n\tfont-size: 0.875em;\n\tcolor: var(--text);\n\tfont-weight: 400;") | ||
| 106 | } | 106 | } | ||
| 107 | + | ||||
| 108 | + | func TestGenerateCSS_DoesNotEmitUnsupportedGTKProperties(t *testing.T) { | |||
| 109 | + | css := GenerateCSS(DefaultDarkPalette()) | |||
| 110 | + | ||||
| 111 | + | assert.NotContains(t, css, "pointer-events:") | |||
| 112 | + | assert.NotContains(t, css, "text-align:") | |||
| 113 | + | } | |||
M internal/ui/theme/webrtc_indicator_css.go +0 -1
| @@ -76,7 +76,6 @@ func generateWebRTCPermissionIndicatorCSS(p Palette) string { | |||
| 76 | 76 | background-color: alpha(var(--bg), 0.35); | |
| 77 | 77 | background-image: none; | |
| 78 | 78 | color: var(--muted); | |
| 79 | - | text-align: left; | |
| 80 | 79 | transition: background-color 150ms ease-in-out, | |
| 81 | 80 | border-color 150ms ease-in-out, | |
| 82 | 81 | color 150ms ease-in-out; | |
| @@ -76,7 +76,6 @@ func generateWebRTCPermissionIndicatorCSS(p Palette) string { | |||||
| 76 | background-color: alpha(var(--bg), 0.35); | 76 | background-color: alpha(var(--bg), 0.35); | ||
| 77 | background-image: none; | 77 | background-image: none; | ||
| 78 | color: var(--muted); | 78 | color: var(--muted); | ||
| 79 | - | text-align: left; | |||
| 80 | transition: background-color 150ms ease-in-out, | 79 | transition: background-color 150ms ease-in-out, | ||
| 81 | border-color 150ms ease-in-out, | 80 | border-color 150ms ease-in-out, | ||
| 82 | color 150ms ease-in-out; | 81 | color 150ms ease-in-out; | ||