feat(linux): add tray icon support
This commit is contained in:
parent
fa76c742c8
commit
1ecd8cf406
|
|
@ -1857,6 +1857,7 @@ dependencies = [
|
|||
"duckdb",
|
||||
"font-kit",
|
||||
"futures",
|
||||
"libloading 0.8.9",
|
||||
"log",
|
||||
"mongodb",
|
||||
"objc2",
|
||||
|
|
|
|||
|
|
@ -48,11 +48,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1783488441,
|
||||
"narHash": "sha256-jmWf+H3iC/0z7/mmvTovaJx1E/LME1QyHkyk+AFfJPk=",
|
||||
"lastModified": 1783614422,
|
||||
"narHash": "sha256-zSX553aXiIKJHWzUF6nrDKgeNRlfNK/SdyNYSbs2nkM=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "7dc3a177a239ed879c5581a80f6dc246c7e102f1",
|
||||
"rev": "e8e9d70b96113fd49ccde6c3e08fb260b6ef5dd6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
51
flake.nix
51
flake.nix
|
|
@ -43,6 +43,7 @@
|
|||
webkitgtk_4_1
|
||||
gtk3
|
||||
libappindicator-gtk3
|
||||
libayatana-appindicator # provides libayatana-appindicator3.so.1 (dlopen'd at runtime)
|
||||
librsvg
|
||||
patchelf
|
||||
openssl
|
||||
|
|
@ -205,6 +206,8 @@
|
|||
pkgs.rustPlatform.cargoSetupHook # sets CARGO_HOME to cargoDeps
|
||||
pkgs.pnpmConfigHook # sets up pnpm offline store
|
||||
pkgs.desktop-file-utils # for `desktop-file-validate`
|
||||
pkgs.copyDesktopItems # installs desktopItem into share/applications
|
||||
pkgs.imagemagick # generates correctly sized hicolor icons
|
||||
]
|
||||
++ pkgs.lib.optionals pkgs.stdenv.isLinux (
|
||||
with pkgs;
|
||||
|
|
@ -272,6 +275,21 @@
|
|||
# Tauri reads the version from this env var during build
|
||||
TAURI_SKIP_DEVSERVER_CHECK = "true";
|
||||
|
||||
# ── Runtime library path injection ───────────────────────────────── #
|
||||
# libappindicator-sys uses dlopen() at runtime to load the appindicator
|
||||
# shared library. dlopen() does NOT honour the binary's RPATH — it only
|
||||
# searches LD_LIBRARY_PATH and system paths. In a Nix derivation the
|
||||
# library lives in the store, not in /usr/lib, so we must inject the
|
||||
# path explicitly into the wrapGAppsHook3 C-wrapper.
|
||||
#
|
||||
# IMPORTANT: wrapGAppsHook3 uses its own `gappsWrapperArgs` bash array
|
||||
# (NOT `makeWrapperArgs`) — inject via preFixup before the hook runs.
|
||||
preFixup = pkgs.lib.optionalString pkgs.stdenv.isLinux ''
|
||||
gappsWrapperArgs+=(
|
||||
--prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath linuxTauriDeps}"
|
||||
)
|
||||
'';
|
||||
|
||||
# ── Build phases ─────────────────────────────────────────────────── #
|
||||
preConfigure = ''
|
||||
export HOME=$TMPDIR
|
||||
|
|
@ -312,9 +330,10 @@
|
|||
# tauri build --no-bundle puts the binary at target/release/dbx
|
||||
cp target/release/dbx $out/bin/dbx
|
||||
|
||||
# Copy desktop integration files if present.
|
||||
# Install every PNG size Tauri ships so the hicolor theme lookup
|
||||
# (e.g. panels @ 48px, launchers @ 128px) always succeeds.
|
||||
# Install icon files into the hicolor theme tree so that all
|
||||
# desktop environments (GNOME Shell, KDE Plasma, XFCE, etc.) can
|
||||
# find the right size: task-switcher (32px), panel (48px),
|
||||
# launcher (64px), app-menu (128px), HiDPI launcher (256px).
|
||||
if [ -d src-tauri/icons ]; then
|
||||
for size in 32 128; do
|
||||
if [ -f "src-tauri/icons/''${size}x''${size}.png" ]; then
|
||||
|
|
@ -323,12 +342,36 @@
|
|||
"$out/share/icons/hicolor/''${size}x''${size}/apps/dbx.png"
|
||||
fi
|
||||
done
|
||||
# @2x retina variant for 128px
|
||||
|
||||
# @2x retina variant (128x128@2x) → install as 256x256
|
||||
if [ -f "src-tauri/icons/128x128@2x.png" ]; then
|
||||
mkdir -p "$out/share/icons/hicolor/256x256/apps"
|
||||
cp "src-tauri/icons/128x128@2x.png" \
|
||||
"$out/share/icons/hicolor/256x256/apps/dbx.png"
|
||||
fi
|
||||
|
||||
# Generate missing common sizes so hicolor directory metadata
|
||||
# always matches the actual PNG dimensions.
|
||||
for size in 16 48 64; do
|
||||
mkdir -p "$out/share/icons/hicolor/''${size}x''${size}/apps"
|
||||
if [ "$size" -le 32 ] && [ -f "src-tauri/icons/32x32.png" ]; then
|
||||
src="src-tauri/icons/32x32.png"
|
||||
elif [ -f "src-tauri/icons/128x128.png" ]; then
|
||||
src="src-tauri/icons/128x128.png"
|
||||
else
|
||||
continue
|
||||
fi
|
||||
magick "$src" -resize "''${size}x''${size}" \
|
||||
"$out/share/icons/hicolor/''${size}x''${size}/apps/dbx.png"
|
||||
done
|
||||
|
||||
# Install the full-size icon.png as the scalable fallback so that
|
||||
# Tauri's default_window_icon() and the taskbar always have an image.
|
||||
if [ -f "src-tauri/icons/icon.png" ]; then
|
||||
mkdir -p "$out/share/icons/hicolor/512x512/apps"
|
||||
cp "src-tauri/icons/icon.png" \
|
||||
"$out/share/icons/hicolor/512x512/apps/dbx.png"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Register the freedesktop .desktop file so app launchers (GNOME
|
||||
|
|
|
|||
|
|
@ -66,3 +66,6 @@ tauri-plugin-clipboard-manager = "2.3.2"
|
|||
objc2 = { version = "0.6.4", default-features = false, features = ["std"] }
|
||||
objc2-app-kit = { version = "0.3.2", default-features = false, features = ["NSApplication", "NSImage"] }
|
||||
objc2-foundation = { version = "0.3.2", default-features = false, features = ["NSData"] }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
libloading = "0.8"
|
||||
|
|
|
|||
|
|
@ -69,8 +69,25 @@ fn should_hide_window_on_close(target_os: &str) -> bool {
|
|||
matches!(target_os, "macos" | "windows")
|
||||
}
|
||||
|
||||
fn should_setup_desktop_tray(target_os: &str, show_tray_icon: bool) -> bool {
|
||||
show_tray_icon && matches!(target_os, "macos" | "windows")
|
||||
fn should_setup_desktop_tray(target_os: &str, show_tray_icon: bool, linux_appindicator_available: bool) -> bool {
|
||||
show_tray_icon
|
||||
&& (matches!(target_os, "macos" | "windows") || (target_os == "linux" && linux_appindicator_available))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn linux_appindicator_available() -> bool {
|
||||
const APPINDICATOR_LIBRARIES: &[&str] = &["libayatana-appindicator3.so.1", "libappindicator3.so.1"];
|
||||
|
||||
APPINDICATOR_LIBRARIES.iter().any(|library| {
|
||||
// tray-icon loads AppIndicator dynamically and panics when neither ABI is
|
||||
// installed, so probe the same libraries before entering that code path.
|
||||
unsafe { libloading::Library::new(library).is_ok() }
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn linux_appindicator_available() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -449,7 +466,15 @@ fn apply_desktop_tray_icon_theme(app: &tauri::AppHandle, _icon_theme: DesktopIco
|
|||
};
|
||||
_tray.set_icon(icon)?;
|
||||
}
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let icon = match _icon_theme {
|
||||
DesktopIconTheme::Default => app.default_window_icon().cloned(),
|
||||
DesktopIconTheme::Black => Some(BLACK_APP_ICON),
|
||||
};
|
||||
_tray.set_icon(icon)?;
|
||||
}
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
|
||||
{
|
||||
let _ = (_tray, _icon_theme);
|
||||
}
|
||||
|
|
@ -460,7 +485,8 @@ fn apply_desktop_tray_icon_theme(app: &tauri::AppHandle, _icon_theme: DesktopIco
|
|||
pub(crate) fn apply_desktop_settings(app: &tauri::AppHandle, desktop_settings: &DesktopSettings) -> tauri::Result<()> {
|
||||
apply_debug_log_level(desktop_settings.debug_logging_enabled);
|
||||
apply_desktop_icon_theme(app, desktop_settings.icon_theme)?;
|
||||
if matches!(std::env::consts::OS, "macos" | "windows") {
|
||||
if should_setup_desktop_tray(std::env::consts::OS, desktop_settings.show_tray_icon, linux_appindicator_available())
|
||||
{
|
||||
if let Some(tray) = app.tray_by_id(DESKTOP_TRAY_ID) {
|
||||
tray.set_visible(desktop_settings.show_tray_icon)?;
|
||||
apply_desktop_tray_icon_theme(app, desktop_settings.icon_theme)?;
|
||||
|
|
@ -496,12 +522,14 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn sets_up_desktop_tray_for_windows_and_macos() {
|
||||
assert!(should_setup_desktop_tray("windows", true));
|
||||
assert!(should_setup_desktop_tray("macos", true));
|
||||
assert!(!should_setup_desktop_tray("windows", false));
|
||||
assert!(!should_setup_desktop_tray("macos", false));
|
||||
assert!(!should_setup_desktop_tray("linux", true));
|
||||
fn sets_up_desktop_tray_for_windows_macos_and_linux() {
|
||||
assert!(should_setup_desktop_tray("windows", true, false));
|
||||
assert!(should_setup_desktop_tray("macos", true, false));
|
||||
assert!(should_setup_desktop_tray("linux", true, true));
|
||||
assert!(!should_setup_desktop_tray("linux", true, false));
|
||||
assert!(!should_setup_desktop_tray("windows", false, true));
|
||||
assert!(!should_setup_desktop_tray("macos", false, true));
|
||||
assert!(!should_setup_desktop_tray("linux", false, true));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
|
@ -800,7 +828,11 @@ pub fn run() {
|
|||
let _ = window.set_decorations(decorations);
|
||||
}
|
||||
}
|
||||
if should_setup_desktop_tray(std::env::consts::OS, desktop_settings.show_tray_icon) {
|
||||
if should_setup_desktop_tray(
|
||||
std::env::consts::OS,
|
||||
desktop_settings.show_tray_icon,
|
||||
linux_appindicator_available(),
|
||||
) {
|
||||
setup_desktop_tray(app, desktop_settings.icon_theme)?;
|
||||
}
|
||||
apply_desktop_icon_theme(app.handle(), desktop_settings.icon_theme)?;
|
||||
|
|
|
|||
Loading…
Reference in New Issue