Skip to content

Commit

Permalink
protect direct accesses to l.selected with propertyLock
Browse files Browse the repository at this point in the history
  • Loading branch information
dweymouth committed Dec 22, 2023
1 parent 261fdbd commit e019568
Showing 1 changed file with 41 additions and 14 deletions.
55 changes: 41 additions & 14 deletions widget/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ func (l *List) Select(id ListItemID) {

// select; return true if selected + refreshed
func (l *List) _select(id ListItemID) bool {
l.propertyLock.RLock()
sel := l.selected
l.propertyLock.RUnlock()
for _, selId := range sel {
if id == selId {
return false
Expand All @@ -213,7 +215,9 @@ func (l *List) _select(id ListItemID) bool {
if id < 0 || id >= length {
return false
}
l.propertyLock.Lock()
l.selected = append(sel, id)
l.propertyLock.Unlock()
defer func() {
if f := l.OnSelected; f != nil {
f(id)
Expand All @@ -229,19 +233,22 @@ func (l *List) _select(id ListItemID) bool {
//
// Since: 2.5
func (l *List) SelectOnly(id ListItemID) {
if len(l.selected) == 1 && id == l.selected[0] {
l.propertyLock.RLock()
sel := l.selected
l.propertyLock.RUnlock()

if len(sel) == 1 && id == sel[0] {
return
}
length := l.length()
if id < 0 || id >= length {
return
}
old := l.selected
l.selected = []ListItemID{id}
wasPrevSelected := false
defer func() {
if f := l.OnUnselected; f != nil {
for _, oldSelId := range old {
for _, oldSelId := range sel {
if oldSelId != id {
f(id)
} else {
Expand All @@ -263,15 +270,20 @@ func (l *List) SelectOnly(id ListItemID) {
// Since: 2.5
func (l *List) SelectAll(id ListItemID) {
length := l.length()
if length == 0 || len(l.selected) == length {
l.propertyLock.RLock()
prev := l.selected
l.propertyLock.RUnlock()
if length == 0 || len(prev) == length {
return
}

prev := l.selected
l.selected = make([]int, length)
for i := range l.selected {
l.selected[i] = i
selected := make([]int, length)
for i := range selected {
selected[i] = i
}
l.propertyLock.Lock()
l.selected = selected
l.propertyLock.Unlock()
l.Refresh()

// Call OnSelected callback for each newly selected item
Expand Down Expand Up @@ -305,14 +317,18 @@ func (l *List) SetSelection(selected []ListItemID) {
return
}

l.propertyLock.RLock()
oldSel := l.selected
l.propertyLock.RUnlock()
newSel := make([]ListItemID, 0, len(selected))
for _, id := range selected {
if id >= 0 && id < length {
newSel = append(newSel, id)
}
}
l.propertyLock.Lock()
l.selected = newSel
l.propertyLock.Unlock()
l.Refresh()

// Call OnSelected, OnUnselected callbacks for each newly (un)selected item
Expand Down Expand Up @@ -426,7 +442,9 @@ func (l *List) TypedRune(_ rune) {
// Unselect removes the item identified by the given ID from the selection.
func (l *List) Unselect(id ListItemID) {
// check if already not selected
l.propertyLock.RLock()
sel := l.selected
l.propertyLock.RUnlock()
selected := false
for _, selID := range sel {
if selID == id {
Expand All @@ -445,7 +463,9 @@ func (l *List) Unselect(id ListItemID) {
}
}

l.propertyLock.Lock()
l.selected = newSel
l.propertyLock.Unlock()
l.Refresh()
if f := l.OnUnselected; f != nil {
f(id)
Expand All @@ -456,12 +476,16 @@ func (l *List) Unselect(id ListItemID) {
//
// Since: 2.1
func (l *List) UnselectAll() {
l.propertyLock.RLock()
sel := l.selected
l.propertyLock.RUnlock()
if len(sel) == 0 {
return
}

l.propertyLock.Lock()
l.selected = nil
l.propertyLock.Unlock()
l.Refresh()
if f := l.OnUnselected; f != nil {
for _, id := range sel {
Expand All @@ -472,7 +496,9 @@ func (l *List) UnselectAll() {

// invariant: all of ids are valid and none are already selected
func (l *List) addToSelection(ids []int) {
l.propertyLock.Lock()
l.selected = append(l.selected, ids...)
l.propertyLock.Unlock()
l.Refresh()
if f := l.OnSelected; f != nil {
for _, id := range ids {
Expand All @@ -482,7 +508,9 @@ func (l *List) addToSelection(ids []int) {
}

func (l *List) handleMultiSelectAction(id ListItemID) {
l.propertyLock.RLock()
sel := l.selected
l.propertyLock.RUnlock()
isSelected := false
for _, selID := range sel {
if selID == id {
Expand Down Expand Up @@ -515,7 +543,7 @@ func (l *List) handleMultiSelectAction(id ListItemID) {
toggleSelect()
} else if mods&fyne.KeyModifierShift > 0 {
if !isSelected {
l.selectRange(id)
l.selectRange(id, sel)
}
} else {
if !isSelected {
Expand All @@ -525,8 +553,8 @@ func (l *List) handleMultiSelectAction(id ListItemID) {
}

// select range between id and nearest existing selected item
func (l *List) selectRange(id ListItemID) {
nearest, dist := l.findNearestSelectedItem(id)
func (l *List) selectRange(id ListItemID, curSelection []int) {
nearest, dist := l.findNearestSelectedItem(id, curSelection)
above := nearest < id
if nearest == -1 || dist <= 1 {
// either nothing selected, or something selected right next to id
Expand All @@ -547,12 +575,11 @@ func (l *List) selectRange(id ListItemID) {
l.addToSelection(selAdd)
}

func (l *List) findNearestSelectedItem(id ListItemID) (nearest ListItemID, dist int) {
func (l *List) findNearestSelectedItem(id ListItemID, curSelection []int) (nearest ListItemID, dist int) {
above, below := -1, math.MaxInt
sel := l.selected
length := l.length()

for _, selId := range sel {
for _, selId := range curSelection {
if selId >= 0 && selId < id && selId > above {
above = selId
} else if selId < length && selId > id && selId < below {
Expand Down

0 comments on commit e019568

Please sign in to comment.