#!/bin/bash # 💫 https://github.com/JaKooLit 💫 # # Quickshell (QtQuick-based shell toolkit) - Debian builder set -Eeuo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PARENT_DIR="$SCRIPT_DIR/.." cd "$PARENT_DIR" || { echo "${ERROR} Failed to change directory to $PARENT_DIR" exit 1 } # Source the global functions script if ! source "$(dirname "$(readlink -f "$0")")/Global_functions.sh"; then echo "Failed to source Global_functions.sh" exit 1 fi # Prefer /usr/local for pkg-config and CMake (for locally built libs like Breakpad) export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:${PKG_CONFIG_PATH:-}" export CMAKE_PREFIX_PATH="/usr/local:${CMAKE_PREFIX_PATH:-}" # Ensure logs dir exists at repo root (we cd into source later) mkdir -p "$PARENT_DIR/Install-Logs" LOG="$PARENT_DIR/Install-Logs/install-$(date +%d-%H%M%S)_quickshell.log" MLOG="$PARENT_DIR/Install-Logs/install-$(date +%d-%H%M%S)_quickshell_build.log" # Debian Trixie guard: Quickshell not compatible on Trixie at this time if grep -Eiq '\bVERSION_CODENAME=trixie\b' /etc/os-release; then echo "[INFO] debian Trixie not compatible with quickshell. Skipping quickshell install." | tee -a "$LOG" exit 0 fi # Refresh sudo credentials once (install_package uses sudo internally) if command -v sudo >/dev/null 2>&1; then sudo -v 2>/dev/null || sudo -v fi note() { echo -e "${NOTE} $*" | tee -a "$LOG"; } info() { echo -e "${INFO} $*" | tee -a "$LOG"; } # Build-time and runtime deps per upstream BUILD.md (Qt 6.6+) # Some may already be present from 00-dependencies.sh DEPS=( build-essential git autoconf automake libtool zlib1g-dev libcurl4-openssl-dev cmake ninja-build pkg-config spirv-tools qt6-base-dev qt6-declarative-dev qt6-shadertools-dev qt6-tools-dev qt6-tools-dev-tools qt6-declarative-private-dev # Wayland + protocols libwayland-dev wayland-protocols # Screencopy/GBM/DRM libdrm-dev libgbm-dev # Optional integrations enabled by default libpipewire-0.3-dev libpam0g-dev libglib2.0-dev libpolkit-gobject-1-dev libpolkit-agent-1-dev libjemalloc-dev # X11 (optional but harmless) libxcb1-dev # SVG support (package name differs across releases; try both) qt6-svg-dev libqt6svg6-dev # Third-party libs used by Quickshell libcli11-dev # Qt Quick runtime QML modules required at runtime (RectangularShadow, etc.) qml6-module-qtquick-effects qml6-module-qtquick-shapes qml6-module-qtquick-controls qml6-module-qtquick-layouts qml6-module-qt5compat-graphicaleffects ) printf "\n%s - Installing ${SKY_BLUE}Quickshell build dependencies${RESET}....\n" "${NOTE}" # Single apt transaction for speed and robustness, but filter packages with no candidate sudo apt update 2>&1 | tee -a "$LOG" AVAILABLE_PKGS=() for PKG in "${DEPS[@]}"; do CAND=$(apt-cache policy "$PKG" | awk '/Candidate:/ {print $2}') if [ -n "$CAND" ] && [ "$CAND" != "(none)" ]; then AVAILABLE_PKGS+=("$PKG") else note "Skipping $PKG (no candidate in APT)" fi done if ! sudo apt install -y "${AVAILABLE_PKGS[@]}" 2>&1 | tee -a "$LOG"; then echo "${ERROR} apt failed when installing Quickshell build dependencies." | tee -a "$LOG" exit 1 fi # Validate critical tools for bin in cmake ninja pkg-config; do if ! command -v "$bin" >/dev/null 2>&1; then echo "${ERROR} Required tool '$bin' not found after apt install." | tee -a "$LOG" exit 1 fi done # Build Google Breakpad from source if pkg-config 'breakpad' is missing if ! pkg-config --exists breakpad; then note "Building Google Breakpad from source..." BP_DIR="$PARENT_DIR/.thirdparty/breakpad" rm -rf "$BP_DIR" mkdir -p "$BP_DIR" ( set -Eeuo pipefail cd "$BP_DIR" # Clone Breakpad into the root of BP_DIR (expected layout: ./src) git clone --depth=1 https://chromium.googlesource.com/breakpad/breakpad . 2>&1 | tee -a "$MLOG" # lss must live at src/third_party/lss relative to Breakpad root git clone --depth=1 https://chromium.googlesource.com/linux-syscall-support src/third_party/lss 2>&1 | tee -a "$MLOG" || true # Autotools bootstrap if needed (at Breakpad root) if [ ! -x ./configure ]; then autoreconf -fi 2>&1 | tee -a "$MLOG" fi ./configure --prefix=/usr/local 2>&1 | tee -a "$MLOG" make -j "$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN)" 2>&1 | tee -a "$MLOG" sudo make install 2>&1 | tee -a "$MLOG" ) || { echo "${ERROR} Breakpad build failed." | tee -a "$LOG"; exit 1; } # Provide pkg-config file if upstream didn't install one under the name 'breakpad' if ! pkg-config --exists breakpad; then if pkg-config --exists breakpad-client; then sudo mkdir -p /usr/local/lib/pkgconfig sudo ln -sf /usr/local/lib/pkgconfig/breakpad-client.pc /usr/local/lib/pkgconfig/breakpad.pc elif [ -f /usr/local/lib/libbreakpad_client.a ] || [ -f /usr/local/lib/libbreakpad_client.so ]; then TMP_PC="/tmp/breakpad.pc.$$" cat >"$TMP_PC" <<'PCEOF' prefix=/usr/local exec_prefix=${prefix} includedir=${prefix}/include libdir=${exec_prefix}/lib Name: breakpad Description: Google Breakpad client library Version: 0 Libs: -L${libdir} -lbreakpad_client Cflags: -I${includedir} PCEOF sudo mkdir -p /usr/local/lib/pkgconfig sudo mv "$TMP_PC" /usr/local/lib/pkgconfig/breakpad.pc fi fi if ! pkg-config --exists breakpad; then echo "${ERROR} breakpad pkg-config entry not found after installation." | tee -a "$LOG" exit 1 fi fi # Clone source (prefer upstream forgejo; mirror available at github:quickshell-mirror/quickshell) SRC_DIR="quickshell-src" if [ -d "$SRC_DIR" ]; then note "Removing existing $SRC_DIR" rm -rf "$SRC_DIR" fi note "Cloning Quickshell source..." if git clone --depth=1 https://git.outfoxxed.me/quickshell/quickshell "$SRC_DIR" 2>&1 | tee -a "$LOG"; then cd "$SRC_DIR" else echo "${ERROR} Failed to clone Quickshell repo" | tee -a "$LOG" exit 1 fi # Configure with Ninja; enable RelWithDebInfo, leave features ON (deps installed above) CMAKE_FLAGS=( -GNinja -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDISTRIBUTOR="Debian-Hyprland installer" ) note "Configuring Quickshell (CMake)..." # Use explicit source/build dirs and preserve cmake exit code with pipefail if ! cmake -S . -B build "${CMAKE_FLAGS[@]}" 2>&1 | tee -a "$MLOG"; then echo "${ERROR} CMake configure failed. See log: $MLOG" | tee -a "$LOG" exit 1 fi # Ensure build files exist before invoking ninja if [ ! -f build/build.ninja ]; then echo "${ERROR} build/build.ninja not generated; aborting build." | tee -a "$LOG" exit 1 fi note "Building Quickshell (Ninja)..." if ! cmake --build build 2>&1 | tee -a "$MLOG"; then echo "${ERROR} Build failed. See log: $MLOG" | tee -a "$LOG" exit 1 fi note "Installing Quickshell..." if ! sudo cmake --install build 2>&1 | tee -a "$MLOG"; then echo "${ERROR} Installation failed. See log: $MLOG" | tee -a "$LOG" exit 1 fi echo "${OK} Quickshell installed successfully." | tee -a "$MLOG" # Provide a shim for missing QtQuick.Effects.RectangularShadow (wraps MultiEffect) OVR_DIR=/usr/local/share/quickshell-overrides/QtQuick/Effects sudo install -d -m 755 "$OVR_DIR" sudo tee "$OVR_DIR/RectangularShadow.qml" >/dev/null <<'QML' import QtQuick import QtQuick.Effects Item { id: root // Minimal RectangularShadow shim using MultiEffect // Map common properties used by configs property alias source: fx.source property color color: "#000000" property real opacity: 0.4 property real blur: 32 property real xOffset: 0 property real yOffset: 6 property real scale: 1.0 MultiEffect { id: fx anchors.fill: parent shadowEnabled: true shadowColor: root.color shadowOpacity: root.opacity shadowBlur: root.blur shadowHorizontalOffset: root.xOffset shadowVerticalOffset: root.yOffset shadowScale: root.scale } } QML # Install a wrapper to run Quickshell with system QML imports (avoids Nix/Flatpak overrides) WRAP=/usr/local/bin/qs-system sudo tee "$WRAP" >/dev/null <<'EOSH' #!/usr/bin/env bash # Run Quickshell preferring system Qt6 QML modules and overrides OVR=/usr/local/share/quickshell-overrides export QML_IMPORT_PATH="$OVR${QML_IMPORT_PATH:+:$QML_IMPORT_PATH}" export QML2_IMPORT_PATH="$OVR${QML2_IMPORT_PATH:+:$QML2_IMPORT_PATH}" exec qs "$@" EOSH sudo chmod +x "$WRAP" || true # Build logs already written to $PARENT_DIR/Install-Logs # Keep source directory for reference in case user wants to rebuild later printf "\n%.0s" {1..1}