diff --git a/Cargo.lock b/Cargo.lock index f2e3d128f2..e7b6bff119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14212,6 +14212,7 @@ dependencies = [ "uuid", "vim", "welcome", + "windows 0.58.0", "winresource", "workspace", "zed_actions", diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index c4647593e9..0fbdbe1ca7 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -67,7 +67,7 @@ log.workspace = true markdown_preview.workspace = true menu.workspace = true mimalloc = { version = "0.1", optional = true } -nix = {workspace = true, features = ["pthread", "signal"] } +nix = { workspace = true, features = ["pthread", "signal"] } node_runtime.workspace = true notifications.workspace = true outline.workspace = true @@ -99,7 +99,7 @@ tab_switcher.workspace = true supermaven.workspace = true task.workspace = true tasks_ui.workspace = true -time.workspace = true +time.workspace = true telemetry_events.workspace = true terminal_view.workspace = true theme.workspace = true @@ -114,6 +114,9 @@ welcome.workspace = true workspace.workspace = true zed_actions.workspace = true +[target.'cfg(target_os = "windows")'.dependencies] +windows.workspace = true + [target.'cfg(target_os = "windows")'.build-dependencies] winresource = "0.1" diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index e23ed69584..d9ffb29c39 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -318,6 +318,15 @@ fn init_ui( } fn main() { + #[cfg(target_os = "windows")] + { + use zed::single_instance::*; + if !check_single_instance() { + println!("zed is already running"); + return; + } + } + let start_time = std::time::Instant::now(); menu::init(); zed_actions::init(); @@ -360,7 +369,7 @@ fn main() { } } } - #[cfg(not(target_os = "linux"))] + #[cfg(not(any(target_os = "linux", target_os = "windows")))] { use zed::only_instance::*; if ensure_only_instance() != IsOnlyInstance::Yes { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 1b9b8ee042..9e0d061884 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -2,9 +2,11 @@ mod app_menus; pub mod inline_completion_registry; #[cfg(target_os = "linux")] pub(crate) mod linux_prompts; -#[cfg(not(target_os = "linux"))] +#[cfg(not(any(target_os = "linux", target_os = "windows")))] pub(crate) mod only_instance; mod open_listener; +#[cfg(target_os = "windows")] +pub(crate) mod single_instance; pub use app_menus::*; use assistant::PromptBuilder; diff --git a/crates/zed/src/zed/single_instance.rs b/crates/zed/src/zed/single_instance.rs new file mode 100644 index 0000000000..e8d32e7ed0 --- /dev/null +++ b/crates/zed/src/zed/single_instance.rs @@ -0,0 +1,39 @@ +use release_channel::ReleaseChannel; +use windows::{ + core::HSTRING, + Win32::{ + Foundation::{GetLastError, ERROR_ALREADY_EXISTS}, + System::Threading::CreateEventW, + }, +}; + +fn retrieve_app_instance_event_identifier() -> &'static str { + match *release_channel::RELEASE_CHANNEL { + ReleaseChannel::Dev => "Local\\Zed-Editor-Dev-Instance-Event", + ReleaseChannel::Nightly => "Local\\Zed-Editor-Nightly-Instance-Event", + ReleaseChannel::Preview => "Local\\Zed-Editor-Preview-Instance-Event", + ReleaseChannel::Stable => "Local\\Zed-Editor-Stable-Instance-Event", + } +} + +pub fn check_single_instance() -> bool { + if *db::ZED_STATELESS || *release_channel::RELEASE_CHANNEL == ReleaseChannel::Dev { + return true; + } + + check_single_instance_event() +} + +fn check_single_instance_event() -> bool { + unsafe { + CreateEventW( + None, + false, + false, + &HSTRING::from(retrieve_app_instance_event_identifier()), + ) + .expect("Unable to create instance sync event") + }; + let last_err = unsafe { GetLastError() }; + last_err != ERROR_ALREADY_EXISTS +}