forked from Shinonome/alt-illogical-impulse
251 lines
10 KiB
Nix
251 lines
10 KiB
Nix
# Quickshell service integration with staging system
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
cfg = config.programs.dots-hyprland.quickshell;
|
|
mainCfg = config.programs.dots-hyprland;
|
|
|
|
# Service startup script that handles initial setup
|
|
# Note: quickshell must be in home.packages
|
|
quickshellStartup = pkgs.writeShellScript "quickshell-startup" ''
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
# Colors for logging
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m'
|
|
|
|
log() {
|
|
echo -e "''${GREEN}[quickshell-service]''${NC} $1" >&2
|
|
}
|
|
|
|
warn() {
|
|
echo -e "''${YELLOW}[quickshell-service]''${NC} WARNING: $1" >&2
|
|
}
|
|
|
|
error() {
|
|
echo -e "''${RED}[quickshell-service]''${NC} ERROR: $1" >&2
|
|
}
|
|
|
|
STAGING_DIR="$HOME/${mainCfg.writable-mode.stagingDir}"
|
|
CONFIG_DIR="$HOME/.config"
|
|
SETUP_SCRIPT="$HOME/${mainCfg.writable-mode.setupScript}"
|
|
SETUP_MARKER="$HOME/.cache/dots-hyprland/setup-complete"
|
|
|
|
# Ensure cache directory exists
|
|
mkdir -p "$(dirname "$SETUP_MARKER")"
|
|
|
|
# Check if initial setup has been run
|
|
if [[ ! -f "$SETUP_MARKER" ]]; then
|
|
log "🚀 First run detected - running initial setup"
|
|
|
|
# Check if staging directory exists
|
|
if [[ ! -d "$STAGING_DIR" ]]; then
|
|
error "Staging directory not found: $STAGING_DIR"
|
|
error "Please run 'home-manager switch' first"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if setup script exists
|
|
if [[ ! -x "$SETUP_SCRIPT" ]]; then
|
|
error "Setup script not found or not executable: $SETUP_SCRIPT"
|
|
exit 1
|
|
fi
|
|
|
|
log "📋 Running initial setup script..."
|
|
if "$SETUP_SCRIPT"; then
|
|
# Mark setup as complete
|
|
echo "$(date)" > "$SETUP_MARKER"
|
|
log "✅ Initial setup completed successfully"
|
|
else
|
|
error "❌ Initial setup failed"
|
|
exit 1
|
|
fi
|
|
else
|
|
log "✅ Setup already completed ($(cat "$SETUP_MARKER"))"
|
|
fi
|
|
|
|
# Verify quickshell configuration exists
|
|
if [[ ! -d "$CONFIG_DIR/quickshell" ]]; then
|
|
error "Quickshell configuration not found at $CONFIG_DIR/quickshell"
|
|
error "Initial setup may have failed"
|
|
exit 1
|
|
fi
|
|
|
|
# Set up environment variables
|
|
export ILLOGICAL_IMPULSE_VIRTUAL_ENV="$HOME/.local/state/quickshell/.venv"
|
|
export QT_SCALE_FACTOR="${toString cfg.scaling}"
|
|
export QT_QUICK_CONTROLS_STYLE="Basic"
|
|
export QT_QUICK_FLICKABLE_WHEEL_DECELERATION="10000"
|
|
|
|
# Ensure PATH includes user applications - CRITICAL for app launching
|
|
export PATH="${config.home.profileDirectory}/bin:/run/wrappers/bin:${config.home.homeDirectory}/.nix-profile/bin:/etc/profiles/per-user/${config.home.username}/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:$PATH"
|
|
export XDG_DATA_DIRS="${config.home.profileDirectory}/share:${config.home.homeDirectory}/.nix-profile/share:/etc/profiles/per-user/${config.home.username}/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share:$XDG_DATA_DIRS"
|
|
|
|
# Create application launcher wrapper that quickshell can use
|
|
LAUNCHER_WRAPPER="$HOME/.cache/dots-hyprland/app-launcher"
|
|
mkdir -p "$(dirname "$LAUNCHER_WRAPPER")"
|
|
cat > "$LAUNCHER_WRAPPER" << 'EOF'
|
|
#!/usr/bin/env bash
|
|
# Application launcher wrapper for quickshell
|
|
# Ensures proper PATH and environment for launched applications
|
|
|
|
# Use the same PATH that quickshell has
|
|
export PATH="${config.home.profileDirectory}/bin:/run/wrappers/bin:${config.home.homeDirectory}/.nix-profile/bin:/etc/profiles/per-user/${config.home.username}/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin"
|
|
export XDG_DATA_DIRS="${config.home.profileDirectory}/share:${config.home.homeDirectory}/.nix-profile/share:/etc/profiles/per-user/${config.home.username}/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share"
|
|
|
|
# Launch the application
|
|
exec "$@"
|
|
EOF
|
|
chmod +x "$LAUNCHER_WRAPPER"
|
|
|
|
# Export the launcher wrapper path for quickshell to use
|
|
export DOTS_HYPRLAND_APP_LAUNCHER="$LAUNCHER_WRAPPER"
|
|
|
|
# Verify Python virtual environment
|
|
if [[ ! -d "$ILLOGICAL_IMPULSE_VIRTUAL_ENV" ]]; then
|
|
warn "Python virtual environment not found at $ILLOGICAL_IMPULSE_VIRTUAL_ENV"
|
|
warn "Some features may not work correctly"
|
|
fi
|
|
|
|
log "🎯 Starting quickshell with dots-hyprland configuration"
|
|
log "📁 Config: $CONFIG_DIR/quickshell/ii/shell.qml"
|
|
log "🐍 Python venv: $ILLOGICAL_IMPULSE_VIRTUAL_ENV"
|
|
log "🚀 App launcher: $LAUNCHER_WRAPPER"
|
|
|
|
# Set up Qt environment for dots-hyprland
|
|
export QML2_IMPORT_PATH="${pkgs.kdePackages.qt5compat}/lib/qt-6/qml:${pkgs.kdePackages.qtpositioning}/lib/qt-6/qml:${pkgs.kdePackages.qtlocation}/lib/qt-6/qml:$HOME/.config/quickshell/ii:$HOME/.config/quickshell:$QML2_IMPORT_PATH"
|
|
export XDG_DATA_DIRS="$XDG_DATA_DIRS:${pkgs.gsettings-desktop-schemas}/share"
|
|
export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:${pkgs.glibc}/lib:${pkgs.zlib}/lib:${pkgs.libffi}/lib:${pkgs.openssl}/lib:${pkgs.bzip2.out}/lib:${pkgs.xz.out}/lib:${pkgs.ncurses}/lib:${pkgs.readline}/lib:${pkgs.sqlite.out}/lib:$LD_LIBRARY_PATH"
|
|
|
|
# Start quickshell (from PATH - must be in home.packages)
|
|
exec quickshell -p "$CONFIG_DIR/quickshell/ii/shell.qml"
|
|
'';
|
|
|
|
in
|
|
{
|
|
options.programs.dots-hyprland.quickshell = {
|
|
enable = mkEnableOption "Quickshell service with staging integration";
|
|
|
|
autoStart = mkEnableOption "Auto-start with Hyprland session" // { default = true; };
|
|
|
|
restartOnFailure = mkEnableOption "Restart service on failure" // { default = true; };
|
|
|
|
scaling = mkOption {
|
|
type = types.float;
|
|
default = 1.0;
|
|
description = "UI scaling factor";
|
|
};
|
|
|
|
logLevel = mkOption {
|
|
type = types.enum [ "debug" "info" "warning" "error" ];
|
|
default = "info";
|
|
description = "Logging level for quickshell service";
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
# Install service management scripts (quickshell itself must be in home.packages)
|
|
home.packages = (with pkgs; [
|
|
(writeShellScriptBin "quickshell-restart" ''
|
|
systemctl --user restart quickshell.service
|
|
echo "✅ Quickshell service restarted"
|
|
'')
|
|
|
|
(writeShellScriptBin "quickshell-status" ''
|
|
echo "🔍 Quickshell Service Status"
|
|
echo "=========================="
|
|
systemctl --user status quickshell.service --no-pager
|
|
echo ""
|
|
echo "📋 Recent logs:"
|
|
journalctl --user -u quickshell.service -n 10 --no-pager
|
|
'')
|
|
|
|
(writeShellScriptBin "quickshell-logs" ''
|
|
echo "📋 Following quickshell logs (Ctrl+C to exit):"
|
|
journalctl --user -u quickshell.service -f
|
|
'')
|
|
|
|
(writeShellScriptBin "quickshell-debug" ''
|
|
echo "🐛 Starting quickshell in debug mode..."
|
|
systemctl --user stop quickshell.service
|
|
QT_LOGGING_RULES="quickshell.*=true" ${quickshellStartup}
|
|
'')
|
|
]);
|
|
|
|
# Systemd user service for quickshell
|
|
systemd.user.services.quickshell = {
|
|
Unit = {
|
|
Description = "Quickshell - QtQuick based desktop shell with dots-hyprland";
|
|
Documentation = [ "https://quickshell.org" "https://end-4.github.io/dots-hyprland-wiki/" ];
|
|
PartOf = [ "hyprland-session.target" ];
|
|
After = [ "hyprland-session.target" "graphical-session.target" ];
|
|
Wants = [ "hyprland-session.target" ];
|
|
};
|
|
|
|
Service = {
|
|
Type = "simple";
|
|
ExecStart = quickshellStartup;
|
|
ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR2 $MAINPID";
|
|
Restart = if cfg.restartOnFailure then "on-failure" else "no";
|
|
RestartSec = 2;
|
|
TimeoutStartSec = 30;
|
|
TimeoutStopSec = 10;
|
|
|
|
# Environment variables - include full user environment
|
|
Environment = [
|
|
"QT_SCALE_FACTOR=${toString cfg.scaling}"
|
|
"QT_QUICK_CONTROLS_STYLE=Basic"
|
|
"QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000"
|
|
"QT_LOGGING_RULES=${
|
|
if cfg.logLevel == "debug" then "quickshell.*=true"
|
|
else if cfg.logLevel == "warning" then "*.warning=true"
|
|
else if cfg.logLevel == "error" then "*.critical=true"
|
|
else "*.info=true"
|
|
}"
|
|
# Include user's full PATH so applications can be launched
|
|
"PATH=${config.home.profileDirectory}/bin:/run/wrappers/bin:${config.home.homeDirectory}/.nix-profile/bin:/etc/profiles/per-user/${config.home.username}/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin"
|
|
# Include XDG data directories for application discovery
|
|
"XDG_DATA_DIRS=${config.home.profileDirectory}/share:${config.home.homeDirectory}/.nix-profile/share:/etc/profiles/per-user/${config.home.username}/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share"
|
|
# Application launcher wrapper path
|
|
"DOTS_HYPRLAND_APP_LAUNCHER=%h/.cache/dots-hyprland/app-launcher"
|
|
# QML module paths for Qt plugins and KDE components
|
|
"QML2_IMPORT_PATH=${pkgs.kdePackages.qt5compat}/lib/qt-6/qml:${pkgs.kdePackages.qtpositioning}/lib/qt-6/qml:${pkgs.kdePackages.qtlocation}/lib/qt-6/qml:${pkgs.kdePackages.bluez-qt}/lib/qt-6/qml:${pkgs.kdePackages.bluedevil}/lib/qt-6/qml:${pkgs.kdePackages.plasma-nm}/lib/qt-6/qml:${pkgs.kdePackages.kconfig}/lib/qt-6/qml:${pkgs.kdePackages.kirigami}/lib/qt-6/qml"
|
|
];
|
|
|
|
# Working directory
|
|
WorkingDirectory = "%h";
|
|
|
|
# Security settings
|
|
PrivateNetwork = false;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = false; # Need access to home directory
|
|
NoNewPrivileges = true;
|
|
|
|
# Resource limits
|
|
MemoryMax = "2G";
|
|
CPUQuota = "200%";
|
|
};
|
|
|
|
Install = mkIf cfg.autoStart {
|
|
WantedBy = [ "hyprland-session.target" ];
|
|
};
|
|
};
|
|
|
|
# Create hyprland session target if it doesn't exist
|
|
systemd.user.targets.hyprland-session = {
|
|
Unit = {
|
|
Description = "Hyprland compositor session";
|
|
Documentation = [ "man:systemd.special(7)" ];
|
|
BindsTo = [ "graphical-session.target" ];
|
|
Wants = [ "graphical-session-pre.target" ];
|
|
After = [ "graphical-session-pre.target" ];
|
|
};
|
|
};
|
|
};
|
|
}
|