#!/bin/sh
# SolidCraft AppImage entry point (packaging/linux/AppRun; installed by package.sh).
# Adapted from PhotoCraft's AppRun (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md).
#
# On Wayland the compositor resolves a window's dock icon by taking the window's
# app_id (ai.storyteller.solidcraft) and looking up an installed .desktop file.
# An AppImage installs nothing, so every AppImage run would otherwise show the
# generic "Wayland" icon. Best-effort desktop integration: on first run
# (and whenever the AppImage's path changes) install the .desktop entry and the
# hicolor icons into $XDG_DATA_HOME, then launch. Every failure here must leave
# the launch untouched. Opt out with SOLIDCRAFT_NO_DESKTOP_INTEGRATION=1 (the pre-rename
# SOLVECRAFT_NO_DESKTOP_INTEGRATION still works: compatibility shim, docs/compatibility.md),
# or for good with an empty file $XDG_DATA_HOME/solidcraft/no-desktop-integration. Nothing is
# installed either when appimaged (go-appimage) already made an entry for this AppImage, or when
# a launcher that manages AppImages (Gear Lever, AppImageLauncher) started it: it sets
# DESKTOPINTEGRATION and owns the menu entry.

set -u

APPDIR="$(dirname "$(readlink -f "$0")")"
DESK_ID=ai.storyteller.solidcraft
# Compatibility shim (docs/compatibility.md): the desktop id of releases before 0.8.
OLD_DESK_ID=ai.storyteller.solvecraft

integrate() {
  case "${SOLIDCRAFT_NO_DESKTOP_INTEGRATION:-${SOLVECRAFT_NO_DESKTOP_INTEGRATION:-}}" in
    1 | true | yes) return 0 ;;
  esac
  # The AppImage runtime exports $APPIMAGE; without it (an extracted AppDir) there
  # is no path to register and nothing to do.
  appimage="${APPIMAGE:-}"
  [ -n "$appimage" ] && [ -f "$appimage" ] || return 0
  appimage="$(readlink -f "$appimage")" || return 0
  # Exec= is parsed by the desktop: a path holding a quote, backquote, dollar, backslash,
  # percent or a line break would need escaping (or could add lines), so skip integration.
  case "$appimage" in
    *[\"\`\$\\%]* | *'
'*) return 0 ;;
  esac
  home="${HOME:-}"
  [ -n "$home" ] || return 0
  data="${XDG_DATA_HOME:-$home/.local/share}"
  [ -e "$data/solidcraft/no-desktop-integration" ] && return 0
  src_desktop="$APPDIR/usr/share/applications/$DESK_ID.desktop"
  [ -f "$src_desktop" ] || return 0

  apps="$data/applications"
  # Gear Lever and AppImageLauncher write their own entry and start the AppImage with
  # DESKTOPINTEGRATION set; treat that like appimaged: no entry from here, and drop the one
  # this script wrote earlier (it would otherwise come back after the launcher's is removed).
  if [ -n "${DESKTOPINTEGRATION:-}" ]; then
    mine="$apps/$DESK_ID.desktop"
    if [ -f "$mine" ] && grep -q '^Exec="' "$mine"; then
      rm -f "$mine"
      command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$apps" >/dev/null 2>&1
    fi
    return 0
  fi
  # appimaged integrates AppImages itself (appimagekit_<hash>-<name>.desktop, Exec= this file):
  # a second entry from here would show the app twice, so drop an entry this script wrote earlier
  # (only one it wrote: it points Exec at a path in quotes) and leave the rest to appimaged.
  for other in "$apps"/appimagekit_*.desktop; do
    if ! { [ -f "$other" ] && grep -qF "$appimage" "$other" 2>/dev/null; }; then
      continue
    fi
    mine="$apps/$DESK_ID.desktop"
    if [ -f "$mine" ] && grep -q '^Exec="' "$mine"; then
      rm -f "$mine"
      command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$apps" >/dev/null 2>&1
    fi
    return 0
  done

  # Rewrite Exec to this AppImage (the binary is not on the host PATH) and drop
  # TryExec, which would hide the entry; everything else is shipped as packaged.
  mkdir -p "$apps" 2>/dev/null || return 0
  tmp="$apps/.$DESK_ID.tmp.$$"
  esc="$(printf '%s' "$appimage" | sed 's/[\\&|]/\\&/g')"
  if sed -e "s|^Exec=.*|Exec=\"$esc\" %F|" -e '/^TryExec=/d' "$src_desktop" 2>/dev/null >"$tmp"; then
    if cmp -s "$tmp" "$apps/$DESK_ID.desktop"; then
      rm -f "$tmp"
    else
      if mv -f "$tmp" "$apps/$DESK_ID.desktop" 2>/dev/null; then
        command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$apps" >/dev/null 2>&1
      else
        rm -f "$tmp"
      fi
    fi
  else
    rm -f "$tmp"
    return 0
  fi

  # An entry and icons that an AppImage before 0.8 installed under the old id would show a
  # second menu entry; remove them (only an entry this script wrote: it points Exec at a path).
  old="$apps/$OLD_DESK_ID.desktop"
  if [ -f "$old" ] && grep -q "^Icon=$OLD_DESK_ID\$" "$old" && grep -q '^Exec="' "$old"; then
    rm -f "$old" "$data"/icons/hicolor/*/apps/"$OLD_DESK_ID".png 2>/dev/null
    command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$apps" >/dev/null 2>&1
  fi

  # Icons: per-file compare so an unchanged install costs a handful of cmp calls.
  src_icons="$APPDIR/usr/share/icons/hicolor"
  [ -d "$src_icons" ] || return 0
  icons="$data/icons/hicolor"
  (cd "$src_icons" && find . -type f) | while IFS= read -r rel; do
    mkdir -p "$icons/$(dirname "$rel")" 2>/dev/null || continue
    if ! cmp -s "$src_icons/$rel" "$icons/$rel"; then
      cp "$src_icons/$rel" "$icons/$rel" 2>/dev/null || true
    fi
  done
}

integrate
exec "$APPDIR/usr/bin/solidcraft" "$@"
