refactor(browser): prevent GTK bloom filter corruption
Don't manually remove GTK controllers before reparenting - GTK4 does this automatically. Manually removing causes GTK bloom filter corruption and assertion failures. Just mark for reattachment and clear references.
- commit
- a4698c61036dc90f3357f476ca5c1d93aabd6cdf
- author
- bamen · · 2025-10-09 18:46 UTC
- committer
- bamen · · 2025-10-09 18:03 UTC
- parent
- 3a7535c
- signature
- unsigned
1 file · +11 -6
M internal/app/browser/workspace_pane_ops.go +11 -6
| @@ -128,8 +128,10 @@ func (wm *WorkspaceManager) clonePaneState(_ *paneNode, target *paneNode) { | |||
| 128 | 128 | // Omnibox will auto-open on about:blank via client-side detection | |
| 129 | 129 | } | |
| 130 | 130 | ||
| 131 | - | // safelyDetachControllersBeforeReparent removes GTK controllers that GTK will auto-clean up during reparenting. | |
| 132 | - | // It marks nodes for reattachment once the widget hierarchy settles after the split operation. | |
| 131 | + | // safelyDetachControllersBeforeReparent marks nodes for controller reattachment after reparenting. | |
| 132 | + | // GTK4 automatically removes controllers when widgets are unparented, so we just clear our | |
| 133 | + | // references and mark for reattachment. Manually removing controllers causes GTK bloom filter | |
| 134 | + | // corruption (double-removal assertion failure). | |
| 133 | 135 | func (wm *WorkspaceManager) safelyDetachControllersBeforeReparent(node *paneNode) { | |
| 134 | 136 | if wm == nil || node == nil { | |
| 135 | 137 | return | |
| @@ -140,15 +142,18 @@ func (wm *WorkspaceManager) safelyDetachControllersBeforeReparent(node *paneNode | |||
| 140 | 142 | return | |
| 141 | 143 | } | |
| 142 | 144 | ||
| 145 | + | // Just mark for reattachment and clear our references | |
| 146 | + | // GTK4 will auto-remove controllers during unparent | |
| 143 | 147 | if target.hoverToken != nil { | |
| 144 | 148 | target.pendingHoverReattach = true | |
| 145 | - | wm.detachHover(target) | |
| 149 | + | target.hoverToken = nil // Clear reference, don't manually remove | |
| 150 | + | log.Printf("[workspace] Marked hover controller for reattach on pane %p (GTK will auto-remove)", target) | |
| 146 | 151 | } | |
| 147 | 152 | ||
| 148 | - | if wm.focusStateMachine != nil && target.focusControllerToken != 0 { | |
| 149 | - | token := target.focusControllerToken | |
| 153 | + | if target.focusControllerToken != 0 { | |
| 150 | 154 | target.pendingFocusReattach = true | |
| 151 | - | wm.focusStateMachine.detachGTKController(target, token) | |
| 155 | + | target.focusControllerToken = 0 // Clear reference, don't manually remove | |
| 156 | + | log.Printf("[workspace] Marked focus controller for reattach on pane %p (GTK will auto-remove)", target) | |
| 152 | 157 | } | |
| 153 | 158 | } | |
| 154 | 159 | ||
| @@ -128,8 +128,10 @@ func (wm *WorkspaceManager) clonePaneState(_ *paneNode, target *paneNode) { | |||||
| 128 | // Omnibox will auto-open on about:blank via client-side detection | 128 | // Omnibox will auto-open on about:blank via client-side detection | ||
| 129 | } | 129 | } | ||
| 130 | 130 | ||||
| 131 | - | // safelyDetachControllersBeforeReparent removes GTK controllers that GTK will auto-clean up during reparenting. | 131 | + | // safelyDetachControllersBeforeReparent marks nodes for controller reattachment after reparenting. |
| 132 | - | // It marks nodes for reattachment once the widget hierarchy settles after the split operation. | 132 | + | // GTK4 automatically removes controllers when widgets are unparented, so we just clear our |
| 133 | + | // references and mark for reattachment. Manually removing controllers causes GTK bloom filter | |||
| 134 | + | // corruption (double-removal assertion failure). | |||
| 133 | func (wm *WorkspaceManager) safelyDetachControllersBeforeReparent(node *paneNode) { | 135 | func (wm *WorkspaceManager) safelyDetachControllersBeforeReparent(node *paneNode) { | ||
| 134 | if wm == nil || node == nil { | 136 | if wm == nil || node == nil { | ||
| 135 | return | 137 | return | ||
| @@ -140,15 +142,18 @@ func (wm *WorkspaceManager) safelyDetachControllersBeforeReparent(node *paneNode | |||||
| 140 | return | 142 | return | ||
| 141 | } | 143 | } | ||
| 142 | 144 | ||||
| 145 | + | // Just mark for reattachment and clear our references | |||
| 146 | + | // GTK4 will auto-remove controllers during unparent | |||
| 143 | if target.hoverToken != nil { | 147 | if target.hoverToken != nil { | ||
| 144 | target.pendingHoverReattach = true | 148 | target.pendingHoverReattach = true | ||
| 145 | - | wm.detachHover(target) | 149 | + | target.hoverToken = nil // Clear reference, don't manually remove |
| 150 | + | log.Printf("[workspace] Marked hover controller for reattach on pane %p (GTK will auto-remove)", target) | |||
| 146 | } | 151 | } | ||
| 147 | 152 | ||||
| 148 | - | if wm.focusStateMachine != nil && target.focusControllerToken != 0 { | 153 | + | if target.focusControllerToken != 0 { |
| 149 | - | token := target.focusControllerToken | |||
| 150 | target.pendingFocusReattach = true | 154 | target.pendingFocusReattach = true | ||
| 151 | - | wm.focusStateMachine.detachGTKController(target, token) | 155 | + | target.focusControllerToken = 0 // Clear reference, don't manually remove |
| 156 | + | log.Printf("[workspace] Marked focus controller for reattach on pane %p (GTK will auto-remove)", target) | |||
| 152 | } | 157 | } | ||
| 153 | } | 158 | } | ||
| 154 | 159 | ||||