ed063ab1fe
Capture desktop-specific system, session, Noctalia, and Pi integration alongside shared laptop support. Retire obsolete X11 configuration and make package ownership explicit for repeatable Decman deployments.
165 lines
8.1 KiB
Lua
165 lines
8.1 KiB
Lua
-- Shared Hyprland profile. yadm deploys machine.lua for the active class.
|
|
--
|
|
-- Scope: preserve launch, media, directional focus/move, workspace, scratchpad,
|
|
-- floating, fullscreen, and window-placement muscle memory. i3's split-tree,
|
|
-- stacking/tabbed, and resize-mode behavior is intentionally deferred.
|
|
local machine = dofile(os.getenv("HOME") .. "/.config/hypr/machine.lua")
|
|
|
|
for _, monitor in ipairs(machine.monitors or {}) do
|
|
hl.monitor(monitor)
|
|
end
|
|
|
|
local main_mod = "SUPER"
|
|
local terminal = "kitty"
|
|
|
|
local input = {
|
|
kb_layout = "us",
|
|
kb_variant = "intl",
|
|
numlock_by_default = true,
|
|
}
|
|
for key, value in pairs(machine.input or {}) do
|
|
input[key] = value
|
|
end
|
|
|
|
hl.config({
|
|
input = input,
|
|
general = {
|
|
gaps_in = 4,
|
|
-- Keep a thin black perimeter so the bottom border remains on-screen.
|
|
gaps_out = 2,
|
|
border_size = 2,
|
|
col = {
|
|
-- Muted Ember tones: visible focus without a high-brightness OLED edge.
|
|
active_border = "rgba(c9782ed9)",
|
|
inactive_border = "rgba(2a190fa6)",
|
|
},
|
|
},
|
|
decoration = {
|
|
rounding = 0,
|
|
},
|
|
animations = {
|
|
enabled = false,
|
|
},
|
|
binds = {
|
|
-- Selecting the current workspace again returns to the last workspace.
|
|
workspace_back_and_forth = true,
|
|
},
|
|
})
|
|
|
|
-- Three-finger horizontal swipes change workspaces; touchscreens remain excluded
|
|
-- by Hyprland's default workspace_swipe_touch = false behavior.
|
|
hl.gesture({
|
|
fingers = 3,
|
|
direction = "horizontal",
|
|
action = "workspace",
|
|
})
|
|
|
|
-- Dynamically hide the border when a workspace has exactly one tiled app.
|
|
hl.workspace_rule({
|
|
workspace = "w[t1]",
|
|
no_border = true,
|
|
})
|
|
|
|
-- Application and session bindings.
|
|
local noctalia_ipc = "noctalia msg "
|
|
local pi_status_ui_toggle = 'ui="${PI_STATUS_UI_BINARY:-$HOME/.local/bin/pi-status-ui}"; if test -x "$ui"; then setsid -f env TMPDIR=/tmp "$ui" --toggle >/tmp/pi-status-ui.log 2>&1; fi'
|
|
-- Tap and release Super on its own to open Noctalia's control-center home.
|
|
hl.bind(main_mod .. " + SUPER_L", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"), { release = true })
|
|
hl.bind(main_mod .. " + RETURN", hl.dsp.exec_cmd(terminal))
|
|
hl.bind(main_mod .. " + CTRL + RETURN", hl.dsp.exec_cmd(terminal .. " -e zellij"))
|
|
hl.bind(main_mod .. " + SHIFT + RETURN", hl.dsp.exec_cmd("rofi -show combi"))
|
|
hl.bind(main_mod .. " + SPACE", hl.dsp.exec_cmd(pi_status_ui_toggle))
|
|
hl.bind(main_mod .. " + N", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle alex/knowledge-lookup:panel"))
|
|
hl.bind(main_mod .. " + S", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle control-center"))
|
|
hl.bind(main_mod .. " + 0", hl.dsp.exec_cmd(noctalia_ipc .. "panel-toggle session"))
|
|
hl.bind(main_mod .. " + SHIFT + F", hl.dsp.exec_cmd(noctalia_ipc .. "bar-toggle main"))
|
|
hl.bind(main_mod .. " + SHIFT + R", hl.dsp.exec_cmd("hyprctl reload"))
|
|
hl.bind(main_mod .. " + CTRL + L", hl.dsp.exec_cmd("command -v hyprlock >/dev/null && hyprlock || loginctl lock-session"))
|
|
hl.bind(main_mod .. " + CTRL + SHIFT + ALT + S", hl.dsp.exec_cmd("systemctl suspend"))
|
|
hl.bind(main_mod .. " + CTRL + SHIFT + ALT + H", hl.dsp.exec_cmd("systemctl hibernate"))
|
|
hl.bind(main_mod .. " + SHIFT + C", hl.dsp.window.close())
|
|
|
|
-- Audio, media, brightness, and calculator keys.
|
|
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true })
|
|
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true })
|
|
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true })
|
|
hl.bind(main_mod .. " + XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), { locked = true })
|
|
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
|
|
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
|
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
|
hl.bind(main_mod .. " + XF86AudioRaiseVolume", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
|
hl.bind(main_mod .. " + XF86AudioLowerVolume", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
|
if machine.is_laptop then
|
|
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd('light -A 5'), { locked = true })
|
|
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd('light -U 5'), { locked = true })
|
|
hl.bind(main_mod .. " + XF86MonBrightnessDown", hl.dsp.exec_cmd('light -S 0.0'), { locked = true })
|
|
hl.bind(main_mod .. " + XF86MonBrightnessUp", hl.dsp.exec_cmd('light -S 100'), { locked = true })
|
|
end
|
|
hl.bind("XF86Calculator", hl.dsp.exec_cmd("qalculate-qt"), { locked = true })
|
|
|
|
-- Retain i3's hjkl and arrow-key directional workflow.
|
|
for _, direction in ipairs({ "left", "down", "up", "right" }) do
|
|
local key = ({ left = "H", down = "J", up = "K", right = "L" })[direction]
|
|
hl.bind(main_mod .. " + " .. key, hl.dsp.focus({ direction = direction }))
|
|
hl.bind(main_mod .. " + " .. direction, hl.dsp.focus({ direction = direction }))
|
|
end
|
|
|
|
for key, direction in pairs({ H = "l", J = "d", K = "u", L = "r", LEFT = "l", DOWN = "d", UP = "u", RIGHT = "r" }) do
|
|
hl.bind(main_mod .. " + SHIFT + " .. key, hl.dsp.window.move({ direction = direction }))
|
|
end
|
|
|
|
-- Numbered workspaces match the i3 profile. Shift moves; Ctrl moves and follows.
|
|
for workspace = 1, 9 do
|
|
local key = tostring(workspace)
|
|
hl.bind(main_mod .. " + " .. key, hl.dsp.focus({ workspace = workspace }))
|
|
hl.bind(main_mod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = workspace }))
|
|
hl.bind(main_mod .. " + CTRL + " .. key, hl.dsp.window.move({ workspace = workspace, follow = true }))
|
|
end
|
|
-- Match i3's back-and-forth workflow: Super+Tab switches to the last workspace;
|
|
-- selecting the current numbered workspace also returns to it.
|
|
hl.bind(main_mod .. " + TAB", hl.dsp.focus({ workspace = "previous" }))
|
|
hl.bind(main_mod .. " + CTRL + RIGHT", hl.dsp.focus({ workspace = "+1" }))
|
|
hl.bind(main_mod .. " + CTRL + LEFT", hl.dsp.focus({ workspace = "-1" }))
|
|
|
|
-- Hyprland special workspaces are the Wayland analogue of the i3 scratchpad.
|
|
hl.bind(main_mod .. " + MINUS", hl.dsp.workspace.toggle_special("scratchpad"))
|
|
hl.bind(main_mod .. " + SHIFT + MINUS", hl.dsp.window.move({ workspace = "special:scratchpad" }))
|
|
|
|
-- Keep the i3 floating and fullscreen shortcuts. Layout-specific binds are deferred.
|
|
hl.bind(main_mod .. " + F", hl.dsp.window.fullscreen({ action = "toggle" }))
|
|
hl.bind(main_mod .. " + SHIFT + SPACE", hl.dsp.window.float({ action = "toggle" }))
|
|
hl.bind(main_mod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
|
hl.bind(main_mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
|
|
|
-- i3 for_window/assign translations. Verify Wayland class/title values with `hyprctl clients`.
|
|
local function float_rule(name, match, border_size)
|
|
hl.window_rule({
|
|
name = name,
|
|
match = match,
|
|
float = true,
|
|
border_size = border_size,
|
|
})
|
|
end
|
|
|
|
hl.window_rule({ name = "obsidian-workspace", match = { class = "^obsidian$" }, workspace = "8" })
|
|
hl.window_rule({ name = "thunderbird-workspace", match = { class = "^Thunderbird$" }, workspace = "9" })
|
|
float_rule("pi-status-ui", { class = "^(pi-status-ui|Pi-status-ui)$" }, 1)
|
|
float_rule("alsamixer", { title = "^alsamixer$" }, 1)
|
|
float_rule("qalculate", { title = "^Qalculate!$" })
|
|
float_rule("blueman", { class = "^Blueman-manager$" })
|
|
float_rule("gparted", { class = "^GParted$" })
|
|
float_rule("pavucontrol", { class = "^pavucontrol$" })
|
|
float_rule("volume-control", { title = "^Volume Control$" })
|
|
float_rule("virtualbox", { class = ".*VirtualBox.*" })
|
|
hl.window_rule({ name = "virtualbox-manager-tiles", match = { class = ".*VirtualBox Manager.*" }, tile = true })
|
|
hl.window_rule({ name = "virtualbox-machine-tiles", match = { class = ".*VirtualBox Machine.*" }, tile = true })
|
|
-- Send music clients to the existing scratchpad without stealing startup focus.
|
|
hl.window_rule({ name = "spotify-music", match = { class = "^Spotify$" }, workspace = "special:scratchpad silent", no_initial_focus = true })
|
|
hl.window_rule({ name = "deezer-music", match = { class = "^Deezer$" }, workspace = "special:scratchpad silent", no_initial_focus = true })
|
|
|
|
hl.on("hyprland.start", function()
|
|
for _, command in ipairs(machine.startup or {}) do
|
|
hl.exec_cmd(command)
|
|
end
|
|
end)
|