| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4a5a7b9 commit 3736342
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,3 +1,4 @@ | |||
| 1 | + import sys | ||
| 1 | 2 | import unittest | |
| 2 | 3 | import tkinter | |
| 3 | 4 | from tkinter import messagebox, ttk | |
@@ -245,6 +246,26 @@ def test_go(self): | |||
| 245 | 246 | d.root.after(1, lambda: d._buttons[0].invoke()) | |
| 246 | 247 | self.assertEqual(d.go(), 0) | |
| 247 | 248 | ||
| 249 | + def test_go_foreign_grab(self): | ||
| 250 | + # gh-157676: the grab and the focus can be in a window which was not | ||
| 251 | + # created by tkinter, such as a native message box; they must be | ||
| 252 | + # restored after the dialog. | ||
| 253 | + tk = self.root.tk | ||
| 254 | + tk.call('toplevel', '.foreign') | ||
| 255 | + self.addCleanup(tk.call, 'destroy', '.foreign') | ||
| 256 | + tk.call('wm', 'deiconify', '.foreign') | ||
| 257 | + tk.call('update') | ||
| 258 | + tk.call('grab', 'set', '.foreign') | ||
| 259 | + tk.call('focus', '-force', '.foreign') | ||
| 260 | + d = self.create() | ||
| 261 | + d.root.after(1, lambda: d._buttons[0].invoke()) | ||
| 262 | + self.assertEqual(d.go(), 0) | ||
| 263 | + self.assertEqual(tk.call('grab', 'current', self.root._w), '.foreign') | ||
| 264 | + # On Windows the application can lose the focus when the dialog is | ||
| 265 | + # destroyed, and then "focus" returns an empty string. | ||
| 266 | + if sys.platform != 'win32': | ||
| 267 | + self.assertEqual(tk.call('focus'), '.foreign') | ||
| 268 | + | ||
| 248 | 269 | ||
| 249 | 270 | class DialogTest(AbstractDialogTest, unittest.TestCase): | |
| 250 | 271 | # Dialog's button box is modelled on tk::MessageBox. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -722,12 +722,13 @@ def askstring(title, prompt, **kw): | |||
| 722 | 722 | ||
| 723 | 723 | @contextlib.contextmanager | |
| 724 | 724 | def _temp_grab_focus(grab, focus=None, destroy=True): | |
| 725 | - old_focus = grab.focus_get() | ||
| 726 | - old_grab = grab.grab_current() | ||
| 727 | - if old_grab is not None and old_grab.winfo_exists(): | ||
| 728 | - old_status = old_grab.grab_status() | ||
| 729 | - else: | ||
| 730 | - old_status = None | ||
| 725 | + # Use Tcl window names rather than widgets, because the focus and the | ||
| 726 | + # grab can be in a window which was not created by tkinter, such as | ||
| 727 | + # a native message box. | ||
| 728 | + tk = grab.tk | ||
| 729 | + old_focus = tk.call('focus') | ||
| 730 | + old_grab = tk.call('grab', 'current', grab._w) | ||
| 731 | + old_status = tk.call('grab', 'status', old_grab) if old_grab else None | ||
| 731 | 732 | # The "grab" command will fail if another application | |
| 732 | 733 | # already holds the grab. So catch it. | |
| 733 | 734 | try: | |
@@ -741,9 +742,11 @@ def _temp_grab_focus(grab, focus=None, destroy=True): | |||
| 741 | 742 | yield | |
| 742 | 743 | ||
| 743 | 744 | finally: | |
| 744 | - if old_focus is not None: | ||
| 745 | + # The old windows and even the whole application can be destroyed | ||
| 746 | + # by now, so catch errors. | ||
| 747 | + if old_focus: | ||
| 745 | 748 | try: | |
| 746 | - old_focus.focus_set() | ||
| 749 | + tk.call('focus', old_focus) | ||
| 747 | 750 | except TclError: | |
| 748 | 751 | pass | |
| 749 | 752 | try: | |
@@ -755,15 +758,17 @@ def _temp_grab_focus(grab, focus=None, destroy=True): | |||
| 755 | 758 | grab.destroy() | |
| 756 | 759 | except TclError: | |
| 757 | 760 | pass | |
| 758 | - if (old_grab is not None and old_grab.winfo_exists() | ||
| 759 | - and old_grab.winfo_ismapped()): | ||
| 760 | - # The "grab" command will fail if another application | ||
| 761 | - # already holds the grab. So catch it. | ||
| 761 | + if old_grab: | ||
| 762 | + # Do not restore the grab if the window is no longer mapped: | ||
| 763 | + # a local grab on an unmapped window would block the application. | ||
| 764 | + # The "grab" command will fail if another application already | ||
| 765 | + # holds the grab on a window with the same name. So catch it. | ||
| 762 | 766 | try: | |
| 763 | - if old_status == 'global': | ||
| 764 | - old_grab.grab_set_global() | ||
| 765 | - else: | ||
| 766 | - old_grab.grab_set() | ||
| 767 | + if grab.getboolean(tk.call('winfo', 'ismapped', old_grab)): | ||
| 768 | + if old_status == 'global': | ||
| 769 | + tk.call('grab', 'set', '-global', old_grab) | ||
| 770 | + else: | ||
| 771 | + tk.call('grab', 'set', old_grab) | ||
| 767 | 772 | except TclError: | |
| 768 | 773 | pass | |
| 769 | 774 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments