diff --git a/autostart.lua b/autostart.lua deleted file mode 100644 index ab1b771..0000000 --- a/autostart.lua +++ /dev/null @@ -1,30 +0,0 @@ -------------------- ----- 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/config/appearance.lua b/config/appearance.lua new file mode 100644 index 0000000..68ec5bc --- /dev/null +++ b/config/appearance.lua @@ -0,0 +1,90 @@ +-- Base visual behavior. Theme colors are intentionally applied separately at +-- the end of this module because Noctalia generates them. +hl.config({ + -- Window spacing, borders, and compositor-wide rendering behavior. + general = { + gaps_in = 5, + gaps_out = 20, + border_size = 2, + resize_on_border = false, + allow_tearing = false, + }, + + -- Window shape, opacity, shadows, and background blur. + decoration = { + rounding = 10, + rounding_power = 2, + 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, + }, + }, + + -- This is the global animation switch; individual animation tracks below + -- control timing and style. + animations = { + enabled = true, + }, + + -- Keep the built-in wallpaper enabled as a fallback. + misc = { + force_default_wallpaper = -1, + disable_hyprland_logo = false, + }, +}) + +-- Curves are data-driven so adding or tuning one does not require another +-- standalone `hl.curve` call. +local curves = { + { "easeOutQuint", { type = "bezier", points = { { 0.23, 1 }, { 0.32, 1 } } } }, + { "easeInOutCubic", { type = "bezier", points = { { 0.65, 0.05 }, { 0.36, 1 } } } }, + { "linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } } }, + { "almostLinear", { type = "bezier", points = { { 0.5, 0.5 }, { 0.75, 1 } } } }, + { "quick", { type = "bezier", points = { { 0.15, 0 }, { 0.1, 1 } } } }, + { "easy", { type = "spring", mass = 1, stiffness = 238.1191, dampening = 24.21279333 } }, +} + +for _, curve in ipairs(curves) do + hl.curve(curve[1], curve[2]) +end + +-- Animation tracks inherit from broader leaves unless a more specific track +-- (for example windowsIn or workspacesOut) overrides them. +local animations = { + { leaf = "global", enabled = true, speed = 10, bezier = "default" }, + { leaf = "border", enabled = true, speed = 5.39, bezier = "easeOutQuint" }, + { leaf = "windows", enabled = true, speed = 4.79, spring = "easy" }, + { leaf = "windowsIn", enabled = true, speed = 4.1, spring = "easy", style = "popin 87%" }, + { leaf = "windowsOut", enabled = true, speed = 1.49, bezier = "linear", style = "popin 87%" }, + { leaf = "fadeIn", enabled = true, speed = 1.73, bezier = "almostLinear" }, + { leaf = "fadeOut", enabled = true, speed = 1.46, bezier = "almostLinear" }, + { leaf = "fade", enabled = true, speed = 3.03, bezier = "quick" }, + { leaf = "layers", enabled = true, speed = 3.81, bezier = "easeOutQuint" }, + { leaf = "layersIn", enabled = true, speed = 4, bezier = "easeOutQuint", style = "fade" }, + { leaf = "layersOut", enabled = true, speed = 1.5, bezier = "linear", style = "fade" }, + { leaf = "fadeLayersIn", enabled = true, speed = 1.79, bezier = "almostLinear" }, + { leaf = "fadeLayersOut", enabled = true, speed = 1.39, bezier = "almostLinear" }, + { leaf = "workspaces", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }, + { leaf = "workspacesIn", enabled = true, speed = 1.21, bezier = "almostLinear", style = "fade" }, + { leaf = "workspacesOut", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }, + { leaf = "zoomFactor", enabled = true, speed = 7, bezier = "quick" }, +} + +for _, animation in ipairs(animations) do + hl.animation(animation) +end + +-- Noctalia generates the palette module; appearance owns when it is applied. +require("noctalia").apply_theme() diff --git a/config/autostart.lua b/config/autostart.lua new file mode 100644 index 0000000..48da9eb --- /dev/null +++ b/config/autostart.lua @@ -0,0 +1,26 @@ +-- Build the startup list once, using the same program names and UWSM wrapper as +-- the keybinding module. +local commands = require("lib.commands") +local settings = require("config.settings") + +local startup_commands = { + -- Session services that manage their own lifecycle. + "fcitx5 -d", + "hyprpm reload -n", + + -- Graphical/session applications launched inside UWSM scopes. + commands.uwsm(settings.programs.terminal), + commands.uwsm("hyprpaper"), + commands.uwsm("firefox"), + commands.uwsm("wl-paste --type text --watch cliphist store"), + commands.uwsm("wl-paste --type image --watch cliphist store"), + commands.uwsm("noctalia"), +} + +-- This event only fires when Hyprland starts; reloading the config will not +-- launch duplicate copies of these applications. +hl.on("hyprland.start", function() + for _, command in ipairs(startup_commands) do + hl.exec_cmd(command) + end +end) diff --git a/config/environment.lua b/config/environment.lua new file mode 100644 index 0000000..9810e44 --- /dev/null +++ b/config/environment.lua @@ -0,0 +1,6 @@ +-- Keep XCursor and Hyprcursor at the same size for consistent pointers across +-- XWayland and native Wayland applications. +local cursor_size = "24" + +hl.env("XCURSOR_SIZE", cursor_size) +hl.env("HYPRCURSOR_SIZE", cursor_size) diff --git a/config/input.lua b/config/input.lua new file mode 100644 index 0000000..ca2632f --- /dev/null +++ b/config/input.lua @@ -0,0 +1,31 @@ +-- Keyboard, pointer, and touchpad defaults shared by all input devices. +hl.config({ + input = { + kb_layout = "us", + kb_variant = "", + kb_model = "", + -- Turn Caps Lock into MOD3, which settings.lua exposes as Hyper. + kb_options = "caps:hyper", + kb_rules = "", + follow_mouse = 1, + sensitivity = 0, + + touchpad = { + natural_scroll = false, + }, + }, +}) + +-- Three-finger horizontal swipes move between workspaces. +hl.gesture({ + fingers = 3, + direction = "horizontal", + action = "workspace", +}) + +-- Example device-specific override retained from the original configuration. +-- It only applies when Hyprland sees a device with this exact name. +hl.device({ + name = "epic-mouse-v1", + sensitivity = -0.5, +}) diff --git a/config/keybinds.lua b/config/keybinds.lua new file mode 100644 index 0000000..1eaa172 --- /dev/null +++ b/config/keybinds.lua @@ -0,0 +1,167 @@ +-- All keybindings live in this module so conflicts can be audited in one +-- place. Shared values come from settings; command wrapping comes from lib. +local commands = require("lib.commands") +local settings = require("config.settings") + +local main = settings.modifiers.main +local hyper = settings.modifiers.hyper + +-- Build normalized bind strings and avoid hand-written separator mistakes such +-- as doubled `+` characters. +local function chord(...) + return table.concat({ ... }, " + ") +end + +-- Generate matching focus/move bindings for numbered workspaces. Workspace 10 +-- maps to the 0 key because `% 10` returns zero. +local function bind_numbered_workspaces(modifier, move_modifier, count) + for workspace = 1, count do + local key = workspace % 10 + + hl.bind( + chord(modifier, key), + hl.dsp.focus({ workspace = workspace }), + { description = "Switch to workspace " .. workspace } + ) + hl.bind( + chord(modifier, move_modifier, key), + hl.dsp.window.move({ workspace = workspace }), + { description = "Send focused window to workspace " .. workspace } + ) + end +end + +-- Core application and window-management shortcuts. +hl.bind( + chord(main, "SPACE"), + hl.dsp.exec_cmd("noctalia msg panel-toggle launcher"), + { description = "Toggle Noctalia launcher" } +) +hl.bind(chord(main, "W"), hl.dsp.window.close()) +hl.bind(chord(main, "Q"), hl.dsp.exec_cmd(commands.uwsm(settings.programs.terminal))) +hl.bind(chord(main, "E"), hl.dsp.exec_cmd(commands.uwsm(settings.programs.file_manager))) +hl.bind(chord(main, "V"), hl.dsp.window.float({ action = "toggle" })) +hl.bind(chord(main, "R"), hl.dsp.exec_cmd(settings.programs.launcher)) +hl.bind(chord(main, "P"), hl.dsp.window.pseudo()) +hl.bind(chord(main, "J"), hl.dsp.layout("togglesplit")) + +-- One direction table drives arrow-key focus, Hyper+WASD focus/movement, and +-- moving the active workspace between adjacent monitors. +local directions = { + { arrow = "left", key = "A", direction = "l" }, + { arrow = "right", key = "D", direction = "r" }, + { arrow = "up", key = "W", direction = "u" }, + { arrow = "down", key = "S", direction = "d" }, +} + +for _, direction in ipairs(directions) do + hl.bind( + chord(main, direction.arrow), + hl.dsp.focus({ direction = direction.arrow }) + ) + hl.bind( + chord(hyper, direction.key), + hl.dsp.focus({ direction = direction.direction }) + ) + hl.bind( + chord(hyper, "CTRL", direction.key), + hl.dsp.window.move({ direction = direction.direction }) + ) + hl.bind( + chord(hyper, main, direction.key), + hl.dsp.workspace.move({ monitor = direction.direction }), + { description = "Move workspace " .. direction.direction } + ) +end + +bind_numbered_workspaces(main, "SHIFT", 10) +bind_numbered_workspaces(hyper, "CTRL", 9) + +-- Cycle workspaces with the wheel and manipulate windows with mouse buttons. +hl.bind(chord(main, "mouse_down"), hl.dsp.focus({ workspace = "e+1" })) +hl.bind(chord(main, "mouse_up"), hl.dsp.focus({ workspace = "e-1" })) +hl.bind(chord(main, "mouse:272"), hl.dsp.window.drag(), { mouse = true }) +hl.bind(chord(main, "mouse:273"), hl.dsp.window.resize(), { mouse = true }) + +-- Locked media keys also work while the session is locked. Volume and +-- brightness binds repeat while held; playback controls fire once. +local media_binds = { + { "XF86AudioRaiseVolume", "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+", { locked = true, repeating = true } }, + { "XF86AudioLowerVolume", "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-", { locked = true, repeating = true } }, + { "XF86AudioMute", "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", { locked = true, repeating = true } }, + { "XF86AudioMicMute", "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle", { locked = true, repeating = true } }, + { "XF86MonBrightnessUp", "brightnessctl -e4 -n2 set 5%+", { locked = true, repeating = true } }, + { "XF86MonBrightnessDown", "brightnessctl -e4 -n2 set 5%-", { locked = true, repeating = true } }, + { "XF86AudioNext", "playerctl next", { locked = true } }, + { "XF86AudioPause", "playerctl play-pause", { locked = true } }, + { "XF86AudioPlay", "playerctl play-pause", { locked = true } }, + { "XF86AudioPrev", "playerctl previous", { locked = true } }, +} + +for _, bind in ipairs(media_binds) do + hl.bind(bind[1], hl.dsp.exec_cmd(bind[2]), bind[3]) +end + +-- Generate focus/move shortcuts for every named workspace in settings.lua. +for _, workspace in ipairs(settings.named_workspaces) do + hl.bind( + chord(hyper, workspace.key), + hl.dsp.focus({ workspace = workspace.selector }), + { description = "Switch to " .. workspace.name .. " workspace" } + ) + hl.bind( + chord(hyper, "CTRL", workspace.key), + hl.dsp.window.move({ workspace = workspace.selector }), + { description = "Send focused window to " .. workspace.name .. " workspace" } + ) +end + +-- Promote the focused client when a workspace is using master layout. +hl.bind( + chord(hyper, "M"), + hl.dsp.layout("swapwithmaster master ignoremaster"), + { description = "Promote to master" } +) + +-- Hyprtasking provides a visual overview of windows on all workspaces. +hl.bind( + chord(hyper, "SPACE"), + function() + hl.plugin.hyprtasking.toggle("all") + end +) + +-- Toggle a focused client into an 80%-sized centered floating mode. Returning +-- it to tiled mode lets the active layout restore its previous geometry. +hl.bind(chord(hyper, "F"), function() + local window = hl.get_active_window() + local monitor = hl.get_active_monitor() + + if not window or not monitor then + return + end + + local was_tiled = not window.floating + hl.dispatch(hl.dsp.window.float({ action = "toggle" })) + + if not was_tiled then + return + end + + hl.dispatch(hl.dsp.window.resize({ + x = math.floor(monitor.width * 0.80), + y = math.floor(monitor.height * 0.80), + relative = false, + })) + hl.dispatch(hl.dsp.window.center()) + hl.dispatch(hl.dsp.window.alter_zorder({ mode = "top" })) +end, { + description = "Toggle focused floating window", +}) + +-- Open the HyprCapture plugin's interactive region/window picker. +hl.bind( + chord(main, "SHIFT", "S"), + hl.plugin.hyprcapture.open, + { description = "HyprCapture window capture" } +) diff --git a/config/layouts.lua b/config/layouts.lua new file mode 100644 index 0000000..c713f0d --- /dev/null +++ b/config/layouts.lua @@ -0,0 +1,26 @@ +-- Keep layout defaults together so a later module cannot silently override a +-- single field from another `hl.config` call. +hl.config({ + -- Dwindle is the default layout for ordinary workspaces. + general = { + layout = "dwindle", + }, + + -- Remember the user's most recent split direction in dwindle. + dwindle = { + preserve_split = true, + }, + + -- Named workspaces opt into master layout. New windows enter the slave + -- column, leaving the current master in place. + master = { + mfact = 0.80, + orientation = "left", + new_status = "slave", + }, + + -- Expand the only column when using Hyprland's scrolling layout. + scrolling = { + fullscreen_on_one_column = true, + }, +}) diff --git a/config/monitors.lua b/config/monitors.lua new file mode 100644 index 0000000..358a55b --- /dev/null +++ b/config/monitors.lua @@ -0,0 +1,7 @@ +-- Apply the physical display topology defined in the shared settings module. +local settings = require("config.settings") + +-- HDMI is the left/high-refresh display; DisplayPort is positioned to its +-- right and also hosts the dedicated named workspaces. +hl.monitor(settings.monitors.primary) +hl.monitor(settings.monitors.secondary) diff --git a/config/settings.lua b/config/settings.lua new file mode 100644 index 0000000..d496904 --- /dev/null +++ b/config/settings.lua @@ -0,0 +1,49 @@ +-- Central user-editable values. Domain modules consume this table so monitor +-- names, applications, modifiers, and workspace selectors stay in sync. +return { + -- SUPER is used for conventional desktop shortcuts. Caps Lock is mapped to + -- MOD3 in input.lua and acts as the Hyper modifier. + modifiers = { + main = "SUPER", + hyper = "MOD3", + }, + + -- Store raw executable names here. Callers decide whether a command should + -- be wrapped with `uwsm-app` or executed directly. + programs = { + terminal = "alacritty", + file_manager = "dolphin", + launcher = "hyprlauncher", + }, + + -- Named outputs make cross-module references (such as workspace routing) + -- clearer than array indexes. + monitors = { + primary = { + output = "HDMI-A-1", + mode = "2560x1440@144", + position = "0x0", + scale = 1, + }, + secondary = { + output = "DP-3", + mode = "2560x1440@120", + position = "2560x0", + scale = 1, + }, + }, + + -- Both workspace rules and keybindings are generated from this list. + named_workspaces = { + { + name = "bilibili", + selector = "name:bilibili", + key = "F1", + }, + { + name = "im", + selector = "name:im", + key = "F2", + }, + }, +} diff --git a/config/window_rules.lua b/config/window_rules.lua new file mode 100644 index 0000000..25969ad --- /dev/null +++ b/config/window_rules.lua @@ -0,0 +1,51 @@ +-- Window rules are kept as data and registered in order at the bottom. This +-- makes adding a rule independent from the registration mechanism. +local rules = { + -- Render terminal image previews as undecorated, non-focusing overlays. + { + name = "ueberzugpp-preview", + match = { + class = "ueberzugpp_.*", + }, + float = true, + no_initial_focus = true, + border_size = 0, + rounding = 0, + no_shadow = true, + }, + -- Ignore application requests to maximize themselves. + { + name = "suppress-maximize-events", + match = { + class = ".*", + }, + suppress_event = "maximize", + }, + -- Prevent empty XWayland drag helper windows from stealing focus. + { + name = "fix-xwayland-drags", + match = { + class = "^$", + title = "^$", + xwayland = true, + float = true, + fullscreen = false, + pin = false, + }, + no_focus = true, + }, + -- Place the Hyprland runner near the lower-left edge as a floating window. + { + name = "move-hyprland-run", + match = { + class = "hyprland-run", + }, + move = "20 monitor_h-120", + float = true, + }, +} + +-- Register every declarative rule with Hyprland. +for _, rule in ipairs(rules) do + hl.window_rule(rule) +end diff --git a/config/workspaces.lua b/config/workspaces.lua new file mode 100644 index 0000000..51e2824 --- /dev/null +++ b/config/workspaces.lua @@ -0,0 +1,15 @@ +-- Create persistent master-layout workspaces from the shared workspace list. +local settings = require("config.settings") + +for _, workspace in ipairs(settings.named_workspaces) do + hl.workspace_rule({ + workspace = workspace.selector, + layout = "master", + layout_opts = { + orientation = "left", + }, + persistent = true, + -- Keep communication/media workspaces on the right-hand monitor. + monitor = settings.monitors.secondary.output, + }) +end diff --git a/hyprland.lua b/hyprland.lua index 3a6a769..f9b5c07 100644 --- a/hyprland.lua +++ b/hyprland.lua @@ -1,375 +1,25 @@ --- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --- AUTOGENERATED HYPRLAND CONFIG. -- --- EDIT THIS CONFIG ACCORDING TO THE WIKI INSTRUCTIONS. -- --- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +-- Configuration entry point. Each module owns one Hyprland domain and applies +-- its configuration when required. +local modules = { + -- Hardware and environment are loaded first so later modules can rely on + -- the configured outputs and session variables. + "config.monitors", + "config.environment", --- This is an example Hyprland Lua config file. --- Refer to the wiki for more information. --- https://wiki.hypr.land/Configuring/Start/ + -- Core compositor behavior and presentation. + "config.appearance", + "config.layouts", + "config.input", --- Please note not all available settings / options are set here. --- For a full list, see the wiki + -- User-facing rules, shortcuts, and startup integrations. + "config.workspaces", + "config.window_rules", + "config.keybinds", + "config.autostart", +} --- 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 +-- Requiring a module applies that domain's configuration through the global +-- Hyprland Lua API (`hl`). +for _, module in ipairs(modules) do + require(module) 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/keybinds.lua b/keybinds.lua deleted file mode 100644 index da6a18d..0000000 --- a/keybinds.lua +++ /dev/null @@ -1,80 +0,0 @@ -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/lib/commands.lua b/lib/commands.lua new file mode 100644 index 0000000..017eeda --- /dev/null +++ b/lib/commands.lua @@ -0,0 +1,10 @@ +-- Small command builders shared by keybindings and autostart. +local M = {} + +-- Launch graphical applications through UWSM so they inherit the managed +-- Wayland session environment and systemd scope. +function M.uwsm(command) + return "uwsm-app -- " .. command +end + +return M diff --git a/noctalia.lua b/noctalia.lua index 4562308..57caf27 100644 --- a/noctalia.lua +++ b/noctalia.lua @@ -1,10 +1,13 @@ -- Generated by Noctalia +-- This file is the generated color boundary: config/appearance.lua calls +-- apply_theme(), while other modules remain independent of palette values. local primary = "rgb(fff59b)" local surface = "rgb(070722)" local secondary = "rgb(a9aefe)" local error = "rgb(fd4663)" +-- Apply generated colors to regular borders, grouped windows, and group tabs. local function apply_theme() hl.config({ general = { @@ -35,11 +38,14 @@ local function apply_theme() end return { + -- Expose the raw palette for future modules that need matching colors. colors = { primary = primary, surface = surface, secondary = secondary, error = error, }, + -- Keep application explicit so requiring this generated file has no side + -- effects on its own. apply_theme = apply_theme } diff --git a/windowrules.lua b/windowrules.lua deleted file mode 100644 index b75f700..0000000 --- a/windowrules.lua +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 6ba01f3..0000000 --- a/workspaces.lua +++ /dev/null @@ -1,67 +0,0 @@ -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" } -)