Installation Vortex sur GLF OS

  1. Ouvrir le terminal


  1. Créer le fichier vortex.nix

Tape :

sudo nano /etc/nixos/customConfig/vortex.nix

  1. Mettre le code dans vortex.nix

Recopiez/collez le code fourni dans le fichier.
(Vous pouvez faire un clic droit dans le terminal, puis cliquer sur « Coller ».)

Code à recopier (Vous avez un bouton à droite du code pour copier le bloc en entier.)
# gaming/vortex.nix
# ---- Vortex — Nexus Mods ----
{
  pkgs,
  ...
}:

let
  # ---- umu ----
  umu = pkgs.umu-launcher;

  # ---- commande ----
  vortex = pkgs.writeShellScriptBin "vortex" ''
    set -euo pipefail

    # ---- outils ----
    CURL="${pkgs.curl}/bin/curl"
    JQ="${pkgs.jq}/bin/jq"
    UMU="${umu}/bin/umu-run"
    PYTHON="${pkgs.python3}/bin/python3"
    XDG_MIME="${pkgs.xdg-utils}/bin/xdg-mime"
    UPDATE_DESKTOP="${pkgs.desktop-file-utils}/bin/update-desktop-database"
    NOTIFY="${pkgs.libnotify}/bin/notify-send"

    # ---- préfixe ----
    COMPAT="''${XDG_DATA_HOME:-$HOME/.local/share}/vortex"
    PFX="$COMPAT/pfx"
    CACHE="''${XDG_CACHE_HOME:-$HOME/.cache}/vortex"
    DOTNET_URL="''${DOTNET_URL:-https://builds.dotnet.microsoft.com/dotnet/WindowsDesktop/9.0.13/windowsdesktop-runtime-9.0.13-win-x64.exe}"

    # ---- messages ----
    note() { printf '==> %s\n' "$*"; }
    die() { printf 'erreur: %s\n' "$*" >&2; exit 1; }
    notify() {
      "$NOTIFY" -a Vortex "$@" >/dev/null 2>&1 || true
    }

    # ---- environnement ----
    scrub_env() {
      unset GI_TYPELIB_PATH GTK_PATH GIO_EXTRA_MODULES GIO_MODULE_DIR || true
      unset GSETTINGS_SCHEMA_DIR NIX_GSETTINGS_OVERRIDES_DIR NIX_PROFILES || true
      unset GDM_X_SERVER_EXTRA_ARGS || true
      unset XDG_DATA_DIRS XDG_CONFIG_DIRS || true
      unset QT_PLUGIN_PATH QML2_IMPORT_PATH QTWEBKIT_PLUGIN_PATH || true
      unset QT_AUTO_SCREEN_SCALE_FACTOR QT_SCREEN_SCALE_FACTORS || true
      unset QT_QPA_PLATFORMTHEME QT_STYLE_OVERRIDE || true
      unset QT_WAYLAND_DISABLE_WINDOWDECORATION QT_IM_MODULE || true
      unset KDEDIRS KDE_FULL_SESSION KDE_SESSION_VERSION || true
      unset KDE_SESSION_UID KDE_APPLICATIONS_AS_SCOPE || true
      unset XCURSOR_PATH INFOPATH MANPATH TERMINFO_DIRS LIBEXEC_PATH || true
      unset PERLLIB PERL5LIB PYTHONPATH || true
    }

    # ---- steam ----
    find_steam_root() {
      local d
      for d in \
        "$HOME/.local/share/Steam" \
        "$HOME/.steam/steam" \
        "$HOME/.steam/root"
      do
        if [[ -d "$d/steamapps" ]]; then
          printf '%s\n' "$d"
          return 0
        fi
      done
      return 1
    }

    # ---- proton ----
    find_proton() {
      local steam root tool d ge_list=() official_list=()
      for d in \
        "$HOME/.config/heroic/tools/proton/Proton-GE-GLF" \
        "$HOME/.local/share/Steam/compatibilitytools.d/Proton-GE-GLF" \
        "$HOME/.steam/root/compatibilitytools.d/Proton-GE-GLF"
      do
        if [[ -x "$d/proton" ]]; then
          printf '%s\n' "$d"
          return 0
        fi
      done
      steam="$(find_steam_root)" || return 1
      local -a roots=("$steam")
      if [[ -f "$steam/steamapps/libraryfolders.vdf" ]]; then
        while IFS= read -r root; do
          [[ -n "$root" && -d "$root" ]] && roots+=("$root")
        done < <("$PYTHON" - "$steam/steamapps/libraryfolders.vdf" <<'PY'
import re, sys
text = open(sys.argv[1], encoding="utf-8", errors="replace").read()
for path in re.findall(r'"path"\s+"([^"]+)"', text):
    print(path)
PY
        )
      fi
      for root in "''${roots[@]}"; do
        if [[ -d "$root/compatibilitytools.d" ]]; then
          for d in "$root/compatibilitytools.d"/*; do
            [[ -x "$d/proton" ]] || continue
            case "$(basename "$d")" in
              GE-Proton*|GE-Proton) ge_list+=("$d") ;;
              *) official_list+=("$d") ;;
            esac
          done
        fi
        if [[ -d "$root/steamapps/common" ]]; then
          for d in "$root/steamapps/common"/Proton*; do
            [[ -x "$d/proton" ]] || continue
            official_list+=("$d")
          done
        fi
      done
      if [[ ''${#ge_list[@]} -gt 0 ]]; then
        printf '%s\n' "''${ge_list[@]}" | sort -V | tail -n 1
        return 0
      fi
      if [[ ''${#official_list[@]} -gt 0 ]]; then
        printf '%s\n' "''${official_list[@]}" | sort -V | tail -n 1
        return 0
      fi
      return 1
    }

    # ---- vortex.exe ----
    find_exe() {
      local c
      for c in \
        "$PFX/drive_c/Program Files/Black Tree Gaming Ltd/Vortex/Vortex.exe" \
        "$PFX/drive_c/Program Files/Vortex/Vortex.exe"
      do
        if [[ -f "$c" ]]; then
          printf '%s\n' "$c"
          return 0
        fi
      done
      return 1
    }

    # ---- lancement ----
    run_umu() {
      local proton="''${1-}"
      shift
      local shared patched
      shared="$COMPAT/wine-tmp"
      mkdir -p "$COMPAT" "$shared"
      patched="$COMPAT/umu-run"
      if [[ ! -x "$patched" || "$UMU" -nt "$patched" ]]; then
        sed "s|^  --tmpfs /tmp\$|  --bind \"$shared\" /tmp|" "$UMU" > "$patched"
        chmod +x "$patched"
      fi
      grep -q -F -- "--bind \"$shared\" /tmp" "$patched" || die "Partage /tmp impossible."
      scrub_env
      export GAMEID="umu-vortex"
      export SteamGameId="umu-vortex"
      export STORE="none"
      export STEAM_COMPAT_DATA_PATH="$COMPAT"
      export WINEPREFIX="$PFX"
      export WINEDLLOVERRIDES="winemenubuilder.exe=d"
      export PROTON_USE_XALIA=0
      # run : évite waitforexitandrun qui reste coincé si un wineserver zombie tourne
      export PROTON_VERB="''${PROTON_VERB:-run}"
      # X11 seulement : sinon Electron/Wine démarre sans fenêtre sur Wayland
      unset WAYLAND_DISPLAY || true
      unset GDK_BACKEND || true
      unset QT_QPA_PLATFORM || true
      unset NIXOS_OZONE_WL || true
      export GDK_BACKEND=x11
      export QT_QPA_PLATFORM=xcb
      export ELECTRON_OZONE_PLATFORM_HINT=x11
      if [[ -n "$proton" && -x "$proton/proton" ]]; then
        export PROTONPATH="$proton"
      else
        unset PROTONPATH || true
      fi
      "$patched" "$@"
    }

    # ---- nettoyage zombies ----
    cleanup_zombies() {
      local self=$$ pid
      # Ne pas se tuer soi-même : sinon OOM + fenêtre invisible à cause des clones
      while read -r pid; do
        [[ -z "$pid" || "$pid" == "$self" ]] && continue
        kill "$pid" >/dev/null 2>&1 || true
      done < <(pgrep -f '/bin/vortex' || true)
      pkill -f 'Vortex\.exe' >/dev/null 2>&1 || true
      pkill -f 'Program Files/Vortex' >/dev/null 2>&1 || true
      pkill -f 'wineserver -w' >/dev/null 2>&1 || true
      sleep 1
      while read -r pid; do
        [[ -z "$pid" || "$pid" == "$self" ]] && continue
        kill -9 "$pid" >/dev/null 2>&1 || true
      done < <(pgrep -f '/bin/vortex' || true)
      pkill -9 -f 'Vortex\.exe' >/dev/null 2>&1 || true
      pkill -9 -f 'Program Files/Vortex' >/dev/null 2>&1 || true
      rm -f "$PFX/drive_c/users/steamuser/AppData/Roaming/Vortex/lockfile" 2>/dev/null || true
    }

    # ---- bibliothèques ----
    link_steam() {
      local proton="''${1:-}"
      local fake="$PFX/drive_c/Program Files (x86)/Steam"
      local dos="$PFX/dosdevices"
      local steam vdf
      mkdir -p "$fake/steamapps" "$fake/config" "$dos"
      : > "$fake/steam.exe"

      if ! steam="$(find_steam_root)"; then
        note "Steam introuvable."
      elif [[ ! -f "$steam/steamapps/libraryfolders.vdf" ]]; then
        note "libraryfolders.vdf absent."
      else
      vdf="$steam/steamapps/libraryfolders.vdf"

      "$PYTHON" - "$vdf" "$fake/steamapps/libraryfolders.vdf" "$fake/config/libraryfolders.vdf" "$dos" <<'PY'
import os, re, sys

src, out_apps, out_cfg, dos = sys.argv[1:5]
text = open(src, encoding="utf-8", errors="replace").read()
paths = []
seen = set()

def conv(match):
    path = match.group(1)
    if path.startswith("/") and path not in seen:
        seen.add(path)
        paths.append(path)
    if path.startswith("/"):
        path = "Z:" + path.replace("/", "\\")
    return f'"path"\t\t"{path}"'

converted = re.sub(r'"path"\s+"([^"]+)"', conv, text)
for dest in (out_apps, out_cfg):
    os.makedirs(os.path.dirname(dest), exist_ok=True)
    with open(dest, "w", encoding="utf-8") as fh:
        fh.write(converted)

letters = list("jklmnopqrstuvwxy")
used = 0
for path in paths:
    common = os.path.join(path, "steamapps", "common")
    if not os.path.isdir(common) or used >= len(letters):
        continue
    link = os.path.join(dos, f"{letters[used]}:")
    if os.path.isdir(link) and not os.path.islink(link):
        print(f"    {letters[used]}: déjà un dossier, ignoré")
        used += 1
        continue
    if os.path.lexists(link):
        os.remove(link)
    os.symlink(common, link)
    print(f"    {letters[used]}: -> {common}")
    used += 1
PY

      if [[ -n "$proton" ]]; then
        run_umu "$proton" reg add 'HKCU\Software\Valve\Steam' /v SteamPath /t REG_SZ /d 'C:\Program Files (x86)\Steam' /f \
          || note "Registre SteamPath non écrit."
        run_umu "$proton" reg add 'HKCU\Software\Valve\Steam' /v SteamExe /t REG_SZ /d 'C:\Program Files (x86)\Steam\steam.exe' /f \
          || true
        run_umu "$proton" reg add 'HKCU\Software\Wine' /v Version /t REG_SZ /d win10 /f || true
      fi
      fi
      link_launchers "$proton"
      note "Jeux liés."
    }

    # ---- lanceurs ----
    link_launchers() {
      local proton="''${1:-}"
      local dos="$PFX/dosdevices"
      local list="$CACHE/launchers.tsv"
      local kind app path
      mkdir -p "$dos" "$CACHE"
      "$PYTHON" - "$dos" "$list" <<'PY'
import json, os, sys

home = os.environ["HOME"]
dos, out = sys.argv[1:3]
lines = []
parents = []
seen = set()

def remember(path):
    path = os.path.realpath(path)
    if os.path.isdir(path) and path not in seen:
        seen.add(path)
        parents.append(path)

def win(path):
    return "Z:" + os.path.realpath(path).replace("/", "\\")

gog = os.path.join(home, ".config/heroic/gog_store/installed.json")
if os.path.isfile(gog):
    for game in json.load(open(gog, encoding="utf-8")).get("installed") or []:
        if game.get("is_dlc"):
            continue
        path = game.get("install_path") or ""
        app = str(game.get("appName") or "")
        if app and path and os.path.isdir(path):
            lines.append(f"GOG\t{app}\t{win(path)}")
            remember(os.path.dirname(os.path.realpath(path)))

leg = os.path.join(home, ".config/heroic/legendaryConfig/legendary/installed.json")
if os.path.isfile(leg):
    data = json.load(open(leg, encoding="utf-8"))
    items = data if isinstance(data, list) else []
    if isinstance(data, dict):
        items = data.get("installed") or [
            v for v in data.values() if isinstance(v, dict)
        ]
    for game in items:
        if not isinstance(game, dict):
            continue
        path = game.get("install_path") or game.get("install_dir") or ""
        if path and os.path.isdir(path):
            remember(os.path.dirname(os.path.realpath(path)))

db = os.path.join(home, ".local/share/lutris/pga.db")
if os.path.isfile(db):
    import sqlite3
    con = sqlite3.connect(db)
    try:
        for directory, service, service_id, installed in con.execute(
            "SELECT directory, service, service_id, installed FROM games"
        ):
            if not installed or not directory or not os.path.isdir(directory):
                continue
            parent = os.path.dirname(os.path.realpath(directory))
            if parent and parent != "/":
                remember(parent)
            if (service or "").lower() == "gog" and service_id:
                lines.append(f"GOG\t{service_id}\t{win(directory)}")
    finally:
        con.close()

faugus = os.path.join(home, ".config/faugus-launcher/config.json")
if os.path.isfile(faugus):
    path = json.load(open(faugus, encoding="utf-8")).get("default-prefix") or ""
    if path and os.path.isdir(path):
        remember(path)

games = os.path.join(home, ".config/faugus-launcher/games.json")
if os.path.isfile(games):
    def walk(node):
        if isinstance(node, dict):
            for key, value in node.items():
                if key.lower() in {"path", "prefix", "install_path", "game_path", "folder"} \
                        and isinstance(value, str) and value.startswith("/") and os.path.isdir(value):
                    remember(value)
                else:
                    walk(value)
        elif isinstance(node, list):
            for item in node:
                walk(item)
    walk(json.load(open(games, encoding="utf-8")))

used = set()
if os.path.isdir(dos):
    for name in os.listdir(dos):
        if len(name) == 2 and name.endswith(":"):
            used.add(name[0].lower())
letters = [c for c in "jklmnopqrstuvwxy" if c not in used]
for path in parents:
    if not letters:
        break
    letter = letters.pop(0)
    link = os.path.join(dos, f"{letter}:")
    if os.path.isdir(link) and not os.path.islink(link):
        print(f"    {letter}: dossier, ignoré")
        continue
    if os.path.lexists(link):
        os.remove(link)
    os.symlink(path, link)
    print(f"    {letter}: -> {path}")
    stage = os.path.join(path, "Vortex")
    try:
        os.makedirs(os.path.join(stage, "staging"), exist_ok=True)
        os.makedirs(os.path.join(stage, "downloads"), exist_ok=True)
        lines.append(f"STAGE\t{stage}")
    except OSError as err:
        print(f"    staging ignoré: {err}")

with open(out, "w", encoding="utf-8") as fh:
    fh.write("".join(f"{line}\n" for line in lines))
PY
      [[ -f "$list" ]] || return 0
      while IFS=$'\t' read -r kind app path; do
        [[ -n "$kind" ]] || continue
        case "$kind" in
          GOG)
            [[ -n "$proton" && -n "$app" && -n "$path" ]] || continue
            run_umu "$proton" reg add "HKLM\\Software\\GOG.com\\Games\\$app" /v path /t REG_SZ /d "$path" /f || true
            run_umu "$proton" reg add "HKLM\\Software\\WOW6432Node\\GOG.com\\Games\\$app" /v path /t REG_SZ /d "$path" /f || true
            note "GOG $app"
            ;;
          STAGE)
            note "staging $app"
            ;;
        esac
      done < "$list"
    }

    # ---- nxm ----
    register_nxm() {
      "$XDG_MIME" default vortex.desktop x-scheme-handler/nxm || true
      "$XDG_MIME" default vortex.desktop x-scheme-handler/nxm-protocol || true
      if [[ -d "$HOME/.local/share/applications" ]]; then
        "$UPDATE_DESKTOP" "$HOME/.local/share/applications" || true
      fi
      "$UPDATE_DESKTOP" || true
    }

    # ---- téléchargement ----
    download() {
      local url="$1" dest="$2"
      if [[ -f "$dest" && "''${VORTEX_FORCE_DOWNLOAD:-}" != 1 ]]; then
        note "Déjà téléchargé : $dest"
        return 0
      fi
      note "Téléchargement : $url"
      "$CURL" -fL --retry 3 --retry-delay 2 -o "$dest.partial" "$url"
      mv -f "$dest.partial" "$dest"
    }

    # ---- installation ----
    do_install() {
      local proton="" ver url setup dotnet
      mkdir -p "$CACHE" "$COMPAT"
      notify "Installation de Vortex" "Téléchargement de la dernière version stable…"

      if proton="$(find_proton)"; then
        note "Proton : $proton"
      else
        note "Aucun Proton Steam trouvé. umu va télécharger GE-Proton au premier lancement."
        proton=""
      fi

      if [[ -n "''${VORTEX_VERSION:-}" ]]; then
        ver="''${VORTEX_VERSION#v}"
        url="https://github.com/Nexus-Mods/Vortex/releases/download/v''${ver}/vortex-setup-''${ver}.exe"
      else
        note "Recherche de la dernière release stable…"
        local api
        api="$("$CURL" -fsSL \
          -H "Accept: application/vnd.github+json" \
          -H "User-Agent: glf-vortex-install" \
          https://api.github.com/repos/Nexus-Mods/Vortex/releases/latest)"
        ver="$("$JQ" -er '.tag_name' <<<"$api")"
        ver="''${ver#v}"
        url="$("$JQ" -er '[.assets[].browser_download_url | select(test("vortex-setup-.*\\.exe$"))][0]' <<<"$api")"
        [[ -n "$url" && "$url" != null ]] || die "Installeur Windows introuvable dans la release $ver."
      fi

      note "Vortex $ver"
      setup="$CACHE/vortex-setup-$ver.exe"
      dotnet="$CACHE/windowsdesktop-runtime-9.0.13-win-x64.exe"
      download "$url" "$setup"
      download "$DOTNET_URL" "$dotnet"

      note "Préfixe : $PFX"
      note "Runtime .NET 9 Desktop (9.0.13)…"
      run_umu "$proton" "$dotnet" /install /quiet /norestart || note "Le runtime a renvoyé une erreur ; l’installeur Vortex embarque le sien."

      note "Windows 10 dans le préfixe (Vortex 1.8+)."
      run_umu "$proton" reg add 'HKCU\Software\Wine' /v Version /t REG_SZ /d win10 /f || true

      note "Installation silencieuse de Vortex (/S)…"
      run_umu "$proton" "$setup" /S || note "L’installeur a renvoyé un code non nul ; vérification du binaire…"

      find_exe >/dev/null || die "Vortex.exe introuvable dans $PFX. Relance avec VORTEX_FORCE_DOWNLOAD=1 vortex install"
      printf '%s\n' "$ver" > "$COMPAT/version"  # version installée 
      note "Liaison des jeux…"
      link_steam "$proton"
      register_nxm
      notify "Vortex est installé" "vortex"
      printf 'Vortex %s\n%s\n' "$ver" "$PFX"
    }

    # ---- démarrage ----
    vortex_running() {
      local line
      while IFS= read -r line; do
        [[ "$line" == *--type=* ]] && continue
        [[ "$line" == *Vortex.exe* ]] && return 0
      done < <(pgrep -af -- 'Vortex\.exe' 2>/dev/null || true)
      return 1
    }

    # Transmet un nxm:// au Vortex déjà ouvert / Hand an nxm:// to the running Vortex
    send_nxm() {
      local proton="$1" exe="$2" url="$3" pid i
      cd "$(dirname "$exe")"
      # via umu, en arrière-plan, sans le verrou (9>&-) / via umu, background, without the lock fd
      PROTON_VERB=run run_umu "$proton" "$exe" -d "$url" >> "$COMPAT/nxm.log" 2>&1 9>&- &
      pid=$!
      # attente max 6 s puis on passe au lien suivant, sans kill / wait max 6s then move on, no kill
      for i in 1 2 3 4 5 6; do
        kill -0 "$pid" >/dev/null 2>&1 || break
        sleep 1
      done
      disown "$pid" >/dev/null 2>&1 || true
    }

    # ---- mise à jour auto ----
    check_update() {
      local proton="$1" cur="" latest api url setup
      # désactivable avec VORTEX_NO_UPDATE=1 / can be disabled with VORTEX_NO_UPDATE=1
      [[ -z "''${VORTEX_NO_UPDATE:-}" && -z "''${VORTEX_VERSION:-}" ]] || return 0
      if [[ -f "$COMPAT/version" ]]; then cur="$(<"$COMPAT/version")"; fi
      # timeout 5s, hors ligne = on passe / 5s timeout, offline = skip
      api="$("$CURL" -fsS --max-time 5 \
        -H "Accept: application/vnd.github+json" \
        -H "User-Agent: glf-vortex-install" \
        https://api.github.com/repos/Nexus-Mods/Vortex/releases/latest)" || return 0
      latest="$("$JQ" -er '.tag_name' <<<"$api")" || return 0
      latest="''${latest#v}"
      [[ "$latest" != "$cur" ]] || return 0
      url="$("$JQ" -er '[.assets[].browser_download_url | select(test("vortex-setup-.*\\.exe$"))][0]' <<<"$api")" || return 0
      [[ -n "$url" && "$url" != null ]] || return 0
      note "Mise à jour Vortex : ''${cur:-inconnue} -> $latest"
      notify "Vortex" "Mise à jour vers $latest…"
      setup="$CACHE/vortex-setup-$latest.exe"
      mkdir -p "$CACHE"
      download "$url" "$setup" || return 0
      run_umu "$proton" "$setup" /S || note "Mise à jour en erreur / update failed"
      printf '%s\n' "$latest" > "$COMPAT/version"
    }

    do_launch() {
      local proton exe
      exe="$(find_exe)" || die "Vortex n’est pas installé. Lance : vortex install"
      proton="$(find_proton || true)"
      # pas de MAJ si Vortex tourne déjà
      if ! vortex_running; then check_update "$proton"; fi
      cd "$(dirname "$exe")"
      if [[ "''${1:-}" == nxm://* || "''${1:-}" == nxm-protocol://* ]]; then
        if vortex_running; then
          local queue="$COMPAT/nxm.queue" lock="$COMPAT/nxm.lock" url
          mkdir -p "$COMPAT"
          printf '%s\n' "$1" >> "$queue"
          (
            flock 9 || exit 0
            while true; do
              mapfile -t urls < "$queue" || true
              : > "$queue"
              [[ ''${#urls[@]} -eq 0 ]] && break
              for url in "''${urls[@]}"; do
                [[ -n "$url" ]] || continue
                send_nxm "$proton" "$exe" "$url"
              done
            done
          ) 9>"$lock" >/dev/null 2>&1 &
          disown || true
        else
          printf '%s nxm sans Vortex actif, relance\n' "$(date +%T)" >> "$COMPAT/nxm.log"
          notify "Vortex" "Ouverture…"
          cleanup_zombies
          PROTON_VERB=run run_umu "$proton" "$exe" -d "$1"
        fi
      elif [[ $# -gt 0 ]]; then
        cleanup_zombies
        notify "Vortex" "Ouverture…"
        run_umu "$proton" "$exe" "$@"
      else
        cleanup_zombies
        notify "Vortex" "Ouverture…"
        run_umu "$proton" "$exe"
      fi
    }

    # ---- commandes ----
    cmd="''${1:-}"
    case "$cmd" in
      install)
        do_install
        ;;
      link-steam|link)
        link_steam "$(find_proton || true)"
        ;;
      help|-h|--help)
        cat <<EOF
vortex
vortex install
vortex link-steam
EOF
        ;;
      nxm://*|nxm-protocol://*)
        if find_exe >/dev/null; then
          do_launch "$@"
        else
          notify "Vortex n’est pas installé" "Lance d’abord : vortex install"
          die "Vortex n’est pas installé. Lance : vortex install"
        fi
        ;;
      *)
        if find_exe >/dev/null; then
          do_launch "$@"
        else
          note "Vortex n’est pas encore installé. Installation…"
          do_install
          do_launch "$@"
        fi
        ;;
    esac
  '';

  # ---- icône ----
  vortexIcon = pkgs.fetchurl {
    url = "https://raw.githubusercontent.com/Nexus-Mods/Vortex/master/assets/images/vortex.png";
    hash = "sha256-SUaJlRM+s/V/KNmd+oCQIZ8d85Oz+F75Yi2VDBwtlU0=";
  };

  # ---- raccourci ----
  vortexDesktop = pkgs.stdenvNoCC.mkDerivation {
    name = "vortex-desktop";
    dontUnpack = true;
    nativeBuildInputs = [ pkgs.copyDesktopItems ];

    desktopItems = [
      (pkgs.makeDesktopItem {
        name = "vortex";
        desktopName = "Vortex";
        comment = "Gestionnaire de mods Nexus Mods";
        exec = "vortex %u";
        icon = "com.nexusmods.vortex";
        terminal = false;
        categories = [ "Game" "Utility" ];
        mimeTypes = [
          "x-scheme-handler/nxm"
          "x-scheme-handler/nxm-protocol"
        ];
        startupWMClass = "vortex";
      })
    ];

    installPhase = ''
      runHook preInstall
      mkdir -p \
        $out/share/icons/hicolor/256x256/apps \
        $out/share/icons/Tela-circle/scalable/apps
      cp ${vortexIcon} $out/share/icons/hicolor/256x256/apps/com.nexusmods.vortex.png
      cp ${vortexIcon} $out/share/icons/Tela-circle/scalable/apps/com.nexusmods.vortex.png
      runHook postInstall
    '';
  };
in
{
  # ---- paquets ----
  environment.systemPackages = [
    vortex
    vortexDesktop
    umu
  ];
}

Ensuite :

Ctrl + X pour quitter

Faire O pour confirmer l'enregistrement

Entrée pour confirmer


  1. Modifier default.nix

Ouvre ensuite :

sudo nano /etc/nixos/customConfig/default.nix

Dans imports :

  imports = [
    ./vortex.nix
  ];

Ensuite :

Ctrl + X -> O -> Entrée


  1. Rebuild GLF-OS

Faite :

glf-update --switch

L’icône Vortex apparaît dans le menu. Le programme n’est pas encore téléchargé.


  1. Premier lancement

Clique sur l’icône Vortex dans le menu.

La première fois, le téléchargement et l’installation se font tout seuls. Comptez plusieurs minutes. Le bureau reste en Wayland. Seule la fenêtre de Vortex passe par XWayland.

Steam, Heroic (GOG et Epic), Lutris et Faugus déjà installés sont reliés tout seuls. Rien d’autre à faire.

Dans Vortex : compte Nexus, déploiement Hardlink, dossier de staging sur le même disque que le jeu.

Les liens « Download with manager » (nxm://) ouvrent Vortex.

Si besoin, le terminal :

vortex

Icone


DÉSINSTALLATION

Retire l’import dans default.nix :

    ./vortex.nix

Supprime le fichier :

sudo rm -f /etc/nixos/customConfig/vortex.nix

Puis :

glf-update --switch

Ça enlève la commande vortex et le raccourci du menu.

Ce qui reste à supprimer manuellement si voulu :

~/.local/share/vortex (préfixe Proton + Vortex)
~/.cache/vortex (installeurs téléchargés)

rm -rf ~/.local/share/vortex
rm -rf ~/.cache/vortex