Add cef2gtk bridge adapter
- commit
- e77e49226a8fd4744d137d3e517e2a70c220f4ce
- author
- brice · · 2026-04-29 18:57 UTC
- parent
- 1f211c0
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +276 -0
A internal/infrastructure/cef/cef2gtk_adapter.go +195 -0
| @@ -0,0 +1,195 @@ | |||
| 1 | + | package cef | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "errors" | |
| 5 | + | ||
| 6 | + | purecef "github.com/bnema/purego-cef/cef" | |
| 7 | + | cef2gtk "github.com/bnema/purego-cef2gtk" | |
| 8 | + | "github.com/bnema/puregotk/v4/gtk" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | // ErrAdapterDestroyed is returned when an operation is attempted on a destroyed | |
| 12 | + | // Cef2gtkAdapter. | |
| 13 | + | var ErrAdapterDestroyed = errors.New("cef2gtk_adapter: adapter is destroyed") | |
| 14 | + | ||
| 15 | + | // Cef2gtkAdapter is a thin infrastructure adapter around *cef2gtk.View. It | |
| 16 | + | // keeps purego-cef2gtk imports confined to internal/infrastructure/cef. | |
| 17 | + | // | |
| 18 | + | // GTK-thread affinity is a hard constraint: most methods touch GTK/CEF view | |
| 19 | + | // lifecycle or input and MUST be called from Dumber's GTK scheduling path | |
| 20 | + | // (e.g. runOnGTK or runOnGTKSync) unless the caller is already executing on | |
| 21 | + | // the GTK main context. Methods are annotated below. | |
| 22 | + | // | |
| 23 | + | // The adapter does NOT own GL/PBO staging, dirty-rect uploads, or GTK input | |
| 24 | + | // controller implementation — those belong to purego-cef2gtk. | |
| 25 | + | type Cef2gtkAdapter struct { | |
| 26 | + | view *cef2gtk.View | |
| 27 | + | destroyed bool | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | // NewCef2gtkAdapter creates a GtkGLArea-backed accelerated CEF view and wraps | |
| 31 | + | // it in a thin Dumber adapter. | |
| 32 | + | func NewCef2gtkAdapter() *Cef2gtkAdapter { | |
| 33 | + | v := cef2gtk.NewView() | |
| 34 | + | if v == nil { | |
| 35 | + | return nil | |
| 36 | + | } | |
| 37 | + | return &Cef2gtkAdapter{view: v} | |
| 38 | + | } | |
| 39 | + | ||
| 40 | + | // Widget returns the native GTK widget for embedding into containers. | |
| 41 | + | // The returned pointer must be used from the GTK main thread for packing. | |
| 42 | + | func (a *Cef2gtkAdapter) Widget() *gtk.Widget { | |
| 43 | + | if a == nil || a.view == nil { | |
| 44 | + | return nil | |
| 45 | + | } | |
| 46 | + | return a.view.Widget() | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | // GLArea returns the underlying GtkGLArea for signal connections (resize, | |
| 50 | + | // tick, etc.). Signal connection/disconnection must happen on the GTK thread. | |
| 51 | + | func (a *Cef2gtkAdapter) GLArea() *gtk.GLArea { | |
| 52 | + | if a == nil || a.view == nil { | |
| 53 | + | return nil | |
| 54 | + | } | |
| 55 | + | return a.view.GLArea() | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // NativeWidget returns the uintptr of the GLArea for embedding via | |
| 59 | + | // port.NativeWidgetProvider. | |
| 60 | + | func (a *Cef2gtkAdapter) NativeWidget() uintptr { | |
| 61 | + | area := a.GLArea() | |
| 62 | + | if area == nil { | |
| 63 | + | return 0 | |
| 64 | + | } | |
| 65 | + | return area.GoPointer() | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // Size returns the bridge's last observed positive widget size, or 1x1 before | |
| 69 | + | // the GTK widget has been allocated. It is safe to call off the GTK thread. | |
| 70 | + | func (a *Cef2gtkAdapter) Size() (int32, int32) { | |
| 71 | + | if a == nil || a.view == nil { | |
| 72 | + | return 1, 1 | |
| 73 | + | } | |
| 74 | + | return a.view.Size() | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // DeviceScaleFactor returns the bridge's last observed GTK scale factor, or 1 | |
| 78 | + | // before the widget has reported a scale. It is safe to call off the GTK thread. | |
| 79 | + | func (a *Cef2gtkAdapter) DeviceScaleFactor() float32 { | |
| 80 | + | if a == nil || a.view == nil { | |
| 81 | + | return 1 | |
| 82 | + | } | |
| 83 | + | return a.view.DeviceScaleFactor() | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // AddSizeObserver registers a positive-size change callback. Register and | |
| 87 | + | // unregister from the GTK main thread; callbacks are invoked by the bridge from | |
| 88 | + | // GTK size notifications. | |
| 89 | + | func (a *Cef2gtkAdapter) AddSizeObserver(fn func(width, height int32)) func() { | |
| 90 | + | if a == nil || a.view == nil { | |
| 91 | + | return func() {} | |
| 92 | + | } | |
| 93 | + | return a.view.AddSizeObserver(fn) | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // HasFocus reports whether the bridge widget currently has GTK focus. Must be | |
| 97 | + | // called on the GTK main thread. | |
| 98 | + | func (a *Cef2gtkAdapter) HasFocus() bool { | |
| 99 | + | if a == nil || a.view == nil { | |
| 100 | + | return false | |
| 101 | + | } | |
| 102 | + | return a.view.HasFocus() | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // SetCursorFromName applies a named cursor to the bridge widget. Must be called | |
| 106 | + | // on the GTK main thread. | |
| 107 | + | func (a *Cef2gtkAdapter) SetCursorFromName(name string) { | |
| 108 | + | if a == nil || a.view == nil { | |
| 109 | + | return | |
| 110 | + | } | |
| 111 | + | a.view.SetCursorFromName(name) | |
| 112 | + | } | |
| 113 | + | ||
| 114 | + | // PrepareOnGTKThread initializes GL/EGL resources owned by purego-cef2gtk. | |
| 115 | + | // Must be called on the GTK main thread. | |
| 116 | + | func (a *Cef2gtkAdapter) PrepareOnGTKThread() error { | |
| 117 | + | if a == nil || a.view == nil { | |
| 118 | + | return ErrAdapterDestroyed | |
| 119 | + | } | |
| 120 | + | return a.view.PrepareOnGTKThread() | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | // RenderHandler returns a CEF render handler that delegates accelerated paint | |
| 124 | + | // handling to purego-cef2gtk. The returned handler satisfies cef.RenderHandler | |
| 125 | + | // and uses the bridge's DMABUF/EGL import path. | |
| 126 | + | // | |
| 127 | + | // hooks may be a zero-value cef2gtk.Hooks if no custom callbacks are needed. | |
| 128 | + | func (a *Cef2gtkAdapter) RenderHandler(hooks cef2gtk.Hooks) purecef.RenderHandler { | |
| 129 | + | if a == nil || a.view == nil { | |
| 130 | + | return nil | |
| 131 | + | } | |
| 132 | + | return a.view.RenderHandler(hooks) | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | // AttachInput attaches GTK event controllers to the view and forwards input | |
| 136 | + | // to the given CEF browser host. Must be called on the GTK main thread. | |
| 137 | + | // | |
| 138 | + | // opts.Scale configures HiDPI scale for pointer coordinate translation. | |
| 139 | + | func (a *Cef2gtkAdapter) AttachInput(host purecef.BrowserHost, opts cef2gtk.InputOptions) error { | |
| 140 | + | if a == nil || a.view == nil { | |
| 141 | + | return ErrAdapterDestroyed | |
| 142 | + | } | |
| 143 | + | return a.view.AttachInput(host, opts) | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | // SetInputHost updates the CEF browser host used by the attached input bridge. | |
| 147 | + | // Must be called on the GTK main thread. Callers must call AttachInput first or | |
| 148 | + | // this returns an error from the underlying bridge. | |
| 149 | + | func (a *Cef2gtkAdapter) SetInputHost(host purecef.BrowserHost) error { | |
| 150 | + | if a == nil || a.view == nil { | |
| 151 | + | return ErrAdapterDestroyed | |
| 152 | + | } | |
| 153 | + | return a.view.SetInputHost(host) | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | // DetachInput removes GTK input controllers attached by AttachInput. | |
| 157 | + | // Must be called on the GTK main thread. | |
| 158 | + | func (a *Cef2gtkAdapter) DetachInput() error { | |
| 159 | + | if a == nil || a.view == nil { | |
| 160 | + | return ErrAdapterDestroyed | |
| 161 | + | } | |
| 162 | + | return a.view.DetachInput() | |
| 163 | + | } | |
| 164 | + | ||
| 165 | + | // Diagnostics returns a point-in-time snapshot of bridge rendering diagnostics | |
| 166 | + | // including accelerated paint counts, import/render failures, and events. | |
| 167 | + | func (a *Cef2gtkAdapter) Diagnostics() cef2gtk.Diagnostics { | |
| 168 | + | if a == nil || a.view == nil { | |
| 169 | + | return cef2gtk.Diagnostics{} | |
| 170 | + | } | |
| 171 | + | return a.view.Diagnostics() | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | // Destroy releases GL resources owned by purego-cef2gtk and disconnects GTK | |
| 175 | + | // signal handlers. Must be called on the GTK main thread. Not safe for | |
| 176 | + | // concurrent use. After Destroy, the adapter is marked destroyed and all | |
| 177 | + | // subsequent operations return ErrAdapterDestroyed. | |
| 178 | + | func (a *Cef2gtkAdapter) Destroy() error { | |
| 179 | + | if a == nil { | |
| 180 | + | return ErrAdapterDestroyed | |
| 181 | + | } | |
| 182 | + | if a.view == nil { | |
| 183 | + | a.destroyed = true | |
| 184 | + | return ErrAdapterDestroyed | |
| 185 | + | } | |
| 186 | + | err := a.view.Destroy() | |
| 187 | + | a.view = nil | |
| 188 | + | a.destroyed = true | |
| 189 | + | return err | |
| 190 | + | } | |
| 191 | + | ||
| 192 | + | // IsDestroyed returns true if the adapter has been destroyed. | |
| 193 | + | func (a *Cef2gtkAdapter) IsDestroyed() bool { | |
| 194 | + | return a == nil || a.destroyed | |
| 195 | + | } | |
| @@ -0,0 +1,195 @@ | |||||
| 1 | + | package cef | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "errors" | |||
| 5 | + | ||||
| 6 | + | purecef "github.com/bnema/purego-cef/cef" | |||
| 7 | + | cef2gtk "github.com/bnema/purego-cef2gtk" | |||
| 8 | + | "github.com/bnema/puregotk/v4/gtk" | |||
| 9 | + | ) | |||
| 10 | + | ||||
| 11 | + | // ErrAdapterDestroyed is returned when an operation is attempted on a destroyed | |||
| 12 | + | // Cef2gtkAdapter. | |||
| 13 | + | var ErrAdapterDestroyed = errors.New("cef2gtk_adapter: adapter is destroyed") | |||
| 14 | + | ||||
| 15 | + | // Cef2gtkAdapter is a thin infrastructure adapter around *cef2gtk.View. It | |||
| 16 | + | // keeps purego-cef2gtk imports confined to internal/infrastructure/cef. | |||
| 17 | + | // | |||
| 18 | + | // GTK-thread affinity is a hard constraint: most methods touch GTK/CEF view | |||
| 19 | + | // lifecycle or input and MUST be called from Dumber's GTK scheduling path | |||
| 20 | + | // (e.g. runOnGTK or runOnGTKSync) unless the caller is already executing on | |||
| 21 | + | // the GTK main context. Methods are annotated below. | |||
| 22 | + | // | |||
| 23 | + | // The adapter does NOT own GL/PBO staging, dirty-rect uploads, or GTK input | |||
| 24 | + | // controller implementation — those belong to purego-cef2gtk. | |||
| 25 | + | type Cef2gtkAdapter struct { | |||
| 26 | + | view *cef2gtk.View | |||
| 27 | + | destroyed bool | |||
| 28 | + | } | |||
| 29 | + | ||||
| 30 | + | // NewCef2gtkAdapter creates a GtkGLArea-backed accelerated CEF view and wraps | |||
| 31 | + | // it in a thin Dumber adapter. | |||
| 32 | + | func NewCef2gtkAdapter() *Cef2gtkAdapter { | |||
| 33 | + | v := cef2gtk.NewView() | |||
| 34 | + | if v == nil { | |||
| 35 | + | return nil | |||
| 36 | + | } | |||
| 37 | + | return &Cef2gtkAdapter{view: v} | |||
| 38 | + | } | |||
| 39 | + | ||||
| 40 | + | // Widget returns the native GTK widget for embedding into containers. | |||
| 41 | + | // The returned pointer must be used from the GTK main thread for packing. | |||
| 42 | + | func (a *Cef2gtkAdapter) Widget() *gtk.Widget { | |||
| 43 | + | if a == nil || a.view == nil { | |||
| 44 | + | return nil | |||
| 45 | + | } | |||
| 46 | + | return a.view.Widget() | |||
| 47 | + | } | |||
| 48 | + | ||||
| 49 | + | // GLArea returns the underlying GtkGLArea for signal connections (resize, | |||
| 50 | + | // tick, etc.). Signal connection/disconnection must happen on the GTK thread. | |||
| 51 | + | func (a *Cef2gtkAdapter) GLArea() *gtk.GLArea { | |||
| 52 | + | if a == nil || a.view == nil { | |||
| 53 | + | return nil | |||
| 54 | + | } | |||
| 55 | + | return a.view.GLArea() | |||
| 56 | + | } | |||
| 57 | + | ||||
| 58 | + | // NativeWidget returns the uintptr of the GLArea for embedding via | |||
| 59 | + | // port.NativeWidgetProvider. | |||
| 60 | + | func (a *Cef2gtkAdapter) NativeWidget() uintptr { | |||
| 61 | + | area := a.GLArea() | |||
| 62 | + | if area == nil { | |||
| 63 | + | return 0 | |||
| 64 | + | } | |||
| 65 | + | return area.GoPointer() | |||
| 66 | + | } | |||
| 67 | + | ||||
| 68 | + | // Size returns the bridge's last observed positive widget size, or 1x1 before | |||
| 69 | + | // the GTK widget has been allocated. It is safe to call off the GTK thread. | |||
| 70 | + | func (a *Cef2gtkAdapter) Size() (int32, int32) { | |||
| 71 | + | if a == nil || a.view == nil { | |||
| 72 | + | return 1, 1 | |||
| 73 | + | } | |||
| 74 | + | return a.view.Size() | |||
| 75 | + | } | |||
| 76 | + | ||||
| 77 | + | // DeviceScaleFactor returns the bridge's last observed GTK scale factor, or 1 | |||
| 78 | + | // before the widget has reported a scale. It is safe to call off the GTK thread. | |||
| 79 | + | func (a *Cef2gtkAdapter) DeviceScaleFactor() float32 { | |||
| 80 | + | if a == nil || a.view == nil { | |||
| 81 | + | return 1 | |||
| 82 | + | } | |||
| 83 | + | return a.view.DeviceScaleFactor() | |||
| 84 | + | } | |||
| 85 | + | ||||
| 86 | + | // AddSizeObserver registers a positive-size change callback. Register and | |||
| 87 | + | // unregister from the GTK main thread; callbacks are invoked by the bridge from | |||
| 88 | + | // GTK size notifications. | |||
| 89 | + | func (a *Cef2gtkAdapter) AddSizeObserver(fn func(width, height int32)) func() { | |||
| 90 | + | if a == nil || a.view == nil { | |||
| 91 | + | return func() {} | |||
| 92 | + | } | |||
| 93 | + | return a.view.AddSizeObserver(fn) | |||
| 94 | + | } | |||
| 95 | + | ||||
| 96 | + | // HasFocus reports whether the bridge widget currently has GTK focus. Must be | |||
| 97 | + | // called on the GTK main thread. | |||
| 98 | + | func (a *Cef2gtkAdapter) HasFocus() bool { | |||
| 99 | + | if a == nil || a.view == nil { | |||
| 100 | + | return false | |||
| 101 | + | } | |||
| 102 | + | return a.view.HasFocus() | |||
| 103 | + | } | |||
| 104 | + | ||||
| 105 | + | // SetCursorFromName applies a named cursor to the bridge widget. Must be called | |||
| 106 | + | // on the GTK main thread. | |||
| 107 | + | func (a *Cef2gtkAdapter) SetCursorFromName(name string) { | |||
| 108 | + | if a == nil || a.view == nil { | |||
| 109 | + | return | |||
| 110 | + | } | |||
| 111 | + | a.view.SetCursorFromName(name) | |||
| 112 | + | } | |||
| 113 | + | ||||
| 114 | + | // PrepareOnGTKThread initializes GL/EGL resources owned by purego-cef2gtk. | |||
| 115 | + | // Must be called on the GTK main thread. | |||
| 116 | + | func (a *Cef2gtkAdapter) PrepareOnGTKThread() error { | |||
| 117 | + | if a == nil || a.view == nil { | |||
| 118 | + | return ErrAdapterDestroyed | |||
| 119 | + | } | |||
| 120 | + | return a.view.PrepareOnGTKThread() | |||
| 121 | + | } | |||
| 122 | + | ||||
| 123 | + | // RenderHandler returns a CEF render handler that delegates accelerated paint | |||
| 124 | + | // handling to purego-cef2gtk. The returned handler satisfies cef.RenderHandler | |||
| 125 | + | // and uses the bridge's DMABUF/EGL import path. | |||
| 126 | + | // | |||
| 127 | + | // hooks may be a zero-value cef2gtk.Hooks if no custom callbacks are needed. | |||
| 128 | + | func (a *Cef2gtkAdapter) RenderHandler(hooks cef2gtk.Hooks) purecef.RenderHandler { | |||
| 129 | + | if a == nil || a.view == nil { | |||
| 130 | + | return nil | |||
| 131 | + | } | |||
| 132 | + | return a.view.RenderHandler(hooks) | |||
| 133 | + | } | |||
| 134 | + | ||||
| 135 | + | // AttachInput attaches GTK event controllers to the view and forwards input | |||
| 136 | + | // to the given CEF browser host. Must be called on the GTK main thread. | |||
| 137 | + | // | |||
| 138 | + | // opts.Scale configures HiDPI scale for pointer coordinate translation. | |||
| 139 | + | func (a *Cef2gtkAdapter) AttachInput(host purecef.BrowserHost, opts cef2gtk.InputOptions) error { | |||
| 140 | + | if a == nil || a.view == nil { | |||
| 141 | + | return ErrAdapterDestroyed | |||
| 142 | + | } | |||
| 143 | + | return a.view.AttachInput(host, opts) | |||
| 144 | + | } | |||
| 145 | + | ||||
| 146 | + | // SetInputHost updates the CEF browser host used by the attached input bridge. | |||
| 147 | + | // Must be called on the GTK main thread. Callers must call AttachInput first or | |||
| 148 | + | // this returns an error from the underlying bridge. | |||
| 149 | + | func (a *Cef2gtkAdapter) SetInputHost(host purecef.BrowserHost) error { | |||
| 150 | + | if a == nil || a.view == nil { | |||
| 151 | + | return ErrAdapterDestroyed | |||
| 152 | + | } | |||
| 153 | + | return a.view.SetInputHost(host) | |||
| 154 | + | } | |||
| 155 | + | ||||
| 156 | + | // DetachInput removes GTK input controllers attached by AttachInput. | |||
| 157 | + | // Must be called on the GTK main thread. | |||
| 158 | + | func (a *Cef2gtkAdapter) DetachInput() error { | |||
| 159 | + | if a == nil || a.view == nil { | |||
| 160 | + | return ErrAdapterDestroyed | |||
| 161 | + | } | |||
| 162 | + | return a.view.DetachInput() | |||
| 163 | + | } | |||
| 164 | + | ||||
| 165 | + | // Diagnostics returns a point-in-time snapshot of bridge rendering diagnostics | |||
| 166 | + | // including accelerated paint counts, import/render failures, and events. | |||
| 167 | + | func (a *Cef2gtkAdapter) Diagnostics() cef2gtk.Diagnostics { | |||
| 168 | + | if a == nil || a.view == nil { | |||
| 169 | + | return cef2gtk.Diagnostics{} | |||
| 170 | + | } | |||
| 171 | + | return a.view.Diagnostics() | |||
| 172 | + | } | |||
| 173 | + | ||||
| 174 | + | // Destroy releases GL resources owned by purego-cef2gtk and disconnects GTK | |||
| 175 | + | // signal handlers. Must be called on the GTK main thread. Not safe for | |||
| 176 | + | // concurrent use. After Destroy, the adapter is marked destroyed and all | |||
| 177 | + | // subsequent operations return ErrAdapterDestroyed. | |||
| 178 | + | func (a *Cef2gtkAdapter) Destroy() error { | |||
| 179 | + | if a == nil { | |||
| 180 | + | return ErrAdapterDestroyed | |||
| 181 | + | } | |||
| 182 | + | if a.view == nil { | |||
| 183 | + | a.destroyed = true | |||
| 184 | + | return ErrAdapterDestroyed | |||
| 185 | + | } | |||
| 186 | + | err := a.view.Destroy() | |||
| 187 | + | a.view = nil | |||
| 188 | + | a.destroyed = true | |||
| 189 | + | return err | |||
| 190 | + | } | |||
| 191 | + | ||||
| 192 | + | // IsDestroyed returns true if the adapter has been destroyed. | |||
| 193 | + | func (a *Cef2gtkAdapter) IsDestroyed() bool { | |||
| 194 | + | return a == nil || a.destroyed | |||
| 195 | + | } | |||
A internal/infrastructure/cef/cef2gtk_migration_audit.md +81 -0
| @@ -0,0 +1,81 @@ | |||
| 1 | + | # purego-cef2gtk migration audit | |
| 2 | + | ||
| 3 | + | Date: 2026-04-29 | |
| 4 | + | Branch: `feature/use-purego-cef2gtk` | |
| 5 | + | ||
| 6 | + | This audit records the old Dumber CEF/GTK rendering/input stack references that must be replaced before the old files are deleted. | |
| 7 | + | ||
| 8 | + | ## Old-stack references | |
| 9 | + | ||
| 10 | + | ### `renderPipeline` | |
| 11 | + | ||
| 12 | + | - Defined in `internal/infrastructure/cef/render_pipeline.go`. | |
| 13 | + | - Owned by `WebView.pipeline` in `webview.go`. | |
| 14 | + | - Created in `factory.go`. | |
| 15 | + | - Used for view rect/screen info, popup paint, CPU `OnPaint`, diagnostics, cursor updates, begin-frame `GtkGLArea`, native widget, and resize callbacks. | |
| 16 | + | ||
| 17 | + | Classification: | |
| 18 | + | ||
| 19 | + | - Rendering/GL upload: replace with `purego-cef2gtk.View.RenderHandler` and accelerated DMABUF path. | |
| 20 | + | - Widget/GLArea access: replace with the thin Dumber `Cef2gtkAdapter`. | |
| 21 | + | - Size/resize: use `purego-cef2gtk` size observer/size APIs plus small Dumber browser lifecycle callbacks. | |
| 22 | + | - Software paint/PBO tests: delete or move responsibility to `purego-cef2gtk` tests. | |
| 23 | + | ||
| 24 | + | ### `inputBridge` | |
| 25 | + | ||
| 26 | + | - Defined in `internal/infrastructure/cef/input_bridge.go`. | |
| 27 | + | - Created and attached in `factory.go`. | |
| 28 | + | - Host updated/cleared in `webview_handlers.go`. | |
| 29 | + | - Focus queried in loading/focus paths. | |
| 30 | + | - Middle-click link behavior wired in `factory.go` via `OnLinkMiddleClick` and cached hover URI. | |
| 31 | + | ||
| 32 | + | Classification: | |
| 33 | + | ||
| 34 | + | - Mouse/key/scroll/IME/paste/focus forwarding: replace with `purego-cef2gtk.View.AttachInput`, `SetInputHost`, and `DetachInput`. | |
| 35 | + | - Host attach/update/detach: call through Dumber GTK scheduling path. | |
| 36 | + | - Focus state: use bridge focus helper on GTK thread. | |
| 37 | + | - Middle-click link open: preserve through `purego-cef2gtk.InputOptions.OnMiddleClick`. | |
| 38 | + | - Old input translation tests: delete from Dumber or replace with lifecycle/callback wiring tests. | |
| 39 | + | ||
| 40 | + | ### `glLoader` | |
| 41 | + | ||
| 42 | + | - Defined in `internal/infrastructure/cef/gl_loader.go`. | |
| 43 | + | - Owned by `Engine.gl` and created in `engine_init.go`. | |
| 44 | + | - Passed to factory and consumed by `renderPipeline`. | |
| 45 | + | ||
| 46 | + | Classification: delete from Dumber. GL/EGL loading belongs to `purego-cef2gtk` internals. | |
| 47 | + | ||
| 48 | + | ### `resizeReconciler` | |
| 49 | + | ||
| 50 | + | - Defined in `internal/infrastructure/cef/resize_reconciler.go`. | |
| 51 | + | - Owned by `WebView.resizeReconciler`. | |
| 52 | + | - Started from resize callbacks and paint completion callbacks. | |
| 53 | + | ||
| 54 | + | Classification: | |
| 55 | + | ||
| 56 | + | - Paint-based retry/diagnostics: obsolete after deleting Dumber software paint pipeline. | |
| 57 | + | - Browser resize notification: keep only a small Dumber lifecycle path that calls CEF host `WasResized`/`Invalidate` from bridge size events. | |
| 58 | + | ||
| 59 | + | ## Non-obvious callouts | |
| 60 | + | ||
| 61 | + | - Load watchdog diagnostics in `webview.go` currently log `renderPipelineSnapshot`; replace with bridge diagnostics, accepting less Dumber-specific render detail unless a real product need appears. | |
| 62 | + | - Cursor updates in `webview_handlers.go` currently call `wv.pipeline.glArea.SetCursorFromName`; replace with `Cef2gtkAdapter.SetCursorFromName` on GTK thread. | |
| 63 | + | - Loading/focus checks currently use `wv.input.hasGTKFocus`; replace with bridge focus helper on GTK thread. | |
| 64 | + | - Browser close currently clears old input host directly; replace with GTK-thread `SetInputHost(nil)` or `DetachInput`. | |
| 65 | + | - Begin-frame loop currently uses `pipeline.glArea`; replace with adapter `GLArea` if external begin frame remains enabled. | |
| 66 | + | - `NativeWidget` currently returns old GLArea pointer; replace with adapter native widget pointer. | |
| 67 | + | - Popup/select handling needs runtime verification. `purego-cef2gtk` currently treats CPU `OnPaint` as diagnostic-only and popup callbacks as no-op. | |
| 68 | + | - Text selection updates Dumber state and should be preserved through render-handler hook/composition while paint handling delegates to the bridge. | |
| 69 | + | ||
| 70 | + | ## Upstream bridge gaps addressed during Phase 2 | |
| 71 | + | ||
| 72 | + | `purego-cef2gtk` now exposes or implements: | |
| 73 | + | ||
| 74 | + | - real size access and size observers; | |
| 75 | + | - device scale factor access; | |
| 76 | + | - `GetScreenInfo` based on bridge size/scale; | |
| 77 | + | - text-selection render hook; | |
| 78 | + | - middle-click input hook; | |
| 79 | + | - focus and cursor helpers. | |
| 80 | + | ||
| 81 | + | Remaining runtime risk: popup/select behavior should be smoke-tested after Dumber is fully migrated. | |
| @@ -0,0 +1,81 @@ | |||||
| 1 | + | # purego-cef2gtk migration audit | |||
| 2 | + | ||||
| 3 | + | Date: 2026-04-29 | |||
| 4 | + | Branch: `feature/use-purego-cef2gtk` | |||
| 5 | + | ||||
| 6 | + | This audit records the old Dumber CEF/GTK rendering/input stack references that must be replaced before the old files are deleted. | |||
| 7 | + | ||||
| 8 | + | ## Old-stack references | |||
| 9 | + | ||||
| 10 | + | ### `renderPipeline` | |||
| 11 | + | ||||
| 12 | + | - Defined in `internal/infrastructure/cef/render_pipeline.go`. | |||
| 13 | + | - Owned by `WebView.pipeline` in `webview.go`. | |||
| 14 | + | - Created in `factory.go`. | |||
| 15 | + | - Used for view rect/screen info, popup paint, CPU `OnPaint`, diagnostics, cursor updates, begin-frame `GtkGLArea`, native widget, and resize callbacks. | |||
| 16 | + | ||||
| 17 | + | Classification: | |||
| 18 | + | ||||
| 19 | + | - Rendering/GL upload: replace with `purego-cef2gtk.View.RenderHandler` and accelerated DMABUF path. | |||
| 20 | + | - Widget/GLArea access: replace with the thin Dumber `Cef2gtkAdapter`. | |||
| 21 | + | - Size/resize: use `purego-cef2gtk` size observer/size APIs plus small Dumber browser lifecycle callbacks. | |||
| 22 | + | - Software paint/PBO tests: delete or move responsibility to `purego-cef2gtk` tests. | |||
| 23 | + | ||||
| 24 | + | ### `inputBridge` | |||
| 25 | + | ||||
| 26 | + | - Defined in `internal/infrastructure/cef/input_bridge.go`. | |||
| 27 | + | - Created and attached in `factory.go`. | |||
| 28 | + | - Host updated/cleared in `webview_handlers.go`. | |||
| 29 | + | - Focus queried in loading/focus paths. | |||
| 30 | + | - Middle-click link behavior wired in `factory.go` via `OnLinkMiddleClick` and cached hover URI. | |||
| 31 | + | ||||
| 32 | + | Classification: | |||
| 33 | + | ||||
| 34 | + | - Mouse/key/scroll/IME/paste/focus forwarding: replace with `purego-cef2gtk.View.AttachInput`, `SetInputHost`, and `DetachInput`. | |||
| 35 | + | - Host attach/update/detach: call through Dumber GTK scheduling path. | |||
| 36 | + | - Focus state: use bridge focus helper on GTK thread. | |||
| 37 | + | - Middle-click link open: preserve through `purego-cef2gtk.InputOptions.OnMiddleClick`. | |||
| 38 | + | - Old input translation tests: delete from Dumber or replace with lifecycle/callback wiring tests. | |||
| 39 | + | ||||
| 40 | + | ### `glLoader` | |||
| 41 | + | ||||
| 42 | + | - Defined in `internal/infrastructure/cef/gl_loader.go`. | |||
| 43 | + | - Owned by `Engine.gl` and created in `engine_init.go`. | |||
| 44 | + | - Passed to factory and consumed by `renderPipeline`. | |||
| 45 | + | ||||
| 46 | + | Classification: delete from Dumber. GL/EGL loading belongs to `purego-cef2gtk` internals. | |||
| 47 | + | ||||
| 48 | + | ### `resizeReconciler` | |||
| 49 | + | ||||
| 50 | + | - Defined in `internal/infrastructure/cef/resize_reconciler.go`. | |||
| 51 | + | - Owned by `WebView.resizeReconciler`. | |||
| 52 | + | - Started from resize callbacks and paint completion callbacks. | |||
| 53 | + | ||||
| 54 | + | Classification: | |||
| 55 | + | ||||
| 56 | + | - Paint-based retry/diagnostics: obsolete after deleting Dumber software paint pipeline. | |||
| 57 | + | - Browser resize notification: keep only a small Dumber lifecycle path that calls CEF host `WasResized`/`Invalidate` from bridge size events. | |||
| 58 | + | ||||
| 59 | + | ## Non-obvious callouts | |||
| 60 | + | ||||
| 61 | + | - Load watchdog diagnostics in `webview.go` currently log `renderPipelineSnapshot`; replace with bridge diagnostics, accepting less Dumber-specific render detail unless a real product need appears. | |||
| 62 | + | - Cursor updates in `webview_handlers.go` currently call `wv.pipeline.glArea.SetCursorFromName`; replace with `Cef2gtkAdapter.SetCursorFromName` on GTK thread. | |||
| 63 | + | - Loading/focus checks currently use `wv.input.hasGTKFocus`; replace with bridge focus helper on GTK thread. | |||
| 64 | + | - Browser close currently clears old input host directly; replace with GTK-thread `SetInputHost(nil)` or `DetachInput`. | |||
| 65 | + | - Begin-frame loop currently uses `pipeline.glArea`; replace with adapter `GLArea` if external begin frame remains enabled. | |||
| 66 | + | - `NativeWidget` currently returns old GLArea pointer; replace with adapter native widget pointer. | |||
| 67 | + | - Popup/select handling needs runtime verification. `purego-cef2gtk` currently treats CPU `OnPaint` as diagnostic-only and popup callbacks as no-op. | |||
| 68 | + | - Text selection updates Dumber state and should be preserved through render-handler hook/composition while paint handling delegates to the bridge. | |||
| 69 | + | ||||
| 70 | + | ## Upstream bridge gaps addressed during Phase 2 | |||
| 71 | + | ||||
| 72 | + | `purego-cef2gtk` now exposes or implements: | |||
| 73 | + | ||||
| 74 | + | - real size access and size observers; | |||
| 75 | + | - device scale factor access; | |||
| 76 | + | - `GetScreenInfo` based on bridge size/scale; | |||
| 77 | + | - text-selection render hook; | |||
| 78 | + | - middle-click input hook; | |||
| 79 | + | - focus and cursor helpers. | |||
| 80 | + | ||||
| 81 | + | Remaining runtime risk: popup/select behavior should be smoke-tested after Dumber is fully migrated. | |||