util.singleInstance module

One copy of a program at a time (per user): a second copy, started to open some files (eg: a document double-clicked in Explorer or the file manager), hands them to the copy that’s running and quits. On the Mac this isn’t needed – the Finder sends a running app the documents to open itself (Tk’s ::tk::mac::OpenDocument) – but on Windows and Linux each double-click starts a new copy.

The running copy listens on a socket on this computer only (127.0.0.1), whose port, and a secret the other copies must send with their files, are in a file in a folder of the user’s own (eg: ~/.sn). Use:

instance = SingleInstance("sn", folder)
if instance.handOff(sys.argv[1:]):
  sys.exit(0)             # the running copy has them
root = tk.Tk()
instance.listen(root, openFiles) # openFiles(paths) is called in Tk's thread

Code author: Rob Kremer <robkremer@me.com>

class util.singleInstance.SingleInstance(name: str, folder: str)

Bases: object

Hands a second copy’s files to the running copy (see the module doc).

TIMEOUT = 2.0

How long (seconds) a second copy waits for the running one to answer.

POLL_MS = 200

How often (milliseconds) the running copy looks for files handed to it.

__init__(name: str, folder: str)
Parameters:
  • name – The program’s (short) name: the port file is folder/<name>.port.

  • folder – A folder of the user’s own, for the port file (made if it isn’t there).

handOff(args: list[str]) → bool

If a copy of the program is running, give it args (the files to open: made absolute, as this copy’s current folder may not be its).

Returns:

Whether a running copy took them: if so, this one should quit.

listen(root: Any, onArgs: Callable[[list[str]], None]) → None

Be the running copy: take the files later copies hand over, and call onArgs with them – in Tk’s thread, from root’s event loop.

Parameters:
  • root – The Tk root (or any widget that lasts as long as the program).

  • onArgs – Called with each later copy’s files (perhaps none: then it was just started again – eg, show a window).

_serve(server: socket, secret: str) → None
close() → None

Stop listening (eg: when the program quits), and remove the port file if it’s this copy’s.