fix(workspace): prevent script messages stealing focus
- commit
- bf83908b7654970aa8b041b6983140f2f8b5893f
- author
- bamen · · 2025-10-12 08:08 UTC
- parent
- b511179
- signature
- unsigned
1 file · +32 -15
M internal/app/browser/webview.go +32 -15
| @@ -78,22 +78,22 @@ func (app *BrowserApp) buildAppearanceConfigJSON() string { | |||
| 78 | 78 | // It looks for window.__dumber_palette = { "light": {...}, "dark": {...} } | |
| 79 | 79 | paletteConfig := map[string]interface{}{ | |
| 80 | 80 | "light": map[string]string{ | |
| 81 | - | "background": app.config.Appearance.LightPalette.Background, | |
| 82 | - | "surface": app.config.Appearance.LightPalette.Surface, | |
| 83 | - | "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant, | |
| 84 | - | "text": app.config.Appearance.LightPalette.Text, | |
| 85 | - | "muted": app.config.Appearance.LightPalette.Muted, | |
| 86 | - | "accent": app.config.Appearance.LightPalette.Accent, | |
| 87 | - | "border": app.config.Appearance.LightPalette.Border, | |
| 81 | + | "background": app.config.Appearance.LightPalette.Background, | |
| 82 | + | "surface": app.config.Appearance.LightPalette.Surface, | |
| 83 | + | "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant, | |
| 84 | + | "text": app.config.Appearance.LightPalette.Text, | |
| 85 | + | "muted": app.config.Appearance.LightPalette.Muted, | |
| 86 | + | "accent": app.config.Appearance.LightPalette.Accent, | |
| 87 | + | "border": app.config.Appearance.LightPalette.Border, | |
| 88 | 88 | }, | |
| 89 | 89 | "dark": map[string]string{ | |
| 90 | - | "background": app.config.Appearance.DarkPalette.Background, | |
| 91 | - | "surface": app.config.Appearance.DarkPalette.Surface, | |
| 92 | - | "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant, | |
| 93 | - | "text": app.config.Appearance.DarkPalette.Text, | |
| 94 | - | "muted": app.config.Appearance.DarkPalette.Muted, | |
| 95 | - | "accent": app.config.Appearance.DarkPalette.Accent, | |
| 96 | - | "border": app.config.Appearance.DarkPalette.Border, | |
| 90 | + | "background": app.config.Appearance.DarkPalette.Background, | |
| 91 | + | "surface": app.config.Appearance.DarkPalette.Surface, | |
| 92 | + | "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant, | |
| 93 | + | "text": app.config.Appearance.DarkPalette.Text, | |
| 94 | + | "muted": app.config.Appearance.DarkPalette.Muted, | |
| 95 | + | "accent": app.config.Appearance.DarkPalette.Accent, | |
| 96 | + | "border": app.config.Appearance.DarkPalette.Border, | |
| 97 | 97 | }, | |
| 98 | 98 | } | |
| 99 | 99 | ||
| @@ -190,7 +190,7 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) { | |||
| 190 | 190 | }) | |
| 191 | 191 | ||
| 192 | 192 | pane.webView.RegisterScriptMessageHandler(func(payload string) { | |
| 193 | - | if app.workspace != nil { | |
| 193 | + | if app.workspace != nil && shouldFocusForScriptMessage(payload) { | |
| 194 | 194 | app.workspace.focusByView(pane.webView) | |
| 195 | 195 | } | |
| 196 | 196 | pane.messageHandler.Handle(payload) | |
| @@ -210,6 +210,23 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) { | |||
| 210 | 210 | } | |
| 211 | 211 | } | |
| 212 | 212 | ||
| 213 | + | // shouldFocusForScriptMessage filters out bootstrap messages that fire without user | |
| 214 | + | // interaction (palette sync, shortcut preload, etc.). Only actionable payloads should | |
| 215 | + | // bump the pane back to the front. | |
| 216 | + | func shouldFocusForScriptMessage(payload string) bool { | |
| 217 | + | var msg messaging.Message | |
| 218 | + | if err := json.Unmarshal([]byte(payload), &msg); err != nil { | |
| 219 | + | return true // keep legacy behaviour if parsing fails | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | switch msg.Type { | |
| 223 | + | case "get_color_palettes", "get_search_shortcuts", "request-webview-id", "console-message": | |
| 224 | + | return false | |
| 225 | + | default: | |
| 226 | + | return true | |
| 227 | + | } | |
| 228 | + | } | |
| 229 | + | ||
| 213 | 230 | // createWebView creates and configures the WebView | |
| 214 | 231 | func (app *BrowserApp) createWebView() error { | |
| 215 | 232 | log.Printf("Creating WebView (native backend expected: %v)", webkit.IsNativeAvailable()) | |
| @@ -78,22 +78,22 @@ func (app *BrowserApp) buildAppearanceConfigJSON() string { | |||||
| 78 | // It looks for window.__dumber_palette = { "light": {...}, "dark": {...} } | 78 | // It looks for window.__dumber_palette = { "light": {...}, "dark": {...} } | ||
| 79 | paletteConfig := map[string]interface{}{ | 79 | paletteConfig := map[string]interface{}{ | ||
| 80 | "light": map[string]string{ | 80 | "light": map[string]string{ | ||
| 81 | - | "background": app.config.Appearance.LightPalette.Background, | 81 | + | "background": app.config.Appearance.LightPalette.Background, |
| 82 | - | "surface": app.config.Appearance.LightPalette.Surface, | 82 | + | "surface": app.config.Appearance.LightPalette.Surface, |
| 83 | - | "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant, | 83 | + | "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant, |
| 84 | - | "text": app.config.Appearance.LightPalette.Text, | 84 | + | "text": app.config.Appearance.LightPalette.Text, |
| 85 | - | "muted": app.config.Appearance.LightPalette.Muted, | 85 | + | "muted": app.config.Appearance.LightPalette.Muted, |
| 86 | - | "accent": app.config.Appearance.LightPalette.Accent, | 86 | + | "accent": app.config.Appearance.LightPalette.Accent, |
| 87 | - | "border": app.config.Appearance.LightPalette.Border, | 87 | + | "border": app.config.Appearance.LightPalette.Border, |
| 88 | }, | 88 | }, | ||
| 89 | "dark": map[string]string{ | 89 | "dark": map[string]string{ | ||
| 90 | - | "background": app.config.Appearance.DarkPalette.Background, | 90 | + | "background": app.config.Appearance.DarkPalette.Background, |
| 91 | - | "surface": app.config.Appearance.DarkPalette.Surface, | 91 | + | "surface": app.config.Appearance.DarkPalette.Surface, |
| 92 | - | "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant, | 92 | + | "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant, |
| 93 | - | "text": app.config.Appearance.DarkPalette.Text, | 93 | + | "text": app.config.Appearance.DarkPalette.Text, |
| 94 | - | "muted": app.config.Appearance.DarkPalette.Muted, | 94 | + | "muted": app.config.Appearance.DarkPalette.Muted, |
| 95 | - | "accent": app.config.Appearance.DarkPalette.Accent, | 95 | + | "accent": app.config.Appearance.DarkPalette.Accent, |
| 96 | - | "border": app.config.Appearance.DarkPalette.Border, | 96 | + | "border": app.config.Appearance.DarkPalette.Border, |
| 97 | }, | 97 | }, | ||
| 98 | } | 98 | } | ||
| 99 | 99 | ||||
| @@ -190,7 +190,7 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) { | |||||
| 190 | }) | 190 | }) | ||
| 191 | 191 | ||||
| 192 | pane.webView.RegisterScriptMessageHandler(func(payload string) { | 192 | pane.webView.RegisterScriptMessageHandler(func(payload string) { | ||
| 193 | - | if app.workspace != nil { | 193 | + | if app.workspace != nil && shouldFocusForScriptMessage(payload) { |
| 194 | app.workspace.focusByView(pane.webView) | 194 | app.workspace.focusByView(pane.webView) | ||
| 195 | } | 195 | } | ||
| 196 | pane.messageHandler.Handle(payload) | 196 | pane.messageHandler.Handle(payload) | ||
| @@ -210,6 +210,23 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) { | |||||
| 210 | } | 210 | } | ||
| 211 | } | 211 | } | ||
| 212 | 212 | ||||
| 213 | + | // shouldFocusForScriptMessage filters out bootstrap messages that fire without user | |||
| 214 | + | // interaction (palette sync, shortcut preload, etc.). Only actionable payloads should | |||
| 215 | + | // bump the pane back to the front. | |||
| 216 | + | func shouldFocusForScriptMessage(payload string) bool { | |||
| 217 | + | var msg messaging.Message | |||
| 218 | + | if err := json.Unmarshal([]byte(payload), &msg); err != nil { | |||
| 219 | + | return true // keep legacy behaviour if parsing fails | |||
| 220 | + | } | |||
| 221 | + | ||||
| 222 | + | switch msg.Type { | |||
| 223 | + | case "get_color_palettes", "get_search_shortcuts", "request-webview-id", "console-message": | |||
| 224 | + | return false | |||
| 225 | + | default: | |||
| 226 | + | return true | |||
| 227 | + | } | |||
| 228 | + | } | |||
| 229 | + | ||||
| 213 | // createWebView creates and configures the WebView | 230 | // createWebView creates and configures the WebView | ||
| 214 | func (app *BrowserApp) createWebView() error { | 231 | func (app *BrowserApp) createWebView() error { | ||
| 215 | log.Printf("Creating WebView (native backend expected: %v)", webkit.IsNativeAvailable()) | 232 | log.Printf("Creating WebView (native backend expected: %v)", webkit.IsNativeAvailable()) | ||