diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml
new file mode 100644
index 00000000..bd6e8474
--- /dev/null
+++ b/.github/workflows/appimage.yml
@@ -0,0 +1,128 @@
+name: Build AppImage
+
+on:
+ # Triggers the workflow on push or pull request events but only for the main branch
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+env:
+ BUILD_TYPE: RelWithDebInfo
+
+jobs:
+ build-appimage:
+ runs-on: ubuntu-22.04
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Update Package Database
+ run: sudo apt-get update
+
+ - name: Install Dependencies
+ run: sudo apt-get install libgtkmm-3.0-dev gettext wget file libfuse2
+
+ - name: Download linuxdeploy
+ # Note: Using 'continuous' release for latest version. For reproducible builds,
+ # pin to a specific release tag and verify SHA256 checksum.
+ run: |
+ wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
+ chmod +x linuxdeploy-x86_64.AppImage
+ sudo mv linuxdeploy-x86_64.AppImage /usr/local/bin/linuxdeploy
+
+ - name: Download appimagetool
+ # Note: Using 'continuous' release for latest version. For reproducible builds,
+ # pin to a specific release tag and verify SHA256 checksum.
+ run: |
+ wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
+ chmod +x appimagetool-x86_64.AppImage
+ sudo mv appimagetool-x86_64.AppImage /usr/local/bin/appimagetool
+
+ - name: Create Build Directory
+ run: cmake -E make_directory build-appimage
+
+ - name: Configure CMake for AppImage
+ shell: bash
+ working-directory: ${{github.workspace}}/build-appimage
+ env:
+ CC: gcc-11
+ CXX: g++-11
+ run: >
+ cmake $GITHUB_WORKSPACE
+ -DCMAKE_BUILD_TYPE=$BUILD_TYPE
+ -DCMAKE_INSTALL_PREFIX=/usr
+ -DAPP_BUILD_APPIMAGE=ON
+ -DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/linux-dev.cmake"
+
+ - name: Build
+ shell: bash
+ working-directory: ${{github.workspace}}/build-appimage
+ run: cmake --build . --config $BUILD_TYPE -j$(nproc)
+
+ - name: Install to AppDir
+ shell: bash
+ working-directory: ${{github.workspace}}/build-appimage
+ run: DESTDIR=${{github.workspace}}/AppDir cmake --install .
+
+ - name: Setup AppDir structure
+ shell: bash
+ working-directory: ${{github.workspace}}
+ run: |
+ # Copy desktop file and icon to AppDir root
+ cp AppDir/usr/share/applications/dev.shaduri.gsmartcontrol.desktop AppDir/
+ cp AppDir/usr/share/icons/hicolor/256x256/apps/gsmartcontrol.png AppDir/
+
+ # Create AppRun script
+ cat > AppDir/AppRun << 'EOF'
+ #!/bin/bash
+ SELF=$(readlink -f "$0")
+ HERE=${SELF%/*}
+ export LD_LIBRARY_PATH="$HERE/usr/lib:${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
+ export PATH="$HERE/usr/bin:${PATH:+:$PATH}"
+ export GSETTINGS_SCHEMA_DIR="$HERE/usr/share/glib-2.0/schemas:${GSETTINGS_SCHEMA_DIR:+:$GSETTINGS_SCHEMA_DIR}"
+ export GDK_PIXBUF_MODULEDIR="$HERE/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders"
+ export GDK_PIXBUF_MODULE_FILE="$HERE/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
+ exec "$HERE/usr/bin/gsmartcontrol" "$@"
+ EOF
+ chmod +x AppDir/AppRun
+
+ - name: Bundle dependencies with linuxdeploy
+ shell: bash
+ working-directory: ${{github.workspace}}
+ run: |
+ linuxdeploy --appdir AppDir \
+ --executable AppDir/usr/bin/gsmartcontrol \
+ --desktop-file AppDir/dev.shaduri.gsmartcontrol.desktop \
+ --icon-file AppDir/gsmartcontrol.png
+
+ - name: Update GDK pixbuf cache
+ shell: bash
+ working-directory: ${{github.workspace}}
+ continue-on-error: true
+ run: |
+ if [ -d "AppDir/usr/lib/gdk-pixbuf-2.0" ]; then
+ gdk-pixbuf-query-loaders > AppDir/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache || true
+ fi
+
+ - name: Get version
+ id: version
+ shell: bash
+ run: |
+ VERSION=$(sed -n 's/.*CMAKE_PROJECT_VERSION[[:space:]]*"\([^"]*\)".*/\1/p' version.txt)
+ echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
+ echo "Version: $VERSION"
+
+ - name: Create AppImage
+ shell: bash
+ working-directory: ${{github.workspace}}
+ run: |
+ ARCH=x86_64 appimagetool AppDir GSmartControl-${{ steps.version.outputs.VERSION }}-x86_64.AppImage
+
+ - name: Upload AppImage artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: GSmartControl AppImage
+ path: ${{github.workspace}}/GSmartControl-*-x86_64.AppImage
diff --git a/.obs/workflows.yml b/.obs/workflows.yml
index 6a6b1a37..ef8338b9 100644
--- a/.obs/workflows.yml
+++ b/.obs/workflows.yml
@@ -175,6 +175,16 @@ build_main_workflow:
- x86_64
- i586
+ # AppImage build (using Ubuntu 22.04 as base)
+ - name: AppImage
+ paths:
+ - target_project: openSUSE:Tools
+ target_repository: xUbuntu_22.04
+ - target_project: Ubuntu:22.04
+ target_repository: universe
+ architectures:
+ - x86_64
+
- set_flags:
flags:
- type: publish
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7ba065c8..1d768622 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,6 +39,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
# User-controlled build options
option(APP_BUILD_EXAMPLES "Build examples" OFF)
option(APP_BUILD_TESTS "Build tests" OFF)
+option(APP_BUILD_APPIMAGE "Build for AppImage (portable data file paths)" OFF)
# Install documentation
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
index 53a99cf8..5596b5d7 100644
--- a/data/CMakeLists.txt
+++ b/data/CMakeLists.txt
@@ -6,8 +6,17 @@
# Generate files
-configure_file("gsmartcontrol.appdata.in.xml" "gsmartcontrol.appdata.xml" ESCAPE_QUOTES @ONLY)
-configure_file("gsmartcontrol.in.desktop" "gsmartcontrol.desktop" ESCAPE_QUOTES @ONLY)
+if (APP_BUILD_APPIMAGE)
+ set(APPIMAGE_DESKTOP_ID "dev.shaduri.gsmartcontrol")
+ set(APPIMAGE_EXEC_LINE "Exec=\"${CMAKE_INSTALL_FULL_BINDIR}/gsmartcontrol\"")
+ configure_file("gsmartcontrol.appdata.in.xml" "gsmartcontrol.appdata.xml" ESCAPE_QUOTES @ONLY)
+ configure_file("gsmartcontrol.in.desktop" "dev.shaduri.gsmartcontrol.desktop" ESCAPE_QUOTES @ONLY)
+else()
+ set(APPIMAGE_DESKTOP_ID "gsmartcontrol")
+ set(APPIMAGE_EXEC_LINE "Exec=\"${CMAKE_INSTALL_FULL_BINDIR}/gsmartcontrol-root\"")
+ configure_file("gsmartcontrol.appdata.in.xml" "gsmartcontrol.appdata.xml" ESCAPE_QUOTES @ONLY)
+ configure_file("gsmartcontrol.in.desktop" "gsmartcontrol.desktop" ESCAPE_QUOTES @ONLY)
+endif()
configure_file("gsmartcontrol-root.in.sh" "gsmartcontrol-root.sh" ESCAPE_QUOTES @ONLY)
configure_file("org.gsmartcontrol.in.policy" "org.gsmartcontrol.policy" ESCAPE_QUOTES @ONLY)
@@ -42,8 +51,13 @@ endif()
# Desktop file
if (NOT WIN32)
- install(FILES "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol.desktop"
- DESTINATION "${CMAKE_INSTALL_DATADIR}/applications/")
+ if (APP_BUILD_APPIMAGE)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/dev.shaduri.gsmartcontrol.desktop"
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/applications/")
+ else()
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol.desktop"
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/applications/")
+ endif()
# Appdata file
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol.appdata.xml"
@@ -55,9 +69,13 @@ if (NOT WIN32)
# Man pages
install(FILES "man1/gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
- install(FILES "man1/gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" RENAME "gsmartcontrol-root.1")
+ if (NOT APP_BUILD_APPIMAGE)
+ install(FILES "man1/gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" RENAME "gsmartcontrol-root.1")
+ endif()
# Scripts (this goes to bin, not sbin, as it doesn't require root privileges before running)
- install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol-root.sh" TYPE BIN RENAME "gsmartcontrol-root")
+ if (NOT APP_BUILD_APPIMAGE)
+ install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol-root.sh" TYPE BIN RENAME "gsmartcontrol-root")
+ endif()
endif()
diff --git a/data/gsmartcontrol.appdata.in.xml b/data/gsmartcontrol.appdata.in.xml
index 48663444..c411ab13 100644
--- a/data/gsmartcontrol.appdata.in.xml
+++ b/data/gsmartcontrol.appdata.in.xml
@@ -1,6 +1,6 @@
- gsmartcontrol
+ dev.shaduri.gsmartcontrol
CC0-1.0
GPL-3.0
GSmartControl
@@ -14,7 +14,7 @@
on it.
- gsmartcontrol.desktop
+ @APPIMAGE_DESKTOP_ID@.desktop
https://gsmartcontrol.shaduri.dev
diff --git a/data/gsmartcontrol.in.desktop b/data/gsmartcontrol.in.desktop
index 30545362..e5908218 100644
--- a/data/gsmartcontrol.in.desktop
+++ b/data/gsmartcontrol.in.desktop
@@ -63,4 +63,5 @@ Icon=gsmartcontrol
#X-KDE-RootOnly=true
# Run with root permissions.
-Exec="@CMAKE_INSTALL_FULL_BINDIR@/gsmartcontrol-root"
+# For AppImage builds, execute the binary directly (AppImage does not support embedded sudo scripts)
+@APPIMAGE_EXEC_LINE@
diff --git a/packaging/appimage/README.md b/packaging/appimage/README.md
new file mode 100644
index 00000000..68f02f20
--- /dev/null
+++ b/packaging/appimage/README.md
@@ -0,0 +1,106 @@
+# GSmartControl AppImage Build
+
+This directory contains scripts and configurations for building GSmartControl as an AppImage.
+
+## What is AppImage?
+
+AppImage is a format for distributing portable software on Linux without requiring installation. AppImages are self-contained applications that can run on most Linux distributions.
+
+## Building the AppImage
+
+### Prerequisites
+
+You need to have the following installed:
+- cmake (>= 3.14)
+- g++ or clang with C++20 support
+- GTK3 and gtkmm-3.0 development packages
+- smartmontools (for runtime)
+- linuxdeploy and appimagetool (the script will download them if not available)
+
+On Ubuntu/Debian:
+```bash
+sudo apt-get install cmake g++ libgtkmm-3.0-dev gettext smartmontools
+```
+
+On Fedora:
+```bash
+sudo dnf install cmake gcc-c++ gtkmm30-devel gettext smartmontools
+```
+
+### Build Steps
+
+From the repository root directory, run:
+
+```bash
+./packaging/appimage/build-appimage.sh
+```
+
+The script will:
+1. Configure CMake with `-DAPP_BUILD_APPIMAGE=ON`
+2. Build the application
+3. Create an AppDir with the proper structure
+4. Bundle dependencies using linuxdeploy
+5. Create the final AppImage file
+
+### Output
+
+The script creates an AppImage file named `GSmartControl--.AppImage` in the repository root.
+
+## Running the AppImage
+
+**Important:** GSmartControl requires root privileges to access disk drives. You must run the AppImage with sudo:
+
+```bash
+sudo ./GSmartControl--x86_64.AppImage
+```
+
+### Why sudo is required?
+
+- AppImage format does not support embedded privilege escalation scripts
+- The binary must be executed directly as root to access `/dev/sd*` and `/dev/nvme*` devices
+- This is different from traditional package installations which use the `gsmartcontrol-root` wrapper script
+
+## AppImage-Specific Changes
+
+When building with `-DAPP_BUILD_APPIMAGE=ON`, the following changes are applied:
+
+1. **Data file paths**: Uses relative paths from binary location (`bin/../share/...`)
+2. **Desktop file**:
+ - Uses rDNS format: `dev.shaduri.gsmartcontrol.desktop`
+ - Executes binary directly without `gsmartcontrol-root` wrapper
+3. **Binary location**: Installed to `bin/` instead of `sbin/`
+4. **No wrapper script**: `gsmartcontrol-root` is not installed
+
+## Compatibility
+
+The AppImage should work on:
+- Fedora Atomic (Silverblue, Kinoite, etc.)
+- Most modern Linux distributions with GTK3 support
+- Systems with read-only root filesystems
+
+Tested architectures:
+- x86_64 (Intel/AMD 64-bit)
+
+## Troubleshooting
+
+### "Permission denied" when running AppImage
+Make the AppImage executable:
+```bash
+chmod +x GSmartControl-*.AppImage
+```
+
+### "No drives detected"
+Make sure to run with sudo:
+```bash
+sudo ./GSmartControl-*.AppImage
+```
+
+### GTK theme issues
+You may need to install GTK3 themes on your system. The AppImage bundles the necessary libraries but uses system themes when available.
+
+## Notes for Developers
+
+- The AppImage build uses the same source code as regular builds
+- The `BuildEnv::is_appimage_build()` function can be used to detect AppImage builds at runtime
+- Icon and UI file paths are resolved at runtime relative to the binary location
+- The AppImage includes all necessary GTK3 and gtkmm libraries
diff --git a/packaging/appimage/build-appimage.sh b/packaging/appimage/build-appimage.sh
new file mode 100755
index 00000000..3593479d
--- /dev/null
+++ b/packaging/appimage/build-appimage.sh
@@ -0,0 +1,147 @@
+#!/bin/bash
+###############################################################################
+# License: BSD Zero Clause License file
+# Copyright:
+# (C) 2025 Alexander Shaduri
+###############################################################################
+
+# Script to build GSmartControl AppImage
+# This script should be run from the repository root directory
+#
+# Requirements:
+# - cmake, wget, file
+# - libgtkmm-3.0-dev (or equivalent GTK3 development packages)
+# - libfuse2 (required to run linuxdeploy and appimagetool AppImages)
+# On Ubuntu/Debian: sudo apt-get install libfuse2
+# On Ubuntu 24.04+: sudo apt-get install libfuse2t64
+
+set -e # Exit on error
+set -u # Exit on undefined variable
+
+# Configuration
+APPDIR="${APPDIR:-AppDir}"
+BUILD_DIR="${BUILD_DIR:-build-appimage}"
+ARCH="${ARCH:-x86_64}"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+echo -e "${GREEN}Building GSmartControl AppImage${NC}"
+echo "Architecture: $ARCH"
+echo "Build directory: $BUILD_DIR"
+echo "AppDir: $APPDIR"
+echo
+
+# Check dependencies
+if ! command -v cmake &> /dev/null; then
+ echo -e "${RED}Error: cmake not found. Please install cmake.${NC}"
+ exit 1
+fi
+
+if ! command -v linuxdeploy &> /dev/null; then
+ echo -e "${YELLOW}Warning: linuxdeploy not found. Will attempt to download it.${NC}"
+ # Note: Using 'continuous' release for latest version. For reproducible builds,
+ # pin to a specific release tag and verify SHA256 checksum.
+ LINUXDEPLOY_URL="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${ARCH}.AppImage"
+ wget -N "$LINUXDEPLOY_URL" -O linuxdeploy
+ chmod +x linuxdeploy
+ LINUXDEPLOY="./linuxdeploy"
+else
+ LINUXDEPLOY="linuxdeploy"
+fi
+
+if ! command -v appimagetool &> /dev/null; then
+ echo -e "${YELLOW}Warning: appimagetool not found. Will attempt to download it.${NC}"
+ # Note: Using 'continuous' release for latest version. For reproducible builds,
+ # pin to a specific release tag and verify SHA256 checksum.
+ APPIMAGETOOL_URL="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${ARCH}.AppImage"
+ wget -N "$APPIMAGETOOL_URL" -O appimagetool
+ chmod +x appimagetool
+ APPIMAGETOOL="./appimagetool"
+else
+ APPIMAGETOOL="appimagetool"
+fi
+
+# Clean previous build
+echo -e "${GREEN}Cleaning previous build...${NC}"
+rm -rf "$BUILD_DIR"
+rm -rf "$APPDIR"
+
+# Create build directory
+mkdir -p "$BUILD_DIR"
+cd "$BUILD_DIR"
+
+# Configure with CMake for AppImage build
+echo -e "${GREEN}Configuring CMake for AppImage build...${NC}"
+cmake .. \
+ -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+ -DCMAKE_INSTALL_PREFIX=/usr \
+ -DAPP_BUILD_APPIMAGE=ON \
+ -DCMAKE_TOOLCHAIN_FILE="../toolchains/linux-dev.cmake"
+
+# Build
+echo -e "${GREEN}Building...${NC}"
+cmake --build . --config RelWithDebInfo -j$(nproc)
+
+# Install to AppDir
+echo -e "${GREEN}Installing to AppDir...${NC}"
+DESTDIR="../$APPDIR" cmake --install .
+
+cd ..
+
+# Copy desktop file and icon to AppDir root (required by AppImage)
+echo -e "${GREEN}Setting up AppDir structure...${NC}"
+cp "$APPDIR/usr/share/applications/dev.shaduri.gsmartcontrol.desktop" "$APPDIR/"
+cp "$APPDIR/usr/share/icons/hicolor/256x256/apps/gsmartcontrol.png" "$APPDIR/"
+
+# Create AppRun script
+cat > "$APPDIR/AppRun" << 'EOF'
+#!/bin/bash
+# AppRun script for GSmartControl AppImage
+
+SELF=$(readlink -f "$0")
+HERE=${SELF%/*}
+
+# Export library paths
+export LD_LIBRARY_PATH="$HERE/usr/lib:${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
+export PATH="$HERE/usr/bin:${PATH:+:$PATH}"
+
+# Export GTK settings
+export GSETTINGS_SCHEMA_DIR="$HERE/usr/share/glib-2.0/schemas:${GSETTINGS_SCHEMA_DIR:+:$GSETTINGS_SCHEMA_DIR}"
+export GDK_PIXBUF_MODULEDIR="$HERE/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders"
+export GDK_PIXBUF_MODULE_FILE="$HERE/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
+
+# Run the application
+exec "$HERE/usr/bin/gsmartcontrol" "$@"
+EOF
+chmod +x "$APPDIR/AppRun"
+
+# Use linuxdeploy to bundle dependencies
+echo -e "${GREEN}Bundling dependencies with linuxdeploy...${NC}"
+$LINUXDEPLOY --appdir "$APPDIR" \
+ --executable "$APPDIR/usr/bin/gsmartcontrol" \
+ --desktop-file "$APPDIR/dev.shaduri.gsmartcontrol.desktop" \
+ --icon-file "$APPDIR/gsmartcontrol.png"
+
+# Update GDK pixbuf cache
+if [ -d "$APPDIR/usr/lib/gdk-pixbuf-2.0" ]; then
+ echo -e "${GREEN}Updating GDK pixbuf cache...${NC}"
+ gdk-pixbuf-query-loaders > "$APPDIR/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" 2>/dev/null || true
+fi
+
+# Get version from version.txt (extract quoted CMAKE_PROJECT_VERSION value)
+VERSION=$(sed -n 's/.*CMAKE_PROJECT_VERSION[[:space:]]*"\([^"]*\)".*/\1/p' version.txt | head -n1)
+
+# Create AppImage
+echo -e "${GREEN}Creating AppImage...${NC}"
+ARCH=$ARCH $APPIMAGETOOL "$APPDIR" "GSmartControl-${VERSION}-${ARCH}.AppImage"
+
+echo
+echo -e "${GREEN}AppImage created successfully!${NC}"
+echo -e "Output: ${GREEN}GSmartControl-${VERSION}-${ARCH}.AppImage${NC}"
+echo
+echo -e "${YELLOW}Note: The AppImage must be run with sudo to access disk drives.${NC}"
+echo -e "Example: ${GREEN}sudo ./GSmartControl-${VERSION}-${ARCH}.AppImage${NC}"
diff --git a/src/build_config/CMakeLists.txt b/src/build_config/CMakeLists.txt
index 17340150..440c2020 100644
--- a/src/build_config/CMakeLists.txt
+++ b/src/build_config/CMakeLists.txt
@@ -82,6 +82,12 @@ elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "QNX")
set(CONFIG_KERNEL_QNX TRUE)
endif()
+# AppImage build configuration
+if (APP_BUILD_APPIMAGE)
+ set(CONFIG_APPIMAGE_BUILD TRUE)
+ message(STATUS "AppImage build enabled - using portable data file paths")
+endif()
+
# Additionally, these macros are defined by OS / compilers:
diff --git a/src/build_config/build_config.in.h b/src/build_config/build_config.in.h
index 0b5564d9..81060bbe 100644
--- a/src/build_config/build_config.in.h
+++ b/src/build_config/build_config.in.h
@@ -26,6 +26,7 @@ License: BSD Zero Clause License
#cmakedefine CONFIG_KERNEL_SOLARIS
#cmakedefine CONFIG_KERNEL_DARWIN
#cmakedefine CONFIG_KERNEL_QNX
+#cmakedefine CONFIG_APPIMAGE_BUILD
#if defined CONFIG_KERNEL_WINDOWS32 || defined CONFIG_KERNEL_WINDOWS64
#define CONFIG_KERNEL_FAMILY_WINDOWS
@@ -183,6 +184,16 @@ struct BuildEnv {
#endif
}
+ /// Check if this is an AppImage build (portable data file paths).
+ static constexpr bool is_appimage_build()
+ {
+ #ifdef CONFIG_APPIMAGE_BUILD
+ return true;
+ #else
+ return false;
+ #endif
+ }
+
};
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 63aa790a..4e0e51f2 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -62,6 +62,8 @@ target_link_libraries(gsmartcontrol
if (WIN32)
install(TARGETS gsmartcontrol DESTINATION .)
+elseif (APP_BUILD_APPIMAGE)
+ install(TARGETS gsmartcontrol DESTINATION "${CMAKE_INSTALL_BINDIR}/")
else()
install(TARGETS gsmartcontrol DESTINATION "${CMAKE_INSTALL_SBINDIR}/")
endif()
diff --git a/src/gui/gsc_init.cpp b/src/gui/gsc_init.cpp
index 0dff60c5..966fd748 100644
--- a/src/gui/gsc_init.cpp
+++ b/src/gui/gsc_init.cpp
@@ -475,7 +475,13 @@ bool app_init_and_loop(int& argc, char**& argv)
hz::data_file_add_search_directory("icons", application_dir / "icons");
hz::data_file_add_search_directory("ui", application_dir / "ui");
hz::data_file_add_search_directory("doc", application_dir / "doc");
+ } else if constexpr(BuildEnv::is_appimage_build()) {
+ // AppImage: Use relative paths from binary location (bin/../share/...)
+ hz::data_file_add_search_directory("icons", application_dir.parent_path() / "share" / BuildEnv::package_name() / "icons");
+ hz::data_file_add_search_directory("ui", application_dir.parent_path() / "share" / BuildEnv::package_name() / "ui");
+ hz::data_file_add_search_directory("doc", application_dir.parent_path() / "share" / "doc" / BuildEnv::package_name());
} else {
+ // Traditional Unix installation: Use absolute paths from BuildEnv
hz::data_file_add_search_directory("icons", hz::fs_path_from_string(BuildEnv::package_pkgdata_dir()) / BuildEnv::package_name() / "icons"); // /usr/share/program_name/icons
hz::data_file_add_search_directory("ui", hz::fs_path_from_string(BuildEnv::package_pkgdata_dir()) / BuildEnv::package_name() / "ui"); // /usr/share/program_name/ui
hz::data_file_add_search_directory("doc", hz::fs_path_from_string(BuildEnv::package_doc_dir())); // /usr/share/doc/[packages/]gsmartcontrol