refactor(ui): split app activation into helpers
- commit
- 04b95bc45e761cbcd96864e35390981d70b5c509
- author
- brice · · 2025-12-22 06:47 UTC
- parent
- 83d1d24
- signature
- unsigned
1 file · +126 -52
M internal/ui/app.go +126 -52
| @@ -166,74 +166,127 @@ func (a *App) onActivate(ctx context.Context) { | |||
| 166 | 166 | log := logging.FromContext(ctx) | |
| 167 | 167 | log.Debug().Msg("GTK application activated") | |
| 168 | 168 | ||
| 169 | + | a.applyGTKColorSchemePreference(ctx) | |
| 170 | + | a.prewarmWebViewPool(ctx) | |
| 171 | + | ||
| 172 | + | if err := a.createMainWindow(ctx); err != nil { | |
| 173 | + | log.Error().Err(err).Msg("failed to create main window") | |
| 174 | + | return | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | a.initLayoutInfrastructure() | |
| 178 | + | a.initAppToasterOverlay() | |
| 179 | + | a.initFocusAndBorderOverlay() | |
| 180 | + | ||
| 181 | + | a.initCoordinators(ctx) | |
| 182 | + | a.initKeyboardHandler(ctx) | |
| 183 | + | a.initOmniboxConfig(ctx) | |
| 184 | + | a.initFindBarConfig() | |
| 185 | + | a.createInitialTab(ctx) | |
| 186 | + | a.finalizeActivation(ctx) | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | func (a *App) applyGTKColorSchemePreference(ctx context.Context) { | |
| 190 | + | log := logging.FromContext(ctx) | |
| 191 | + | ||
| 169 | 192 | // Propagate app color scheme preference to GTK (and WebKit) | |
| 170 | 193 | // so web content can correctly evaluate prefers-color-scheme. | |
| 171 | - | if settings := gtk.SettingsGetDefault(); settings != nil { | |
| 172 | - | scheme := "default" | |
| 173 | - | if a.deps != nil && a.deps.Config != nil && a.deps.Config.Appearance.ColorScheme != "" { | |
| 174 | - | scheme = a.deps.Config.Appearance.ColorScheme | |
| 175 | - | } | |
| 176 | - | prefersDark := theme.ResolveColorScheme(scheme) | |
| 177 | - | settings.SetPropertyGtkApplicationPreferDarkTheme(prefersDark) | |
| 178 | - | log.Debug(). | |
| 179 | - | Str("scheme", scheme). | |
| 180 | - | Bool("prefers_dark", prefersDark). | |
| 181 | - | Msg("set gtk-application-prefer-dark-theme") | |
| 194 | + | settings := gtk.SettingsGetDefault() | |
| 195 | + | if settings == nil { | |
| 196 | + | return | |
| 182 | 197 | } | |
| 183 | 198 | ||
| 184 | - | // Prewarm WebView pool now that GTK is initialized | |
| 185 | - | if a.pool != nil { | |
| 186 | - | a.pool.Prewarm(ctx, 0) | |
| 199 | + | scheme := "default" | |
| 200 | + | if a.deps != nil && a.deps.Config != nil && a.deps.Config.Appearance.ColorScheme != "" { | |
| 201 | + | scheme = a.deps.Config.Appearance.ColorScheme | |
| 187 | 202 | } | |
| 203 | + | prefersDark := theme.ResolveColorScheme(scheme) | |
| 204 | + | settings.SetPropertyGtkApplicationPreferDarkTheme(prefersDark) | |
| 205 | + | log.Debug(). | |
| 206 | + | Str("scheme", scheme). | |
| 207 | + | Bool("prefers_dark", prefersDark). | |
| 208 | + | Msg("set gtk-application-prefer-dark-theme") | |
| 209 | + | } | |
| 188 | 210 | ||
| 189 | - | // Create the main window | |
| 190 | - | var err error | |
| 191 | - | a.mainWindow, err = window.New(ctx, a.gtkApp, a.deps.Config) | |
| 192 | - | if err != nil { | |
| 193 | - | log.Error().Err(err).Msg("failed to create main window") | |
| 211 | + | func (a *App) prewarmWebViewPool(ctx context.Context) { | |
| 212 | + | // Prewarm WebView pool now that GTK is initialized. | |
| 213 | + | if a.pool == nil { | |
| 194 | 214 | return | |
| 195 | 215 | } | |
| 216 | + | a.pool.Prewarm(ctx, 0) | |
| 217 | + | } | |
| 196 | 218 | ||
| 197 | - | // Apply GTK CSS styling from theme manager | |
| 198 | - | if a.deps.Theme != nil { | |
| 199 | - | if display := a.mainWindow.Window().GetDisplay(); display != nil { | |
| 200 | - | a.deps.Theme.ApplyToDisplay(ctx, display) | |
| 201 | - | } | |
| 219 | + | func (a *App) createMainWindow(ctx context.Context) error { | |
| 220 | + | mainWindow, err := window.New(ctx, a.gtkApp, a.deps.Config) | |
| 221 | + | if err != nil { | |
| 222 | + | return err | |
| 202 | 223 | } | |
| 224 | + | a.mainWindow = mainWindow | |
| 203 | 225 | ||
| 204 | - | // Initialize widget factory for pane layout | |
| 226 | + | // Apply GTK CSS styling from theme manager. | |
| 227 | + | if a.deps == nil || a.deps.Theme == nil { | |
| 228 | + | return nil | |
| 229 | + | } | |
| 230 | + | if display := a.mainWindow.Window().GetDisplay(); display != nil { | |
| 231 | + | a.deps.Theme.ApplyToDisplay(ctx, display) | |
| 232 | + | } | |
| 233 | + | return nil | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | func (a *App) initLayoutInfrastructure() { | |
| 237 | + | // Initialize widget factory for pane layout. | |
| 205 | 238 | a.widgetFactory = layout.NewGtkWidgetFactory() | |
| 206 | 239 | ||
| 207 | - | // Initialize stacked pane manager for incremental widget operations | |
| 240 | + | // Initialize stacked pane manager for incremental widget operations. | |
| 208 | 241 | a.stackedPaneMgr = component.NewStackedPaneManager(a.widgetFactory) | |
| 242 | + | } | |
| 209 | 243 | ||
| 210 | - | // Create app-level toaster for system notifications | |
| 244 | + | func (a *App) initAppToasterOverlay() { | |
| 245 | + | if a.mainWindow == nil { | |
| 246 | + | return | |
| 247 | + | } | |
| 248 | + | ||
| 249 | + | // Create app-level toaster for system notifications. | |
| 211 | 250 | a.appToaster = component.NewToaster(a.widgetFactory) | |
| 212 | - | if toasterWidget := a.appToaster.Widget(); toasterWidget != nil { | |
| 213 | - | if gtkWidget := toasterWidget.GtkWidget(); gtkWidget != nil { | |
| 214 | - | a.mainWindow.AddOverlay(gtkWidget) | |
| 215 | - | } | |
| 251 | + | toasterWidget := a.appToaster.Widget() | |
| 252 | + | if toasterWidget == nil { | |
| 253 | + | return | |
| 216 | 254 | } | |
| 255 | + | gtkWidget := toasterWidget.GtkWidget() | |
| 256 | + | if gtkWidget == nil { | |
| 257 | + | return | |
| 258 | + | } | |
| 259 | + | a.mainWindow.AddOverlay(gtkWidget) | |
| 260 | + | } | |
| 217 | 261 | ||
| 218 | - | // Initialize focus manager for geometric navigation | |
| 262 | + | func (a *App) initFocusAndBorderOverlay() { | |
| 263 | + | // Initialize focus manager for geometric navigation. | |
| 219 | 264 | a.focusMgr = focus.NewManager(a.panesUC) | |
| 220 | 265 | ||
| 221 | - | // Initialize border manager for mode indicators | |
| 266 | + | // Initialize border manager for mode indicators. | |
| 222 | 267 | a.borderMgr = focus.NewBorderManager(a.widgetFactory) | |
| 223 | 268 | ||
| 224 | - | // Attach border overlay to main window (visible for all tabs) | |
| 225 | - | if a.borderMgr != nil && a.mainWindow != nil { | |
| 226 | - | if borderWidget := a.borderMgr.Widget(); borderWidget != nil { | |
| 227 | - | if gtkWidget := borderWidget.GtkWidget(); gtkWidget != nil { | |
| 228 | - | a.mainWindow.AddOverlay(gtkWidget) | |
| 229 | - | } | |
| 230 | - | } | |
| 269 | + | // Attach border overlay to main window (visible for all tabs). | |
| 270 | + | if a.borderMgr == nil || a.mainWindow == nil { | |
| 271 | + | return | |
| 272 | + | } | |
| 273 | + | borderWidget := a.borderMgr.Widget() | |
| 274 | + | if borderWidget == nil { | |
| 275 | + | return | |
| 276 | + | } | |
| 277 | + | gtkWidget := borderWidget.GtkWidget() | |
| 278 | + | if gtkWidget == nil { | |
| 279 | + | return | |
| 231 | 280 | } | |
| 281 | + | a.mainWindow.AddOverlay(gtkWidget) | |
| 282 | + | } | |
| 232 | 283 | ||
| 233 | - | // Initialize coordinators | |
| 234 | - | a.initCoordinators(ctx) | |
| 284 | + | func (a *App) initKeyboardHandler(ctx context.Context) { | |
| 285 | + | if a.mainWindow == nil || a.deps == nil || a.deps.Config == nil { | |
| 286 | + | return | |
| 287 | + | } | |
| 235 | 288 | ||
| 236 | - | // Create keyboard handler and wire to dispatcher | |
| 289 | + | // Create keyboard handler and wire to dispatcher. | |
| 237 | 290 | a.keyboardHandler = input.NewKeyboardHandler( | |
| 238 | 291 | ctx, | |
| 239 | 292 | &a.deps.Config.Workspace, | |
| @@ -252,8 +305,16 @@ func (a *App) onActivate(ctx context.Context) { | |||
| 252 | 305 | return wsView.IsOmniboxVisible() | |
| 253 | 306 | }) | |
| 254 | 307 | a.keyboardHandler.AttachTo(a.mainWindow.Window()) | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | func (a *App) initOmniboxConfig(ctx context.Context) { | |
| 311 | + | if a.deps == nil || a.deps.Config == nil { | |
| 312 | + | return | |
| 313 | + | } | |
| 255 | 314 | ||
| 256 | - | // Store omnibox config (omnibox is created per-pane via WorkspaceView) | |
| 315 | + | log := logging.FromContext(ctx) | |
| 316 | + | ||
| 317 | + | // Store omnibox config (omnibox is created per-pane via WorkspaceView). | |
| 257 | 318 | a.omniboxCfg = component.OmniboxConfig{ | |
| 258 | 319 | HistoryUC: a.deps.HistoryUC, | |
| 259 | 320 | FavoritesUC: a.deps.FavoritesUC, | |
| @@ -271,8 +332,10 @@ func (a *App) onActivate(ctx context.Context) { | |||
| 271 | 332 | } | |
| 272 | 333 | a.navCoord.SetOmniboxProvider(a) | |
| 273 | 334 | log.Debug().Msg("omnibox config stored, provider set") | |
| 335 | + | } | |
| 274 | 336 | ||
| 275 | - | // Store find bar config (find bar is created per-pane via WorkspaceView) | |
| 337 | + | func (a *App) initFindBarConfig() { | |
| 338 | + | // Store find bar config (find bar is created per-pane via WorkspaceView). | |
| 276 | 339 | a.findBarCfg = component.FindBarConfig{ | |
| 277 | 340 | GetFindController: func(paneID entity.PaneID) port.FindController { | |
| 278 | 341 | if a.contentCoord == nil { | |
| @@ -285,29 +348,40 @@ func (a *App) onActivate(ctx context.Context) { | |||
| 285 | 348 | return wv.GetFindController() | |
| 286 | 349 | }, | |
| 287 | 350 | } | |
| 351 | + | } | |
| 288 | 352 | ||
| 289 | - | // Create an initial tab using coordinator | |
| 353 | + | func (a *App) createInitialTab(ctx context.Context) { | |
| 354 | + | log := logging.FromContext(ctx) | |
| 355 | + | ||
| 356 | + | // Create an initial tab using coordinator. | |
| 290 | 357 | initialURL := "dumb://home" | |
| 291 | - | if a.deps.InitialURL != "" { | |
| 358 | + | if a.deps != nil && a.deps.InitialURL != "" { | |
| 292 | 359 | initialURL = a.deps.InitialURL | |
| 293 | 360 | } | |
| 294 | 361 | if _, err := a.tabCoord.Create(ctx, initialURL); err != nil { | |
| 295 | 362 | log.Error().Err(err).Msg("failed to create initial tab") | |
| 296 | 363 | } | |
| 364 | + | } | |
| 297 | 365 | ||
| 298 | - | // Show the window | |
| 299 | - | a.mainWindow.Show() | |
| 366 | + | func (a *App) finalizeActivation(ctx context.Context) { | |
| 367 | + | log := logging.FromContext(ctx) | |
| 300 | 368 | ||
| 369 | + | // Show the window. | |
| 370 | + | if a.mainWindow != nil { | |
| 371 | + | a.mainWindow.Show() | |
| 372 | + | } | |
| 301 | 373 | log.Info().Msg("main window displayed") | |
| 302 | 374 | ||
| 303 | - | // Start watching config for appearance changes | |
| 375 | + | // Start watching config for appearance changes. | |
| 304 | 376 | a.initConfigWatcher(ctx) | |
| 305 | 377 | ||
| 306 | 378 | // Ensure the current appearance config is applied once at startup. | |
| 307 | 379 | // This avoids the WebUI showing default tokens until the first config change event. | |
| 308 | - | a.applyAppearanceConfig(ctx, a.deps.Config) | |
| 380 | + | if a.deps != nil { | |
| 381 | + | a.applyAppearanceConfig(ctx, a.deps.Config) | |
| 382 | + | } | |
| 309 | 383 | ||
| 310 | - | // Start async filter loading after window is visible | |
| 384 | + | // Start async filter loading after window is visible. | |
| 311 | 385 | a.initFilteringAsync(ctx) | |
| 312 | 386 | } | |
| 313 | 387 | ||
| @@ -166,74 +166,127 @@ func (a *App) onActivate(ctx context.Context) { | |||||
| 166 | log := logging.FromContext(ctx) | 166 | log := logging.FromContext(ctx) | ||
| 167 | log.Debug().Msg("GTK application activated") | 167 | log.Debug().Msg("GTK application activated") | ||
| 168 | 168 | ||||
| 169 | + | a.applyGTKColorSchemePreference(ctx) | |||
| 170 | + | a.prewarmWebViewPool(ctx) | |||
| 171 | + | ||||
| 172 | + | if err := a.createMainWindow(ctx); err != nil { | |||
| 173 | + | log.Error().Err(err).Msg("failed to create main window") | |||
| 174 | + | return | |||
| 175 | + | } | |||
| 176 | + | ||||
| 177 | + | a.initLayoutInfrastructure() | |||
| 178 | + | a.initAppToasterOverlay() | |||
| 179 | + | a.initFocusAndBorderOverlay() | |||
| 180 | + | ||||
| 181 | + | a.initCoordinators(ctx) | |||
| 182 | + | a.initKeyboardHandler(ctx) | |||
| 183 | + | a.initOmniboxConfig(ctx) | |||
| 184 | + | a.initFindBarConfig() | |||
| 185 | + | a.createInitialTab(ctx) | |||
| 186 | + | a.finalizeActivation(ctx) | |||
| 187 | + | } | |||
| 188 | + | ||||
| 189 | + | func (a *App) applyGTKColorSchemePreference(ctx context.Context) { | |||
| 190 | + | log := logging.FromContext(ctx) | |||
| 191 | + | ||||
| 169 | // Propagate app color scheme preference to GTK (and WebKit) | 192 | // Propagate app color scheme preference to GTK (and WebKit) | ||
| 170 | // so web content can correctly evaluate prefers-color-scheme. | 193 | // so web content can correctly evaluate prefers-color-scheme. | ||
| 171 | - | if settings := gtk.SettingsGetDefault(); settings != nil { | 194 | + | settings := gtk.SettingsGetDefault() |
| 172 | - | scheme := "default" | 195 | + | if settings == nil { |
| 173 | - | if a.deps != nil && a.deps.Config != nil && a.deps.Config.Appearance.ColorScheme != "" { | 196 | + | return |
| 174 | - | scheme = a.deps.Config.Appearance.ColorScheme | |||
| 175 | - | } | |||
| 176 | - | prefersDark := theme.ResolveColorScheme(scheme) | |||
| 177 | - | settings.SetPropertyGtkApplicationPreferDarkTheme(prefersDark) | |||
| 178 | - | log.Debug(). | |||
| 179 | - | Str("scheme", scheme). | |||
| 180 | - | Bool("prefers_dark", prefersDark). | |||
| 181 | - | Msg("set gtk-application-prefer-dark-theme") | |||
| 182 | } | 197 | } | ||
| 183 | 198 | ||||
| 184 | - | // Prewarm WebView pool now that GTK is initialized | 199 | + | scheme := "default" |
| 185 | - | if a.pool != nil { | 200 | + | if a.deps != nil && a.deps.Config != nil && a.deps.Config.Appearance.ColorScheme != "" { |
| 186 | - | a.pool.Prewarm(ctx, 0) | 201 | + | scheme = a.deps.Config.Appearance.ColorScheme |
| 187 | } | 202 | } | ||
| 203 | + | prefersDark := theme.ResolveColorScheme(scheme) | |||
| 204 | + | settings.SetPropertyGtkApplicationPreferDarkTheme(prefersDark) | |||
| 205 | + | log.Debug(). | |||
| 206 | + | Str("scheme", scheme). | |||
| 207 | + | Bool("prefers_dark", prefersDark). | |||
| 208 | + | Msg("set gtk-application-prefer-dark-theme") | |||
| 209 | + | } | |||
| 188 | 210 | ||||
| 189 | - | // Create the main window | 211 | + | func (a *App) prewarmWebViewPool(ctx context.Context) { |
| 190 | - | var err error | 212 | + | // Prewarm WebView pool now that GTK is initialized. |
| 191 | - | a.mainWindow, err = window.New(ctx, a.gtkApp, a.deps.Config) | 213 | + | if a.pool == nil { |
| 192 | - | if err != nil { | |||
| 193 | - | log.Error().Err(err).Msg("failed to create main window") | |||
| 194 | return | 214 | return | ||
| 195 | } | 215 | } | ||
| 216 | + | a.pool.Prewarm(ctx, 0) | |||
| 217 | + | } | |||
| 196 | 218 | ||||
| 197 | - | // Apply GTK CSS styling from theme manager | 219 | + | func (a *App) createMainWindow(ctx context.Context) error { |
| 198 | - | if a.deps.Theme != nil { | 220 | + | mainWindow, err := window.New(ctx, a.gtkApp, a.deps.Config) |
| 199 | - | if display := a.mainWindow.Window().GetDisplay(); display != nil { | 221 | + | if err != nil { |
| 200 | - | a.deps.Theme.ApplyToDisplay(ctx, display) | 222 | + | return err |
| 201 | - | } | |||
| 202 | } | 223 | } | ||
| 224 | + | a.mainWindow = mainWindow | |||
| 203 | 225 | ||||
| 204 | - | // Initialize widget factory for pane layout | 226 | + | // Apply GTK CSS styling from theme manager. |
| 227 | + | if a.deps == nil || a.deps.Theme == nil { | |||
| 228 | + | return nil | |||
| 229 | + | } | |||
| 230 | + | if display := a.mainWindow.Window().GetDisplay(); display != nil { | |||
| 231 | + | a.deps.Theme.ApplyToDisplay(ctx, display) | |||
| 232 | + | } | |||
| 233 | + | return nil | |||
| 234 | + | } | |||
| 235 | + | ||||
| 236 | + | func (a *App) initLayoutInfrastructure() { | |||
| 237 | + | // Initialize widget factory for pane layout. | |||
| 205 | a.widgetFactory = layout.NewGtkWidgetFactory() | 238 | a.widgetFactory = layout.NewGtkWidgetFactory() | ||
| 206 | 239 | ||||
| 207 | - | // Initialize stacked pane manager for incremental widget operations | 240 | + | // Initialize stacked pane manager for incremental widget operations. |
| 208 | a.stackedPaneMgr = component.NewStackedPaneManager(a.widgetFactory) | 241 | a.stackedPaneMgr = component.NewStackedPaneManager(a.widgetFactory) | ||
| 242 | + | } | |||
| 209 | 243 | ||||
| 210 | - | // Create app-level toaster for system notifications | 244 | + | func (a *App) initAppToasterOverlay() { |
| 245 | + | if a.mainWindow == nil { | |||
| 246 | + | return | |||
| 247 | + | } | |||
| 248 | + | ||||
| 249 | + | // Create app-level toaster for system notifications. | |||
| 211 | a.appToaster = component.NewToaster(a.widgetFactory) | 250 | a.appToaster = component.NewToaster(a.widgetFactory) | ||
| 212 | - | if toasterWidget := a.appToaster.Widget(); toasterWidget != nil { | 251 | + | toasterWidget := a.appToaster.Widget() |
| 213 | - | if gtkWidget := toasterWidget.GtkWidget(); gtkWidget != nil { | 252 | + | if toasterWidget == nil { |
| 214 | - | a.mainWindow.AddOverlay(gtkWidget) | 253 | + | return |
| 215 | - | } | |||
| 216 | } | 254 | } | ||
| 255 | + | gtkWidget := toasterWidget.GtkWidget() | |||
| 256 | + | if gtkWidget == nil { | |||
| 257 | + | return | |||
| 258 | + | } | |||
| 259 | + | a.mainWindow.AddOverlay(gtkWidget) | |||
| 260 | + | } | |||
| 217 | 261 | ||||
| 218 | - | // Initialize focus manager for geometric navigation | 262 | + | func (a *App) initFocusAndBorderOverlay() { |
| 263 | + | // Initialize focus manager for geometric navigation. | |||
| 219 | a.focusMgr = focus.NewManager(a.panesUC) | 264 | a.focusMgr = focus.NewManager(a.panesUC) | ||
| 220 | 265 | ||||
| 221 | - | // Initialize border manager for mode indicators | 266 | + | // Initialize border manager for mode indicators. |
| 222 | a.borderMgr = focus.NewBorderManager(a.widgetFactory) | 267 | a.borderMgr = focus.NewBorderManager(a.widgetFactory) | ||
| 223 | 268 | ||||
| 224 | - | // Attach border overlay to main window (visible for all tabs) | 269 | + | // Attach border overlay to main window (visible for all tabs). |
| 225 | - | if a.borderMgr != nil && a.mainWindow != nil { | 270 | + | if a.borderMgr == nil || a.mainWindow == nil { |
| 226 | - | if borderWidget := a.borderMgr.Widget(); borderWidget != nil { | 271 | + | return |
| 227 | - | if gtkWidget := borderWidget.GtkWidget(); gtkWidget != nil { | 272 | + | } |
| 228 | - | a.mainWindow.AddOverlay(gtkWidget) | 273 | + | borderWidget := a.borderMgr.Widget() |
| 229 | - | } | 274 | + | if borderWidget == nil { |
| 230 | - | } | 275 | + | return |
| 276 | + | } | |||
| 277 | + | gtkWidget := borderWidget.GtkWidget() | |||
| 278 | + | if gtkWidget == nil { | |||
| 279 | + | return | |||
| 231 | } | 280 | } | ||
| 281 | + | a.mainWindow.AddOverlay(gtkWidget) | |||
| 282 | + | } | |||
| 232 | 283 | ||||
| 233 | - | // Initialize coordinators | 284 | + | func (a *App) initKeyboardHandler(ctx context.Context) { |
| 234 | - | a.initCoordinators(ctx) | 285 | + | if a.mainWindow == nil || a.deps == nil || a.deps.Config == nil { |
| 286 | + | return | |||
| 287 | + | } | |||
| 235 | 288 | ||||
| 236 | - | // Create keyboard handler and wire to dispatcher | 289 | + | // Create keyboard handler and wire to dispatcher. |
| 237 | a.keyboardHandler = input.NewKeyboardHandler( | 290 | a.keyboardHandler = input.NewKeyboardHandler( | ||
| 238 | ctx, | 291 | ctx, | ||
| 239 | &a.deps.Config.Workspace, | 292 | &a.deps.Config.Workspace, | ||
| @@ -252,8 +305,16 @@ func (a *App) onActivate(ctx context.Context) { | |||||
| 252 | return wsView.IsOmniboxVisible() | 305 | return wsView.IsOmniboxVisible() | ||
| 253 | }) | 306 | }) | ||
| 254 | a.keyboardHandler.AttachTo(a.mainWindow.Window()) | 307 | a.keyboardHandler.AttachTo(a.mainWindow.Window()) | ||
| 308 | + | } | |||
| 309 | + | ||||
| 310 | + | func (a *App) initOmniboxConfig(ctx context.Context) { | |||
| 311 | + | if a.deps == nil || a.deps.Config == nil { | |||
| 312 | + | return | |||
| 313 | + | } | |||
| 255 | 314 | ||||
| 256 | - | // Store omnibox config (omnibox is created per-pane via WorkspaceView) | 315 | + | log := logging.FromContext(ctx) |
| 316 | + | ||||
| 317 | + | // Store omnibox config (omnibox is created per-pane via WorkspaceView). | |||
| 257 | a.omniboxCfg = component.OmniboxConfig{ | 318 | a.omniboxCfg = component.OmniboxConfig{ | ||
| 258 | HistoryUC: a.deps.HistoryUC, | 319 | HistoryUC: a.deps.HistoryUC, | ||
| 259 | FavoritesUC: a.deps.FavoritesUC, | 320 | FavoritesUC: a.deps.FavoritesUC, | ||
| @@ -271,8 +332,10 @@ func (a *App) onActivate(ctx context.Context) { | |||||
| 271 | } | 332 | } | ||
| 272 | a.navCoord.SetOmniboxProvider(a) | 333 | a.navCoord.SetOmniboxProvider(a) | ||
| 273 | log.Debug().Msg("omnibox config stored, provider set") | 334 | log.Debug().Msg("omnibox config stored, provider set") | ||
| 335 | + | } | |||
| 274 | 336 | ||||
| 275 | - | // Store find bar config (find bar is created per-pane via WorkspaceView) | 337 | + | func (a *App) initFindBarConfig() { |
| 338 | + | // Store find bar config (find bar is created per-pane via WorkspaceView). | |||
| 276 | a.findBarCfg = component.FindBarConfig{ | 339 | a.findBarCfg = component.FindBarConfig{ | ||
| 277 | GetFindController: func(paneID entity.PaneID) port.FindController { | 340 | GetFindController: func(paneID entity.PaneID) port.FindController { | ||
| 278 | if a.contentCoord == nil { | 341 | if a.contentCoord == nil { | ||
| @@ -285,29 +348,40 @@ func (a *App) onActivate(ctx context.Context) { | |||||
| 285 | return wv.GetFindController() | 348 | return wv.GetFindController() | ||
| 286 | }, | 349 | }, | ||
| 287 | } | 350 | } | ||
| 351 | + | } | |||
| 288 | 352 | ||||
| 289 | - | // Create an initial tab using coordinator | 353 | + | func (a *App) createInitialTab(ctx context.Context) { |
| 354 | + | log := logging.FromContext(ctx) | |||
| 355 | + | ||||
| 356 | + | // Create an initial tab using coordinator. | |||
| 290 | initialURL := "dumb://home" | 357 | initialURL := "dumb://home" | ||
| 291 | - | if a.deps.InitialURL != "" { | 358 | + | if a.deps != nil && a.deps.InitialURL != "" { |
| 292 | initialURL = a.deps.InitialURL | 359 | initialURL = a.deps.InitialURL | ||
| 293 | } | 360 | } | ||
| 294 | if _, err := a.tabCoord.Create(ctx, initialURL); err != nil { | 361 | if _, err := a.tabCoord.Create(ctx, initialURL); err != nil { | ||
| 295 | log.Error().Err(err).Msg("failed to create initial tab") | 362 | log.Error().Err(err).Msg("failed to create initial tab") | ||
| 296 | } | 363 | } | ||
| 364 | + | } | |||
| 297 | 365 | ||||
| 298 | - | // Show the window | 366 | + | func (a *App) finalizeActivation(ctx context.Context) { |
| 299 | - | a.mainWindow.Show() | 367 | + | log := logging.FromContext(ctx) |
| 300 | 368 | ||||
| 369 | + | // Show the window. | |||
| 370 | + | if a.mainWindow != nil { | |||
| 371 | + | a.mainWindow.Show() | |||
| 372 | + | } | |||
| 301 | log.Info().Msg("main window displayed") | 373 | log.Info().Msg("main window displayed") | ||
| 302 | 374 | ||||
| 303 | - | // Start watching config for appearance changes | 375 | + | // Start watching config for appearance changes. |
| 304 | a.initConfigWatcher(ctx) | 376 | a.initConfigWatcher(ctx) | ||
| 305 | 377 | ||||
| 306 | // Ensure the current appearance config is applied once at startup. | 378 | // Ensure the current appearance config is applied once at startup. | ||
| 307 | // This avoids the WebUI showing default tokens until the first config change event. | 379 | // This avoids the WebUI showing default tokens until the first config change event. | ||
| 308 | - | a.applyAppearanceConfig(ctx, a.deps.Config) | 380 | + | if a.deps != nil { |
| 381 | + | a.applyAppearanceConfig(ctx, a.deps.Config) | |||
| 382 | + | } | |||
| 309 | 383 | ||||
| 310 | - | // Start async filter loading after window is visible | 384 | + | // Start async filter loading after window is visible. |
| 311 | a.initFilteringAsync(ctx) | 385 | a.initFilteringAsync(ctx) | ||
| 312 | } | 386 | } | ||
| 313 | 387 | ||||