webview.go RawHistoryFolder
1//go:build !webkit_cgo
2
3package webkit
4
5import (
6 "fmt"
7 "log"
8 "strconv"
9 "sync/atomic"
10 "unsafe"
11)
12
13// Package-level ID counter for stub WebViews
14var stubViewIDCounter uint64
15
16// nextStubViewID generates a unique ID for stub WebViews
17func nextStubViewID() uintptr {
18 return uintptr(atomic.AddUint64(&stubViewIDCounter, 1))
19}
20
21// WebView represents a browser view powered by WebKit2GTK.
22// Methods are currently stubs returning ErrNotImplemented to satisfy TDD ordering.
23type WebView struct {
24 config *Config
25 visible bool
26 zoom float64
27 url string
28 destroyed bool
29 window *Window
30 msgHandler func(payload string)
31 titleHandler func(title string)
32 uriHandler func(uri string)
33 faviconHandler func(data []byte)
34 faviconURIHandler func(pageURI, faviconURI string)
35 zoomHandler func(level float64)
36 popupHandler func(string) *WebView
37 closeHandler func()
38 navigationPolicyHandler func(url string, isUserGesture bool) bool
39 useDomZoom bool
40 domZoomSeed float64
41 container uintptr
42 id uintptr // WebView unique identifier
43
44 // Window type fields (no-op in stub)
45 windowType WindowType
46 windowFeatures *WindowFeatures
47 windowTypeCallback func(WindowType, *WindowFeatures)
48}
49
50// NewWebView constructs a new WebView instance.
51func NewWebView(cfg *Config) (*WebView, error) {
52 if cfg == nil {
53 cfg = &Config{}
54 }
55 log.Printf("[webkit] NewWebView (non-CGO stub) — UI will not be displayed. Build with -tags=webkit_cgo for native window.")
56 wv := &WebView{config: cfg, useDomZoom: cfg.UseDomZoom}
57 if cfg.ZoomDefault <= 0 {
58 wv.zoom = 1.0
59 } else {
60 wv.zoom = cfg.ZoomDefault
61 }
62 wv.domZoomSeed = wv.zoom
63 wv.id = nextStubViewID() // Assign unique ID
64 // Construction succeeds; create a logical window placeholder.
65 wv.window = &Window{Title: "Dumber Browser"}
66 wv.container = newWidgetHandle()
67 return wv, nil
68}
69
70// NewWebViewWithRelated creates a new WebView related to an existing one (non-CGO stub)
71func NewWebViewWithRelated(cfg *Config, relatedView *WebView) (*WebView, error) {
72 // In non-CGO build, just create a regular WebView
73 return NewWebView(cfg)
74}
75
76// LoadURL navigates the webview to the specified URL.
77func (w *WebView) LoadURL(rawURL string) error {
78 if w == nil || w.destroyed {
79 return ErrNotImplemented
80 }
81 if rawURL == "" {
82 return fmt.Errorf("url cannot be empty")
83 }
84 // Minimal validation; actual navigation handled by CGO bridge later.
85 w.url = rawURL
86 log.Printf("[webkit] LoadURL (non-CGO stub): %s", rawURL)
87 return nil
88}
89
90// Show makes the WebView visible.
91func (w *WebView) Show() error {
92 if w == nil || w.destroyed {
93 return ErrNotImplemented
94 }
95 w.visible = true
96 log.Printf("[webkit] Show (non-CGO stub): no native window will appear")
97 return nil
98}
99
100// Hide hides the WebView window.
101func (w *WebView) Hide() error {
102 if w == nil || w.destroyed {
103 return ErrNotImplemented
104 }
105 w.visible = false
106 return nil
107}
108
109// Destroy releases native resources.
110func (w *WebView) Destroy() error {
111 if w == nil {
112 return ErrNotImplemented
113 }
114 w.destroyed = true
115 return nil
116}
117
118// IsDestroyed returns whether this WebView has been destroyed
119func (w *WebView) IsDestroyed() bool {
120 return w != nil && w.destroyed
121}
122
123// Window returns the associated native window wrapper (non-nil).
124func (w *WebView) Window() *Window { return w.window }
125
126// GetCurrentURL returns the last requested URL (non-CGO build approximation).
127func (w *WebView) GetCurrentURL() string { return w.url }
128
129// GetTitle returns a stub page title.
130func (w *WebView) GetTitle() string { return "New Tab" }
131
132// GoBack is not supported in the non-CGO stub.
133func (w *WebView) GoBack() error { return ErrNotImplemented }
134
135// GoForward is not supported in the non-CGO stub.
136func (w *WebView) GoForward() error { return ErrNotImplemented }
137
138// Reload is not supported in the non-CGO stub.
139func (w *WebView) Reload() error { return ErrNotImplemented }
140
141// ReloadBypassCache is not supported in the non-CGO stub.
142func (w *WebView) ReloadBypassCache() error { return ErrNotImplemented }
143
144// ShowDevTools is a no-op in the non-CGO build.
145func (w *WebView) ShowDevTools() error { return nil }
146
147// CloseDevTools is a no-op in the non-CGO build.
148func (w *WebView) CloseDevTools() error { return nil }
149
150// ShowPrintDialog is a no-op in the non-CGO build.
151func (w *WebView) ShowPrintDialog() error { return nil }
152
153// RegisterScriptMessageHandler registers a callback invoked when the content script posts a message.
154func (w *WebView) RegisterScriptMessageHandler(cb func(payload string)) { w.msgHandler = cb }
155
156func (w *WebView) RegisterPopupHandler(cb func(string) *WebView) { w.popupHandler = cb }
157
158func (w *WebView) RegisterCloseHandler(cb func()) { w.closeHandler = cb }
159
160func (w *WebView) RegisterNavigationPolicyHandler(cb func(url string, isUserGesture bool) bool) {
161 w.navigationPolicyHandler = cb
162}
163
164func (w *WebView) dispatchScriptMessage(payload string) { //nolint:unused // Called from CGO WebKit callbacks
165 if w != nil && w.msgHandler != nil {
166 w.msgHandler(payload)
167 }
168}
169
170func (w *WebView) dispatchPopupRequest(uri string) *WebView { //nolint:unused // Called from CGO WebKit callbacks
171 if w != nil && w.popupHandler != nil {
172 return w.popupHandler(uri)
173 }
174 return nil
175}
176
177// GetNativePointer returns nil for non-CGO build (stub implementation)
178func (w *WebView) GetNativePointer() unsafe.Pointer { //nolint:unused // Needed for interface compatibility
179 return nil
180}
181
182// RegisterTitleChangedHandler registers a callback invoked when the page title changes.
183func (w *WebView) RegisterTitleChangedHandler(cb func(title string)) { w.titleHandler = cb }
184
185func (w *WebView) dispatchTitleChanged(title string) { //nolint:unused // Called from CGO WebKit callbacks
186 if w != nil && w.titleHandler != nil {
187 w.titleHandler(title)
188 }
189}
190
191// RegisterURIChangedHandler registers a callback invoked when the current page URI changes.
192func (w *WebView) RegisterURIChangedHandler(cb func(uri string)) { w.uriHandler = cb }
193
194func (w *WebView) dispatchURIChanged(uri string) { //nolint:unused // Called from CGO WebKit callbacks
195 if w != nil && w.uriHandler != nil {
196 w.uriHandler(uri)
197 }
198}
199
200// RegisterFaviconChangedHandler registers a callback invoked when the page favicon changes.
201func (w *WebView) RegisterFaviconChangedHandler(cb func(data []byte)) { w.faviconHandler = cb }
202
203// RegisterFaviconURIChangedHandler registers a callback invoked when WebKit detects a favicon URI.
204func (w *WebView) RegisterFaviconURIChangedHandler(cb func(pageURI, faviconURI string)) {
205 w.faviconURIHandler = cb
206}
207
208func (w *WebView) dispatchFaviconChanged(data []byte) { //nolint:unused // Called from CGO WebKit callbacks
209 if w != nil && w.faviconHandler != nil {
210 w.faviconHandler(data)
211 }
212}
213
214// RegisterZoomChangedHandler registers a callback invoked when zoom level changes.
215func (w *WebView) RegisterZoomChangedHandler(cb func(level float64)) { w.zoomHandler = cb }
216
217func (w *WebView) dispatchZoomChanged(level float64) {
218 if w != nil && w.zoomHandler != nil {
219 w.zoomHandler(level)
220 }
221}
222
223// Widget returns an empty handle in stub builds.
224func (w *WebView) Widget() uintptr { return 0 }
225
226// RootWidget returns the container widget handle in CGO builds. Stub returns 0.
227func (w *WebView) RootWidget() uintptr { return w.container }
228
229// DestroyWindow is a no-op in stub builds.
230func (w *WebView) DestroyWindow() {}
231
232// RunOnMainThread executes fn immediately in non-CGO builds.
233func (w *WebView) RunOnMainThread(fn func()) {
234 if fn != nil {
235 fn()
236 }
237}
238
239// PrepareForReparenting is a no-op in stub builds.
240func (w *WebView) PrepareForReparenting() {}
241
242// RefreshAfterReparenting is a no-op in stub builds.
243func (w *WebView) RefreshAfterReparenting() {}
244
245// UsesDomZoom reports whether DOM-based zoom is enabled in this WebView.
246func (w *WebView) UsesDomZoom() bool {
247 return w != nil && w.useDomZoom
248}
249
250// SeedDomZoom stores the desired DOM zoom level for the next navigation (stub implementation).
251func (w *WebView) SeedDomZoom(level float64) {
252 if w == nil || !w.useDomZoom {
253 return
254 }
255 if level < 0.25 {
256 level = 0.25
257 } else if level > 5.0 {
258 level = 5.0
259 }
260 w.domZoomSeed = level
261}
262
263// CreateRelatedView returns a new WebView (stub creates independent)
264func (w *WebView) CreateRelatedView() *WebView {
265 nw, _ := NewWebView(w.config)
266 return nw
267}
268
269// OnWindowTypeDetected registers a callback (stored but never invoked in stub)
270func (w *WebView) OnWindowTypeDetected(callback func(WindowType, *WindowFeatures)) {
271 if w != nil {
272 w.windowTypeCallback = callback
273 }
274}
275
276// InitializeContentBlocking initializes WebKit content blocking with filter manager (stub)
277func (w *WebView) InitializeContentBlocking(filterManager interface{}) error {
278 return ErrNotImplemented
279}
280
281// OnNavigate sets up domain-specific cosmetic filtering on navigation (stub)
282func (w *WebView) OnNavigate(url string, filterManager interface{}) {
283 // No-op in stub
284}
285
286// UpdateContentFilters updates the content filters dynamically (stub)
287func (w *WebView) UpdateContentFilters(filterManager interface{}) error {
288 return ErrNotImplemented
289}
290
291// SetWindowFeatures sets the window features for this WebView (stub)
292func (w *WebView) SetWindowFeatures(features *WindowFeatures) {
293 w.windowFeatures = features
294}
295
296// SetActive sets whether this WebView is currently active/focused (stub)
297func (w *WebView) SetActive(active bool) {
298 // No-op in stub
299}
300
301// IsActive returns whether this WebView is currently active/focused (stub)
302func (w *WebView) IsActive() bool {
303 return false
304}
305
306// ID returns the unique identifier for this WebView as a string (stub)
307func (w *WebView) ID() string {
308 if w == nil {
309 return ""
310 }
311 return strconv.FormatUint(uint64(w.id), 10)
312}
313
314// PrefersDarkTheme returns true if GTK is configured to prefer dark theme (stub)
315func PrefersDarkTheme() bool {
316 return false // Fallback to light theme when not using CGO
317}