app-single-instance
A lightweight, cross-platform single-instance library for Rust desktop applications.
When a second instance of your application is launched, this library sends a wake-up signal to the already-running instance and lets the second instance exit gracefully. The primary instance can then respond by restoring and focusing its window.
Platform Support
| Platform | Socket Type | Force Window to Front |
|---|---|---|
| Windows | Named pipe (namespaced) | ✅ Supported via egui viewport commands |
| macOS | Unix domain socket (/tmp/) |
✅ Supported via NSApplication |
| Linux (X11) | Unix domain socket (/tmp/) |
✅ Supported via wmctrl |
| Linux (Wayland) | Unix domain socket (/tmp/) |
⚠️ Not supported (see Wayland Limitation) |
Installation
Add the following to your Cargo.toml:
[]
= "0.1"
Usage
The typical usage pattern involves two steps:
- Before launching your app, call [
notify_if_running] to check whether another instance is already running. If it is, the signal is sent and you should exit immediately. - After launching your app, call [
start_primary] to register the current process as the primary instance and begin listening for signals.
use ;
const APP_ID: &str = env!;
Important:
notify_if_runningmust always be called beforestart_primary. Thehandlereturned bystart_primarymust be kept alive for the duration of your application — dropping it will stop the listener.
API
notify_if_running(app_id: &str) -> bool
Checks whether a primary instance is already running.
- Returns
trueif a running instance was found and the wake-up signal was sent. The caller should exit immediately. - Returns
falseif no existing instance was detected. The caller may proceed to start normally.
start_primary(app_id: &str, on_show: impl Fn() + Send + 'static) -> PrimaryHandle
Registers the current process as the primary instance and spawns a background listener thread.
app_id: A string that uniquely identifies your application. It is used to name the IPC socket, so it must be consistent across all calls and unique enough to avoid conflicts with other applications. Usingenv!("CARGO_PKG_NAME")is a safe default.on_show: A callback invoked on the listener thread each time a wake-up signal is received. Use this to trigger a window restore, repaint request, or similar action.
PrimaryHandle
The handle returned by start_primary. It serves two purposes:
- Keeps the listener alive: the background thread runs as long as the handle is not dropped.
- Poll-based detection: call
handle.check_show()from your main loop as an alternative to the callback.
PrimaryHandle::check_show() -> bool
Returns true if a wake-up signal has been received since the last call. This is non-blocking and suitable for polling inside a UI update loop.
Example: egui / eframe
A complete example using eframe is provided in examples/egui.rs.
use egui;
use ;
const APP_ID: &str = env!;
Run the example with:
Launch a second terminal and run the same command again to see the single-instance behavior in action.
Wayland Limitation
On Linux under a Wayland compositor, it is not possible for an application to force itself to the foreground. This is a deliberate design decision of the Wayland protocol: compositors control window stacking and focus, and applications are not permitted to request it unconditionally.
As a result, when a wake-up signal is received on Wayland:
on_showis still called andcheck_show()still returnstrue— your application logic runs normally.- Viewport commands such as
ViewportCommand::Focusare sent but may have no visible effect depending on the compositor. - The window cannot be reliably un-minimized or raised to the front programmatically.
The recommended approach on Wayland is to use taskbar attention requests to notify the user that the application wants focus, and let the user act on it:
ctx.send_viewport_cmd;
This will typically cause the application's taskbar icon to flash or highlight, which is the standard Wayland-compliant way to signal the user.
On X11 (still common on Ubuntu with the classic session), wmctrl can be used as a workaround:
wmctrlmust be installed on the user's system (sudo apt install wmctrl). The-aargument must match the window title exactly.
Unclean Shutdown and Stale Sockets
On Unix platforms, local sockets are backed by files under /tmp/. If the primary instance exits uncleanly (e.g. via SIGKILL or a crash), the socket file may be left behind. On the next launch, this would normally cause an AddrInUse error.
This library handles this automatically: if binding fails with AddrInUse, the stale socket file is removed and the bind is retried. No user intervention is required.
License
MIT