qt6: switch from kvantum to kde family & hyprland: a new set of config
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"workspace": {
|
||||
"library": ["/usr/share/hypr/stubs"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
-- https://wiki.hypr.land/Configuring/Start/
|
||||
|
||||
-- require("hyprland/envs") -- managed by uwsm
|
||||
|
||||
require("hyprland/monitors")
|
||||
require("hyprland/permissions")
|
||||
require("hyprland/input")
|
||||
|
||||
require("hyprland/looks")
|
||||
require("hyprland/animations")
|
||||
require("hyprland/layouts")
|
||||
require("hyprland/rules")
|
||||
require("hyprland/gestures")
|
||||
require("hyprland/binds")
|
||||
|
||||
require("hyprland/execs")
|
||||
@@ -0,0 +1,45 @@
|
||||
-- Windows use springs so they settle with weight; everything else uses short
|
||||
-- asymmetric beziers, entering with deceleration and leaving faster.
|
||||
|
||||
hl.curve("standard", { type = "bezier", points = { { 0.2, 0.0 }, { 0.0, 1.0 } } })
|
||||
hl.curve("decel", { type = "bezier", points = { { 0.05, 0.7 }, { 0.1, 1.0 } } })
|
||||
hl.curve("accel", { type = "bezier", points = { { 0.3, 0.0 }, { 0.8, 0.15 } } })
|
||||
hl.curve("linear", { type = "bezier", points = { { 0.0, 0.0 }, { 1.0, 1.0 } } })
|
||||
|
||||
-- Stiffness sets the speed, dampening how much it overshoots.
|
||||
hl.curve("snappy", { type = "spring", mass = 1, stiffness = 300, dampening = 26 })
|
||||
hl.curve("smooth", { type = "spring", mass = 1, stiffness = 190, dampening = 24 })
|
||||
hl.curve("lively", { type = "spring", mass = 1, stiffness = 250, dampening = 19 })
|
||||
|
||||
-- Unset leaves inherit from their parent.
|
||||
hl.animation({ leaf = "global", enabled = true, speed = 4, bezier = "standard" })
|
||||
|
||||
hl.animation({ leaf = "windows", enabled = true, speed = 4, spring = "snappy" })
|
||||
hl.animation({ leaf = "windowsIn", enabled = true, speed = 4, spring = "lively", style = "popin 92%" })
|
||||
hl.animation({ leaf = "windowsOut", enabled = true, speed = 2.2, bezier = "accel", style = "popin 94%" })
|
||||
hl.animation({ leaf = "windowsMove", enabled = true, speed = 4, spring = "smooth" })
|
||||
|
||||
hl.animation({ leaf = "layers", enabled = true, speed = 3, bezier = "decel" })
|
||||
hl.animation({ leaf = "layersIn", enabled = true, speed = 3, bezier = "decel", style = "slide" })
|
||||
hl.animation({ leaf = "layersOut", enabled = true, speed = 2.2, bezier = "accel", style = "slide" })
|
||||
|
||||
hl.animation({ leaf = "fade", enabled = true, speed = 2.6, bezier = "standard" })
|
||||
hl.animation({ leaf = "fadeIn", enabled = true, speed = 2.2, bezier = "decel" })
|
||||
hl.animation({ leaf = "fadeOut", enabled = true, speed = 1.8, bezier = "accel" })
|
||||
hl.animation({ leaf = "fadeSwitch", enabled = true, speed = 2.5, bezier = "standard" })
|
||||
hl.animation({ leaf = "fadeDim", enabled = true, speed = 2.5, bezier = "standard" })
|
||||
hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 2.2, bezier = "decel" })
|
||||
hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 1.8, bezier = "accel" })
|
||||
hl.animation({ leaf = "fadePopupsIn", enabled = true, speed = 1.8, bezier = "decel" })
|
||||
hl.animation({ leaf = "fadePopupsOut", enabled = true, speed = 1.4, bezier = "accel" })
|
||||
|
||||
hl.animation({ leaf = "border", enabled = true, speed = 3, bezier = "standard" })
|
||||
|
||||
-- `borderangle` with style "loop" is left unset on purpose: it renders
|
||||
-- continuously at the refresh rate even when idle, which costs battery.
|
||||
|
||||
hl.animation({ leaf = "workspaces", enabled = true, speed = 4.5, bezier = "standard", style = "slidefadevert 12%" })
|
||||
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 4, spring = "smooth", style = "slidevert" })
|
||||
|
||||
hl.animation({ leaf = "zoomFactor", enabled = true, speed = 4, bezier = "decel" })
|
||||
hl.animation({ leaf = "monitorAdded", enabled = true, speed = 4, bezier = "decel" })
|
||||
@@ -0,0 +1,189 @@
|
||||
local mod = "SUPER"
|
||||
local L = require("hyprland/layout-actions")
|
||||
|
||||
-- Applications
|
||||
|
||||
hl.bind(mod .. " + T", hl.dsp.exec_cmd("kitty"), { description = "Terminal" })
|
||||
hl.bind(mod .. " + Return", hl.dsp.exec_cmd("kitty"), { description = "Terminal" })
|
||||
hl.bind(mod .. " + SHIFT + T", hl.dsp.exec_cmd("kitty-floating"), { description = "Floating terminal" })
|
||||
hl.bind(mod .. " + SHIFT + Return", hl.dsp.exec_cmd("kitty-floating"), { description = "Floating terminal" })
|
||||
|
||||
hl.bind(mod .. " + C", hl.dsp.exec_cmd("code"), { description = "Editor" })
|
||||
hl.bind(mod .. " + E", hl.dsp.exec_cmd("nautilus --new-window"), { description = "File manager (GTK)" })
|
||||
hl.bind(mod .. " + SHIFT + E", hl.dsp.exec_cmd("dolphin --new-window"), { description = "File manager" })
|
||||
hl.bind(mod .. " + W", hl.dsp.exec_cmd("zen || zen-browser"), { description = "Browser" })
|
||||
|
||||
hl.bind(mod .. " + B", hl.dsp.exec_cmd("pkill -x -n btop || kitty-floating -e btop"), { description = "System monitor" })
|
||||
hl.bind(mod .. " + O", hl.dsp.exec_cmd("pkill -x -n pwvucontrol || pwvucontrol"), { description = "Audio mixer" })
|
||||
hl.bind("CTRL + ALT + Delete", hl.dsp.exec_cmd("pkill -x wlogout || wlogout"), { description = "Session menu" })
|
||||
|
||||
-- Launcher. URLs are quoted: `?` is a glob to the `sh -c` exec_cmd runs.
|
||||
|
||||
hl.bind("ALT + space", hl.dsp.exec_cmd("vicinae toggle"), { description = "Launcher" })
|
||||
hl.bind(mod .. " + D", hl.dsp.exec_cmd("vicinae 'vicinae://launch/system/run?toggle=true'"), { description = "Run command" })
|
||||
hl.bind(mod .. " + V", hl.dsp.exec_cmd("vicinae 'vicinae://launch/clipboard/history?toggle=true'"), { description = "Clipboard history" })
|
||||
hl.bind(mod .. " + period", hl.dsp.exec_cmd("vicinae 'vicinae://launch/core/search-emojis?toggle=true'"), { description = "Emoji picker" })
|
||||
|
||||
-- Screenshots and colour
|
||||
|
||||
hl.bind("Print", hl.dsp.exec_cmd("screenshot-script full"), { description = "Screenshot: screen" })
|
||||
hl.bind(mod .. " + SHIFT + S", hl.dsp.exec_cmd("screenshot-script area"), { description = "Screenshot: region" })
|
||||
hl.bind(mod .. " + CTRL + SHIFT + S", hl.dsp.exec_cmd("screenshot-script window"), { description = "Screenshot: window" })
|
||||
hl.bind(mod .. " + SHIFT + C", hl.dsp.exec_cmd("hyprpicker -a"), { description = "Pick colour" })
|
||||
|
||||
-- Utilities
|
||||
|
||||
hl.bind(mod .. " + N", hl.dsp.exec_cmd("sunset"), { description = "Night light" })
|
||||
hl.bind(mod .. " + SHIFT + K", hl.dsp.exec_cmd("pkill -x waybar; waybar"), { description = "Restart the bar" })
|
||||
hl.bind(mod .. " + CTRL + R", hl.dsp.exec_cmd("hyprctl reload"), { description = "Reload config" })
|
||||
|
||||
-- hypridle has no runtime toggle, and probing for it would mean a blocking
|
||||
-- popen, which must not happen in a bind callback.
|
||||
local idle_inhibited = false
|
||||
hl.bind(mod .. " + I", function()
|
||||
idle_inhibited = not idle_inhibited
|
||||
if idle_inhibited then
|
||||
hl.exec_cmd("pkill -x hypridle")
|
||||
else
|
||||
hl.exec_cmd("hypridle")
|
||||
end
|
||||
hl.notification.create({
|
||||
text = idle_inhibited and "Idle inhibited" or "Idle timers active",
|
||||
timeout = 1500,
|
||||
})
|
||||
end, { description = "Toggle idle inhibit" })
|
||||
|
||||
-- Media and brightness. BRIGHTNESSCTL_DEVICE comes from set_display.
|
||||
|
||||
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+"),
|
||||
{ locked = true, repeating = true })
|
||||
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"),
|
||||
{ locked = true, repeating = true })
|
||||
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true })
|
||||
hl.bind("XF86AudioMicMute", 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("XF86AudioPause", 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("XF86MonBrightnessUp",
|
||||
hl.dsp.exec_cmd('brightnessctl -d "${BRIGHTNESSCTL_DEVICE:-intel_backlight}" -e4 -n2 set 5%+'),
|
||||
{ locked = true, repeating = true })
|
||||
hl.bind("XF86MonBrightnessDown",
|
||||
hl.dsp.exec_cmd('brightnessctl -d "${BRIGHTNESSCTL_DEVICE:-intel_backlight}" -e4 -n2 set 5%-'),
|
||||
{ locked = true, repeating = true })
|
||||
|
||||
-- Window management
|
||||
|
||||
hl.bind(mod .. " + Q", hl.dsp.window.close(), { description = "Close window" })
|
||||
hl.bind("ALT + F4", hl.dsp.window.close(), { description = "Close window" })
|
||||
hl.bind(mod .. " + SHIFT + Q", hl.dsp.window.kill(), { description = "Force kill window" })
|
||||
|
||||
for key, dir in pairs({ Left = "l", Right = "r", Up = "u", Down = "d" }) do
|
||||
hl.bind(mod .. " + " .. key, hl.dsp.focus({ direction = dir }))
|
||||
hl.bind(mod .. " + SHIFT + " .. key, hl.dsp.window.move({ direction = dir, group_aware = true }))
|
||||
hl.bind(mod .. " + CTRL + " .. key, hl.dsp.focus({ monitor = dir }))
|
||||
hl.bind(mod .. " + CTRL + SHIFT + " .. key, hl.dsp.window.move({ monitor = dir, follow = true }))
|
||||
end
|
||||
|
||||
hl.bind(mod .. " + ALT + space", hl.dsp.window.float({ action = "toggle" }), { description = "Toggle floating" })
|
||||
hl.bind(mod .. " + P", hl.dsp.window.pin(), { description = "Pin window" })
|
||||
hl.bind(mod .. " + Y", hl.dsp.window.center(), { description = "Centre window" })
|
||||
|
||||
hl.bind(mod .. " + F", hl.dsp.window.fullscreen({ mode = "maximized" }), { description = "Maximize" })
|
||||
hl.bind(mod .. " + SHIFT + F", hl.dsp.window.fullscreen({ mode = "fullscreen" }), { description = "Fullscreen" })
|
||||
|
||||
-- The client believes it is fullscreen, the layout does not. Stops
|
||||
-- Chromium-likes dropping into presentation mode.
|
||||
hl.bind(mod .. " + ALT + F", hl.dsp.window.fullscreen_state({ internal = 0, client = 2 }),
|
||||
{ description = "Fake fullscreen" })
|
||||
|
||||
hl.bind("ALT + Tab", function()
|
||||
L.cycle_next()
|
||||
hl.dispatch(hl.dsp.window.bring_to_top())
|
||||
end, { description = "Next window" })
|
||||
hl.bind("ALT + SHIFT + Tab", function()
|
||||
L.cycle_prev()
|
||||
hl.dispatch(hl.dsp.window.bring_to_top())
|
||||
end, { description = "Previous window" })
|
||||
|
||||
hl.bind(mod .. " + SHIFT + Tab", function()
|
||||
local w = hl.get_active_window()
|
||||
hl.dispatch(hl.dsp.focus({ window = (w and w.floating) and "tiled" or "floating" }))
|
||||
end, { description = "Floating <-> tiled focus" })
|
||||
|
||||
-- Tabbed groups
|
||||
|
||||
hl.bind(mod .. " + SHIFT + M", hl.dsp.group.toggle(), { description = "Toggle tabbed group" })
|
||||
hl.bind(mod .. " + CTRL + Tab", hl.dsp.group.next(), { description = "Next tab" })
|
||||
hl.bind(mod .. " + CTRL + SHIFT + Tab", hl.dsp.group.prev(), { description = "Previous tab" })
|
||||
|
||||
-- Layout-aware
|
||||
|
||||
hl.bind(mod .. " + minus", L.narrow, { repeating = true, description = "Narrower" })
|
||||
hl.bind(mod .. " + plus", L.widen, { repeating = true, description = "Wider" })
|
||||
hl.bind(mod .. " + SHIFT + minus", hl.dsp.window.resize({ x = 0, y = -40, relative = true }), { repeating = true })
|
||||
hl.bind(mod .. " + SHIFT + plus", hl.dsp.window.resize({ x = 0, y = 40, relative = true }), { repeating = true })
|
||||
|
||||
hl.bind(mod .. " + R", L.cycle_width, { description = "Cycle preset width" })
|
||||
hl.bind(mod .. " + J", L.tweak, { description = "Split / orientation / expand" })
|
||||
hl.bind(mod .. " + U", L.promote, { description = "Promote window" })
|
||||
|
||||
hl.bind(mod .. " + ALT + Left", L.consume_prev, { description = "Consume/expel left" })
|
||||
hl.bind(mod .. " + ALT + Right", L.consume_next, { description = "Consume/expel right" })
|
||||
hl.bind(mod .. " + SHIFT + comma", L.consume, { description = "Consume window" })
|
||||
hl.bind(mod .. " + SHIFT + period", L.expel, { description = "Expel window" })
|
||||
|
||||
-- Workspaces
|
||||
|
||||
for i = 1, 10 do
|
||||
local key = tostring(i % 10) -- workspace 10 sits on the 0 key
|
||||
hl.bind(mod .. " + " .. key, hl.dsp.focus({ workspace = i }))
|
||||
hl.bind(mod .. " + ALT + " .. key, hl.dsp.window.move({ workspace = i, follow = true }))
|
||||
end
|
||||
|
||||
hl.bind(mod .. " + Page_Down", hl.dsp.focus({ workspace = "+1" }))
|
||||
hl.bind(mod .. " + Page_Up", hl.dsp.focus({ workspace = "-1" }))
|
||||
-- hl.bind(mod .. " + Down", hl.dsp.focus({ workspace = "+1" }))
|
||||
-- hl.bind(mod .. " + Up", hl.dsp.focus({ workspace = "-1" }))
|
||||
hl.bind(mod .. " + SHIFT + Page_Down", hl.dsp.window.move({ workspace = "+1", follow = true }))
|
||||
hl.bind(mod .. " + SHIFT + Page_Up", hl.dsp.window.move({ workspace = "-1", follow = true }))
|
||||
-- hl.bind(mod .. " + SHIFT + Down", hl.dsp.window.move({ workspace = "+1", follow = true }))
|
||||
-- hl.bind(mod .. " + SHIFT + Up", hl.dsp.window.move({ workspace = "-1", follow = true }))
|
||||
|
||||
-- Scroll through only the workspaces that exist.
|
||||
hl.bind(mod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
|
||||
hl.bind(mod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
|
||||
|
||||
hl.bind(mod .. " + Tab", hl.dsp.focus({ workspace = "previous" }), { description = "Last workspace" })
|
||||
|
||||
hl.bind(mod .. " + S", hl.dsp.workspace.toggle_special("scratchpad"), { description = "Scratchpad" })
|
||||
hl.bind(mod .. " + ALT + S", hl.dsp.window.move({ workspace = "special:scratchpad" }),
|
||||
{ description = "Send to scratchpad" })
|
||||
|
||||
-- Mouse
|
||||
|
||||
hl.bind(mod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
||||
hl.bind(mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
||||
hl.bind(mod .. " + mouse:274", hl.dsp.window.close(), { description = "Close window" })
|
||||
|
||||
-- Cycles dwindle -> master -> scrolling, notifying which. No submap: a modal
|
||||
-- state with no on-screen indicator traps the keyboard.
|
||||
hl.bind(mod .. " + SHIFT + L", L.next(), { description = "Cycle layout" })
|
||||
|
||||
-- Session
|
||||
|
||||
hl.bind(mod .. " + L", hl.dsp.exec_cmd("loginctl lock-session"), { description = "Lock" })
|
||||
|
||||
-- The delay is deliberate: driving dpms straight from a keybind is documented
|
||||
-- as undefined behaviour.
|
||||
hl.bind(mod .. " + SHIFT + P", function()
|
||||
hl.exec_cmd("loginctl lock-session")
|
||||
hl.timer(function()
|
||||
hl.dispatch(hl.dsp.dpms({ action = "disable" }))
|
||||
end, { timeout = 800, type = "oneshot" })
|
||||
end, { description = "Lock and blank screens" })
|
||||
|
||||
-- hyprshutdown rather than hl.dsp.exit(), so the session tears down in order.
|
||||
hl.bind(mod .. " + K", hl.dsp.exec_cmd("hyprshutdown"), { description = "Exit Hyprland" })
|
||||
@@ -0,0 +1,41 @@
|
||||
-- Cursor
|
||||
|
||||
hl.env("XCURSOR_SIZE", "24")
|
||||
hl.env("HYPRCURSOR_SIZE", "24")
|
||||
hl.env("XCURSOR_THEME", "Bibata-Modern-Ice")
|
||||
|
||||
-- Qt
|
||||
|
||||
hl.env("QT_QPA_PLATFORM", "wayland")
|
||||
hl.env("QT_QPA_PLATFORMTHEME", "kde")
|
||||
hl.env("QT_STYLE_OVERRIDE", "Kvantum")
|
||||
|
||||
-- Nvidia
|
||||
|
||||
hl.env("LIBVA_DRIVER_NAME", "nvidia")
|
||||
hl.env("NVD_BACKEND", "nvidia")
|
||||
hl.env("GBM_BACKEND", "nvidia-drm")
|
||||
|
||||
-- Aquamarine reads AQ_DRM_DEVICES; set_display exports the resolved list as
|
||||
-- HYPR_AQ_DRM_DEVICES. The fallback applies only if it was never sourced.
|
||||
local drm_devices = os.getenv("HYPR_AQ_DRM_DEVICES")
|
||||
if drm_devices == nil or drm_devices == "" then
|
||||
drm_devices = "/dev/dri/card0:/dev/dri/card1"
|
||||
end
|
||||
hl.env("AQ_DRM_DEVICES", drm_devices)
|
||||
|
||||
-- Input method
|
||||
|
||||
hl.env("QT_IM_MODULE", "fcitx")
|
||||
hl.env("XMODIFIERS", "@im=fcitx")
|
||||
hl.env("SDL_IM_MODULE", "fcitx")
|
||||
hl.env("GLFW_IM_MODULE", "ibus")
|
||||
hl.env("INPUT_METHOD", "fcitx")
|
||||
|
||||
-- Swing
|
||||
|
||||
hl.env("_JAVA_AWT_WM_NONREPARENTING", "1")
|
||||
|
||||
-- Others
|
||||
|
||||
hl.env("ELECTRON_OZONE_PLATFORM_HINT", "wayland")
|
||||
@@ -0,0 +1,10 @@
|
||||
hl.on("hyprland.start", function()
|
||||
hl.exec_cmd("uwsm finalize HYPRLAND_INSTANCE_SIGNATURE")
|
||||
hl.exec_cmd("waybar")
|
||||
hl.exec_cmd("gnome-keyring-daemon --start --components=secrets")
|
||||
hl.exec_cmd("/usr/lib/soteria-polkit/soteria")
|
||||
hl.exec_cmd("solaar -w hide")
|
||||
hl.exec_cmd("sunshine")
|
||||
hl.exec_cmd("hypridle")
|
||||
hl.exec_cmd("vicinae server")
|
||||
end)
|
||||
@@ -0,0 +1,28 @@
|
||||
hl.config({
|
||||
gestures = {
|
||||
workspace_swipe_distance = 400,
|
||||
workspace_swipe_cancel_ratio = 0.2,
|
||||
workspace_swipe_min_speed_to_force = 5,
|
||||
|
||||
workspace_swipe_direction_lock = true,
|
||||
workspace_swipe_direction_lock_threshold = 10,
|
||||
|
||||
workspace_swipe_create_new = true,
|
||||
workspace_swipe_forever = true,
|
||||
workspace_swipe_touch = false,
|
||||
},
|
||||
})
|
||||
|
||||
hl.gesture({ fingers = 3, direction = "vertical", action = "workspace" })
|
||||
|
||||
-- Only does anything under the scrolling layout, harmless elsewhere.
|
||||
hl.gesture({ fingers = 4, direction = "horizontal", action = "scroll_move" })
|
||||
|
||||
hl.gesture({ fingers = 4, direction = "up", action = "special", workspace_name = "scratchpad" })
|
||||
|
||||
-- Held modifiers turn a swipe into a window action rather than navigation.
|
||||
hl.gesture({ fingers = 3, direction = "up", mods = "SUPER", action = "fullscreen" })
|
||||
hl.gesture({ fingers = 3, direction = "down", mods = "SUPER", action = "close" })
|
||||
hl.gesture({ fingers = 3, direction = "left", mods = "SUPER", scale = 1.5, action = "float" })
|
||||
|
||||
hl.gesture({ fingers = 2, direction = "pinch", action = "cursor_zoom", zoom_level = 1, mode = "live" })
|
||||
@@ -0,0 +1,14 @@
|
||||
hl.config({
|
||||
input = {
|
||||
kb_layout = "de",
|
||||
numlock_by_default = true,
|
||||
|
||||
follow_mouse = 1,
|
||||
|
||||
sensitivity = 0, -- -1.0 - 1.0
|
||||
|
||||
touchpad = {
|
||||
natural_scroll = true,
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,120 @@
|
||||
-- Layout messages are layout-specific: "splitratio" means nothing to master,
|
||||
-- "mfact" nothing to scrolling. These resolve one key to the right action.
|
||||
|
||||
local M = {}
|
||||
|
||||
--- Layout of the active workspace; per-workspace rules win over the default.
|
||||
function M.current()
|
||||
local ws = hl.get_active_workspace()
|
||||
if ws and ws.tiled_layout and ws.tiled_layout ~= "" then
|
||||
return ws.tiled_layout
|
||||
end
|
||||
return hl.get_config("general.layout") or "dwindle"
|
||||
end
|
||||
|
||||
--- `map` is keyed by layout name, `map.default` covers anything unlisted.
|
||||
--- Values are functions so no dispatcher is built until the bind fires.
|
||||
local function by_layout(map)
|
||||
return function()
|
||||
local pick = map[M.current()] or map.default
|
||||
if pick then
|
||||
hl.dispatch(pick())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
M.by_layout = by_layout
|
||||
|
||||
M.widen = by_layout({
|
||||
dwindle = function() return hl.dsp.layout("splitratio +0.05") end,
|
||||
master = function() return hl.dsp.layout("mfact +0.05") end,
|
||||
scrolling = function() return hl.dsp.layout("colresize +0.05") end,
|
||||
})
|
||||
|
||||
M.narrow = by_layout({
|
||||
dwindle = function() return hl.dsp.layout("splitratio -0.05") end,
|
||||
master = function() return hl.dsp.layout("mfact -0.05") end,
|
||||
scrolling = function() return hl.dsp.layout("colresize -0.05") end,
|
||||
})
|
||||
|
||||
--- Cycle preset widths under scrolling, elsewhere snap back to an even split.
|
||||
M.cycle_width = by_layout({
|
||||
dwindle = function() return hl.dsp.layout("splitratio 1.0 exact") end,
|
||||
master = function() return hl.dsp.layout("mfact exact 0.58") end,
|
||||
scrolling = function() return hl.dsp.layout("colresize +conf") end,
|
||||
})
|
||||
|
||||
--- Root of the tree, the master slot, or a column of its own.
|
||||
M.promote = by_layout({
|
||||
dwindle = function() return hl.dsp.layout("movetoroot") end,
|
||||
master = function() return hl.dsp.layout("swapwithmaster master") end,
|
||||
scrolling = function() return hl.dsp.layout("promote") end,
|
||||
})
|
||||
|
||||
--- Flip the split, rotate the master area, or fill the free space.
|
||||
M.tweak = by_layout({
|
||||
dwindle = function() return hl.dsp.layout("togglesplit") end,
|
||||
master = function() return hl.dsp.layout("orientationnext") end,
|
||||
scrolling = function() return hl.dsp.layout("fit expand") end,
|
||||
})
|
||||
|
||||
M.cycle_next = by_layout({
|
||||
master = function() return hl.dsp.layout("cyclenext") end,
|
||||
default = function() return hl.dsp.window.cycle_next() end,
|
||||
})
|
||||
|
||||
M.cycle_prev = by_layout({
|
||||
master = function() return hl.dsp.layout("cycleprev") end,
|
||||
default = function() return hl.dsp.window.cycle_next({ next = false }) end,
|
||||
})
|
||||
|
||||
--- Scrolling consumes into columns; elsewhere the analogue is a tabbed group.
|
||||
M.consume_prev = by_layout({
|
||||
scrolling = function() return hl.dsp.layout("consume_or_expel prev") end,
|
||||
default = function() return hl.dsp.window.move({ into_or_create_group = "l" }) end,
|
||||
})
|
||||
|
||||
M.consume_next = by_layout({
|
||||
scrolling = function() return hl.dsp.layout("consume_or_expel next") end,
|
||||
default = function() return hl.dsp.window.move({ into_or_create_group = "r" }) end,
|
||||
})
|
||||
|
||||
M.consume = by_layout({
|
||||
scrolling = function() return hl.dsp.layout("consume") end,
|
||||
default = function() return hl.dsp.window.move({ into_or_create_group = "l" }) end,
|
||||
})
|
||||
|
||||
M.expel = by_layout({
|
||||
scrolling = function() return hl.dsp.layout("expel") end,
|
||||
default = function() return hl.dsp.window.move({ out_of_group = true }) end,
|
||||
})
|
||||
|
||||
local LAYOUTS = { "dwindle", "master", "scrolling" }
|
||||
|
||||
--- Re-point the active workspace at another layout. Returns a bind callback.
|
||||
function M.set(name)
|
||||
return function()
|
||||
local ws = hl.get_active_workspace()
|
||||
if not ws then
|
||||
return
|
||||
end
|
||||
hl.workspace_rule({ workspace = tostring(ws.id), layout = name })
|
||||
hl.notification.create({ text = "Layout: " .. name, timeout = 1500 })
|
||||
end
|
||||
end
|
||||
|
||||
function M.next()
|
||||
return function()
|
||||
local now = M.current()
|
||||
local at = 1
|
||||
for i, name in ipairs(LAYOUTS) do
|
||||
if name == now then
|
||||
at = i
|
||||
break
|
||||
end
|
||||
end
|
||||
M.set(LAYOUTS[(at % #LAYOUTS) + 1])()
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,58 @@
|
||||
-- All three layouts. SUPER+SHIFT+L switches the active workspace between them;
|
||||
-- the keymap is shared, see layout-actions.lua.
|
||||
|
||||
hl.config({
|
||||
dwindle = {
|
||||
-- Required for SUPER+J (togglesplit) to mean anything.
|
||||
preserve_split = true,
|
||||
|
||||
smart_split = false,
|
||||
force_split = 2, -- new window lands right/bottom
|
||||
|
||||
smart_resizing = true,
|
||||
use_active_for_splits = true,
|
||||
precise_mouse_move = true,
|
||||
|
||||
default_split_ratio = 1.0,
|
||||
-- 2560px stays "wide" through several splits, so stack sooner.
|
||||
split_width_multiplier = 1.35,
|
||||
|
||||
special_scale_factor = 1.0,
|
||||
},
|
||||
|
||||
master = {
|
||||
mfact = 0.58,
|
||||
orientation = "left",
|
||||
|
||||
-- New windows join the stack instead of stealing the master slot.
|
||||
new_status = "slave",
|
||||
new_on_active = "after",
|
||||
new_on_top = false,
|
||||
|
||||
allow_small_split = true,
|
||||
smart_resizing = true,
|
||||
drop_at_cursor = true,
|
||||
always_keep_position = false,
|
||||
focus_master_on_close = false,
|
||||
|
||||
slave_count_for_center_master = 2,
|
||||
center_master_fallback = "left",
|
||||
special_scale_factor = 1.0,
|
||||
},
|
||||
|
||||
scrolling = {
|
||||
column_width = 0.5,
|
||||
explicit_column_widths = "0.3, 0.5, 0.7, 1.0",
|
||||
|
||||
fullscreen_on_one_column = true,
|
||||
focus_fit_method = 1,
|
||||
follow_focus = true,
|
||||
follow_min_visible = 0.4,
|
||||
|
||||
-- Let focus fall off the ends onto the other monitor.
|
||||
wrap_focus = false,
|
||||
wrap_swapcol = true,
|
||||
|
||||
direction = "right",
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,168 @@
|
||||
local c = require("hyprland/theme")
|
||||
|
||||
hl.config({
|
||||
general = {
|
||||
gaps_in = 3,
|
||||
gaps_out = 6,
|
||||
gaps_workspaces = 40,
|
||||
|
||||
border_size = 2,
|
||||
col = {
|
||||
active_border = c.gradient(c.blue, c.mauve, 45),
|
||||
inactive_border = c.rgba(c.surface0, "cc"),
|
||||
},
|
||||
|
||||
resize_on_border = true,
|
||||
extend_border_grab_area = 12, -- 2px borders are hard to hit
|
||||
hover_icon_on_border = true,
|
||||
|
||||
no_focus_fallback = true,
|
||||
allow_tearing = true, -- gates the `immediate` rule
|
||||
|
||||
layout = "dwindle",
|
||||
|
||||
snap = {
|
||||
enabled = true,
|
||||
window_gap = 8,
|
||||
monitor_gap = 8,
|
||||
respect_gaps = true,
|
||||
},
|
||||
},
|
||||
|
||||
decoration = {
|
||||
rounding = 14,
|
||||
rounding_power = 2,
|
||||
|
||||
active_opacity = 1.0,
|
||||
inactive_opacity = 0.96,
|
||||
fullscreen_opacity = 1.0,
|
||||
|
||||
dim_inactive = false,
|
||||
dim_special = 0.3,
|
||||
|
||||
shadow = {
|
||||
enabled = true,
|
||||
range = 24,
|
||||
render_power = 3,
|
||||
offset = { 0, 4 },
|
||||
color = c.rgba("000000", "44"),
|
||||
color_inactive = c.rgba("000000", "22"),
|
||||
},
|
||||
|
||||
blur = {
|
||||
enabled = true,
|
||||
size = 6,
|
||||
passes = 3,
|
||||
new_optimizations = true,
|
||||
xray = true,
|
||||
ignore_opacity = true,
|
||||
noise = 0.012,
|
||||
contrast = 1.0,
|
||||
brightness = 1.0,
|
||||
vibrancy = 0.17,
|
||||
vibrancy_darkness = 0.0,
|
||||
|
||||
special = false,
|
||||
popups = true,
|
||||
popups_ignorealpha = 0.6,
|
||||
|
||||
-- Keeps the fcitx5 candidate window readable over bright content.
|
||||
input_methods = true,
|
||||
input_methods_ignorealpha = 0.8,
|
||||
},
|
||||
},
|
||||
|
||||
group = {
|
||||
auto_group = false,
|
||||
insert_after_current = true,
|
||||
focus_removed_window = true,
|
||||
merge_groups_on_drag = true,
|
||||
|
||||
col = {
|
||||
border_active = c.gradient(c.blue, c.mauve, 45),
|
||||
border_inactive = c.rgba(c.surface0, "cc"),
|
||||
border_locked_active = c.gradient(c.peach, c.red, 45),
|
||||
border_locked_inactive = c.rgba(c.surface0, "cc"),
|
||||
},
|
||||
|
||||
groupbar = {
|
||||
enabled = true,
|
||||
font_family = "Noto Sans",
|
||||
font_size = 11,
|
||||
height = 18,
|
||||
indicator_height = 3,
|
||||
indicator_gap = 2,
|
||||
gradients = false,
|
||||
render_titles = true,
|
||||
scrolling = true,
|
||||
middle_click_close = true,
|
||||
stacked = false,
|
||||
keep_upper_gap = true,
|
||||
rounding = 6,
|
||||
gaps_in = 2,
|
||||
gaps_out = 2,
|
||||
|
||||
col = {
|
||||
active = c.rgb(c.blue),
|
||||
inactive = c.rgba(c.surface0, "dd"),
|
||||
locked_active = c.rgb(c.peach),
|
||||
locked_inactive = c.rgba(c.surface0, "dd"),
|
||||
},
|
||||
text_color = c.rgb(c.crust),
|
||||
text_color_inactive = c.rgb(c.text),
|
||||
},
|
||||
},
|
||||
|
||||
cursor = {
|
||||
warp_on_change_workspace = 1,
|
||||
warp_on_toggle_special = 1,
|
||||
persistent_warps = true,
|
||||
|
||||
hide_on_key_press = true,
|
||||
inactive_timeout = 0,
|
||||
|
||||
default_monitor = "DP-1",
|
||||
},
|
||||
|
||||
binds = {
|
||||
workspace_back_and_forth = true,
|
||||
allow_workspace_cycles = true,
|
||||
hide_special_on_workspace_change = true,
|
||||
movefocus_cycles_fullscreen = false,
|
||||
window_direction_monitor_fallback = true,
|
||||
scroll_event_delay = 0,
|
||||
drag_threshold = 10,
|
||||
},
|
||||
|
||||
misc = {
|
||||
font_family = "Noto Sans",
|
||||
|
||||
-- Backdrop behind windows; no wallpaper daemon is started here.
|
||||
disable_hyprland_logo = true,
|
||||
disable_splash_rendering = true,
|
||||
force_default_wallpaper = 0,
|
||||
background_color = c.rgb(c.base),
|
||||
|
||||
vrr = 2, -- fullscreen only; 3 also gates on content type
|
||||
|
||||
mouse_move_enables_dpms = true,
|
||||
key_press_enables_dpms = true,
|
||||
|
||||
animate_manual_resizes = false,
|
||||
animate_mouse_windowdragging = false,
|
||||
|
||||
enable_swallow = false,
|
||||
middle_click_paste = false,
|
||||
|
||||
focus_on_activate = true,
|
||||
initial_workspace_tracking = 0,
|
||||
on_focus_under_fullscreen = 2,
|
||||
allow_session_lock_restore = true,
|
||||
close_special_on_empty = true,
|
||||
},
|
||||
|
||||
xwayland = {
|
||||
-- The panel runs at 1.25; without this XWayland apps render blurry.
|
||||
force_zero_scaling = true,
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,27 @@
|
||||
hl.monitor({
|
||||
output = "eDP-1",
|
||||
mode = "2560x1600@60",
|
||||
position = "0x0",
|
||||
scale = 1.25
|
||||
})
|
||||
|
||||
hl.monitor({
|
||||
output = "eDP-2",
|
||||
mode = "2560x1600@60",
|
||||
position = "0x0",
|
||||
scale = 1.25
|
||||
})
|
||||
|
||||
hl.monitor({
|
||||
output = "DP-1",
|
||||
mode = "2560x1440@180",
|
||||
position = "2048x0",
|
||||
scale = 1
|
||||
})
|
||||
|
||||
hl.workspace_rule({ workspace = 1, monitor = "DP-1", persistent = true })
|
||||
hl.workspace_rule({ workspace = 3, monitor = "DP-1", persistent = false })
|
||||
hl.workspace_rule({ workspace = 5, monitor = "DP-1", persistent = false })
|
||||
hl.workspace_rule({ workspace = 2, monitor = "eDP-1", persistent = true })
|
||||
hl.workspace_rule({ workspace = 4, monitor = "eDP-1", persistent = false })
|
||||
hl.workspace_rule({ workspace = 6, monitor = "eDP-1", persistent = false })
|
||||
@@ -0,0 +1,17 @@
|
||||
hl.config({
|
||||
ecosystem = {
|
||||
enforce_permissions = true,
|
||||
},
|
||||
})
|
||||
|
||||
hl.permission({ binary = "/usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland", type = "screencopy", mode = "allow" })
|
||||
hl.permission({ binary = "/usr/(bin|local/bin)/hyprpm", type = "plugin", mode = "allow" })
|
||||
|
||||
-- Prompts are drawn by hyprland-qtutils, which is not installed, so anything
|
||||
-- not granted here fails rather than asking.
|
||||
hl.permission({ binary = "/usr/(bin|local/bin)/grim", type = "screencopy", mode = "allow" })
|
||||
hl.permission({ binary = "/usr/(bin|local/bin)/hyprshot", type = "screencopy", mode = "allow" })
|
||||
hl.permission({ binary = "/usr/(bin|local/bin)/hyprpicker", type = "screencopy", mode = "allow" })
|
||||
hl.permission({ binary = "/usr/(bin|local/bin)/wf-recorder", type = "screencopy", mode = "allow" })
|
||||
hl.permission({ binary = "/usr/(bin|local/bin)/wl-mirror", type = "screencopy", mode = "allow" })
|
||||
hl.permission({ binary = "/usr/(bin|local/bin)/sunshine", type = "screencopy", mode = "allow" })
|
||||
@@ -0,0 +1,140 @@
|
||||
local c = require("hyprland/theme")
|
||||
|
||||
-- Most apps ask to be maximized on launch, which is rarely wanted when tiling.
|
||||
hl.window_rule({
|
||||
name = "suppress-maximize",
|
||||
match = { class = ".*" },
|
||||
suppress_event = "maximize",
|
||||
})
|
||||
|
||||
-- XWayland drag surfaces appear as empty floating windows; focusing them
|
||||
-- breaks the drag.
|
||||
hl.window_rule({
|
||||
name = "fix-xwayland-drags",
|
||||
match = { class = "^$", title = "^$", xwayland = true, float = true, fullscreen = false, pin = false },
|
||||
no_focus = true,
|
||||
})
|
||||
|
||||
-- Blurring XWayland makes their client-drawn shadows look wrong.
|
||||
hl.window_rule({ name = "no-blur-xwayland", match = { xwayland = true }, no_blur = true })
|
||||
|
||||
hl.window_rule({ name = "no-shadow-tiled", match = { float = false }, no_shadow = true })
|
||||
|
||||
-- Dialogs
|
||||
|
||||
local dialogs = {
|
||||
"^(Open File)(.*)$",
|
||||
"^(Select a File)(.*)$",
|
||||
"^(Choose wallpaper)(.*)$",
|
||||
"^(Open Folder)(.*)$",
|
||||
"^(Save As)(.*)$",
|
||||
"^(Library)(.*)$",
|
||||
"^(File Upload)(.*)$",
|
||||
}
|
||||
for _, title in ipairs(dialogs) do
|
||||
hl.window_rule({ match = { title = title }, float = true, center = true })
|
||||
end
|
||||
|
||||
hl.window_rule({ name = "float-modals", match = { modal = true }, float = true, center = true })
|
||||
|
||||
-- Picture-in-Picture
|
||||
|
||||
local pip = "^([Pp]icture[-\\s]?[Ii]n[-\\s]?[Pp]icture)(.*)$"
|
||||
hl.window_rule({
|
||||
name = "pip",
|
||||
match = { title = pip },
|
||||
float = true,
|
||||
pin = true,
|
||||
keep_aspect_ratio = true,
|
||||
size = { "monitor_w*0.22", "monitor_h*0.22" },
|
||||
move = { "monitor_w-window_w-24", "monitor_h-window_h-24" },
|
||||
no_shadow = false,
|
||||
})
|
||||
|
||||
-- Floating by default
|
||||
|
||||
local floaters = {
|
||||
"^(blueberry\\.py)$",
|
||||
"^(blueman-manager)$",
|
||||
"^(org\\.pulseaudio\\.pavucontrol)$",
|
||||
"^(com\\.saivert\\.pwvucontrol)$",
|
||||
"^(Waydroid)$",
|
||||
"^(waydroid.*)$",
|
||||
"^(org\\.kde\\.kcalc)$",
|
||||
"^(org\\.kde\\.kalk)$",
|
||||
"^(org\\.gnome\\.NautilusPreviewer)$",
|
||||
"^(coin)$",
|
||||
"^(wallreel)$",
|
||||
"^(be\\.alexandervanhee\\.gradia)$",
|
||||
"^(nm-connection-editor)$",
|
||||
"^(org\\.gnome\\.Calculator)$",
|
||||
"^(xdg-desktop-portal-gtk)$",
|
||||
}
|
||||
for _, class in ipairs(floaters) do
|
||||
hl.window_rule({ match = { class = class }, float = true, center = true })
|
||||
end
|
||||
|
||||
-- QQ's image viewer has no useful class, only a title.
|
||||
hl.window_rule({ match = { title = "^(图片查看器)(.*)$" }, float = true, center = true })
|
||||
|
||||
-- Terminals
|
||||
|
||||
hl.window_rule({
|
||||
name = "floating-terminal",
|
||||
match = { class = "^(kitty-floating)$" },
|
||||
float = true,
|
||||
size = { "monitor_w*0.5", "monitor_h*0.5" },
|
||||
center = true,
|
||||
})
|
||||
hl.window_rule({ match = { class = "^(com\\.mitchellh\\.ghostty)$" }, float = true, center = true })
|
||||
|
||||
hl.window_rule({ match = { class = "^(kitty)$" }, scrolling_width = 0.5 })
|
||||
hl.window_rule({ match = { class = "^(scrcpy)$" }, scrolling_width = 0.3 })
|
||||
|
||||
-- Media, games, tearing
|
||||
|
||||
hl.window_rule({ name = "opaque-video", match = { content = "video" }, opaque = true, no_blur = true })
|
||||
hl.window_rule({
|
||||
name = "opaque-game",
|
||||
match = { content = "game" },
|
||||
opaque = true,
|
||||
no_blur = true,
|
||||
no_dim = true,
|
||||
immediate = true,
|
||||
})
|
||||
|
||||
hl.window_rule({ match = { class = "^(steam_app.*)$" }, immediate = true })
|
||||
hl.window_rule({ match = { title = "^(.*\\.exe)$" }, immediate = true })
|
||||
|
||||
-- Steam's notification toasts are windows, and they steal focus.
|
||||
hl.window_rule({
|
||||
name = "steam-toasts",
|
||||
match = { class = "^(steam)$", title = "^(notificationtoasts_\\d+_desktop)$" },
|
||||
float = true,
|
||||
no_initial_focus = true,
|
||||
no_shadow = true,
|
||||
})
|
||||
|
||||
hl.window_rule({ match = { class = "^(org\\.mozilla\\.[Tt]hunderbird)$" }, no_screen_share = true })
|
||||
|
||||
hl.window_rule({ match = { pin = true }, border_color = c.gradient(c.teal, c.green, 45) })
|
||||
|
||||
-- Smart gaps: a lone tiled or fullscreen window drops its gaps and border.
|
||||
-- Rounding is kept.
|
||||
hl.workspace_rule({ workspace = "w[tv1]s[false]", gaps_out = 0, gaps_in = 0 })
|
||||
hl.workspace_rule({ workspace = "f[1]s[false]", gaps_out = 0, gaps_in = 0 })
|
||||
hl.window_rule({ match = { float = false, workspace = "w[tv1]s[false]" }, border_size = 0 })
|
||||
hl.window_rule({ match = { float = false, workspace = "f[1]s[false]" }, border_size = 0 })
|
||||
|
||||
hl.workspace_rule({ workspace = "special:scratchpad", gaps_out = 40, gaps_in = 6 })
|
||||
|
||||
-- Layer rules
|
||||
|
||||
hl.layer_rule({ name = "blur-bar", match = { namespace = "^waybar$" }, blur = true, ignore_alpha = 0.4 })
|
||||
hl.layer_rule({ name = "blur-launcher", match = { namespace = "^vicinae$" }, blur = true, ignore_alpha = 0.4 })
|
||||
hl.layer_rule({ name = "blur-logout", match = { namespace = "^logout_dialog$" }, blur = true })
|
||||
hl.layer_rule({ name = "blur-notifications", match = { namespace = "^notifications$" }, blur = true, ignore_alpha = 0.6 })
|
||||
|
||||
-- The colour picker must see the screen exactly as it is.
|
||||
hl.layer_rule({ name = "no-anim-picker", match = { namespace = "^hyprpicker$" }, no_anim = true })
|
||||
hl.layer_rule({ name = "no-anim-selection", match = { namespace = "^selection$" }, no_anim = true })
|
||||
@@ -0,0 +1,37 @@
|
||||
-- Catppuccin Mocha.
|
||||
|
||||
local M = {
|
||||
base = "1e1e2e",
|
||||
mantle = "181825",
|
||||
crust = "11111b",
|
||||
surface0 = "313244",
|
||||
surface1 = "45475a",
|
||||
surface2 = "585b70",
|
||||
overlay0 = "6c7086",
|
||||
subtext0 = "a6adc8",
|
||||
text = "cdd6f4",
|
||||
|
||||
blue = "89b4fa",
|
||||
lavender = "b4befe",
|
||||
mauve = "cba6f7",
|
||||
red = "f38ba8",
|
||||
peach = "fab387",
|
||||
yellow = "f9e2af",
|
||||
green = "a6e3a1",
|
||||
teal = "94e2d5",
|
||||
}
|
||||
|
||||
function M.rgb(hex)
|
||||
return "rgb(" .. hex .. ")"
|
||||
end
|
||||
|
||||
--- `alpha` is a two-digit hex string, e.g. "80".
|
||||
function M.rgba(hex, alpha)
|
||||
return "rgba(" .. hex .. alpha .. ")"
|
||||
end
|
||||
|
||||
function M.gradient(from, to, angle)
|
||||
return { colors = { M.rgb(from), M.rgb(to) }, angle = angle or 45 }
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user