lock.sh no longer falls back to swaylock (hyprlock instead), and the comments in hyprland.lua and the README no longer mention sway. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
277 lines
15 KiB
Lua
277 lines
15 KiB
Lua
-- Hyprland 0.57 (Lua). Clean dark work setup; shell = DankMaterialShell.
|
|
-- Fallback login session: GNOME (via GDM).
|
|
|
|
local terminal = "kitty"
|
|
local mod = "SUPER"
|
|
|
|
----------------
|
|
---- OUTPUT ----
|
|
----------------
|
|
-- eDP-1 at 1.25 scale is 1536 logical px wide, so HDMI sits right of it.
|
|
hl.monitor({ output = "eDP-1", mode = "preferred", position = "0x0", scale = 1.25 })
|
|
hl.monitor({ output = "HDMI-A-1", mode = "preferred", position = "1536x0", scale = 1 })
|
|
hl.monitor({ output = "", mode = "preferred", position = "auto", scale = "auto" })
|
|
|
|
-----------------
|
|
---- STARTUP ----
|
|
-----------------
|
|
hl.env("XCURSOR_SIZE", "24")
|
|
hl.env("HYPRCURSOR_SIZE", "24")
|
|
hl.env("XDG_CURRENT_DESKTOP", "Hyprland")
|
|
hl.env("XDG_SESSION_TYPE", "wayland")
|
|
hl.env("QT_QPA_PLATFORM", "wayland;xcb")
|
|
hl.env("ELECTRON_OZONE_PLATFORM_HINT", "auto")
|
|
|
|
hl.on("hyprland.start", function()
|
|
hl.exec_cmd("dbus-update-activation-environment --systemd WAYLAND_DISPLAY DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP XDG_SESSION_TYPE")
|
|
hl.exec_cmd("systemctl --user import-environment WAYLAND_DISPLAY DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP XDG_SESSION_TYPE")
|
|
-- portals (file pickers, screen sharing, Nautilus) need graphical-session.target, which is not started outside uwsm
|
|
hl.exec_cmd("systemctl --user start hyprland-session.target")
|
|
hl.exec_cmd("sh -c 'pgrep -x dms >/dev/null || exec dms run'")
|
|
hl.exec_cmd("systemctl --user start hyprpolkitagent")
|
|
hl.exec_cmd("hypridle")
|
|
hl.exec_cmd("nm-applet --indicator")
|
|
hl.exec_cmd("wl-paste --type text --watch cliphist store")
|
|
hl.exec_cmd("wl-paste --type image --watch cliphist store")
|
|
hl.exec_cmd(terminal .. " --class scratch")
|
|
hl.exec_cmd("sh -c 'sleep 5; flatpak info com.nextcloud.desktopclient.nextcloud >/dev/null 2>&1 && ! pgrep -f \"[n]extcloud.*--background\" >/dev/null && flatpak run com.nextcloud.desktopclient.nextcloud --background'")
|
|
hl.exec_cmd("sh -c 'sleep 5; flatpak info org.remmina.Remmina >/dev/null 2>&1 && ! pgrep -f \"[R]emmina.* -i\" >/dev/null && flatpak run org.remmina.Remmina -i'")
|
|
hl.exec_cmd("sh -c 'sleep 8; command -v geary >/dev/null && ! pgrep -x geary >/dev/null && geary --gapplication-service'")
|
|
end)
|
|
|
|
-----------------------
|
|
---- LOOK AND FEEL ----
|
|
-----------------------
|
|
hl.config({
|
|
general = {
|
|
gaps_in = 6,
|
|
gaps_out = 14,
|
|
border_size = 2,
|
|
col = {
|
|
active_border = { colors = { "rgba(e91e63ff)", "rgba(ff6398ff)", "rgba(f8bbd9ff)", "rgba(e91e63ff)" }, angle = 45 },
|
|
inactive_border = "rgba(3a2a2eaa)",
|
|
},
|
|
resize_on_border = true,
|
|
allow_tearing = false,
|
|
layout = "dwindle",
|
|
},
|
|
decoration = {
|
|
rounding = 16,
|
|
rounding_power = 4, -- squircle corners
|
|
active_opacity = 1.0,
|
|
inactive_opacity = 0.96,
|
|
dim_inactive = true,
|
|
dim_strength = 0.06,
|
|
shadow = {
|
|
enabled = true,
|
|
range = 30,
|
|
render_power = 3,
|
|
color = 0x66e91e63, -- soft pink glow on the focused window
|
|
color_inactive = 0x66000000,
|
|
},
|
|
blur = {
|
|
enabled = true,
|
|
size = 10,
|
|
passes = 4,
|
|
noise = 0.02,
|
|
vibrancy = 0.3,
|
|
brightness = 1.05,
|
|
popups = true,
|
|
},
|
|
},
|
|
animations = { enabled = true },
|
|
binds = { workspace_back_and_forth = true },
|
|
dwindle = { preserve_split = true, force_split = 2 }, -- new window always opens to the right/below
|
|
xwayland = { force_zero_scaling = true }, -- crisp X11 apps on the 1.25x laptop panel
|
|
cursor = { hide_on_key_press = true, inactive_timeout = 5 },
|
|
misc = {
|
|
force_default_wallpaper = 0,
|
|
disable_hyprland_logo = true,
|
|
focus_on_activate = true,
|
|
key_press_enables_dpms = true, -- wake the screen on any key / mouse move (hypridle turns it off)
|
|
mouse_move_enables_dpms = true,
|
|
animate_manual_resizes = true,
|
|
animate_mouse_windowdragging = 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("quick", { type = "bezier", points = { {0.15, 0}, {0.1, 1} } })
|
|
hl.curve("linear", { type = "bezier", points = { {0, 0}, {1, 1} } })
|
|
hl.curve("snappy", { type = "spring", mass = 1, stiffness = 340, damping = 24 })
|
|
hl.curve("bouncy", { type = "spring", mass = 1, stiffness = 280, damping = 17 })
|
|
|
|
hl.animation({ leaf = "global", enabled = true, speed = 10, bezier = "default" })
|
|
hl.animation({ leaf = "border", enabled = true, speed = 4, bezier = "easeOutQuint" })
|
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 60, bezier = "linear", style = "loop" }) -- slowly rotating gradient border
|
|
hl.animation({ leaf = "windows", enabled = true, speed = 3.2, spring = "snappy" })
|
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 3.0, spring = "bouncy", style = "popin 88%" })
|
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 1.2, bezier = "quick", style = "popin 88%" })
|
|
hl.animation({ leaf = "fade", enabled = true, speed = 2, bezier = "quick" })
|
|
hl.animation({ leaf = "fadeDim", enabled = true, speed = 2.5, bezier = "quick" })
|
|
hl.animation({ leaf = "layers", enabled = true, speed = 2.6, bezier = "easeOutQuint" })
|
|
hl.animation({ leaf = "layersIn", enabled = true, speed = 2.6, bezier = "easeOutQuint", style = "slide" })
|
|
hl.animation({ leaf = "layersOut", enabled = true, speed = 1.0, bezier = "quick", style = "fade" })
|
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 3.0, bezier = "easeInOutCubic", style = "slide" })
|
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 2.8, bezier = "easeOutQuint", style = "slidevert" })
|
|
|
|
-- No gaps/border/rounding for a single tiled window.
|
|
hl.workspace_rule({ workspace = "w[tv1]", gaps_out = 0, gaps_in = 0 })
|
|
hl.workspace_rule({ workspace = "f[1]", gaps_out = 0, gaps_in = 0 })
|
|
hl.window_rule({ name = "smart-gaps-1", match = { float = false, workspace = "w[tv1]" }, border_size = 0, rounding = 0 })
|
|
hl.window_rule({ name = "smart-gaps-2", match = { float = false, workspace = "f[1]" }, border_size = 0, rounding = 0 })
|
|
|
|
---------------
|
|
---- INPUT ----
|
|
---------------
|
|
hl.config({
|
|
input = {
|
|
kb_layout = "us,ru",
|
|
kb_options = "grp:alt_shift_toggle,grp_led:scroll",
|
|
follow_mouse = 2, -- click to focus; the cursor can still cross other windows
|
|
sensitivity = -0.5,
|
|
touchpad = {
|
|
natural_scroll = true,
|
|
tap_to_click = true,
|
|
tap_button_map = "lrm",
|
|
disable_while_typing = true,
|
|
middle_button_emulation = true,
|
|
},
|
|
},
|
|
})
|
|
hl.device({ name = "type:touchpad", sensitivity = 0.3 })
|
|
hl.gesture({ fingers = 3, direction = "horizontal", action = "workspace" })
|
|
|
|
---------------------
|
|
---- KEYBINDINGS ----
|
|
---------------------
|
|
local function b(keys, dsp, opts) hl.bind(keys, dsp, opts) end
|
|
local function dms(args) return hl.dsp.exec_cmd("dms ipc call " .. args) end
|
|
|
|
b(mod .. " + Return", hl.dsp.exec_cmd(terminal))
|
|
b(mod .. " + SHIFT + Q", hl.dsp.window.close())
|
|
b(mod .. " + D", dms("spotlight toggle"))
|
|
b(mod .. " + SHIFT + E", dms("powermenu toggle"))
|
|
b(mod .. " + SHIFT + P", dms("powermenu toggle"))
|
|
b(mod .. " + SHIFT + C", hl.dsp.reload_config())
|
|
b(mod .. " + N", dms("control-center toggle"))
|
|
b(mod .. " + SHIFT + N", dms("notifications toggle"))
|
|
b(mod .. " + SHIFT + V", dms("clipboard toggle"))
|
|
b(mod .. " + SHIFT + X", hl.dsp.exec_cmd("~/.config/hypr/scripts/lock.sh"))
|
|
b(mod .. " + O", hl.dsp.exec_cmd("nautilus --new-window"))
|
|
|
|
-- focus / move (vim keys + arrows)
|
|
local dirs = { h = "left", j = "down", k = "up", l = "right", left = "left", down = "down", up = "up", right = "right" }
|
|
for key, d in pairs(dirs) do
|
|
b(mod .. " + " .. key, hl.dsp.focus({ direction = d }))
|
|
b(mod .. " + SHIFT + " .. key, hl.dsp.window.move({ direction = d }))
|
|
end
|
|
|
|
-- layout
|
|
b(mod .. " + F", hl.dsp.window.fullscreen())
|
|
b(mod .. " + SHIFT + SPACE", hl.dsp.window.float({ action = "toggle" }))
|
|
b(mod .. " + SHIFT + F", hl.dsp.window.float({ action = "toggle" }))
|
|
b(mod .. " + C", hl.dsp.window.center())
|
|
b(mod .. " + E", hl.dsp.layout("togglesplit"))
|
|
b(mod .. " + P", hl.dsp.window.pseudo())
|
|
b(mod .. " + W", hl.dsp.group.toggle())
|
|
b("ALT + TAB", hl.dsp.exec_cmd("~/.config/hypr/scripts/prev-window.sh")) -- previous window (press again to go back)
|
|
b(mod .. " + ALT + TAB", hl.dsp.window.cycle_next()) -- next window on this workspace
|
|
b(mod .. " + TAB", hl.dsp.focus({ workspace = "e+1" }))
|
|
b(mod .. " + SHIFT + TAB", hl.dsp.focus({ workspace = "e-1" }))
|
|
b(mod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
|
|
b(mod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
|
|
|
|
-- workspaces 1..10
|
|
for i = 1, 10 do
|
|
local key = i % 10
|
|
b(mod .. " + " .. key, hl.dsp.focus({ workspace = i }))
|
|
b(mod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i }))
|
|
end
|
|
|
|
-- scratchpad
|
|
b(mod .. " + grave", hl.dsp.workspace.toggle_special("scratch"))
|
|
b(mod .. " + SHIFT + minus", hl.dsp.window.move({ workspace = "special:scratch" }))
|
|
b(mod .. " + minus", hl.dsp.workspace.toggle_special("scratch"))
|
|
|
|
-- mouse
|
|
b(mod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
|
b(mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
|
|
|
-- resize the focused window without a mode: Mod+Ctrl + h/j/k/l or arrows (hold to repeat)
|
|
local rs = { h = {-40, 0}, l = {40, 0}, k = {0, -40}, j = {0, 40}, left = {-40, 0}, right = {40, 0}, up = {0, -40}, down = {0, 40} }
|
|
for key, d in pairs(rs) do
|
|
b(mod .. " + CTRL + " .. key, hl.dsp.window.resize({ x = d[1], y = d[2], relative = true }), { repeating = true })
|
|
end
|
|
|
|
-- sysadmin toolbox
|
|
b(mod .. " + S", hl.dsp.exec_cmd("kitty --class ssh-menu -o font_size=12 -o env=SSH_MENU=1 --title 'ssh menu' ~/.config/hypr/scripts/ssh-menu.sh")) -- SSH hub (fzf)
|
|
local raise = "~/.config/hypr/scripts/raise.sh "
|
|
b(mod .. " + T", hl.dsp.exec_cmd(raise .. "'^org.telegram.desktop$' flatpak run org.telegram.desktop")) -- focus if open, else launch
|
|
b(mod .. " + B", hl.dsp.exec_cmd(raise .. "'^google-chrome$' flatpak run com.google.Chrome")) -- again = next Chrome window
|
|
b(mod .. " + SHIFT + B", hl.dsp.exec_cmd("flatpak run com.google.Chrome --new-window")) -- always a new window
|
|
b(mod .. " + F1", hl.dsp.exec_cmd("~/.config/hypr/scripts/cheatsheet.sh")) -- hotkey reference
|
|
b(mod .. " + K", hl.dsp.exec_cmd(raise .. "'^org.keepassxc.KeePassXC$' keepassxc"))
|
|
b(mod .. " + SHIFT + T", hl.dsp.window.pin()) -- keep a floating window on top
|
|
b(mod .. " + bracketright", hl.dsp.group.next())
|
|
b(mod .. " + bracketleft", hl.dsp.group.prev())
|
|
|
|
-- two monitors: laptop <-> external (focus only)
|
|
b(mod .. " + comma", hl.dsp.focus({ monitor = "-1" }))
|
|
b(mod .. " + period", hl.dsp.focus({ monitor = "+1" }))
|
|
|
|
-- screenshots (grim + slurp; saved to ~/Pictures/Screenshots and copied)
|
|
local shot = "mkdir -p ~/Pictures/Screenshots; f=~/Pictures/Screenshots/$(date +%F_%H-%M-%S).png; "
|
|
b("Print", hl.dsp.exec_cmd(shot .. "grim -g \"$(slurp)\" - | tee $f | wl-copy"))
|
|
b(mod .. " + SHIFT + S", hl.dsp.exec_cmd(shot .. "grim -g \"$(slurp)\" - | tee $f | wl-copy"))
|
|
b("SHIFT + Print", hl.dsp.exec_cmd(shot .. "grim - | tee $f | wl-copy"))
|
|
b("CTRL + Print", hl.dsp.exec_cmd(shot .. "grim -g \"$(hyprctl activewindow -j | jq -r '\"\\(.at[0]),\\(.at[1]) \\(.size[0])x\\(.size[1])\"')\" - | tee $f | wl-copy"))
|
|
b(mod .. " + CTRL + C", hl.dsp.exec_cmd("hyprpicker -a")) -- color picker
|
|
b(mod .. " + SHIFT + O", hl.dsp.exec_cmd("~/.config/hypr/scripts/ocr.sh")) -- screen region -> text in clipboard
|
|
|
|
-- media / brightness / volume via DMS (shows OSD)
|
|
b("XF86AudioRaiseVolume", dms("audio increment 5"), { locked = true, repeating = true })
|
|
b("XF86AudioLowerVolume", dms("audio decrement 5"), { locked = true, repeating = true })
|
|
b("XF86AudioMute", dms("audio mute"), { locked = true })
|
|
b("XF86AudioMicMute", dms("audio micmute"), { locked = true })
|
|
b("XF86MonBrightnessUp", dms("brightness increment 5 \"\""), { locked = true, repeating = true })
|
|
b("XF86MonBrightnessDown", dms("brightness decrement 5 \"\""), { locked = true, repeating = true })
|
|
b("XF86AudioPlay", dms("mpris playPause"), { locked = true })
|
|
b("XF86AudioNext", dms("mpris next"), { locked = true })
|
|
b("XF86AudioPrev", dms("mpris previous"), { locked = true })
|
|
|
|
-----------------
|
|
---- RULES ------
|
|
-----------------
|
|
hl.window_rule({ name = "suppress-maximize", match = { class = ".*" }, suppress_event = "maximize" })
|
|
hl.window_rule({
|
|
name = "xwayland-drag-fix",
|
|
match = { class = "^$", title = "^$", xwayland = true, float = true, fullscreen = false, pin = false },
|
|
no_focus = true,
|
|
})
|
|
hl.window_rule({
|
|
name = "float-utils",
|
|
match = { class = "^(pavucontrol|nm-connection-editor|blueman-manager|org.pulseaudio.pavucontrol)$" },
|
|
float = true, size = "700 500", center = true,
|
|
})
|
|
hl.window_rule({ name = "float-mpv", match = { class = "^mpv$" }, float = true })
|
|
hl.window_rule({ name = "idle-inhibit-fs", match = { class = "^(firefox|mpv|google-chrome|org.telegram.desktop)$" }, idle_inhibit = "fullscreen" })
|
|
-- no auto-lock in the middle of an RDP/VNC session
|
|
hl.window_rule({ name = "idle-inhibit-rdp", match = { class = "^(org.remmina.Remmina|com.freerdp.FreeRDP|xfreerdp)$" }, idle_inhibit = "focus" })
|
|
-- file dialogs from the portal and Chrome picture-in-picture
|
|
hl.window_rule({ name = "float-portal-dialogs", match = { class = "^xdg-desktop-portal-gtk$" }, float = true, size = "900 600", center = true })
|
|
hl.window_rule({ name = "pip", match = { title = "^Picture in picture$" }, float = true, pin = true, size = "480 270", move = "monitor_w-500 monitor_h-290" })
|
|
hl.window_rule({
|
|
name = "scratch-term",
|
|
match = { class = "^scratch$" },
|
|
workspace = "special:scratch silent", float = true, size = "1000 560", center = true,
|
|
})
|
|
|
|
hl.window_rule({ name = "float-ssh-menu", match = { class = "^ssh-menu$" }, float = true, size = "1400 780", center = true })
|
|
hl.window_rule({ name = "float-keepass", match = { class = "^org.keepassxc.KeePassXC$" }, float = true, size = "1300 860", center = true })
|
|
|
|
-- Blur the DMS surfaces (bar, launcher, popups, notifications).
|
|
hl.layer_rule({ name = "dms-blur", match = { namespace = "^dms:.*" }, blur = true, blur_popups = true, ignore_alpha = 0.3 })
|
|
hl.layer_rule({ name = "noanim-slurp", match = { namespace = "^selection$" }, no_anim = true })
|