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