jpayne@69: from tkinter import Toplevel, TclError jpayne@69: import sys jpayne@69: jpayne@69: jpayne@69: class WindowList: jpayne@69: jpayne@69: def __init__(self): jpayne@69: self.dict = {} jpayne@69: self.callbacks = [] jpayne@69: jpayne@69: def add(self, window): jpayne@69: window.after_idle(self.call_callbacks) jpayne@69: self.dict[str(window)] = window jpayne@69: jpayne@69: def delete(self, window): jpayne@69: try: jpayne@69: del self.dict[str(window)] jpayne@69: except KeyError: jpayne@69: # Sometimes, destroy() is called twice jpayne@69: pass jpayne@69: self.call_callbacks() jpayne@69: jpayne@69: def add_windows_to_menu(self, menu): jpayne@69: list = [] jpayne@69: for key in self.dict: jpayne@69: window = self.dict[key] jpayne@69: try: jpayne@69: title = window.get_title() jpayne@69: except TclError: jpayne@69: continue jpayne@69: list.append((title, key, window)) jpayne@69: list.sort() jpayne@69: for title, key, window in list: jpayne@69: menu.add_command(label=title, command=window.wakeup) jpayne@69: jpayne@69: def register_callback(self, callback): jpayne@69: self.callbacks.append(callback) jpayne@69: jpayne@69: def unregister_callback(self, callback): jpayne@69: try: jpayne@69: self.callbacks.remove(callback) jpayne@69: except ValueError: jpayne@69: pass jpayne@69: jpayne@69: def call_callbacks(self): jpayne@69: for callback in self.callbacks: jpayne@69: try: jpayne@69: callback() jpayne@69: except: jpayne@69: t, v, tb = sys.exc_info() jpayne@69: print("warning: callback failed in WindowList", t, ":", v) jpayne@69: jpayne@69: jpayne@69: registry = WindowList() jpayne@69: jpayne@69: add_windows_to_menu = registry.add_windows_to_menu jpayne@69: register_callback = registry.register_callback jpayne@69: unregister_callback = registry.unregister_callback jpayne@69: jpayne@69: jpayne@69: class ListedToplevel(Toplevel): jpayne@69: jpayne@69: def __init__(self, master, **kw): jpayne@69: Toplevel.__init__(self, master, kw) jpayne@69: registry.add(self) jpayne@69: self.focused_widget = self jpayne@69: jpayne@69: def destroy(self): jpayne@69: registry.delete(self) jpayne@69: Toplevel.destroy(self) jpayne@69: # If this is Idle's last window then quit the mainloop jpayne@69: # (Needed for clean exit on Windows 98) jpayne@69: if not registry.dict: jpayne@69: self.quit() jpayne@69: jpayne@69: def update_windowlist_registry(self, window): jpayne@69: registry.call_callbacks() jpayne@69: jpayne@69: def get_title(self): jpayne@69: # Subclass can override jpayne@69: return self.wm_title() jpayne@69: jpayne@69: def wakeup(self): jpayne@69: try: jpayne@69: if self.wm_state() == "iconic": jpayne@69: self.wm_withdraw() jpayne@69: self.wm_deiconify() jpayne@69: self.tkraise() jpayne@69: self.focused_widget.focus_set() jpayne@69: except TclError: jpayne@69: # This can happen when the Window menu was torn off. jpayne@69: # Simply ignore it. jpayne@69: pass jpayne@69: jpayne@69: jpayne@69: if __name__ == "__main__": jpayne@69: from unittest import main jpayne@69: main('idlelib.idle_test.test_window', verbosity=2)