detached 6611f45

fix(workspace): ensure root pane redraw after reattachment

commit
6611f459944b8df65e45d417fe148c0bc4dc10c4
author
Brice · · 2025-10-04 20:09 UTC
committer
Brice · · 2025-10-05 13:54 UTC
parent
b29fd2f
signature
unsigned
1 file · +49 -17
M internal/app/browser/workspace_pane_ops.go +49 -17
@@ -456,6 +456,18 @@ func (wm *WorkspaceManager) insertPopupPane(target *paneNode, newPane *BrowserPa
456456
457457 webkit.WidgetShow(paned)
458458
459+ // Force GTK to re-layout the new GtkPaned container once both children are attached.
460+ wm.scheduleIdleGuarded(func() bool {
461+ if split == nil || !split.widgetValid {
462+ return false
463+ }
464+ if split.container != 0 && webkit.WidgetIsValid(split.container) {
465+ webkit.WidgetQueueResize(split.container)
466+ webkit.WidgetQueueDraw(split.container)
467+ }
468+ return false
469+ }, split)
470+
459471 // CRITICAL: Set initial 50/50 split position after showing paned
460472 // GTK needs the widget to be realized before we can set position based on allocation
461473 // Schedule this to run after GTK has allocated space to the paned
@@ -946,12 +958,7 @@ func (wm *WorkspaceManager) cascadePromotion(singleChildPaned *paneNode) {
946958
947959 // Attach to window
948960 if onlyChild.container != 0 && webkit.WidgetIsValid(onlyChild.container) {
949- // GTK4 window.SetChild automatically handles unparenting
950- wm.window.SetChild(onlyChild.container)
951- webkit.WidgetSetHExpand(onlyChild.container, true)
952- webkit.WidgetSetVExpand(onlyChild.container, true)
953- webkit.WidgetQueueAllocate(onlyChild.container)
954- webkit.WidgetShow(onlyChild.container)
961+ wm.attachRoot(onlyChild)
955962 }
956963
957964 // Cleanup the now-orphaned paned
@@ -1008,19 +1015,44 @@ func (wm *WorkspaceManager) attachRoot(root *paneNode) {
10081015 if root == nil || root.container == 0 || wm.window == nil {
10091016 return
10101017 }
1011- if webkit.WidgetIsValid(root.container) {
1012- // GTK4 window.SetChild automatically handles unparenting from old parent
1013- // DO NOT unparent manually as it can destroy complex widgets like GtkBox
1014- wm.window.SetChild(root.container)
1015- webkit.WidgetQueueAllocate(root.container)
1016- webkit.WidgetShow(root.container)
1018+ if !webkit.WidgetIsValid(root.container) {
1019+ return
1020+ }
10171021
1018- // Verify attachment succeeded
1019- if finalParent := webkit.WidgetGetParent(root.container); finalParent == 0 {
1020- log.Printf("[workspace] WARNING: widget %#x has no parent after SetChild", root.container)
1021- } else {
1022- log.Printf("[workspace] attachRoot successful: widget %#x now child of %#x", root.container, finalParent)
1022+ // Clear any existing window child to avoid GTK warnings when swapping roots.
1023+ wm.window.SetChild(0)
1024+
1025+ // Unparent from the previous container (paned, stack, etc.) before reattaching.
1026+ if parent := webkit.WidgetGetParent(root.container); parent != 0 {
1027+ log.Printf("[workspace] unparenting widget %#x from parent %#x before window attach", root.container, parent)
1028+ webkit.WidgetUnparent(root.container)
1029+ }
1030+
1031+ webkit.WidgetSetHExpand(root.container, true)
1032+ webkit.WidgetSetVExpand(root.container, true)
1033+
1034+ wm.window.SetChild(root.container)
1035+ webkit.WidgetQueueAllocate(root.container)
1036+ webkit.WidgetShow(root.container)
1037+ webkit.WidgetQueueResize(root.container)
1038+ webkit.WidgetQueueDraw(root.container)
1039+
1040+ wm.scheduleIdleGuarded(func() bool {
1041+ if root == nil || !root.widgetValid {
1042+ return false
1043+ }
1044+ if root.container != 0 && webkit.WidgetIsValid(root.container) {
1045+ webkit.WidgetQueueResize(root.container)
1046+ webkit.WidgetQueueDraw(root.container)
10231047 }
1048+ return false
1049+ }, root)
1050+
1051+ // Verify attachment succeeded
1052+ if finalParent := webkit.WidgetGetParent(root.container); finalParent == 0 {
1053+ log.Printf("[workspace] WARNING: widget %#x has no parent after SetChild", root.container)
1054+ } else {
1055+ log.Printf("[workspace] attachRoot successful: widget %#x now child of %#x", root.container, finalParent)
10241056 }
10251057 }
10261058
@@ -456,6 +456,18 @@ func (wm *WorkspaceManager) insertPopupPane(target *paneNode, newPane *BrowserPa
456 456
457 webkit.WidgetShow(paned)457 webkit.WidgetShow(paned)
458 458
459+ // Force GTK to re-layout the new GtkPaned container once both children are attached.
460+ wm.scheduleIdleGuarded(func() bool {
461+ if split == nil || !split.widgetValid {
462+ return false
463+ }
464+ if split.container != 0 && webkit.WidgetIsValid(split.container) {
465+ webkit.WidgetQueueResize(split.container)
466+ webkit.WidgetQueueDraw(split.container)
467+ }
468+ return false
469+ }, split)
470+
459 // CRITICAL: Set initial 50/50 split position after showing paned471 // CRITICAL: Set initial 50/50 split position after showing paned
460 // GTK needs the widget to be realized before we can set position based on allocation472 // GTK needs the widget to be realized before we can set position based on allocation
461 // Schedule this to run after GTK has allocated space to the paned473 // Schedule this to run after GTK has allocated space to the paned
@@ -946,12 +958,7 @@ func (wm *WorkspaceManager) cascadePromotion(singleChildPaned *paneNode) {
946 958
947 // Attach to window959 // Attach to window
948 if onlyChild.container != 0 && webkit.WidgetIsValid(onlyChild.container) {960 if onlyChild.container != 0 && webkit.WidgetIsValid(onlyChild.container) {
949- // GTK4 window.SetChild automatically handles unparenting961+ wm.attachRoot(onlyChild)
950- wm.window.SetChild(onlyChild.container)
951- webkit.WidgetSetHExpand(onlyChild.container, true)
952- webkit.WidgetSetVExpand(onlyChild.container, true)
953- webkit.WidgetQueueAllocate(onlyChild.container)
954- webkit.WidgetShow(onlyChild.container)
955 }962 }
956 963
957 // Cleanup the now-orphaned paned964 // Cleanup the now-orphaned paned
@@ -1008,19 +1015,44 @@ func (wm *WorkspaceManager) attachRoot(root *paneNode) {
1008 if root == nil || root.container == 0 || wm.window == nil {1015 if root == nil || root.container == 0 || wm.window == nil {
1009 return1016 return
1010 }1017 }
1011- if webkit.WidgetIsValid(root.container) {1018+ if !webkit.WidgetIsValid(root.container) {
1012- // GTK4 window.SetChild automatically handles unparenting from old parent1019+ return
1013- // DO NOT unparent manually as it can destroy complex widgets like GtkBox1020+ }
1014- wm.window.SetChild(root.container)
1015- webkit.WidgetQueueAllocate(root.container)
1016- webkit.WidgetShow(root.container)
1017 1021
1018- // Verify attachment succeeded1022+ // Clear any existing window child to avoid GTK warnings when swapping roots.
1019- if finalParent := webkit.WidgetGetParent(root.container); finalParent == 0 {1023+ wm.window.SetChild(0)
1020- log.Printf("[workspace] WARNING: widget %#x has no parent after SetChild", root.container)1024+
1021- } else {1025+ // Unparent from the previous container (paned, stack, etc.) before reattaching.
1022- log.Printf("[workspace] attachRoot successful: widget %#x now child of %#x", root.container, finalParent)1026+ if parent := webkit.WidgetGetParent(root.container); parent != 0 {
1027+ log.Printf("[workspace] unparenting widget %#x from parent %#x before window attach", root.container, parent)
1028+ webkit.WidgetUnparent(root.container)
1029+ }
1030+
1031+ webkit.WidgetSetHExpand(root.container, true)
1032+ webkit.WidgetSetVExpand(root.container, true)
1033+
1034+ wm.window.SetChild(root.container)
1035+ webkit.WidgetQueueAllocate(root.container)
1036+ webkit.WidgetShow(root.container)
1037+ webkit.WidgetQueueResize(root.container)
1038+ webkit.WidgetQueueDraw(root.container)
1039+
1040+ wm.scheduleIdleGuarded(func() bool {
1041+ if root == nil || !root.widgetValid {
1042+ return false
1043+ }
1044+ if root.container != 0 && webkit.WidgetIsValid(root.container) {
1045+ webkit.WidgetQueueResize(root.container)
1046+ webkit.WidgetQueueDraw(root.container)
1023 }1047 }
1048+ return false
1049+ }, root)
1050+
1051+ // Verify attachment succeeded
1052+ if finalParent := webkit.WidgetGetParent(root.container); finalParent == 0 {
1053+ log.Printf("[workspace] WARNING: widget %#x has no parent after SetChild", root.container)
1054+ } else {
1055+ log.Printf("[workspace] attachRoot successful: widget %#x now child of %#x", root.container, finalParent)
1024 }1056 }
1025 }1057 }
1026 1058

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close