Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .config/hypr/conf/animations.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- Preserve the original bezier curves, animation speeds, and transition styles.
hl.config({ animations = { enabled = true } })
hl.curve("easeOutQuint", { type = "bezier", points = { { 0.23, 1 }, { 0.32, 1 } } })
hl.curve("easeInOutCubic", { type = "bezier", points = { { 0.65, 0.05 }, { 0.36, 1 } } })
hl.curve("linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } })
hl.curve("almostLinear", { type = "bezier", points = { { 0.5, 0.5 }, { 0.75, 1 } } })
hl.curve("quick", { type = "bezier", points = { { 0.15, 0 }, { 0.1, 1 } } })

hl.animation({ leaf = "global", enabled = true, speed = 10, bezier = "default" })
hl.animation({ leaf = "border", enabled = true, speed = 5.39, bezier = "easeOutQuint" })
hl.animation({ leaf = "windows", enabled = true, speed = 4.79, bezier = "easeOutQuint" })
hl.animation({ leaf = "windowsIn", enabled = true, speed = 4.1, bezier = "easeOutQuint", style = "popin 87%" })
hl.animation({ leaf = "windowsOut", enabled = true, speed = 1.49, bezier = "linear", style = "popin 87%" })
hl.animation({ leaf = "fadeIn", enabled = true, speed = 1.73, bezier = "almostLinear" })
hl.animation({ leaf = "fadeOut", enabled = true, speed = 1.46, bezier = "almostLinear" })
hl.animation({ leaf = "fade", enabled = true, speed = 3.03, bezier = "quick" })
hl.animation({ leaf = "layers", enabled = true, speed = 3.81, bezier = "easeOutQuint" })
hl.animation({ leaf = "layersIn", enabled = true, speed = 4, bezier = "easeOutQuint", style = "fade" })
hl.animation({ leaf = "layersOut", enabled = true, speed = 1.5, bezier = "linear", style = "fade" })
hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 1.79, bezier = "almostLinear" })
hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 1.39, bezier = "almostLinear" })
hl.animation({ leaf = "workspaces", enabled = true, speed = 4, bezier = "easeOutQuint", style = "slidefade 20%" })
hl.animation({ leaf = "zoomFactor", enabled = true, speed = 7, bezier = "quick" })
10 changes: 10 additions & 0 deletions .config/hypr/conf/autostart.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Start session services once, never during parsing or ordinary config reload.
hl.on("hyprland.start", function()
hl.exec_cmd("nm-applet --indicator")
hl.exec_cmd("~/.config/waybar/scripts/launch.sh --start & awww-daemon")
hl.exec_cmd("swaync")
hl.exec_cmd("hypridle")
hl.exec_cmd("~/.config/hypr/scripts/wallpaper.sh")
hl.exec_cmd("wl-paste --watch cliphist store")
hl.exec_cmd("/usr/libexec/kf6/polkit-kde-authentication-agent-1")
end)
8 changes: 8 additions & 0 deletions .config/hypr/conf/env.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Preserve cursor sizes and Wayland toolkit preferences as complete strings.
hl.env("XCURSOR_SIZE", "24")
hl.env("HYPRCURSOR_SIZE", "24")
hl.env("GDK_BACKEND", "wayland,x11,*")
hl.env("QT_QPA_PLATFORM", "wayland;xcb")
hl.env("QT_AUTO_SCREEN_SCALE_FACTOR", "1")
hl.env("ELECTRON_OZONE_PLATFORM_HINT", "auto")
hl.env("CLUTTER_BACKEND", "wayland")
13 changes: 13 additions & 0 deletions .config/hypr/conf/input.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- Preserve keyboard defaults, pointer behavior, workspace gesture, and device override.
hl.config({ input = {
kb_layout = "us",
kb_variant = "",
kb_model = "",
kb_options = "",
kb_rules = "",
follow_mouse = 1,
sensitivity = 0,
touchpad = { natural_scroll = false },
} })
hl.gesture({ fingers = 3, direction = "horizontal", action = "workspace" })
hl.device({ name = "epic-mouse-v1", sensitivity = -0.5 })
56 changes: 56 additions & 0 deletions .config/hypr/conf/keybinds.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
-- Preserve existing shortcuts with native Lua dispatchers and explicit modifiers.
local programs = require("conf.programs")
local mainMod = "SUPER"

hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd(programs.terminal))
hl.bind(mainMod .. " + Q", hl.dsp.window.close())
hl.bind(mainMod .. " + M", hl.dsp.exec_cmd("~/.config/rofi/scripts/powermenu.sh"))
hl.bind(mainMod .. " + Escape", hl.dsp.exec_cmd("~/.config/rofi/scripts/powermenu.sh"))
hl.bind(mainMod .. " + F", hl.dsp.exec_cmd(programs.fileManager))
hl.bind(mainMod .. " + SHIFT + F", hl.dsp.window.fullscreen({ mode = "fullscreen", action = "toggle" }))
hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" }))
hl.bind(mainMod .. " + Space", hl.dsp.window.float({ action = "toggle" }))
hl.bind(mainMod .. " + D", hl.dsp.exec_cmd(programs.menu))
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo({ action = "toggle" }))
hl.bind(mainMod .. " + J", hl.dsp.layout("togglesplit"))
hl.bind(mainMod .. " + SHIFT + S", hl.dsp.exec_cmd([[sh -c 'grimblast copysave area "$HOME/Pictures/Screenshots/$(date +%F_%H-%M-%S).png"']]))
hl.bind(mainMod .. " + W", hl.dsp.exec_cmd("firefox"))
hl.bind(mainMod .. " + N", hl.dsp.exec_cmd("swaync-client -t -sw"))
hl.bind(mainMod .. " + C", hl.dsp.exec_cmd("code"))
hl.bind(mainMod .. " + SHIFT + W", hl.dsp.exec_cmd(programs.wifi))
hl.bind(mainMod .. " + SHIFT + B", hl.dsp.exec_cmd(programs.bluetooth))
hl.bind(mainMod .. " + SHIFT + A", hl.dsp.exec_cmd(programs.wallpaper))
hl.bind(mainMod .. " + L", hl.dsp.exec_cmd("hyprlock"))
hl.bind(mainMod .. " + G", hl.dsp.exec_cmd("kitty --class floating-terminal -e lazygit"))
hl.bind(mainMod .. " + SHIFT + Escape", hl.dsp.exec_cmd("kitty --class floating-terminal -e btop"))
hl.bind(mainMod .. " + A", hl.dsp.exec_cmd("~/.config/hypr/scripts/wallpaper.sh --once"))
hl.bind(mainMod .. " + SHIFT + R", hl.dsp.exec_cmd("~/.config/hypr/scripts/reload.sh"))
hl.bind(mainMod .. " + R", hl.dsp.exec_cmd("~/.config/waybar/scripts/launch.sh"))
hl.bind(mainMod .. " + SHIFT + V", hl.dsp.exec_cmd("~/.config/rofi/scripts/clipboard_history.sh"))

hl.bind(mainMod .. " + left", hl.dsp.focus({ direction = "left" }))
hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = "right" }))
hl.bind(mainMod .. " + up", hl.dsp.focus({ direction = "up" }))
hl.bind(mainMod .. " + down", hl.dsp.focus({ direction = "down" }))

for workspace = 1, 10 do
local key = workspace % 10
hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = workspace }))
hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = workspace, follow = true }))
end
hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
-- Lua drag dispatchers handle press/release; the legacy mouse flag is not a bind option.
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag())
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize())

hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true, repeating = true })
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true, repeating = true })
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true, repeating = true })
hl.bind("XF86AudioMicMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), { locked = true, repeating = true })
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%+"), { locked = true, repeating = true })
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"), { locked = true, repeating = true })
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true })
hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
2 changes: 2 additions & 0 deletions .config/hypr/conf/layouts.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Preserve dwindle split orientation and master insertion behavior.
hl.config({ dwindle = { preserve_split = true }, master = { new_status = "master" } })
30 changes: 30 additions & 0 deletions .config/hypr/conf/look_and_feel.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-- Preserve Catppuccin Mocha decoration and the existing rendering policy.
hl.config({
general = {
gaps_in = 5,
gaps_out = 16,
border_size = 2,
col = {
active_border = { colors = { "rgba(cba6f7ee)", "rgba(b4befeee)" }, angle = 45 },
inactive_border = "rgba(313244aa)",
},
resize_on_border = false,
allow_tearing = false,
layout = "dwindle",
},
decoration = {
rounding = 10,
rounding_power = 2,
active_opacity = 1.0,
inactive_opacity = 0.95,
shadow = { enabled = true, range = 8, render_power = 3, color = "rgba(11111bee)" },
blur = { enabled = true, size = 5, passes = 2, vibrancy = 0.1696 },
},
render = { direct_scanout = 1 },
misc = {
force_default_wallpaper = 0,
disable_hyprland_logo = true,
disable_hyprland_guiutils_check = true,
vrr = 1,
},
})
2 changes: 2 additions & 0 deletions .config/hypr/conf/monitors.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Match any output using its preferred mode and automatic placement/scale.
hl.monitor({ output = "", mode = "preferred", position = "auto", scale = "auto", vrr = 1 })
9 changes: 9 additions & 0 deletions .config/hypr/conf/programs.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Shared application commands; requiring this module does not launch anything.
return {
terminal = "kitty",
fileManager = "dolphin",
menu = "rofi -show drun",
wifi = "~/.config/rofi/scripts/wifi.sh",
bluetooth = "~/.config/rofi/scripts/bluetooth.sh",
wallpaper = "~/.config/rofi/scripts/wallpaper.sh",
}
24 changes: 24 additions & 0 deletions .config/hypr/conf/windowrules.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-- Preserve named application rules, geometry strings, and XWayland drag matching.
hl.window_rule({
name = "suppress-maximize-events",
match = { class = ".*" },
suppress_event = "maximize",
})
hl.window_rule({
name = "floating-terminal",
match = { class = "^(floating-terminal)$" },
float = true,
size = "85% 85%",
center = true,
})
hl.window_rule({
name = "dialogs-and-pickers",
match = { title = "^(Open File|Save File|Choose Files|Select a File|Confirm|Authentication|File Upload|Open Folder|Save As).*$" },
float = true,
center = true,
})
hl.window_rule({
name = "fix-xwayland-drags",
match = { class = "^$", title = "^$", xwayland = true, float = true, fullscreen = false, pin = false },
no_focus = true,
})
7 changes: 4 additions & 3 deletions .config/hypr/hypridle.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Idle timeouts and Lua compositor commands; hypridle itself still uses Hyprlang.
general {
lock_cmd = pidof hyprlock || hyprlock
before_sleep_cmd = loginctl lock-session
after_sleep_cmd = hyprctl dispatch dpms on
after_sleep_cmd = hyprctl dispatch 'hl.dsp.dpms({ action = "on" })'
ignore_dbus_inhibit = false
}

