mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
Fix icon/menu entries on macOS after update
We need to exec() Python from a GUI context so that the app name and icon are inherited from our launcher bundle. And we need to munge sys.argv[0] prior to main window instantiation so that we don't get app menu entries like "Hide -c". We do that in the launcher instead of __init__.py so that older versions display correctly too.
This commit is contained in:
parent
f5073b402a
commit
aa8dfe1cf4
2 changed files with 32 additions and 11 deletions
|
@ -6,7 +6,6 @@
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::os::unix::process::CommandExt;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use std::time::UNIX_EPOCH;
|
use std::time::UNIX_EPOCH;
|
||||||
|
@ -25,8 +24,8 @@ use anyhow::Result;
|
||||||
use crate::platform::ensure_terminal_shown;
|
use crate::platform::ensure_terminal_shown;
|
||||||
use crate::platform::get_exe_and_resources_dirs;
|
use crate::platform::get_exe_and_resources_dirs;
|
||||||
use crate::platform::get_uv_binary_name;
|
use crate::platform::get_uv_binary_name;
|
||||||
use crate::platform::launch_anki_after_update;
|
|
||||||
use crate::platform::launch_anki_normally;
|
use crate::platform::launch_anki_normally;
|
||||||
|
use crate::platform::respawn_launcher;
|
||||||
|
|
||||||
mod platform;
|
mod platform;
|
||||||
|
|
||||||
|
@ -148,8 +147,8 @@ fn run() -> Result<()> {
|
||||||
println!("\x1B[1mYou can close this window.\x1B[0m\n");
|
println!("\x1B[1mYou can close this window.\x1B[0m\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
let cmd = build_python_command(&state.uv_install_root, &[])?;
|
// respawn the launcher as a disconnected subprocess for normal startup
|
||||||
launch_anki_after_update(cmd)?;
|
respawn_launcher()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -493,7 +492,7 @@ fn build_python_command(uv_install_root: &std::path::Path, args: &[String]) -> R
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut cmd = Command::new(python_exe);
|
let mut cmd = Command::new(python_exe);
|
||||||
cmd.args(["-c", "import aqt; aqt.run()"]);
|
cmd.args(["-c", "import aqt, sys; sys.argv[0] = 'Anki'; aqt.run()"]);
|
||||||
cmd.args(args);
|
cmd.args(args);
|
||||||
// tell the Python code it was invoked by the launcher, and updating is
|
// tell the Python code it was invoked by the launcher, and updating is
|
||||||
// available
|
// available
|
||||||
|
|
|
@ -49,10 +49,32 @@ pub fn get_uv_binary_name() -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launch_anki_after_update(mut cmd: std::process::Command) -> Result<()> {
|
pub fn respawn_launcher() -> Result<()> {
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
|
|
||||||
cmd.stdin(Stdio::null())
|
let mut launcher_cmd = if cfg!(target_os = "macos") {
|
||||||
|
// On macOS, we need to launch the .app bundle, not the executable directly
|
||||||
|
let current_exe =
|
||||||
|
std::env::current_exe().context("Failed to get current executable path")?;
|
||||||
|
|
||||||
|
// Navigate from Contents/MacOS/launcher to the .app bundle
|
||||||
|
let app_bundle = current_exe
|
||||||
|
.parent() // MacOS
|
||||||
|
.and_then(|p| p.parent()) // Contents
|
||||||
|
.and_then(|p| p.parent()) // .app
|
||||||
|
.context("Failed to find .app bundle")?;
|
||||||
|
|
||||||
|
let mut cmd = std::process::Command::new("open");
|
||||||
|
cmd.arg(app_bundle);
|
||||||
|
cmd
|
||||||
|
} else {
|
||||||
|
let current_exe =
|
||||||
|
std::env::current_exe().context("Failed to get current executable path")?;
|
||||||
|
std::process::Command::new(current_exe)
|
||||||
|
};
|
||||||
|
|
||||||
|
launcher_cmd
|
||||||
|
.stdin(Stdio::null())
|
||||||
.stdout(Stdio::null())
|
.stdout(Stdio::null())
|
||||||
.stderr(Stdio::null());
|
.stderr(Stdio::null());
|
||||||
|
|
||||||
|
@ -61,16 +83,16 @@ pub fn launch_anki_after_update(mut cmd: std::process::Command) -> Result<()> {
|
||||||
use std::os::windows::process::CommandExt;
|
use std::os::windows::process::CommandExt;
|
||||||
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
|
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
|
||||||
const DETACHED_PROCESS: u32 = 0x00000008;
|
const DETACHED_PROCESS: u32 = 0x00000008;
|
||||||
cmd.creation_flags(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS);
|
launcher_cmd.creation_flags(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
{
|
{
|
||||||
use std::os::unix::process::CommandExt;
|
use std::os::unix::process::CommandExt;
|
||||||
cmd.process_group(0);
|
launcher_cmd.process_group(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let child = cmd.ensure_spawn()?;
|
let child = launcher_cmd.ensure_spawn()?;
|
||||||
std::mem::forget(child);
|
std::mem::forget(child);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue