webview_related.go RawHistoryFolder
1package webkit
2
3/*
4#cgo pkg-config: webkitgtk-6.0 gtk4
5#include <webkit/webkit.h>
6#include <gtk/gtk.h>
7#include <stdlib.h>
8
9// create_related_web_view creates a WebView with the related-view property set
10// This is the WebKitGTK 6.0 way to share session/cookies between views (for popups)
11// The related-view property is construct-only, so it must be set during g_object_new
12static inline WebKitWebView* create_related_web_view(WebKitWebView* parent) {
13 return WEBKIT_WEB_VIEW(g_object_new(
14 WEBKIT_TYPE_WEB_VIEW,
15 "related-view", parent,
16 NULL
17 ));
18}
19*/
20import "C"
21import (
22 "fmt"
23 "runtime"
24 "unsafe"
25
26 "github.com/bnema/dumber/internal/logging"
27 webkit "github.com/diamondburned/gotk4-webkitgtk/pkg/webkit/v6"
28 coreglib "github.com/diamondburned/gotk4/pkg/core/glib"
29 "github.com/diamondburned/gotk4/pkg/glib/v2"
30 "github.com/diamondburned/gotk4/pkg/gtk/v4"
31)
32
33// NewBareRelatedWebView creates a bare gotk4 WebView with the related-view property set
34// This ensures the popup shares the same session/process context as the parent
35// The returned WebView is bare (no wrapper, no initialization) and must be initialized later
36//
37// Since gotk4-webkitgtk's wrapWebView() is internal and cannot be accessed,
38// we manually construct the WebView struct hierarchy using CGO.
39func NewBareRelatedWebView(parentView *webkit.WebView) *webkit.WebView {
40 if parentView == nil {
41 logging.Warn(fmt.Sprintf("[webkit] NewBareRelatedWebView: parent is nil, creating unrelated WebView"))
42 return webkit.NewWebView()
43 }
44
45 // Get the native C pointer from the gotk4 WebView
46 parentObj := glib.BaseObject(parentView)
47 if parentObj == nil {
48 logging.Error(fmt.Sprintf("[webkit] NewBareRelatedWebView: failed to get parent object, creating unrelated WebView"))
49 return webkit.NewWebView()
50 }
51 parentNative := (*C.WebKitWebView)(unsafe.Pointer(parentObj.Native()))
52 if parentNative == nil {
53 logging.Error(fmt.Sprintf("[webkit] NewBareRelatedWebView: parent native pointer is nil, creating unrelated WebView"))
54 return webkit.NewWebView()
55 }
56
57 logging.Debug(fmt.Sprintf("[webkit] Creating bare WebView with related-view property (parent=%p)", parentNative))
58
59 // Create related WebView using CGO helper with g_object_new
60 logging.Debug(fmt.Sprintf("[webkit] Step 3: About to call C.create_related_web_view"))
61 webViewNative := C.create_related_web_view(parentNative)
62 logging.Debug(fmt.Sprintf("[webkit] Step 4: C.create_related_web_view returned: %p", webViewNative))
63
64 if webViewNative == nil {
65 logging.Error(fmt.Sprintf("[webkit] NewBareRelatedWebView: C.create_related_web_view returned nil"))
66 return nil
67 }
68
69 // Wrap the C object in a coreglib.Object
70 // This takes ownership of the floating reference
71 logging.Debug(fmt.Sprintf("[webkit] Step 5: About to call coreglib.Take"))
72 obj := coreglib.Take(unsafe.Pointer(webViewNative))
73 logging.Debug(fmt.Sprintf("[webkit] Step 6: coreglib.Take succeeded, obj=%p", obj))
74
75 // Manually construct the WebView struct hierarchy
76 // WebView -> WebViewBase -> gtk.Widget -> coreglib.InitiallyUnowned -> coreglib.Object
77 //
78 // Since we cannot call the internal wrapWebView() function, we must
79 // manually construct the full struct hierarchy using the same pattern
80 // that gotk4 uses internally.
81
82 logging.Debug(fmt.Sprintf("[webkit] Step 7: About to create gtk.Widget base"))
83 // Create the gtk.Widget base
84 widget := gtk.Widget{
85 InitiallyUnowned: coreglib.InitiallyUnowned{
86 Object: obj,
87 },
88 Object: obj,
89 Accessible: gtk.Accessible{
90 Object: obj,
91 },
92 Buildable: gtk.Buildable{
93 Object: obj,
94 },
95 ConstraintTarget: gtk.ConstraintTarget{
96 Object: obj,
97 },
98 }
99 logging.Debug(fmt.Sprintf("[webkit] Step 8: Created gtk.Widget base"))
100
101 // Create the WebViewBase
102 logging.Debug(fmt.Sprintf("[webkit] Step 9: About to create WebViewBase"))
103 webViewBase := webkit.WebViewBase{
104 Widget: widget,
105 }
106 logging.Debug(fmt.Sprintf("[webkit] Step 10: Created WebViewBase"))
107
108 // Create the final WebView
109 logging.Debug(fmt.Sprintf("[webkit] Step 11: About to create final WebView"))
110 relatedView := &webkit.WebView{
111 WebViewBase: webViewBase,
112 }
113 logging.Debug(fmt.Sprintf("[webkit] Step 12: Created final WebView: %p", relatedView))
114
115 // Ensure parentView is kept alive until after the CGO call completes
116 runtime.KeepAlive(parentView)
117
118 logging.Debug(fmt.Sprintf("[webkit] Created bare related WebView (parent=%p)", parentNative))
119 return relatedView
120}