diff --git a/.gitignore b/.gitignore index c888b21..9ed1d40 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,12 @@ /target-android Cargo.lock.bak *.log + +# makepkg build products. `packaging/PKGBUILD` and the .desktop entry are +# sources and belong in the tree; everything makepkg derives from them does +# not — `pkg/` and `src/` are staging directories it recreates on every run, +# and the package itself is 33 MB of compiled output. +/packaging/pkg/ +/packaging/src/ +/packaging/*.pkg.tar.* +/packaging/*.log diff --git a/packaging/PKGBUILD b/packaging/PKGBUILD new file mode 100644 index 0000000..5b29c8f --- /dev/null +++ b/packaging/PKGBUILD @@ -0,0 +1,46 @@ +# Maintainer: Duncan Tourolle +# +# Builds from the local checkout rather than a release tarball, which is what +# makes `makepkg -si` in this directory install what you are actually working +# on. Swap `source` for a tagged tarball when there is something to release. +pkgname=darkroom +pkgver=0.3.0 +pkgrel=1 +pkgdesc="Non-destructive RAW photo library and editor" +arch=('x86_64') +url="https://gitea.tourolle.paris/dtourolle/DarkRoom" +license=('GPL-3.0-or-later') +# Runtime: Vulkan for wgpu, and a Secret Service implementation for the +# Nextcloud credentials (FR-NC-2) — gnome-keyring or kwallet both provide it. +depends=('vulkan-icd-loader' 'fontconfig' 'libxkbcommon') +makedepends=('cargo' 'git') +optdepends=('gnome-keyring: store Nextcloud credentials' + 'kwallet: store Nextcloud credentials') +options=('!lto') # the workspace sets its own LTO in Cargo.toml + +_repo="$(cd "${startdir}/.." && pwd)" + +build() { + cd "${_repo}" + export RUSTUP_TOOLCHAIN=stable + export CARGO_TARGET_DIR="${_repo}/target" + cargo build --release --locked -p darkroom-desktop +} + +package() { + cd "${_repo}" + install -Dm755 "target/release/darkroom-desktop" \ + "${pkgdir}/usr/bin/darkroom-desktop" + + install -Dm644 "packaging/paris.tourolle.darkroom.desktop" \ + "${pkgdir}/usr/share/applications/paris.tourolle.darkroom.desktop" + + # The icon's *name* is the contract, not its path: the desktop entry says + # `Icon=paris.tourolle.darkroom` and the compositor resolves that through + # the hicolor theme. Installed under 256x256 because that is the source's + # actual size — lying about it makes scaled-down icons look wrong. + install -Dm644 "ui/dr-ui/ui/app-icon.png" \ + "${pkgdir}/usr/share/icons/hicolor/256x256/apps/paris.tourolle.darkroom.png" + + install -Dm644 "README.md" "${pkgdir}/usr/share/doc/${pkgname}/README.md" +} diff --git a/packaging/paris.tourolle.darkroom.desktop b/packaging/paris.tourolle.darkroom.desktop new file mode 100644 index 0000000..7d18de6 --- /dev/null +++ b/packaging/paris.tourolle.darkroom.desktop @@ -0,0 +1,18 @@ +[Desktop Entry] +Type=Application +Name=DarkRoom +GenericName=Photo Editor +Comment=Non-destructive RAW photo library and editor +# The basename of this file is the contract: a Wayland compositor finds it by +# matching the surface's app_id, which `dr_ui::run` sets to the same string. +# Rename one without the other and the icon silently disappears. +Exec=darkroom-desktop %F +Icon=paris.tourolle.darkroom +Terminal=false +Categories=Graphics;Photography;RasterGraphics;2DGraphics; +Keywords=RAW;photo;photography;develop;darkroom;library; +# X11 falls back to matching the WM_CLASS instead of the app_id; winit sets it +# from the same string, so naming it here covers both display servers. +StartupWMClass=paris.tourolle.darkroom +StartupNotify=true +MimeType=image/x-canon-cr2;image/x-canon-cr3;image/x-nikon-nef;image/x-sony-arw;image/x-adobe-dng;image/x-fuji-raf;image/x-olympus-orf;image/x-panasonic-rw2;image/jpeg;image/png;image/tiff; diff --git a/ui/dr-ui/src/lib.rs b/ui/dr-ui/src/lib.rs index 4463f42..e089b03 100644 --- a/ui/dr-ui/src/lib.rs +++ b/ui/dr-ui/src/lib.rs @@ -733,6 +733,30 @@ pub fn run(paths: Vec) -> Result<()> { let entries = Rc::new(RefCell::new(collect(&paths))); log::info!("{} image(s) to browse", entries.borrow().len()); + // TRACES: FR-PLAT-LIN-1 + // The name the compositor knows this window by, and the reason the + // launcher shows a real icon rather than a grey square. + // + // `app.slint` sets `icon:`, and that is genuinely embedded (see + // `build.rs`) — but a Wayland compositor ignores a client-set icon + // entirely. It takes the icon from the `.desktop` file whose basename + // matches the surface's `app_id`, and nothing else. So the embedded icon + // is what X11 and the window itself use, and *this* is what GNOME's + // overview, dash and alt-tab use. Both are needed and neither substitutes + // for the other. + // + // The string must equal the installed `.desktop` file's basename exactly: + // `packaging/paris.tourolle.darkroom.desktop`. It matches the Android + // package id (`AndroidManifest.xml`) on purpose — one application, one + // reverse-DNS name on both platforms. + // + // Before the window, necessarily: it is read when the surface is created. + if let Err(e) = slint::set_xdg_app_id("paris.tourolle.darkroom") { + // Not fatal. On X11 and on Android this does nothing useful, and a + // missing app id costs an icon rather than a working application. + log::debug!("could not set the xdg app id: {e}"); + } + // Before the window, and it has to be: this selects the Slint backend, and // creating a window selects one for us. See `shared_gpu`. The device is // shared by demosaic, the adjust pass and the compositor; without one the