Files
hypr/hyprland.lua
T
2026-06-28 14:42:47 -04:00

307 lines
12 KiB
Lua

-- ~/.config/hypr/hyprland.luaA
-----------------------------------------------------
-- Variables (from variables.conf)
-----------------------------------------------------
local copy = "wl-copy --trim-newline"
local paste = "wl-paste"
local launcher = "rofi -show run -p 'launch'"
-- local clear = "cliphist list | head -n1 | cliphist delete"
-----------------------------------------------------
-- Monitors (from monitors.conf)
-----------------------------------------------------
hl.monitor({ output = "desc:Ancor Communications Inc ASUS VS228 E3LMTF071438", mode = "preferred", position = "0x0", scale = "1" }) -- DP-7, left
hl.monitor({ output = "desc:Samsung Display Corp. 0x4193", mode = "preferred", position = "1920x0", scale = "2" }) -- eDP-1, center
hl.monitor({ output = "desc:Ancor Communications Inc ASUS VS228 E3LMTF071391", mode = "preferred", position = "3360x0", scale = "1" }) -- DP-8, right
hl.monitor({ output = "desc:Stargate Technology FHD", mode = "preferred", position = "auto", scale = "auto" }) -- portable monitor
-----------------------------------------------------
-- Environment Variables (from env.conf)
-----------------------------------------------------
hl.env("GDK_BACKEND", "wayland,x11,*")
hl.env("GUI_ENABLE_WAYLAND", "1")
hl.env("HYPRCURSOR_SIZE", "18")
hl.env("QT_QPA_PLATFORM", "wayland;xcb")
hl.env("QT_QPA_PLATFORMTHEME", "qt6ct")
hl.env("QT_AUTO_SCREEN_SCALE_FACTOR", "1")
hl.env("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1")
hl.env("XCURSOR_SIZE", "18")
hl.env("XDG_CURRENT_DESKTOP", "Hyprland")
hl.env("XDG_SESSION_TYPE", "wayland")
hl.env("XDG_SESSION_DESKTOP", "Hyprland")
-----------------------------------------------------
-- Appearance & Input (from appearance.conf & input.conf)
-----------------------------------------------------
hl.config({
general = {
gaps_in = 1,
gaps_out = 2,
border_size = 2,
col = {
active_border = "rgba(fabd2f99)",
inactive_border = "rgba(595959aa)",
},
resize_on_border = false,
allow_tearing = false,
layout = "dwindle"
},
decoration = {
rounding = 10,
rounding_power = 2,
active_opacity = 1.0,
inactive_opacity = 1.0,
shadow = {
enabled = true,
range = 4,
render_power = 3,
color = "rgba(1a1a1aee)"
},
blur = {
enabled = true,
size = 3,
passes = 1,
vibrancy = 0.1696
}
},
animations = {
enabled = true,
bezier = {
"easeOutQuint,0.23,1,0.32,1",
"easeInOutCubic,0.65,0.05,0.36,1",
"linear,0,0,1,1",
"almostLinear,0.5,0.5,0.75,1.0",
"quick,0.15,0,0.1,1"
},
animation = {
"global, 1, 10, default",
"border, 1, 5.39, easeOutQuint",
"windows, 1, 4.79, easeOutQuint",
"windowsIn, 1, 4.1, easeOutQuint, popin 87%",
"windowsOut, 1, 1.49, linear, popin 87%",
"fadeIn, 1, 1.73, almostLinear",
"fadeOut, 1, 1.46, almostLinear",
"fade, 1, 3.03, quick",
"layers, 1, 3.81, easeOutQuint",
"layersIn, 1, 4, easeOutQuint, fade",
"layersOut, 1, 1.5, linear, fade",
"fadeLayersIn, 1, 1.79, almostLinear",
"fadeLayersOut, 1, 1.39, almostLinear",
"workspaces, 1, 1.94, almostLinear, fade",
"workspacesIn, 1, 1.21, almostLinear, fade",
"workspacesOut, 1, 1.94, almostLinear, fade"
}
},
dwindle = { preserve_split = true },
master = { new_status = "master" },
misc = {
on_focus_under_fullscreen = 1,
force_default_wallpaper = 0,
disable_hyprland_logo = true
},
input = {
resolve_binds_by_sym = 1,
kb_layout = "us, us",
kb_variant = "colemak,",
kb_options = "ctrl:nocaps, compose:ralt, grp:ctrls_toggle",
follow_mouse = 1,
sensitivity = 0,
touchpad = { natural_scroll = false }
}})
hl.device({
name = "epic-mouse-v1",
sensitivity = -0.5
})
-----------------------------------------------------
-- Window Rules (from windowrules.conf)
-----------------------------------------------------
-- XWayland dragging
hl.window_rule({
no_focus = true,
match = { xwayland = true, float = true, fullscreen = false, pin = false }
})
-- Floating rules
local float_class_regex = "(gcr-prompter|qt5ct|qt6ct|simple-scan|espanso|nm-applet)"
local float_title_regex = "(\"HP Device Manager - Plug-in Installer\")"
local float_regex = "(" .. float_class_regex .. "|" .. float_title_regex .. ")"
hl.window_rule({ float = true, match = { class = float_class_regex } })
hl.window_rule({ float = true, match = { title = float_title_regex } })
-- Pin rules
local pin_regex = "(gcr-prompter|nm-applet)"
hl.window_rule({ pin = true, match = { class = pin_regex } })
-- Maximize everything else (fixed typo fioat_regex -> float_regex)
hl.window_rule({
maximize = true,
match = { class = "negative:" .. float_regex }
})
-- Espanso on special
hl.window_rule({
workspace = "special",
match = { title = "Espanso Sync Tool" }
})
-- App-specific workspaces
local browsers = "(.*qutebrowser.*|.*[Ff]irefox.*)"
local meeting = "(.*[Zz]oom.*)"
hl.window_rule({ workspace = "name:shell", match = { class = ".*[Aa]lacritty.*" } })
hl.window_rule({ workspace = "name:browser silent", match = { class = browsers } })
hl.window_rule({ workspace = "name:jobs silent", match = { class = ".*[Vv]ivaldi-stable.*" } })
hl.window_rule({ workspace = "name:meeting silent", match = { class = meeting } })
-----------------------------------------------------
-- Workspaces (from workspaces.conf)
-----------------------------------------------------
require("workspaces")
-----------------------------------------------------
-- Keybindings & Macros (from keybindings.conf & macros.conf)
-----------------------------------------------------
local bind = hl.bind
local dsp = hl.dsp
local fn = require("functions")
bind("SUPER + Q", dsp.exec_cmd("hyprctl reload && killall -SIGUSR2 waybar && notify-send 'Hyprland' 'Config Reloaded' -u low -t 2000"))
-- BUG FIX: SUPER + SHIFT + Q was bound to both tmux kill and uwsm stop.
-- bind("SUPER + SHIFT + Q", dsp.exec_cmd("tmux kill-server"))
bind("SUPER + SHIFT + Q", dsp.exec_cmd("killall -q signal-desktop; uwsm stop"))
bind("CTRL + ALT + Delete", dsp.exec_cmd("bash ~/.config/hypr/scripts/sysmenu.sh"))
bind("SUPER + L", dsp.exec_cmd("hyprlock"))
bind("switch:Lid Switch", dsp.exec_cmd("hyprlock"))
-- Screenshots (evaluated natively in Lua at keypress time)
bind("CTRL + SHIFT + 3", function()
local cmd = string.format("grim 'images/screenshots/%s_screenshot.png' && paplay ~/wav/camera.wav", os.date("%FT%H%M%S"))
hl.dispatch(hl.dsp.exec_cmd(cmd))
end)
bind("CTRL + SHIFT + 4", function()
local cmd = string.format("slurp | grim -g - '%s_screenshot.png' && paplay ~/wav/camera.wav", os.date("%FT%H%M%S"))
hl.dispatch(hl.dsp.exec_cmd(cmd))
end)
-- App launchers using our custom Lua focusOrLaunch function
bind("SUPER + return", function() fn.focusOrLaunch("alacritty", "Alacritty") end)
bind("SUPER + SHIFT + A", function() fn.focusOrLaunch("slack", "Slack", "Slack") end)
bind("SUPER + SHIFT + D", function() fn.focusOrLaunch("gnome-dictionary", "org.gnome.Dictionary", "org.gnome.Dictionary") end)
bind("SUPER + G", function() fn.focusOrLaunch("vivaldi-stable", "vivaldi-stable", "vivaldi-stable") end)
bind("SUPER + ALT + H", function() fn.focusOrLaunch("qutebrowser", "org.qutebrowser.qutebrowser") end)
-- Windows 11 equivalent shortcuts
bind("SUPER + S", dsp.exec_cmd(launcher)) -- Win+S for Search/Launcher
bind("SUPER + R", dsp.exec_cmd(launcher)) -- Win+R for Run
bind("SUPER + E", dsp.exec_cmd("nautilus")) -- Win+E for Explorer
bind("SUPER + V", dsp.exec_cmd("cliphist list | rofi -dmenu -p 'paste' | cliphist decode | " .. copy .. " && " .. paste)) -- Win+V for Clipboard
bind("SUPER + SHIFT + S", function() fn.focusOrLaunch("pavucontrol", "org.pulseaudio.pavucontrol", "org.pulseaudio.pavucontrol") end)
-- Window control
bind("SUPER + C", dsp.window.close())
bind("ALT + F4", dsp.window.close())
bind("SUPER + T", dsp.window.float({ action = "toggle" }))
bind("SUPER + space", dsp.window.fullscreen({ mode = 1 }))
-- Cycle Layouts
local layouts = { "dwindle", "master", "scrolling" }
local layout_icons = { dwindle = "", master = "", scrolling = "" }
local layout_idx = 1
local function cycle_layout()
layout_idx = (layout_idx % #layouts) + 1
local new_layout = layouts[layout_idx]
hl.config({ general = { layout = new_layout } })
os.execute("echo '" .. layout_icons[new_layout] .. "' > /tmp/hypr_layout.txt")
os.execute("pkill -RTMIN+8 waybar")
end
bind("SUPER + right", function() cycle_layout() end)
bind("SUPER + left", function() cycle_layout() end)
bind("SUPER + up", dsp.window.fullscreen({ mode = 1 }))
bind("SUPER + down", hl.dsp.window.cycle_next())
-- XMonad-style cycle & Alt+Tab (using native dsp dispatchers)
bind("SUPER + J", hl.dsp.window.cycle_next())
bind("SUPER + K", hl.dsp.window.cycle_next({ prev = true }))
bind("ALT + Tab", hl.dsp.window.cycle_next())
bind("ALT + SHIFT + Tab", hl.dsp.window.cycle_next({ prev = true }))
bind("SUPER + X", dsp.exec_cmd("dunstctl close"))
bind("SUPER + Y", dsp.exec_cmd("dunstctl close-all"))
-- Workspace control
bind("SUPER + CTRL + right", function() hl.dispatch(hl.dsp.focus({ workspace = "m+1" })) end)
bind("SUPER + CTRL + left", function() hl.dispatch(hl.dsp.focus({ workspace = "m-1" })) end)
bind("SUPER + SHIFT + H", function() hl.dispatch(hl.dsp.focus({ workspace = "m-1" })) end)
bind("SUPER + SHIFT + L", function() hl.dispatch(hl.dsp.focus({ workspace = "m+1" })) end)
bind("SUPER + SHIFT + M", function() fn.mv2workspace() end)
bind("SUPER + SHIFT + N", function() fn.createWorkspace() end)
bind("SUPER + SHIFT + X", function() fn.deleteWorkspace() end)
bind("SUPER + SHIFT + Z", function() fn.createWorkspace(fn.getActiveWorkspaceName()) end)
bind("SUPER + SHIFT + left", function() fn.moveWorkspace(-1) end)
bind("SUPER + SHIFT + right", function() fn.moveWorkspace(1) end)
bind("SUPER + ALT + DOWN", function() fn.moveWorkspace(nil, "DP-8") end)
-- Laptop keys
bind("XF86MonBrightnessUp", dsp.exec_cmd("brightnessctl -- set +10%"))
bind("XF86MonBrightnessDown", dsp.exec_cmd("brightnessctl -- set -10%"))
-- Macros (uses fn.pasteText and native Lua os.time/os.date instead of bash scripts)
bind("SUPER + CTRL + S", function() fn.pasteText(os.date("%F")) end)
bind("SUPER + CTRL + N", function() fn.pasteText(os.date("%FT%T %z")) end)
bind("SUPER + CTRL + Y", function() fn.pasteText(os.date("%F", os.time() - 86400)) end)
bind("SUPER + CTRL + T", function() fn.pasteText(os.date("%F", os.time() + 86400)) end)
-- Timetracker Macro
bind("CTRL + SHIFT + S", function() fn.timetracker() end)
-- Bitwarden Macro
bind("SUPER + CTRL + 1", function() fn.pasteMacro("secret-tool lookup app bw") end)
-----------------------------------------------------
-- Autostart (from autostart.conf)
-----------------------------------------------------
hl.on("hyprland.start", function()
hl.exec_cmd("dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP")
hl.exec_cmd("hyprpolkitagent")
hl.exec_cmd("uwsm app -- hypridle")
hl.exec_cmd("uwsm app -- hyprpaper")
hl.exec_cmd("uwsm app -- waybar")
hl.exec_cmd("uwsm app -- espanso start")
hl.exec_cmd("uwsm app -- dunst")
hl.exec_cmd("nm-applet")
hl.exec_cmd("signal-desktop")
hl.exec_cmd("hp-systray")
hl.exec_cmd("blueman-applet")
hl.exec_cmd("wl-paste --watch cliphist store")
hl.exec_cmd("wl-clip-persist --clipboard regular")
hl.exec_cmd("qutebrowser")
hl.exec_cmd("vivaldi-stable")
hl.exec_cmd("alacritty")
-- Start the battery low-level notifier
hl.exec_cmd("bash ~/.config/hypr/scripts/battery-notify.sh")
-- Randomize wallpapers after hyprpaper has time to start
hl.exec_cmd("sleep 2 && hyprctl eval 'require(\"functions\").randomizeWallpaper()'")
end)