pane.go RawHistoryFolder
1package browser
2
3import (
4 "log"
5 "time"
6
7 "github.com/bnema/dumber/internal/app/control"
8 "github.com/bnema/dumber/internal/app/messaging"
9 "github.com/bnema/dumber/pkg/webkit"
10)
11
12// BrowserPane bundles the per-pane WebView and its controllers.
13type BrowserPane struct {
14 webView *webkit.WebView
15 navigationController *control.NavigationController
16 zoomController *control.ZoomController
17 clipboardController *control.ClipboardController
18 messageHandler *messaging.Handler
19 shortcutHandler *ShortcutHandler
20
21 // Multi-pane support
22 id string
23 hasGUI bool
24 guiComponents map[string]bool
25 lastFocusTime time.Time
26}
27
28func (p *BrowserPane) WebView() *webkit.WebView { return p.webView }
29
30func (p *BrowserPane) MessageHandler() *messaging.Handler { return p.messageHandler }
31
32func (p *BrowserPane) NavigationController() *control.NavigationController {
33 return p.navigationController
34}
35
36func (p *BrowserPane) ZoomController() *control.ZoomController { return p.zoomController }
37
38func (p *BrowserPane) ClipboardController() *control.ClipboardController {
39 return p.clipboardController
40}
41
42func (p *BrowserPane) ShortcutHandler() *ShortcutHandler { return p.shortcutHandler }
43
44// ID returns the unique pane identifier
45func (p *BrowserPane) ID() string { return p.id }
46
47// HasGUI returns whether GUI components are injected
48func (p *BrowserPane) HasGUI() bool { return p.hasGUI }
49
50// SetHasGUI marks GUI components as injected
51func (p *BrowserPane) SetHasGUI(has bool) { p.hasGUI = has }
52
53// SetID sets the pane identifier
54func (p *BrowserPane) SetID(id string) { p.id = id }
55
56// UpdateLastFocus updates the last focus time
57func (p *BrowserPane) UpdateLastFocus() { p.lastFocusTime = time.Now() }
58
59// Initialize GUI component tracking
60func (p *BrowserPane) initializeGUITracking() {
61 if p.guiComponents == nil {
62 p.guiComponents = make(map[string]bool)
63 }
64}
65
66// HasGUIComponent checks if a specific GUI component is loaded
67func (p *BrowserPane) HasGUIComponent(component string) bool {
68 if p.guiComponents == nil {
69 return false
70 }
71 return p.guiComponents[component]
72}
73
74// SetGUIComponent marks a GUI component as loaded
75func (p *BrowserPane) SetGUIComponent(component string, loaded bool) {
76 p.initializeGUITracking()
77 p.guiComponents[component] = loaded
78}
79
80// Cleanup releases pane resources
81func (p *BrowserPane) Cleanup() {
82 if p == nil {
83 return
84 }
85
86 if p.shortcutHandler != nil {
87 p.shortcutHandler.Detach()
88 log.Printf("[pane-%s] Cleaned up shortcuts", p.id)
89 }
90
91 if p.navigationController != nil {
92 p.navigationController.Detach()
93 }
94
95 if p.zoomController != nil {
96 p.zoomController.DetachWebView()
97 }
98
99 if p.clipboardController != nil {
100 p.clipboardController.Detach()
101 }
102
103 if p.messageHandler != nil {
104 p.messageHandler.SetWebView(nil)
105 }
106
107 // Notify JS to cleanup GUI
108 if p.webView != nil && p.hasGUI && !p.webView.IsDestroyed() {
109 cleanupScript := `try {
110 if (typeof window.__dumber_teardown === 'function') {
111 window.__dumber_teardown();
112 }
113 if (window.__dumber_gui_manager) {
114 window.__dumber_gui_manager.destroy();
115 }
116} catch (err) {
117 console.warn('[dumber] GUI teardown failed', err);
118}`
119 if err := p.webView.InjectScript(cleanupScript); err != nil {
120 log.Printf("[pane-%s] failed to inject cleanup script: %v", p.id, err)
121 }
122 }
123
124 // Clear tracking
125 p.guiComponents = nil
126 p.hasGUI = false
127}