Initial clean flake structure - Phase 3 complete

This commit is contained in:
Celes Renata
2025-08-08 22:05:41 -07:00
commit 8011f1c842
11 changed files with 2313 additions and 0 deletions
+258
View File
@@ -0,0 +1,258 @@
# Quickshell service integration with staging system
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.dots-hyprland.quickshell;
mainCfg = config.programs.dots-hyprland;
# Our working quickshell build with QtPositioning support
workingQuickshell =
let
quickshellSrc = pkgs.fetchFromGitHub {
owner = "quickshell-mirror";
repo = "quickshell";
rev = "a5431dd02dc23d9ef1680e67777fed00fe5f7cda";
hash = "sha256-vqkSDvh7hWhPvNjMjEDV4KbSCv2jyl2Arh73ZXe274k=";
};
quickshellBase = pkgs.callPackage (quickshellSrc + "/default.nix") {
debug = true;
gitRev = "a5431dd02dc23d9ef1680e67777fed00fe5f7cda";
};
in
quickshellBase.withModules (with pkgs.qt6; [ qtpositioning qtmultimedia ]);
# Service startup script that handles initial setup
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"
# Start quickshell
exec ${workingQuickshell}/bin/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 the working quickshell build and service management scripts
home.packages = [ workingQuickshell ] ++ (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"
];
# 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" ];
};
};
};
}
+271
View File
@@ -0,0 +1,271 @@
# Touchegg gesture support for dots-hyprland
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.dots-hyprland.touchegg;
mainCfg = config.programs.dots-hyprland;
in
{
options.programs.dots-hyprland.touchegg = {
enable = mkEnableOption "Touchegg gesture support";
config = mkOption {
type = types.lines;
default = ''
<touchégg>
<settings>
<property name="animation_delay">150</property>
<property name="action_execute_threshold">80</property>
<property name="color">auto</property>
<property name="borderColor">auto</property>
</settings>
<application name="All">
<!-- 3-finger pinch in: Close window -->
<gesture type="PINCH" fingers="3" direction="IN">
<action type="CLOSE_WINDOW">
<animate>true</animate>
<color>F84A53</color>
<borderColor>F84A53</borderColor>
</action>
</gesture>
<!-- 2-finger tap: Right click -->
<gesture type="TAP" fingers="2" direction="UNKNOWN">
<action type="MOUSE_CLICK">
<button>3</button>
<on>begin</on>
</action>
</gesture>
<!-- 3-finger tap: Middle click -->
<gesture type="TAP" fingers="3" direction="UNKNOWN">
<action type="MOUSE_CLICK">
<button>2</button>
<on>begin</on>
</action>
</gesture>
<!-- 4-finger pinch in: Fullscreen mode 0 -->
<gesture type="PINCH" fingers="4" direction="IN">
<action type="RUN_COMMAND">
<command>hyprctl dispatch fullscreen 0</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
<!-- 4-finger pinch out: Fullscreen mode 1 -->
<gesture type="PINCH" fingers="4" direction="OUT">
<action type="RUN_COMMAND">
<command>hyprctl dispatch fullscreen 1</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
<!-- Note: 3-finger left/right swipes removed - handled by Hyprland's built-in workspace_swipe -->
<!-- 3-finger swipe up: Show overview -->
<gesture type="SWIPE" fingers="3" direction="UP">
<action type="RUN_COMMAND">
<command>hyprctl dispatch global quickshell:overviewToggle</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
<!-- 3-finger swipe down: Show all windows -->
<gesture type="SWIPE" fingers="3" direction="DOWN">
<action type="RUN_COMMAND">
<command>hyprctl dispatch overview</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
<!-- 4-finger swipe left: Move window left -->
<gesture type="SWIPE" fingers="4" direction="LEFT">
<action type="RUN_COMMAND">
<command>hyprctl dispatch movewindow l</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
<!-- 4-finger swipe right: Move window right -->
<gesture type="SWIPE" fingers="4" direction="RIGHT">
<action type="RUN_COMMAND">
<command>hyprctl dispatch movewindow r</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
<!-- 4-finger swipe up: Move window up -->
<gesture type="SWIPE" fingers="4" direction="UP">
<action type="RUN_COMMAND">
<command>hyprctl dispatch movewindow u</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
<!-- 4-finger swipe down: Move window down -->
<gesture type="SWIPE" fingers="4" direction="DOWN">
<action type="RUN_COMMAND">
<command>hyprctl dispatch movewindow d</command>
<repeat>false</repeat>
<animation>NONE</animation>
<on>begin</on>
</action>
</gesture>
</application>
<!-- Browser-specific gestures for zoom -->
<application name="chromium-browser">
<gesture type="PINCH" fingers="2" direction="IN">
<action type="SEND_KEYS">
<repeat>true</repeat>
<modifiers>Control_L</modifiers>
<keys>KP_Subtract</keys>
<decreaseKeys>KP_Add</decreaseKeys>
</action>
</gesture>
<gesture type="PINCH" fingers="2" direction="OUT">
<action type="SEND_KEYS">
<repeat>true</repeat>
<modifiers>Control_L</modifiers>
<keys>KP_Add</keys>
<decreaseKeys>KP_Subtract</decreaseKeys>
</action>
</gesture>
</application>
<application name="google-chrome">
<gesture type="PINCH" fingers="2" direction="IN">
<action type="SEND_KEYS">
<repeat>true</repeat>
<modifiers>Control_L</modifiers>
<keys>KP_Subtract</keys>
<decreaseKeys>KP_Add</decreaseKeys>
</action>
</gesture>
<gesture type="PINCH" fingers="2" direction="OUT">
<action type="SEND_KEYS">
<repeat>true</repeat>
<modifiers>Control_L</modifiers>
<keys>KP_Add</keys>
<decreaseKeys>KP_Subtract</decreaseKeys>
</action>
</gesture>
</application>
<application name="firefox">
<gesture type="PINCH" fingers="2" direction="IN">
<action type="SEND_KEYS">
<repeat>true</repeat>
<modifiers>Control_L</modifiers>
<keys>KP_Subtract</keys>
<decreaseKeys>KP_Add</decreaseKeys>
</action>
</gesture>
<gesture type="PINCH" fingers="2" direction="OUT">
<action type="SEND_KEYS">
<repeat>true</repeat>
<modifiers>Control_L</modifiers>
<keys>KP_Add</keys>
<decreaseKeys>KP_Subtract</decreaseKeys>
</action>
</gesture>
</application>
</touchégg>
'';
description = "Touchegg configuration XML";
};
};
config = mkIf cfg.enable {
# Note: touchegg service needs to be enabled at system level
# Add this to your NixOS configuration: services.touchegg.enable = true;
# Install touchegg configuration (both user and system locations)
xdg.configFile."touchegg/touchegg.conf" = {
text = cfg.config;
};
# Also create system config that touchegg service can read
# Note: This requires the touchegg service to be enabled at system level
home.activation.toucheggSystemConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
echo "📄 Creating system-wide touchegg configuration..."
$DRY_RUN_CMD sudo mkdir -p /etc/touchegg
$DRY_RUN_CMD sudo cp ${config.xdg.configHome}/touchegg/touchegg.conf /etc/touchegg/touchegg.conf
echo " System touchegg config updated"
'';
# Create touchegg client service (required for gesture execution)
systemd.user.services.touchegg-client = {
Unit = {
Description = "Touchegg Client";
After = [ "graphical-session.target" ];
};
Service = {
Type = "simple";
ExecStart = "${pkgs.touchegg}/bin/touchegg --client";
Restart = "on-failure";
RestartSec = 3;
};
Install = {
WantedBy = [ "default.target" ];
};
};
# Install touchegg and management scripts
home.packages = [ pkgs.touchegg ] ++ [
(pkgs.writeShellScriptBin "touchegg-restart" ''
echo "🔄 Restarting touchegg service..."
sudo systemctl restart touchegg
echo " Touchegg restarted"
'')
(pkgs.writeShellScriptBin "touchegg-status" ''
echo "📊 Touchegg service status:"
systemctl status touchegg --no-pager
echo ""
echo "📄 Touchegg configuration:"
echo " ~/.config/touchegg/touchegg.conf"
if [[ -f ~/.config/touchegg/touchegg.conf ]]; then
echo " Configuration file exists"
else
echo " Configuration file missing"
fi
'')
(pkgs.writeShellScriptBin "touchegg-reload-config" ''
echo "🔄 Reloading touchegg configuration..."
if systemctl is-active touchegg >/dev/null 2>&1; then
sudo systemctl reload touchegg 2>/dev/null || sudo systemctl restart touchegg
echo " Touchegg configuration reloaded"
else
echo " Touchegg service is not running"
echo "💡 Try: sudo systemctl start touchegg"
fi
'')
];
# Session variables for touchegg
home.sessionVariables = {
TOUCHEGG_CONFIG_PATH = "$HOME/.config/touchegg/touchegg.conf";
};
};
}