1// Package port defines application-layer interfaces for external capabilities.
2// Ports abstract infrastructure concerns, allowing the application layer to
3// remain independent of specific implementations (WebKit, GTK, etc.).
4package port
5
6import (
7 "context"
8)
9
10// WebViewID uniquely identifies a WebView instance.
11type WebViewID uint64
12
13// LoadEvent represents page load state transitions.
14type LoadEvent int
15
16const (
17 // LoadStarted indicates navigation has begun.
18 LoadStarted LoadEvent = iota
19 // LoadRedirected indicates a redirect occurred.
20 LoadRedirected
21 // LoadCommitted indicates content is being received.
22 LoadCommitted
23 // LoadFinished indicates the page has fully loaded.
24 LoadFinished
25)
26
27// String returns a human-readable representation of the load event.
28func (e LoadEvent) String() string {
29 switch e {
30 case LoadStarted:
31 return "started"
32 case LoadRedirected:
33 return "redirected"
34 case LoadCommitted:
35 return "committed"
36 case LoadFinished:
37 return "finished"
38 default:
39 return "unknown"
40 }
41}
42
43// WebViewState represents a snapshot of the current WebView state.
44// This is an immutable struct that can be safely passed between components.
45type WebViewState struct {
46 URI string
47 Title string
48 IsLoading bool
49 Progress float64 // 0.0 to 1.0
50 CanGoBack bool
51 CanGoFwd bool
52 ZoomLevel float64
53}
54
55// WebProcessTerminationReason describes why the web process terminated.
56type WebProcessTerminationReason int
57
58const (
59 WebProcessTerminationUnknown WebProcessTerminationReason = iota
60 WebProcessTerminationCrashed
61 WebProcessTerminationExceededMemory
62 WebProcessTerminationByAPI
63)
64
65// PopupRequest contains metadata about a popup window request.
66type PopupRequest struct {
67 TargetURI string
68 FrameName string // e.g., "_blank", custom name, or empty
69 IsUserGesture bool
70 ParentViewID WebViewID
71}
72
73// Texture represents a graphics texture returned by the engine.
74// GoPointer returns a native toolkit pointer (e.g. *gdk.Texture in GTK engines).
75// Engine implementations are responsible for the concrete type.
76type Texture interface {
77 GoPointer() uintptr
78}
79
80// WebViewCallbacks defines callback handlers for WebView events.
81// Implementations should invoke these on the main thread/goroutine.
82type WebViewCallbacks struct {
83 // OnLoadChanged is called when load state changes.
84 OnLoadChanged func(event LoadEvent)
85 // OnTitleChanged is called when the page title changes.
86 OnTitleChanged func(title string)
87 // OnURIChanged is called when the URI changes.
88 OnURIChanged func(uri string)
89 // OnProgressChanged is called during page load with progress 0.0-1.0.
90 OnProgressChanged func(progress float64)
91 // OnFaviconChanged is called when the page favicon changes.
92 // The parameter is a *gdk.Texture (passed as Texture interface to avoid GTK import in port layer).
93 OnFaviconChanged func(favicon Texture)
94 // OnClose is called when the WebView requests to close.
95 OnClose func()
96 // OnCreate is called when a popup window is requested.
97 // Return a WebView to allow the popup, or nil to block it.
98 OnCreate func(request PopupRequest) WebView
99 // OnReadyToShow is called when a popup WebView is ready to display.
100 OnReadyToShow func()
101 // OnLinkHover is called when hovering over a link, image, or media element.
102 // The uri parameter contains the target URL, or empty string when leaving.
103 OnLinkHover func(uri string)
104 // OnWebProcessTerminated is called when the web process exits unexpectedly.
105 OnWebProcessTerminated func(reason WebProcessTerminationReason, reasonLabel string, uri string)
106
107 // OnPermissionRequest is called when a site requests permission (mic, camera, screen sharing).
108 // Return true to indicate the request was handled. Call allow()/deny() to respond.
109 // The permission types are passed as strings ("microphone", "camera", "display", etc.).
110 // The metadata map carries permission-type-specific context; for website_data_access both
111 // entity.PermissionMetadataKeyRequestingDomain and entity.PermissionMetadataKeyCurrentDomain must be populated.
112 OnPermissionRequest func(origin string, permTypes []string, metadata map[string]string, allow, deny func()) bool
113
114 // OnLinkMiddleClick is called when a link is middle-clicked.
115 // Return true if handled (blocks default navigation).
116 OnLinkMiddleClick func(uri string) bool
117
118 // OnEnterFullscreen is called when the WebView requests fullscreen mode.
119 // Return true to prevent fullscreen.
120 OnEnterFullscreen func() bool
121
122 // OnLeaveFullscreen is called when the WebView exits fullscreen mode.
123 // Return true to prevent leaving fullscreen.
124 OnLeaveFullscreen func() bool
125
126 // OnAudioStateChanged is called when audio playback starts or stops.
127 OnAudioStateChanged func(playing bool)
128}
129
130// FindOptions configures search behavior.
131type FindOptions struct {
132 CaseInsensitive bool
133 AtWordStarts bool
134 WrapAround bool
135}
136
137// FindController abstracts WebKit's FindController for clean architecture.
138type FindController interface {
139 Search(text string, options FindOptions, maxMatches uint)
140 CountMatches(text string, options FindOptions, maxMatches uint)
141 SearchNext()
142 SearchPrevious()
143 SearchFinish()
144 GetSearchText() string
145
146 // Signal connections
147 OnFoundText(callback func(matchCount uint)) uint
148 OnFailedToFindText(callback func()) uint
149 OnCountedMatches(callback func(matchCount uint)) uint
150 DisconnectSignal(id uint)
151}
152
153// WebView defines the port interface for browser view operations.
154// This interface abstracts the underlying browser engine (WebKit, etc.)
155// and exposes only the navigation and state capabilities needed by
156// the application layer.
157type WebView interface {
158 // ID returns the unique identifier for this WebView.
159 ID() WebViewID
160
161 // --- Navigation ---
162
163 // LoadURI navigates to the specified URI.
164 LoadURI(ctx context.Context, uri string) error
165
166 // LoadHTML loads HTML content with an optional base URI for relative links.
167 LoadHTML(ctx context.Context, content, baseURI string) error
168
169 // Reload reloads the current page.
170 Reload(ctx context.Context) error
171
172 // ReloadBypassCache reloads the current page, bypassing cache.
173 ReloadBypassCache(ctx context.Context) error
174
175 // Stop stops the current page load.
176 Stop(ctx context.Context) error
177
178 // GoBack navigates back in history.
179 // Uses WebKit native navigation if available, falls back to JavaScript history.back() for SPA compatibility.
180 GoBack(ctx context.Context) error
181
182 // GoForward navigates forward in history.
183 // Uses WebKit native navigation if available, falls back to JavaScript history.forward() for SPA compatibility.
184 GoForward(ctx context.Context) error
185
186 // --- State Queries ---
187
188 // State returns the current WebView state as a snapshot.
189 State() WebViewState
190
191 // URI returns the current URI.
192 URI() string
193
194 // Title returns the current page title.
195 Title() string
196
197 // IsLoading returns true if a page is currently loading.
198 IsLoading() bool
199
200 // EstimatedProgress returns the load progress (0.0 to 1.0).
201 EstimatedProgress() float64
202
203 // CanGoBack returns true if back navigation is available.
204 CanGoBack() bool
205
206 // CanGoForward returns true if forward navigation is available.
207 CanGoForward() bool
208
209 // --- Zoom ---
210
211 // SetZoomLevel sets the zoom level (1.0 = 100%).
212 SetZoomLevel(ctx context.Context, level float64) error
213
214 // GetZoomLevel returns the current zoom level.
215 GetZoomLevel() float64
216
217 // --- Find ---
218
219 // GetFindController returns the find controller for text search.
220 // Returns nil if find is not supported.
221 GetFindController() FindController
222
223 // --- Callbacks ---
224
225 // SetCallbacks registers callback handlers for WebView events.
226 // Pass nil to clear all callbacks.
227 SetCallbacks(callbacks *WebViewCallbacks)
228
229 // --- Appearance ---
230
231 // RunJavaScript executes a script in the main world. Fire-and-forget.
232 RunJavaScript(ctx context.Context, script string)
233
234 // SetBackgroundColor sets the background color shown before content paints (0.0-1.0 RGBA).
235 SetBackgroundColor(r, g, b, a float64)
236
237 // ResetBackgroundToDefault resets the background to white (browser default).
238 ResetBackgroundToDefault()
239
240 // --- Favicon ---
241
242 // Favicon returns the current page favicon, or nil if unavailable.
243 Favicon() Texture
244
245 // Generation returns a monotonic counter incremented on pool reuse.
246 // Used to detect stale callbacks after a WebView is recycled.
247 Generation() uint64
248
249 // --- Media/Fullscreen State ---
250
251 // IsFullscreen returns true if the WebView is currently in fullscreen mode.
252 IsFullscreen() bool
253
254 // IsPlayingAudio returns true if the WebView is currently playing audio.
255 IsPlayingAudio() bool
256
257 // --- Lifecycle ---
258
259 // IsDestroyed returns true if the WebView has been destroyed.
260 IsDestroyed() bool
261
262 // Destroy releases all resources associated with this WebView.
263 // After calling Destroy, the WebView should not be used.
264 Destroy()
265}
266
267// WebViewPool defines the port interface for WebView pooling.
268// Pools maintain pre-created WebViews for fast tab creation.
269type WebViewPool interface {
270 // Acquire obtains a WebView from the pool or creates a new one.
271 // The context can be used for cancellation.
272 Acquire(ctx context.Context) (WebView, error)
273
274 // Release returns a WebView to the pool for reuse.
275 // The WebView will be reset to a blank state.
276 // If the pool is full, the WebView will be destroyed.
277 Release(wv WebView)
278
279 // Prewarm creates WebViews synchronously to populate the pool.
280 // Pass count <= 0 to use the default prewarm count.
281 Prewarm(count int)
282
283 // PrewarmAsync schedules WebView creation on the toolkit idle loop,
284 // avoiding blocking startup while still warming up WebViews.
285 // Pass count <= 0 to use the default prewarm count.
286 PrewarmAsync(ctx context.Context, count int)
287
288 // Size returns the current number of available WebViews in the pool.
289 Size() int
290
291 // Close shuts down the pool and destroys all pooled WebViews.
292 Close()
293}
294
295// WebViewFactory creates new WebView instances.
296// This is used when direct WebView creation is needed without pooling.
297type WebViewFactory interface {
298 // Create creates a new WebView instance.
299 Create(ctx context.Context) (WebView, error)
300
301 // CreateRelated creates a WebView that shares session/cookies with parent.
302 // This is required for popup windows to maintain authentication state.
303 // Popup WebViews bypass the pool since they must be related to a specific parent.
304 CreateRelated(ctx context.Context, parentID WebViewID) (WebView, error)
305}
306
307// DevToolsOpener is an optional capability for WebViews that support developer tools.
308type DevToolsOpener interface {
309 OpenDevTools()
310}
311
312// Printer is an optional capability for WebViews that support printing.
313type Printer interface {
314 PrintPage()
315}
316
317// PopupCapable is implemented by WebViews that support popup lifecycle callbacks.
318// SetOnClose composes the provided function with any existing close handler so
319// that multiple callers can each register a close callback without overwriting
320// one another.
321type PopupCapable interface {
322 SetOnReadyToShow(fn func())
323 SetOnClose(fn func())
324 Show()
325}
326
327// OAuthCallbackCapable is implemented by WebViews that support OAuth auto-close callbacks.
328// It is an optional capability; callers should type-assert port.WebView to this interface
329// before use and degrade gracefully when it is absent.
330type OAuthCallbackCapable interface {
331 // AddCloseCallback registers fn to be called when the WebView is programmatically closed.
332 // Multiple callbacks may be registered; each will be called in registration order.
333 AddCloseCallback(fn func())
334 // AddNavigationCallback registers fn to be called whenever the URI changes or a
335 // committed load is detected. The uri parameter contains the new URL.
336 // Multiple callbacks may be registered; each will be called in registration order.
337 AddNavigationCallback(fn func(uri string))
338 // Close triggers a programmatic close of the WebView (equivalent to window.close()).
339 Close()
340}
341
342// TextInputTargetProvider is an optional capability for WebViews that support
343// text input method integration.
344type TextInputTargetProvider interface {
345 TextInputTarget() TextInputTarget
346}