Compare commits
1 Commits
pre-lua
...
lua-migration
| Author | SHA1 | Date | |
|---|---|---|---|
| 3cadcad501 |
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"diagnostics": {
|
||||
"globals": [
|
||||
"hl"
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"library": [
|
||||
"/usr/share/hypr/stubs",
|
||||
"/usr/share/hyprland/stubs"
|
||||
],
|
||||
"checkThirdParty": false
|
||||
}
|
||||
}
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
-- ~/.config/hypr/functions.lua
|
||||
local M = {}
|
||||
|
||||
-- focusOrLaunch: checks if a window with the given class exists.
|
||||
-- If it does, focuses it (and sends specific shortcuts if it's qutebrowser).
|
||||
-- If not, optionally switches to a workspace and launches the app.
|
||||
function M.focusOrLaunch(app_cmd, class_name, workspace_name)
|
||||
local clients = hl.get_windows()
|
||||
local found = false
|
||||
|
||||
for _, client in ipairs(clients) do
|
||||
if client.class == class_name then
|
||||
hl.dispatch(hl.dsp.focus({ window = "class:" .. class_name }))
|
||||
-- Specific qutebrowser logic ported from your zsh script
|
||||
if app_cmd:match("qutebrowser") then
|
||||
hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "Escape", window = "class:" .. class_name }))
|
||||
hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "0", window = "class:" .. class_name }))
|
||||
hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "1", window = "class:" .. class_name }))
|
||||
hl.dispatch(hl.dsp.send_shortcut({ mods = "ALT", key = "J", window = "class:" .. class_name }))
|
||||
hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "Escape", window = "class:" .. class_name }))
|
||||
end
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
if workspace_name and #workspace_name > 0 then
|
||||
hl.dispatch(hl.dsp.focus({ workspace = workspace_name }))
|
||||
end
|
||||
hl.dispatch(hl.dsp.exec_cmd(app_cmd))
|
||||
end
|
||||
end
|
||||
|
||||
function M.getActiveWorkspaceName()
|
||||
local f = io.popen("hyprctl -j activeworkspace | jq -r '.name'")
|
||||
local active_ws_name = f:read("*a"):gsub("%s+", "")
|
||||
f:close()
|
||||
return active_ws_name
|
||||
end
|
||||
|
||||
function M.mv2workspace()
|
||||
local cmd = [[
|
||||
bash -c '
|
||||
WORKSPACES=$(hyprctl -j workspaces | jq -r ".[] | .name")
|
||||
ACTIVE="$(hyprctl -j activewindow)"
|
||||
CLASS="$(jq -r ".class" <<< "$ACTIVE")"
|
||||
TITLE="$(jq -r ".title" <<< "$ACTIVE")"
|
||||
ADDR="$(jq -r ".address" <<< "$ACTIVE")"
|
||||
PROMPT="Move window of ${CLASS} with title '\''${TITLE}'\'' to which workspace? "
|
||||
NEW_WS="$(echo "$WORKSPACES" | rofi -dmenu -p "$PROMPT")"
|
||||
if [ -n "$NEW_WS" ]; then
|
||||
hyprctl dispatch "hl.dsp.window.move({ workspace = \"$NEW_WS\", window = \"address:$ADDR\", follow = false })"
|
||||
fi
|
||||
'
|
||||
]]
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
end
|
||||
|
||||
function M.createWorkspace(after_name)
|
||||
local after_str = after_name or ""
|
||||
local cmd = string.format([[
|
||||
bash -c '
|
||||
NEW_NAME=$(rofi -dmenu -p "new workspace name" -l 0 < /dev/null | tr -d "[:space:]")
|
||||
if [ -z "$NEW_NAME" ]; then exit 0; fi
|
||||
|
||||
ACTIVE_MON=$(hyprctl -j monitors | jq -r ".[] | select(.focused) | .name")
|
||||
NEW_LINE=" { name = \"$NEW_NAME\", monitor = \"$ACTIVE_MON\" },"
|
||||
FILE="$HOME/.config/hypr/workspace_config.lua"
|
||||
|
||||
AFTER="%s"
|
||||
|
||||
if [ -n "$AFTER" ] && grep -q "name *= *\"$AFTER\"" "$FILE"; then
|
||||
sed -i "/name *= *\"$AFTER\"/a \\$NEW_LINE" "$FILE"
|
||||
else
|
||||
sed -i "/^}/i \\$NEW_LINE" "$FILE"
|
||||
fi
|
||||
hyprctl reload
|
||||
'
|
||||
]], after_str)
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
end
|
||||
|
||||
function M.deleteWorkspace()
|
||||
local cmd = [[
|
||||
bash -c '
|
||||
ACTIVE_WS=$(hyprctl -j activeworkspace | jq -r ".name")
|
||||
if [ -z "$ACTIVE_WS" ]; then exit 0; fi
|
||||
FILE="$HOME/.config/hypr/workspace_config.lua"
|
||||
sed -i "/name *= *\"$ACTIVE_WS\"/d" "$FILE"
|
||||
hyprctl dispatch "hl.dsp.focus({ workspace = \"m-1\" })"
|
||||
hyprctl reload
|
||||
'
|
||||
]]
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
end
|
||||
|
||||
function M.moveWorkspace(direction, target_monitor)
|
||||
-- If no target_monitor is provided and direction is nil, prompt interactively via async bash to avoid deadlocks
|
||||
if (not target_monitor or target_monitor == "") and not direction then
|
||||
local cmd = [[
|
||||
bash -c '
|
||||
ACTIVE_WS=$(hyprctl -j activeworkspace | jq -r ".name")
|
||||
if [ -z "$ACTIVE_WS" ]; then exit 0; fi
|
||||
MONITORS=$(hyprctl -j monitors | jq -r ".[].name")
|
||||
PROMPT="Move workspace '\''$ACTIVE_WS'\'' to which monitor? "
|
||||
NEW_MON=$(echo "$MONITORS" | rofi -dmenu -p "$PROMPT")
|
||||
if [ -n "$NEW_MON" ]; then
|
||||
FILE="$HOME/.config/hypr/workspace_config.lua"
|
||||
sed -i -E "/name *= *\"$ACTIVE_WS\"/ s/monitor *= *\"[^\"]+\"/monitor = \"$NEW_MON\"/" "$FILE"
|
||||
hyprctl reload
|
||||
fi
|
||||
'
|
||||
]]
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
return
|
||||
end
|
||||
|
||||
-- NATIVE LUA PATH for directional shifts or explicit monitor arguments passed from keybinds
|
||||
local active_ws_name = M.getActiveWorkspaceName()
|
||||
if not active_ws_name or active_ws_name == "" then return end
|
||||
|
||||
local path = os.getenv("HOME") .. "/.config/hypr/workspace_config.lua"
|
||||
local f_in = io.open(path, "r")
|
||||
if not f_in then return end
|
||||
|
||||
local lines = {}
|
||||
local ws_idx = nil
|
||||
|
||||
for line in f_in:lines() do
|
||||
table.insert(lines, line)
|
||||
if line:match('name%s*=%s*"' .. active_ws_name .. '"') then
|
||||
ws_idx = #lines
|
||||
end
|
||||
end
|
||||
f_in:close()
|
||||
|
||||
if not ws_idx then return end
|
||||
|
||||
if target_monitor and target_monitor ~= "" then
|
||||
lines[ws_idx] = lines[ws_idx]:gsub('monitor%s*=%s*"[^"]+"', 'monitor = "' .. target_monitor .. '"')
|
||||
end
|
||||
|
||||
if direction then
|
||||
local first_idx = 2
|
||||
local last_idx = #lines - 1
|
||||
|
||||
while first_idx < #lines and not lines[first_idx]:match("name%s*=") do first_idx = first_idx + 1 end
|
||||
while last_idx > 1 and not lines[last_idx]:match("name%s*=") do last_idx = last_idx - 1 end
|
||||
|
||||
if first_idx <= last_idx then
|
||||
local current_line = table.remove(lines, ws_idx)
|
||||
local new_idx = ws_idx
|
||||
|
||||
if direction > 0 then
|
||||
new_idx = ws_idx + 1
|
||||
if new_idx > last_idx then
|
||||
new_idx = first_idx
|
||||
end
|
||||
elseif direction < 0 then
|
||||
new_idx = ws_idx - 1
|
||||
if new_idx < first_idx then
|
||||
new_idx = last_idx
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(lines, new_idx, current_line)
|
||||
end
|
||||
end
|
||||
|
||||
local f_out = io.open(path, "w")
|
||||
for _, line in ipairs(lines) do
|
||||
f_out:write(line .. "\n")
|
||||
end
|
||||
f_out:close()
|
||||
|
||||
hl.dispatch(hl.dsp.exec_cmd("hyprctl reload"))
|
||||
end
|
||||
|
||||
function M.pasteMacro(script_path)
|
||||
local cmd = string.format([[
|
||||
bash -c '
|
||||
exec > /tmp/paste.log 2>&1
|
||||
out="$(%s)"
|
||||
echo -n "$out" | wl-copy
|
||||
|
||||
# 1. Wait a moment for physical keys to be released
|
||||
sleep 0.3
|
||||
# 2. Release modifiers logically, then execute CTRL+V
|
||||
wtype -m logo -m ctrl -m shift -m alt -M ctrl -k v -m ctrl
|
||||
|
||||
# 3. Wait a full second to ensure Wayland apps finish reading the clipboard asynchronously
|
||||
sleep 1.0
|
||||
|
||||
# 4. Scrub the password from cliphist securely
|
||||
PREV=$(cliphist list | awk "NR==2")
|
||||
cliphist list | awk "NR==1" | cliphist delete
|
||||
if [ -n "$PREV" ]; then
|
||||
echo "$PREV" | cliphist decode | wl-copy
|
||||
else
|
||||
wl-copy -c
|
||||
fi
|
||||
'
|
||||
]], script_path)
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
end
|
||||
|
||||
function M.pasteText(text)
|
||||
local cmd = string.format([[
|
||||
bash -c '
|
||||
exec &> /tmp/$(date +%%FT%%H%%M%%S)_paste.log
|
||||
echo -n "%s" | wl-copy
|
||||
|
||||
# Wait a moment for physical keys to be released, then execute CTRL+V
|
||||
sleep 0.3
|
||||
wtype -m logo -m ctrl -m shift -m alt -M ctrl -k v -m ctrl
|
||||
# Note: We do not scrub cliphist here because dates are not sensitive passwords,
|
||||
# which completely eliminates the paste race condition for dates!
|
||||
'
|
||||
]], text)
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
end
|
||||
|
||||
function M.timetracker()
|
||||
local cmd = [[
|
||||
bash -c '
|
||||
CHOICE=$(echo -e "Begin...\nEnd..." | rofi -dmenu -theme-str "inputbar {enabled: false;}" -i -matching prefix -auto-select -l 2)
|
||||
if [ "$CHOICE" = "Begin..." ]; then
|
||||
DATE_STR=$(date "+%F %T")
|
||||
wtype -m logo -m ctrl -m shift -m alt -k Escape
|
||||
wtype "I${DATE_STR}: Begin "
|
||||
elif [ "$CHOICE" = "End..." ]; then
|
||||
DATE_STR=$(date "+%F %T")
|
||||
wtype -m logo -m ctrl -m shift -m alt -k Escape
|
||||
wtype "I${DATE_STR}: End "
|
||||
wtype -k Escape
|
||||
wtype "kly\$jpo"
|
||||
wtype "${DATE_STR}: Begin "
|
||||
fi
|
||||
'
|
||||
]]
|
||||
hl.dispatch(hl.dsp.exec_cmd(cmd))
|
||||
end
|
||||
|
||||
function M.randomizeWallpaper()
|
||||
local monitors = hl.get_monitors()
|
||||
local home = os.getenv("HOME")
|
||||
local april_dir = home .. "/images/April"
|
||||
local sbm_dir = home .. "/images/Seven Beats Music"
|
||||
|
||||
-- Choose image source based on monitor count
|
||||
local img_dir = (#monitors <= 1) and april_dir or sbm_dir
|
||||
|
||||
local images = {}
|
||||
local handle = io.popen('find "' .. img_dir .. '" -type f \\( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \\) 2>/dev/null')
|
||||
if handle then
|
||||
for line in handle:lines() do
|
||||
table.insert(images, line)
|
||||
end
|
||||
handle:close()
|
||||
end
|
||||
|
||||
if #images == 0 then return end
|
||||
|
||||
-- Pick a unique random image for each monitor
|
||||
math.randomseed(os.time())
|
||||
local used = {}
|
||||
for _, mon in ipairs(monitors) do
|
||||
local img = nil
|
||||
local attempts = 0
|
||||
while attempts < #images do
|
||||
local idx = math.random(1, #images)
|
||||
if not used[idx] then
|
||||
img = images[idx]
|
||||
used[idx] = true
|
||||
break
|
||||
end
|
||||
attempts = attempts + 1
|
||||
end
|
||||
if img then
|
||||
hl.dispatch(hl.dsp.exec_cmd('hyprctl hyprpaper reload "' .. mon.name .. ',' .. img .. '"'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -40,3 +40,5 @@ listener {
|
||||
timeout = 900 # 10min
|
||||
on-timeout = systemd-ac-power || systemctl suspend # only suspend pc on battery
|
||||
}
|
||||
|
||||
# vim:ft=hyprlang
|
||||
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
-- ~/.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("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 + A", function() fn.focusOrLaunch("slack", "Slack", "Slack") end)
|
||||
bind("SUPER + 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)
|
||||
bind("SUPER + P", dsp.exec_cmd(launcher))
|
||||
bind("SUPER + S", function() fn.focusOrLaunch("pavucontrol", "org.pulseaudio.pavucontrol", "org.pulseaudio.pavucontrol") end)
|
||||
bind("SUPER + V", function() fn.focusOrLaunch("alacritty", "Alacritty") end)
|
||||
|
||||
-- Window control
|
||||
bind("SUPER + C", dsp.window.close())
|
||||
bind("SUPER + T", dsp.window.float({ action = "toggle" }))
|
||||
bind("SUPER + space", dsp.window.fullscreen({ mode = 1 }))
|
||||
|
||||
-- BUG FIX: H/J/K were redundantly bound to move_focus AND fullscreen.
|
||||
bind("SUPER + H", dsp.focus({ direction = "l" }))
|
||||
bind("SUPER + K", dsp.focus({ direction = "u" }))
|
||||
bind("SUPER + J", dsp.focus({ direction = "d" }))
|
||||
|
||||
bind("SUPER + X", dsp.exec_cmd("dunstctl close"))
|
||||
bind("SUPER + Y", dsp.exec_cmd("dunstctl close-all"))
|
||||
|
||||
-- Workspace control
|
||||
bind("SUPER + right", function() hl.dispatch(hl.dsp.focus({ workspace = "m+1" })) end)
|
||||
bind("SUPER + 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)
|
||||
|
||||
-- Cliphist
|
||||
bind("ALT + V", dsp.exec_cmd("cliphist list | rofi -dmenu -p 'paste' | cliphist decode | " .. copy .. " && " .. paste))
|
||||
|
||||
-- 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)
|
||||
+8
-8
@@ -1,19 +1,20 @@
|
||||
ipc = true
|
||||
splash = false
|
||||
wallpaper {
|
||||
monitor = DP-7
|
||||
path = /home/trey/images/black.png
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
wallpaper {
|
||||
monitor = eDP-1
|
||||
path = /home/trey/images/black.png
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
wallpaper {
|
||||
monitor = DP-7
|
||||
path = /home/trey/images/Seven Beats Music/2024-09-16.jpg
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
wallpaper {
|
||||
monitor = DP-8
|
||||
path = /home/trey/images/Seven Beats Music/2024-10-14.jpg
|
||||
path = /home/trey/images/black.png
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
@@ -22,4 +23,3 @@ wallpaper {
|
||||
path = /home/trey/images/black.png
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
general {
|
||||
lock_cmd = pidof hyprlock || hyprlock # avoid starting multiple hyprlock instances.
|
||||
before_sleep_cmd = loginctl lock-session # lock before suspend.
|
||||
after_sleep_cmd = hyprctl dispatch dpms on # to avoid having to press a key twice to turn on the display.
|
||||
}
|
||||
|
||||
listener {
|
||||
timeout = 150 # 2.5min.
|
||||
on-timeout = brightnessctl -s set 10 # set monitor backlight to minimum, avoid 0 on OLED monitor.
|
||||
on-resume = brightnessctl -r # monitor backlight restore.
|
||||
}
|
||||
|
||||
# turn off keyboard backlight, comment out this section if you dont have a keyboard backlight.
|
||||
listener {
|
||||
timeout = 150 # 2.5min.
|
||||
on-timeout = brightnessctl -sd rgb:kbd_backlight set 0 # turn off keyboard backlight.
|
||||
on-resume = brightnessctl -rd rgb:kbd_backlight # turn on keyboard backlight.
|
||||
}
|
||||
|
||||
#listener {
|
||||
# timeout = 300 # 5min
|
||||
# on-timeout = loginctl lock-session # lock screen when timeout has passed
|
||||
#}
|
||||
|
||||
listener {
|
||||
timeout = 300
|
||||
# 1. Lock the vault via DBus, 2. Start the lock screen
|
||||
on-timeout = busctl --user call org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.Secret.Service Lock "as" 1 "/org/freedesktop/secrets/aliases/default" && hyprlock
|
||||
# When hyprlock exits (via fingerprint or password), instantly run the unlock script
|
||||
on-resume = ~/.local/bin/unlock-ring.sh
|
||||
}
|
||||
|
||||
listener {
|
||||
timeout = 330 # 5.5min
|
||||
on-timeout = hyprctl dispatch dpms off # screen off when timeout has passed
|
||||
on-resume = hyprctl dispatch dpms on # screen on when activity is detected after timeout has fired.
|
||||
}
|
||||
|
||||
listener {
|
||||
timeout = 900 # 10min
|
||||
on-timeout = systemd-ac-power || systemctl suspend # only suspend pc on battery
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
auth {
|
||||
fingerprint {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
background {
|
||||
# path = screenshot
|
||||
color = rgb(000000)
|
||||
}
|
||||
|
||||
input-field {
|
||||
size = 200, 30
|
||||
outline_thickness = 1
|
||||
rounding = 10
|
||||
outer_color = rgb(665c54)
|
||||
inner_color = rgb(3c3836)
|
||||
font_color = rgb(ebdbb2)
|
||||
check_color = rgb(d79921)
|
||||
fail_color = rgb(cc241d)
|
||||
fade_on_empty = false
|
||||
placeholder_text = password
|
||||
fail_text =
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:500]date +"%FT%H:%M:%S"
|
||||
color = rgb(ebdbb2)
|
||||
font_size = 45
|
||||
font_family = monospace
|
||||
|
||||
position = 0, 60
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:3000]pidof spotify > /dev/null && echo "<span foreground='##b8bb26' size='25000' rise='-4.5pt'> </span>$(playerctl -p spotify metadata xesam:title) - $(playerctl -p spotify metadata xesam:artist)"
|
||||
color = rgb(ebdbb2)
|
||||
font_size = 14
|
||||
font_family = JetBrains Mono Nerd Font Mono Semibold
|
||||
|
||||
position = 0, -420
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:60] uptime -p
|
||||
color = rgb(ebdbb2)
|
||||
offont_size = 10
|
||||
font_family = monospace
|
||||
|
||||
position = 0, -450
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
listener {
|
||||
timeout = 300 # 5 minutes
|
||||
on-timeout = sleep 60 && busctl --user call org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.Secret.Service Lock "as" 1 "/org/freedesktop/secrets/aliases/default" && hyprlock
|
||||
}
|
||||
|
||||
listener {
|
||||
timeout = 330 # 5.5 minutes
|
||||
on-timeout = hyprctl dispatch dpms off # screen off
|
||||
on-resume = hyprctl dispatch dpms on # screen on
|
||||
}
|
||||
|
||||
# vim:ft=hyprlang
|
||||
@@ -0,0 +1,25 @@
|
||||
splash = false
|
||||
wallpaper {
|
||||
monitor = eDP-1
|
||||
path = /home/trey/images/black.png
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
wallpaper {
|
||||
monitor = DP-7
|
||||
path = /home/trey/images/Seven Beats Music/2024-09-16.jpg
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
wallpaper {
|
||||
monitor = DP-8
|
||||
path = /home/trey/images/Seven Beats Music/2024-10-14.jpg
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
wallpaper {
|
||||
monitor =
|
||||
path = /home/trey/images/black.png
|
||||
fit_mode = cover
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
workspace = 1, defaultName:shell, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 3, defaultName:browser, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 4, defaultName:work, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 5, defaultName:jobs, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 6, defaultName:meeting, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 7, defaultName:monitoring, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 8, defaultName:ai, monitor:eDP-1, persistent:true, default:true
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Background loop to monitor battery status and trigger dunstify on low power.
|
||||
while true; do
|
||||
if [ ! -d /sys/class/power_supply/BAT0 ]; then
|
||||
sleep 60
|
||||
continue
|
||||
fi
|
||||
|
||||
STATUS=$(cat /sys/class/power_supply/BAT0/status 2>/dev/null)
|
||||
# Using the native kernel capacity file instead of relying on ibam
|
||||
CAPACITY=$(cat /sys/class/power_supply/BAT0/capacity 2>/dev/null)
|
||||
|
||||
if [ -z "$CAPACITY" ]; then
|
||||
sleep 60
|
||||
continue
|
||||
fi
|
||||
|
||||
# Trigger notification at 5% or below
|
||||
if [ "$STATUS" == "Discharging" ] && [ "$CAPACITY" -le 5 ]; then
|
||||
if [ ! -f "/run/user/${UID}/battery_low" ]; then
|
||||
logger "Low power! Triggering notification...."
|
||||
dunstify --urgency=critical \
|
||||
--icon=/usr/share/icons/breeze-dark/emblems/16/emblem-warning.svg \
|
||||
"LOW BATTERY!" \
|
||||
"Battery level is at ${CAPACITY}%, plug power quick!"
|
||||
touch "/run/user/${UID}/battery_low"
|
||||
fi
|
||||
|
||||
# Clear the notification if we plug back in and rise above 5%
|
||||
elif [ "$STATUS" == "Charging" ] && [ "$CAPACITY" -gt 5 ]; then
|
||||
if [ -f "/run/user/${UID}/battery_low" ]; then
|
||||
logger "Power reconnected and above 5 percent, clearing notification state."
|
||||
rm -f "/run/user/${UID}/battery_low"
|
||||
|
||||
# Find and close the specific dunst notification by ID
|
||||
for id in $(dunstctl history | jq '.data[0][] | select(.summary.data == "LOW BATTERY!") | .id.data'); do
|
||||
dunstify --close=${id}
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 60
|
||||
done
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env zsh
|
||||
|
||||
#set -x
|
||||
old_profile="$(kanshictl status | jq -r '.current_profile')"
|
||||
new_profile="${1}"
|
||||
shift
|
||||
|
||||
if [[ "${old_profile}" == "${new_profile}" ]]; then
|
||||
if [[ "${1}" != "--force" ]] && [[ "${1}" != '-f' ]]; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
case "${new_profile}" in
|
||||
home_office)
|
||||
perl -pi -e 'if (/shell/) {s/monitor:.*?,/monitor:DP-6,/}' ${XDG_CONFIG_HOME}/hypr/workspaces.conf
|
||||
perl -pi -e 'if (/browser/) {s/monitor:.*?,/monitor:DP-6,/}' ${XDG_CONFIG_HOME}/hypr/workspaces.conf
|
||||
perl -pi -e 'if (/work/) {s/monitor:.*?,/monitor:HDMI-A-1,/}' ${XDG_CONFIG_HOME}/hypr/workspaces.conf
|
||||
perl -pi -e 'if (/jobs/) {s/monitor:.*?,/monitor:HDMI-A-1,/}' ${XDG_CONFIG_HOME}/hypr/workspaces.conf
|
||||
kanshictl switch home_office
|
||||
hyprctl reload
|
||||
killall -s USR2 waybar
|
||||
;;
|
||||
single_headed)
|
||||
perl -pi -e 's/monitor:.*?,/monitor:eDP-1,/' ${XDG_CONFIG_HOME}/hypr/workspaces.conf
|
||||
kanshictl switch single_headed
|
||||
hyprctl reload
|
||||
killall -s USR2 waybar
|
||||
;;
|
||||
*)
|
||||
print "Invalid profile!" >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
#set +x
|
||||
@@ -0,0 +1,8 @@
|
||||
return {
|
||||
{ name = "shell", monitor = "DP-8" },
|
||||
{ name = "browser", monitor = "DP-8" },
|
||||
{ name = "jobs", monitor = "DP-7" },
|
||||
{ name = "work", monitor = "DP-7" },
|
||||
{ name = "meeting", monitor = "eDP-1" },
|
||||
{ name = "monitoring", monitor = "eDP-1" },
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
workspace = 1, defaultName:shell, monitor:DP-8, persistent:true, default:true
|
||||
workspace = 3, defaultName:browser, monitor:DP-8, persistent:true, default:true
|
||||
workspace = 4, defaultName:work, monitor:DP-7, persistent:true, default:true
|
||||
workspace = 5, defaultName:jobs, monitor:DP-7, persistent:true, default:true
|
||||
workspace = 6, defaultName:meeting, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 7, defaultName:monitoring, monitor:eDP-1, persistent:true, default:true
|
||||
workspace = 8, defaultName:ai, monitor:eDP-1, persistent:true, default:true
|
||||
@@ -0,0 +1,37 @@
|
||||
-- ~/.config/hypr/workspaces.lua
|
||||
-- Dynamic workspace assignment: replaces kanshi + scripts
|
||||
-- Detects monitor configuration and assigns workspaces accordingly.
|
||||
|
||||
local function get_monitor_names()
|
||||
local names = {}
|
||||
for _, m in ipairs(hl.get_monitors()) do
|
||||
names[m.name] = true
|
||||
end
|
||||
return names
|
||||
end
|
||||
|
||||
local function assign_workspaces()
|
||||
local monitors = get_monitor_names()
|
||||
local has_dock = monitors["DP-7"] and monitors["DP-8"]
|
||||
|
||||
-- Read workspace configurations
|
||||
package.loaded["workspace_config"] = nil -- force reload in case it changed
|
||||
local ws_config = require("workspace_config")
|
||||
|
||||
for _, ws in ipairs(ws_config) do
|
||||
local target_mon = has_dock and ws.monitor or "eDP-1"
|
||||
hl.workspace_rule({ workspace = "name:" .. ws.name, monitor = target_mon, persistent = true, default = true })
|
||||
end
|
||||
end
|
||||
|
||||
-- Apply on initial load
|
||||
assign_workspaces()
|
||||
|
||||
-- Re-apply when monitors change
|
||||
hl.on("monitor.added", function(monitor)
|
||||
assign_workspaces()
|
||||
end)
|
||||
|
||||
hl.on("monitor.removed", function(monitor)
|
||||
assign_workspaces()
|
||||
end)
|
||||
Reference in New Issue
Block a user