1from tkinter import *
2
3
4class WindowList:
5
6    def __init__(self):
7        self.dict = {}
8        self.callbacks = []
9
10    def add(self, window):
11        window.after_idle(self.call_callbacks)
12        self.dict[str(window)] = window
13
14    def delete(self, window):
15        try:
16            del self.dict[str(window)]
17        except KeyError:
18            # Sometimes, destroy() is called twice
19            pass
20        self.call_callbacks()
21
22    def add_windows_to_menu(self,  menu):
23        list = []
24        for key in self.dict:
25            window = self.dict[key]
26            try:
27                title = window.get_title()
28            except TclError:
29                continue
30            list.append((title, key, window))
31        list.sort()
32        for title, key, window in list:
33            menu.add_command(label=title, command=window.wakeup)
34
35    def register_callback(self, callback):
36        self.callbacks.append(callback)
37
38    def unregister_callback(self, callback):
39        try:
40            self.callbacks.remove(callback)
41        except ValueError:
42            pass
43
44    def call_callbacks(self):
45        for callback in self.callbacks:
46            try:
47                callback()
48            except:
49                t, v, tb = sys.exc_info()
50                print("warning: callback failed in WindowList", t, ":", v)
51
52
53registry = WindowList()
54
55add_windows_to_menu = registry.add_windows_to_menu
56register_callback = registry.register_callback
57unregister_callback = registry.unregister_callback
58
59
60class ListedToplevel(Toplevel):
61
62    def __init__(self, master, **kw):
63        Toplevel.__init__(self, master, kw)
64        registry.add(self)
65        self.focused_widget = self
66
67    def destroy(self):
68        registry.delete(self)
69        Toplevel.destroy(self)
70        # If this is Idle's last window then quit the mainloop
71        # (Needed for clean exit on Windows 98)
72        if not registry.dict:
73            self.quit()
74
75    def update_windowlist_registry(self, window):
76        registry.call_callbacks()
77
78    def get_title(self):
79        # Subclass can override
80        return self.wm_title()
81
82    def wakeup(self):
83        try:
84            if self.wm_state() == "iconic":
85                self.wm_withdraw()
86                self.wm_deiconify()
87            self.tkraise()
88            self.focused_widget.focus_set()
89        except TclError:
90            # This can happen when the window menu was torn off.
91            # Simply ignore it.
92            pass
93