fix(ui): prevent early GTK notify::position from overwriting restored split ratios
- commit
- 67bb8aa9372319e8c8792c818af103b6f67fd7a4
- author
- brice · · 2025-12-26 07:52 UTC
- parent
- 19bb708
- signature
- unsigned
1 file · +30 -0
M internal/ui/layout/split.go +30 -0
| @@ -24,6 +24,9 @@ type SplitView struct { | |||
| 24 | 24 | pendingNotifyRatio float64 | |
| 25 | 25 | notifyDebounceTimer *time.Timer | |
| 26 | 26 | ||
| 27 | + | hasAppliedRatio bool | |
| 28 | + | suppressNotifyUntil time.Time | |
| 29 | + | ||
| 27 | 30 | mu sync.RWMutex | |
| 28 | 31 | } | |
| 29 | 32 | ||
| @@ -81,6 +84,21 @@ func NewSplitView( | |||
| 81 | 84 | return | |
| 82 | 85 | } | |
| 83 | 86 | ||
| 87 | + | now := time.Now() | |
| 88 | + | ||
| 89 | + | sv.mu.Lock() | |
| 90 | + | // Ignore early notifications before we've applied the snapshot ratio. | |
| 91 | + | // GTK often emits an initial notify::position (typically 50/50) during allocation. | |
| 92 | + | if !sv.hasAppliedRatio { | |
| 93 | + | sv.mu.Unlock() | |
| 94 | + | return | |
| 95 | + | } | |
| 96 | + | if !sv.suppressNotifyUntil.IsZero() && now.Before(sv.suppressNotifyUntil) { | |
| 97 | + | sv.mu.Unlock() | |
| 98 | + | return | |
| 99 | + | } | |
| 100 | + | sv.mu.Unlock() | |
| 101 | + | ||
| 84 | 102 | ratio := clampRatio(float64(position) / float64(totalSize)) | |
| 85 | 103 | ||
| 86 | 104 | sv.mu.Lock() | |
| @@ -204,7 +222,19 @@ func (sv *SplitView) ApplyRatio() bool { | |||
| 204 | 222 | Float64("ratio", ratio). | |
| 205 | 223 | Int("position", position). | |
| 206 | 224 | Msg("ApplyRatio: setting position") | |
| 225 | + | ||
| 226 | + | // Avoid treating programmatic SetPosition as a user resize. | |
| 227 | + | // We suppress notify::position briefly; GTK may emit during/after SetPosition. | |
| 228 | + | sv.mu.Lock() | |
| 229 | + | sv.suppressNotifyUntil = time.Now().Add(50 * time.Millisecond) | |
| 230 | + | sv.mu.Unlock() | |
| 231 | + | ||
| 207 | 232 | sv.paned.SetPosition(position) | |
| 233 | + | ||
| 234 | + | sv.mu.Lock() | |
| 235 | + | sv.hasAppliedRatio = true | |
| 236 | + | sv.mu.Unlock() | |
| 237 | + | ||
| 208 | 238 | return true | |
| 209 | 239 | } | |
| 210 | 240 | ||
| @@ -24,6 +24,9 @@ type SplitView struct { | |||||
| 24 | pendingNotifyRatio float64 | 24 | pendingNotifyRatio float64 | ||
| 25 | notifyDebounceTimer *time.Timer | 25 | notifyDebounceTimer *time.Timer | ||
| 26 | 26 | ||||
| 27 | + | hasAppliedRatio bool | |||
| 28 | + | suppressNotifyUntil time.Time | |||
| 29 | + | ||||
| 27 | mu sync.RWMutex | 30 | mu sync.RWMutex | ||
| 28 | } | 31 | } | ||
| 29 | 32 | ||||
| @@ -81,6 +84,21 @@ func NewSplitView( | |||||
| 81 | return | 84 | return | ||
| 82 | } | 85 | } | ||
| 83 | 86 | ||||
| 87 | + | now := time.Now() | |||
| 88 | + | ||||
| 89 | + | sv.mu.Lock() | |||
| 90 | + | // Ignore early notifications before we've applied the snapshot ratio. | |||
| 91 | + | // GTK often emits an initial notify::position (typically 50/50) during allocation. | |||
| 92 | + | if !sv.hasAppliedRatio { | |||
| 93 | + | sv.mu.Unlock() | |||
| 94 | + | return | |||
| 95 | + | } | |||
| 96 | + | if !sv.suppressNotifyUntil.IsZero() && now.Before(sv.suppressNotifyUntil) { | |||
| 97 | + | sv.mu.Unlock() | |||
| 98 | + | return | |||
| 99 | + | } | |||
| 100 | + | sv.mu.Unlock() | |||
| 101 | + | ||||
| 84 | ratio := clampRatio(float64(position) / float64(totalSize)) | 102 | ratio := clampRatio(float64(position) / float64(totalSize)) | ||
| 85 | 103 | ||||
| 86 | sv.mu.Lock() | 104 | sv.mu.Lock() | ||
| @@ -204,7 +222,19 @@ func (sv *SplitView) ApplyRatio() bool { | |||||
| 204 | Float64("ratio", ratio). | 222 | Float64("ratio", ratio). | ||
| 205 | Int("position", position). | 223 | Int("position", position). | ||
| 206 | Msg("ApplyRatio: setting position") | 224 | Msg("ApplyRatio: setting position") | ||
| 225 | + | ||||
| 226 | + | // Avoid treating programmatic SetPosition as a user resize. | |||
| 227 | + | // We suppress notify::position briefly; GTK may emit during/after SetPosition. | |||
| 228 | + | sv.mu.Lock() | |||
| 229 | + | sv.suppressNotifyUntil = time.Now().Add(50 * time.Millisecond) | |||
| 230 | + | sv.mu.Unlock() | |||
| 231 | + | ||||
| 207 | sv.paned.SetPosition(position) | 232 | sv.paned.SetPosition(position) | ||
| 233 | + | ||||
| 234 | + | sv.mu.Lock() | |||
| 235 | + | sv.hasAppliedRatio = true | |||
| 236 | + | sv.mu.Unlock() | |||
| 237 | + | ||||
| 208 | return true | 238 | return true | ||
| 209 | } | 239 | } | ||
| 210 | 240 | ||||