diff --git a/.nix/pkgs/graphite.nix b/.nix/pkgs/graphite.nix
index d60d3667f5..d2bbca81bf 100644
--- a/.nix/pkgs/graphite.nix
+++ b/.nix/pkgs/graphite.nix
@@ -134,7 +134,10 @@ deps.crane.lib.buildPackage (
cp target/${if dev then "debug" else "release"}/graphite $out/bin/graphite
mkdir -p $out/share/applications
- cp $src/desktop/assets/*.desktop $out/share/applications/
+ cp $src/desktop/assets/art.graphite.Graphite.desktop $out/share/applications/
+
+ mkdir -p $out/share/mime/packages
+ cp $src/desktop/assets/art.graphite.Graphite.xml $out/share/mime/packages/
mkdir -p $out/share/icons/hicolor/scalable/apps
cp ${branding}/app-icons/graphite.svg $out/share/icons/hicolor/scalable/apps/art.graphite.Graphite.svg
diff --git a/Cargo.lock b/Cargo.lock
index dcc71e997b..c8a4a75c6b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2138,6 +2138,7 @@ name = "graphite-desktop-platform-win"
version = "0.0.0"
dependencies = [
"graphite-desktop",
+ "windows-registry 0.6.1",
"winres",
]
@@ -2439,7 +2440,7 @@ dependencies = [
"tokio",
"tower-service",
"tracing",
- "windows-registry",
+ "windows-registry 0.5.3",
]
[[package]]
@@ -6848,6 +6849,17 @@ dependencies = [
"windows-strings 0.4.2",
]
+[[package]]
+name = "windows-registry"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
+dependencies = [
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
+ "windows-strings 0.5.1",
+]
+
[[package]]
name = "windows-result"
version = "0.2.0"
diff --git a/desktop/assets/art.graphite.Graphite.desktop b/desktop/assets/art.graphite.Graphite.desktop
index 2e17c64fec..2e715a4f7d 100644
--- a/desktop/assets/art.graphite.Graphite.desktop
+++ b/desktop/assets/art.graphite.Graphite.desktop
@@ -2,10 +2,11 @@
Name=Graphite
GenericName=Vector & Raster Graphics Editor
Comment=Open-source vector & raster graphics editor. Featuring node based procedural nondestructive editing workflow.
-Exec=graphite
+Exec=graphite %F
Terminal=false
Type=Application
Icon=art.graphite.Graphite
Categories=Graphics;VectorGraphics;RasterGraphics;
Keywords=graphite;editor;vector;raster;procedural;design;
StartupWMClass=art.graphite.Graphite
+MimeType=application/graphite+json;image/svg+xml;image/png;image/jpeg;
diff --git a/desktop/assets/art.graphite.Graphite.xml b/desktop/assets/art.graphite.Graphite.xml
new file mode 100644
index 0000000000..7c087ee356
--- /dev/null
+++ b/desktop/assets/art.graphite.Graphite.xml
@@ -0,0 +1,9 @@
+
+
+
+ Graphite Document
+
+
+
+
+
diff --git a/desktop/platform/win/Cargo.toml b/desktop/platform/win/Cargo.toml
index e268622cca..34cf4871b4 100644
--- a/desktop/platform/win/Cargo.toml
+++ b/desktop/platform/win/Cargo.toml
@@ -15,5 +15,8 @@ path = "src/main.rs"
[dependencies]
graphite-desktop = { path = "../.." }
+[target.'cfg(target_os = "windows")'.dependencies]
+windows-registry = "0.6"
+
[target.'cfg(target_os = "windows")'.build-dependencies]
winres = "0.1"
diff --git a/desktop/platform/win/src/file_associations.rs b/desktop/platform/win/src/file_associations.rs
new file mode 100644
index 0000000000..18eee49124
--- /dev/null
+++ b/desktop/platform/win/src/file_associations.rs
@@ -0,0 +1,48 @@
+use std::env;
+use std::error::Error;
+
+use windows_registry::CURRENT_USER;
+
+const PROG_ID: &str = "Graphite.Document";
+const EXECUTABLE_NAME: &str = "Graphite.exe";
+const APP_FRIENDLY_NAME: &str = "Graphite";
+const DOCUMENT_FRIENDLY_NAME: &str = "Graphite Document";
+const MIME_TYPE: &str = "application/graphite+json";
+const FILE_EXTENSION: &str = ".graphite";
+const SUPPORTED_EXTENSIONS: &[&str] = &[FILE_EXTENSION, ".svg", ".png", ".jpg", ".jpeg"];
+
+pub fn register() {
+ if let Err(e) = register_inner() {
+ eprintln!("Failed to register file associations: {e}");
+ }
+}
+
+fn register_inner() -> Result<(), Box> {
+ let exe = env::current_exe()?;
+ let exe_string = exe.to_string_lossy();
+ let open_command = format!("\"{exe_string}\" \"%1\"");
+ let icon_value = format!("{exe_string},0");
+
+ let prog_id = CURRENT_USER.create(format!("Software\\Classes\\{PROG_ID}"))?;
+ prog_id.set_string("", DOCUMENT_FRIENDLY_NAME)?;
+ let prog_id_icon = CURRENT_USER.create(format!("Software\\Classes\\{PROG_ID}\\DefaultIcon"))?;
+ prog_id_icon.set_string("", &icon_value)?;
+ let prog_id_command = CURRENT_USER.create(format!("Software\\Classes\\{PROG_ID}\\shell\\open\\command"))?;
+ prog_id_command.set_string("", &open_command)?;
+
+ let app_base = format!("Software\\Classes\\Applications\\{EXECUTABLE_NAME}");
+ let app = CURRENT_USER.create(&app_base)?;
+ app.set_string("FriendlyAppName", APP_FRIENDLY_NAME)?;
+ let app_command = CURRENT_USER.create(format!("{app_base}\\shell\\open\\command"))?;
+ app_command.set_string("", &open_command)?;
+ let supported = CURRENT_USER.create(format!("{app_base}\\SupportedTypes"))?;
+ for extension in SUPPORTED_EXTENSIONS {
+ supported.set_string(extension, "")?;
+ }
+
+ let extension = CURRENT_USER.create(format!("Software\\Classes\\{FILE_EXTENSION}"))?;
+ extension.set_string("", PROG_ID)?;
+ extension.set_string("Content Type", MIME_TYPE)?;
+
+ Ok(())
+}
diff --git a/desktop/platform/win/src/main.rs b/desktop/platform/win/src/main.rs
index 2864480316..34a9762387 100644
--- a/desktop/platform/win/src/main.rs
+++ b/desktop/platform/win/src/main.rs
@@ -1,4 +1,11 @@
#![windows_subsystem = "windows"]
+
+#[cfg(target_os = "windows")]
+mod file_associations;
+
fn main() {
+ #[cfg(target_os = "windows")]
+ file_associations::register();
+
graphite_desktop::start();
}