From d6a8ebe7d3493872f4b512c834aca1533aea6e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Tue, 18 Aug 2026 15:17:51 +0200 Subject: [PATCH] [client] Seed a cold main window with its target URL ShowMainAt created the main window with URL "/" and navigated with SetURL right after; if the initial load is dispatched asynchronously the two can race and strand the user on "/". The main-window factory now takes the start URL, so a cold window is built directly on the requested page and SetURL only runs on an already-live window. --- client/ui/main.go | 8 ++++---- client/ui/services/windowmanager.go | 30 ++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/client/ui/main.go b/client/ui/main.go index 1861177eb..e20bfe074 100644 --- a/client/ui/main.go +++ b/client/ui/main.go @@ -140,8 +140,8 @@ func main() { }) windowManager := services.NewWindowManager(app, nil, bundle, prefStore, iconWindow) - windowManager.SetMainFactory(func() *application.WebviewWindow { - return newMainWindow(app, prefStore, windowManager) + windowManager.SetMainFactory(func(startURL string) *application.WebviewWindow { + return newMainWindow(app, prefStore, windowManager, startURL) }) registerDockReopenHook(app, windowManager) // Minimal WMs (XEmbed-tray path) neither center small windows nor restore @@ -338,7 +338,7 @@ func registerServices(app *application.App, conn *Conn, s registeredServices) { app.RegisterService(application.NewService(s.compat)) } -func newMainWindow(app *application.App, prefStore *preferences.Store, wm *services.WindowManager) *application.WebviewWindow { +func newMainWindow(app *application.App, prefStore *preferences.Store, wm *services.WindowManager, startURL string) *application.WebviewWindow { // Width matches the last view mode so Advanced-mode users don't see the // window pop from 380px to 900px on launch. Height is mode-agnostic. initialWidth := 380 @@ -355,7 +355,7 @@ func newMainWindow(app *application.App, prefStore *preferences.Store, wm *servi InitialPosition: application.WindowCentered, Hidden: true, BackgroundColour: services.WindowBackgroundColour, - URL: "/", + URL: startURL, DisableResize: true, MinimiseButtonState: application.ButtonHidden, MaximiseButtonState: application.ButtonHidden, diff --git a/client/ui/services/windowmanager.go b/client/ui/services/windowmanager.go index ba69a597b..69f76034d 100644 --- a/client/ui/services/windowmanager.go +++ b/client/ui/services/windowmanager.go @@ -115,7 +115,7 @@ type WindowManager struct { hiddenForLogin []application.Window mu sync.Mutex createMu sync.Mutex - newMain func() *application.WebviewWindow + newMain func(startURL string) *application.WebviewWindow ready map[uint]bool showPending map[uint]bool pendingTab map[uint]string @@ -192,7 +192,7 @@ func (s *WindowManager) OpenSettings(tab string) { target = "general" } - w := s.ensureWindow(&s.settings, s.newSettingsWindow) + w, _ := s.ensureWindow(&s.settings, s.newSettingsWindow) s.mu.Lock() ready := s.ready[w.ID()] @@ -494,13 +494,23 @@ func (s *WindowManager) ShowMainAndEmit(event string) { } func (s *WindowManager) MainWindow() *application.WebviewWindow { + w, _ := s.ensureMain("/") + return w +} + +func (s *WindowManager) ensureMain(startURL string) (*application.WebviewWindow, bool) { s.mu.Lock() factory := s.newMain s.mu.Unlock() - return s.ensureWindow(&s.mainWindow, factory) + if factory == nil { + return s.ensureWindow(&s.mainWindow, nil) + } + return s.ensureWindow(&s.mainWindow, func() *application.WebviewWindow { + return factory(startURL) + }) } -func (s *WindowManager) ensureWindow(slot **application.WebviewWindow, factory func() *application.WebviewWindow) *application.WebviewWindow { +func (s *WindowManager) ensureWindow(slot **application.WebviewWindow, factory func() *application.WebviewWindow) (*application.WebviewWindow, bool) { s.createMu.Lock() defer s.createMu.Unlock() @@ -508,7 +518,7 @@ func (s *WindowManager) ensureWindow(slot **application.WebviewWindow, factory f w := *slot s.mu.Unlock() if w != nil || factory == nil { - return w + return w, false } w = factory() @@ -517,7 +527,7 @@ func (s *WindowManager) ensureWindow(slot **application.WebviewWindow, factory f s.mu.Lock() *slot = w s.mu.Unlock() - return w + return w, true } func (s *WindowManager) armReady(w *application.WebviewWindow) { @@ -639,15 +649,17 @@ func (s *WindowManager) showNow(w *application.WebviewWindow) { } func (s *WindowManager) ShowMainAt(url string) { - w := s.MainWindow() + w, created := s.ensureMain(url) if w == nil { return } - w.SetURL(url) + if !created { + w.SetURL(url) + } s.showWhenReady(w) } -func (s *WindowManager) SetMainFactory(f func() *application.WebviewWindow) { +func (s *WindowManager) SetMainFactory(f func(startURL string) *application.WebviewWindow) { s.mu.Lock() defer s.mu.Unlock() s.newMain = f