1package webkit
2
3import (
4 "fmt"
5 "log"
6
7 "github.com/bnema/dumber/assets"
8 webkit "github.com/diamondburned/gotk4-webkitgtk/pkg/webkit/v6"
9)
10
11// SetupUserContentManager configures UserContentManager for the WebView
12// This injects GUI scripts at document-start and registers message handlers
13func SetupUserContentManager(view *webkit.WebView, appearanceConfigJSON string, webviewID uint64) error {
14 if view == nil {
15 return nil
16 }
17
18 // Get the UserContentManager from the WebView
19 ucm := view.UserContentManager()
20 if ucm == nil {
21 log.Printf("[webkit] UserContentManager is nil, skipping script injection")
22 return nil
23 }
24
25 // Inject webview ID FIRST, so GUI scripts can access it immediately
26 // Note: webviewID is uint64, formatted as number (not string) to avoid any injection concerns
27 webviewIDScript := fmt.Sprintf(`
28 window.__dumber_webview_id = %d;
29 console.log('[webkit] WebView ID set in JavaScript:', window.__dumber_webview_id);
30 `, webviewID)
31 ucm.AddScript(webkit.NewUserScript(
32 webviewIDScript,
33 webkit.UserContentInjectTopFrame, // Only top frame needs the webview ID
34 webkit.UserScriptInjectAtDocumentStart,
35 nil,
36 nil,
37 ))
38 log.Printf("[webkit] Injected webview ID script for ID: %d", webviewID)
39
40 // Inject GTK theme detection SECOND, before color-scheme script
41 // The color-scheme.ts expects window.__dumber_gtk_prefers_dark to be set
42 prefersDark := PrefersDarkTheme()
43 gtkThemeScript := fmt.Sprintf(`window.__dumber_gtk_prefers_dark = %t;`, prefersDark)
44 ucm.AddScript(webkit.NewUserScript(
45 gtkThemeScript,
46 webkit.UserContentInjectTopFrame, // Only top frame needs theme preference
47 webkit.UserScriptInjectAtDocumentStart,
48 nil,
49 nil,
50 ))
51 log.Printf("[webkit] Injected GTK theme preference: prefersDark=%t", prefersDark)
52
53 // Inject palette config SECOND, before GUI scripts
54 // The GUI expects window.__dumber_palette = { "light": {...}, "dark": {...} }
55 if appearanceConfigJSON != "" {
56 paletteScript := fmt.Sprintf(`window.__dumber_palette = %s;`, appearanceConfigJSON)
57 ucm.AddScript(webkit.NewUserScript(
58 paletteScript,
59 webkit.UserContentInjectTopFrame, // Only top frame needs palette config
60 webkit.UserScriptInjectAtDocumentStart,
61 nil,
62 nil,
63 ))
64 log.Printf("[webkit] Injected palette config at document-start (%d bytes)", len(paletteScript))
65 }
66
67 // Inject color-scheme script at document-start
68 if assets.ColorSchemeScript != "" {
69 ucm.AddScript(webkit.NewUserScript(
70 assets.ColorSchemeScript,
71 webkit.UserContentInjectTopFrame, // Only top frame needs color scheme detection
72 webkit.UserScriptInjectAtDocumentStart,
73 nil, // whitelist (nil = all)
74 nil, // blacklist (nil = none)
75 ))
76 log.Printf("[webkit] Injected color-scheme script (%d bytes)", len(assets.ColorSchemeScript))
77 }
78
79 // Inject main-world script at document-start
80 if assets.MainWorldScript != "" {
81 ucm.AddScript(webkit.NewUserScript(
82 assets.MainWorldScript,
83 webkit.UserContentInjectTopFrame, // Only top frame needs bridge/UI functionality
84 webkit.UserScriptInjectAtDocumentStart,
85 nil,
86 nil,
87 ))
88 log.Printf("[webkit] Injected main-world script (%d bytes)", len(assets.MainWorldScript))
89 }
90
91 // Inject GUI controls script at document-start
92 if assets.GUIScript != "" {
93 ucm.AddScript(webkit.NewUserScript(
94 assets.GUIScript,
95 webkit.UserContentInjectTopFrame, // Only top frame needs GUI controls
96 webkit.UserScriptInjectAtDocumentStart,
97 nil,
98 nil,
99 ))
100 log.Printf("[webkit] Injected GUI controls script (%d bytes)", len(assets.GUIScript))
101 }
102
103 // Register script message handler "dumber" for communication from JS
104 // Pass empty string for worldName to use the default world
105 if !ucm.RegisterScriptMessageHandler("dumber", "") {
106 log.Printf("[webkit] Warning: failed to register 'dumber' script message handler")
107 } else {
108 log.Printf("[webkit] Registered 'dumber' script message handler")
109 }
110
111 return nil
112}