Merge pull request #255 from bnema/fix/omnibox-hover-callback-leak
fix(omnibox): avoid per-row hover callback churn
1 file · +41 -24
M internal/ui/component/omnibox.go +41 -24
| @@ -779,9 +779,50 @@ func (o *Omnibox) initList() error { | |||
| 779 | 779 | o.retainedCallbacks = append(o.retainedCallbacks, rowActivatedCb) | |
| 780 | 780 | o.listBox.ConnectRowActivated(&rowActivatedCb) | |
| 781 | 781 | ||
| 782 | + | o.setupListHoverSelection() | |
| 783 | + | ||
| 782 | 784 | return nil | |
| 783 | 785 | } | |
| 784 | 786 | ||
| 787 | + | func (o *Omnibox) setupListHoverSelection() { | |
| 788 | + | motionCtrl := gtk.NewEventControllerMotion() | |
| 789 | + | if motionCtrl == nil { | |
| 790 | + | logging.FromContext(o.ctx).Error().Msg("failed to create motion event controller") | |
| 791 | + | return | |
| 792 | + | } | |
| 793 | + | ||
| 794 | + | motionCb := func(_ gtk.EventControllerMotion, _ float64, y float64) { | |
| 795 | + | o.handleListHoverSelection(y) | |
| 796 | + | } | |
| 797 | + | o.retainedCallbacks = append(o.retainedCallbacks, motionCb) | |
| 798 | + | motionCtrl.ConnectMotion(&motionCb) | |
| 799 | + | o.listBox.AddController(&motionCtrl.EventController) | |
| 800 | + | } | |
| 801 | + | ||
| 802 | + | func (o *Omnibox) handleListHoverSelection(y float64) { | |
| 803 | + | o.mu.RLock() | |
| 804 | + | realInput := o.realInput | |
| 805 | + | hasGhostText := o.ghostSuffix != "" | |
| 806 | + | hasNavigated := o.hasNavigated | |
| 807 | + | selectedIndex := o.selectedIndex | |
| 808 | + | o.mu.RUnlock() | |
| 809 | + | ||
| 810 | + | if !shouldPromoteHoverSelection(realInput, hasGhostText, hasNavigated) { | |
| 811 | + | return | |
| 812 | + | } | |
| 813 | + | ||
| 814 | + | row := o.listBox.GetRowAtY(int(y)) | |
| 815 | + | if row == nil { | |
| 816 | + | return | |
| 817 | + | } | |
| 818 | + | ||
| 819 | + | index := row.GetIndex() | |
| 820 | + | if index < 0 || index == selectedIndex { | |
| 821 | + | return | |
| 822 | + | } | |
| 823 | + | o.selectIndex(index) | |
| 824 | + | } | |
| 825 | + | ||
| 785 | 826 | func (o *Omnibox) assembleWidgets() { | |
| 786 | 827 | o.headerBox.Append(&o.historyBtn.Widget) | |
| 787 | 828 | o.headerBox.Append(&o.favoritesBtn.Widget) | |
| @@ -2087,7 +2128,6 @@ func (o *Omnibox) createRowWithFaviconURL( | |||
| 2087 | 2128 | return nil | |
| 2088 | 2129 | } | |
| 2089 | 2130 | row.AddCssClass("omnibox-row") | |
| 2090 | - | o.attachRowHoverSelection(row, index) | |
| 2091 | 2131 | ||
| 2092 | 2132 | const rowSpacing = 8 | |
| 2093 | 2133 | hbox := gtk.NewBox(gtk.OrientationHorizontalValue, rowSpacing) | |
| @@ -2119,29 +2159,6 @@ func (o *Omnibox) createRowWithFaviconURL( | |||
| 2119 | 2159 | return row | |
| 2120 | 2160 | } | |
| 2121 | 2161 | ||
| 2122 | - | func (o *Omnibox) attachRowHoverSelection(row *gtk.ListBoxRow, index int) { | |
| 2123 | - | motionCtrl := gtk.NewEventControllerMotion() | |
| 2124 | - | if motionCtrl == nil { | |
| 2125 | - | return | |
| 2126 | - | } | |
| 2127 | - | ||
| 2128 | - | enterCb := func(_ gtk.EventControllerMotion, _ float64, _ float64) { | |
| 2129 | - | o.mu.RLock() | |
| 2130 | - | realInput := o.realInput | |
| 2131 | - | hasGhostText := o.ghostSuffix != "" | |
| 2132 | - | hasNavigated := o.hasNavigated | |
| 2133 | - | o.mu.RUnlock() | |
| 2134 | - | ||
| 2135 | - | if !shouldPromoteHoverSelection(realInput, hasGhostText, hasNavigated) { | |
| 2136 | - | return | |
| 2137 | - | } | |
| 2138 | - | o.selectIndex(index) | |
| 2139 | - | } | |
| 2140 | - | o.retainedCallbacks = append(o.retainedCallbacks, enterCb) | |
| 2141 | - | motionCtrl.ConnectEnter(&enterCb) | |
| 2142 | - | row.AddController(&motionCtrl.EventController) | |
| 2143 | - | } | |
| 2144 | - | ||
| 2145 | 2162 | func shouldPromoteHoverSelection(realInput string, hasGhostText, hasNavigated bool) bool { | |
| 2146 | 2163 | return realInput == "" && !hasGhostText && !hasNavigated | |
| 2147 | 2164 | } | |
| @@ -779,9 +779,50 @@ func (o *Omnibox) initList() error { | |||||
| 779 | o.retainedCallbacks = append(o.retainedCallbacks, rowActivatedCb) | 779 | o.retainedCallbacks = append(o.retainedCallbacks, rowActivatedCb) | ||
| 780 | o.listBox.ConnectRowActivated(&rowActivatedCb) | 780 | o.listBox.ConnectRowActivated(&rowActivatedCb) | ||
| 781 | 781 | ||||
| 782 | + | o.setupListHoverSelection() | |||
| 783 | + | ||||
| 782 | return nil | 784 | return nil | ||
| 783 | } | 785 | } | ||
| 784 | 786 | ||||
| 787 | + | func (o *Omnibox) setupListHoverSelection() { | |||
| 788 | + | motionCtrl := gtk.NewEventControllerMotion() | |||
| 789 | + | if motionCtrl == nil { | |||
| 790 | + | logging.FromContext(o.ctx).Error().Msg("failed to create motion event controller") | |||
| 791 | + | return | |||
| 792 | + | } | |||
| 793 | + | ||||
| 794 | + | motionCb := func(_ gtk.EventControllerMotion, _ float64, y float64) { | |||
| 795 | + | o.handleListHoverSelection(y) | |||
| 796 | + | } | |||
| 797 | + | o.retainedCallbacks = append(o.retainedCallbacks, motionCb) | |||
| 798 | + | motionCtrl.ConnectMotion(&motionCb) | |||
| 799 | + | o.listBox.AddController(&motionCtrl.EventController) | |||
| 800 | + | } | |||
| 801 | + | ||||
| 802 | + | func (o *Omnibox) handleListHoverSelection(y float64) { | |||
| 803 | + | o.mu.RLock() | |||
| 804 | + | realInput := o.realInput | |||
| 805 | + | hasGhostText := o.ghostSuffix != "" | |||
| 806 | + | hasNavigated := o.hasNavigated | |||
| 807 | + | selectedIndex := o.selectedIndex | |||
| 808 | + | o.mu.RUnlock() | |||
| 809 | + | ||||
| 810 | + | if !shouldPromoteHoverSelection(realInput, hasGhostText, hasNavigated) { | |||
| 811 | + | return | |||
| 812 | + | } | |||
| 813 | + | ||||
| 814 | + | row := o.listBox.GetRowAtY(int(y)) | |||
| 815 | + | if row == nil { | |||
| 816 | + | return | |||
| 817 | + | } | |||
| 818 | + | ||||
| 819 | + | index := row.GetIndex() | |||
| 820 | + | if index < 0 || index == selectedIndex { | |||
| 821 | + | return | |||
| 822 | + | } | |||
| 823 | + | o.selectIndex(index) | |||
| 824 | + | } | |||
| 825 | + | ||||
| 785 | func (o *Omnibox) assembleWidgets() { | 826 | func (o *Omnibox) assembleWidgets() { | ||
| 786 | o.headerBox.Append(&o.historyBtn.Widget) | 827 | o.headerBox.Append(&o.historyBtn.Widget) | ||
| 787 | o.headerBox.Append(&o.favoritesBtn.Widget) | 828 | o.headerBox.Append(&o.favoritesBtn.Widget) | ||
| @@ -2087,7 +2128,6 @@ func (o *Omnibox) createRowWithFaviconURL( | |||||
| 2087 | return nil | 2128 | return nil | ||
| 2088 | } | 2129 | } | ||
| 2089 | row.AddCssClass("omnibox-row") | 2130 | row.AddCssClass("omnibox-row") | ||
| 2090 | - | o.attachRowHoverSelection(row, index) | |||
| 2091 | 2131 | ||||
| 2092 | const rowSpacing = 8 | 2132 | const rowSpacing = 8 | ||
| 2093 | hbox := gtk.NewBox(gtk.OrientationHorizontalValue, rowSpacing) | 2133 | hbox := gtk.NewBox(gtk.OrientationHorizontalValue, rowSpacing) | ||
| @@ -2119,29 +2159,6 @@ func (o *Omnibox) createRowWithFaviconURL( | |||||
| 2119 | return row | 2159 | return row | ||
| 2120 | } | 2160 | } | ||
| 2121 | 2161 | ||||
| 2122 | - | func (o *Omnibox) attachRowHoverSelection(row *gtk.ListBoxRow, index int) { | |||
| 2123 | - | motionCtrl := gtk.NewEventControllerMotion() | |||
| 2124 | - | if motionCtrl == nil { | |||
| 2125 | - | return | |||
| 2126 | - | } | |||
| 2127 | - | ||||
| 2128 | - | enterCb := func(_ gtk.EventControllerMotion, _ float64, _ float64) { | |||
| 2129 | - | o.mu.RLock() | |||
| 2130 | - | realInput := o.realInput | |||
| 2131 | - | hasGhostText := o.ghostSuffix != "" | |||
| 2132 | - | hasNavigated := o.hasNavigated | |||
| 2133 | - | o.mu.RUnlock() | |||
| 2134 | - | ||||
| 2135 | - | if !shouldPromoteHoverSelection(realInput, hasGhostText, hasNavigated) { | |||
| 2136 | - | return | |||
| 2137 | - | } | |||
| 2138 | - | o.selectIndex(index) | |||
| 2139 | - | } | |||
| 2140 | - | o.retainedCallbacks = append(o.retainedCallbacks, enterCb) | |||
| 2141 | - | motionCtrl.ConnectEnter(&enterCb) | |||
| 2142 | - | row.AddController(&motionCtrl.EventController) | |||
| 2143 | - | } | |||
| 2144 | - | ||||
| 2145 | func shouldPromoteHoverSelection(realInput string, hasGhostText, hasNavigated bool) bool { | 2162 | func shouldPromoteHoverSelection(realInput string, hasGhostText, hasNavigated bool) bool { | ||
| 2146 | return realInput == "" && !hasGhostText && !hasNavigated | 2163 | return realInput == "" && !hasGhostText && !hasNavigated | ||
| 2147 | } | 2164 | } | ||