diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-05-01 10:09:39 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-05-01 10:09:39 -0500 |
| commit | af43100e29859adbf5dcb6ee90cd8f981439b859 (patch) | |
| tree | 6d51db8b4f0b77cf4443cb2f49c4e5a7c354d7b6 | |
| parent | 5d1fb2964a172e3444f18ca2ea823ee36784e699 (diff) | |
Remove AppImage build target and runtime references
We ship via portable tarball directory + .bin self-extracting installer
only; the AppImage path was unmaintained and pulling in linuxdeploy
tooling for a format we no longer publish.
Build:
- build.sh: drop appimage/all-includes-appimage modes (now: tarball,
installer, all=both, shell). Output listing tracks the directory.
- docker/Dockerfile: drop BUILD_APPIMAGE arg and the linuxdeploy
download/extract block.
- docker/build-inner.sh: drop build_appimage() (~120 lines), AppImage
arm of the BUILD_MODE switch, *.AppImage summary listing.
- docker/AppRun.sh: deleted.
- .gitignore: drop *.AppImage / squashfs-root / *.flatpak entries.
Runtime: no longer key off APPIMAGE/APPDIR env vars or AppRun-set
state. The fluorine-manager launcher script already exports
FLUORINE_ORIG_*, MO2_BASE_DIR, MO2_PLUGINS_DIR, MO2_LIBS_DIR,
MO2_PYTHON_DIR for the same purpose, so simplify:
- envshortcut: appImageOrBinary -> launcherOrBinary; bundledFluorineIcon
no longer probes APPDIR.
- nxmhandler: drop APPIMAGE-based wrapper path; use applicationFilePath.
- protonlauncher: rename cleanAppImageEnv -> cleanFluorineEnv, drop
APPIMAGE/APPDIR/OWD/ARGV0/APPIMAGE_ORIGINAL_EXEC/DESKTOPINTEGRATION
removals and .mount_Fluori pattern strip.
- prefixsetuprunner: same env-cleaning trim.
- utility, library.h, proxypython, mainwindow, moapplication, appconfig:
comment cleanup pointing at the launcher instead of AppRun.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| -rw-r--r-- | .gitignore | 8 | ||||
| -rwxr-xr-x | build.sh | 20 | ||||
| -rw-r--r-- | docker/AppRun.sh | 131 | ||||
| -rw-r--r-- | docker/Dockerfile | 23 | ||||
| -rwxr-xr-x | docker/build-inner.sh | 133 | ||||
| -rw-r--r-- | libs/archive/src/library.h | 2 | ||||
| -rw-r--r-- | libs/plugin_python/src/proxy/proxypython.cpp | 13 | ||||
| -rw-r--r-- | libs/uibase/src/utility.cpp | 11 | ||||
| -rw-r--r-- | src/src/envshortcut.cpp | 26 | ||||
| -rw-r--r-- | src/src/mainwindow.cpp | 4 | ||||
| -rw-r--r-- | src/src/moapplication.cpp | 2 | ||||
| -rw-r--r-- | src/src/nxmhandler_linux.cpp | 8 | ||||
| -rw-r--r-- | src/src/prefixsetuprunner.cpp | 12 | ||||
| -rw-r--r-- | src/src/protonlauncher.cpp | 37 | ||||
| -rw-r--r-- | src/src/shared/appconfig.h | 12 |
15 files changed, 59 insertions, 383 deletions
@@ -7,9 +7,6 @@ build-container-2404-gcc14/ # Rust build artifacts target/ -# AppImage build artifacts -*.AppImage - # Logs *.log @@ -23,11 +20,8 @@ compile_commands.json .DS_Store Thumbs.db -# AppImage extraction/build leftovers -squashfs-root/ +# Build leftovers build-source/ -flatpak-repo/ -*.flatpak # Python bytecode __pycache__/ @@ -7,8 +7,7 @@ set -euo pipefail # ./build.sh # Build portable .tar.gz (default) # ./build.sh tarball # Build portable .tar.gz only # ./build.sh installer # Build self-extracting .bin installer only -# ./build.sh appimage # Build AppImage (legacy) -# ./build.sh all # Build tarball + AppImage (if available) +# ./build.sh all # Build tarball + installer # ./build.sh shell # Drop into the build container for debugging # # Prerequisites: Docker or Podman @@ -32,27 +31,20 @@ cd "${SCRIPT_DIR}" # Determine build mode from first argument BUILD_MODE="${1:-tarball}" case "${BUILD_MODE}" in - tarball|installer|appimage|all|shell) ;; + tarball|installer|all|shell) ;; *) - echo "Usage: ./build.sh [tarball|installer|appimage|all|shell]" + echo "Usage: ./build.sh [tarball|installer|all|shell]" echo "" echo " tarball Build portable .tar.gz" echo " installer Build self-extracting .bin installer" - echo " appimage Build AppImage (legacy)" - echo " all Build tarball (+ AppImage if available)" + echo " all Build tarball + installer" echo " shell Drop into build container" exit 1 ;; esac -# Build the Docker image if it doesn't exist or Dockerfile changed. -# Pass BUILD_APPIMAGE=1 only when AppImage builds are requested. echo "=== Ensuring build image is up to date ===" -DOCKER_BUILD_ARGS=() -if [ "${BUILD_MODE}" = "appimage" ] || [ "${BUILD_MODE}" = "all" ]; then - DOCKER_BUILD_ARGS+=(--build-arg BUILD_APPIMAGE=1) -fi -${DOCKER} build "${DOCKER_BUILD_ARGS[@]}" -t "${IMAGE_NAME}" docker/ +${DOCKER} build -t "${IMAGE_NAME}" docker/ # Persistent ccache directory for faster rebuilds. CCACHE_DIR="${HOME}/.cache/fluorine-ccache" @@ -92,5 +84,5 @@ ${DOCKER} run --rm \ echo "" echo "=== Done ===" echo "Build outputs:" -ls -lh build/fluorine-manager.tar.gz build/fluorine-manager.bin build/*.AppImage 2>/dev/null || echo " (none found)" +ls -ldh build/fluorine-manager build/fluorine-manager.bin 2>/dev/null || echo " (none found)" echo "Staging: build/staging/" diff --git a/docker/AppRun.sh b/docker/AppRun.sh deleted file mode 100644 index 145ac61..0000000 --- a/docker/AppRun.sh +++ /dev/null @@ -1,131 +0,0 @@ -#!/bin/bash -HERE="$(dirname "$(readlink -f "$0")")" -APPIMAGE_DIR="$(dirname "$(readlink -f "${APPIMAGE:-$0}")")" - -cleanup_stale_fuse_mounts() { - local root="$1" - [ -n "${root}" ] || return 0 - [ -r /proc/mounts ] || return 0 - - local src mp fstype rest mount_path stat_out - while IFS=' ' read -r src mp fstype rest; do - # Decode escaped paths from /proc/mounts. - mount_path="${mp//\\040/ }" - mount_path="${mount_path//\\011/$'\t'}" - mount_path="${mount_path//\\012/$'\n'}" - - case "${mount_path}" in - "${root}"/*) ;; - *) continue ;; - esac - - case "${fstype}" in - fuse*|fuse.*) ;; - *) continue ;; - esac - - stat_out="$(LC_ALL=C stat "${mount_path}" 2>&1 || true)" - if printf "%s" "${stat_out}" | grep -Eq "Transport endpoint is not connected|Stale file handle|Input/output error"; then - echo "[Fluorine] Recovering stale FUSE mount: ${mount_path}" - fusermount3 -uz "${mount_path}" >/dev/null 2>&1 || \ - fusermount -uz "${mount_path}" >/dev/null 2>&1 || \ - umount -l "${mount_path}" >/dev/null 2>&1 || true - fi - done < /proc/mounts -} - -cleanup_stale_fuse_mounts "${APPIMAGE_DIR}" - -sync_dir_overwrite_files() { - local name="$1" - local src="${HERE}/usr/share/fluorine/${name}" - local dst="${APPIMAGE_DIR}/${name}" - - [ -d "${src}" ] || return 0 - - if [ ! -d "${dst}" ]; then - echo "[Fluorine] First run: extracting ${name}/ next to AppImage..." - else - echo "[Fluorine] Updating ${name}/ bundled files..." - fi - mkdir -p "${dst}" - # Merge bundled payload while skipping VCS metadata (.git, etc.). - ( - cd "${src}" - tar --exclude-vcs -cf - . - ) | ( - cd "${dst}" - tar -xf - - ) -} - -# ── Extract/sync writable dirs ── -sync_dir_overwrite_files "plugins" -sync_dir_overwrite_files "lib" -sync_dir_overwrite_files "python" - -# Some existing Windows portable setups include plugins/plugin_python with -# .pyd/.dll payload. On Linux, the proxy will prefer this folder if present, -# which can hide the correct Linux mobase module. Overlay Linux runtime files -# into that folder to keep compatibility without deleting user content. -if [ -d "${APPIMAGE_DIR}/plugins/plugin_python" ]; then - if find "${APPIMAGE_DIR}/plugins/plugin_python" -type f \( -name '*.pyd' -o -name 'python*.dll' \) | grep -q .; then - echo "[Fluorine] Detected Windows plugin_python payload, overlaying Linux runtime files..." - mkdir -p "${APPIMAGE_DIR}/plugins/plugin_python/libs" - [ -d "${APPIMAGE_DIR}/plugins/libs" ] && cp -a "${APPIMAGE_DIR}/plugins/libs/." "${APPIMAGE_DIR}/plugins/plugin_python/libs/" - PYTHON_ROOT_CANDIDATE="${HERE}/usr/share/fluorine/python" - [ -d "${PYTHON_ROOT_CANDIDATE}/lib" ] || PYTHON_ROOT_CANDIDATE="${APPIMAGE_DIR}/python" - if [ -d "${PYTHON_ROOT_CANDIDATE}/lib" ]; then - PYVER_DIR="$(find "${PYTHON_ROOT_CANDIDATE}/lib" -mindepth 1 -maxdepth 1 -type d -name 'python3.*' | head -n 1)" - if [ -n "${PYVER_DIR}" ]; then - SITE_DIR="${PYVER_DIR}/site-packages" - [ -d "${SITE_DIR}/PyQt6" ] && cp -a "${SITE_DIR}/PyQt6" "${APPIMAGE_DIR}/plugins/plugin_python/libs/" - [ -d "${SITE_DIR}/PyQt6_sip" ] && cp -a "${SITE_DIR}/PyQt6_sip" "${APPIMAGE_DIR}/plugins/plugin_python/libs/" - [ -d "${SITE_DIR}/sip" ] && cp -a "${SITE_DIR}/sip" "${APPIMAGE_DIR}/plugins/plugin_python/libs/" - fi - fi - fi -fi - -# ── Environment ── -# Save original LD_LIBRARY_PATH so child processes (xdg-open, kde-open, etc.) -# can use host libraries instead of the bundled (potentially older) ones. -export FLUORINE_ORIG_LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}" -export PATH="${HERE}/usr/bin:${HERE}/usr/libexec:${PATH}" -export LD_LIBRARY_PATH="${HERE}/usr/lib:${HERE}/usr/libexec:${LD_LIBRARY_PATH:-}" - -# Qt plugins (read-only, inside AppImage) -export QT_PLUGIN_PATH="${HERE}/usr/plugins" -export QT_QPA_PLATFORM_PLUGIN_PATH="${HERE}/usr/plugins/platforms" -if [ -x "${HERE}/usr/libexec/QtWebEngineProcess" ]; then - export QTWEBENGINEPROCESS_PATH="${HERE}/usr/libexec/QtWebEngineProcess" -fi -if [ -d "${HERE}/usr/resources" ]; then - export QTWEBENGINE_RESOURCES_PATH="${HERE}/usr/resources" -fi -if [ -d "${HERE}/usr/translations/qtwebengine_locales" ]; then - export QTWEBENGINE_LOCALES_PATH="${HERE}/usr/translations/qtwebengine_locales" -fi - -# Tell the app to use the writable dirs next to the AppImage. -# MO2_BASE_DIR overrides qApp->applicationDirPath() for plugin/library discovery. -export MO2_BASE_DIR="${APPIMAGE_DIR}" -export MO2_PLUGINS_DIR="${APPIMAGE_DIR}/plugins" -export MO2_LIBS_DIR="${APPIMAGE_DIR}/lib" -MO2_PYTHON_BUNDLED="${HERE}/usr/share/fluorine/python" -if [ -d "${MO2_PYTHON_BUNDLED}/lib" ]; then - export MO2_PYTHON_DIR="${MO2_PYTHON_BUNDLED}" -else - export MO2_PYTHON_DIR="${APPIMAGE_DIR}/python" -fi -# Do not export PYTHONHOME/PYTHONPATH globally here. MO2 sets Python runtime -# internally for plugin_python, while child processes (NaK/launchers) must -# use their own system Python environment. -unset PYTHONHOME PYTHONPATH PYTHONNOUSERSITE - -# Raise open file descriptor limit — large modlists with FUSE VFS -# can easily exceed the default 1024 -ulimit -n 65536 2>/dev/null - -cd "${APPIMAGE_DIR}" -exec "${HERE}/usr/bin/ModOrganizer.bin" "$@" diff --git a/docker/Dockerfile b/docker/Dockerfile index 827d45b..643074c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -74,27 +74,4 @@ RUN /opt/python-bundled/bin/pip3 install --no-cache-dir \ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ sh -s -- -y --default-toolchain stable --profile minimal -# ── Pre-download linuxdeploy tooling (optional, only for AppImage builds) ── -# Set BUILD_APPIMAGE=1 to include linuxdeploy in the image. -# Without it, only tarball and installer builds are available. -ARG BUILD_APPIMAGE=0 -RUN if [ "${BUILD_APPIMAGE}" = "1" ]; then \ - mkdir -p /opt/linuxdeploy && \ - curl -L --retry 3 -o /opt/linuxdeploy/linuxdeploy-x86_64.AppImage \ - https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage && \ - curl -L --retry 3 -o /opt/linuxdeploy/linuxdeploy-plugin-qt-x86_64.AppImage \ - https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage && \ - chmod +x /opt/linuxdeploy/linuxdeploy-x86_64.AppImage \ - /opt/linuxdeploy/linuxdeploy-plugin-qt-x86_64.AppImage && \ - cd /opt/linuxdeploy && \ - ./linuxdeploy-plugin-qt-x86_64.AppImage --appimage-extract >/dev/null && \ - mv squashfs-root linuxdeploy-plugin-qt.AppDir && \ - chmod +x linuxdeploy-plugin-qt.AppDir/AppRun && \ - ln -sf /opt/linuxdeploy/linuxdeploy-plugin-qt.AppDir/AppRun \ - /opt/linuxdeploy/linuxdeploy-plugin-qt && \ - chmod -x /opt/linuxdeploy/linuxdeploy-plugin-qt-x86_64.AppImage; \ - else \ - echo "Skipping linuxdeploy (BUILD_APPIMAGE not set)"; \ - fi - WORKDIR /build diff --git a/docker/build-inner.sh b/docker/build-inner.sh index fb5497b..7adab23 100755 --- a/docker/build-inner.sh +++ b/docker/build-inner.sh @@ -523,7 +523,7 @@ cp -f /src/data/icons/com.fluorine.manager.metainfo.xml "${OUT_DIR}/icons/" echo "Wrote manifest: $(wc -l < "${OUT_DIR}/fluorine-manifest.txt") entries" # ── Determine build mode ── -# BUILD_MODE is passed from build.sh: tarball (default), installer, appimage, all +# BUILD_MODE is passed from build.sh: tarball (default), installer, all BUILD_MODE="${BUILD_MODE:-tarball}" # ── Build portable distribution (directory) ── @@ -657,126 +657,6 @@ INSTALLER_HEADER ls -lh "/src/build/${TARBALL_NAME}.bin" } -# ── Build AppImage (legacy, optional) ── -build_appimage() { - echo "" - echo "=== Building AppImage ===" - - if [ ! -d /opt/linuxdeploy ]; then - echo "ERROR: linuxdeploy not available. Rebuild Docker image with --build-arg BUILD_APPIMAGE=1" - return 1 - fi - - APPDIR="/src/build/AppDir" - rm -rf "${APPDIR}" - mkdir -p "${APPDIR}/usr/bin" "${APPDIR}/usr/lib" "${APPDIR}/usr/share/applications" \ - "${APPDIR}/usr/plugins" \ - "${APPDIR}/usr/share/icons/hicolor/256x256/apps" \ - "${APPDIR}/usr/share/metainfo" - - cp -a "${OUT_DIR}"/. "${APPDIR}/usr/bin/" - mv "${APPDIR}/usr/bin/lib"/* "${APPDIR}/usr/lib/" 2>/dev/null || true - rmdir "${APPDIR}/usr/bin/lib" 2>/dev/null || true - if [ -d "${APPDIR}/usr/bin/qt6plugins" ]; then - cp -a "${APPDIR}/usr/bin/qt6plugins"/. "${APPDIR}/usr/plugins/" - fi - - cp -f "${OUT_DIR}/icons/com.fluorine.manager.desktop" "${APPDIR}/usr/share/applications/" - cp -f "${OUT_DIR}/icons/com.fluorine.manager.png" "${APPDIR}/usr/share/icons/hicolor/256x256/apps/" - cp -f "${OUT_DIR}/icons/com.fluorine.manager.metainfo.xml" "${APPDIR}/usr/share/metainfo/" - - mkdir -p "${APPDIR}/usr/share/icons" - for theme_dir in /usr/share/icons/*; do - [ -d "${theme_dir}" ] || continue - cp -a "${theme_dir}" "${APPDIR}/usr/share/icons/" - done - if [ -f "/usr/share/icons/default/index.theme" ]; then - mkdir -p "${APPDIR}/usr/share/icons/default" - cp -f "/usr/share/icons/default/index.theme" "${APPDIR}/usr/share/icons/default/" - fi - - patchelf --force-rpath --set-rpath '$ORIGIN/../lib' "${APPDIR}/usr/bin/ModOrganizer-core" - find "${APPDIR}/usr/bin/plugins" -name "*.so" -exec patchelf --force-rpath --set-rpath '$ORIGIN/../../lib' {} \; 2>/dev/null || true - find "${APPDIR}/usr/lib" -name "*.so" -exec patchelf --force-rpath --set-rpath '$ORIGIN' {} \; 2>/dev/null || true - - cat > "${APPDIR}/AppRun" <<'APPRUN' -#!/usr/bin/env bash -set -euo pipefail -SELF="$(readlink -f "$0")" -HERE="$(cd "$(dirname "$SELF")" && pwd)" -BIN="${HERE}/usr/bin" -APPIMAGE_DIR="$(dirname "$(readlink -f "${APPIMAGE:-$0}")")" - -export FLUORINE_ORIG_LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}" -export FLUORINE_ORIG_LD_PRELOAD="${LD_PRELOAD:-}" -export FLUORINE_ORIG_PATH="${PATH}" -export FLUORINE_ORIG_XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" -export FLUORINE_ORIG_QT_PLUGIN_PATH="${QT_PLUGIN_PATH:-}" - -# Steam injects 32-bit gameoverlayrenderer.so via LD_PRELOAD — clear it. -unset LD_PRELOAD - -# Suppress Qt debug logging by default (see comment in main launcher). -: "${QT_LOGGING_RULES:=default.debug=false}" -export QT_LOGGING_RULES - -export PATH="${BIN}:${PATH}" -# Replace (not append) LD_LIBRARY_PATH — Steam game mode injects its runtime -# libs which break Python/Qt. RPATH handles the binary's own deps. -export LD_LIBRARY_PATH="${HERE}/usr/lib" - -export MO2_BASE_DIR="${APPIMAGE_DIR}" -export MO2_PLUGINS_DIR="${BIN}/plugins" -export MO2_LIBS_DIR="${BIN}/lib" - -unset PYTHONPATH PYTHONNOUSERSITE PYTHONHOME MO2_PYTHON_DIR - -export QT_PLUGIN_PATH="${HERE}/usr/plugins" -export QT_QPA_PLATFORM_PLUGIN_PATH="${HERE}/usr/plugins/platforms" -export XDG_DATA_DIRS="${HERE}/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" -export QT_ICON_THEME_NAME="${QT_ICON_THEME_NAME:-breeze}" -export QT_STYLE_OVERRIDE="${QT_STYLE_OVERRIDE:-Breeze}" -export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-KDE}" - -# Raise open file descriptor limit — large modlists with FUSE VFS -# can easily exceed the default 1024 -ulimit -n 65536 2>/dev/null - -cd "${APPIMAGE_DIR}" -exec "${BIN}/ModOrganizer-core" "$@" -APPRUN - chmod +x "${APPDIR}/AppRun" - - ln -sf usr/share/applications/com.fluorine.manager.desktop "${APPDIR}/com.fluorine.manager.desktop" - ln -sf usr/share/icons/hicolor/256x256/apps/com.fluorine.manager.png "${APPDIR}/com.fluorine.manager.png" - ln -sf usr/share/icons/hicolor/256x256/apps/com.fluorine.manager.png "${APPDIR}/.DirIcon" - - DEPLOY_DIR="/tmp/linuxdeploy-extract" - if [ ! -d "${DEPLOY_DIR}" ]; then - cd /opt/linuxdeploy - ./linuxdeploy-x86_64.AppImage --appimage-extract >/dev/null - mv squashfs-root "${DEPLOY_DIR}" - chmod +x "${DEPLOY_DIR}/AppRun" - fi - - export ARCH=x86_64 - "${DEPLOY_DIR}/AppRun" \ - --appdir "${APPDIR}" \ - --output appimage \ - --desktop-file "${APPDIR}/usr/share/applications/com.fluorine.manager.desktop" \ - --icon-file "${APPDIR}/usr/share/icons/hicolor/256x256/apps/com.fluorine.manager.png" \ - 2>&1 || { - echo "WARNING: linuxdeploy AppImage generation failed" - } - - APPIMAGE_FILE=$(ls -1 Fluorine*.AppImage 2>/dev/null || ls -1 *.AppImage 2>/dev/null || true) - if [ -n "${APPIMAGE_FILE}" ]; then - mv "${APPIMAGE_FILE}" "/src/build/" - echo "AppImage: /src/build/${APPIMAGE_FILE}" - ls -lh "/src/build/"*.AppImage - fi -} - # ── Execute requested build mode ── case "${BUILD_MODE}" in tarball) @@ -785,17 +665,12 @@ case "${BUILD_MODE}" in installer) build_installer ;; - appimage) - build_appimage - ;; all) build_tarball - if [ -d /opt/linuxdeploy ]; then - build_appimage - fi + build_installer ;; *) - echo "ERROR: Unknown BUILD_MODE '${BUILD_MODE}'. Use: tarball, installer, appimage, all" + echo "ERROR: Unknown BUILD_MODE '${BUILD_MODE}'. Use: tarball, installer, all" exit 1 ;; esac @@ -805,4 +680,4 @@ echo "=== Build Summary ===" du -sh "${OUT_DIR}"/*/ "${OUT_DIR}"/ModOrganizer-core 2>/dev/null | sort -rh echo "" echo "Build outputs:" -ls -dh /src/build/fluorine-manager/ /src/build/fluorine-manager.bin /src/build/*.AppImage 2>/dev/null || echo " (none found)" +ls -dh /src/build/fluorine-manager/ /src/build/fluorine-manager.bin 2>/dev/null || echo " (none found)" diff --git a/libs/archive/src/library.h b/libs/archive/src/library.h index a0656f2..e182f08 100644 --- a/libs/archive/src/library.h +++ b/libs/archive/src/library.h @@ -94,7 +94,7 @@ private: exeDir = exeDir.substr(0, slash); } - // AppImage: check MO2_LIBS_DIR env var first (writable dir next to AppImage) + // Honor MO2_LIBS_DIR (set by the fluorine-manager launcher) first. std::string envLibs; const char* envVal = std::getenv("MO2_LIBS_DIR"); if (envVal && envVal[0] != '\0') { diff --git a/libs/plugin_python/src/proxy/proxypython.cpp b/libs/plugin_python/src/proxy/proxypython.cpp index 6e4acad..56d9dae 100644 --- a/libs/plugin_python/src/proxy/proxypython.cpp +++ b/libs/plugin_python/src/proxy/proxypython.cpp @@ -167,9 +167,10 @@ bool ProxyPython::init(IOrganizer* moInfo) std::filesystem::path{IOrganizer::getPluginDataPath().toStdWString()}}; m_Runner->initialize(paths); #else - // On Linux, rely on the unpacked stdlib from PYTHONHOME (AppRun sets - // MO2_PYTHON_DIR/PYTHONHOME). Do not prepend pythoncore.zip here: - // forcing zipimport can fail when zlib is unavailable in embedded mode. + // On Linux, rely on the unpacked stdlib from PYTHONHOME (the + // fluorine-manager launcher sets MO2_PYTHON_DIR/PYTHONHOME). Do not + // prepend pythoncore.zip here: forcing zipimport can fail when zlib + // is unavailable in embedded mode. std::vector<fs::path> paths{ libpath, std::filesystem::path{IOrganizer::getPluginDataPath().toStdWString()}}; @@ -184,9 +185,9 @@ bool ProxyPython::init(IOrganizer* moInfo) } } - // Allow portable/AppImage builds to ship Python packages next to the app. - // MO2_PYTHON_DIR (set by AppRun) points to the writable python/ dir - // next to the AppImage; fall back to <exe_dir>/python. + // Allow portable builds to ship Python packages next to the app. + // MO2_PYTHON_DIR (set by the fluorine-manager launcher) points to the + // writable python/ dir; fall back to <exe_dir>/python. fs::path pythonDir; const char* envPy = std::getenv("MO2_PYTHON_DIR"); if (envPy && envPy[0] != '\0') { diff --git a/libs/uibase/src/utility.cpp b/libs/uibase/src/utility.cpp index 40774ae..4304561 100644 --- a/libs/uibase/src/utility.cpp +++ b/libs/uibase/src/utility.cpp @@ -396,16 +396,16 @@ namespace shell } } - // Launch an external host process with AppImage environment variables - // cleaned up, so tools like xdg-open/kde-open use the host's own - // libraries and Qt plugins instead of the bundled ones. + // Launch an external host process with bundled-runtime environment + // variables cleaned up, so tools like xdg-open/kde-open use the host's + // own libraries and Qt plugins instead of the ones we ship. static bool startDetachedHostProcess(const QString& program, const QStringList& args) { QProcess proc; auto env = QProcessEnvironment::systemEnvironment(); - // Restore original LD_LIBRARY_PATH (saved by AppRun.sh) + // Restore original LD_LIBRARY_PATH (saved by the fluorine-manager launcher). if (env.contains(QStringLiteral("FLUORINE_ORIG_LD_LIBRARY_PATH"))) { const auto orig = env.value(QStringLiteral("FLUORINE_ORIG_LD_LIBRARY_PATH")); if (orig.isEmpty()) @@ -414,7 +414,8 @@ namespace shell env.insert(QStringLiteral("LD_LIBRARY_PATH"), orig); } - // Remove AppImage-specific Qt/path variables that would confuse host apps + // Remove Qt/path variables pointing at our bundled runtime that would + // confuse host apps. env.remove(QStringLiteral("QT_PLUGIN_PATH")); env.remove(QStringLiteral("QT_QPA_PLATFORM_PLUGIN_PATH")); env.remove(QStringLiteral("QTWEBENGINEPROCESS_PATH")); diff --git a/src/src/envshortcut.cpp b/src/src/envshortcut.cpp index 60cd33a..60786d2 100644 --- a/src/src/envshortcut.cpp +++ b/src/src/envshortcut.cpp @@ -17,17 +17,11 @@ namespace env { -// Returns the path to the AppImage file itself, or falls back to the -// running binary if not running from an AppImage. -static QString appImageOrBinary() +// Prefer the fluorine-manager launcher script over the bare ModOrganizer-core +// binary — the launcher sets up bundled library paths, Qt plugin paths, etc. +// Without it, shortcuts fail on systems that don't have all deps in PATH. +static QString launcherOrBinary() { - QString appImage = QProcessEnvironment::systemEnvironment().value("APPIMAGE"); - if (!appImage.isEmpty() && QFile::exists(appImage)) { - return appImage; - } - // Prefer the fluorine-manager launcher script over the bare ModOrganizer-core - // binary — the launcher sets up bundled library paths, Qt plugin paths, etc. - // Without it, shortcuts fail on systems that don't have all deps in PATH. const QString appDir = QCoreApplication::applicationDirPath(); const QString launcher = appDir + "/fluorine-manager"; if (QFile::exists(launcher)) { @@ -281,16 +275,10 @@ static QImage extractIconFromExe(const QString& exePath) return img; } -// Return the path to the bundled Fluorine icon inside the AppImage, -// or the installed hicolor copy. Empty string if neither exists. +// Return the path to the installed hicolor copy of the Fluorine icon. +// Empty string if not present. static QString bundledFluorineIcon() { - QString const appDir = QProcessEnvironment::systemEnvironment().value("APPDIR"); - if (!appDir.isEmpty()) { - QString bundled = appDir + "/usr/share/icons/hicolor/256x256/apps/com.fluorine.manager.png"; - if (QFile::exists(bundled)) - return bundled; - } QString hicolor = QDir::homePath() + "/.local/share/icons/hicolor/256x256/apps/com.fluorine.manager.png"; if (QFile::exists(hicolor)) @@ -362,7 +350,7 @@ Shortcut::Shortcut(const Executable& exe) : Shortcut() m_name = exe.title(); m_instanceName = i.displayName(); - m_target = appImageOrBinary(); + m_target = launcherOrBinary(); // For portable instances, use the absolute directory path so MO2 can // find it (line 595 in instancemanager.cpp handles abs path lookup). diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index ee32208..a928c6d 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -636,8 +636,8 @@ void MainWindow::resetActionIcons() void MainWindow::resetButtonIcons() { - // Some icon-only QPushButtons can lose their icons after stylesheet repolish on - // Linux/AppImage. Re-apply explicit resource icons to keep these controls visible. + // Some icon-only QPushButtons can lose their icons after stylesheet repolish + // on Linux. Re-apply explicit resource icons to keep these controls visible. ui->listOptionsBtn->setIcon(QIcon::fromTheme( "preferences-system", QIcon(":/MO/gui/settings"))); ui->openFolderMenu->setIcon( diff --git a/src/src/moapplication.cpp b/src/src/moapplication.cpp index 0c50509..aac387f 100644 --- a/src/src/moapplication.cpp +++ b/src/src/moapplication.cpp @@ -190,7 +190,7 @@ MOApplication::MOApplication(int& argc, char** argv) : QApplication(argc, argv) TimeThis const tt("MOApplication()"); // Ensure the app name is always "ModOrganizer" regardless of the binary - // filename (e.g. "ModOrganizer.bin" inside an AppImage). + // filename (settings/profile lookups key off this). setApplicationName("ModOrganizer"); setDesktopFileName(QStringLiteral("com.fluorine.manager")); setWindowIcon(QIcon(":/MO/gui/app_icon")); diff --git a/src/src/nxmhandler_linux.cpp b/src/src/nxmhandler_linux.cpp index 3c9ef2a..c7db527 100644 --- a/src/src/nxmhandler_linux.cpp +++ b/src/src/nxmhandler_linux.cpp @@ -198,13 +198,7 @@ void NxmHandlerLinux::registerHandler() const QString wrapperPath = localBin + "/mo2-nxm-handler"; // Determine a stable executable path for the wrapper script. - // QCoreApplication::applicationFilePath() returns the temp FUSE mount for - // AppImages (/tmp/.mount_XXXXX/...) which changes every launch. Use the - // APPIMAGE env var (the actual .AppImage file) when available. - QString executable = qEnvironmentVariable("APPIMAGE"); - if (executable.isEmpty()) { - executable = QCoreApplication::applicationFilePath(); - } + const QString executable = QCoreApplication::applicationFilePath(); const QString wrapper = QString("#!/bin/sh\nexec \"%1\" nxm-handle \"$@\"\n").arg(executable); diff --git a/src/src/prefixsetuprunner.cpp b/src/src/prefixsetuprunner.cpp index cd2fcf4..a3f782f 100644 --- a/src/src/prefixsetuprunner.cpp +++ b/src/src/prefixsetuprunner.cpp @@ -564,18 +564,16 @@ QProcess* PrefixSetupRunner::buildWrappedProcess( { auto* proc = new QProcess(this); - // Start from the system environment and clean AppImage vars. + // Start from the system environment and clean Fluorine bundling vars. QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - // Remove AppImage/Fluorine vars that can confuse Wine. + // Remove Fluorine vars that can confuse Wine. for (const char* var : {"QT_QPA_PLATFORM_PLUGIN_PATH", "MO2_PLUGINS_DIR", - "MO2_LIBS_DIR", "MO2_PYTHON_DIR", "MO2_BASE_DIR", - "APPIMAGE", "APPDIR", "OWD", "ARGV0", - "APPIMAGE_ORIGINAL_EXEC", "DESKTOPINTEGRATION"}) { + "MO2_LIBS_DIR", "MO2_PYTHON_DIR", "MO2_BASE_DIR"}) { env.remove(var); } - // Restore pre-AppImage environment if available. + // Restore pre-launcher environment if available. auto restoreOrStrip = [&env](const QString& var, const QString& origVar) { if (env.contains(origVar)) { const QString orig = env.value(origVar); @@ -719,7 +717,7 @@ int PrefixSetupRunner::runHostProcess(const QString& exe, proc.setArguments(args); proc.setProcessChannelMode(QProcess::MergedChannels); - // Clean AppImage/Fluorine env so host tools find their system libraries. + // Clean Fluorine env so host tools find their system libraries. QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); auto restoreOrStrip = [&env](const QString& var, const QString& origVar) { if (env.contains(origVar)) { diff --git a/src/src/protonlauncher.cpp b/src/src/protonlauncher.cpp index 9c6bba8..d8b1289 100644 --- a/src/src/protonlauncher.cpp +++ b/src/src/protonlauncher.cpp @@ -14,32 +14,22 @@ namespace { -// Restore the pre-AppImage environment for child processes (Proton, Wine). -// The AppRun script saves FLUORINE_ORIG_* vars before -// modifying PATH, LD_LIBRARY_PATH, etc. We restore from those saved values -// so game processes get a clean host environment without AppImage library paths. -void cleanAppImageEnv(QProcessEnvironment& env) +// Restore the pre-launcher environment for child processes (Proton, Wine). +// The fluorine-manager launcher script saves FLUORINE_ORIG_* before +// modifying PATH, LD_LIBRARY_PATH, etc., so game processes get a clean +// host environment without the bundled-library paths leaking through. +void cleanFluorineEnv(QProcessEnvironment& env) { - // Remove Fluorine/AppImage-specific vars that should never leak to game processes. + // Remove Fluorine-specific vars that should never leak to game processes. env.remove("QT_QPA_PLATFORM_PLUGIN_PATH"); env.remove("MO2_PLUGINS_DIR"); env.remove("MO2_LIBS_DIR"); env.remove("MO2_PYTHON_DIR"); env.remove("MO2_BASE_DIR"); - // AppImage runtime injects these — they can confuse Proton/Wine. - env.remove("APPIMAGE"); - env.remove("APPDIR"); - env.remove("OWD"); - env.remove("ARGV0"); - env.remove("APPIMAGE_ORIGINAL_EXEC"); - - env.remove("DESKTOPINTEGRATION"); - - // Restore saved pre-AppImage values. AppRun sets FLUORINE_ORIG_* before - // modifying PATH, LD_LIBRARY_PATH, etc. If those vars exist, use them to - // restore the original host environment. If not (standalone/non-AppImage), - // fall back to stripping known AppImage patterns. + // Restore saved pre-launcher values from FLUORINE_ORIG_*. If those + // vars are missing (e.g. someone invoked ModOrganizer-core directly), + // fall back to stripping bundled-runtime paths by pattern. auto restoreOrStrip = [](const QString& var, const QString& origVar, QProcessEnvironment& e) { if (e.contains(origVar)) { @@ -51,12 +41,11 @@ void cleanAppImageEnv(QProcessEnvironment& env) } e.remove(origVar); } else { - // Fallback: strip AppImage mount paths by pattern. const QString value = e.value(var); if (value.isEmpty()) return; QStringList kept; for (const QString& p : value.split(':')) { - if (p.contains(".mount_Fluori") || p.contains("/fluorine/python")) { + if (p.contains("/fluorine/python")) { continue; } kept.append(p); @@ -76,7 +65,7 @@ void cleanAppImageEnv(QProcessEnvironment& env) restoreOrStrip("XDG_DATA_DIRS", "FLUORINE_ORIG_XDG_DATA_DIRS", env); restoreOrStrip("QT_PLUGIN_PATH", "FLUORINE_ORIG_QT_PLUGIN_PATH", env); - MOBase::log::debug("cleanAppImageEnv: {} (LD_LIBRARY_PATH='{}')", + MOBase::log::debug("cleanFluorineEnv: {} (LD_LIBRARY_PATH='{}')", hasOrigVars ? "restored from FLUORINE_ORIG_*" : "pattern-strip fallback", env.value("LD_LIBRARY_PATH", "<unset>")); } @@ -577,7 +566,7 @@ bool ProtonLauncher::launchWithProton(qint64& pid) const QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.remove("PYTHONHOME"); - cleanAppImageEnv(env); + cleanFluorineEnv(env); // Prepend fluorine's bin dir to PATH so the container sees our injected // xrandr (steamrt4 ships without it; Proton-GE protonfixes require it). @@ -819,7 +808,7 @@ bool ProtonLauncher::launchDirect(qint64& pid) const QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.remove("PYTHONHOME"); - cleanAppImageEnv(env); + cleanFluorineEnv(env); for (auto it = m_wrapperEnvVars.cbegin(); it != m_wrapperEnvVars.cend(); ++it) { env.insert(it.key(), it.value()); } diff --git a/src/src/shared/appconfig.h b/src/src/shared/appconfig.h index efbc169..e7e94b1 100644 --- a/src/src/shared/appconfig.h +++ b/src/src/shared/appconfig.h @@ -31,15 +31,13 @@ namespace AppConfig #define APPPARAM(partype, parid, value) partype parid(); #include "appconfig.inc" -// Returns the application base directory. On Linux, if the MO2_BASE_DIR -// environment variable is set (e.g. by an AppImage wrapper) that value is -// returned; otherwise falls back to QCoreApplication::applicationDirPath(). +// Returns the application base directory. Respects MO2_BASE_DIR if set +// (the fluorine-manager launcher exports it), otherwise falls back to +// QCoreApplication::applicationDirPath(). QString basePath(); -// Returns the directory containing MO2 plugins. On Linux, if the -// MO2_PLUGINS_DIR environment variable is set (e.g. when plugins live -// inside a read-only AppImage squashfs) that value is used; otherwise -// falls back to basePath() + "/plugins". +// Returns the directory containing MO2 plugins. Respects MO2_PLUGINS_DIR +// if set, otherwise falls back to basePath() + "/plugins". QString pluginsPath(); // Returns the directory containing bundled Linux libraries (7z.so, etc.). |
