| """Interface to the system tray icon and desktop notifications. | |
| The SysTrayIcon class gives access to the "tk systray" command and | |
| the notify() function gives access to the "tk sysnotify" command. | |
| They require Tk 8.7/9.0 or newer. | |
| Only one system tray icon is supported per Tcl interpreter. | |
| On Windows, sending a notification requires that the system tray icon | |
| has been created first; the icon is also displayed in the | |
| notification. | |
| """ | |
| import tkinter | |
| __all__ = ["SysTrayIcon", "notify"] | |
| class SysTrayIcon: | |
| """The system tray icon. | |
| Only one system tray icon is supported per Tcl interpreter. | |
| With exists false (the default) a new icon is created, and creating | |
| a second one raises TclError. With exists true this refers to the | |
| already-existing icon instead of creating one. | |
| Supported configuration options are: | |
| image: the image displayed in the system tray (required when | |
| creating an icon; it must be a photo image on Windows) | |
| text: the text displayed in the tooltip of the icon | |
| button1: a callback that is called when the icon is clicked | |
| with the left mouse button | |
| button3: a callback that is called when the icon is clicked | |
| with the right mouse button | |
| """ | |
| def __init__(self, master=None, *, exists=False, **options): | |
| if master is None: | |
| master = tkinter._get_default_root('use the system tray icon') | |
| self.master = master | |
| self._command_names = {} | |
| if exists: | |
| # Refer to the already-existing icon, reconfiguring it if | |
| # any options are given. | |
| if options: | |
| self._call('configure', options) | |
| else: | |
| if options.get('image') is None: | |
| raise TypeError( | |
| "the 'image' argument is required to create an icon") | |
| self._call('create', options) | |
| def _call(self, subcommand, cnf): | |
| # Call "tk systray" with the given options, registering and | |
| # unregistering the callback commands as needed. | |
| master = self.master | |
| cnf = dict(cnf) | |
| new_names = {} | |
| for key in ('button1', 'button3'): | |
| if key in cnf: | |
| command = cnf[key] | |
| if command is None: | |
| cnf[key] = '' | |
| elif callable(command): | |
| new_names[key] = cnf[key] = master._register(command) | |
| try: | |
| master.tk.call('tk', 'systray', subcommand, | |
| *master._options(cnf)) | |
| except tkinter.TclError: | |
| for name in new_names.values(): | |
| master.deletecommand(name) | |
| raise | |
| for key in ('button1', 'button3'): | |
| if key in cnf: | |
| old_name = self._command_names.pop(key, None) | |
| if old_name is not None: | |
| master.deletecommand(old_name) | |
| if key in new_names: | |
| self._command_names[key] = new_names[key] | |
| def configure(self, cnf=None, **kw): | |
| """Query or modify the options of the system tray icon. | |
| With no arguments, return a dict of all option values. With a | |
| string argument, return the value of that option. Otherwise, | |
| set the given options. | |
| """ | |
| if kw: | |
| cnf = tkinter._cnfmerge((cnf, kw)) | |
| elif cnf: | |
| cnf = tkinter._cnfmerge(cnf) | |
| tk = self.master.tk | |
| if cnf is None: | |
| items = tk.splitlist(tk.call('tk', 'systray', 'configure')) | |
| return {items[i][1:]: items[i+1] for i in range(0, len(items), 2)} | |
| if isinstance(cnf, str): | |
| return tk.call('tk', 'systray', 'configure', '-' + cnf) | |
| self._call('configure', cnf) | |
| config = configure | |
| def cget(self, option): | |
| """Return the value of the given option of the system tray icon.""" | |
| return self.master.tk.call('tk', 'systray', 'configure', '-' + option) | |
| def exists(self): | |
| """Return whether the system tray icon exists.""" | |
| tk = self.master.tk | |
| return tk.getboolean(tk.call('tk', 'systray', 'exists')) | |
| def destroy(self): | |
| """Destroy the system tray icon.""" | |
| self.master.tk.call('tk', 'systray', 'destroy') | |
| for name in self._command_names.values(): | |
| self.master.deletecommand(name) | |
| self._command_names.clear() | |
| def notify(self, title, message): | |
| """Send a desktop notification with the given title and message.""" | |
| self.master.tk.call('tk', 'sysnotify', title, message) | |
| def notify(title, message, *, master=None): | |
| """Send a desktop notification with the given title and message. | |
| On Windows, the system tray icon must have been created first. | |
| """ | |
| if master is None: | |
| master = tkinter._get_default_root('send a notification') | |
| master.tk.call('tk', 'sysnotify', title, message) |