diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000..d738a82 --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,60 @@ +{ + "features": { + "ghcr.io/devcontainers-extra/features/fish-apt-get:1": { + "version": "1.0.5", + "resolved": "ghcr.io/devcontainers-extra/features/fish-apt-get@sha256:d3c21bb6aec6e0f9d5348adee443c70c31d5f4372b8ad5f56a0ab925b2725108", + "integrity": "sha256:d3c21bb6aec6e0f9d5348adee443c70c31d5f4372b8ad5f56a0ab925b2725108" + }, + "ghcr.io/guziomg/devcontainers/extension-spellcheck:latest": { + "version": "1.0.0", + "resolved": "ghcr.io/guziomg/devcontainers/extension-spellcheck@sha256:954a79f524e5130b7c961e6d0ac7252fbc8e40c5e63229b030f5a27477dfa7ce", + "integrity": "sha256:954a79f524e5130b7c961e6d0ac7252fbc8e40c5e63229b030f5a27477dfa7ce" + }, + "ghcr.io/guziomg/devcontainers/extensions-essentials-ultimate:latest": { + "version": "1.0.0", + "resolved": "ghcr.io/guziomg/devcontainers/extensions-essentials-ultimate@sha256:62483dfabb169b804d1d385eccf0344a8b0d6a62c60b3761d579e70a59291772", + "integrity": "sha256:62483dfabb169b804d1d385eccf0344a8b0d6a62c60b3761d579e70a59291772", + "dependsOn": [ + "ghcr.io/guziomg/devcontainers/extensions-github:latest", + "ghcr.io/guziomg/devcontainers/extensions-essentials:latest", + "ghcr.io/guziomg/devcontainers/extension-spellcheck:latest" + ] + }, + "ghcr.io/guziomg/devcontainers/extensions-essentials:latest": { + "version": "1.0.0", + "resolved": "ghcr.io/guziomg/devcontainers/extensions-essentials@sha256:bbd0673cb07d64ca60e714a786db2c55bf921fbd49bad907376a0dfa960258d9", + "integrity": "sha256:bbd0673cb07d64ca60e714a786db2c55bf921fbd49bad907376a0dfa960258d9" + }, + "ghcr.io/guziomg/devcontainers/extensions-github:latest": { + "version": "1.0.0", + "resolved": "ghcr.io/guziomg/devcontainers/extensions-github@sha256:5455b28dcb0cfa1c4a0ed0c9ac9fad263af9c5265406021923c50027b6ca62d9", + "integrity": "sha256:5455b28dcb0cfa1c4a0ed0c9ac9fad263af9c5265406021923c50027b6ca62d9" + }, + "ghcr.io/guziomg/devcontainers/fish-apt-extended:latest": { + "version": "1.1.0", + "resolved": "ghcr.io/guziomg/devcontainers/fish-apt-extended@sha256:ce8190cd2f0365c625c2e8b5800f27771ccf517823feb082ec96c75f5c083a66", + "integrity": "sha256:ce8190cd2f0365c625c2e8b5800f27771ccf517823feb082ec96c75f5c083a66", + "dependsOn": [ + "ghcr.io/devcontainers-extra/features/fish-apt-get:1" + ] + }, + "ghcr.io/guziomg/devcontainers/personal:latest": { + "version": "1.0.0", + "resolved": "ghcr.io/guziomg/devcontainers/personal@sha256:f116eaa06ae322f69943724323d757c8fb9b326c3bd7fc1899ee4d54863568ff", + "integrity": "sha256:f116eaa06ae322f69943724323d757c8fb9b326c3bd7fc1899ee4d54863568ff", + "dependsOn": [ + "ghcr.io/guziomg/devcontainers/extensions-essentials-ultimate:latest", + "ghcr.io/guziomg/devcontainers/polskie-rozszerzenia:latest", + "ghcr.io/guziomg/devcontainers/fish-apt-extended:latest" + ] + }, + "ghcr.io/guziomg/devcontainers/polskie-rozszerzenia:latest": { + "version": "1.0.0", + "resolved": "ghcr.io/guziomg/devcontainers/polskie-rozszerzenia@sha256:708c77bf302f7a097384dd98b3beec2e344e4965995ab38a3f861bb923fcf71d", + "integrity": "sha256:708c77bf302f7a097384dd98b3beec2e344e4965995ab38a3f861bb923fcf71d", + "dependsOn": [ + "ghcr.io/guziomg/devcontainers/extension-spellcheck:latest" + ] + } + } +} \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..520bd78 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,8 @@ +{ + "name": "Hyprland configs", + "image": "mcr.microsoft.com/devcontainers/base:noble", + "features": { + //"ghcr.io/guziomg/devcontainers/hyprland:latest": {}, + "ghcr.io/guziomg/devcontainers/personal:latest": {} + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e2f0a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +scripts/volume-bin \ No newline at end of file diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..4deb9fd --- /dev/null +++ b/.luarc.json @@ -0,0 +1,7 @@ +{ + "workspace": { + "library": [ + "/usr/share/hypr/stubs" + ] + } + } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..00067de --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "cSpell.words": [ + "envar", + "hypr", + "hyprpanel", + "killall" + ] +} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 0979c10..466c6e4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,18 +1,7 @@ MIT License -Copyright (c) 2026 Guzio +Copyright © 2026 Guzio -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/hyprland.conf.stub b/hyprland.conf.stub new file mode 100644 index 0000000..d1e9a7e --- /dev/null +++ b/hyprland.conf.stub @@ -0,0 +1,16 @@ +# This config is a STUB! This should never be generated. +# Use the default lua config from https://github.com/hyprwm/Hyprland/blob/main/example/hyprland.lua + + + +$mainMod = SUPER +$terminal = konsole +$fileManager = dolphin +$menu = hyprlauncher + +bind = $mainMod, Q, exec, $terminal +bind = $mainMod, C, killactive, +bind = $mainMod, M, exec, command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch exit +bind = $mainMod, E, exec, $fileManager +bind = $mainMod, V, togglefloating, +bind = $mainMod, R, exec, $menu \ No newline at end of file diff --git a/hyprland.lua b/hyprland.lua new file mode 100644 index 0000000..0bcaade --- /dev/null +++ b/hyprland.lua @@ -0,0 +1,413 @@ +------------------- +---- VARIABLES ---- +------------------- +local hyprdir = ".config/hypr/" +local scripts = hyprdir.."scripts/" + +-- Set programs that I use +local terminal = scripts.."terminal.sh" +local fileManager = "dolphin" +local menu = scripts.."toggle_hyprshell.sh" + + +------------------ +---- MONITORS ---- +------------------ + +-- See https://wiki.hypr.land/Configuring/Basics/Monitors/ + +-- defaults +hl.monitor({ + output = "", + mode = "preferred", + position = "auto", + scale = 1, + mirror = "eDP-1", +}) + +-- Main tablet screen +hl.monitor({ + output = "eDP-1", + mode = "preferred", + position = "0x0", + scale = 1, +}) + +-- My monitor at home +hl.monitor({ + output = "desc:Acer Technologies Acer XF240H 0x0160F332", + mode = "preferred", + position = "1925x-900", + scale = 1, +}) + + +------------------- +---- AUTOSTART ---- +------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Autostart/ + +hl.on("hyprland.start", function () + -- Load plugins + --hl.exec_cmd("hyprpm reload") + + -- Special workspaces + hl.exec_cmd(terminal) + hl.exec_cmd("flatpak run app.zen_browser.zen") + hl.exec_cmd("flatpak run com.discordapp.Discord") + hl.exec_cmd("flatpak run im.riot.Riot") + hl.exec_cmd("flatpak run md.obsidian.Obsidian") + + -- Core daemons + hl.exec_cmd("hyprshell -c "..hyprdir.."hyprshell.ron -s "..hyprdir.."hyprshell.css run") + hl.exec_cmd("vicinae server") + hl.exec_cmd("wvkbd-deskintl --hidden -o") + hl.exec_cmd("hyprpanel") + hl.exec_cmd(scripts.."keyboard.sh reset") + hl.exec_cmd(scripts.."volume-core.sh --start-daemon") + + -- Waydroid (note: this also launches rootedinit.sh under-the-hood) + hl.exec_cmd(scripts.."waydroid.sh") + + -- Dark theme + hl.exec_cmd("gsettings set org.gnome.desktop.interface gtk-theme Breeze-Dark"); -- for GTK3 apps + hl.exec_cmd("gsettings set org.gnome.desktop.interface color-scheme prefer-dark"); -- for GTK4 apps + hl.exec_cmd("gsettings set org.gnome.desktop.interface gtk-color-palette \"'black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90'\""); --Unrelated to Dark Theme (just my color palette), but there was no better place for it. +end) + + +------------------------------- +---- ENVIRONMENT VARIABLES ---- +------------------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Environment-variables/ + +-- Were the defaults; no reason to fuck around +hl.env("XCURSOR_SIZE", "24") +hl.env("HYPRCURSOR_SIZE", "24") + +-- Dark theme, again (*must set manually) +hl.env("QT_QPA_PLATFORMTHEME", "qt6ct") + + +----------------------- +----- PERMISSIONS ----- +----------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Permissions/ + +hl.config({ + ecosystem = { + enforce_permissions = true, + }, +}) + +hl.permission({binary="/usr/(bin|local/bin)/grim", type="screencopy", mode="allow"}) +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"}) +hl.permission({binary="/usr/(bin|local/bin)/hyprshell", type="plugin", mode="allow"}) + + +----------------------- +---- LOOK AND FEEL ---- +----------------------- + +-- Refer to https://wiki.hypr.land/Configuring/Basics/Variables/ +hl.config({ + general = { + gaps_in = 4, + gaps_out = {top=0, right=8, bottom=8, left=8}, + + border_size = 2, + + col = { + active_border = { colors = {"rgb(FFE610)", "rgb(E6FF10)"}, angle = 240 }, + inactive_border = { colors = {"rgba(FFE61020)", "rgba(E6FF10E0)"}, angle = 240 }, + }, + + -- Set to true to enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = true, + + -- Please see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Tearing/ before you turn this on + allow_tearing = false, + + layout = "dwindle", + }, + + decoration = { + rounding = 15, + rounding_power = 3, + + -- 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, --During the Lua migration, I noticed the following note attached in the previous config: „NOTE: Occasionally (when terminal breaks), this needs to be disabled (until I figure out how to get blur only on the background ALWAYS, without making all terminal text glow SOMETIMES)”. However, I don't think I experienced any „terminal glowing” problems in a long time (tho transparency still breaks on it from time to time), so ig this is no longer needed? Leaving the note in, just in case it does end up happening again. + 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 = 71.2633, dampening = 15.8273644 }) + +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" }) + +-- Special workspaces slide-in from the top (thx, https://github.com/hyprwm/Hyprland/discussions/1757#discussioncomment-8921961) +hl.animation({ leaf = "specialWorkspaceIn", enabled=true, speed=2, bezier="easeInOutCubic", style="slidefadevert -50%" }) +hl.animation({ leaf = "specialWorkspaceOut", enabled=true, speed=2, bezier="easeInOutCubic", style="slidefadevert -50%" }) + +-- 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 = 2, -- 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 = "pl", + kb_variant = "", + kb_model = "", + kb_options = "fkeys:basic_13-24", + kb_rules = "", + + follow_mouse = 1, + + sensitivity = 0, -- -1.0 - 1.0, 0 means no modification. + + touchpad = { + natural_scroll = true, + }, + }, +}) + + +--------------------- +---- 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 .. " + T", hl.dsp.exec_cmd(terminal)) +local closeWindowBind = hl.bind(mainMod .. " + Q", hl.dsp.window.close()) +-- closeWindowBind:set_enabled(false) +hl.bind(mainMod .. " + M", hl.dsp.exit()) +hl.bind(mainMod .. " + SUPER_L", hl.dsp.exec_cmd(menu), { release = true }) + +-- Quick-pad: Special workspaces + boss-key +hl.bind(mainMod .. " + X", hl.dsp.workspace.toggle_special("terminal")) +hl.bind(mainMod .. " + A", hl.dsp.workspace.toggle_special("browser")) +hl.bind(mainMod .. " + D", hl.dsp.workspace.toggle_special("discord")) +hl.bind(mainMod .. " + C", hl.dsp.workspace.toggle_special("element")) +hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("obsidian")) +hl.bind(mainMod .. " + Z", hl.dsp.exec_cmd(scripts.."hide.sh")) + +-- 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("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 }) + +-- Screenshots +hl.bind("PRINT", hl.dsp.exec_cmd(scripts.."screenshot.sh")) +hl.bind(mainMod.." + PRINT", hl.dsp.exec_cmd(scripts.."screenshot.sh --full")) + + +-------------------------------- +---- 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) -- ...No, I won't. I run everything as exclusive-window-per-workspace anyway, so I'm not worried about „Windows deciding to take up all my space” (I literally do that). All this will do is cause de-syncs (especially in client-side decorated apps, like all the crapware made in GTK) for exactly 0 benefit. + +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, +}) + +-- Hyprland-run windowrule +hl.window_rule({ + name = "move-hyprland-run", + match = { class = "hyprland-run" }, + move = "20 monitor_h-120", + float = true, +}) + +-- My rules + +hl.window_rule({ + name = "onwinopen-default", + match = { + class = ".*", + float = false + }, + workspace = "emptym" +}) + +hl.window_rule({ + name = "onwinopen-override-special-terminal", + match = { class = "org.kde.konsole" }, + workspace = "special:terminal" +}) + +hl.window_rule({ + name = "onwinopen-override-special-browser", + match = { class = "app.zen_browser.zen" }, + workspace = "special:browser silent" +}) + +hl.window_rule({ + name = "onwinopen-override-special-discord", + match = { class = "discord" }, + workspace = "special:discord silent" +}) + +hl.window_rule({ + name = "onwinopen-override-special-element", + match = { class = "im.riot.Riot" }, + workspace = "special:element silent" +}) + +hl.window_rule({ + name = "onwinopen-override-special-obsidian", + match = { class = "obsidian" }, + workspace = "special:obsidian silent" +}) + +hl.window_rule({ + name = "onwinopen-override-minecraft-default", + match = { class = "Minecraft.*" }, + workspace = "emptym", + maximize = true +}) + +hl.window_rule({ + name = "onwinopen-override-minecraft-modpack-melatonin", + match = { class = "Melatonin" }, + workspace = "emptym", + maximize = true +}) + +hl.window_rule({ + name = "onwinopen-override-waydroid", + match = { class = "Waydroid" }, + workspace = "special:waydroid", + fullscreen = true +}) + + +------------------- +---- HYPRGRASS ---- +------------------- + +--hl.plugin.touch_gestures = { +-- sensitivity = 4.0, +-- edge_margin = 50, +-- ["hyprgrass-bind"] = ", edge:d:u, exec, $scriptsdir/keyboard.sh --no-rotate", +-- ["hyprgrass-bind"] = ", tap:3, exec, $menu -k" +--} \ No newline at end of file diff --git a/hyprlock.conf b/hyprlock.conf new file mode 100644 index 0000000..b2bf458 --- /dev/null +++ b/hyprlock.conf @@ -0,0 +1,107 @@ +# sample hyprlock.conf +# for more configuration options, refer https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock +# +# rendered text in all widgets supports pango markup (e.g. or tags) +# ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#general-remarks +# +# shortcuts to clear password buffer: ESC, Ctrl+U, Ctrl+Backspace +# +# you can get started by copying this config to ~/.config/hypr/hyprlock.conf +# + +$font = Monospace + +general { + # CHANGED: to true + hide_cursor = true +} + +# uncomment to enable fingerprint authentication +# auth { +# fingerprint { +# enabled = true +# ready_message = Scan fingerprint to unlock +# present_message = Scanning... +# retry_delay = 250 # in milliseconds +# } +# } + +animations { + enabled = true + bezier = linear, 1, 1, 0, 0 + animation = fadeIn, 1, 5, linear + animation = fadeOut, 1, 5, linear + animation = inputFieldDots, 1, 2, linear +} + +background { + monitor = + path = screenshot + blur_passes = 3 +} + +input-field { + monitor = + size = 20%, 5% + outline_thickness = 3 + inner_color = rgba(0, 0, 0, 0.0) # no fill + + outer_color = rgba(33ccffee) rgba(00ff99ee) 45deg + check_color = rgba(00ff99ee) rgba(ff6633ee) 120deg + fail_color = rgba(ff6633ee) rgba(ff0066ee) 40deg + + font_color = rgb(143, 143, 143) + fade_on_empty = false + rounding = 15 + + font_family = $font + placeholder_text = Input password... + fail_text = $PAMFAIL + + # uncomment to use a letter instead of a dot to indicate the typed password + # dots_text_format = * + # dots_size = 0.4 + dots_spacing = 0.3 + + # uncomment to use an input indicator that does not show the password length (similar to swaylock's input indicator) + # hide_input = true + + position = 0, -20 + halign = center + valign = center +} + +# TIME +label { + monitor = + text = $TIME # ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#variable-substitution + font_size = 90 + font_family = $font + + position = -30, 0 + halign = right + valign = top +} + +# DATE +label { + monitor = + text = cmd[update:60000] date +"%A, %d %B %Y" # update every 60 seconds + font_size = 25 + font_family = $font + + position = -30, -150 + halign = right + valign = top +} + +label { + monitor = + text = $LAYOUT[en,ru] + font_size = 24 + onclick = hyprctl switchxkblayout all next + + position = 250, -20 + halign = center + valign = center +} \ No newline at end of file diff --git a/hyprpanel/config.json b/hyprpanel/config.json new file mode 100644 index 0000000..4433b48 --- /dev/null +++ b/hyprpanel/config.json @@ -0,0 +1,178 @@ +{ + "bar.customModules.storage.paths": [ + "/" + ], + "theme.bar.floating": false, + "bar.layouts": { + "0": { + "middle": [ + "worldclock" + ], + "right": [ + "microphone", + "cava", + "battery", + "windowtitle", + "custom/desktop" + ], + "left": [ + "dashboard", + "custom/menu", + "custom/screenshot", + "custom/rotate", + "custom/keyboard", + "custom/clipboard", + "systray", + "notifications" + ] + }, + "1": { + "left": [ + "dashboard", + "workspaces", + "windowtitle" + ], + "middle": [ + "media" + ], + "right": [ + "volume", + "network", + "bluetooth", + "battery", + "systray", + "clock", + "notifications" + ] + }, + "2": { + "left": [ + "dashboard", + "workspaces", + "windowtitle" + ], + "middle": [ + "media" + ], + "right": [ + "volume", + "clock", + "notifications" + ] + } + }, + "menus.dashboard.controls.enabled": true, + "menus.dashboard.shortcuts.enabled": false, + "menus.dashboard.directories.enabled": false, + "menus.volume.raiseMaximumVolume": false, + "bar.launcher.icon": "󰚥", + "menus.clock.weather.enabled": false, + "menus.power.showLabel": true, + "menus.clock.time.military": true, + "menus.clock.weather.location": "Los Angeles", + "bar.customModules.worldclock.leftClick": "menu:calendar", + "theme.bar.buttons.modules.worldclock.enableBorder": true, + "bar.customModules.worldclock.format": "%H:%M:%S", + "menus.clock.time.hideSeconds": false, + "menus.clock.weather.unit": "imperial", + "bar.customModules.worldclock.divider": "", + "bar.customModules.worldclock.tz": [ + "Europe/Warsaw" + ], + "bar.customModules.worldclock.icon": "", + "bar.customModules.cava.leftClick": "menu:media", + "bar.customModules.cava.middleClick": "", + "theme.bar.menus.opacity": 100, + "theme.bar.opacity": 100, + "theme.bar.buttons.dashboard.icon": "#f9e2af", + "theme.bar.buttons.dashboard.border": "#f9e2af", + "theme.bar.buttons.style": "wave2", + "theme.bar.menus.border.color": "#313244", + "theme.bar.buttons.battery.text": "#f9e2af", + "theme.bar.buttons.battery.icon": "#f9e2af", + "theme.bar.transparent": true, + "bar.launcher.autoDetectIcon": false, + "theme.bar.buttons.dashboard.enableBorder": true, + "bar.workspaces.monitorSpecific": false, + "bar.workspaces.show_numbered": false, + "bar.workspaces.ignored": "-[0-9]+", + "theme.bar.buttons.windowtitle.enableBorder": true, + "bar.windowtitle.custom_title": true, + "theme.bar.buttons.notifications.enableBorder": true, + "bar.notifications.show_total": true, + "bar.notifications.hideCountWhenZero": true, + "theme.bar.buttons.battery.enableBorder": true, + "theme.bar.buttons.workspaces.enableBorder": true, + "theme.bar.buttons.volume.enableBorder": true, + "theme.bar.buttons.network.enableBorder": true, + "theme.bar.buttons.bluetooth.enableBorder": true, + "theme.bar.buttons.systray.enableBorder": true, + "theme.bar.buttons.clock.enableBorder": true, + "theme.bar.buttons.media.enableBorder": true, + "theme.bar.buttons.modules.microphone.enableBorder": true, + "theme.bar.buttons.modules.ram.enableBorder": true, + "theme.bar.buttons.modules.cpu.enableBorder": true, + "theme.bar.buttons.modules.cpuTemp.enableBorder": true, + "theme.bar.buttons.modules.storage.enableBorder": true, + "theme.bar.buttons.modules.netstat.enableBorder": true, + "theme.bar.buttons.modules.kbLayout.enableBorder": true, + "theme.bar.buttons.modules.updates.enableBorder": true, + "theme.bar.buttons.modules.submap.enableBorder": true, + "theme.bar.buttons.modules.weather.enableBorder": true, + "theme.bar.buttons.modules.hypridle.enableBorder": true, + "theme.bar.buttons.modules.cava.enableBorder": true, + "theme.bar.buttons.modules.power.enableBorder": true, + "bar.customModules.cava.rightClick": "menu:audio", + "bar.volume.rightClick": "menu:media", + "bar.customModules.cava.scrollDown": "hyprpanel vol -5", + "bar.customModules.cava.scrollUp": "hyprpanel vol +5", + "bar.clock.icon": "", + "bar.clock.format": "%A, %Y-%m-%d %H:%M:%S", + "bar.customModules.worldclock.formatDiffDate": "", + "bar.windowtitle.leftClick": "hyprctl dispatch \"hl.dsp.window.close()\"", + "bar.workspaces.show_icons": false, + "bar.workspaces.workspaces": 5, + "bar.workspaces.icons.available": "", + "bar.workspaces.showWsIcons": true, + "bar.workspaces.showApplicationIcons": true, + "bar.workspaces.applicationIconEmptyWorkspace": "", + "theme.bar.buttons.workspaces.smartHighlight": true, + "bar.workspaces.applicationIconOncePerWorkspace": false, + "bar.workspaces.numbered_active_indicator": "highlight", + "theme.bar.buttons.workspaces.numbered_inactive_padding": "0em", + "theme.bar.buttons.workspaces.fontSize": "1.2em", + "theme.bar.buttons.workspaces.pill.radius": "1.9rem * 0.6", + "bar.windowtitle.class_name": true, + "bar.windowtitle.truncation_size": 1, + "bar.windowtitle.icon": true, + "bar.customModules.microphone.label": false, + "menus.media.noMediaText": "Cicho tutaj...", + "bar.volume.label": true, + "bar.network.label": true, + "bar.network.showWifiInfo": true, + "bar.bluetooth.label": false, + "theme.bar.buttons.monochrome": true, + "theme.bar.buttons.borderColor": "#e6ff10", + "theme.bar.buttons.text": "#e6ff10", + "theme.bar.buttons.icon": "#e6ff10", + "theme.bar.buttons.icon_background": "#242438", + "theme.bar.buttons.background": "#000000", + "theme.bar.buttons.workspaces.active": "#e6ff10", + "theme.bar.buttons.workspaces.numbered_active_highlighted_text_color": "#000000", + "theme.bar.buttons.workspaces.background": "#000000", + "theme.bar.buttons.workspaces.occupied": "#62a0ea", + "theme.bar.buttons.workspaces.available": "#77767b", + "theme.bar.buttons.workspaces.hover": "#62a0ea", + "menus.transition": "crossfade", + "theme.bar.border.width": "0.15em", + "theme.bar.layer": "top", + "theme.bar.margin_sides": "0.5em", + "theme.bar.buttons.enableBorders": false, + "theme.bar.border_radius": "0.4em", + "theme.bar.outer_spacing": "0.2em", + "theme.bar.buttons.y_margins": "0.33em", + "theme.bar.buttons.spacing": "0.19em", + "theme.bar.buttons.padding_x": "0.7rem", + "theme.bar.buttons.padding_y": "0.2rem", + "theme.bar.buttons.background_hover_opacity": 100 +} \ No newline at end of file diff --git a/hyprpanel/modules.json b/hyprpanel/modules.json new file mode 100644 index 0000000..f67db12 --- /dev/null +++ b/hyprpanel/modules.json @@ -0,0 +1,45 @@ +{ + "custom/keyboard": { + "icon": "\udb80\udf0c", + "tooltip": "Przełącz klawiaturę.", + "actions": { + "onLeftClick": "$HOME/.config/hypr/scripts/keyboard.sh" + } + }, + "custom/menu": { + "icon": "\udb83\ude6f", + "tooltip": "Menu główne.", + "actions": { + "onLeftClick": "$HOME/.config/hypr/scripts/toggle_hyprshell.sh -k" + } + }, + "custom/rotate": { + "icon": "\udb82\udc86", + "tooltip": "Obróć ekran.", + "actions": { + "onLeftClick": "$HOME/.config/hypr/scripts/rotate.sh" + } + }, + "custom/clipboard": { + "icon": "\ued7b", + "tooltip": "Schowek", + "actions": { + "onLeftClick": "vicinae vicinae://extensions/vicinae/clipboard/history" + } + }, + "custom/screenshot": { + "icon": "\uf030", + "tooltip": "Screenshot", + "actions": { + "onLeftClick": "$HOME/.config/hypr/scripts/screenshot.sh --button", + "onRightClick": "$HOME/.config/hypr/scripts/screenshot.sh --button --full" + } + }, + "custom/desktop": { + "icon": "\uebf6", + "tooltip": "Pokaż pulpit", + "actions": { + "onLeftClick": "$HOME/.config/hypr/scripts/hide.sh" + } + } +} \ No newline at end of file diff --git a/hyprpanel/modules.scss b/hyprpanel/modules.scss new file mode 100644 index 0000000..c116511 --- /dev/null +++ b/hyprpanel/modules.scss @@ -0,0 +1,98 @@ +/* ################################## + * # Custom Volume Module Styling # + * ################################## */ +@include styleModule( + // class name + 'cmodule-keyboard', + // styling properties + ( + 'text-color': #E6FF10, + 'icon-color': #E6FF10, + 'icon-background': #000000, + 'label-background': #000000, + 'inner-spacing': 0em, + 'border-enabled': true, + 'border-color': #E6FF10, + 'icon-size': 1.2em + ) +); + +@include styleModule( + // class name + 'cmodule-menu', + // styling properties + ( + 'text-color': #E6FF10, + 'icon-color': #E6FF10, + 'icon-background': #000000, + 'label-background': #000000, + 'inner-spacing': 0em, + 'border-enabled': true, + 'border-color': #E6FF10, + 'icon-size': 1.2em + ) +); + +@include styleModule( + // class name + 'cmodule-rotate', + // styling properties + ( + 'text-color': #E6FF10, + 'icon-color': #E6FF10, + 'icon-background': #000000, + 'label-background': #000000, + 'inner-spacing': 0em, + 'border-enabled': true, + 'border-color': #E6FF10, + 'icon-size': 1.2em + ) +); + +@include styleModule( + // class name + 'cmodule-clipboard', + // styling properties + ( + 'text-color': #E6FF10, + 'icon-color': #E6FF10, + 'icon-background': #000000, + 'label-background': #000000, + 'inner-spacing': 0em, + 'border-enabled': true, + 'border-color': #E6FF10, + 'icon-size': 1.2em + ) +); + +@include styleModule( + // class name + 'cmodule-screenshot', + // styling properties + ( + 'text-color': #E6FF10, + 'icon-color': #E6FF10, + 'icon-background': #000000, + 'label-background': #000000, + 'inner-spacing': 0em, + 'border-enabled': true, + 'border-color': #E6FF10, + 'icon-size': 1.2em + ) +); + +@include styleModule( + // class name + 'cmodule-desktop', + // styling properties + ( + 'text-color': #E6FF10, + 'icon-color': #E6FF10, + 'icon-background': #000000, + 'label-background': #000000, + 'inner-spacing': 0em, + 'border-enabled': true, + 'border-color': #E6FF10, + 'icon-size': 1.2em + ) +); \ No newline at end of file diff --git a/hyprshell.css b/hyprshell.css new file mode 100644 index 0000000..a9b2c0f --- /dev/null +++ b/hyprshell.css @@ -0,0 +1,57 @@ +:root { + --border-color: #E6FF1030; + --border-color-active: #E6FF10; + + --bg-color: rgba(20, 20, 20, 0.7); + --bg-color-hover: rgba(40, 40, 50, 1); + + --border-radius: 12px; + --border-size: 3px; + --border-style: solid; + + --text-color: rgba(245, 245, 245, 1); + + --window-padding: 2px; +} + +.window { +} + + +.monitor { +} + +.workspace { + font-size: x-small; +} + +.client { +} + +.client-image { +} + + +.launcher { +} + +.launcher-input { +} + +.launcher-results { +} + +.launcher-item { +} + +.launcher-exec { +} + +.launcher-key { +} + +.launcher-plugins { +} + +.launcher-plugin { +} \ No newline at end of file diff --git a/hyprshell.ron b/hyprshell.ron new file mode 100644 index 0000000..de55422 --- /dev/null +++ b/hyprshell.ron @@ -0,0 +1,79 @@ +// Edit with `hyprshell config edit` +( + version: 4, + windows: ( + scale: 5.0, + items_per_row: 6, + overview: ( + launcher: ( + default_terminal: "konsole", + launch_modifier: "ctrl", + width: 650, + max_items: 5, + show_when_empty: true, + plugins: ( + applications: ( + run_cache_weeks: 8, + show_execs: true, + show_actions_submenu: true, + ), + terminal: (), + shell: (), + websearch: ( + engines: [ + ( + url: "https://www.startpage.com/sp/search?query={}", + name: "Startpage", + key: 's', + ), + ( + url: "https://www.youtube.com/results?search_query={}", + name: "YouTube", + key: 'y', + ), + ], + ), + calc: (), + path: (), + actions: ( + actions: [ + logout, + reboot, + shutdown, + custom( + names: [ + "Reload", + ], + details: "Reloads Hyprshell", + command: "sleep 1; hyprshell socat \'\"Restart\"\'", + icon: "system-restart", + ), + custom( + names: [ + "Clipboard", + ], + details: "Shows clipboard history", + command: "`", + icon: "system-clipboard", + ), + ], + ), + ), + ), + key: "insert", + top_offset: 430, + modifier: "super", + filter_by: [], + exclude_workspaces: "", + ), + switch: ( + modifier: "super", + key: "Tab", + filter_by: [], + switch_workspaces: false, + exclude_workspaces: "special:*", + kill_key: 'q', + ), + switch_2: None, + ), +) \ No newline at end of file diff --git a/mhyprland.conf b/mhyprland.conf new file mode 100644 index 0000000..fe19be8 --- /dev/null +++ b/mhyprland.conf @@ -0,0 +1,427 @@ +# NOTE: Observation - all EXECs are relative to $HOME - do $scriptsdir/.sh to EXEC scripts + +# ####################################################################################### +# AUTOGENERATED HYPRLAND CONFIG. +# EDIT THIS CONFIG ACCORDING TO THE WIKI INSTRUCTIONS. +# ####################################################################################### + +#autogenerated = 1 # remove this line to remove the warning + +# This is an example Hyprland config file. +# Refer to the wiki for more information. +# https://wiki.hypr.land/Configuring/ + +# Please note not all available settings / options are set here. +# For a full list, see the wiki + +# You can split this configuration into multiple files +# Create your files separately and then link them to this file like this: +# source = ~/$hyprdir/myColors.conf + +# ADDED: convenience variables +$hyprdir = .config/hypr +$scriptsdir = $hyprdir/scripts + + +################ +### MONITORS ### +################ + +# See https://wiki.hypr.land/Configuring/Monitors/ +monitor=,preferred,auto,auto +# ADDED: upped my 2nd monitor by 700 pixels to align with main; fixed main's position (it somehow becomes 3200x0 after changing 2nd monitor's position - I reset it back to 0x0) +monitor = eDP-1,preferred,0x0,1,transform,0 +monitor = desc:Acer Technologies Acer XF240H 0x0160F332,preferred,1925x-900,1 + + +################### +### MY PROGRAMS ### +################### + +# See https://wiki.hypr.land/Configuring/Keywords/ + +# Set programs that you use +# CHANGED: From kitty to konsole; from Rofi to Hyprshell +$terminal = $scriptsdir/terminal.sh +#$fileManager = dolphin +$menu = $scriptsdir/toggle_hyprshell.sh + + +################# +### AUTOSTART ### +################# + +# Autostart necessary processes (like notifications daemons, status bars, etc.) +# Or execute your favorite apps at launch like this: + +# CHANGED: Enabled +exec-once = $terminal +# exec-once = nm-applet &flatpak run app.zen_browser.zen +# exec-once = waybar & hyprpaper & firefox +# ADDED: Hyprshell, Vicinae; virtual keyboard, Hyprpanel; browser, Discord, Element, Obsidian; virtual keyboard state reset; volumekey daemon; Waydroid +exec-once = hyprshell -c $hyprdir/hyprshell.ron -s $hyprdir/hyprshell.css run +exec-once = vicinae server +exec-once = wvkbd-deskintl --hidden -o +exec-once = hyprpanel +exec-once = flatpak run app.zen_browser.zen +exec-once = flatpak run com.discordapp.Discord +exec-once = flatpak run im.riot.Riot +exec-once = flatpak run md.obsidian.Obsidian +exec-once = $scriptsdir/keyboard.sh reset +exec-once = $scriptsdir/volume-core.sh --start-daemon +exec-once = $scriptsdir/waydroid.sh + +############################# +### ENVIRONMENT VARIABLES ### +############################# + +# See https://wiki.hypr.land/Configuring/Environment-variables/ + +env = XCURSOR_SIZE,24 +env = HYPRCURSOR_SIZE,24 + + +################### +### PERMISSIONS ### +################### + +# See https://wiki.hypr.land/Configuring/Permissions/ +# Please note permission changes here require a Hyprland restart and are not applied on-the-fly +# for security reasons + +# CHANGED: enabled defaults (grim, xdg-desktop-portal-hyprland, plugins and enforce_permissions) + +ecosystem { + enforce_permissions = 1 +} + +permission = /usr/(bin|local/bin)/grim, screencopy, allow +permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow +permission = /usr/(bin|local/bin)/hyprpm, plugin, allow +# ADDED: Hyprshell's plugin +permission = /usr/bin/hyprshell, plugin, allow + +##################### +### LOOK AND FEEL ### +##################### + +# Refer to https://wiki.hypr.land/Configuring/Variables/ + +# ADDED: dark mode +exec-once = gsettings set org.gnome.desktop.interface gtk-theme "Breeze-Dark" # for GTK3 apps +exec-once = gsettings set org.gnome.desktop.interface color-scheme "prefer-dark" # for GTK4 apps +# NOTE: a dark theme must be set in qt6ct +env = QT_QPA_PLATFORMTHEME,qt6ct # for Qt apps + +# https://wiki.hypr.land/Configuring/Variables/#general +general { + gaps_in = 4 + gaps_out = 0, 8, 8, 8 + + border_size = 2 + + # https://wiki.hypr.land/Configuring/Variables/#variable-types for info about colors + # CHANGED: My colors :) + col.active_border = rgb(FFE610) rgb(E6FF10) 240deg + col.inactive_border = rgba(FFE61020) rgba(E6FF10E0) 240deg + + # Set to true enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = true + + # Please see https://wiki.hypr.land/Configuring/Tearing/ before you turn this on + allow_tearing = false + + layout = dwindle +} + +# https://wiki.hypr.land/Configuring/Variables/#decoration +decoration { + rounding = 15 + rounding_power = 3 + + # Change transparency of focused and unfocused windows + active_opacity = 1.0 + inactive_opacity = 1.0 + + shadow { + enabled = true + range = 4 + render_power = 3 + color = rgba(1a1a1aee) + } + + # https://wiki.hypr.land/Configuring/Variables/#blur + blur { + # NOTE: Occasionally (when terminal breaks), this needs to be disabled (until I figure out how to get blur only on the background ALWAYS, without making all terminal text glow SOMETIMES) + enabled = true + size = 3 + passes = 1 + + vibrancy = 0.1696 + } +} + +# https://wiki.hypr.land/Configuring/Variables/#animations +animations { + enabled = yes#, please :) + + # Default curves, see https://wiki.hypr.land/Configuring/Animations/#curves + # NAME, X0, Y0, X1, Y1 + bezier = easeOutQuint, 0.23, 1, 0.32, 1 + bezier = easeInOutCubic, 0.65, 0.05, 0.36, 1 + bezier = linear, 0, 0, 1, 1 + bezier = almostLinear, 0.5, 0.5, 0.75, 1 + bezier = quick, 0.15, 0, 0.1, 1 + + # Default animations, see https://wiki.hypr.land/Configuring/Animations/ + # NAME, ONOFF, SPEED, CURVE, [STYLE] + animation = global, 1, 10, default + animation = border, 1, 5.39, easeOutQuint + animation = windows, 1, 4.79, easeOutQuint + animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% + animation = windowsOut, 1, 1.49, linear, popin 87% + animation = fadeIn, 1, 1.73, almostLinear + animation = fadeOut, 1, 1.46, almostLinear + animation = fade, 1, 3.03, quick + animation = layers, 1, 3.81, easeOutQuint + animation = layersIn, 1, 4, easeOutQuint, fade + animation = layersOut, 1, 1.5, linear, fade + animation = fadeLayersIn, 1, 1.79, almostLinear + animation = fadeLayersOut, 1, 1.39, almostLinear + animation = workspaces, 1, 1.94, almostLinear, fade + animation = workspacesIn, 1, 1.21, almostLinear, fade + animation = workspacesOut, 1, 1.94, almostLinear, fade + animation = zoomFactor, 1, 7, quick + # ADDED: make special workspaces slide in from the top (thx, https://github.com/hyprwm/Hyprland/discussions/1757#discussioncomment-8921961) + animation = specialWorkspaceIn, 1, 2, easeInOutCubic, slidefadevert -50% + animation = specialWorkspaceOut, 1, 2, easeInOutCubic, slidefadevert -50% +} + +# ADDED: My color palette for GTK apps +exec-once = gsettings set org.gnome.desktop.interface gtk-color-palette "'black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90'" + +# Ref https://wiki.hypr.land/Configuring/Workspace-Rules/ +# "Smart gaps" / "No gaps when only" +# uncomment all if you wish to use that. +# workspace = w[tv1], gapsout:0, gapsin:0 +# workspace = f[1], gapsout:0, gapsin:0 +# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] +# windowrule = rounding 0, floating:0, onworkspace:w[tv1] +# windowrule = bordersize 0, floating:0, onworkspace:f[1] +# windowrule = rounding 0, floating:0, onworkspace:f[1] + +# See https://wiki.hypr.land/Configuring/Dwindle-Layout/ for more +#dwindle { +# pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below +# preserve_split = true # You probably want this +#} + +# See https://wiki.hypr.land/Configuring/Master-Layout/ for more +master { + new_status = master +} + +# https://wiki.hypr.land/Configuring/Variables/#misc +misc { + #CHANGED: preferred wallpaper; Waydroid fix + force_default_wallpaper = 2 # 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. :( + size_limits_tiled = true #Waydroid needs this +} + + +############# +### INPUT ### +############# + +# https://wiki.hypr.land/Configuring/Variables/#input +input { + kb_layout = pl + kb_variant = + kb_model = + kb_options = fkeys:basic_13-24 + kb_rules = + + follow_mouse = 1 + + sensitivity = 0 # -1.0 - 1.0, 0 means no modification. + + touchpad { + natural_scroll = true + } + + # ADDED: Fix touch&pen mapping + tablet { + output = eDP-1 + transform = 0 + } + touchdevice { + output = eDP-1 + transform = 0 + } +} + +# See https://wiki.hypr.land/Configuring/Gestures +#gesture = 3, horizontal, workspace + +# Example per-device config +# See https://wiki.hypr.land/Configuring/Keywords/#per-device-input-configs for more +#device { +# name = epic-mouse-v1 +# sensitivity = -0.5 +#} + + +################### +### KEYBINDINGS ### +################### + +# See https://wiki.hypr.land/Configuring/Keywords/ +$mainMod = SUPER # Sets "Windows" key as main modifier + +# Example binds, see https://wiki.hypr.land/Configuring/Binds/ for more +bind = $mainMod, T, exec, $terminal # CHANGED: From Q to T +# NOTE: This just means "close window"; no actual pkill involved +bind = $mainMod, Q, killactive, # CHANGED: From C to Q +bind = $mainMod, M, exit, +#bind = $mainMod, E, exec, $fileManager +#bind = $mainMod, V, togglefloating, +# CHANGED: From R to SUPER_L +bind = $mainMod, SUPER_L, exec, $menu +#bind = $mainMod, P, pseudo, # dwindle +#bind = $mainMod, J, togglesplit, # dwindle + +# Move focus with mainMod + arrow keys +#bind = $mainMod, left, movefocus, l +#bind = $mainMod, right, movefocus, r +#bind = $mainMod, up, movefocus, u +#bind = $mainMod, down, movefocus, d + +# Switch workspaces with mainMod + [0-9] +#bind = $mainMod, 1, workspace, 1 +#bind = $mainMod, 2, workspace, 2 +#bind = $mainMod, 3, workspace, 3 +#bind = $mainMod, 4, workspace, 4 +#bind = $mainMod, 5, workspace, 5 +#bind = $mainMod, 6, workspace, 6 +#bind = $mainMod, 7, workspace, 7 +#bind = $mainMod, 8, workspace, 8 +#bind = $mainMod, 9, workspace, 9 +#bind = $mainMod, 0, workspace, 10 +# ADDED: blank-screen workspace; +bind = $mainMod, Z, exec, "$scriptsdir/hide.sh" + +# Move active window to a workspace with mainMod + SHIFT + [0-9] +#bind = $mainMod SHIFT, 1, movetoworkspace, 1 +#bind = $mainMod SHIFT, 2, movetoworkspace, 2 +#bind = $mainMod SHIFT, 3, movetoworkspace, 3 +#bind = $mainMod SHIFT, 4, movetoworkspace, 4 +#bind = $mainMod SHIFT, 5, movetoworkspace, 5 +#bind = $mainMod SHIFT, 6, movetoworkspace, 6 +#bind = $mainMod SHIFT, 7, movetoworkspace, 7 +#bind = $mainMod SHIFT, 8, movetoworkspace, 8 +#bind = $mainMod SHIFT, 9, movetoworkspace, 9 +#bind = $mainMod SHIFT, 0, movetoworkspace, 10 + +# CHANGED: Made my own special workspaces +bind = $mainMod, X, togglespecialworkspace, terminal +bind = $mainMod, A, togglespecialworkspace, browser +bind = $mainMod, D, togglespecialworkspace, discord +bind = $mainMod, C, togglespecialworkspace, element +bind = $mainMod, S, togglespecialworkspace, obsidian +#bind = $mainMod SHIFT, S, movetoworkspace, special:magic + +# Scroll through existing workspaces with mainMod + scroll +bind = $mainMod, mouse_down, workspace, e+1 +bind = $mainMod, mouse_up, workspace, e-1 + +# Move/resize windows with mainMod + LMB/RMB and dragging +bindm = $mainMod, mouse:272, movewindow +bindm = $mainMod, mouse:273, resizewindow + +# Laptop multimedia keys for volume and LCD brightness +# NOTE: This - for whatever reason - didn't work when the keyboard was detached. Also, it would suddenly jump by like... 50 presses if I presses the volume key in quick succession. So instead, I have a custom script for this now. +#bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 1%+ +#bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%- +bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+ +bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%- + +# Requires playerctl +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPause, exec, playerctl play-pause +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioPrev, exec, playerctl previous + +# ADDED: screenshots +bind = , PRINT, exec, $scriptsdir/screenshot.sh --full +bind = $mainMod, PRINT, exec, $scriptsdir/screenshot.sh +bind = , F10, exec, $scriptsdir/screenshot.sh --full +bind = $mainMod, F10, exec, $scriptsdir/screenshot.sh + +############################## +### WINDOWS AND WORKSPACES ### +############################## + +# See https://wiki.hypr.land/Configuring/Window-Rules/ for more +# See https://wiki.hypr.land/Configuring/Workspace-Rules/ for workspace rules + +# Example windowrule +# windowrule = float,class:^(kitty)$,title:^(kitty)$ + +# Ignore maximize requests from apps. You'll probably like this. +#windowrule = suppressevent maximize, class:.* + +# Fix some dragging issues with XWayland +#windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 + +# ADDED: Every new window (*also requires special treatment for MC windows) is a workspace of its own, except for special workspaces +windowrule = match:class .*, match:float false, workspace emptym +windowrule = match:class org.kde.konsole, workspace special:terminal silent +windowrule = match:class app.zen_browser.zen, workspace special:browser silent +windowrule = match:class discord, workspace special:discord silent +windowrule = match:class im.riot.Riot, workspace special:element silent +windowrule = match:class obsidian, workspace special:obsidian silent +# ADDED: Minecraft (incl. modpacks having custom names - only Melatonin discovered so far) windows require special treatment to avoid being treated as floating +windowrule = match:class Melatonin, workspace emptym, maximize on +windowrule = match:class Minecraft.*, workspace emptym, maximize on + +# ADDED: Lock Waydroid size (Android throws a hissy fit and explodes if you try to resize its „monitor” at runtime) - DISABLED, instead I just decided to make it fullscreen +#windowrule = match:class Waydroid, max_size 1900 1221, min_size 1900 1221, tile on +windowrule = match:class Waydroid, fullscreen on + +# ADDED: window rules recommended by Vicinae +#layerrule = blur,vicinae +#layerrule = ignorealpha 0, vicinae +#layerrule = noanim, vicinae + + +####################### +### ADDED: XWAYLAND ### +####################### + +xwayland { + force_zero_scaling = true +} + + +#################### +### ADDED: TOUCH ### +#################### + +exec = hyprpm reload + +plugin { + touch_gestures { + sensitivity = 4.0 + edge_margin = 50 + + hyprgrass-bind = , edge:d:u, exec, $scriptsdir/keyboard.sh --no-rotate + hyprgrass-bind = , tap:3, exec, $menu -k + } +} + +debug { + #disable_logs = false +} diff --git a/myhyprland.lua b/myhyprland.lua new file mode 100644 index 0000000..7399801 --- /dev/null +++ b/myhyprland.lua @@ -0,0 +1,412 @@ +------------------- +---- VARIABLES ---- +------------------- +local hyprdir = ".config/hypr" +local scripts = hyprdir.."/scripts" + +-- Set programs that I use +local terminal = scripts.."terminal.sh" +local fileManager = "dolphin" +local menu = scripts.."toggle-hyprshell.sh" + + +------------------ +---- MONITORS ---- +------------------ + +-- See https://wiki.hypr.land/Configuring/Basics/Monitors/ + +-- defaults +hl.monitor({ + output = "", + mode = "preferred", + position = "auto", + scale = 1, + mirror = "eDP-1", +}) + +-- Main tablet screen +hl.monitor({ + output = "eDP-1", + mode = "preferred", + position = "0x0", + scale = 1, +}) + +-- My monitor at home +hl.monitor({ + output = "desc:Acer Technologies Acer XF240H 0x0160F332", + mode = "preferred", + position = "1925x-900", + scale = 1, +}) + + +------------------- +---- AUTOSTART ---- +------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Autostart/ + +hl.on("hyprland.start", function () + -- Load plugins + --hl.exec_cmd("hyprpm reload") + + -- Special workspaces + hl.exec_cmd(terminal) + hl.exec_cmd("flatpak run app.zen_browser.zen") + hl.exec_cmd("flatpak run com.discordapp.Discord") + hl.exec_cmd("flatpak run im.riot.Riot") + hl.exec_cmd("flatpak run md.obsidian.Obsidian") + + -- Core daemons + hl.exec_cmd("hyprshell -c "..hyprdir.."/hyprshell.ron -s "..hyprdir.."/hyprshell.css run") + hl.exec_cmd("vicinae server") + hl.exec_cmd("wvkbd-deskintl --hidden -o") + hl.exec_cmd("hyprpanel") + hl.exec_cmd(scripts.."keyboard.sh reset") + hl.exec_cmd(scripts.."volume-core.sh --start-daemon") + + -- Waydroid (note: this also launches rootedinit.sh under-the-hood) + hl.exec_cmd(scripts.."waydroid.sh") + + -- Dark theme + hl.exec_cmd("gsettings set org.gnome.desktop.interface gtk-theme Breeze-Dark"); -- for GTK3 apps + hl.exec_cmd("gsettings set org.gnome.desktop.interface color-scheme prefer-dark"); -- for GTK4 apps + hl.exec_cmd("gsettings set org.gnome.desktop.interface gtk-color-palette \"'black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90'\""); --Unrelated to Dark Theme (just my color palette), but there was no better place for it. +end) + + +------------------------------- +---- ENVIRONMENT VARIABLES ---- +------------------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Environment-variables/ + +-- Were the defaults; no reason to fuck around +hl.env("XCURSOR_SIZE", "24") +hl.env("HYPRCURSOR_SIZE", "24") + +-- Dark theme, again (*must set manually) +hl.env("QT_QPA_PLATFORMTHEME", "qt6ct") + + +----------------------- +----- PERMISSIONS ----- +----------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Permissions/ + +hl.config({ + ecosystem = { + enforce_permissions = true, + }, +}) + +hl.permission({binary="/usr/(bin|local/bin)/grim", type="screencopy", mode="allow"}) +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"}) +hl.permission({binary="/usr/(bin|local/bin)/hyprshell", type="plugin", mode="allow"}) + + +----------------------- +---- LOOK AND FEEL ---- +----------------------- + +-- Refer to https://wiki.hypr.land/Configuring/Basics/Variables/ +hl.config({ + general = { + gaps_in = 4, + gaps_out = {top=0, right=8, bottom=8, left=8}, + + border_size = 2, + + col = { + active_border = { colors = {"rgb(FFE610)", "rgb(E6FF10)"}, angle = 240 }, + inactive_border = { colors = {"rgba(FFE61020)", "rgba(E6FF10E0)"}, angle = 240 }, + }, + + -- Set to true to enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = true, + + -- Please see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Tearing/ before you turn this on + allow_tearing = false, + + layout = "dwindle", + }, + + decoration = { + rounding = 15, + rounding_power = 3, + + -- 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, --During the Lua migration, I noticed the following note attached in the previous config: „NOTE: Occasionally (when terminal breaks), this needs to be disabled (until I figure out how to get blur only on the background ALWAYS, without making all terminal text glow SOMETIMES)”. However, I don't think I experienced any „terminal glowing” problems in a long time (tho transparency still breaks on it from time to time), so ig this is no longer needed? Leaving the note in, just in case it does end up happening again. + 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 = 71.2633, dampening = 15.8273644 }) + +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" }) + +-- Special workspaces slide-in from the top (thx, https://github.com/hyprwm/Hyprland/discussions/1757#discussioncomment-8921961) +hl.animation({ leaf = "specialWorkspaceIn", enabled=true, speed=2, bezier="easeInOutCubic", style="slidefadevert -50%" }) +hl.animation({ leaf = "specialWorkspaceOut", enabled=true, speed=2, bezier="easeInOutCubic", style="slidefadevert -50%" }) + +-- 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 = 2, -- 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 = "pl", + kb_variant = "", + kb_model = "", + kb_options = "fkeys:basic_13-24", + kb_rules = "", + + follow_mouse = 1, + + sensitivity = 0, -- -1.0 - 1.0, 0 means no modification. + + touchpad = { + natural_scroll = true, + }, + }, +}) + + +--------------------- +---- 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 .. " + T", hl.dsp.exec_cmd(terminal)) +local closeWindowBind = hl.bind(mainMod .. " + Q", hl.dsp.window.close()) +-- closeWindowBind:set_enabled(false) +hl.bind(mainMod .. " + M", hl.dsp.exit()) +hl.bind(mainMod, hl.dsp.exec_cmd(menu)) + +-- Quick-pad: Special workspaces + boss-key +hl.bind(mainMod .. " + X", hl.dsp.workspace.toggle_special("terminal")) +hl.bind(mainMod .. " + A", hl.dsp.workspace.toggle_special("browser")) +hl.bind(mainMod .. " + D", hl.dsp.workspace.toggle_special("discord")) +hl.bind(mainMod .. " + C", hl.dsp.workspace.toggle_special("element")) +hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("obsidian")) +hl.bind(mainMod .. " + Z", hl.dsp.exec_cmd(scripts.."hide.sh")) + +-- 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("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 }) + +-- Screenshots +hl.bind("PRINT", hl.dsp.exec_cmd(scripts.."screenshot.sh")) +hl.bind(mainMod.." + PRINT", hl.dsp.exec_cmd(scripts.."screenshot.sh --full")) + + +-------------------------------- +---- 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) -- ...No, I won't. I run everything as exclusive-window-per-workspace anyway, so I'm not worried about „Windows deciding to take up all my space” (I literally do that). All this will do is cause de-syncs (especially in client-side decorated apps, like all the crapware made in GTK) for exactly 0 benefit. + +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, +}) + +-- Hyprland-run windowrule +hl.window_rule({ + name = "move-hyprland-run", + match = { class = "hyprland-run" }, + move = "20 monitor_h-120", + float = true, +}) + +-- My rules + +hl.window_rule({ + name = "onwinopen-default", + match = { + class = ".*", + float = false + }, + workspace = "emptym" +}) + +hl.window_rule({ + name = "onwinopen-override-special-terminal", + match = { class = "org.kde.konsole" }, + workspace = "special:terminal" +}) + +hl.window_rule({ + name = "onwinopen-override-special-browser", + match = { class = "app.zen_browser.zen" }, + workspace = "special:browser silent" +}) + +hl.window_rule({ + name = "onwinopen-override-special-discord", + match = { class = "discord" }, + workspace = "special:discord silent" +}) + +hl.window_rule({ + name = "onwinopen-override-special-element", + match = { class = "im.riot.Riot" }, + workspace = "special:element silent" +}) + +hl.window_rule({ + name = "onwinopen-override-special-obsidian", + match = { class = "obsidian" }, + workspace = "special:obsidian silent" +}) + +hl.window_rule({ + name = "onwinopen-override-minecraft-default", + match = { class = "Minecraft.*" }, + workspace = "emptym", + maximize = true +}) + +hl.window_rule({ + name = "onwinopen-override-minecraft-modpack-melatonin", + match = { class = "Melatonin" }, + workspace = "emptym", + maximize = true +}) + +hl.window_rule({ + name = "onwinopen-override-waydroid", + match = { class = "Waydroid" }, + fullscreen = true +}) + + +------------------- +---- HYPRGRASS ---- +------------------- + +--hl.plugin.touch_gestures = { +-- sensitivity = 4.0, +-- edge_margin = 50, +-- ["hyprgrass-bind"] = ", edge:d:u, exec, $scriptsdir/keyboard.sh --no-rotate", +-- ["hyprgrass-bind"] = ", tap:3, exec, $menu -k" +--} diff --git a/ohyprland.conf b/ohyprland.conf new file mode 100644 index 0000000..c04563d --- /dev/null +++ b/ohyprland.conf @@ -0,0 +1,340 @@ +# This is an example Hyprland config file. +# Refer to the wiki for more information. +# https://wiki.hypr.land/Configuring/ + +# Please note not all available settings / options are set here. +# For a full list, see the wiki + +# You can split this configuration into multiple files +# Create your files separately and then link them to this file like this: +# source = ~/.config/hypr/myColors.conf + + +################ +### MONITORS ### +################ + +# See https://wiki.hypr.land/Configuring/Monitors/ +monitor=,preferred,auto,auto + + +################### +### MY PROGRAMS ### +################### + +# See https://wiki.hypr.land/Configuring/Keywords/ + +# Set programs that you use +$terminal = kitty +$fileManager = dolphin +$menu = hyprlauncher + + +################# +### AUTOSTART ### +################# + +# Autostart necessary processes (like notifications daemons, status bars, etc.) +# Or execute your favorite apps at launch like this: + +# exec-once = $terminal +# exec-once = nm-applet & +# exec-once = waybar & hyprpaper & firefox + + +############################# +### ENVIRONMENT VARIABLES ### +############################# + +# See https://wiki.hypr.land/Configuring/Environment-variables/ + +env = XCURSOR_SIZE,24 +env = HYPRCURSOR_SIZE,24 + + +################### +### PERMISSIONS ### +################### + +# See https://wiki.hypr.land/Configuring/Permissions/ +# Please note permission changes here require a Hyprland restart and are not applied on-the-fly +# for security reasons + +# ecosystem { +# enforce_permissions = 1 +# } + +# permission = /usr/(bin|local/bin)/grim, screencopy, allow +# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow +# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow + + +##################### +### LOOK AND FEEL ### +##################### + +# Refer to https://wiki.hypr.land/Configuring/Variables/ + +# https://wiki.hypr.land/Configuring/Variables/#general +general { + gaps_in = 5 + gaps_out = 20 + + border_size = 2 + + # https://wiki.hypr.land/Configuring/Variables/#variable-types for info about colors + col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg + col.inactive_border = rgba(595959aa) + + # Set to true enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = false + + # Please see https://wiki.hypr.land/Configuring/Tearing/ before you turn this on + allow_tearing = false + + layout = dwindle +} + +# https://wiki.hypr.land/Configuring/Variables/#decoration +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 = rgba(1a1a1aee) + } + + # https://wiki.hypr.land/Configuring/Variables/#blur + blur { + enabled = true + size = 3 + passes = 1 + + vibrancy = 0.1696 + } +} + +# https://wiki.hypr.land/Configuring/Variables/#animations +animations { + enabled = yes, please :) + + # Default curves, see https://wiki.hypr.land/Configuring/Animations/#curves + # NAME, X0, Y0, X1, Y1 + bezier = easeOutQuint, 0.23, 1, 0.32, 1 + bezier = easeInOutCubic, 0.65, 0.05, 0.36, 1 + bezier = linear, 0, 0, 1, 1 + bezier = almostLinear, 0.5, 0.5, 0.75, 1 + bezier = quick, 0.15, 0, 0.1, 1 + + # Default animations, see https://wiki.hypr.land/Configuring/Animations/ + # NAME, ONOFF, SPEED, CURVE, [STYLE] + animation = global, 1, 10, default + animation = border, 1, 5.39, easeOutQuint + animation = windows, 1, 4.79, easeOutQuint + animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% + animation = windowsOut, 1, 1.49, linear, popin 87% + animation = fadeIn, 1, 1.73, almostLinear + animation = fadeOut, 1, 1.46, almostLinear + animation = fade, 1, 3.03, quick + animation = layers, 1, 3.81, easeOutQuint + animation = layersIn, 1, 4, easeOutQuint, fade + animation = layersOut, 1, 1.5, linear, fade + animation = fadeLayersIn, 1, 1.79, almostLinear + animation = fadeLayersOut, 1, 1.39, almostLinear + animation = workspaces, 1, 1.94, almostLinear, fade + animation = workspacesIn, 1, 1.21, almostLinear, fade + animation = workspacesOut, 1, 1.94, almostLinear, fade + animation = zoomFactor, 1, 7, quick +} + +# Ref https://wiki.hypr.land/Configuring/Workspace-Rules/ +# "Smart gaps" / "No gaps when only" +# uncomment all if you wish to use that. +# workspace = w[tv1], gapsout:0, gapsin:0 +# workspace = f[1], gapsout:0, gapsin:0 +# windowrule { +# name = no-gaps-wtv1 +# match:float = false +# match:workspace = w[tv1] +# +# border_size = 0 +# rounding = 0 +# } +# +# windowrule { +# name = no-gaps-f1 +# match:float = false +# match:workspace = f[1] +# +# border_size = 0 +# rounding = 0 +# } + +# See https://wiki.hypr.land/Configuring/Dwindle-Layout/ for more +dwindle { + preserve_split = true # You probably want this +} + +# See https://wiki.hypr.land/Configuring/Master-Layout/ for more +master { + new_status = master +} + +# https://wiki.hypr.land/Configuring/Variables/#misc +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 ### +############# + +# https://wiki.hypr.land/Configuring/Variables/#input +input { + kb_layout = us + kb_variant = + kb_model = + kb_options = + kb_rules = + + follow_mouse = 1 + + sensitivity = 0 # -1.0 - 1.0, 0 means no modification. + + touchpad { + natural_scroll = false + } +} + +# See https://wiki.hypr.land/Configuring/Gestures +gesture = 3, horizontal, workspace + +# Example per-device config +# See https://wiki.hypr.land/Configuring/Keywords/#per-device-input-configs for more +device { + name = epic-mouse-v1 + sensitivity = -0.5 +} + + +################### +### KEYBINDINGS ### +################### + +# See https://wiki.hypr.land/Configuring/Keywords/ +$mainMod = SUPER # Sets "Windows" key as main modifier + +# Example binds, see https://wiki.hypr.land/Configuring/Binds/ for more +bind = $mainMod, Q, exec, $terminal +bind = $mainMod, C, killactive, +bind = $mainMod, M, exec, command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch exit +bind = $mainMod, E, exec, $fileManager +bind = $mainMod, V, togglefloating, +bind = $mainMod, R, exec, $menu +bind = $mainMod, P, pseudo, # dwindle +bind = $mainMod, J, layoutmsg, togglesplit # dwindle + +# Move focus with mainMod + arrow keys +bind = $mainMod, left, movefocus, l +bind = $mainMod, right, movefocus, r +bind = $mainMod, up, movefocus, u +bind = $mainMod, down, movefocus, d + +# Switch workspaces with mainMod + [0-9] +bind = $mainMod, 1, workspace, 1 +bind = $mainMod, 2, workspace, 2 +bind = $mainMod, 3, workspace, 3 +bind = $mainMod, 4, workspace, 4 +bind = $mainMod, 5, workspace, 5 +bind = $mainMod, 6, workspace, 6 +bind = $mainMod, 7, workspace, 7 +bind = $mainMod, 8, workspace, 8 +bind = $mainMod, 9, workspace, 9 +bind = $mainMod, 0, workspace, 10 + +# Move active window to a workspace with mainMod + SHIFT + [0-9] +bind = $mainMod SHIFT, 1, movetoworkspace, 1 +bind = $mainMod SHIFT, 2, movetoworkspace, 2 +bind = $mainMod SHIFT, 3, movetoworkspace, 3 +bind = $mainMod SHIFT, 4, movetoworkspace, 4 +bind = $mainMod SHIFT, 5, movetoworkspace, 5 +bind = $mainMod SHIFT, 6, movetoworkspace, 6 +bind = $mainMod SHIFT, 7, movetoworkspace, 7 +bind = $mainMod SHIFT, 8, movetoworkspace, 8 +bind = $mainMod SHIFT, 9, movetoworkspace, 9 +bind = $mainMod SHIFT, 0, movetoworkspace, 10 + +# Example special workspace (scratchpad) +bind = $mainMod, S, togglespecialworkspace, magic +bind = $mainMod SHIFT, S, movetoworkspace, special:magic + +# Scroll through existing workspaces with mainMod + scroll +bind = $mainMod, mouse_down, workspace, e+1 +bind = $mainMod, mouse_up, workspace, e-1 + +# Move/resize windows with mainMod + LMB/RMB and dragging +bindm = $mainMod, mouse:272, movewindow +bindm = $mainMod, mouse:273, resizewindow + +# Laptop multimedia keys for volume and LCD brightness +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+ +bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%- + +# Requires playerctl +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPause, exec, playerctl play-pause +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioPrev, exec, playerctl previous + +############################## +### WINDOWS AND WORKSPACES ### +############################## + +# See https://wiki.hypr.land/Configuring/Window-Rules/ for more +# See https://wiki.hypr.land/Configuring/Workspace-Rules/ for workspace rules + +# Example windowrules that are useful + +windowrule { + # Ignore maximize requests from all apps. You'll probably like this. + name = suppress-maximize-events + match:class = .* + + suppress_event = maximize +} + +windowrule { + # Fix some dragging issues with XWayland + name = fix-xwayland-drags + match:class = ^$ + match:title = ^$ + match:xwayland = true + match:float = true + match:fullscreen = false + match:pin = false + + no_focus = true +} + +# Hyprland-run windowrule +windowrule { + name = move-hyprland-run + + match:class = hyprland-run + + move = 20 monitor_h-120 + float = yes +} \ No newline at end of file diff --git a/ohyprland.lua b/ohyprland.lua new file mode 100644 index 0000000..fd31568 --- /dev/null +++ b/ohyprland.lua @@ -0,0 +1,356 @@ +-- 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") + + +------------------ +---- MONITORS ---- +------------------ + +-- See https://wiki.hypr.land/Configuring/Basics/Monitors/ +hl.monitor({ + output = "", + mode = "preferred", + position = "auto", + scale = "auto", +}) + + +--------------------- +---- MY PROGRAMS ---- +--------------------- + +-- Set programs that you use +local terminal = "konsole" +local fileManager = "dolphin" +local menu = "hyprlauncher" + + +------------------- +---- 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: +-- +-- hl.on("hyprland.start", function () +-- hl.exec_cmd(terminal) +-- hl.exec_cmd("nm-applet") +-- hl.exec_cmd("waybar & hyprpaper & firefox") +-- end) + + +------------------------------- +---- 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 = 71.2633, dampening = 15.8273644 }) + +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 = "", + 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)) +local closeWindowBind = hl.bind(mainMod .. " + C", hl.dsp.window.close()) +-- closeWindowBind:set_enabled(false) +hl.bind(mainMod .. " + M", hl.dsp.exec_cmd("command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch 'hl.dsp.exit()'")) +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 + +-- Example special workspace (scratchpad) +hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("magic")) +hl.bind(mainMod .. " + SHIFT + S", hl.dsp.window.move({ workspace = "special:magic" })) + +-- 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 }) + + +-------------------------------- +---- 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, +}) diff --git a/scripts/get_active_workspace.sh b/scripts/get_active_workspace.sh new file mode 100755 index 0000000..9811e22 --- /dev/null +++ b/scripts/get_active_workspace.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ "$(hyprctl activewindow)" = "Invalid" ]; then + echo "empty"; +else + hyprctl activewindow -j | jq -r .workspace.name | grep special >> /dev/null + if [ $? -eq 0 ]; then + echo "special"; + else + echo "normal" + fi +fi + +exit 0; \ No newline at end of file diff --git a/scripts/hide.sh b/scripts/hide.sh new file mode 100755 index 0000000..3d5745c --- /dev/null +++ b/scripts/hide.sh @@ -0,0 +1,41 @@ +#!/bin/sh +SCRIPT_THIS="$(realpath "$0")" +SCRIPT_GETTER="$(dirname "$SCRIPT_THIS")/get_active_workspace.sh" + +RESTORE_TARGET="2" +RESTORE_TARGET_SPECIAL="DO_NOT_RESTORE_ANY_SPECIAL_WORKSPACES" + +ACTIVE_WORKSPACE="$("$SCRIPT_GETTER")" +if [ "$ACTIVE_WORKSPACE" = "empty" ]; then + hyprctl dispatch "hl.dsp.focus({workspace=\"$RESTORE_TARGET\"})" + #hyprctl notify 3 6000 000 "hl.dsp.focus({workspace=\"$RESTORE_TARGET\"})" + if [ "$RESTORE_TARGET_SPECIAL" != "DO_NOT_RESTORE_ANY_SPECIAL_WORKSPACES" ]; then + hyprctl dispatch "hl.dsp.workspace.toggle_special(\"$RESTORE_TARGET_SPECIAL\")" + #hyprctl notify 3 6000 000 "hl.dsp.workspace.toggle_special(\"$RESTORE_TARGET_SPECIAL\")" + fi + + +elif [ "$ACTIVE_WORKSPACE" = "special" ]; then + SPECIAL_WS_NAME="$(hyprctl activewindow -j | jq -r .workspace.name)" + SPECIAL_WS_NAME="${SPECIAL_WS_NAME#"special:"}" + UNDERLYING_WS_ID="$(hyprctl -j monitors | jq --argjson monitorid "$(hyprctl activewindow -j | jq -r .monitor)" ".[] | select(.id == \$monitorid) | .activeWorkspace.id")" + + sed -i "s/RESTORE_TARGET=\"$RESTORE_TARGET\"/RESTORE_TARGET=\"$UNDERLYING_WS_ID\"/" "$SCRIPT_THIS" + sed -i "s/RESTORE_TARGET_SPECIAL=\"$RESTORE_TARGET_SPECIAL\"/RESTORE_TARGET_SPECIAL=\"$SPECIAL_WS_NAME\"/" "$SCRIPT_THIS" + + hyprctl dispatch "hl.dsp.workspace.toggle_special(\"$SPECIAL_WS_NAME\")" + #hyprctl notify 3 6000 000 "hl.dsp.workspace.toggle_special(\"$SPECIAL_WS_NAME\")" + hyprctl dispatch "hl.dsp.focus({workspace=\"emptynm\"})" + #hyprctl notify 3 6000 000 "hl.dsp.focus({workspace=\"emptynm\"})" + + +elif [ "$ACTIVE_WORKSPACE" = "normal" ]; then + sed -i "s/RESTORE_TARGET=\"$RESTORE_TARGET\"/RESTORE_TARGET=\"$(hyprctl activewindow -j | jq -r .workspace.name)\"/" "$SCRIPT_THIS" + sed -i "s/RESTORE_TARGET_SPECIAL=\"$RESTORE_TARGET_SPECIAL\"/RESTORE_TARGET_SPECIAL=\"DO_NOT_RESTORE_ANY_SPECIAL_WORKSPACES\"/" "$SCRIPT_THIS" + hyprctl dispatch "hl.dsp.focus({workspace=\"emptynm\"})" + #hyprctl notify 3 6000 000 "hl.dsp.focus({workspace=\"emptynm\"})" + +else + hyprctl notify 3 1000 000 "Error: Unknown workspace state \"$ACTIVE_WORKSPACE\"."; + exit 1; +fi \ No newline at end of file diff --git a/scripts/hyprpanel_bluetooth.desktop b/scripts/hyprpanel_bluetooth.desktop new file mode 100755 index 0000000..a1ff41f --- /dev/null +++ b/scripts/hyprpanel_bluetooth.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Application +Name=Bluetooth Settings +Comment=Open Hyprpanel's Bluetooth menu +Exec=hyprpanel t bluetoothmenu +Terminal=false \ No newline at end of file diff --git a/scripts/hyprpanel_settings.desktop b/scripts/hyprpanel_settings.desktop new file mode 100755 index 0000000..b95bb98 --- /dev/null +++ b/scripts/hyprpanel_settings.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Application +Name=Hyprpanel Settings +Comment=Open Hyprpanel's Settings menu +Exec=hyprpanel t settings-dialog +Terminal=false \ No newline at end of file diff --git a/scripts/hyprpanel_wifi.desktop b/scripts/hyprpanel_wifi.desktop new file mode 100755 index 0000000..00c3b63 --- /dev/null +++ b/scripts/hyprpanel_wifi.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Application +Name=WiFi Settings +Comment=Open Hyprpanel's WiFi menu +Exec=hyprpanel t networkmenu +Terminal=false \ No newline at end of file diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..68df8fe --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +if [ -z "$1" ]; then + PERMS="555" +elif [ "$1" = "--editable" ] || [ "$1" = "-e" ]; then + PERMS="777" +else + echo "Usage: $0 [--editable|-e]"; + exit 1; +fi + +if [ -z "$HOME" ]; then + echo "Script unusable by homeless users. ;-P"; + echo "Set your \$HOME envar (or have your shell do it for you, like on every normal distro) and try again."; + exit 1; +fi + +DIR="$HOME/.config/hypr/scripts" + +if [ "$(realpath "$DIR/$(basename "$0")")" != "$(realpath "$0")" ]; then + echo "This script must exist inside of $DIR"; + exit 1; +fi + +echo "Installing..."; +ln -vrs "$DIR"/*.desktop "$HOME/.local/share/applications/" +ln -vrs "$HOME/.config/hypr/hyprpanel" "$HOME/.config/" +chmod --verbose $PERMS "$DIR"/*.sh +xdg-mime default open_folder.desktop inode/directory +echo "Done!"; +exit 0; \ No newline at end of file diff --git a/scripts/keyboard.sh b/scripts/keyboard.sh new file mode 100755 index 0000000..7bdd146 --- /dev/null +++ b/scripts/keyboard.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +IS_ACTIVE="false" +SCRIPT_LOCATION="$(realpath "$0")" + + +if [ -z "$1" ]; then + if [ $IS_ACTIVE = "true" ]; then + "$SCRIPT_LOCATION" hide; + else + "$SCRIPT_LOCATION" show; + fi + exit 0; +fi + + +if [ "$1" == "--no-rotate" ]; then + if [ $IS_ACTIVE = "true" ]; then + "$SCRIPT_LOCATION" hide --no-rotate; + else + "$SCRIPT_LOCATION" show --no-rotate; + fi + exit 0; +fi + +if [ "$1" == "hide" ]; then + killall -s SIGUSR1 wvkbd-deskintl; + "$SCRIPT_LOCATION" reset; + if [ -z "$2" ]; then + hyprctl keyword monitor eDP-1,preferred,0x0,1,transform,0 + hyprctl keyword input:tablet:transform 0 + hyprctl keyword input:touchdevice:transform 0 + exit 0; + elif [ "$2" == "--no-rotate" ]; then + exit 0; + else + echo "Unknown flag: $2"; + fi + exit 1; +fi + +if [ "$1" == "show" ]; then + killall -s SIGUSR2 wvkbd-deskintl; + sed -i "s/IS_ACTIVE=\"false\"/IS_ACTIVE=\"true\"/" "$SCRIPT_LOCATION"; + if [ -z "$2" ]; then + hyprctl keyword monitor eDP-1,preferred,0x0,1,transform,1 + hyprctl keyword input:tablet:transform 1 + hyprctl keyword input:touchdevice:transform 1 + exit 0; + elif [ "$2" == "--no-rotate" ]; then + exit 0; + else + echo "Unknown flag: $2"; + fi + exit 1; +fi + +if [ "$1" == "json" ]; then + if [ $IS_ACTIVE = "true" ]; then + STATE="active" + ACTION="Hide" + ACTION_PL="Ukryj" + else + STATE="hidden" + ACTION="Show" + ACTION_PL="Pokaż" + fi + echo "{\"state\":\"${STATE}\",\"alt\":\"${ACTION}\",\"action\":{\"en\":\"${ACTION}\",\"pl\":\"${ACTION_PL}\"}}"; + exit 0; +fi + +if [ "$1" == "status" ]; then + if [ $IS_ACTIVE = "true" ]; then + echo "active"; + else + echo "hidden"; + fi + exit 0; +fi + +if [ "$1" == "reset" ]; then + sed -i "s/IS_ACTIVE=\"true\"/IS_ACTIVE=\"false\"/" "$SCRIPT_LOCATION"; + exit 0; +fi + + +if [ "$1" == "help" ]; then + echo "params: --no-rotate|hide [--no-rotate]|show [--no-rotate]|json|status|reset|help"; + echo "no param: toggle"; + exit 0; +fi + +echo "Unknown command \"${SCRIPT_LOCATION} $1\", use \"${SCRIPT_LOCATION} help\" for help."; +exit 1; \ No newline at end of file diff --git a/scripts/open_folder.desktop b/scripts/open_folder.desktop new file mode 100755 index 0000000..ad071cd --- /dev/null +++ b/scripts/open_folder.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=Terminal Folder Opener +Comment=Open a terminal in the selected folder +Exec=/home/guzio/.config/hypr/scripts/terminal.sh %f +MimeType=inode/directory +Terminal=false + +# Please replace /home/guzio/ with your actual $HOME path!!! \ No newline at end of file diff --git a/scripts/rootedinit.sh b/scripts/rootedinit.sh new file mode 100755 index 0000000..e1fde0f --- /dev/null +++ b/scripts/rootedinit.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# from volume-root.sh + +if [ -z "$1" ]; then + DIR="$HOME/.config/hypr/scripts" + SELF="$(realpath "$DIR/$(basename "$0")")" + + if [ "$SELF" != "$(realpath "$0")" ]; then + echo "This script must exist inside of $DIR"; + exit 1; + fi +else + if [ "root" != "$USER" ]; then + echo "Only root are allowed to arbitrarily specify the directory."; + exit 1; + fi + DIR=$1 + SELF="Something went horribly wrong! You were assumed to be root in one check, but non-root by the next one."; +fi + +if [ "root" != "$USER" ]; then + + if [ "$SELF" != "$(realpath "$0")" ]; then + echo "This script must exist inside of $DIR"; + exit 1; + fi + + exec sudo "$SELF" "$DIR"; + echo "NOTE: You should never see this message!" + exit 1; +fi + +# custom logic for rootedinit.sh +USRDIR="$DIR/../../.." +iptables -P FORWARD ACCEPT #Or Waydroid won't have internet access; iptables-save didn't work for some reason +mount -Bv "$USRDIR/Obrazy" "$USRDIR/.local/share/waydroid/data/media/0/Pictures" +mount -Bv "$USRDIR/Obrazy" "$USRDIR/.local/share/waydroid/data/media/0/DCIM" +mount -Bv "$USRDIR/Dokumenty" "$USRDIR/.local/share/waydroid/data/media/0/Documents" +mount -Bv "$USRDIR/Pobrane" "$USRDIR/.local/share/waydroid/data/media/0/Download" +mount -Bv "$USRDIR/.config" "$USRDIR/.local/share/waydroid/data/media/0/Source OS/conf" +mount -Bv "$USRDIR/.var/app" "$USRDIR/.local/share/waydroid/data/media/0/Source OS/flatpak" +swapon /dev/nvme0n1p3 #Unrelated to Waydroid, but this is probably the least awkward place to lazily put it \ No newline at end of file diff --git a/scripts/rotate.sh b/scripts/rotate.sh new file mode 100755 index 0000000..b34a6f0 --- /dev/null +++ b/scripts/rotate.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +ORIENTATION="$(head -n1 <(monitor-sensor --accel | grep --line-buffered -Eo "normal|left-up|bottom-up|right-up"))" + +hyprctl activewindow|grep Waydroid >> /dev/null +if [ $? -eq 0 ]; then + "$(dirname "$(realpath "$0")")/waydroid-root.sh" "rotate-$ORIENTATION" + ORIENTATION="normal" +fi + +if [[ "$ORIENTATION" == "normal" ]]; then + hyprctl keyword monitor eDP-1,preferred,0x0,1,transform,0 + hyprctl keyword input:tablet:transform 0 + hyprctl keyword input:touchdevice:transform 0 +elif [[ "$ORIENTATION" == "left-up" ]]; then + hyprctl keyword monitor eDP-1,preferred,0x0,1,transform,1 + hyprctl keyword input:tablet:transform 1 + hyprctl keyword input:touchdevice:transform 1 +elif [[ "$ORIENTATION" == "bottom-up" ]]; then + hyprctl keyword monitor eDP-1,preferred,0x0,1,transform,2 + hyprctl keyword input:tablet:transform 2 + hyprctl keyword input:touchdevice:transform 2 +elif [[ "$ORIENTATION" == "right-up" ]]; then + hyprctl keyword monitor eDP-1,preferred,0x0,1,transform,3 + hyprctl keyword input:tablet:transform 3 + hyprctl keyword input:touchdevice:transform 3 +else + hyprctl notify 3 1000 000 "Unknown orientation: $ORIENTATION. Resetting to normal." + hyprctl keyword monitor eDP-1,preferred,0x0,1,transform,0 + hyprctl keyword input:tablet:transform 0 + hyprctl keyword input:touchdevice:transform 0 + exit 1; +fi + +killall monitor-sensor + +exit 0; \ No newline at end of file diff --git a/scripts/screenshot.sh b/scripts/screenshot.sh new file mode 100755 index 0000000..2ada0f8 --- /dev/null +++ b/scripts/screenshot.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +KILLED=false +if pgrep satty; then + killall satty + KILLED=true +fi + +if [ -z $1 ]; then + : +elif [ $1 = "--button" ]; then + if [ $KILLED = "true" ]; then + exit 0; + else + set -- "$2"; + fi +fi + +if [ -z "$1" ]; then + grim -w "$(hyprctl activewindow -j | jq -r .address)" - | satty --filename - +elif [ "$1" = "--full" ]; then + grim - | satty --filename - +else + echo "Usage: $0 [--button] [--full]"; + exit 1; +fi + +exit 0; \ No newline at end of file diff --git a/scripts/stop_waydroid.desktop b/scripts/stop_waydroid.desktop new file mode 100755 index 0000000..c34afd2 --- /dev/null +++ b/scripts/stop_waydroid.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Name=Kill WayDroid Session +Comment=Kills a WayDroid Session +Exec=waydroid session stop +Terminal=true + +# Please replace /home/guzio/ with your actual $HOME path!!! \ No newline at end of file diff --git a/scripts/terminal.sh b/scripts/terminal.sh new file mode 100755 index 0000000..3f64679 --- /dev/null +++ b/scripts/terminal.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -z "$1" ]; then + konsole --new-tab --workdir $HOME + exit 0; +fi +konsole --new-tab --workdir $1 +hyprctl dispatch "hl.dsp.workspace.toggle_special(\"terminal\")" \ No newline at end of file diff --git a/scripts/toggle_hyprshell.sh b/scripts/toggle_hyprshell.sh new file mode 100755 index 0000000..2496633 --- /dev/null +++ b/scripts/toggle_hyprshell.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +SCRIPTDIR="$(dirname "$(realpath "$0")")" + +if hyprctl layers|grep hyprshell; then + wtype -k escape +else + hyprshell socat '"OpenOverview"' + + hyprctl activewindow|grep Waydroid >> /dev/null + if [ $? -eq 0 ]; then + hyprctl dispatch "hl.dsp.workspace.toggle_special(\"waydroid\")" + fi + + if [ "$1" = "-k" ] && [ "$("$SCRIPTDIR"/keyboard.sh status)" != "active" ]; then + "$SCRIPTDIR"/keyboard.sh show --no-rotate + while hyprctl layers|grep hyprshell; do + sleep 0.1; + done + "$SCRIPTDIR"/keyboard.sh hide --no-rotate + fi +fi \ No newline at end of file diff --git a/scripts/volume-core.sh b/scripts/volume-core.sh new file mode 100755 index 0000000..4c3afca --- /dev/null +++ b/scripts/volume-core.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +SCRIPT_THIS="$(realpath "$0")" +SCRIPT_ROOT="$(dirname "$SCRIPT_THIS")/volume-root.sh" +SCRIPT_ROOT_WD="$(dirname "$SCRIPT_THIS")/waydroid-root.sh" + +if [ -z "$1" ]; then + : +elif [ "$1" = "115" ]; then + # „Always control volume on the Linux side” flow commented out and waiting for a better day, because waydroid-root.sh reset-volume is broken (see waydroid-root.sh for details) + #hyprctl activewindow|grep Waydroid >> /dev/null + #if [ $? -eq 0 ]; then + # "$SCRIPT_ROOT_WD" reset-volume + #fi + #hyprpanel vol +5 + + # Shitty „hand controls to Android when Waydroid is in focus” flow that I wish I could forgo + hyprctl activewindow|grep Waydroid >> /dev/null + if [ $? -eq 0 ]; then + wpctl set-volume @DEFAULT_AUDIO_SINK@ 100% + else + wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ + fi +elif [ "$1" = "114" ]; then + # „Always control volume on the Linux side” flow commented out and waiting for a better day, because waydroid-root.sh reset-volume is broken (see waydroid-root.sh for details) + #hyprctl activewindow|grep Waydroid >> /dev/null + #if [ $? -eq 0 ]; then + # "$SCRIPT_ROOT_WD" reset-volume + #fi + #hyprpanel vol -5 + + # Shitty „hand controls to Android when Waydroid is in focus” flow that I wish I could forgo + hyprctl activewindow|grep Waydroid >> /dev/null + if [ $? -eq 0 ]; then + wpctl set-volume @DEFAULT_AUDIO_SINK@ 100% + else + wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- + fi +elif [ "$1" = "--start-daemon" ]; then + while true; do + "$SCRIPT_ROOT"|xargs "$SCRIPT_THIS" + done +elif [ "$1" = "--quit-daemon" ]; then + killall "$(basename "$SCRIPT_THIS")"; +else + echo "Unknown flag: $1"; + exit 1; +fi \ No newline at end of file diff --git a/scripts/volume-root.sh b/scripts/volume-root.sh new file mode 100755 index 0000000..e2b5d42 --- /dev/null +++ b/scripts/volume-root.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# I forgot that dirname exists while writing this. + +if [ -z "$1" ]; then + DIR="$HOME/.config/hypr/scripts" + SELF="$(realpath "$DIR/$(basename "$0")")" + + if [ "$SELF" != "$(realpath "$0")" ]; then + echo "This script must exist inside of $DIR"; + exit 1; + fi +else + if [ "root" != "$USER" ]; then + echo "Only root are allowed to arbitrarily specify the directory."; + exit 1; + fi + DIR=$1 + SELF="Something went horribly wrong! You were assumed to be root in one check, but non-root by the next one."; +fi + +if [ "root" != "$USER" ]; then + + if [ "$SELF" != "$(realpath "$0")" ]; then + echo "This script must exist inside of $DIR"; + exit 1; + fi + + exec sudo "$SELF" "$DIR"; + echo "NOTE: You should never see this message!" + exit 1; +fi + +"$DIR/volume-bin" | grep -Eo "115 press|114 press" \ No newline at end of file diff --git a/scripts/waydroid-root.sh b/scripts/waydroid-root.sh new file mode 100755 index 0000000..534cedc --- /dev/null +++ b/scripts/waydroid-root.sh @@ -0,0 +1,87 @@ +#!/bin/sh + +# custom logic for waydroid-root.sh [PART 1] +if [ -z "$1" ]; then + echo "Subcommand needed, use \"${SCRIPT_LOCATION} help\" for help."; + exit 1; +fi + +if [ "$1" == "help" ]; then + echo "params: rotate-normal|rotate-left-up|rotate-right-up|rotate-bottom-up|reset-volume|help"; + exit 0; +fi + + +# from volume-root.sh (modified to allow an extra param from the user) +if [ -z "$2" ]; then + DIR="$HOME/.config/hypr/scripts" + SELF="$(realpath "$DIR/$(basename "$0")")" + + if [ "$SELF" != "$(realpath "$0")" ]; then + echo "This script must exist inside of $DIR"; + exit 1; + fi +else + if [ "root" != "$USER" ]; then + echo "Only root are allowed to arbitrarily specify the directory."; + exit 1; + fi + DIR=$2 + SELF="Something went horribly wrong! You were assumed to be root in one check, but non-root by the next one."; +fi + +if [ "root" != "$USER" ]; then + + if [ "$SELF" != "$(realpath "$0")" ]; then + echo "This script must exist inside of $DIR"; + exit 1; + fi + + exec sudo "$SELF" "$1" "$DIR"; + echo "NOTE: You should never see this message!" + exit 1; +fi + +# custom logic for waydroid-root.sh [PART 2] + +if [ "$1" == "rotate-normal" ]; then + waydroid shell settings put system user_rotation 0 + exit; +fi + +if [ "$1" == "rotate-right-up" ]; then + waydroid shell settings put system user_rotation 1 + exit; +fi + +if [ "$1" == "rotate-bottom-up" ]; then + waydroid shell settings put system user_rotation 2 + exit; +fi + +if [ "$1" == "rotate-left-up" ]; then + waydroid shell settings put system user_rotation 3 + exit; +fi + +# Commented-out because it doesn't work. I can QUERY those values just fine, and the returned numbers correspond to what I put in my setting on the Android side - but when I try to SET them, nothing happens. I have no idea why, but it is what it is. +#if [ "$1" == "reset-volume" ]; then +# # These are the „everything is maxed out” values. Don't ask me why are they so random; I didn't make Android. +# waydroid shell settings put system volume_alarm 6 +# waydroid shell settings put system volume_alarm_speaker 7 +# waydroid shell settings put system volume_bluetooth_sco 7 +# waydroid shell settings put system volume_music 5 +# waydroid shell settings put system volume_music_speaker 15 +# waydroid shell settings put system volume_music_usb_headset 3 +# waydroid shell settings put system volume_notification 5 +# waydroid shell settings put system volume_notification_speaker 7 +# waydroid shell settings put system volume_ring 5 +# waydroid shell settings put system volume_ring_speaker 7 +# waydroid shell settings put system volume_system 7 +# waydroid shell settings put system volume_voice 4 +# waydroid shell settings put system volume_voice_speaker 15 +# exit 0; +#fi + +echo "Unknown command \"${SCRIPT_LOCATION} $1\", use \"${SCRIPT_LOCATION} help\" for help."; +exit 1; \ No newline at end of file diff --git a/scripts/waydroid.sh b/scripts/waydroid.sh new file mode 100755 index 0000000..67252e9 --- /dev/null +++ b/scripts/waydroid.sh @@ -0,0 +1,6 @@ +#!/bin/bash +SCRIPTDIR="$(dirname "$(realpath "$0")")" + +/usr/bin/sshd -f "$HOME/.ssh/wd-local/sshd_config" + +waydroid show-full-ui & sleep 60;"$SCRIPTDIR/rootedinit.sh" \ No newline at end of file diff --git a/wallpaper-test/wall3.png b/wallpaper-test/wall3.png new file mode 100644 index 0000000..f8bae22 Binary files /dev/null and b/wallpaper-test/wall3.png differ diff --git a/wallpaper-test/wall4.png b/wallpaper-test/wall4.png new file mode 100644 index 0000000..3f46c43 Binary files /dev/null and b/wallpaper-test/wall4.png differ diff --git a/wayle/config.toml b/wayle/config.toml new file mode 100644 index 0000000..03ffa27 --- /dev/null +++ b/wayle/config.toml @@ -0,0 +1 @@ +# Wayle configuration file diff --git a/wayle/runtime.toml b/wayle/runtime.toml new file mode 100644 index 0000000..a7a64f8 --- /dev/null +++ b/wayle/runtime.toml @@ -0,0 +1,191 @@ +[bar] +bg = "transparent" +button-variant = "basic" +button-label-weight = "bold" +button-rounding = "full" +button-border-width = 2 +dropdown-freeze-label = false + +[styling] +scale = 1.0 +rounding = "full" + +[styling.palette] +bg = "#000000" +surface = "#000000" +elevated = "#000000" +fg = "#e6ff10" +fg-muted = "#c6bb05" +primary = "#e6ff10" +red = "#ff0000" +yellow = "#e6ff10" +green = "#00ff00" +blue = "#00ffff" + +[modules.battery] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.bluetooth] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.cava] +button-bg-color = "bg-base" +border-show = true + +[modules.clock] +border-show = true +button-bg-color = "bg-base" + +[modules.cpu] +border-show = true +border-color = "fg-default" +icon-bg-color = "fg-default" +label-color = "fg-default" +button-bg-color = "bg-base" + +[modules.dashboard] +border-show = true + +[modules.hyprland-workspaces] +container-bg-color = "bg-base" +border-show = true +border-color = "accent" + +[modules.hyprsunset] +border-show = true +border-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.idle-inhibit] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.keybind-mode] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.keyboard-input] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.media] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.microphone] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.network] +border-show = true +icon-color = "accent" +button-bg-color = "bg-base" + +[modules.netstat] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.notification] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.power] +border-show = true +border-color = "accent" +icon-color = "bg-base" +icon-bg-color = "accent" + +[modules.ram] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.storage] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +label-max-length = 435 +button-bg-color = "bg-base" + +[modules.systray] +border-show = true +button-bg-color = "bg-base" + +[modules.volume] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.weather] +border-show = true +icon-color = "accent" +button-bg-color = "bg-base" + +[modules.window-title] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[modules.world-clock] +border-show = true +border-color = "accent" +icon-color = "accent" +icon-bg-color = "accent" +label-color = "accent" +button-bg-color = "bg-base" + +[wallpaper] +engine-enabled = false +transition-type = "fade" +cycling-mode = "shuffle" diff --git a/wayle/schema.json b/wayle/schema.json new file mode 100644 index 0000000..03b331f --- /dev/null +++ b/wayle/schema.json @@ -0,0 +1 @@ +{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"Config","description":"Main configuration structure for Wayle.\n\nRepresents the complete configuration schema that can be loaded\nfrom TOML files. All fields have sensible defaults.","type":"object","properties":{"imports":{"description":"TOML files to import and merge before this config.\n\nPaths are relative to the config file.\nImported values are overridden by values in this file.\n\n```toml\nimports = [\"themes.toml\", \"modules/clock.toml\"]\n```","type":"array","items":{"type":"string"},"default":[]},"general":{"description":"General Wayle settings.","$ref":"#/$defs/GeneralConfig","default":{"font-sans":"Inter","font-mono":"JetBrains Mono","tearing-mode":false}},"bar":{"description":"Bar layout and module placement.","$ref":"#/$defs/BarConfig","default":{"layout":[{"monitor":"*","extends":null,"show":true,"left":["media"],"center":["clock"],"right":["battery","bluetooth","network","microphone","volume"]}],"scale":1.0,"inset-edge":0.0,"inset-ends":0.0,"padding":0.3499999940395355,"padding-ends":0.5,"module-gap":0.5,"location":"top","bg":"bg-surface","background-opacity":100,"border-location":"none","border-width":1,"border-color":"border-accent","rounding":"none","shadow":"none","button-variant":"block-prefix","button-opacity":100,"button-bg-opacity":100,"button-icon-size":1.0,"button-icon-padding":1.0,"button-label-size":1.0,"button-label-weight":"semibold","button-label-padding":1.0,"button-rounding":"sm","button-gap":1.0,"button-icon-position":"start","button-border-location":"all","button-border-width":1,"button-group-border-location":"none","button-group-border-width":1,"button-group-padding":0.0,"button-group-module-gap":0.25,"button-group-background":"bg-elevated","button-group-opacity":100,"button-group-border-color":"border-accent","button-group-rounding":"sm","dropdown-shadow":true,"dropdown-opacity":100,"dropdown-autohide":true,"dropdown-freeze-label":true}},"styling":{"description":"Styling configuration (theme, fonts, scale).","$ref":"#/$defs/StylingConfig","default":{"scale":1.0099999904632568,"rounding":"sm","theme-provider":"wayle","theming-monitor":"","matugen-scheme":"tonal-spot","matugen-contrast":0.0,"matugen-source-color":0,"matugen-light":false,"wallust-palette":"dark16","wallust-saturation":0,"wallust-check-contrast":true,"wallust-backend":"fastresize","wallust-colorspace":"labmixed","wallust-apply-globally":true,"pywal-saturation":0.05,"pywal-contrast":3.0,"pywal-light":false,"pywal-apply-globally":true,"palette":{"bg":"#141420","surface":"#1c1c2c","elevated":"#262638","fg":"#d4d6e8","fg-muted":"#8a8ca4","primary":"#e0947a","red":"#e46870","yellow":"#e0b870","green":"#68c898","blue":"#78a0e0"}}},"modules":{"description":"Module-specific configurations.","$ref":"#/$defs/ModulesConfig","default":{"battery":{"level-icons":["md-battery_android_0-symbolic","md-battery_android_frame_1-symbolic","md-battery_android_frame_2-symbolic","md-battery_android_frame_3-symbolic","md-battery_android_frame_4-symbolic","md-battery_android_frame_5-symbolic","md-battery_android_frame_6-symbolic","md-battery_android_frame_full-symbolic"],"charging-icon":"md-battery_android_frame_bolt-symbolic","alert-icon":"md-battery_android_alert-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","format":"{{ percent }}%","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:battery","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]},"bluetooth":{"disabled-icon":"ld-bluetooth-off-symbolic","disconnected-icon":"ld-bluetooth-symbolic","connected-icon":"ld-bluetooth-connected-symbolic","searching-icon":"ld-bluetooth-searching-symbolic","border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":15,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:bluetooth","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"cava":{"bars":20,"framerate":60,"stereo":false,"noise-reduction":0.65,"monstercat":0.0,"waves":0,"low-cutoff":50,"high-cutoff":17000,"input":"pipe-wire","source":"auto","style":"bars","direction":"normal","color":"accent","button-bg-color":"bg-surface-elevated","bar-width":6,"bar-gap":1,"internal-padding":0.5,"border-show":false,"border-color":"border-accent","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"clock":{"format":"%a %b %d %I:%M %p","icon-name":"tb-calendar-time-symbolic","border-show":false,"border-color":"border-accent","icon-show":true,"icon-color":"auto","icon-bg-color":"accent","label-show":true,"label-color":"accent","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:calendar","right-click":"dropdown:weather","middle-click":"","scroll-up":"","scroll-down":"","dropdown-show-seconds":false},"cpu":{"poll-interval-ms":2000,"temp-sensor":"auto","format":"{{ percent }}%","icon-name":"ld-cpu-symbolic","border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]},"dashboard":{"icon-override":"","border-show":false,"border-color":"yellow","icon-color":"auto","icon-bg-color":"yellow","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","left-click":"dropdown:dashboard","dropdown-lock-command":"loginctl lock-session","dropdown-logout-command":"loginctl terminate-session $XDG_SESSION_ID","dropdown-reboot-command":"systemctl reboot","dropdown-poweroff-command":"systemctl poweroff"},"hyprland-workspaces":{"min-workspace-count":0,"monitor-specific":true,"show-special":true,"urgent-show":true,"urgent-mode":"workspace","display-mode":"label","label-use-name":false,"numbering":"absolute","divider":" ","app-icons-show":false,"app-icons-dedupe":true,"app-icons-fallback":"ld-app-window-symbolic","app-icons-empty":"tb-minus-symbolic","icon-gap":0.30000001192092896,"workspace-padding":0.5,"icon-size":1.0,"label-size":1.0,"workspace-ignore":[],"active-indicator":"background","active-color":"accent","occupied-color":"fg-muted","empty-color":"fg-subtle","container-bg-color":"bg-surface-elevated","border-show":false,"border-color":"border-default","workspace-map":{},"app-icon-map":{}},"hyprsunset":{"format":"{{ status }}","temperature":5000,"gamma":100,"icon-off":"ld-sun-symbolic","icon-on":"ld-moon-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":":toggle","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"idle-inhibit":{"startup-duration":60,"icon-inactive":"tb-coffee-off-symbolic","icon-active":"tb-coffee-symbolic","format":"{{ state }}","border-show":false,"border-color":"green","icon-show":true,"icon-color":"auto","icon-bg-color":"green","label-show":true,"label-color":"green","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"wayle idle toggle --indefinite","right-click":"wayle idle toggle","middle-click":"","scroll-up":"","scroll-down":""},"keybind-mode":{"format":"{{ mode }}","icon-name":"ld-layers-symbolic","auto-hide":false,"border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"keyboard-input":{"format":"{{ alias }}","icon-name":"ld-keyboard-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","layout-alias-map":{}},"media":{"icon-type":"application-mapped","player-icons":{},"players-ignored":[],"player-priority":[],"format":"{{ title }} - {{ artist }}","icon-name":"ld-music-symbolic","spinning-disc-icon":"ld-disc-3-symbolic","border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":35,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:media","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"microphone":{"icon-active":"ld-mic-symbolic","icon-muted":"ld-mic-off-symbolic","border-show":false,"border-color":"red","icon-show":true,"icon-color":"auto","icon-bg-color":"red","label-show":true,"label-color":"red","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:audio","right-click":"","middle-click":"wayle audio input-mute","scroll-up":"","scroll-down":"","thresholds":[]},"network":{"wifi-disabled-icon":"cm-wireless-disabled-symbolic","wifi-acquiring-icon":"cm-wireless-acquiring-symbolic","wifi-offline-icon":"cm-wireless-offline-symbolic","wifi-connected-icon":"cm-wireless-connected-symbolic","wifi-signal-icons":["cm-wireless-signal-weak-symbolic","cm-wireless-signal-ok-symbolic","cm-wireless-signal-good-symbolic","cm-wireless-signal-excellent-symbolic"],"wired-connected-icon":"cm-wired-symbolic","wired-acquiring-icon":"cm-wired-acquiring-symbolic","wired-disconnected-icon":"cm-wired-disconnected-symbolic","border-show":false,"border-color":"accent","icon-show":true,"icon-color":"auto","icon-bg-color":"accent","label-show":true,"label-color":"accent","label-max-length":15,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:network","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"netstat":{"poll-interval-ms":2000,"interface":"auto","format":"{{ down_auto }} {{ up_auto }}","icon-name":"ld-activity-symbolic","border-show":false,"border-color":"red","icon-show":true,"icon-color":"auto","icon-bg-color":"red","label-show":true,"label-color":"red","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"notification":{"icon-name":"ld-bell-symbolic","icon-unread":"ld-bell-dot-symbolic","icon-dnd":"ld-bell-off-symbolic","border-show":false,"border-color":"green","icon-show":true,"icon-color":"auto","icon-bg-color":"green","label-show":true,"label-color":"green","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:notification","right-click":"wayle notify dnd","middle-click":"","scroll-up":"","scroll-down":"","blocklist":[],"icon-source":"automatic","popup-position":"top-right","popup-max-visible":5,"popup-stacking-order":"newest-first","popup-duration":5000,"popup-hover-pause":true,"popup-margin-x":0.0,"popup-margin-y":0.0,"popup-gap":8.0,"popup-monitor":"primary","popup-close-behavior":"dismiss","popup-shadow":true,"popup-urgency-bar":"low","thresholds":[]},"power":{"icon-name":"ld-power-symbolic","border-show":false,"border-color":"red","icon-color":"auto","icon-bg-color":"red","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","left-click":""},"ram":{"poll-interval-ms":5000,"format":"{{ percent }}%","icon-name":"ld-memory-stick-symbolic","border-show":false,"border-color":"green","icon-show":true,"icon-color":"auto","icon-bg-color":"green","label-show":true,"label-color":"green","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]},"storage":{"poll-interval-ms":30000,"mount-point":"/","format":"{{ percent }}%","icon-name":"ld-hard-drive-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]},"separator":{"size":1,"length":1.5,"color":"fg-subtle"},"systray":{"icon-scale":1.0,"item-gap":0.25,"internal-padding":0.5,"blacklist":[],"overrides":[],"border-show":false,"border-color":"border-accent","button-bg-color":"bg-surface-elevated"},"volume":{"level-icons":["ld-volume-symbolic","ld-volume-1-symbolic","ld-volume-2-symbolic"],"icon-muted":"ld-volume-x-symbolic","border-show":false,"border-color":"red","icon-show":true,"icon-color":"auto","icon-bg-color":"red","label-show":true,"label-color":"red","format":"{{ percent }}%","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:audio","right-click":"","middle-click":"wayle audio output-mute","scroll-up":"","scroll-down":"","dropdown-app-icons":"mapped","thresholds":[]},"weather":{"provider":"open-meteo","location":"San Francisco","units":"metric","format":"{{ temp }}{{ temp_unit }}","time-format":"12h","refresh-interval-seconds":1800,"visual-crossing-key":null,"weatherapi-key":null,"icon-name":"ld-sun-symbolic","border-show":false,"border-color":"border-accent","icon-show":true,"icon-color":"auto","icon-bg-color":"accent","label-show":true,"label-color":"accent","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:weather","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"window-title":{"format":"{{ title }}","icon-name":"ld-app-window-symbolic","icon-mappings":{},"border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":50,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"world-clock":{"format":"{{ tz('UTC', '%H:%M %Z') }}","icon-name":"ld-globe-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""},"custom":[]}},"osd":{"description":"On-screen display settings.","$ref":"#/$defs/OsdConfig","default":{"enabled":true,"position":"bottom","duration":2500,"monitor":"primary","margin":150.0,"border":true}},"wallpaper":{"description":"Wallpaper service settings.","$ref":"#/$defs/WallpaperConfig","default":{"engine-enabled":true,"transition-type":"simple","transition-duration":0.699999988079071,"transition-fps":60,"cycling-enabled":false,"cycling-directory":"","cycling-mode":"sequential","cycling-interval-mins":15,"cycling-same-image":false,"monitors":[]}}},"$defs":{"GeneralConfig":{"description":"Shell-wide settings that don't belong to any specific module.","type":"object","properties":{"font-sans":{"description":"Sans-serif font family for UI text and labels.","$ref":"#/$defs/string","default":"Inter"},"font-mono":{"description":"Monospace font family for code and technical content.","$ref":"#/$defs/string","default":"JetBrains Mono"},"tearing-mode":{"description":"Demote overlay surfaces to allow compositor screen tearing.\n\nWhen enabled, surfaces that would normally use the `overlay` layer\nare demoted to `top`, allowing fullscreen games to use direct scanout.","$ref":"#/$defs/boolean","default":false}}},"string":{"type":"string"},"boolean":{"type":"boolean"},"BarConfig":{"description":"Bar chrome: per-monitor layout, spacing, colors, and button styling.","type":"object","properties":{"layout":{"description":"Per-monitor bar layouts. Each entry targets a monitor by connector name\n(e.g., `\"DP-1\"`) or `\"*\"` for all monitors. See [`BarLayout`] for the\nfull shape, including layout inheritance via `extends`.\n\n## Example\n\n```toml\n[[bar.layout]]\nmonitor = \"*\"\nleft = [\"dashboard\"]\ncenter = [\"clock\"]\nright = [\"battery\", \"network\", \"volume\", \"systray\"]\n\n[[bar.layout]]\nmonitor = \"HDMI-1\"\nextends = \"*\"\nright = [\"volume\", \"systray\"]\n```","$ref":"#/$defs/Array_of_BarLayout","default":[{"monitor":"*","extends":null,"show":true,"left":["media"],"center":["clock"],"right":["battery","bluetooth","network","microphone","volume"]}]},"scale":{"description":"Bar-specific scale multiplier for spacing, radius, and other bar elements.","$ref":"#/$defs/ScaleFactor","default":1.0},"inset-edge":{"description":"Gap between bar and its attached screen edge.\n\n- **Orientation**: Distance from top (horizontal bar) or left (vertical bar)","$ref":"#/$defs/Spacing","default":0.0},"inset-ends":{"description":"Gap at the bar's ends.\n\n- **Orientation**: Left/right (horizontal bar), top/bottom (vertical bar)","$ref":"#/$defs/Spacing","default":0.0},"padding":{"description":"Internal spacing along bar thickness.\n\n- **Orientation**: Top/bottom (horizontal bar), left/right (vertical bar)","$ref":"#/$defs/Spacing","default":0.3499999940395355},"padding-ends":{"description":"Internal spacing at bar ends.\n\n- **Orientation**: Left/right (horizontal bar), top/bottom (vertical bar)","$ref":"#/$defs/Spacing","default":0.5},"module-gap":{"description":"Gap between modules and groups on the bar.","$ref":"#/$defs/Spacing","default":0.5},"location":{"description":"Bar position on screen edge.","$ref":"#/$defs/Location","default":"top"},"bg":{"description":"Bar background color.","$ref":"#/$defs/ColorValue","default":"bg-surface"},"background-opacity":{"description":"Bar background opacity (0-100).","$ref":"#/$defs/Percentage","default":100},"border-location":{"description":"Border placement for bar.","$ref":"#/$defs/BorderLocation","default":"none"},"border-width":{"description":"Border width for bar (pixels).","$ref":"#/$defs/uint8","default":1},"border-color":{"description":"Border color for the bar.","$ref":"#/$defs/ColorValue","default":"border-accent"},"rounding":{"description":"Corner rounding level for the bar.","$ref":"#/$defs/RoundingLevel","default":"none"},"shadow":{"description":"Shadow style for the bar.","$ref":"#/$defs/ShadowPreset","default":"none"},"button-variant":{"description":"Visual style variant for bar buttons.","$ref":"#/$defs/BarButtonVariant","default":"block-prefix"},"button-opacity":{"description":"Button opacity (0-100).","$ref":"#/$defs/Percentage","default":100},"button-bg-opacity":{"description":"Button background opacity (0-100).","$ref":"#/$defs/Percentage","default":100},"button-icon-size":{"description":"Button icon size.","$ref":"#/$defs/ScaleFactor","default":1.0},"button-icon-padding":{"description":"Button icon container padding. Only applies to `block-prefix` and `icon-square` variants.","$ref":"#/$defs/ScaleFactor","default":1.0},"button-label-size":{"description":"Button label text size.","$ref":"#/$defs/ScaleFactor","default":1.0},"button-label-weight":{"description":"Button label font weight.","$ref":"#/$defs/FontWeightClass","default":"semibold"},"button-label-padding":{"description":"Button label container padding.","$ref":"#/$defs/ScaleFactor","default":1.0},"button-rounding":{"description":"Corner rounding level for the buttons in the bar.","$ref":"#/$defs/RoundingLevel","default":"sm"},"button-gap":{"description":"Gap between button icon and label.","$ref":"#/$defs/ScaleFactor","default":1.0},"button-icon-position":{"description":"Icon position relative to label in bar buttons.","$ref":"#/$defs/IconPosition","default":"start"},"button-border-location":{"description":"Border placement for bar buttons.","$ref":"#/$defs/BorderLocation","default":"all"},"button-border-width":{"description":"Border width for bar buttons (pixels).","$ref":"#/$defs/uint8","default":1},"button-group-border-location":{"description":"Border placement for button groups.","$ref":"#/$defs/BorderLocation","default":"none"},"button-group-border-width":{"description":"Border width for button groups (pixels).","$ref":"#/$defs/uint8","default":1},"button-group-padding":{"description":"Internal padding for button groups.","$ref":"#/$defs/Spacing","default":0.0},"button-group-module-gap":{"description":"Gap between modules within a group.","$ref":"#/$defs/Spacing","default":0.25},"button-group-background":{"description":"Background color for button groups.","$ref":"#/$defs/ColorValue","default":"bg-elevated"},"button-group-opacity":{"description":"Button group opacity (0-100).","$ref":"#/$defs/Percentage","default":100},"button-group-border-color":{"description":"Border color for button groups.","$ref":"#/$defs/ColorValue","default":"border-accent"},"button-group-rounding":{"description":"Corner rounding level for button groups.","$ref":"#/$defs/RoundingLevel","default":"sm"},"dropdown-shadow":{"description":"Enable dropdown panel shadow.","$ref":"#/$defs/boolean","default":true},"dropdown-opacity":{"description":"Dropdown panel opacity (0-100).","$ref":"#/$defs/Percentage","default":100},"dropdown-autohide":{"description":"Close dropdown when clicking outside it.","$ref":"#/$defs/boolean","default":true},"dropdown-freeze-label":{"description":"Freeze the bar button label while its dropdown is open.\n\nPrevents the button from resizing mid-interaction, which keeps the\ndropdown anchored in place.","$ref":"#/$defs/boolean","default":true}}},"Array_of_BarLayout":{"type":"array","items":{"$ref":"#/$defs/BarLayout"}},"BarLayout":{"description":"Layout configuration for a bar on a specific monitor.\n\n## Examples\n\n```toml\n# Single modules\n[[bar.layout]]\nmonitor = \"*\"\nleft = [\"dashboard\"]\ncenter = [\"clock\"]\nright = [\"systray\"]\n\n# Module with custom CSS class for per-instance styling\n[[bar.layout]]\nmonitor = \"DP-1\"\nleft = [{ module = \"clock\", class = \"primary-clock\" }, \"clock\"]\ncenter = [\"media\"]\n\n# Grouped modules (share a visual container, CSS-targetable by name)\n[[bar.layout]]\nmonitor = \"DP-2\"\nleft = [{ name = \"status\", modules = [\"battery\", \"network\"] }]\n\n# Groups can also contain classed modules\n[[bar.layout]]\nmonitor = \"DP-3\"\nleft = [{ name = \"clocks\", modules = [\n { module = \"clock\", class = \"local\" },\n { module = \"world-clock\", class = \"remote\" }\n]}]\n\n# Inherit from another layout\n[[bar.layout]]\nmonitor = \"*\"\nleft = [\"dashboard\"]\ncenter = [\"clock\"]\nright = [\"systray\"]\n\n[[bar.layout]]\nmonitor = \"HDMI-1\"\nextends = \"*\"\nright = [\"volume\", \"systray\"] # Override just this section\n\n# Hide bar on a specific monitor\n[[bar.layout]]\nmonitor = \"HDMI-2\"\nshow = false\n```","type":"object","properties":{"monitor":{"description":"Monitor connector name (e.g., `\"DP-1\"`) or `\"*\"` for all monitors.","type":"string","default":"*"},"extends":{"description":"Inherit from another layout by its monitor value (e.g., `\"*\"`).","type":["string","null"],"default":null},"show":{"description":"Whether the bar is visible on this monitor.","type":"boolean","default":true},"left":{"description":"Modules in the left section.","type":"array","items":{"$ref":"#/$defs/BarItem"},"default":["media"]},"center":{"description":"Modules in the center section.","type":"array","items":{"$ref":"#/$defs/BarItem"},"default":["clock"]},"right":{"description":"Modules in the right section.","type":"array","items":{"$ref":"#/$defs/BarItem"},"default":["battery","bluetooth","network","microphone","volume"]}}},"BarItem":{"description":"One entry in a bar layout section (`left`, `center`, or `right`).\n\nThree shapes are accepted, all interchangeable in the same array:\n\n- A plain module name: `\"clock\"`\n- A module with a CSS class for per-instance styling: `{ module = \"clock\", class = \"primary\" }`\n- A named group that wraps several modules in a shared container, addressable by CSS ID\n\n## Examples\n\n```toml\n[[bar.layout]]\nmonitor = \"*\"\n\n# Plain module\nleft = [\"dashboard\"]\n\n# Mix of plain and classed modules on the same side\ncenter = [\"clock\", { module = \"clock\", class = \"secondary\" }]\n\n# Named group (renders inside a GTK container with CSS ID `#status`)\nright = [{ name = \"status\", modules = [\"battery\", \"network\", \"volume\"] }]\n\n# Groups can hold classed modules too\n[[bar.layout]]\nmonitor = \"DP-2\"\nleft = [{ name = \"clocks\", modules = [\n { module = \"clock\", class = \"local\" },\n { module = \"world-clock\", class = \"remote\" }\n]}]\n```","anyOf":[{"description":"A single module (plain or with custom CSS class).","$ref":"#/$defs/ModuleRef"},{"description":"A named group of modules with shared visual container.","$ref":"#/$defs/BarGroup"}]},"ModuleRef":{"description":"Reference to a module, optionally with a custom CSS class.\n\n## Examples\n\n```toml\n# Plain module (just the name)\nleft = [\"clock\"]\n\n# Module with custom CSS class\nleft = [{ module = \"clock\", class = \"primary-clock\" }]\n```","anyOf":[{"description":"Module with a custom CSS class.","$ref":"#/$defs/ClassedModule"},{"description":"Plain module reference.","$ref":"#/$defs/BarModule"}]},"ClassedModule":{"description":"A module with an associated CSS class for custom styling.","type":"object","properties":{"module":{"description":"The module type.","$ref":"#/$defs/BarModule"},"class":{"description":"CSS class added to the module's GTK widget.","type":"string"}},"required":["module","class"]},"BarModule":{"description":"Bar module name. Built-in modules or custom modules with a `custom-` pattern.","anyOf":[{"enum":["battery","bluetooth","cava","clock","cpu","dashboard","hyprland-workspaces","hyprsunset","idle-inhibit","keybind-mode","keyboard-input","media","microphone","netstat","network","notifications","power","ram","separator","storage","systray","updates","volume","weather","window-title","world-clock"]},{"description":"Custom module ID (e.g., 'custom-gpu-temp')","type":"string","pattern":"^custom-[a-z0-9-]+$"}]},"BarGroup":{"description":"Named group of modules. The name becomes a CSS ID selector.","type":"object","properties":{"name":{"description":"Unique name for CSS targeting (becomes `#name` selector).","type":"string"},"modules":{"description":"Modules contained in this group.","type":"array","items":{"$ref":"#/$defs/ModuleRef"}}},"required":["name","modules"]},"ScaleFactor":{"description":"Scale multiplier clamped to 0.25-3.0.","type":"number","format":"float","minimum":0.25,"maximum":3.0},"Spacing":{"description":"Non-negative spacing value (clamped at 0).","type":"number","format":"float","minimum":0.0},"Location":{"description":"Bar position on screen.","oneOf":[{"description":"Top edge of the screen.","type":"string","const":"top"},{"description":"Bottom edge of the screen.","type":"string","const":"bottom"},{"description":"Left edge of the screen.","type":"string","const":"left"},{"description":"Right edge of the screen.","type":"string","const":"right"}]},"ColorValue":{"description":"CSS token, hex color (#rgb, #rgba, #rrggbb, or #rrggbbaa), 'transparent', or 'auto'","anyOf":[{"oneOf":[{"description":"`--bg-base` - Application background.","type":"string","const":"bg-base"},{"description":"`--bg-surface` - Elevated surfaces.","type":"string","const":"bg-surface"},{"description":"`--bg-surface-elevated` - Subtle elevation from surface (buttons on surface).","type":"string","const":"bg-surface-elevated"},{"description":"`--bg-elevated` - Higher elevation surfaces.","type":"string","const":"bg-elevated"},{"description":"`--bg-overlay` - Popovers, dialogs.","type":"string","const":"bg-overlay"},{"description":"`--bg-hover` - Hover state background.","type":"string","const":"bg-hover"},{"description":"`--bg-active` - Active/pressed state background.","type":"string","const":"bg-active"},{"description":"`--bg-selected` - Selected item background.","type":"string","const":"bg-selected"},{"description":"`--fg-default` - Primary text color.","type":"string","const":"fg-default"},{"description":"`--fg-muted` - Secondary text color.","type":"string","const":"fg-muted"},{"description":"`--fg-subtle` - Tertiary/hint text color.","type":"string","const":"fg-subtle"},{"description":"`--fg-on-accent` - Text color on accent backgrounds.","type":"string","const":"fg-on-accent"},{"description":"`--accent` - Primary accent color.","type":"string","const":"accent"},{"description":"`--accent-subtle` - Subtle accent background.","type":"string","const":"accent-subtle"},{"description":"`--accent-hover` - Accent hover state.","type":"string","const":"accent-hover"},{"description":"`--status-error` - Error state color.","type":"string","const":"status-error"},{"description":"`--status-warning` - Warning state color.","type":"string","const":"status-warning"},{"description":"`--status-success` - Success state color.","type":"string","const":"status-success"},{"description":"`--status-info` - Info state color.","type":"string","const":"status-info"},{"description":"`--status-error-subtle` - Subtle error background.","type":"string","const":"status-error-subtle"},{"description":"`--status-warning-subtle` - Subtle warning background.","type":"string","const":"status-warning-subtle"},{"description":"`--status-success-subtle` - Subtle success background.","type":"string","const":"status-success-subtle"},{"description":"`--status-info-subtle` - Subtle info background.","type":"string","const":"status-info-subtle"},{"description":"`--status-error-hover` - Error hover state.","type":"string","const":"status-error-hover"},{"description":"`--red` - Red color for stylistic/decorative use.","type":"string","const":"red"},{"description":"`--yellow` - Yellow color for stylistic/decorative use.","type":"string","const":"yellow"},{"description":"`--green` - Green color for stylistic/decorative use.","type":"string","const":"green"},{"description":"`--blue` - Blue color for stylistic/decorative use.","type":"string","const":"blue"},{"description":"`--border-subtle` - Subtle border color.","type":"string","const":"border-subtle"},{"description":"`--border-default` - Default border color.","type":"string","const":"border-default"},{"description":"`--border-strong` - Strong border color.","type":"string","const":"border-strong"},{"description":"`--border-accent` - Accent-colored border.","type":"string","const":"border-accent"},{"description":"`--border-error` - Error state border.","type":"string","const":"border-error"}]},{"enum":["transparent","auto"]},{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"}]},"Percentage":{"description":"Percentage value clamped to 0-100.","type":"integer","format":"uint8","minimum":0,"maximum":100},"BorderLocation":{"description":"Border placement for bar buttons.","oneOf":[{"description":"No border.","type":"string","const":"none"},{"description":"Border on top edge only.","type":"string","const":"top"},{"description":"Border on bottom edge only.","type":"string","const":"bottom"},{"description":"Border on left edge only.","type":"string","const":"left"},{"description":"Border on right edge only.","type":"string","const":"right"},{"description":"Border on all edges.","type":"string","const":"all"}]},"uint8":{"type":"integer","format":"uint8","minimum":0,"maximum":255},"RoundingLevel":{"description":"Global rounding preference for UI components.","oneOf":[{"description":"Sharp corners (no rounding).","type":"string","const":"none"},{"description":"Subtle rounding.","type":"string","const":"sm"},{"description":"Moderate rounding (default).","type":"string","const":"md"},{"description":"Pronounced rounding.","type":"string","const":"lg"},{"description":"Pill shape (fully rounded ends).","type":"string","const":"full"}]},"ShadowPreset":{"description":"Shadow style for the bar.","oneOf":[{"description":"No shadow.","type":"string","const":"none"},{"description":"Directional shadow opposite the anchor edge.","type":"string","const":"drop"},{"description":"All-around shadow.","type":"string","const":"floating"}]},"BarButtonVariant":{"description":"Visual style variants for bar buttons.","oneOf":[{"description":"Icon + label, minimal background.","type":"string","const":"basic"},{"description":"Icon in colored pill container that blends into button edge.","type":"string","const":"block-prefix"},{"description":"Button background with colored icon container inside.","type":"string","const":"icon-square"}]},"FontWeightClass":{"description":"Font weight class for typography.\n\nMaps to CSS classes like `.weight-normal`, `.weight-bold`, etc.\nUses the existing `--weight-*` tokens defined in SCSS.","oneOf":[{"description":"Normal weight (--weight-normal: 400).","type":"string","const":"normal"},{"description":"Medium weight (--weight-medium: 500).","type":"string","const":"medium"},{"description":"Semi-bold weight (--weight-semibold: 600).","type":"string","const":"semibold"},{"description":"Bold weight (--weight-bold: 700).","type":"string","const":"bold"}]},"IconPosition":{"description":"Icon position within bar buttons.","oneOf":[{"description":"Icon before label (left for horizontal, top for vertical bars).","type":"string","const":"start"},{"description":"Icon after label (right for horizontal, bottom for vertical bars).","type":"string","const":"end"}]},"StylingConfig":{"description":"Theme, palette, and rounding tokens applied shell-wide. Changes recompile the stylesheet.","type":"object","properties":{"scale":{"description":"Scale multiplier for dropdowns, popovers, and dialogs.","$ref":"#/$defs/ScaleFactor","default":1.0099999904632568},"rounding":{"description":"Corner rounding for dropdowns, popovers, and dialogs.","$ref":"#/$defs/RoundingLevel","default":"sm"},"theme-provider":{"description":"Theme provider (wayle, matugen, pywal, wallust).","$ref":"#/$defs/ThemeProvider","default":"wayle"},"theming-monitor":{"description":"Monitor whose wallpaper drives color extraction. Empty uses the first available.","$ref":"#/$defs/string","default":""},"matugen-scheme":{"description":"Matugen color scheme type.","$ref":"#/$defs/MatugenScheme","default":"tonal-spot"},"matugen-contrast":{"description":"Matugen contrast level (-1.0 to 1.0).","$ref":"#/$defs/SignedNormalizedF64","default":0.0},"matugen-source-color":{"description":"Matugen source color index (0-3).","$ref":"#/$defs/uint8","default":0},"matugen-light":{"description":"Matugen light mode.","$ref":"#/$defs/boolean","default":false},"wallust-palette":{"description":"Wallust palette mode.","$ref":"#/$defs/WallustPalette","default":"dark16"},"wallust-saturation":{"description":"Wallust saturation boost (0-100, 0 disables).","$ref":"#/$defs/Percentage","default":0},"wallust-check-contrast":{"description":"Wallust contrast checking against background.","$ref":"#/$defs/boolean","default":true},"wallust-backend":{"description":"Wallust image sampling backend.","$ref":"#/$defs/WallustBackend","default":"fastresize"},"wallust-colorspace":{"description":"Wallust color space for dominant color selection.","$ref":"#/$defs/WallustColorspace","default":"labmixed"},"wallust-apply-globally":{"description":"Apply wallust colors to terminals and external tools.","$ref":"#/$defs/boolean","default":true},"pywal-saturation":{"description":"Pywal saturation adjustment (0.0-1.0).","$ref":"#/$defs/NormalizedF64","default":0.05},"pywal-contrast":{"description":"Pywal minimum contrast ratio (1.0-21.0).","$ref":"#/$defs/PywalContrast","default":3.0},"pywal-light":{"description":"Pywal light mode.","$ref":"#/$defs/boolean","default":false},"pywal-apply-globally":{"description":"Apply pywal colors to terminals and external tools.","$ref":"#/$defs/boolean","default":true},"palette":{"description":"Active color palette.","$ref":"#/$defs/PaletteConfig","default":{"bg":"#141420","surface":"#1c1c2c","elevated":"#262638","fg":"#d4d6e8","fg-muted":"#8a8ca4","primary":"#e0947a","red":"#e46870","yellow":"#e0b870","green":"#68c898","blue":"#78a0e0"}}}},"ThemeProvider":{"description":"Source of color palette values.\n\nDynamic providers (Matugen, Pywal, Wallust) inject palette tokens at runtime.","oneOf":[{"description":"Static theming using Wayle's built-in palettes.","type":"string","const":"wayle"},{"description":"Dynamic theming via Matugen.","type":"string","const":"matugen"},{"description":"Dynamic theming via Pywal.","type":"string","const":"pywal"},{"description":"Dynamic theming via Wallust.","type":"string","const":"wallust"}]},"MatugenScheme":{"description":"Matugen color scheme type.","oneOf":[{"description":"Adapts to image content.","type":"string","const":"content"},{"description":"Bold, dramatic palette.","type":"string","const":"expressive"},{"description":"Stays close to source colors.","type":"string","const":"fidelity"},{"description":"Playful multi-color palette.","type":"string","const":"fruit-salad"},{"description":"Single-hue grayscale palette.","type":"string","const":"monochrome"},{"description":"Muted, understated palette.","type":"string","const":"neutral"},{"description":"Broad hue spread.","type":"string","const":"rainbow"},{"description":"Balanced Material You default.","type":"string","const":"tonal-spot"},{"description":"High-saturation palette.","type":"string","const":"vibrant"}]},"SignedNormalizedF64":{"description":"Floating-point value clamped to -1.0 to 1.0.","type":"number","format":"double","minimum":-1.0,"maximum":1.0},"WallustPalette":{"description":"Wallust palette mode.","oneOf":[{"description":"8 dark colors with 16-color trick.","type":"string","const":"dark16"},{"description":"8 dark colors, dark background and light contrast.","type":"string","const":"dark"},{"description":"Dark with complementary counterparts.","type":"string","const":"darkcomp"},{"description":"Dark complementary with 16-color trick.","type":"string","const":"darkcomp16"},{"description":"Dark with hard hue colors.","type":"string","const":"harddark"},{"description":"Hard dark with 16-color trick.","type":"string","const":"harddark16"},{"description":"Hard dark complementary variant.","type":"string","const":"harddarkcomp"},{"description":"Hard dark complementary with 16-color trick.","type":"string","const":"harddarkcomp16"},{"description":"Light background, dark foreground.","type":"string","const":"light"},{"description":"Light with 16-color trick.","type":"string","const":"light16"},{"description":"Light with complementary colors.","type":"string","const":"lightcomp"},{"description":"Light complementary with 16-color trick.","type":"string","const":"lightcomp16"},{"description":"Lightest colors with dark background.","type":"string","const":"softdark"},{"description":"Soft dark with 16-color trick.","type":"string","const":"softdark16"},{"description":"Soft dark complementary variant.","type":"string","const":"softdarkcomp"},{"description":"Soft dark complementary with 16-color trick.","type":"string","const":"softdarkcomp16"},{"description":"Light with soft pastel colors.","type":"string","const":"softlight"},{"description":"Soft light with 16-color trick.","type":"string","const":"softlight16"},{"description":"Soft light with complementary colors.","type":"string","const":"softlightcomp"},{"description":"Soft light complementary with 16-color trick.","type":"string","const":"softlightcomp16"},{"description":"ANSI-ordered dark palette for LS_COLORS.","type":"string","const":"ansidark"},{"description":"ANSI dark with 16-color trick.","type":"string","const":"ansidark16"}]},"WallustBackend":{"description":"Wallust image sampling backend.","oneOf":[{"description":"Reads every pixel.","type":"string","const":"full"},{"description":"Resizes image before sampling.","type":"string","const":"resized"},{"description":"Uses ImageMagick convert (pywal method).","type":"string","const":"wal"},{"description":"Fixed 512x512 thumbnail.","type":"string","const":"thumb"},{"description":"SIMD-accelerated resize.","type":"string","const":"fastresize"},{"description":"K-means clustering.","type":"string","const":"kmeans"}]},"WallustColorspace":{"description":"Wallust color space for dominant color selection.","oneOf":[{"description":"CIELAB perceptual color space.","type":"string","const":"lab"},{"description":"LAB with mixing for sparse images.","type":"string","const":"labmixed"},{"description":"Cylindrical LAB (hue/chroma/lightness).","type":"string","const":"lch"},{"description":"LCH with mixing.","type":"string","const":"lchmixed"},{"description":"LCH mapped to ANSI color ordering.","type":"string","const":"lchansi"}]},"NormalizedF64":{"description":"Floating-point value clamped to 0.0-1.0.","type":"number","format":"double","minimum":0.0,"maximum":1.0},"PywalContrast":{"description":"Pywal contrast ratio clamped to 1.0-21.0 (WCAG range).","type":"number","format":"double","minimum":1.0,"maximum":21.0},"PaletteConfig":{"description":"Color palette configuration for the active theme.","type":"object","properties":{"bg":{"description":"Base background color (darkest).","$ref":"#/$defs/HexColor","default":"#141420"},"surface":{"description":"Card and sidebar background.","$ref":"#/$defs/HexColor","default":"#1c1c2c"},"elevated":{"description":"Raised element background.","$ref":"#/$defs/HexColor","default":"#262638"},"fg":{"description":"Primary text color.","$ref":"#/$defs/HexColor","default":"#d4d6e8"},"fg-muted":{"description":"Secondary text color.","$ref":"#/$defs/HexColor","default":"#8a8ca4"},"primary":{"description":"Accent color for interactive elements.","$ref":"#/$defs/HexColor","default":"#e0947a"},"red":{"description":"Red semantic color.","$ref":"#/$defs/HexColor","default":"#e46870"},"yellow":{"description":"Yellow semantic color.","$ref":"#/$defs/HexColor","default":"#e0b870"},"green":{"description":"Green semantic color.","$ref":"#/$defs/HexColor","default":"#68c898"},"blue":{"description":"Blue semantic color.","$ref":"#/$defs/HexColor","default":"#78a0e0"}}},"HexColor":{"description":"GTK4 CSS hex color (#rgb, #rgba, #rrggbb, or #rrggbbaa)","type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"},"ModulesConfig":{"description":"Configuration for all available Wayle modules.","type":"object","properties":{"battery":{"description":"Battery status module.","$ref":"#/$defs/BatteryConfig","default":{"level-icons":["md-battery_android_0-symbolic","md-battery_android_frame_1-symbolic","md-battery_android_frame_2-symbolic","md-battery_android_frame_3-symbolic","md-battery_android_frame_4-symbolic","md-battery_android_frame_5-symbolic","md-battery_android_frame_6-symbolic","md-battery_android_frame_full-symbolic"],"charging-icon":"md-battery_android_frame_bolt-symbolic","alert-icon":"md-battery_android_alert-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","format":"{{ percent }}%","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:battery","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]}},"bluetooth":{"description":"Bluetooth connection module.","$ref":"#/$defs/BluetoothConfig","default":{"disabled-icon":"ld-bluetooth-off-symbolic","disconnected-icon":"ld-bluetooth-symbolic","connected-icon":"ld-bluetooth-connected-symbolic","searching-icon":"ld-bluetooth-searching-symbolic","border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":15,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:bluetooth","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"cava":{"description":"Cava audio visualizer module.","$ref":"#/$defs/CavaConfig","default":{"bars":20,"framerate":60,"stereo":false,"noise-reduction":0.65,"monstercat":0.0,"waves":0,"low-cutoff":50,"high-cutoff":17000,"input":"pipe-wire","source":"auto","style":"bars","direction":"normal","color":"accent","button-bg-color":"bg-surface-elevated","bar-width":6,"bar-gap":1,"internal-padding":0.5,"border-show":false,"border-color":"border-accent","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"clock":{"description":"Clock display module.","$ref":"#/$defs/ClockConfig","default":{"format":"%a %b %d %I:%M %p","icon-name":"tb-calendar-time-symbolic","border-show":false,"border-color":"border-accent","icon-show":true,"icon-color":"auto","icon-bg-color":"accent","label-show":true,"label-color":"accent","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:calendar","right-click":"dropdown:weather","middle-click":"","scroll-up":"","scroll-down":"","dropdown-show-seconds":false}},"cpu":{"description":"CPU usage module.","$ref":"#/$defs/CpuConfig","default":{"poll-interval-ms":2000,"temp-sensor":"auto","format":"{{ percent }}%","icon-name":"ld-cpu-symbolic","border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]}},"dashboard":{"description":"Dashboard module.","$ref":"#/$defs/DashboardConfig","default":{"icon-override":"","border-show":false,"border-color":"yellow","icon-color":"auto","icon-bg-color":"yellow","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","left-click":"dropdown:dashboard","dropdown-lock-command":"loginctl lock-session","dropdown-logout-command":"loginctl terminate-session $XDG_SESSION_ID","dropdown-reboot-command":"systemctl reboot","dropdown-poweroff-command":"systemctl poweroff"}},"hyprland-workspaces":{"description":"Hyprland workspace switcher module.","$ref":"#/$defs/HyprlandWorkspacesConfig","default":{"min-workspace-count":0,"monitor-specific":true,"show-special":true,"urgent-show":true,"urgent-mode":"workspace","display-mode":"label","label-use-name":false,"numbering":"absolute","divider":" ","app-icons-show":false,"app-icons-dedupe":true,"app-icons-fallback":"ld-app-window-symbolic","app-icons-empty":"tb-minus-symbolic","icon-gap":0.30000001192092896,"workspace-padding":0.5,"icon-size":1.0,"label-size":1.0,"workspace-ignore":[],"active-indicator":"background","active-color":"accent","occupied-color":"fg-muted","empty-color":"fg-subtle","container-bg-color":"bg-surface-elevated","border-show":false,"border-color":"border-default","workspace-map":{},"app-icon-map":{}}},"hyprsunset":{"description":"Hyprsunset (blue light filter) module.","$ref":"#/$defs/HyprsunsetConfig","default":{"format":"{{ status }}","temperature":5000,"gamma":100,"icon-off":"ld-sun-symbolic","icon-on":"ld-moon-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":":toggle","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"idle-inhibit":{"description":"Idle inhibitor module.","$ref":"#/$defs/IdleInhibitConfig","default":{"startup-duration":60,"icon-inactive":"tb-coffee-off-symbolic","icon-active":"tb-coffee-symbolic","format":"{{ state }}","border-show":false,"border-color":"green","icon-show":true,"icon-color":"auto","icon-bg-color":"green","label-show":true,"label-color":"green","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"wayle idle toggle --indefinite","right-click":"wayle idle toggle","middle-click":"","scroll-up":"","scroll-down":""}},"keybind-mode":{"description":"Keybind mode indicator module.","$ref":"#/$defs/KeybindModeConfig","default":{"format":"{{ mode }}","icon-name":"ld-layers-symbolic","auto-hide":false,"border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"keyboard-input":{"description":"Keyboard input module.","$ref":"#/$defs/KeyboardInputConfig","default":{"format":"{{ alias }}","icon-name":"ld-keyboard-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","layout-alias-map":{}}},"media":{"description":"Media player module.","$ref":"#/$defs/MediaConfig","default":{"icon-type":"application-mapped","player-icons":{},"players-ignored":[],"player-priority":[],"format":"{{ title }} - {{ artist }}","icon-name":"ld-music-symbolic","spinning-disc-icon":"ld-disc-3-symbolic","border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":35,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:media","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"microphone":{"description":"Microphone input module.","$ref":"#/$defs/MicrophoneConfig","default":{"icon-active":"ld-mic-symbolic","icon-muted":"ld-mic-off-symbolic","border-show":false,"border-color":"red","icon-show":true,"icon-color":"auto","icon-bg-color":"red","label-show":true,"label-color":"red","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:audio","right-click":"","middle-click":"wayle audio input-mute","scroll-up":"","scroll-down":"","thresholds":[]}},"network":{"description":"Network connection module.","$ref":"#/$defs/NetworkConfig","default":{"wifi-disabled-icon":"cm-wireless-disabled-symbolic","wifi-acquiring-icon":"cm-wireless-acquiring-symbolic","wifi-offline-icon":"cm-wireless-offline-symbolic","wifi-connected-icon":"cm-wireless-connected-symbolic","wifi-signal-icons":["cm-wireless-signal-weak-symbolic","cm-wireless-signal-ok-symbolic","cm-wireless-signal-good-symbolic","cm-wireless-signal-excellent-symbolic"],"wired-connected-icon":"cm-wired-symbolic","wired-acquiring-icon":"cm-wired-acquiring-symbolic","wired-disconnected-icon":"cm-wired-disconnected-symbolic","border-show":false,"border-color":"accent","icon-show":true,"icon-color":"auto","icon-bg-color":"accent","label-show":true,"label-color":"accent","label-max-length":15,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:network","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"netstat":{"description":"Network traffic statistics module.","$ref":"#/$defs/NetstatConfig","default":{"poll-interval-ms":2000,"interface":"auto","format":"{{ down_auto }} {{ up_auto }}","icon-name":"ld-activity-symbolic","border-show":false,"border-color":"red","icon-show":true,"icon-color":"auto","icon-bg-color":"red","label-show":true,"label-color":"red","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"notification":{"description":"Notification center module.","$ref":"#/$defs/NotificationConfig","default":{"icon-name":"ld-bell-symbolic","icon-unread":"ld-bell-dot-symbolic","icon-dnd":"ld-bell-off-symbolic","border-show":false,"border-color":"green","icon-show":true,"icon-color":"auto","icon-bg-color":"green","label-show":true,"label-color":"green","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:notification","right-click":"wayle notify dnd","middle-click":"","scroll-up":"","scroll-down":"","blocklist":[],"icon-source":"automatic","popup-position":"top-right","popup-max-visible":5,"popup-stacking-order":"newest-first","popup-duration":5000,"popup-hover-pause":true,"popup-margin-x":0.0,"popup-margin-y":0.0,"popup-gap":8.0,"popup-monitor":"primary","popup-close-behavior":"dismiss","popup-shadow":true,"popup-urgency-bar":"low","thresholds":[]}},"power":{"description":"Power menu module.","$ref":"#/$defs/PowerConfig","default":{"icon-name":"ld-power-symbolic","border-show":false,"border-color":"red","icon-color":"auto","icon-bg-color":"red","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","left-click":""}},"ram":{"description":"RAM usage module.","$ref":"#/$defs/RamConfig","default":{"poll-interval-ms":5000,"format":"{{ percent }}%","icon-name":"ld-memory-stick-symbolic","border-show":false,"border-color":"green","icon-show":true,"icon-color":"auto","icon-bg-color":"green","label-show":true,"label-color":"green","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]}},"storage":{"description":"Storage usage module.","$ref":"#/$defs/StorageConfig","default":{"poll-interval-ms":30000,"mount-point":"/","format":"{{ percent }}%","icon-name":"ld-hard-drive-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":"","thresholds":[]}},"separator":{"description":"Separator module.","$ref":"#/$defs/SeparatorConfig","default":{"size":1,"length":1.5,"color":"fg-subtle"}},"systray":{"description":"System tray module.","$ref":"#/$defs/SystrayConfig","default":{"icon-scale":1.0,"item-gap":0.25,"internal-padding":0.5,"blacklist":[],"overrides":[],"border-show":false,"border-color":"border-accent","button-bg-color":"bg-surface-elevated"}},"volume":{"description":"Volume control module.","$ref":"#/$defs/VolumeConfig","default":{"level-icons":["ld-volume-symbolic","ld-volume-1-symbolic","ld-volume-2-symbolic"],"icon-muted":"ld-volume-x-symbolic","border-show":false,"border-color":"red","icon-show":true,"icon-color":"auto","icon-bg-color":"red","label-show":true,"label-color":"red","format":"{{ percent }}%","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:audio","right-click":"","middle-click":"wayle audio output-mute","scroll-up":"","scroll-down":"","dropdown-app-icons":"mapped","thresholds":[]}},"weather":{"description":"Weather display module.","$ref":"#/$defs/WeatherConfig","default":{"provider":"open-meteo","location":"San Francisco","units":"metric","format":"{{ temp }}{{ temp_unit }}","time-format":"12h","refresh-interval-seconds":1800,"visual-crossing-key":null,"weatherapi-key":null,"icon-name":"ld-sun-symbolic","border-show":false,"border-color":"border-accent","icon-show":true,"icon-color":"auto","icon-bg-color":"accent","label-show":true,"label-color":"accent","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"dropdown:weather","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"window-title":{"description":"Window title module.","$ref":"#/$defs/WindowTitleConfig","default":{"format":"{{ title }}","icon-name":"ld-app-window-symbolic","icon-mappings":{},"border-show":false,"border-color":"blue","icon-show":true,"icon-color":"auto","icon-bg-color":"blue","label-show":true,"label-color":"blue","label-max-length":50,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"world-clock":{"description":"World clock module.","$ref":"#/$defs/WorldClockConfig","default":{"format":"{{ tz('UTC', '%H:%M %Z') }}","icon-name":"ld-globe-symbolic","border-show":false,"border-color":"yellow","icon-show":true,"icon-color":"auto","icon-bg-color":"yellow","label-show":true,"label-color":"yellow","label-max-length":0,"button-bg-color":"bg-surface-elevated","left-click":"","right-click":"","middle-click":"","scroll-up":"","scroll-down":""}},"custom":{"description":"Custom user-defined modules, each backed by a shell command. See\n[`CustomModuleDefinition`] for all fields (id, command, interval, click\nactions, icons, etc.). Reference them in a layout with `custom-`.\n\n## Example\n\n```toml\n[[modules.custom]]\nid = \"gpu-temp\"\ncommand = \"nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader\"\ninterval-ms = 5000\nicon-name = \"ld-thermometer-symbolic\"\n\n[[modules.custom]]\nid = \"weather\"\ncommand = \"curl -s wttr.in/?format=%t\"\ninterval-ms = 600000\n```","$ref":"#/$defs/Array_of_CustomModuleDefinition","default":[]}}},"BatteryConfig":{"description":"Battery level, charging state, and a dropdown with power-profile controls.","type":"object","properties":{"level-icons":{"description":"Icons for battery levels from empty to full.\n\nThe percentage is divided evenly among icons. With 5 icons:\n0-20% uses icons\\[0\\], 21-40% uses icons\\[1\\], etc.","$ref":"#/$defs/Array_of_string","default":["md-battery_android_0-symbolic","md-battery_android_frame_1-symbolic","md-battery_android_frame_2-symbolic","md-battery_android_frame_3-symbolic","md-battery_android_frame_4-symbolic","md-battery_android_frame_5-symbolic","md-battery_android_frame_6-symbolic","md-battery_android_frame_full-symbolic"]},"charging-icon":{"description":"Icon shown when battery is charging.","$ref":"#/$defs/string","default":"md-battery_android_frame_bolt-symbolic"},"alert-icon":{"description":"Icon shown when battery is not present or in an error state.","$ref":"#/$defs/string","default":"md-battery_android_alert-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-show":{"description":"Display percentage label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ percent }}` - Battery level (0-100)\n\n## Examples\n\n- `\"{{ percent }}%\"` - \"45%\"","$ref":"#/$defs/string","default":"{{ percent }}%"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:battery"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"thresholds":{"description":"Dynamic color thresholds based on battery percentage.\n\nEntries are checked in order; the last matching entry wins for each\ncolor slot. Use `below` for low-value warnings (e.g., low battery).\n\n## Example\n\n```toml\n[[modules.battery.thresholds]]\nbelow = 40\nicon-color = \"status-warning\"\n\n[[modules.battery.thresholds]]\nbelow = 20\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","$ref":"#/$defs/Array_of_ThresholdEntry","default":[]}}},"Array_of_string":{"type":"array","items":{"type":"string"}},"uint32":{"type":"integer","format":"uint32","minimum":0},"ClickAction":{"type":"string"},"Array_of_ThresholdEntry":{"type":"array","items":{"$ref":"#/$defs/ThresholdEntry"}},"ThresholdEntry":{"description":"A threshold entry that maps a numeric value range to color overrides.\n\nAt least one of `above` or `below` must be set. When both are set,\nboth conditions must be satisfied (AND logic).\n\n## TOML Example\n\n```toml\n[[modules.cpu.thresholds]]\nabove = 70\nicon-color = \"status-warning\"\nlabel-color = \"status-warning\"\n\n[[modules.cpu.thresholds]]\nabove = 90\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","type":"object","properties":{"above":{"description":"Activate when metric value >= this threshold.","type":["number","null"],"format":"double","default":null},"below":{"description":"Activate when metric value <= this threshold.","type":["number","null"],"format":"double","default":null},"icon-color":{"description":"Override icon color when threshold is active.","anyOf":[{"$ref":"#/$defs/ColorValue"},{"type":"null"}],"default":null},"label-color":{"description":"Override label color when threshold is active.","anyOf":[{"$ref":"#/$defs/ColorValue"},{"type":"null"}],"default":null},"icon-bg-color":{"description":"Override icon background color when threshold is active.","anyOf":[{"$ref":"#/$defs/ColorValue"},{"type":"null"}],"default":null},"button-bg-color":{"description":"Override button background color when threshold is active.","anyOf":[{"$ref":"#/$defs/ColorValue"},{"type":"null"}],"default":null},"border-color":{"description":"Override border color when threshold is active.","anyOf":[{"$ref":"#/$defs/ColorValue"},{"type":"null"}],"default":null}}},"BluetoothConfig":{"description":"Bluetooth connection status with a dropdown for pairing and managing devices.","type":"object","properties":{"disabled-icon":{"description":"Icon when Bluetooth is disabled or unavailable.","$ref":"#/$defs/string","default":"ld-bluetooth-off-symbolic"},"disconnected-icon":{"description":"Icon when Bluetooth is on but no devices connected.","$ref":"#/$defs/string","default":"ld-bluetooth-symbolic"},"connected-icon":{"description":"Icon when devices are connected.","$ref":"#/$defs/string","default":"ld-bluetooth-connected-symbolic"},"searching-icon":{"description":"Icon when scanning for devices.","$ref":"#/$defs/string","default":"ld-bluetooth-searching-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"blue"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-show":{"description":"Display connection label (device name or count).","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":15},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:bluetooth"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"CavaConfig":{"description":"Audio frequency bars visualising the output stream.","type":"object","properties":{"bars":{"description":"Number of frequency bars.","$ref":"#/$defs/BarCount","default":20},"framerate":{"description":"Visualization update rate in frames per second.","$ref":"#/$defs/Framerate","default":60},"stereo":{"description":"Stereo channel visualization (splits bars between left and right).","$ref":"#/$defs/boolean","default":false},"noise-reduction":{"description":"Noise reduction filter strength.","$ref":"#/$defs/NormalizedF64","default":0.65},"monstercat":{"description":"Monstercat-style smoothing across adjacent bars (0.0 = off).","$ref":"#/$defs/double","default":0.0},"waves":{"description":"Wave-style smoothing (0 = off).","$ref":"#/$defs/uint32","default":0},"low-cutoff":{"description":"Low frequency cutoff in Hz.","$ref":"#/$defs/FrequencyHz","default":50},"high-cutoff":{"description":"High frequency cutoff in Hz.","$ref":"#/$defs/FrequencyHz","default":17000},"input":{"description":"Audio capture backend.","$ref":"#/$defs/CavaInput","default":"pipe-wire"},"source":{"description":"Audio source identifier (\"auto\" for automatic selection).","$ref":"#/$defs/string","default":"auto"},"style":{"description":"Visualization rendering style.","$ref":"#/$defs/CavaStyle","default":"bars"},"direction":{"description":"Bar growth direction.","$ref":"#/$defs/CavaDirection","default":"normal"},"color":{"description":"Bar color.","$ref":"#/$defs/ColorValue","default":"accent"},"button-bg-color":{"description":"Module background color.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"bar-width":{"description":"Width of each frequency bar in pixels.","$ref":"#/$defs/uint32","default":6},"bar-gap":{"description":"Gap between frequency bars in pixels.","$ref":"#/$defs/uint32","default":1},"internal-padding":{"description":"Padding at the ends of the visualizer.","$ref":"#/$defs/Spacing","default":0.5},"border-show":{"description":"Display border around the visualizer.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color.","$ref":"#/$defs/ColorValue","default":"border-accent"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"BarCount":{"description":"Frequency bar count clamped to 1-256 (mirrors `wayle_cava::BarCount`).","type":"integer","format":"uint16","minimum":1,"maximum":256},"Framerate":{"description":"Visualization framerate clamped to 1-360 fps (mirrors `wayle_cava::Framerate`).","type":"integer","format":"uint32","minimum":1,"maximum":360},"double":{"type":"number","format":"double"},"FrequencyHz":{"description":"Frequency value in Hz, minimum 1 Hz.\n\nCross-field constraints (high_cutoff > low_cutoff, samplerate/2 > high_cutoff)\nare validated at the service builder.","type":"integer","format":"uint32","minimum":1},"CavaInput":{"description":"Audio capture backend.","oneOf":[{"description":"PipeWire multimedia server.","type":"string","const":"pipe-wire"},{"description":"PulseAudio sound server.","type":"string","const":"pulse"},{"description":"Advanced Linux Sound Architecture.","type":"string","const":"alsa"},{"description":"JACK Audio Connection Kit.","type":"string","const":"jack"},{"description":"Named pipe (FIFO) input.","type":"string","const":"fifo"},{"description":"PortAudio cross-platform library.","type":"string","const":"port-audio"},{"description":"sndio audio subsystem (BSD).","type":"string","const":"sndio"},{"description":"Open Sound System (legacy).","type":"string","const":"oss"},{"description":"Shared memory input.","type":"string","const":"shmem"},{"description":"Windows audio capture (WASAPI).","type":"string","const":"winscap"}]},"CavaStyle":{"description":"Visualization rendering style.","oneOf":[{"description":"Rectangular frequency bars.","type":"string","const":"bars"},{"description":"Smooth curve connecting bar peaks.","type":"string","const":"wave"},{"description":"Bars with floating peak indicators that decay over time.","type":"string","const":"peaks"}]},"CavaDirection":{"description":"Bar growth direction relative to the bar's attached screen edge.","oneOf":[{"description":"Bars grow away from the attached edge.","type":"string","const":"normal"},{"description":"Bars grow toward the attached edge.","type":"string","const":"reverse"},{"description":"Bars grow symmetrically from center.","type":"string","const":"mirror"}]},"ClockConfig":{"description":"Time display with a calendar dropdown.","type":"object","properties":{"format":{"description":"Format string using strftime syntax.\n\n## Common Specifiers\n\n- `%H` - Hour (00-23)\n- `%I` - Hour (01-12)\n- `%M` - Minute (00-59)\n- `%S` - Second (00-59)\n- `%p` - AM/PM\n- `%a` - Abbreviated weekday (Mon, Tue)\n- `%A` - Full weekday (Monday)\n- `%b` - Abbreviated month (Jan, Feb)\n- `%B` - Full month (January)\n- `%d` - Day of month (01-31)\n- `%Y` - Year (2024)\n\n## Examples\n\n- `\"%H:%M\"` - \"14:30\"\n- `\"%I:%M %p\"` - \"02:30 PM\"\n- `\"%a %b %d %I:%M %p\"` - \"Mon Jan 15 02:30 PM\"","$ref":"#/$defs/string","default":"%a %b %d %I:%M %p"},"icon-name":{"description":"Symbolic icon name.","$ref":"#/$defs/string","default":"tb-calendar-time-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"border-accent"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"accent"},"label-show":{"description":"Display text label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"accent"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:calendar"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":"dropdown:weather"},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"dropdown-show-seconds":{"description":"Show seconds in the calendar dropdown clock display.","$ref":"#/$defs/boolean","default":false}}},"CpuConfig":{"description":"CPU usage, frequency, and temperature.","type":"object","properties":{"poll-interval-ms":{"description":"Polling interval in milliseconds.\n\nFaster polling increases CPU usage.","$ref":"#/$defs/uint64","default":2000},"temp-sensor":{"description":"Temperature sensor label.\n\nUse `\"auto\"` for automatic detection, or specify a\nlabel (e.g., `\"Tctl\"`, `\"Package id 0\"`).\n\nRun `sensors` to see available labels.","$ref":"#/$defs/string","default":"auto"},"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ percent }}` - CPU usage (0-100)\n- `{{ freq_ghz }}` - Frequency of the busiest core (highest usage)\n- `{{ avg_freq_ghz }}` - Average frequency across cores\n- `{{ max_freq_ghz }}` - Maximum frequency among cores\n- `{{ temp_c }}` - Temperature in Celsius (if available)\n- `{{ temp_f }}` - Temperature in Fahrenheit (if available)\n\n## Examples\n\n- `\"{{ percent }}%\"` - \"45%\"\n- `\"{{ percent }}% @ {{ freq_ghz }}GHz\"` - \"45% @ 3.2GHz\"\n- `\"{{ percent }}% {{ temp_c }}C\"` - \"45% 62C\"","$ref":"#/$defs/string","default":"{{ percent }}%"},"icon-name":{"description":"Icon name.","$ref":"#/$defs/string","default":"ld-cpu-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"blue"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-show":{"description":"Display label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-max-length":{"description":"Max label characters before truncation. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"thresholds":{"description":"Dynamic color thresholds based on CPU usage percentage.\n\nEntries are checked in order; the last matching entry wins for each\ncolor slot. Use `above` for high-value warnings (e.g., high CPU usage).\n\n## Example\n\n```toml\n[[modules.cpu.thresholds]]\nabove = 70\nicon-color = \"status-warning\"\nlabel-color = \"status-warning\"\n\n[[modules.cpu.thresholds]]\nabove = 90\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","$ref":"#/$defs/Array_of_ThresholdEntry","default":[]}}},"uint64":{"type":"integer","format":"uint64","minimum":0},"DashboardConfig":{"description":"Quick-access button with a distro icon; opens the dashboard dropdown.","type":"object","properties":{"icon-override":{"description":"Override the auto-detected distro icon.","$ref":"#/$defs/string","default":""},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:dashboard"},"dropdown-lock-command":{"description":"Shell command for the lock button in the dashboard dropdown.","$ref":"#/$defs/string","default":"loginctl lock-session"},"dropdown-logout-command":{"description":"Shell command for the logout button in the dashboard dropdown.","$ref":"#/$defs/string","default":"loginctl terminate-session $XDG_SESSION_ID"},"dropdown-reboot-command":{"description":"Shell command for the reboot button in the dashboard dropdown.","$ref":"#/$defs/string","default":"systemctl reboot"},"dropdown-poweroff-command":{"description":"Shell command for the power-off button in the dashboard dropdown.","$ref":"#/$defs/string","default":"systemctl poweroff"}}},"HyprlandWorkspacesConfig":{"description":"Hyprland workspace indicators with click-to-switch.","type":"object","properties":{"min-workspace-count":{"description":"Minimum number of workspace buttons to display.\n\nWhen set to 0 (default), only active and occupied workspaces are shown.\nWhen set to N, at least N buttons are always visible, with empty ones\nusing `empty-color` styling.","$ref":"#/$defs/uint8","default":0},"monitor-specific":{"description":"Show only workspaces belonging to the bar's monitor.\n\nWhen true, each bar shows only its monitor's workspaces.\nWhen false, all workspaces from all monitors are shown.","$ref":"#/$defs/boolean","default":true},"show-special":{"description":"Include special workspaces (scratchpads) in the display.\n\nSpecial workspaces have negative IDs in Hyprland.","$ref":"#/$defs/boolean","default":true},"urgent-show":{"description":"Pulse animation on workspaces with urgent windows.\n\nWhen a window requests attention (e.g., terminal bell), the workspace\nbutton pulses until you switch to it.","$ref":"#/$defs/boolean","default":true},"urgent-mode":{"description":"Where the urgent pulse is applied.\n\n- `workspace`: Entire workspace pulses (default)\n- `application`: Only the app icon(s) belonging to the urgent window\n pulse, falling back to `workspace` when app icons are disabled","$ref":"#/$defs/UrgentMode","default":"workspace"},"display-mode":{"description":"What identifies each workspace button.\n\n- `label`: Shows workspace number (or name if `label-use-name` is true)\n- `icon`: Shows icon from `workspace-map` (falls back to label if unmapped)\n- `none`: Shows nothing - only app icons visible","$ref":"#/$defs/DisplayMode","default":"label"},"label-use-name":{"description":"Use workspace name instead of number when displaying labels.\n\nOnly applies when `display-mode = \"label\"` or as fallback for unmapped\nworkspaces in `display-mode = \"icon\"`.","$ref":"#/$defs/boolean","default":false},"numbering":{"description":"How workspace numbers are displayed.\n\n- `absolute`: Show actual Hyprland workspace IDs (1, 2, 3, 4, 5, 6...)\n- `relative`: Show numbers relative to monitor's starting workspace.\n If a monitor has workspaces 4, 5, 6 assigned, they display as 1, 2, 3.\n Useful when keybinds use per-monitor numbering.","$ref":"#/$defs/Numbering","default":"absolute"},"divider":{"description":"Text separator between workspace identity and app icons.\n\nOnly shown when both `display-mode` is not `none` and `app-icons-show`\nis enabled. Common values: `\"|\"`, `\"·\"`, `\"-\"`.","$ref":"#/$defs/string","default":" "},"app-icons-show":{"description":"Show application icons for windows in each workspace.\n\nWhen enabled, displays icons for running applications.\nIcons are resolved via `app-icon-map` configuration.","$ref":"#/$defs/boolean","default":false},"app-icons-dedupe":{"description":"Deduplicate application icons within a workspace.\n\nWhen true, shows only one icon per unique window class.\nWhen false, shows an icon for every window.","$ref":"#/$defs/boolean","default":true},"app-icons-fallback":{"description":"Fallback icon for applications not matched by `app-icon-map`.","$ref":"#/$defs/string","default":"ld-app-window-symbolic"},"app-icons-empty":{"description":"Icon shown for empty workspaces when `app-icons-show` is enabled.\n\nWhen a workspace has no windows but is displayed (via `min-workspace-count`),\nthis icon appears as a placeholder.","$ref":"#/$defs/string","default":"tb-minus-symbolic"},"icon-gap":{"description":"Gap between app icons within a workspace button.\n\nOnly applies to spacing between app icons.","$ref":"#/$defs/Spacing","default":0.30000001192092896},"workspace-padding":{"description":"Padding for workspace content along the bar direction.\n\nFor horizontal bars, controls horizontal (left/right) padding.\nFor vertical bars, controls vertical (top/bottom) padding.","$ref":"#/$defs/Spacing","default":0.5},"icon-size":{"description":"Scale multiplier for workspace icons.\n\nApplies to workspace identity icons and custom icons from `workspace-map`.\nRange: 0.25-3.0.","$ref":"#/$defs/ScaleFactor","default":1.0},"label-size":{"description":"Scale multiplier for workspace labels and dividers.\n\nApplies to workspace number/name labels and the divider text.\nRange: 0.25-3.0.","$ref":"#/$defs/ScaleFactor","default":1.0},"workspace-ignore":{"description":"Workspaces to hide from the display.\n\nGlob patterns matching workspace IDs. Examples:\n- `\"10\"` - hide workspace 10\n- `\"1?\"` - hide workspaces 10-19","$ref":"#/$defs/Array_of_string","default":[]},"active-indicator":{"description":"Visual indicator for the active workspace.","$ref":"#/$defs/ActiveIndicator","default":"background"},"active-color":{"description":"Color for the active (focused) workspace.\n\nApplied to icons and labels. In `background` indicator mode,\nalso used as the button background.","$ref":"#/$defs/ColorValue","default":"accent"},"occupied-color":{"description":"Color for occupied workspaces (has windows but not focused).\n\nApplied to icons and labels.","$ref":"#/$defs/ColorValue","default":"fg-muted"},"empty-color":{"description":"Color for empty workspaces.\n\nApplied to the empty placeholder icon and labels.","$ref":"#/$defs/ColorValue","default":"fg-subtle"},"container-bg-color":{"description":"Background color for the workspaces container.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"border-show":{"description":"Display border around the workspaces container.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color for the workspaces container.","$ref":"#/$defs/ColorValue","default":"border-default"},"workspace-map":{"description":"Per-workspace icon and color overrides.\n\nKeys are workspace IDs (use negative for special workspaces).\n\n## Example\n\n```toml\n[modules.hyprland-workspaces.workspace-map]\n1 = { icon = \"ld-globe-symbolic\", color = \"#4a90d9\" }\n2 = { icon = \"ld-terminal-symbolic\" }\n```","$ref":"#/$defs/WorkspaceMap","default":{}},"app-icon-map":{"description":"Application icon mapping with glob pattern support.\n\nMaps window class or title to symbolic icon names. Supports:\n- No prefix: Matches window class (e.g., `\"*firefox*\"`)\n- `class:` prefix: Explicit class match (e.g., `\"class:org.mozilla.*\"`)\n- `title:` prefix: Matches window title (e.g., `\"title:*YouTube*\"`)\n\nUser mappings are merged with built-in defaults for common applications.\n\n## Example\n\n```toml\n[modules.hyprland-workspaces.app-icon-map]\n\"*firefox*\" = \"ld-globe-symbolic\"\n\"title:*YouTube*\" = \"ld-youtube-symbolic\"\n```","$ref":"#/$defs/Map_of_string","default":{}}}},"UrgentMode":{"description":"Where the urgent pulse animation is applied.","oneOf":[{"description":"Pulse the entire workspace.","type":"string","const":"workspace"},{"description":"Pulse only the app icon(s) belonging to the urgent window.\n\nFalls back to `workspace` when app icons are disabled.","type":"string","const":"application"}]},"DisplayMode":{"description":"What identifies a workspace in the UI.","oneOf":[{"description":"Show workspace number or name.","type":"string","const":"label"},{"description":"Show icon from `workspace-map` (falls back to label if unmapped).","type":"string","const":"icon"},{"description":"Show nothing - only app icons visible.","type":"string","const":"none"}]},"Numbering":{"description":"How workspace numbers are displayed.","oneOf":[{"description":"Show actual Hyprland workspace IDs (1, 2, 3, 4, 5, 6...).","type":"string","const":"absolute"},{"description":"Show numbers relative to monitor's starting workspace.\n\nIf monitor has workspaces 4, 5, 6 assigned, they display as 1, 2, 3.\nUseful when keybinds use per-monitor numbering (Shift+1 for ws 4, etc.).","type":"string","const":"relative"}]},"ActiveIndicator":{"description":"Visual indicator style for the active workspace.","oneOf":[{"description":"Entire button gets a colored background.","type":"string","const":"background"},{"description":"Small colored bar under the workspace button.","type":"string","const":"underline"}]},"WorkspaceMap":{"description":"Per-workspace icon and color overrides, keyed by workspace ID.\n\nTOML table keys are always strings, so `\"1\"` parses into the workspace\nwith ID `1`. Negative IDs refer to Hyprland's special workspaces. Keys\nthat don't appear in the map fall back to the default behaviour set by\n[`HyprlandWorkspacesConfig::display_mode`].\n\n## Examples\n\n```toml\n[modules.hyprland-workspaces.workspace-map]\n# Whole entry on one line with an inline table\n1 = { icon = \"ld-globe-symbolic\", color = \"#4a90d9\" }\n2 = { icon = \"ld-terminal-symbolic\" }\n3 = { icon = \"ld-code-symbolic\", color = \"accent\" }\n\n# Or spread the entry across its own subtable\n[modules.hyprland-workspaces.workspace-map.4]\nicon = \"ld-message-square-symbolic\"\ncolor = \"status-success\"\n\n# Negative IDs target Hyprland special workspaces\n[modules.hyprland-workspaces.workspace-map.-99]\nicon = \"ld-scratch-symbolic\"\n```","type":"object","additionalProperties":false,"patternProperties":{"^-?\\d+$":{"$ref":"#/$defs/WorkspaceStyle"}}},"WorkspaceStyle":{"description":"Per-workspace styling override.","type":"object","properties":{"icon":{"description":"Custom icon for this workspace.","type":["string","null"]},"color":{"description":"Custom background color for this workspace when active.","anyOf":[{"$ref":"#/$defs/ColorValue"},{"type":"null"}]}}},"Map_of_string":{"type":"object","additionalProperties":{"type":"string"}},"HyprsunsetConfig":{"description":"Toggle for Hyprland's blue-light filter.","type":"object","properties":{"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ status }}` - Filter status text (On, Off)\n- `{{ temp }}` - Current temperature in Kelvin (shows \"--\" when disabled)\n- `{{ gamma }}` - Current gamma percentage (shows \"--\" when disabled)\n- `{{ config_temp }}` - Configured temperature (always available)\n- `{{ config_gamma }}` - Configured gamma (always available)\n\n## Examples\n\n- `\"{{ status }}\"` - \"On\"\n- `\"{{ temp }}K {{ gamma }}%\"` - \"4500K 80%\"\n- `\"{{ status }} ({{ temp }}K)\"` - \"On (4500K)\"","$ref":"#/$defs/string","default":"{{ status }}"},"temperature":{"description":"Color temperature in Kelvin when filter is enabled. Range: 1000-20000.","$ref":"#/$defs/uint32","default":5000},"gamma":{"description":"Display gamma percentage when filter is enabled. Range: 0-200.","$ref":"#/$defs/uint32","default":100},"icon-off":{"description":"Icon when filter is disabled (showing normal daylight colors).","$ref":"#/$defs/string","default":"ld-sun-symbolic"},"icon-on":{"description":"Icon when filter is enabled (showing warm night colors).","$ref":"#/$defs/string","default":"ld-moon-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-show":{"description":"Display label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click. Default toggles blue light filter.","$ref":"#/$defs/ClickAction","default":":toggle"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"IdleInhibitConfig":{"description":"Toggle that prevents screen dim, lock, and suspend while active.\n\nControllable from the CLI: `wayle idle on|off|duration|remaining|status`.","type":"object","properties":{"startup-duration":{"description":"Duration in minutes when service starts. 0 means indefinite.","$ref":"#/$defs/uint32","default":60},"icon-inactive":{"description":"Icon when idle inhibitor is inactive.","$ref":"#/$defs/string","default":"tb-coffee-off-symbolic"},"icon-active":{"description":"Icon when idle inhibitor is active.","$ref":"#/$defs/string","default":"tb-coffee-symbolic"},"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ state }}` - Inhibitor state text (On, Off)\n- `{{ remaining }}` - Time remaining (e.g., \"45m\", shows \"--\" when indefinite)\n- `{{ duration }}` - Total duration (e.g., \"60m\", shows \"--\" when indefinite)\n\n## Examples\n\n- `\"{{ state }}\"` - \"On\"\n- `\"{{ remaining }}/{{ duration }}\"` - \"45m/60m\"\n- `\"{{ state }} ({{ remaining }})\"` - \"On (45m)\"","$ref":"#/$defs/string","default":"{{ state }}"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"green"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"green"},"label-show":{"description":"Display label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"green"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click. Default toggles indefinite idle inhibit.","$ref":"#/$defs/ClickAction","default":"wayle idle toggle --indefinite"},"right-click":{"description":"Action on right click. Default toggles timed idle inhibit.","$ref":"#/$defs/ClickAction","default":"wayle idle toggle"},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"KeybindModeConfig":{"description":"Current keybind-mode indicator for modal compositors.","type":"object","properties":{"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ mode }}` - Current keybind mode name (shows \"default\" when inactive)\n\n## Examples\n\n- `\"{{ mode }}\"` - \"resize\"\n- `\"Mode: {{ mode }}\"` - \"Mode: resize\"\n- `\"[{{ mode }}]\"` - \"[resize]\"","$ref":"#/$defs/string","default":"{{ mode }}"},"icon-name":{"description":"Symbolic icon name.","$ref":"#/$defs/string","default":"ld-layers-symbolic"},"auto-hide":{"description":"Automatically hide module when no mode is active.","$ref":"#/$defs/boolean","default":false},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"blue"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-show":{"description":"Display text label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"KeyboardInputConfig":{"description":"Active keyboard layout indicator.","type":"object","properties":{"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ layout }}` - Raw layout name from the compositor (e.g., \"English (US)\")\n- `{{ alias }}` - User-defined alias from `layout-alias-map`, falls back to `{{ layout }}`\n\n## Examples\n\n- `\"{{ layout }}\"` - \"English (US)\"\n- `\"{{ alias }}\"` - \"EN\" (with alias map configured)","$ref":"#/$defs/string","default":"{{ alias }}"},"icon-name":{"description":"Symbolic icon name.","$ref":"#/$defs/string","default":"ld-keyboard-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-show":{"description":"Display text label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"layout-alias-map":{"description":"Language name mapping.\n\n## Example\n\n```toml\n[modules.keyboard-input.layout-alias-map]\n\"English (US)\" = \"EN\"\n\"Czech (QWERTY)\" = \"Czech\"\n```","$ref":"#/$defs/Map_of_string","default":{}}}},"MediaConfig":{"description":"Now-playing title and playback controls for the active MPRIS player.","type":"object","properties":{"icon-type":{"description":"Icon display mode.","$ref":"#/$defs/MediaIconType","default":"application-mapped"},"player-icons":{"description":"Custom player-to-icon mappings for application-mapped mode.\n\nKeys are glob patterns matching MPRIS bus names, values are icon names\nfrom the installed icon set. These override built-in mappings when\nmatched.\n\n## Example\n\n```toml\n[modules.media.player-icons]\n\"*spotify*\" = \"si-spotify-symbolic\"\n\"*firefox*\" = \"ld-globe-symbolic\"\n\"*.mpv\" = \"ld-play-circle-symbolic\"\n```","$ref":"#/$defs/Map_of_string","default":{}},"players-ignored":{"description":"Player bus name patterns to exclude from discovery. Requires a restart\nto take effect.\n\n## Example\n\n```toml\n[modules.media]\nplayers-ignored = [\"*chromium*\", \"*discord*\"]\n```","$ref":"#/$defs/Array_of_string","default":[]},"player-priority":{"description":"Preferred player priority order as glob patterns matching bus names.\n\nWhen no player is manually selected, this determines which player\nbecomes active. Patterns are checked in order; first match wins.\nIf no pattern matches, the first playing player is selected.\n\n## Example\n\n```toml\n[modules.media]\nplayer-priority = [\"*spotify*\", \"*firefox*\"]\n```","$ref":"#/$defs/Array_of_string","default":[]},"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ title }}` - Track title\n- `{{ artist }}` - Artist name(s)\n- `{{ album }}` - Album name\n- `{{ status }}` - Playback status text (Playing, Paused, Stopped)\n- `{{ status_icon }}` - Playback status icon character\n\n## Examples\n\n- `\"{{ title }} - {{ artist }}\"` - \"Bohemian Rhapsody - Queen\"\n- `\"{{ status_icon }} {{ title }}\"` - \"▶ Bohemian Rhapsody\"\n- `\"{{ artist }}: {{ title }} ({{ album }})\"` - \"Queen: Bohemian Rhapsody (A Night at the Opera)\"","$ref":"#/$defs/string","default":"{{ title }} - {{ artist }}"},"icon-name":{"description":"Symbolic icon name for default mode.","$ref":"#/$defs/string","default":"ld-music-symbolic"},"spinning-disc-icon":{"description":"Icon shown for spinning-disc mode.","$ref":"#/$defs/string","default":"ld-disc-3-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"blue"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-show":{"description":"Display text label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":35},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:media"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"MediaIconType":{"description":"Icon display mode for the media module.","oneOf":[{"description":"Static icon from icon-name field.","type":"string","const":"default"},{"description":"Dynamic icon from media player's desktop entry, falling back to icon-name.","type":"string","const":"application"},{"description":"Spinning disc icon that animates during playback. Uses slightly more CPU.","type":"string","const":"spinning-disc"},{"description":"Maps player to icon via glob patterns, with built-in mappings for common players.","type":"string","const":"application-mapped"}]},"MicrophoneConfig":{"description":"Microphone input level and mute toggle.","type":"object","properties":{"icon-active":{"description":"Icon shown when microphone is active (unmuted).","$ref":"#/$defs/string","default":"ld-mic-symbolic"},"icon-muted":{"description":"Icon shown when microphone is muted.","$ref":"#/$defs/string","default":"ld-mic-off-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"red"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"red"},"label-show":{"description":"Display percentage label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"red"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:audio"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click. Default toggles input mute.","$ref":"#/$defs/ClickAction","default":"wayle audio input-mute"},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"thresholds":{"description":"Dynamic color thresholds based on microphone volume percentage.\n\nEntries are checked in order; the last matching entry wins for each\ncolor slot. Use `above` for high-value warnings (e.g., high input gain).\n\n## Example\n\n```toml\n[[modules.microphone.thresholds]]\nabove = 70\nicon-color = \"status-warning\"\nlabel-color = \"status-warning\"\n\n[[modules.microphone.thresholds]]\nabove = 90\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","$ref":"#/$defs/Array_of_ThresholdEntry","default":[]}}},"NetworkConfig":{"description":"Network connection status with a dropdown for switching connections.","type":"object","properties":{"wifi-disabled-icon":{"description":"WiFi icon when disabled.","$ref":"#/$defs/string","default":"cm-wireless-disabled-symbolic"},"wifi-acquiring-icon":{"description":"WiFi icon when connecting.","$ref":"#/$defs/string","default":"cm-wireless-acquiring-symbolic"},"wifi-offline-icon":{"description":"WiFi icon when disconnected.","$ref":"#/$defs/string","default":"cm-wireless-offline-symbolic"},"wifi-connected-icon":{"description":"WiFi icon when connected but signal strength unavailable.","$ref":"#/$defs/string","default":"cm-wireless-connected-symbolic"},"wifi-signal-icons":{"description":"WiFi signal strength icons from weak to excellent.\n\nThe signal percentage maps to icons: 0-25% uses icons\\[0\\], 26-50% uses\nicons\\[1\\], etc.","$ref":"#/$defs/Array_of_string","default":["cm-wireless-signal-weak-symbolic","cm-wireless-signal-ok-symbolic","cm-wireless-signal-good-symbolic","cm-wireless-signal-excellent-symbolic"]},"wired-connected-icon":{"description":"Wired icon when connected.","$ref":"#/$defs/string","default":"cm-wired-symbolic"},"wired-acquiring-icon":{"description":"Wired icon when connecting.","$ref":"#/$defs/string","default":"cm-wired-acquiring-symbolic"},"wired-disconnected-icon":{"description":"Wired icon when disconnected.","$ref":"#/$defs/string","default":"cm-wired-disconnected-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"accent"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"accent"},"label-show":{"description":"Display connection label (SSID for WiFi, \"Wired\" for ethernet).","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"accent"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":15},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:network"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"NetstatConfig":{"description":"Network traffic counters (up/down rates).","type":"object","properties":{"poll-interval-ms":{"description":"Polling interval in milliseconds.\n\nFaster polling increases CPU usage.","$ref":"#/$defs/uint64","default":2000},"interface":{"description":"Network interface to monitor.\n\nUse `\"auto\"` to select the first active interface, or specify an\ninterface name like `\"eth0\"` or `\"wlan0\"`.","$ref":"#/$defs/string","default":"auto"},"format":{"description":"Format string for the label.\n\n## Download Placeholders\n\n- `{{ down_kib }}` - Download speed in KiB/s\n- `{{ down_mib }}` - Download speed in MiB/s\n- `{{ down_gib }}` - Download speed in GiB/s\n- `{{ down_auto }}` - Download speed with auto unit (e.g., \"1.5 MiB/s\")\n\n## Upload Placeholders\n\n- `{{ up_kib }}` - Upload speed in KiB/s\n- `{{ up_mib }}` - Upload speed in MiB/s\n- `{{ up_gib }}` - Upload speed in GiB/s\n- `{{ up_auto }}` - Upload speed with auto unit (e.g., \"256 KiB/s\")\n\n## Other Placeholders\n\n- `{{ interface }}` - Interface name (e.g., \"wlan0\")\n\n## Examples\n\n- `\"{{ down_auto }} {{ up_auto }}\"` - \"1.5 MiB/s 256 KiB/s\"\n- `\"D:{{ down_mib }} U:{{ up_mib }}\"` - \"D:1.5 U:0.2\"\n- `\"{{ interface }}: {{ down_auto }}\"` - \"wlan0: 1.5 MiB/s\"","$ref":"#/$defs/string","default":"{{ down_auto }} {{ up_auto }}"},"icon-name":{"description":"Icon name.","$ref":"#/$defs/string","default":"ld-activity-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"red"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"red"},"label-show":{"description":"Display label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"red"},"label-max-length":{"description":"Max label characters before truncation. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"NotificationConfig":{"description":"Notification center: icon in the bar, dropdown with history, DND toggle.","type":"object","properties":{"icon-name":{"description":"Icon shown when no notifications and DND is off.","$ref":"#/$defs/string","default":"ld-bell-symbolic"},"icon-unread":{"description":"Icon shown when notifications exist.","$ref":"#/$defs/string","default":"ld-bell-dot-symbolic"},"icon-dnd":{"description":"Icon shown when Do Not Disturb is active.","$ref":"#/$defs/string","default":"ld-bell-off-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"green"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"green"},"label-show":{"description":"Display notification count label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"green"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:notification"},"right-click":{"description":"Action on right click. Default toggles Do Not Disturb.","$ref":"#/$defs/ClickAction","default":"wayle notify dnd"},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"blocklist":{"description":"Glob patterns for app names whose notifications are blocked entirely.\n\nMatched notifications are silently dropped.\nSupports `*` (any characters) and `?` (single character).\n\nExamples: `[\"notify-send\", \"*chromium*\", \"Vivaldi*\"]`","$ref":"#/$defs/Array_of_string","default":[]},"icon-source":{"description":"How notification icons are resolved.\n\n| Mode | Per-notification image | No image provided |\n|------|----------------------|-------------------|\n| `automatic` | Shows the image | Mapped icon |\n| `mapped` | Ignored | Mapped icon |\n| `application` | Shows the image | App's generic icon, then mapped fallback |","$ref":"#/$defs/IconSource","default":"automatic"},"popup-position":{"description":"Screen position for popup notifications.","$ref":"#/$defs/PopupPosition","default":"top-right"},"popup-max-visible":{"description":"Maximum number of popups visible at once.","$ref":"#/$defs/uint32","default":5},"popup-stacking-order":{"description":"Order in which popups stack on screen.","$ref":"#/$defs/StackingOrder","default":"newest-first"},"popup-duration":{"description":"Maximum popup display duration in milliseconds.\n\nApplications may request a shorter timeout, which takes precedence.","$ref":"#/$defs/uint32","default":5000},"popup-hover-pause":{"description":"Pause popup auto-dismiss timer on hover.","$ref":"#/$defs/boolean","default":true},"popup-margin-x":{"description":"Horizontal margin from screen edges.","$ref":"#/$defs/Spacing","default":0.0},"popup-margin-y":{"description":"Vertical margin from screen edges.","$ref":"#/$defs/Spacing","default":0.0},"popup-gap":{"description":"Gap between stacked popups.","$ref":"#/$defs/Spacing","default":8.0},"popup-monitor":{"description":"Target monitor: \"primary\" or a connector name like \"DP-1\".","$ref":"#/$defs/PopupMonitor","default":"primary"},"popup-close-behavior":{"description":"What happens when the close button on a popup is clicked.","$ref":"#/$defs/PopupCloseBehavior","default":"dismiss"},"popup-shadow":{"description":"Display drop shadow on popup cards.","$ref":"#/$defs/boolean","default":true},"popup-urgency-bar":{"description":"Minimum urgency level that displays a colored urgency bar.","$ref":"#/$defs/UrgencyBarThreshold","default":"low"},"thresholds":{"description":"Dynamic color thresholds based on notification count.\n\nEntries are checked in order; the last matching entry wins for each\ncolor slot. Use `above` for high-value warnings (e.g., many unread\nnotifications).\n\n## Example\n\n```toml\n[[modules.notification.thresholds]]\nabove = 5\nicon-color = \"status-warning\"\nlabel-color = \"status-warning\"\n\n[[modules.notification.thresholds]]\nabove = 20\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","$ref":"#/$defs/Array_of_ThresholdEntry","default":[]}}},"IconSource":{"description":"Source for resolving notification icons.","oneOf":[{"description":"Use per-notification images when provided, otherwise Wayle's mapped icon.","type":"string","const":"automatic"},{"description":"Always use Wayle's mapped icons regardless of what the app provides.","type":"string","const":"mapped"},{"description":"Use the full application icon chain, falling back to mapped if unavailable.","type":"string","const":"application"}]},"PopupPosition":{"description":"Screen position for notification popups.","oneOf":[{"description":"Top-left corner.","type":"string","const":"top-left"},{"description":"Top-center edge.","type":"string","const":"top-center"},{"description":"Top-right corner.","type":"string","const":"top-right"},{"description":"Bottom-left corner.","type":"string","const":"bottom-left"},{"description":"Bottom-center edge.","type":"string","const":"bottom-center"},{"description":"Bottom-right corner.","type":"string","const":"bottom-right"},{"description":"Center-left edge.","type":"string","const":"center-left"},{"description":"Center-right edge.","type":"string","const":"center-right"}]},"StackingOrder":{"description":"Order in which popups are stacked on screen.","oneOf":[{"description":"Newest notifications appear closest to the configured position.","type":"string","const":"newest-first"},{"description":"Oldest notifications appear closest to the configured position.","type":"string","const":"oldest-first"}]},"PopupMonitor":{"description":"\"primary\" or a monitor connector name (e.g. \"DP-1\")","type":"string","default":"primary"},"PopupCloseBehavior":{"description":"Behavior when the close button is clicked on a popup card.","oneOf":[{"description":"Hide the popup; notification stays in history.","type":"string","const":"dismiss"},{"description":"Remove the notification entirely.","type":"string","const":"remove"}]},"UrgencyBarThreshold":{"description":"Minimum urgency level that shows a colored urgency bar on popup cards.\n\nAll urgency levels at or above the threshold display the bar.\nFor example, `Normal` shows bars on both normal and critical popups.","oneOf":[{"description":"Show urgency bars on all popups.","type":"string","const":"low"},{"description":"Show urgency bars on normal and critical popups.","type":"string","const":"normal"},{"description":"Show urgency bars on critical popups only.","type":"string","const":"critical"},{"description":"Never show urgency bars.","type":"string","const":"none"}]},"PowerConfig":{"description":"Shutdown, reboot, and logout menu.","type":"object","properties":{"icon-name":{"description":"Icon name to display.","$ref":"#/$defs/string","default":"ld-power-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"red"},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"red"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""}}},"RamConfig":{"description":"Memory and swap usage.","type":"object","properties":{"poll-interval-ms":{"description":"Polling interval in milliseconds.\n\nFaster polling increases CPU usage.","$ref":"#/$defs/uint64","default":5000},"format":{"description":"Format string for the label.\n\n## Memory Placeholders\n\n- `{{ percent }}` - Memory usage as integer (0-100)\n- `{{ used_gib }}` - Used memory in GiB (e.g., \"7.2\")\n- `{{ total_gib }}` - Total memory in GiB (e.g., \"16.0\")\n- `{{ available_gib }}` - Available memory in GiB (e.g., \"8.8\")\n\n## Swap Placeholders\n\n- `{{ swap_percent }}` - Swap usage as integer (0-100)\n- `{{ swap_used_gib }}` - Used swap in GiB\n- `{{ swap_total_gib }}` - Total swap in GiB\n\n## Examples\n\n- `\"{{ percent }}%\"` - \"45%\"\n- `\"{{ used_gib }}/{{ total_gib }} GiB\"` - \"7.2/16.0 GiB\"\n- `\"{{ percent }}% (Swap: {{ swap_percent }}%)\"` - \"45% (Swap: 12%)\"","$ref":"#/$defs/string","default":"{{ percent }}%"},"icon-name":{"description":"Icon name.","$ref":"#/$defs/string","default":"ld-memory-stick-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"green"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"green"},"label-show":{"description":"Display label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"green"},"label-max-length":{"description":"Max label characters before truncation. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"thresholds":{"description":"Dynamic color thresholds based on RAM usage percentage.\n\nEntries are checked in order; the last matching entry wins for each\ncolor slot. Use `above` for high-value warnings (e.g., high memory usage).\n\n## Example\n\n```toml\n[[modules.ram.thresholds]]\nabove = 80\nicon-color = \"status-warning\"\nlabel-color = \"status-warning\"\n\n[[modules.ram.thresholds]]\nabove = 95\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","$ref":"#/$defs/Array_of_ThresholdEntry","default":[]}}},"StorageConfig":{"description":"Disk usage for a mount point.","type":"object","properties":{"poll-interval-ms":{"description":"Polling interval in milliseconds.\n\nFaster polling increases CPU usage.","$ref":"#/$defs/uint64","default":30000},"mount-point":{"description":"Mount point to monitor (e.g., `\"/\"`, `\"/home\"`).","$ref":"#/$defs/string","default":"/"},"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ percent }}` - Disk usage as integer (0-100)\n- `{{ used_tib }}` - Used space in TiB\n- `{{ used_gib }}` - Used space in GiB\n- `{{ used_mib }}` - Used space in MiB\n- `{{ used_auto }}` - Used space with auto unit (e.g., \"128.5 GiB\")\n- `{{ total_tib }}` - Total space in TiB\n- `{{ total_gib }}` - Total space in GiB\n- `{{ total_mib }}` - Total space in MiB\n- `{{ total_auto }}` - Total space with auto unit\n- `{{ free_tib }}` - Free space in TiB\n- `{{ free_gib }}` - Free space in GiB\n- `{{ free_mib }}` - Free space in MiB\n- `{{ free_auto }}` - Free space with auto unit\n- `{{ filesystem }}` - Filesystem type (e.g., \"ext4\", \"btrfs\")\n\n## Examples\n\n- `\"{{ percent }}%\"` - \"45%\"\n- `\"{{ used_auto }}/{{ total_auto }}\"` - \"128.5 GiB/512.0 GiB\"\n- `\"{{ free_gib }} GiB free\"` - \"383.5 GiB free\"","$ref":"#/$defs/string","default":"{{ percent }}%"},"icon-name":{"description":"Icon name.","$ref":"#/$defs/string","default":"ld-hard-drive-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-show":{"description":"Display label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-max-length":{"description":"Max label characters before truncation. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"thresholds":{"description":"Dynamic color thresholds based on disk usage percentage.\n\nEntries are checked in order; the last matching entry wins for each\ncolor slot. Use `above` for high-value warnings (e.g., disk nearly full).\n\n## Example\n\n```toml\n[[modules.storage.thresholds]]\nabove = 70\nicon-color = \"status-warning\"\nlabel-color = \"status-warning\"\n\n[[modules.storage.thresholds]]\nabove = 90\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","$ref":"#/$defs/Array_of_ThresholdEntry","default":[]}}},"SeparatorConfig":{"description":"A vertical rule between bar modules.","type":"object","properties":{"size":{"description":"Thickness of the separator line in pixels.","$ref":"#/$defs/uint32","default":1},"length":{"description":"Length of the separator line.","$ref":"#/$defs/Spacing","default":1.5},"color":{"description":"Color of the separator line.","$ref":"#/$defs/ColorValue","default":"fg-subtle"}}},"SystrayConfig":{"description":"System tray icons via the StatusNotifierItem protocol.","type":"object","properties":{"icon-scale":{"description":"Scale multiplier for tray item icons.","$ref":"#/$defs/ScaleFactor","default":1.0},"item-gap":{"description":"Gap between tray items.","$ref":"#/$defs/Spacing","default":0.25},"internal-padding":{"description":"Padding at the ends of the container.\n\nApplies to left/right edges for horizontal bars, or top/bottom edges\nfor vertical bars.","$ref":"#/$defs/Spacing","default":0.5},"blacklist":{"description":"Glob patterns for tray items to hide.\n\nMatches against item ID or title.\nExample: `[\"*discord*\", \"Steam\"]`","$ref":"#/$defs/Array_of_string","default":[]},"overrides":{"description":"Custom icon and color overrides.\n\nFirst matching override wins. Supports glob patterns.\n\n```toml\n[[module.systray.overrides]]\nname = \"*discord*\"\nicon = \"si-discord-symbolic\"\ncolor = \"blue\"\n```","$ref":"#/$defs/Array_of_TrayItemOverride","default":[]},"border-show":{"description":"Display border around container.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"border-accent"},"button-bg-color":{"description":"Container background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"}}},"Array_of_TrayItemOverride":{"type":"array","items":{"$ref":"#/$defs/TrayItemOverride"}},"TrayItemOverride":{"description":"Custom icon and color override for tray items matching a pattern.","type":"object","properties":{"name":{"description":"Glob pattern to match against item ID or title.\n\nExamples: `\"discord\"`, `\"*Discord*\"`, `\"org.kde.*\"`","type":"string"},"icon":{"description":"Custom icon name (symbolic icon).","type":["string","null"]},"color":{"description":"Custom icon color.","anyOf":[{"$ref":"#/$defs/ColorValue"},{"type":"null"}]}},"required":["name"]},"VolumeConfig":{"description":"Output volume control with a dropdown for device and app volumes.","type":"object","properties":{"level-icons":{"description":"Icons for volume levels from low to maximum.\n\nThe percentage is divided evenly among icons. With 3 icons:\n1-33% uses icons\\[0\\], 34-66% uses icons\\[1\\], 67-100% uses icons\\[2\\].","$ref":"#/$defs/Array_of_string","default":["ld-volume-symbolic","ld-volume-1-symbolic","ld-volume-2-symbolic"]},"icon-muted":{"description":"Icon shown when audio output is muted.","$ref":"#/$defs/string","default":"ld-volume-x-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"red"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"red"},"label-show":{"description":"Display percentage label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"red"},"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ percent }}` - Volume (0-100)\n\n## Examples\n\n- `\"{{ percent }}%\"` - \"45%\"","$ref":"#/$defs/string","default":"{{ percent }}%"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click. Default opens the audio dropdown.","$ref":"#/$defs/ClickAction","default":"dropdown:audio"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click. Default toggles mute.","$ref":"#/$defs/ClickAction","default":"wayle audio output-mute"},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""},"dropdown-app-icons":{"description":"Icon source for app volume entries in the audio dropdown.","$ref":"#/$defs/AppIconSource","default":"mapped"},"thresholds":{"description":"Dynamic color thresholds based on volume percentage.\n\nEntries are checked in order; the last matching entry wins for each\ncolor slot. Use `above` for high-value warnings (e.g., boosted volume).\n\n## Example\n\n```toml\n[[modules.volume.thresholds]]\nabove = 100\nicon-color = \"status-warning\"\nlabel-color = \"status-warning\"\n\n[[modules.volume.thresholds]]\nabove = 130\nicon-color = \"status-error\"\nlabel-color = \"status-error\"\n```","$ref":"#/$defs/Array_of_ThresholdEntry","default":[]}}},"AppIconSource":{"description":"Icon source for app volume entries in the dropdown.","oneOf":[{"description":"Wayle's curated symbolic icons matched by app name.","type":"string","const":"mapped"},{"description":"Native application icons reported by PulseAudio.","type":"string","const":"native"}]},"WeatherConfig":{"description":"Current conditions with hourly and daily forecasts in a dropdown.","type":"object","properties":{"provider":{"description":"Weather data provider.","$ref":"#/$defs/WeatherProvider","default":"open-meteo"},"location":{"description":"Location for weather data (city name or \"lat,lon\" coordinates).","$ref":"#/$defs/string","default":"San Francisco"},"units":{"description":"Temperature unit.","$ref":"#/$defs/TemperatureUnit","default":"metric"},"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ temp }}` - Current temperature (e.g., \"72\")\n- `{{ temp_unit }}` - Temperature unit symbol (\"°F\" or \"°C\")\n- `{{ feels_like }}` - Feels-like temperature\n- `{{ condition }}` - Weather condition text (e.g., \"Cloudy\")\n- `{{ humidity }}` - Humidity percentage (e.g., \"65%\")\n- `{{ wind_speed }}` - Wind speed with unit (e.g., \"12 km/h\")\n- `{{ wind_dir }}` - Wind direction (e.g., \"NW\")\n- `{{ high }}` - Today's high temperature\n- `{{ low }}` - Today's low temperature\n\n## Examples\n\n- `\"{{ temp }}{{ temp_unit }}\"` - \"22°C\"\n- `\"{{ temp }}{{ temp_unit }} {{ condition }}\"` - \"22°C Partly Cloudy\"\n- `\"{{ temp }}{{ temp_unit }} H:{{ high }} L:{{ low }}\"` - \"22°C H:25 L:18\"","$ref":"#/$defs/string","default":"{{ temp }}{{ temp_unit }}"},"time-format":{"description":"Time display format for sunrise/sunset and hourly forecast.","$ref":"#/$defs/TimeFormat","default":"12h"},"refresh-interval-seconds":{"description":"Polling interval in seconds.","$ref":"#/$defs/uint32","default":1800},"visual-crossing-key":{"description":"Visual Crossing API key. Supports `$VAR_NAME` syntax to reference\nenvironment variables from `.*.env` files in the config directory.","$ref":"#/$defs/Nullable_string","default":null},"weatherapi-key":{"description":"WeatherAPI.com API key. Supports `$VAR_NAME` syntax to reference\nenvironment variables from `.*.env` files in the config directory.","$ref":"#/$defs/Nullable_string","default":null},"icon-name":{"description":"Fallback icon for weather.","$ref":"#/$defs/string","default":"ld-sun-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"border-accent"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"accent"},"label-show":{"description":"Display temperature label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"accent"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":"dropdown:weather"},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"WeatherProvider":{"description":"Weather data provider selection.","oneOf":[{"description":"Open-Meteo (no API key required).","type":"string","const":"open-meteo"},{"description":"Visual Crossing (requires API key).","type":"string","const":"visual-crossing"},{"description":"WeatherAPI.com (requires API key).","type":"string","const":"weather-api"}]},"TemperatureUnit":{"description":"Temperature unit for display.","oneOf":[{"description":"Celsius (metric).","type":"string","const":"metric"},{"description":"Fahrenheit (imperial).","type":"string","const":"imperial"}]},"TimeFormat":{"description":"Time display format.","oneOf":[{"description":"12-hour format with AM/PM (e.g., \"6:30 AM\").","type":"string","const":"12h"},{"description":"24-hour format (e.g., \"06:30\").","type":"string","const":"24h"}]},"Nullable_string":{"type":["string","null"]},"WindowTitleConfig":{"description":"Active window title with optional app-icon prefix.","type":"object","properties":{"format":{"description":"Format string for the label.\n\n## Placeholders\n\n- `{{ title }}` - Window title\n- `{{ app }}` - Application name (WM_CLASS on Hyprland)\n\n## Examples\n\n- `\"{{ title }}\"` - \"README.md - VSCode\"\n- `\"{{ app }}: {{ title }}\"` - \"firefox: GitHub\"","$ref":"#/$defs/string","default":"{{ title }}"},"icon-name":{"description":"Fallback icon when no mapping matches.","$ref":"#/$defs/string","default":"ld-app-window-symbolic"},"icon-mappings":{"description":"Icon mappings. Glob patterns to icon names.\n\nKeys are patterns matching the window class (default) or title (when\nprefixed with `title:`). Values are icon names from the installed icon\nset. User mappings are checked before built-in mappings.\n\n## Example\n\n```toml\n[modules.window-title.icon-mappings]\n\"*firefox*\" = \"ld-globe-symbolic\"\n\"org.mozilla.*\" = \"ld-globe-symbolic\"\n\"title:*YouTube*\" = \"ld-youtube-symbolic\"\n```","$ref":"#/$defs/Map_of_string","default":{}},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"blue"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-show":{"description":"Display text label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"blue"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":50},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"WorldClockConfig":{"description":"Multiple timezones shown together in a dropdown.","type":"object","properties":{"format":{"description":"Format string with embedded timezone blocks.\n\nUse `{{ tz('timezone', 'strftime') }}` to insert a formatted time.\nAnything outside a placeholder stays as literal text.\n\n## Examples\n\n| Format string | Renders as |\n|---|---|\n| `\"{{ tz('UTC', '%H:%M %Z') }}\"` | `14:30 UTC` |\n| `\"NYC {{ tz('America/New_York', '%H:%M') }} TYO {{ tz('Asia/Tokyo', '%H:%M') }}\"` | `NYC 09:30 TYO 23:30` |\n| `\"{{ tz('America/New_York', '%H:%M %Z') }} \\| {{ tz('Europe/London', '%H:%M %Z') }}\"` | `09:30 EST \\| 14:30 GMT` |","$ref":"#/$defs/string","default":"{{ tz('UTC', '%H:%M %Z') }}"},"icon-name":{"description":"Symbolic icon name.","$ref":"#/$defs/string","default":"ld-globe-symbolic"},"border-show":{"description":"Display border around button.","$ref":"#/$defs/boolean","default":false},"border-color":{"description":"Border color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"icon-show":{"description":"Display module icon.","$ref":"#/$defs/boolean","default":true},"icon-color":{"description":"Icon foreground color. Auto selects based on variant for contrast.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-show":{"description":"Display text label.","$ref":"#/$defs/boolean","default":true},"label-color":{"description":"Label text color token.","$ref":"#/$defs/ColorValue","default":"yellow"},"label-max-length":{"description":"Max label characters before truncation with ellipsis. Set to 0 to disable.","$ref":"#/$defs/uint32","default":0},"button-bg-color":{"description":"Button background color token.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"left-click":{"description":"Action on left click.","$ref":"#/$defs/ClickAction","default":""},"right-click":{"description":"Action on right click.","$ref":"#/$defs/ClickAction","default":""},"middle-click":{"description":"Action on middle click.","$ref":"#/$defs/ClickAction","default":""},"scroll-up":{"description":"Action on scroll up.","$ref":"#/$defs/ClickAction","default":""},"scroll-down":{"description":"Action on scroll down.","$ref":"#/$defs/ClickAction","default":""}}},"Array_of_CustomModuleDefinition":{"type":"array","items":{"$ref":"#/$defs/CustomModuleDefinition"}},"CustomModuleDefinition":{"description":"User-defined module that runs a shell command and renders the output in the bar.\n\nFull walkthrough with examples at .","type":"object","properties":{"id":{"description":"Unique identifier for this module.\n\nReferenced in bar layouts as `custom-`. Must be unique across\nall custom module definitions.\n\n## Example\n\n```toml\n[[modules.custom]]\nid = \"gpu-temp\"\n\n# Reference in layout:\n# layout = [\"custom-gpu-temp\", \"clock\"]\n```","type":"string"},"command":{"description":"Shell command to execute.\n\nThe command runs via `sh -c` and should output to stdout.\nStderr is discarded. Commands have a 30-second timeout.\n\n## Output Parsing\n\n- If output starts with `{` or `[`: parsed as JSON\n- Otherwise: treated as plain text\n\n## Behavior by Mode\n\n- **poll**: Executed every `interval-ms` milliseconds\n- **watch**: Spawned once, each stdout line triggers a display update.\n Restarts are controlled by `restart-policy`.","type":["string","null"],"default":null},"mode":{"description":"Execution mode for the command.\n\n| Mode | Behavior |\n|------|----------|\n| `poll` | Run command every `interval-ms` (default) |\n| `watch` | Spawn long-running process, update on each stdout line |\n\nUse `poll` for commands that return current state and exit.\nUse `watch` for commands that stream updates (e.g., `pactl subscribe`).","$ref":"#/$defs/ExecutionMode","default":"poll"},"interval-ms":{"description":"Polling interval in milliseconds.\n\nOnly applies to `poll` mode. Ignored in `watch` mode.\n\nSet to `0` for manual polling mode: no timer is started. In manual\nmode, the command still runs once at startup.","type":"integer","format":"uint64","minimum":0,"default":5000},"restart-policy":{"description":"Restart policy for watch mode.\n\nOnly applies to `watch` mode. Ignored in `poll` mode.\n\n| Policy | Behavior |\n|--------|----------|\n| `never` | Do not restart after exit |\n| `on-exit` | Restart after any exit |\n| `on-failure` | Restart only after non-zero/signal exit |","$ref":"#/$defs/RestartPolicy","default":"never"},"restart-interval-ms":{"description":"Base restart delay in milliseconds for watch mode.\n\nOnly applies to `watch` mode. Ignored in `poll` mode.\n\nUsed when `restart-policy` is `on-exit` or `on-failure`.\nDelay increases exponentially on rapid failures, capped at 30 seconds.","$ref":"#/$defs/RestartDelay","default":1000},"format":{"description":"Format string for the label using Jinja2 template syntax.\n\n## Variables\n\n- `{{ output }}` - Raw command output\n- `{{ field }}` - JSON field access\n- `{{ nested.field }}` - Nested field access\n- `{{ items.0 }}` - Array index access\n\n## Filters\n\n- `{{ val | default('fallback') }}` - Fallback for missing values\n- `{{ \"%02d\" | format(val) }}` - Zero-padding\n- `{{ val | upper }}`, `| lower`, `| trim` - String transforms\n\n## Examples\n\n- `\"{{ output }}°C\"` - Plain text: \"72°C\"\n- `\"{{ percentage }}%\"` - JSON field: \"75%\"\n- `\"{{ data.temp }}°C\"` - Nested: \"22°C\"\n\nIf JSON output contains a `text` field, it overrides this format.","type":"string","default":"{{ output }}"},"tooltip-format":{"description":"Format string for the tooltip (hover text).\n\nSupports the same Jinja2 syntax as `format`. If not set, no tooltip is shown.\nIf JSON output contains a `tooltip` field, it overrides this format.\n\n## Example\n\n```toml\nformat = \"{{ percentage }}%\"\ntooltip-format = \"Volume: {{ percentage }}% on {{ device }}\"\n```","type":["string","null"],"default":null},"hide-if-empty":{"description":"Hide module when output is empty, \"0\", or \"false\".\n\nWhen enabled, the module (including its gap in the bar layout) is\ncompletely hidden if the output indicates an empty/disabled state.","type":"boolean","default":false},"icon-name":{"description":"Static symbolic icon name.\n\nUsed when `icon-names` and `icon-map` don't provide a match.\nShould be a symbolic icon name from the icon theme (e.g., `\"ld-gpu-symbolic\"`).\n\n## Example\n\n```toml\nicon-name = \"ld-temperature-symbolic\"\n```","type":"string","default":""},"icon-names":{"description":"Array of icon names indexed by percentage (0-100).\n\nRequires JSON output with a `percentage` field (0-100).\nThe array is divided evenly across the percentage range.\n\n## Resolution\n\nFor N icons, icon at index `floor(percentage * N / 101)` is selected:\n\n- 4 icons: 0-24% → [0], 25-49% → [1], 50-74% → [2], 75-100% → [3]\n- 5 icons: 0-19% → [0], 20-39% → [1], 40-59% → [2], 60-79% → [3], 80-100% → [4]\n\n## Example\n\n```toml\nicon-names = [\n \"battery-empty-symbolic\",\n \"battery-caution-symbolic\",\n \"battery-low-symbolic\",\n \"battery-good-symbolic\",\n \"battery-full-symbolic\"\n]\n```","type":["array","null"],"items":{"type":"string"},"default":null},"icon-map":{"description":"Map of icon names keyed by the `alt` field value.\n\nRequires JSON output with an `alt` field. The `alt` value is looked up\nin this map. Use `\"default\"` as a fallback key.\n\n**Priority**: `icon-map[alt]` takes precedence over `icon-names[percentage]`,\nallowing state-specific icons to override percentage-based icons.\n\n## Example\n\n```toml\n# Volume with muted state override\nicon-names = [\"vol-0\", \"vol-33\", \"vol-66\", \"vol-100\"]\nicon-map = { \"muted\" = \"audio-volume-muted-symbolic\" }\n\n# Output: {\"percentage\": 50, \"alt\": \"muted\"}\n# Result: Uses \"audio-volume-muted-symbolic\" (alt match beats percentage)\n\n# Output: {\"percentage\": 50}\n# Result: Uses \"vol-33\" (percentage-based, no alt)\n```","type":["object","null"],"additionalProperties":{"type":"string"},"default":null},"class-format":{"description":"Format string for dynamic CSS classes.\n\nSupports the same Jinja2 syntax as `format`. The formatted result is\nsplit on whitespace and each word is added as a CSS class.\n\nCombined with the `class` field from JSON output (if present).\n\n## Example\n\n```toml\nclass-format = \"volume-{{ alt }}\"\n# Output: {\"alt\": \"muted\"} → adds class \"volume-muted\"\n```","type":["string","null"],"default":null},"icon-show":{"description":"Display module icon.","type":"boolean","default":true},"icon-color":{"description":"Icon foreground color.","$ref":"#/$defs/ColorValue","default":"auto"},"icon-bg-color":{"description":"Icon container background color.","$ref":"#/$defs/ColorValue","default":"auto"},"label-show":{"description":"Display text label.","type":"boolean","default":true},"label-color":{"description":"Label text color.","$ref":"#/$defs/ColorValue","default":"auto"},"label-max-length":{"description":"Maximum label length in characters before truncation.\n\nWhen exceeded, label is truncated with ellipsis. Set to `0` to disable.","type":"integer","format":"uint32","minimum":0,"default":0},"button-bg-color":{"description":"Button background color.","$ref":"#/$defs/ColorValue","default":"bg-surface-elevated"},"border-show":{"description":"Display border around button.","type":"boolean","default":false},"border-color":{"description":"Border color.","$ref":"#/$defs/ColorValue","default":"auto"},"left-click":{"description":"Shell command executed on left click.\n\nIf `on-action` is set, it runs after this command completes.","type":"string","default":""},"right-click":{"description":"Shell command executed on right click.\n\nIf `on-action` is set, it runs after this command completes.","type":"string","default":""},"middle-click":{"description":"Shell command executed on middle click.\n\nIf `on-action` is set, it runs after this command completes.","type":"string","default":""},"scroll-up":{"description":"Shell command executed on scroll up.\n\nScroll events are debounced (50ms) to coalesce rapid scrolls.\nIf `on-action` is set, it runs after this command completes.","type":"string","default":""},"scroll-down":{"description":"Shell command executed on scroll down.\n\nScroll events are debounced (50ms) to coalesce rapid scrolls.\nIf `on-action` is set, it runs after this command completes.","type":"string","default":""},"on-action":{"description":"Shell command to run after any click/scroll action completes.\n\nExecutes after the action handler finishes, and its output updates\nthe display immediately. Useful for reflecting state changes without\nwaiting for the next poll interval.\n\n## Example\n\n```toml\n# Volume control with immediate feedback\nscroll-up = \"pactl set-sink-volume @DEFAULT_SINK@ +5%\"\nscroll-down = \"pactl set-sink-volume @DEFAULT_SINK@ -5%\"\non-action = '''\nvol=$(pactl get-sink-volume @DEFAULT_SINK@ | grep -oP '\\d+(?=%)' | head -1)\necho \"{\\\"percentage\\\": $vol}\"\n'''\n```","type":["string","null"],"default":null}},"required":["id"]},"ExecutionMode":{"description":"Execution mode for custom module commands.","oneOf":[{"description":"Run command at regular intervals defined by `interval-ms`.\n\nBest for commands that complete quickly and return current state\n(e.g., reading a file, querying system status).","type":"string","const":"poll"},{"description":"Spawn long-running process and update display on each stdout line.\n\nBest for event-driven updates without polling overhead\n(e.g., `pactl subscribe`, `inotifywait`, `tail -f`).\nConfigure `restart-policy` to control restarts after exit.","type":"string","const":"watch"}]},"RestartPolicy":{"description":"Restart behavior for watch-mode custom modules.","oneOf":[{"description":"Never restart after exit.","type":"string","const":"never"},{"description":"Restart after any exit code (success or failure).","type":"string","const":"on-exit"},{"description":"Restart only after non-zero exit codes or signal termination.","type":"string","const":"on-failure"}]},"RestartDelay":{"description":"Restart delay in milliseconds, clamped to >= 1.","type":"integer","format":"uint64","minimum":1},"OsdConfig":{"description":"On-screen display overlay for transient events like volume and brightness.","type":"object","properties":{"enabled":{"description":"Show OSD overlays for volume, brightness, and keyboard toggles.","$ref":"#/$defs/boolean","default":true},"position":{"description":"Screen anchor position.","$ref":"#/$defs/OsdPosition","default":"bottom"},"duration":{"description":"Auto-dismiss delay in milliseconds.","$ref":"#/$defs/uint32","default":2500},"monitor":{"description":"Target monitor: \"primary\" or a connector name like \"DP-1\".","$ref":"#/$defs/OsdMonitor","default":"primary"},"margin":{"description":"Margin from screen edges.","$ref":"#/$defs/Spacing","default":150.0},"border":{"description":"Show a border around the OSD.","$ref":"#/$defs/boolean","default":true}}},"OsdPosition":{"description":"Screen anchor for the OSD overlay.","oneOf":[{"description":"Top-left corner.","type":"string","const":"top-left"},{"description":"Top-center edge.","type":"string","const":"top"},{"description":"Top-right corner.","type":"string","const":"top-right"},{"description":"Right-center edge.","type":"string","const":"right"},{"description":"Bottom-right corner.","type":"string","const":"bottom-right"},{"description":"Bottom-center edge.","type":"string","const":"bottom"},{"description":"Bottom-left corner.","type":"string","const":"bottom-left"},{"description":"Left-center edge.","type":"string","const":"left"}]},"OsdMonitor":{"description":"\"primary\" or a monitor connector name (e.g. \"DP-1\")","type":"string","default":"primary"},"WallpaperConfig":{"description":"Wallpaper rendering, cycling, and per-monitor overrides.","type":"object","properties":{"engine-enabled":{"description":"Enable the awww wallpaper engine. Disable to use an external wallpaper\ntool while keeping color extraction and theming.","$ref":"#/$defs/boolean","default":true},"transition-type":{"description":"Transition animation type.","$ref":"#/$defs/TransitionType","default":"simple"},"transition-duration":{"description":"Transition animation duration in seconds.","$ref":"#/$defs/TransitionDuration","default":0.699999988079071},"transition-fps":{"description":"Transition animation frame rate.","$ref":"#/$defs/TransitionFps","default":60},"cycling-enabled":{"description":"Enable automatic wallpaper cycling.","$ref":"#/$defs/boolean","default":false},"cycling-directory":{"description":"Directory containing wallpaper images for cycling.","$ref":"#/$defs/string","default":""},"cycling-mode":{"description":"Wallpaper cycling order.","$ref":"#/$defs/CyclingMode","default":"sequential"},"cycling-interval-mins":{"description":"Time between wallpaper changes in minutes.","$ref":"#/$defs/CyclingInterval","default":15},"cycling-same-image":{"description":"Show the same cycling wallpaper on all monitors. Only affects shuffle\nmode since sequential already displays the same image.","$ref":"#/$defs/boolean","default":false},"monitors":{"description":"Per-monitor wallpaper and fit mode settings. Each entry targets a\nmonitor by connector name. See [`MonitorWallpaperConfig`] for the\navailable fields.\n\n## Example\n\n```toml\n[[wallpaper.monitors]]\nname = \"DP-1\"\nwallpaper = \"/home/me/pictures/wall-primary.png\"\nfit-mode = \"fill\"\n\n[[wallpaper.monitors]]\nname = \"HDMI-1\"\nwallpaper = \"/home/me/pictures/wall-secondary.png\"\nfit-mode = \"fit\"\n```","$ref":"#/$defs/Array_of_MonitorWallpaperConfig","default":[]}}},"TransitionType":{"description":"Transition animation type.","oneOf":[{"description":"Instant change with no animation.","type":"string","const":"none"},{"description":"Basic crossfade.","type":"string","const":"simple"},{"description":"Fade with bezier-controlled easing.","type":"string","const":"fade"},{"description":"Wipe from left edge to right.","type":"string","const":"left"},{"description":"Wipe from right edge to left.","type":"string","const":"right"},{"description":"Wipe from top edge to bottom.","type":"string","const":"top"},{"description":"Wipe from bottom edge to top.","type":"string","const":"bottom"},{"description":"Wipe at configurable angle.","type":"string","const":"wipe"},{"description":"Wavy wipe effect.","type":"string","const":"wave"},{"description":"Growing circle from a position.","type":"string","const":"grow"},{"description":"Growing circle from center.","type":"string","const":"center"},{"description":"Shrinking circle from edges inward.","type":"string","const":"outer"},{"description":"Growing circle from random position.","type":"string","const":"any"},{"description":"Randomly selects from all transition types.","type":"string","const":"random"}]},"TransitionDuration":{"description":"Transition duration in seconds, clamped to >= 0.","type":"number","format":"float","minimum":0.0},"TransitionFps":{"description":"Transition frame rate clamped to 1-360 fps.","type":"integer","format":"uint32","minimum":1,"maximum":360},"CyclingMode":{"description":"Wallpaper cycling order.","oneOf":[{"description":"Alphabetical order.","type":"string","const":"sequential"},{"description":"Random order.","type":"string","const":"shuffle"}]},"CyclingInterval":{"description":"Cycling interval in minutes, minimum 1.","type":"integer","format":"uint64","minimum":1},"Array_of_MonitorWallpaperConfig":{"type":"array","items":{"$ref":"#/$defs/MonitorWallpaperConfig"}},"MonitorWallpaperConfig":{"description":"Per-monitor wallpaper configuration.","type":"object","properties":{"name":{"description":"Monitor name (e.g., \"HDMI-1\", \"DP-1\").","type":"string"},"fit-mode":{"description":"Image scaling mode for this monitor.","$ref":"#/$defs/FitMode","default":"fill"},"wallpaper":{"description":"Wallpaper image path for this monitor.","type":"string","default":""}},"required":["name"]},"FitMode":{"description":"Image scaling mode.","oneOf":[{"description":"Scale to cover entire display, cropping excess.","type":"string","const":"fill"},{"description":"Scale to fit within display, letterboxing if needed.","type":"string","const":"fit"},{"description":"Display at original size, centered.","type":"string","const":"center"},{"description":"Stretch to exactly fill, ignoring aspect ratio.","type":"string","const":"stretch"}]}},"$id":"wayle-config-0.2.3"} \ No newline at end of file diff --git a/wayle/themes/schema.json b/wayle/themes/schema.json new file mode 100644 index 0000000..08e1f48 --- /dev/null +++ b/wayle/themes/schema.json @@ -0,0 +1 @@ +{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"Palette","description":"Ten-color palette for CSS generation.","type":"object","properties":{"bg":{"description":"Base background color (darkest).","type":"string"},"surface":{"description":"Card and sidebar background.","type":"string"},"elevated":{"description":"Raised element background.","type":"string"},"fg":{"description":"Primary text color.","type":"string"},"fg_muted":{"description":"Secondary text color.","type":"string"},"primary":{"description":"Accent color for interactive elements.","type":"string"},"red":{"description":"Red palette color.","type":"string"},"yellow":{"description":"Yellow palette color.","type":"string"},"green":{"description":"Green palette color.","type":"string"},"blue":{"description":"Blue palette color.","type":"string"}},"required":["bg","surface","elevated","fg","fg_muted","primary","red","yellow","green","blue"],"$id":"wayle-theme-0.2.3"} \ No newline at end of file diff --git a/wayle/tombi.toml b/wayle/tombi.toml new file mode 100644 index 0000000..d16c7c0 --- /dev/null +++ b/wayle/tombi.toml @@ -0,0 +1,10 @@ +[schema] +enabled = true + +[[schemas]] +path = "./schema.json" +include = ["config.toml", "runtime.toml"] + +[[schemas]] +path = "./themes/schema.json" +include = ["themes/*.toml"]