Skip Menu |

This queue is for tickets about the Tickit-Widgets CPAN distribution.

Report information
The Basics
Id: 133026
Status: new
Priority: 0/
Queue: Tickit-Widgets

People
Owner: Nobody in particular
Requestors: jhealy [...] logn.net
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Infinite loop in focus_next (patch provided)
Date: Sun, 19 Jul 2020 23:42:07 -0400
To: bug-Tickit-Widgets [...] rt.cpan.org
From: Jason Healy <jhealy [...] logn.net>
Hello, In a test application I encountered a bug where hitting Tab on the last entry in a VBox (or S-Tab in the first entry) caused the program to lock up in an infinite loop. After some analysis, I think I've located the bug and have included a patch below. Specifics: my app had a root-level VBox with 3 nested VBoxes inside it (call them A, B, C). The first and last (A and C) only contained Static (no focusable elements); only the middle one (B) contained focusable Entries. When the last Entry in B had the focus and Tab was pressed, the bug would happen. It would also happen if the first Entry in B had S-Tab pressed. Using the "last Entry in B" example, pressing Tab causes find_next to be invoked on the Entry's parent (B). B had no other focusable children, so find_next moved up to the parent (root VBox). The root VBox would not find any focusable items in its next child (C), nor does it have a parent, so it would reset to "first" and cycle the tree again. It tries A as its next element, but in this case, A has no focusable items, so the search must continue. However, because the A was the "first" search, it simply searches "first" again in an infinite loop. The code assumes that you will find a focusable element in the first child of a parent, but that is not necessarily the case. I think this only occurs when there is a nested structure and the "first" or "last" item contains no focusable items. I added a quick check to turn "first" and "last" back into "before" and "after" if a child search fails. That resolved the issue in my test setup, but I have not tested it against any more complex widget trees. Patched code is only 2 lines; please review and let me know if you have questions. Thanks, Jason --- /opt/local/lib/perl5/site_perl/5.30/Tickit/ContainerWidget.pm-orig 2020-07-15 22:19:19.000000000 -0400 +++ /opt/local/lib/perl5/site_perl/5.30/Tickit/ContainerWidget.pm 2020-07-19 23:32:59.000000000 -0400 @@ -377,6 +377,11 @@ # See if child has it return 1 if $next->focus_next( $childhow => undef ); + # If this was our first/last (meaning we wrapped), convert to + # a standard before/after + if( $how eq "first" ) { $how = "after" } + elsif ( $how eq "last" ) { $how = "before" } + $other = $next; redo; }