Expand All @@ -18,8 +19,8 @@ listener {

listener {
timeout = 360
on-timeout = hyprctl dispatch dpms off
on-resume = hyprctl dispatch dpms on
on-timeout = hyprctl dispatch 'hl.dsp.dpms({ action = "off" })'
on-resume = hyprctl dispatch 'hl.dsp.dpms({ action = "on" })'
}

listener {
Expand Down
11 changes: 11 additions & 0 deletions .config/hypr/hyprland.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Load Samuel's desktop modules in dependency order, relative to this config.
require("conf.env")
require("conf.monitors")
require("conf.programs")
require("conf.autostart")
require("conf.look_and_feel")
require("conf.animations")
require("conf.layouts")
require("conf.input")
require("conf.keybinds")
require("conf.windowrules")
14 changes: 9 additions & 5 deletions .config/hypr/scripts/reload.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
#!/bin/bash
#!/usr/bin/env bash
# Reload the compositor and restart the bar/notifications through their launchers.
set -euo pipefail

notify-send "Hyprland" "Reloading configuration..."
# Validate the selected bar before restarting any desktop process.
[[ -x $HOME/.local/opt/waybar-lua/bin/waybar ]] || { echo 'Build Lua-capable Waybar first (docs/hyprland-lua.md).' >&2; exit 1; }

notify-send "Hyprland" "Reloading configuration..." || true

# Reload Hyprland
hyprctl reload

# Restart waybar
killall -9 waybar 2>/dev/null || true
nohup waybar </dev/null >/dev/null 2>&1 & disown
"$HOME/.config/waybar/scripts/launch.sh"

# Restart swaync
killall -9 swaync 2>/dev/null || true
nohup swaync </dev/null >/dev/null 2>&1 & disown

notify-send "Hyprland" "Reload complete!" -t 3000
notify-send "Hyprland" "Reload complete!" -t 3000 || true
3 changes: 2 additions & 1 deletion .config/rofi/scripts/powermenu.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
# Dispatch power-menu actions, using the Lua compositor API for logout.

# Options with Nerd Font icons
lock="󰌾 Lock"
Expand Down Expand Up @@ -29,7 +30,7 @@ case "$chosen" in
systemctl suspend
;;
"$logout")
hyprctl dispatch exit
hyprctl dispatch 'hl.dsp.exit()'
;;
"$reboot")
systemctl reboot
Expand Down
20 changes: 15 additions & 5 deletions .config/waybar/scripts/launch.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
#!/bin/bash

killall -9 waybar

