Files
hyprland-rising/hypr/hyprland.lua
T
aibrashandClaude Sonnet 5.5 af3b12a131 Restore the binds that the resize change removed by mistake
d6d8aa0 cut the whole range between the resize submap and the screenshots
section, which also deleted the "sysadmin toolbox" binds: Mod+S (SSH menu),
Mod+T/B/K, Mod+Shift+B/T, Mod+F1 (cheatsheet), Mod+[ ], Mod+, and Mod+.
Put them back; the resize change itself is unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 14:13:41 +05:00

277 lines
15 KiB
Lua

-- Hyprland 0.57 (Lua). Clean dark work setup; shell = DankMaterialShell.
-- Sway config stays in ~/.config/sway as a fallback session.
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; sway had sway-session.target for this
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 (sway smart_gaps equivalent).
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, like sway's focus_follows_mouse no
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 })