From fef03be5f63c70f8274116640281c76dd1fe3351 Mon Sep 17 00:00:00 2001 From: Felis Date: Wed, 12 Aug 2026 22:58:34 -0700 Subject: [PATCH] initial commit --- .luarc.json | 7 + autostart.lua | 30 ++++ hyprland.lua | 375 ++++++++++++++++++++++++++++++++++++++++++ hyprqt6engine.conf | 5 + keybinds.lua | 80 +++++++++ noctalia.lua | 45 +++++ scripts/select-layout | 28 ++++ windowrules.lua | 14 ++ workspaces.lua | 67 ++++++++ 9 files changed, 651 insertions(+) create mode 100644 .luarc.json create mode 100644 autostart.lua create mode 100644 hyprland.lua create mode 100644 hyprqt6engine.conf create mode 100644 keybinds.lua create mode 100644 noctalia.lua create mode 100755 scripts/select-layout create mode 100644 windowrules.lua create mode 100644 workspaces.lua diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..b4ecec0 --- /dev/null +++ b/.luarc.json @@ -0,0 +1,7 @@ +{ + "workspace": { + "library": [ + "/usr/share/hypr/stubs" + ] + } +} diff --git a/autostart.lua b/autostart.lua new file mode 100644 index 0000000..ab1b771 --- /dev/null +++ b/autostart.lua @@ -0,0 +1,30 @@ +------------------- +---- AUTOSTART ---- +------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Autostart/ + +-- Autostart necessary processes (like notifications daemons, status bars, etc.) +-- Or execute your favorite apps at launch like this: +-- + + +local function uwsm(cmd) + return "uwsm-app -- " .. cmd +end + + +-- Set programs that you use +local terminal = uwsm("alacritty") + + +hl.on("hyprland.start", function() + hl.exec_cmd("fcitx5 -d") + hl.exec_cmd("hyprpm reload -n") + hl.exec_cmd(uwsm(terminal)) + hl.exec_cmd(uwsm("hyprpaper")) + hl.exec_cmd(uwsm("firefox")) + hl.exec_cmd(uwsm("wl-paste --type text --watch cliphist store")) + hl.exec_cmd(uwsm("wl-paste --type image --watch cliphist store")) + hl.exec_cmd(uwsm("noctalia")) +end) diff --git a/hyprland.lua b/hyprland.lua new file mode 100644 index 0000000..3a6a769 --- /dev/null +++ b/hyprland.lua @@ -0,0 +1,375 @@ +-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +-- AUTOGENERATED HYPRLAND CONFIG. -- +-- EDIT THIS CONFIG ACCORDING TO THE WIKI INSTRUCTIONS. -- +-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + +-- This is an example Hyprland Lua config file. +-- Refer to the wiki for more information. +-- https://wiki.hypr.land/Configuring/Start/ + +-- Please note not all available settings / options are set here. +-- For a full list, see the wiki + +-- You can (and should!!) split this configuration into multiple files +-- Create your files separately and then require them like this: +-- require("myColors") + +require("noctalia") +require("keybinds") +require("workspaces") +require("windowrules") +require("autostart") + + +------------------ +---- MONITORS ---- +------------------ + +-- See https://wiki.hypr.land/Configuring/Basics/Monitors/ +hl.monitor({ + output = "HDMI-A-1", + mode = "2560x1440@144", + position = "0x0", + scale = 1, +}) + +hl.monitor({ + output = "DP-3", + mode = "2560x1440@120", + position = "2560x0", + scale = 1, +}) + +local hyper = "MOD3" + +--------------------- +---- MY PROGRAMS ---- +--------------------- +local function uwsm(cmd) + return "uwsm-app -- " .. cmd +end + +-- Set programs that you use +local terminal = uwsm("alacritty") +local fileManager = uwsm("dolphin") +local menu = "hyprlauncher" + + + +------------------------------- +---- ENVIRONMENT VARIABLES ---- +------------------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Environment-variables/ + +hl.env("XCURSOR_SIZE", "24") +hl.env("HYPRCURSOR_SIZE", "24") + + +----------------------- +----- PERMISSIONS ----- +----------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Permissions/ +-- Please note permission changes here require a Hyprland restart and are not applied on-the-fly +-- for security reasons + +-- hl.config({ +-- ecosystem = { +-- enforce_permissions = true, +-- }, +-- }) + +-- hl.permission("/usr/(bin|local/bin)/grim", "screencopy", "allow") +-- hl.permission("/usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland", "screencopy", "allow") +-- hl.permission("/usr/(bin|local/bin)/hyprpm", "plugin", "allow") + + +----------------------- +---- LOOK AND FEEL ---- +----------------------- + +-- Refer to https://wiki.hypr.land/Configuring/Basics/Variables/ +hl.config({ + general = { + gaps_in = 5, + gaps_out = 20, + + border_size = 2, + + col = { + active_border = { colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }, + inactive_border = "rgba(595959aa)", + }, + + -- Set to true to enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = false, + + -- Please see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Tearing/ before you turn this on + allow_tearing = false, + + layout = "dwindle", + }, + + decoration = { + rounding = 10, + rounding_power = 2, + + -- Change transparency of focused and unfocused windows + active_opacity = 1.0, + inactive_opacity = 1.0, + + shadow = { + enabled = true, + range = 4, + render_power = 3, + color = 0xee1a1a1a, + }, + + blur = { + enabled = true, + size = 3, + passes = 1, + vibrancy = 0.1696, + }, + }, + + animations = { + enabled = true, + }, +}) + +-- Default curves and animations, see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Animations/ +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("linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } }) +hl.curve("almostLinear", { type = "bezier", points = { { 0.5, 0.5 }, { 0.75, 1 } } }) +hl.curve("quick", { type = "bezier", points = { { 0.15, 0 }, { 0.1, 1 } } }) + +-- Default springs +hl.curve("easy", { type = "spring", mass = 1, stiffness = 238.1191, dampening = 24.21279333 }) + +hl.animation({ leaf = "global", enabled = true, speed = 10, bezier = "default" }) +hl.animation({ leaf = "border", enabled = true, speed = 5.39, bezier = "easeOutQuint" }) +hl.animation({ leaf = "windows", enabled = true, speed = 4.79, spring = "easy" }) +hl.animation({ leaf = "windowsIn", enabled = true, speed = 4.1, spring = "easy", style = "popin 87%" }) +hl.animation({ leaf = "windowsOut", enabled = true, speed = 1.49, bezier = "linear", style = "popin 87%" }) +hl.animation({ leaf = "fadeIn", enabled = true, speed = 1.73, bezier = "almostLinear" }) +hl.animation({ leaf = "fadeOut", enabled = true, speed = 1.46, bezier = "almostLinear" }) +hl.animation({ leaf = "fade", enabled = true, speed = 3.03, bezier = "quick" }) +hl.animation({ leaf = "layers", enabled = true, speed = 3.81, bezier = "easeOutQuint" }) +hl.animation({ leaf = "layersIn", enabled = true, speed = 4, bezier = "easeOutQuint", style = "fade" }) +hl.animation({ leaf = "layersOut", enabled = true, speed = 1.5, bezier = "linear", style = "fade" }) +hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 1.79, bezier = "almostLinear" }) +hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 1.39, bezier = "almostLinear" }) +hl.animation({ leaf = "workspaces", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "workspacesIn", enabled = true, speed = 1.21, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "workspacesOut", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "zoomFactor", enabled = true, speed = 7, bezier = "quick" }) + +-- Ref https://wiki.hypr.land/Configuring/Basics/Workspace-Rules/ +-- "Smart gaps" / "No gaps when only" +-- uncomment all if you wish to use that. +-- 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 = "no-gaps-wtv1", +-- match = { float = false, workspace = "w[tv1]" }, +-- border_size = 0, +-- rounding = 0, +-- }) +-- hl.window_rule({ +-- name = "no-gaps-f1", +-- match = { float = false, workspace = "f[1]" }, +-- border_size = 0, +-- rounding = 0, +-- }) + +-- See https://wiki.hypr.land/Configuring/Layouts/Dwindle-Layout/ for more +hl.config({ + dwindle = { + preserve_split = true, -- You probably want this + }, +}) + +-- See https://wiki.hypr.land/Configuring/Layouts/Master-Layout/ for more +hl.config({ + master = { + new_status = "master", + }, +}) + +-- See https://wiki.hypr.land/Configuring/Layouts/Scrolling-Layout/ for more +hl.config({ + scrolling = { + fullscreen_on_one_column = true, + }, +}) + +---------------- +---- MISC ---- +---------------- + +hl.config({ + misc = { + force_default_wallpaper = -1, -- Set to 0 or 1 to disable the anime mascot wallpapers + disable_hyprland_logo = false, -- If true disables the random hyprland logo / anime girl background. :( + }, +}) + + +--------------- +---- INPUT ---- +--------------- + +hl.config({ + input = { + kb_layout = "us", + kb_variant = "", + kb_model = "", + kb_options = "caps:hyper", + kb_rules = "", + + follow_mouse = 1, + + sensitivity = 0, -- -1.0 - 1.0, 0 means no modification. + + touchpad = { + natural_scroll = false, + }, + }, +}) + +hl.gesture({ + fingers = 3, + direction = "horizontal", + action = "workspace" +}) + +-- Example per-device config +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Devices/ for more +hl.device({ + name = "epic-mouse-v1", + sensitivity = -0.5, +}) + + +--------------------- +---- KEYBINDINGS ---- +--------------------- + +local mainMod = "SUPER" -- Sets "Windows" key as main modifier + +-- Example binds, see https://wiki.hypr.land/Configuring/Basics/Binds/ for more +hl.bind(mainMod .. " + Q", hl.dsp.exec_cmd(terminal)) +-- closeWindowBind:set_enabled(false) +hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(fileManager)) +hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" })) +hl.bind(mainMod .. " + R", hl.dsp.exec_cmd(menu)) +hl.bind(mainMod .. " + P", hl.dsp.window.pseudo()) +hl.bind(mainMod .. " + J", hl.dsp.layout("togglesplit")) -- dwindle only + +-- Move focus with mainMod + arrow keys +hl.bind(mainMod .. " + left", hl.dsp.focus({ direction = "left" })) +hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = "right" })) +hl.bind(mainMod .. " + up", hl.dsp.focus({ direction = "up" })) +hl.bind(mainMod .. " + down", hl.dsp.focus({ direction = "down" })) + +-- Switch workspaces with mainMod + [0-9] +-- Move active window to a workspace with mainMod + SHIFT + [0-9] +for i = 1, 10 do + local key = i % 10 -- 10 maps to key 0 + hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i })) + hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i })) +end + +-- Scroll through existing workspaces with mainMod + scroll +hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" })) +hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" })) + +-- Move/resize windows with mainMod + LMB/RMB and dragging +hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true }) +hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true }) + +-- Laptop multimedia keys for volume and LCD brightness +hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume -l 1 @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, repeating = true }) +hl.bind("XF86AudioMicMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), + { locked = true, repeating = true }) +hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%+"), { locked = true, repeating = true }) +hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"), { locked = true, repeating = true }) + +-- Requires playerctl +hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true }) +hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true }) + +hl.bind(hyper .. " + W", hl.dsp.focus({ direction = "u" })) +hl.bind(hyper .. " + A", hl.dsp.focus({ direction = "l" })) +hl.bind(hyper .. " + S", hl.dsp.focus({ direction = "d" })) +hl.bind(hyper .. " + D", hl.dsp.focus({ direction = "r" })) + +hl.bind(hyper .. " + CTRL + W", hl.dsp.window.move({ direction = "u" })) +hl.bind(hyper .. " + CTRL + A", hl.dsp.window.move({ direction = "l" })) +hl.bind(hyper .. " + CTRL + S", hl.dsp.window.move({ direction = "d" })) +hl.bind(hyper .. " + CTRL + D", hl.dsp.window.move({ direction = "r" })) + + + +-------------------------------- +---- WINDOWS AND WORKSPACES ---- +-------------------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Window-Rules/ +-- and https://wiki.hypr.land/Configuring/Basics/Workspace-Rules/ + +-- Example window rules that are useful + +local suppressMaximizeRule = hl.window_rule({ + -- Ignore maximize requests from all apps. You'll probably like this. + name = "suppress-maximize-events", + match = { class = ".*" }, + + suppress_event = "maximize", +}) +-- suppressMaximizeRule:set_enabled(false) + +hl.window_rule({ + -- Fix some dragging issues with XWayland + name = "fix-xwayland-drags", + match = { + class = "^$", + title = "^$", + xwayland = true, + float = true, + fullscreen = false, + pin = false, + }, + + no_focus = true, +}) + +-- Layer rules also return a handle. +-- local overlayLayerRule = hl.layer_rule({ +-- name = "no-anim-overlay", +-- match = { namespace = "^my-overlay$" }, +-- no_anim = true, +-- }) +-- overlayLayerRule:set_enabled(false) + +-- Hyprland-run windowrule +hl.window_rule({ + name = "move-hyprland-run", + match = { class = "hyprland-run" }, + + move = "20 monitor_h-120", + float = true, +}) + +-- For Noctalia Color templates +require("noctalia").apply_theme() diff --git a/hyprqt6engine.conf b/hyprqt6engine.conf new file mode 100644 index 0000000..99a0b40 --- /dev/null +++ b/hyprqt6engine.conf @@ -0,0 +1,5 @@ +theme { + color_scheme = /usr/share/color-schemes/BreezeDark.colors + style = Breeze + icon_theme = breeze-dark +} diff --git a/keybinds.lua b/keybinds.lua new file mode 100644 index 0000000..da6a18d --- /dev/null +++ b/keybinds.lua @@ -0,0 +1,80 @@ +local hyper = "MOD3 + " + +hl.bind("SUPER + SPACE", function() + hl.dispatch( + hl.dsp.exec_cmd("noctalia msg panel-toggle launcher") + ) +end, { + description = "Toggle Noctalia launcher", +}) + + +hl.bind("SUPER + W", hl.dsp.window.close()) + +for i = 1, 9 do + hl.bind( + "MOD3 + " .. i, + hl.dsp.focus({ workspace = i }), + { description = "Switch to workspace " .. i } + ) + + hl.bind( + "MOD3 + CTRL + " .. i, + hl.dsp.window.move({ workspace = i }), + { description = "Send focused window to " .. i } + ) +end + +local monitor_dirs = { + W = "u", + A = "l", + S = "d", + D = "r", +} + +for key, dir in pairs(monitor_dirs) do + hl.bind( + hyper .. " + SUPER + " .. key, + hl.dsp.workspace.move({ monitor = dir }), + { description = "Move workspace " .. dir } + ) +end + +--- Hyprspace + +hl.bind(hyper .. "SPACE", function() hl.plugin.hyprtasking.toggle("all") end) + +--- floating focus +hl.bind(hyper .. " F", function() + local win = hl.get_active_window() + local mon = hl.get_active_monitor() + + if not win or not mon then + return + end + + local was_tiled = not win.floating + + hl.dispatch(hl.dsp.window.float({ + action = "toggle", + })) + + -- Only resize when entering floating focus mode. + -- When leaving it, let the tiling layout restore the window. + if was_tiled then + hl.dispatch(hl.dsp.window.resize({ + x = math.floor(mon.width * 0.80), + y = math.floor(mon.height * 0.80), + relative = false, + })) + + hl.dispatch(hl.dsp.window.center()) + + hl.dispatch(hl.dsp.window.alter_zorder({ + mode = "top", + })) + end +end, { + description = "Toggle focused floating window", }) + +hl.bind("SUPER + SHIFT + S", hl.plugin.hyprcapture.open, { description = "HyprCapture window capture" }) diff --git a/noctalia.lua b/noctalia.lua new file mode 100644 index 0000000..4562308 --- /dev/null +++ b/noctalia.lua @@ -0,0 +1,45 @@ +-- Generated by Noctalia + +local primary = "rgb(fff59b)" +local surface = "rgb(070722)" +local secondary = "rgb(a9aefe)" +local error = "rgb(fd4663)" + +local function apply_theme() + hl.config({ + general = { + col = { + active_border = primary, + inactive_border = surface, + }, + }, + + group = { + col = { + border_active = secondary, + border_inactive = surface, + border_locked_active = error, + border_locked_inactive = surface, + }, + + groupbar = { + col = { + active = secondary, + inactive = surface, + locked_active = error, + locked_inactive = surface, + }, + }, + }, + }) +end + +return { + colors = { + primary = primary, + surface = surface, + secondary = secondary, + error = error, + }, + apply_theme = apply_theme +} diff --git a/scripts/select-layout b/scripts/select-layout new file mode 100755 index 0000000..c0642aa --- /dev/null +++ b/scripts/select-layout @@ -0,0 +1,28 @@ +#!/bin/sh + +set -eu + +selection="$({ + printf '1\tDwindle — binary split\n' + printf '2\tMaster — main window plus stack\n' + printf '3\tScrolling — columns\n' + printf '4\tMonocle — one window at a time\n' +} | noctalia dmenu -p 'Layout for current workspace (1-4)')" || exit 0 + +case "$selection" in + 1*) layout=dwindle ;; + 2*) layout=master ;; + 3*) layout=scrolling ;; + 4*) layout=monocle ;; + *) exit 0 ;; +esac + +workspace="$(hyprctl activeworkspace -j | jq -r '.id')" + +case "$workspace" in + ''|*[!0-9]*) exit 1 ;; +esac + +# Workspace rules are scoped to this workspace; changing general:layout would +# affect every workspace. +hyprctl keyword workspace "$workspace, layout:$layout" diff --git a/windowrules.lua b/windowrules.lua new file mode 100644 index 0000000..b75f700 --- /dev/null +++ b/windowrules.lua @@ -0,0 +1,14 @@ +hl.window_rule({ + name = "ueberzugpp-preview", + + match = { + class = "ueberzugpp_.*", + }, + + float = true, + no_initial_focus = true, + + border_size = 0, + rounding = 0, + no_shadow = true, +}) diff --git a/workspaces.lua b/workspaces.lua new file mode 100644 index 0000000..6ba01f3 --- /dev/null +++ b/workspaces.lua @@ -0,0 +1,67 @@ +local hyper = "MOD3" +local bili_space = "name:bilibili" +local im_space = "name:im" + +-- Master layout configuration +hl.config({ + master = { + mfact = 0.80, + orientation = "left", + + -- New windows go into the background/slave column, + -- rather than replacing your master. + new_status = "slave", + }, +}) + +-- Dedicated workspace +hl.workspace_rule({ + workspace = bili_space, + layout = "master", + layout_opts = { + orientation = "left", + }, + persistent = true, + monitor = "DP-3" +}) + +hl.workspace_rule({ + workspace = im_space, + layout = "master", + layout_opts = { + orientation = "left", + }, + persistent = true, + monitor = "DP-3" +}) + +hl.bind( + hyper .. " + F1", + hl.dsp.focus({ workspace = bili_space }), + { description = "Switch to bilibili workspace" } +) + +hl.bind( + hyper .. " + CTRL + F1", + hl.dsp.window.move({ workspace = bili_space }), + { description = "Send focused window to bilibili workspace" } +) + +hl.bind( + hyper .. " + F2", + hl.dsp.focus({ workspace = im_space }), + { description = "Switch to im workspace" } +) + +hl.bind( + hyper .. " + CTRL + F2", + hl.dsp.window.move({ workspace = im_space }), + { description = "Send focused window to im workspace" } +) + + +hl.bind( + hyper .. " + M", + hl.dsp.layout("swapwithmaster master ignoremaster"), + { description = "Promote to master" } +)