nohup waybar </dev/null >/dev/null 2>&1 & disown
#!/usr/bin/env bash
# Start or restart the verified user-local Waybar without falling back to legacy IPC.
set -euo pipefail
mode=${1:-restart}
if (( $# > 1 )) || [[ $mode != restart && $mode != --start ]]; then
echo 'Usage: launch.sh [--start]' >&2
exit 2
fi
waybar_binary="$HOME/.local/opt/waybar-lua/bin/waybar"
[[ -x $waybar_binary ]] || { echo "Missing Lua-capable Waybar: $waybar_binary (see docs/hyprland-lua.md)" >&2; exit 1; }
if [[ $mode == --start ]]; then
exec "$waybar_binary"
fi
killall -9 waybar 2>/dev/null || true
nohup "$waybar_binary" </dev/null >/dev/null 2>&1 & disown
4 changes: 2 additions & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: sudo apt-get update && sudo apt-get install -y shellcheck jq
- run: sudo apt-get update && sudo apt-get install -y shellcheck jq luajit
- run: bash tests/run.sh
- name: ShellCheck changed shell scripts
run: shellcheck .config/hypr/scripts/wallpaper.sh .config/rofi/scripts/{wifi,clipboard_history,wallpaper}.sh scripts/apply-system-optimizations.sh tests/*.sh
run: shellcheck .config/hypr/scripts/{wallpaper,reload}.sh .config/waybar/scripts/launch.sh .config/rofi/scripts/{wifi,clipboard_history,wallpaper,powermenu}.sh scripts/{apply-system-optimizations,build-waybar}.sh tests/*.sh
42 changes: 29 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Hyprland desktop setup on Fedora Linux, styled with Catppuccin Mocha. Built for an AMD Ryzen 5 7600X and Radeon RX 6750 XT driving a 144Hz 1440p display.

The Lua migration targets Hyprland 0.56.2 and a pinned user-local Waybar build.
It is staged and must pass the build, review, and desktop checks before activation.
See [Lua migration, Waybar build, and rollback](docs/hyprland-lua.md).

> [!NOTE]
> Configured for Fedora, but works on any modern Wayland distribution with minor path adjustments. Update wallpaper paths in `~/.config/hypr/scripts/wallpaper.sh` to match your local files.

Expand All @@ -18,19 +22,20 @@ Hyprland desktop setup on Fedora Linux, styled with Catppuccin Mocha. Built for
│ │ ├── config.jsonc # System info display
│ │ └── my-logo.txt # Custom ASCII logo
│ ├── hypr/
│ │ ├── conf/ # Modular configuration
│ │ │ ├── animations.conf # Smooth slidefade transitions
│ │ │ ├── autostart.conf # Background daemons & polkit agent
│ │ │ ├── env.conf # Wayland and toolkit variables
│ │ │ ├── input.conf # Keyboard, mouse, and focus
│ │ │ ├── keybinds.conf # Hotkeys and layout bindings
│ │ │ ├── layouts.conf # Dwindle layout settings
│ │ │ ├── look_and_feel.conf# Gaps, borders, shadows, and blur
│ │ │ ├── monitors.conf # Resolution, refresh rate, and scale
│ │ │ ├── programs.conf # Default terminal, file manager, and launcher
│ │ │ └── windowrules.conf # Opacity, floating, and window placement
│ │ ├── conf/ # Ten Lua modules; original .conf files retained
│ │ │ ├── animations.lua # Smooth slidefade transitions
│ │ │ ├── autostart.lua # Background daemons & polkit agent
│ │ │ ├── env.lua # Wayland and toolkit variables
│ │ │ ├── input.lua # Keyboard, mouse, and focus
│ │ │ ├── keybinds.lua # Hotkeys and layout bindings
│ │ │ ├── layouts.lua # Dwindle layout settings
│ │ │ ├── look_and_feel.lua # Gaps, borders, shadows, and blur
│ │ │ ├── monitors.lua # Resolution, refresh rate, and scale
│ │ │ ├── programs.lua # Default terminal, file manager, and launcher
│ │ │ └── windowrules.lua # Floating and window placement
│ │ ├── hypridle.conf # Screen dimming and sleep triggers
│ │ ├── hyprland.conf # Root entry point (sources conf/*.conf)
│ │ ├── hyprland.lua # Maintained entry point (requires conf/*.lua)
│ │ ├── hyprland.conf # Frozen legacy entry point for rollback
│ │ ├── hyprlock.conf # Lock screen with frosted blur
│ │ └── scripts/
│ │ ├── reload.sh # Reload compositor, bar, and notifications
Expand Down Expand Up @@ -60,6 +65,7 @@ Hyprland desktop setup on Fedora Linux, styled with Catppuccin Mocha. Built for
├── assets/ # Screenshots and demo media
├── scripts/
│ ├── apply-system-optimizations.sh # DNF, tuned profile, and service tweaks
│ ├── build-waybar.sh # Build/test/select the pinned local Waybar
│ └── install-symlinks.sh # Idempotent symlink installer for ~/.config
└── README.md
```
Expand Down Expand Up @@ -162,6 +168,10 @@ do not replace those links to run this installer.

To link all configuration directories (`hypr`, `waybar`, `kitty`, `rofi`, `swaync`, `fastfetch`, `btop`, `starship.toml`) to `~/.config/`:

For the Lua migration, first follow the staged verification and activation procedure
in [the migration guide](docs/hyprland-lua.md). The general installer immediately
links this checkout and is not a preview operation.

```bash
./scripts/install-symlinks.sh
```
Expand All @@ -184,9 +194,15 @@ changes and rollback. Previously applied system settings are left in place.

## Verification

Run `bash tests/run.sh` for shell syntax and isolated regression checks. Tests use
Run `bash tests/run.sh` for shell syntax and isolated regression checks (requires
Python 3, LuaJIT, jq, and Bash). Tests use
mock commands and temporary homes; they do not alter the running desktop.

Lua preservation checks cover all 63 bindings and configuration values. Validate
the actual API separately with `Hyprland --verify-config --config "$PWD/.config/hypr/hyprland.lua"`.
The [migration guide](docs/hyprland-lua.md) includes the Waybar build, CodeRabbit
review gate, and required fresh-login acceptance checks.

The workspace wallpaper listener has one owner per Hyprland session. `SUPER+A`
runs `wallpaper.sh --once` to refresh without creating another listener. Workspaces
6–10 retain the last wallpaper. Missing images and daemon failures go to stderr.
Expand Down
Loading
Loading