From 68f901065b31f3ae62faece40b57132f9efc9efe Mon Sep 17 00:00:00 2001 From: Tal Einat <532281+taleinat@users.noreply.github.com> Date: Tue, 14 Sep 2021 18:21:17 +0300 Subject: [PATCH] IDLE: make the auto-complete window's winnconfig handler only trigger once Before, this was only enforced on the Windows platform, where multiple calls would result in errors. But logically it is the correct behavior, and it allows simplifying the code as well. Signed-off-by: Tal Einat <532281+taleinat@users.noreply.github.com> --- Lib/idlelib/autocomplete_w.py | 42 ++++++++++++++--------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/Lib/idlelib/autocomplete_w.py b/Lib/idlelib/autocomplete_w.py index 13ff60ae4493e6..0e0bda57ce327e 100644 --- a/Lib/idlelib/autocomplete_w.py +++ b/Lib/idlelib/autocomplete_w.py @@ -58,8 +58,6 @@ def __init__(self, widget, tags): self.winconfigid = self.keyreleaseid = self.doubleclickid = None # Flag set if last keypress was a tab self.lastkey_was_tab = False - # Flag set to avoid recursive callback invocations. - self.is_configuring = False def _change_start(self, newstart): min_len = min(len(self.start), len(newstart)) @@ -229,30 +227,36 @@ def show_window(self, comp_lists, index, complete, mode, userWantsWin): self.widget.event_add(KEYRELEASE_VIRTUAL_EVENT_NAME,KEYRELEASE_SEQUENCE) self.listupdateid = listbox.bind(LISTUPDATE_SEQUENCE, self.listselect_event) - self.is_configuring = False - self.winconfigid = acw.bind(WINCONFIG_SEQUENCE, self.winconfig_event) self.doubleclickid = listbox.bind(DOUBLECLICK_SEQUENCE, self.doubleclick_event) + + # Schedule self.winconfig_event to be called once the completion + # window is rendered, since we need its size to correctly position it. + self.winconfigid = acw.bind(WINCONFIG_SEQUENCE, self.winconfig_event) return None def winconfig_event(self, event): - if self.is_configuring: - # Avoid running on recursive callback invocations. - return - - self.is_configuring = True if not self.is_active(): return - # Since the event may occur after the completion window is gone, - # catch potential TclError exceptions when accessing acw. See: bpo-41611. + acw = self.autocompletewindow + + # Unbind this event handler, since it should only run once. + try: + acw.unbind(WINCONFIG_SEQUENCE, self.winconfigid) + except TclError: + pass + self.winconfigid = None + + # Since the event may occur after the completion window is + # gone, catch potential TclError exceptions when accessing acw. + # See: bpo-41611. try: # Position the completion list window text = self.widget text.see(self.startindex) x, y, cx, cy = text.bbox(self.startindex) - acw = self.autocompletewindow - if platform.system().startswith('Windows'): + if platform.system() == 'Windows': # On Windows an update() call is needed for the completion # list window to be created, so that we can fetch its width # and height. However, this is not needed on other platforms @@ -275,18 +279,6 @@ def winconfig_event(self, event): except TclError: pass - if platform.system().startswith('Windows'): - # See issue 15786. When on Windows platform, Tk will misbehave - # to call winconfig_event multiple times, we need to prevent this, - # otherwise mouse button double click will not be able to used. - try: - acw.unbind(WINCONFIG_SEQUENCE, self.winconfigid) - except TclError: - pass - self.winconfigid = None - - self.is_configuring = False - def _hide_event_check(self): if not self.autocompletewindow: return