Let a second copy yield to the instance already running

listen() was the whole of the single-instance check and it cannot be one:
a Windows named pipe takes a second server on the same name rather than
refusing it, and everywhere else removeServer() first takes the live socket
away from the instance holding it. Starting Dikte over a running Dikte then
left two whole copies up, two tray icons and all, and the newer one's
sweep() killed the whisper the older one was answering dictations with. On
a machine that sleeps instead of logging out, that is one Start Menu click
away, and it cost a real dictation before it was understood.

A QLockFile in the data directory closes the race on all three systems,
taken before the QApplication is even built, and behind it the probe is the
side-effect-free status verb: the Settings window opens as the sign of life
only when a bare second start deliberately asks for it, not as a byproduct
of a probe racing a forwarded toggle. The two Windows relaunch dances
collapse into one ipc.respawn.

The checkout installer and the packaged setup each kept an autostart the
other could not see, so a machine that tried both started two copies at
every sign-in: each autostart now removes the other's entry, the silent
every-start repair backs off from a Run value whose target still exists,
and each uninstaller deletes the shared dikte.cmd only when the shim
names its own install.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
huseyin-emre-tigci
2026-08-22 23:09:05 +03:00
co-authored by Claude Fable 5
parent 0a70484d84
commit 6f601ab969
7 changed files with 308 additions and 17 deletions
+9
View File
@@ -1122,6 +1122,15 @@ def _stay_out_of_the_dock():
def run_app(args):
command = args[0] if args else ""
# One Dikte per user, checked by asking rather than by listening: see
# ipc.already_serving. Before the QApplication, so a second copy costs a
# moment and not a second tray icon.
if ipc.already_serving():
print("dikte: already running; its Settings window has the attention")
if command:
ipc.send(command)
return 0
app = QApplication(sys.argv)
app.setApplicationName("Dikte")
app.setDesktopFileName("dikte")