From e48c2f6f96b974e2388783c98c0fa840609a66f6 Mon Sep 17 00:00:00 2001 From: Jacob Date: Sat, 6 Jan 2024 10:42:37 +0100 Subject: [PATCH 1/3] Don't fire callback inside locks, fixes #4516 Fixes #4516 --- widget/entry.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/widget/entry.go b/widget/entry.go index 1cbb707fcf..b68060a5cb 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -846,11 +846,12 @@ func (e *Entry) cutToClipboard(clipboard fyne.Clipboard) { e.copyToClipboard(clipboard) e.setFieldsAndRefresh(e.eraseSelection) - e.propertyLock.Lock() + e.propertyLock.RLock() + content := e.Text + e.propertyLock.RUnlock() if e.OnChanged != nil { - e.OnChanged(e.Text) + e.OnChanged(content) } - e.propertyLock.Unlock() e.Validate() } @@ -1092,11 +1093,13 @@ func (e *Entry) selectingKeyHandler(key *fyne.KeyEvent) bool { case fyne.KeyBackspace, fyne.KeyDelete: // clears the selection -- return handled e.setFieldsAndRefresh(e.eraseSelection) - e.propertyLock.Lock() + + e.propertyLock.RLock() + content := e.Text + e.propertyLock.RUnlock() if e.OnChanged != nil { - e.OnChanged(e.Text) + e.OnChanged(content) } - e.propertyLock.Unlock() e.Validate() return true case fyne.KeyReturn, fyne.KeyEnter: From f395807a654a5c661fad427a5a5722a520ccb249 Mon Sep 17 00:00:00 2001 From: Jacob Date: Sat, 6 Jan 2024 10:51:18 +0100 Subject: [PATCH 2/3] Add a simple test to verify that we don't deadlock --- widget/entry_internal_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/widget/entry_internal_test.go b/widget/entry_internal_test.go index db56c05fc4..c45341799e 100644 --- a/widget/entry_internal_test.go +++ b/widget/entry_internal_test.go @@ -283,6 +283,21 @@ func TestEntry_EraseSelection(t *testing.T) { assert.Equal(t, -1, b) } +func TestEntry_CallbackLocking(t *testing.T) { + e := &Entry{} + called := 0 + e.OnChanged = func(_ string) { + e.propertyLock.Lock() + called++ // Just to not have an empty critical section. + e.propertyLock.Unlock() + } + + test.Type(e, "abc123") + e.selectAll() + e.TypedKey(&fyne.KeyEvent{Name: fyne.KeyBackspace}) + assert.Equal(t, 7, called) +} + func TestEntry_MouseClickAndDragOutsideText(t *testing.T) { entry := NewEntry() entry.SetText("A\nB\n") From 614949f63406eea62506f8e867a9294e5e7ad574 Mon Sep 17 00:00:00 2001 From: Jacob Date: Sat, 6 Jan 2024 10:53:50 +0100 Subject: [PATCH 3/3] Remove a newline that shouldn't be there --- widget/entry.go | 1 - 1 file changed, 1 deletion(-) diff --git a/widget/entry.go b/widget/entry.go index b68060a5cb..56851650ab 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -1093,7 +1093,6 @@ func (e *Entry) selectingKeyHandler(key *fyne.KeyEvent) bool { case fyne.KeyBackspace, fyne.KeyDelete: // clears the selection -- return handled e.setFieldsAndRefresh(e.eraseSelection) - e.propertyLock.RLock() content := e.Text e.propertyLock.RUnlock()