diff --git a/CHANGELOG.md b/CHANGELOG.md index 5025e539a3..129023f8a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## Unreleased ### Fixed +- Core: app launchers no longer show a false error when an unrelated `DEBUG` variable contains a non-boolean value such as `release` +- Desktop: the generated battery notification startup command now launches `batterynotify.lua` instead of the removed shell implementation +- Hyprland: Lua keybinds again match the documented shortcuts for window management, screenshots, wallpapers, Waybar, selectors, workspaces and the scratchpad +- Screenshot: area capture now uses the fixed upstream Grimblast selector instead of prompting for the region twice +- Screenshot: Satty defaults to the compatible GTK GL renderer when no explicit `GSK_RENDERER` is configured +- Screenshot: the "print all monitors" keybind now invokes a full-output capture instead of capturing only the focused monitor - Waybar `hyprland/workspaces` module adapted to use lua dispatchers - Hyprland: `Super + Ctrl + arrows` no longer changes the group and the workspace at the same time. - Group navigation stays on `Super + Alt + arrows` + Group navigation uses `Super + Ctrl + H/L` - Hyprland: the right Control key no longer hides Waybar on its own. Hiding moved to `Super + Ctrl + B` - Hyprland: workspaces 11-20 on the numpad respond again - OCR: the language list in the result notification is no longer split across arguments diff --git a/Configs/.local/lib/hyde/app.sh b/Configs/.local/lib/hyde/app.sh index f26ebf956a..3f3c1d5bf2 100755 --- a/Configs/.local/lib/hyde/app.sh +++ b/Configs/.local/lib/hyde/app.sh @@ -5,6 +5,14 @@ # @cmd: service # @cmd.desc: Run a script as a systemd service +# app2unit and xdg-terminal-exec fall back to the generic DEBUG variable, +# which may contain non-boolean build modes such as "release". +# Give both helpers an explicit, scoped default while preserving any +# user-provided values on both execution paths. +APP2UNIT_DEBUG=${APP2UNIT_DEBUG:-0} +XTE_DEBUG=${XTE_DEBUG:-0} +export APP2UNIT_DEBUG XTE_DEBUG + if [ -d "/run/systemd/system" ]; then exec app2unit "$@" fi diff --git a/Configs/.local/lib/hyde/screenshot.sh b/Configs/.local/lib/hyde/screenshot.sh index ce6c01533d..9148f2d437 100755 --- a/Configs/.local/lib/hyde/screenshot.sh +++ b/Configs/.local/lib/hyde/screenshot.sh @@ -90,6 +90,14 @@ fi [[ -n ${SCREENSHOT_ANNOTATION_ARGS[*]} ]] && annotation_args+=("${SCREENSHOT_ANNOTATION_ARGS[@]}") +run_annotation_tool() { + if [[ $annotation_tool == "satty" ]]; then + GSK_RENDERER="${GSK_RENDERER:-gl}" "$annotation_tool" "${annotation_args[@]}" + else + "$annotation_tool" "${annotation_args[@]}" + fi +} + take_screenshot() { local mode=$1 shift @@ -102,7 +110,7 @@ take_screenshot() { print_log -g "Executing screenshot command: ${command[*]}" if eval "${command[*]}"; then [[ ${SCREENSHOT_ANNOTATION_ENABLED} == false ]] && return 0 - if ! "$annotation_tool" "${annotation_args[@]}"; then + if ! run_annotation_tool; then send_notifs -r 9 -a "HyDE Alert" "Screenshot Error" "Failed to open annotation tool" return 1 fi diff --git a/Configs/.local/share/hyde/schema/config.md b/Configs/.local/share/hyde/schema/config.md index 1aa1a23fdf..fa381f9632 100644 --- a/Configs/.local/share/hyde/schema/config.md +++ b/Configs/.local/share/hyde/schema/config.md @@ -8,7 +8,7 @@ Users are encouraged to use an editor that support schema validation to ensure t --- ### [battery.notify] -batterynotify.sh configuration. +Battery notification configuration. | Key | Description | Default | | --- | ----------- | ------- | @@ -155,7 +155,7 @@ Generic desktop autostart configuration. Use this header instead of hyprland-sta | applet_removable_media | Removable media applet. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-removable-media-applet.service -t service -- udiskie --no-automount --smart-tray | | auth_dialogue | Authentication dialogue. | hyde-shell app -t service -- polkitkdeauth.sh | | bar | Bar. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-bar.scope -t scope -- waybar.py --watch | -| battery_notify | Battery notification script. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh | +| battery_notify | Battery notification script. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua | | blue_light_filter_daemon | Blue-light filter daemon. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-blue-light-filter.service -t service -- hyprsunset | | clipboard_persist | Clipboard persist daemon. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-clipboard-persist.service -t service wl-clip-persist --clipboard regular | | dbus_share_picker | DBus share picker (for XDG portal / XDPH). | dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP XDG_SESSION_TYPE XDG_SESSION_DESKTOP XDG_CONFIG_HOME QT_QPA_PLATFORMTHEME | diff --git a/Configs/.local/share/hyde/schema/config.toml b/Configs/.local/share/hyde/schema/config.toml index cf3743464e..37588cbebb 100644 --- a/Configs/.local/share/hyde/schema/config.toml +++ b/Configs/.local/share/hyde/schema/config.toml @@ -98,7 +98,7 @@ font = "JetBrainsMono Nerd Font" # Font for bookmarks. [wlogout] style = 2 # Style for wlogout. -# batterynotify.sh configuration. +# Battery notification configuration. [battery.notify] timer = 120 # Timer for battery notifications. notify = 1140 # Notification threshold. @@ -321,7 +321,7 @@ clipboard_persist = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-clipboard-persi wallpaper = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-wallpaper.service -t service -- wallpaper.sh --start --global" # Wallpaper script. bar = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-bar.scope -t scope -- waybar.py --watch" # Bar. notifications = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-notifications.service -t service -- dunst" # Notification daemon. -battery_notify = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh" # Battery notification script. +battery_notify = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua" # Battery notification script. applet_network_manager = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-network-manager-applet.service -t service -- nm-applet --indicator" # Network manager applet. applet_removable_media = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-removable-media-applet.service -t service -- udiskie --no-automount --smart-tray" # Removable media applet. applet_bluetooth = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-bluetooth-applet.service -t service -- blueman-applet" # Bluetooth applet. diff --git a/Configs/.local/share/hyde/schema/config.toml.json b/Configs/.local/share/hyde/schema/config.toml.json index ace7cb5899..73701fb369 100644 --- a/Configs/.local/share/hyde/schema/config.toml.json +++ b/Configs/.local/share/hyde/schema/config.toml.json @@ -402,7 +402,7 @@ } }, "battery.notify": { - "description": "batterynotify.sh configuration.", + "description": "Battery notification configuration.", "type": "object", "properties": { "timer": { @@ -1345,7 +1345,7 @@ "type": "string" }, "battery_notify": { - "default": "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh", + "default": "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua", "description": "Battery notification script.", "type": "string" }, diff --git a/Configs/.local/share/hyde/schema/schema.toml b/Configs/.local/share/hyde/schema/schema.toml index 819c7d4cda..006af3ab8a 100644 --- a/Configs/.local/share/hyde/schema/schema.toml +++ b/Configs/.local/share/hyde/schema/schema.toml @@ -362,7 +362,7 @@ options = [1, 2] type = "integer" [properties."battery.notify"] -description = "batterynotify.sh configuration." +description = "Battery notification configuration." type = "object" [properties."battery.notify".properties.timer] @@ -1186,7 +1186,7 @@ description = "Notification daemon." type = "string" [properties."desktop.start".properties.battery_notify] -default = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh" +default = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua" description = "Battery notification script." type = "string" diff --git a/Configs/.local/share/hypr/lua/key_binds.lua b/Configs/.local/share/hypr/lua/key_binds.lua index 2503159f3d..f5eb8d2e24 100644 --- a/Configs/.local/share/hypr/lua/key_binds.lua +++ b/Configs/.local/share/hypr/lua/key_binds.lua @@ -50,7 +50,7 @@ end _F = {description = "[Launcher|Apps] terminal emulator"} hl.bind(MOD .. " + T", hl.dsp.exec_cmd(_apps.terminal), _F) _F = {description = "[Launcher|Apps] dropdown terminal"} -hl.bind(MOD .. " + grave", hl.dsp.exec_cmd("hyde-shell pypr toggle console"), _F) +hl.bind(MOD .. " + ALT + T", hl.dsp.exec_cmd("hyde-shell pypr toggle console"), _F) _F = {description = "[Launcher|Apps] file explorer"} hl.bind(MOD .. " + E", hl.dsp.exec_cmd(_apps.explorer), _F) _F = {description = "[Launcher|Apps] browser"} @@ -63,10 +63,12 @@ hl.bind("CTRL + SHIFT + ESCAPE", hl.dsp.exec_cmd("hyde-shell system.monitor.sh") local _wm = "Window Management" _F = {description = "[Window Management] close focused window"} hl.bind(MOD .. " + Q", hl.dsp.window.close(), _F) +_F = {description = "[Window Management] close focused window"} +hl.bind("ALT + F4", hl.dsp.window.close(), _F) _F = {description = "[Window Management] kill focused window"} hl.bind(MOD .. "+ ALT + F4", hl.dsp.window.kill(), _F) _F = {description = "[Window Management] exit hyprland session"} -hl.bind("CTRL + Delete", hl.dsp.exit(), _F) +hl.bind(MOD .. " + Delete", hl.dsp.exit(), _F) _F = {description = "[Window Management] toggle float true"} hl.bind(MOD .. " + W", hl.dsp.window.float({action = "toggle"}), _F) _F = {description = "[Window Management] toggle group"} @@ -76,9 +78,9 @@ hl.bind("ALT + P", hl.dsp.window.pseudo(), _F) -- bindd = $mainMod, G, $d toggle group,exec, hydectl tabs _F = {description = "[Window Management] cycle fullscreen"} -hl.bind(MOD .. " + F11", cycle_fullscreen, _F) +hl.bind("SHIFT + F11", cycle_fullscreen, _F) _F = {description = "[Window Management] toggle pin"} -hl.bind(MOD .. " + F", hl.dsp.exec_cmd(hyde.sh.window.pin()), _F) +hl.bind(MOD .. " + SHIFT + F", hl.dsp.exec_cmd(hyde.sh.window.pin()), _F) _F = {description = "[Window Management] logout menu"} hl.bind("CTRL + ALT + DELETE", hl.dsp.exec_cmd(hyde.sh.session.logout.launcher()), _F) -- ALT_R is a keysym, not a modifier: "ALT_R + CONTROL_R" resolves to a bare @@ -88,12 +90,10 @@ hl.bind(MOD .. " + CTRL + B", hl.dsp.exec_cmd(hyde.sh.waybar("--hide")), _F) _F = {description = "[Window Management] lock session"} hl.bind(MOD .. " + L", hl.dsp.exec_cmd(hyde.sh.session.lock()), _F) --- Group navigation lives on ALT only. The CTRL variant collided with relative --- workspace navigation further down, which binds the same combo. _F = {description = "[Window Management|Group Navigation] change active group backwards"} -hl.bind(MOD .. " + ALT + Left", hl.dsp.group.prev(), _F) +hl.bind(MOD .. " + CTRL + H", hl.dsp.group.prev(), _F) _F = {description = "[Window Management|Group Navigation] change active group forwards"} -hl.bind(MOD .. " + ALT + Right", hl.dsp.group.next(), _F) +hl.bind(MOD .. " + CTRL + L", hl.dsp.group.next(), _F) -- $d=[$wm|Change focus] @@ -122,15 +122,15 @@ hl.bind("ALT + ALT_L", hl.dsp.exec_cmd(hyde.sh.altab("--apply")), _F) -- # Resize kwindows _F = {description = "[Window Management|Resize Active Window] resize window right", repeating = true} -hl.bind(MOD .. " + EQUAL", hl.dsp.window.resize({x = 30, y = 0, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + RIGHT", hl.dsp.window.resize({x = 30, y = 0, relative = true}), _F) _F = {description = "[Window Management|Resize Active Window] resize window left", repeating = true} -hl.bind(MOD .. " + MINUS", hl.dsp.window.resize({x = -30, y = 0, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + LEFT", hl.dsp.window.resize({x = -30, y = 0, relative = true}), _F) _F = {description = "[Window Management|Resize Active Window] resize window up", repeating = true} -hl.bind(MOD .. " + SHIFT + EQUAL", hl.dsp.window.resize({x = 0, y = -30, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + UP", hl.dsp.window.resize({x = 0, y = -30, relative = true}), _F) _F = {description = "[Window Management|Resize Active Window] resize window down", repeating = true} -hl.bind(MOD .. " + SHIFT + MINUS", hl.dsp.window.resize({x = 0, y = 30, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + DOWN", hl.dsp.window.resize({x = 0, y = 30, relative = true}), _F) -- TEXT = hl.get_active_window().floating @@ -158,7 +158,7 @@ hl.bind(MOD .. " + X", hl.dsp.window.resize(), _F) -- $d=[$wm] _F = {description = "[Layout Management|Dwindle] toggle split"} -_F = {description = "[Layout Management|Scrolling] toggle fit"} +hl.bind(MOD .. " + J", hl.dsp.layout("togglesplit"), _F) _F = {description = "[Launcher|Rofi menus] application finder"} hl.bind(MOD .. " + A", hl.dsp.exec_cmd(hyde.sh.menu.apps()), _F) @@ -190,6 +190,12 @@ hl.bind(MOD .. " + SHIFT + slash", hl.dsp.exec_cmd(hyde.sh.menu.search()), _F) -- # binddel = , F11, $d decrease volume , exec, hyde-shell volumecontrol.sh -o d # decrease volume -- # binddel = , F12, $d increase volume , exec, hyde-shell volumecontrol.sh -o i # increase volume +_F = {description = "[Hardware Controls|Audio] un/mute output", locked = true} +hl.bind("F10", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "m")), _F) +_F = {description = "[Hardware Controls|Audio] decrease volume", locked = true, repeating = true} +hl.bind("F11", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "d")), _F) +_F = {description = "[Hardware Controls|Audio] increase volume", locked = true, repeating = true} +hl.bind("F12", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "i")), _F) _F = {description = "[Hardware Controls|Audio] un/mmute output", locked = true} hl.bind("XF86AudioMute", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "m")), _F) _F = {description = "[Hardware Controls|Audio] un/mute microphone", locked = true} @@ -219,26 +225,30 @@ _F = {description = "[Utilities] toggle keyboard layout", locked = true} hl.bind(MOD .. " + K", hl.dsp.exec_cmd(hyde.sh.kb.switch()), _F) _F = {description = "[Utilities] game mode", locked = true} hl.bind(MOD .. " + ALT + G", hl.dsp.exec_cmd(hyde.sh.gamemode()), _F) -- TODO +_F = {description = "[Utilities] game launcher"} +hl.bind(MOD .. " + SHIFT + G", hl.dsp.exec_cmd("hyde-shell gamelauncher"), _F) _F = {description = "[Utilities] screen capture] color picker", locked = true} hl.bind(MOD .. " + SHIFT + P", hl.dsp.exec_cmd("hyprpicker -an"), _F) _F = {description = "[Utilities] partial screenshot capture", locked = true} -hl.bind(MOD .. " + S", hl.dsp.exec_cmd(hyde.sh.screenshot.snip()), _F) +hl.bind(MOD .. " + P", hl.dsp.exec_cmd(hyde.sh.screenshot.snip()), _F) _F = {description = "[Utilities] freeze and snip screen", locked = true} -hl.bind(MOD .. " + SHIFT + S", hl.dsp.exec_cmd(hyde.sh.screenshot.freeze()), _F) +hl.bind(MOD .. " + CONTROL + P", hl.dsp.exec_cmd(hyde.sh.screenshot.freeze()), _F) _F = {description = "[Utilities] print monitor", locked = true} -hl.bind(MOD .. " + ALT + S", hl.dsp.exec_cmd(hyde.sh.screenshot.monitor()), _F) +hl.bind(MOD .. " + ALT + P", hl.dsp.exec_cmd(hyde.sh.screenshot.monitor()), _F) _F = {description = "[Utilities] print all monitors", locked = true} -hl.bind(MOD .. " + CONTROL + A", hl.dsp.exec_cmd(hyde.sh.screenshot.monitor()), _F) +hl.bind("Print", hl.dsp.exec_cmd(hyde.sh.screenshot.full()), _F) _F = {description = "[Utilities] OCR scanner", locked = true} hl.bind(MOD .. " + CONTROL + S", hl.dsp.exec_cmd(hyde.sh.screenshot.ocr()), _F) --- _F = { description = "[Theming and Wallpaper] next global wallpaper"} --- hl.bind(MOD .. "+ ALT + Right", hl.dsp.exec_cmd(hyde.sh.wallpaper("--next")), _F) --- _F = { description = "[Theming and Wallpaper] previous global wallpaper"} --- hl.bind(MOD .. "+ ALT + Left", hl.dsp.exec_cmd(hyde.sh.wallpaper("--prev")), _F) --- _F = { description = "[Theming and Wallpaper] next waybar layout"} --- hl.bind(MOD .. "+ CONTROL + ALT + Right", hl.dsp.exec_cmd(hyde.sh.waybar("--next")), _F) +_F = {description = "[Theming and Wallpaper] next global wallpaper"} +hl.bind(MOD .. "+ ALT + Right", hl.dsp.exec_cmd(hyde.sh.wallpaper("--next")), _F) +_F = {description = "[Theming and Wallpaper] previous global wallpaper"} +hl.bind(MOD .. "+ ALT + Left", hl.dsp.exec_cmd(hyde.sh.wallpaper("--prev")), _F) +_F = {description = "[Theming and Wallpaper] next Waybar layout"} +hl.bind(MOD .. "+ ALT + Up", hl.dsp.exec_cmd("hyde-shell waybar --next"), _F) +_F = {description = "[Theming and Wallpaper] previous Waybar layout"} +hl.bind(MOD .. "+ ALT + Down", hl.dsp.exec_cmd("hyde-shell waybar --prev"), _F) _F = {description = "[Theming and Wallpaper] select a global wallpaper"} hl.bind(MOD .. "+ SHIFT + W", hl.dsp.exec_cmd(hyde.sh.menu.wallpapers()), _F) @@ -246,6 +256,10 @@ _F = {description = "[Theming and Wallpaper] wallbash mode selector"} hl.bind(MOD .. "+ SHIFT + R", hl.dsp.exec_cmd(hyde.sh.menu.wallbash()), _F) _F = {description = "[Theming and Wallpaper] select a theme"} hl.bind(MOD .. "+ SHIFT + T", hl.dsp.exec_cmd(hyde.sh.menu.themes()), _F) +_F = {description = "[Theming and Wallpaper] select animations"} +hl.bind(MOD .. "+ SHIFT + Y", hl.dsp.exec_cmd("hyde-shell animations --select"), _F) +_F = {description = "[Theming and Wallpaper] select Hyprlock layout"} +hl.bind(MOD .. "+ SHIFT + U", hl.dsp.exec_cmd("hyde-shell hyprlock --select"), _F) -- # TODO Make a main rofi menu for these selectors -- $rice=Theming and Wallpaper @@ -320,15 +334,17 @@ _F = { hl.bind(MOD .. " + CONTROL + ALT + LEFT", hl.dsp.window.move({workspace = "r-1"}), _F) _F = {description = "[Workspaces|Navigation|Mouse] next workspace"} -hl.bind(MOD .. " + SHIFT + mouse_down", hl.dsp.focus({workspace = "r+1"}), _F) +hl.bind(MOD .. " + mouse_down", hl.dsp.focus({workspace = "e+1"}), _F) _F = {description = "[Workspaces|Navigation|Mouse] previous workspace"} -hl.bind(MOD .. " + SHIFT + mouse_up", hl.dsp.focus({workspace = "r-1"}), _F) +hl.bind(MOD .. " + mouse_up", hl.dsp.focus({workspace = "e-1"}), _F) -- # Move/Switch to special workspace (scratchpad) --- $d=[$ws|Navigation|Special workspace] --- # bindd = $mainMod, grave, $d toggle scratchpad , togglespecialworkspace --- # bindd = $mainMod SHIFT, grave, $d move to scratchpad , movetoworkspace, special --- # bindd = $mainMod Alt, grave, $d move to scratchpad (silent) , movetoworkspacesilent, special +_F = {description = "[Workspaces|Navigation|Special workspace] toggle scratchpad"} +hl.bind(MOD .. " + S", hl.dsp.workspace.toggle_special(), _F) +_F = {description = "[Workspaces|Navigation|Special workspace] move focused window to scratchpad"} +hl.bind(MOD .. " + SHIFT + S", hl.dsp.window.move({workspace = "special"}), _F) +_F = {description = "[Workspaces|Navigation|Special workspace] move focused window silently to scratchpad"} +hl.bind(MOD .. " + ALT + S", hl.dsp.window.move({workspace = "special", follow = false}), _F) --- Move silent --- diff --git a/KEYBINDINGS.md b/KEYBINDINGS.md index f41e7db24a..dd09fec158 100644 --- a/KEYBINDINGS.md +++ b/KEYBINDINGS.md @@ -52,7 +52,7 @@ Multi-language KEYBINDINGS support Here are all HyDE specific keybindings listed. -> [!TIP] +> [!TIP] > Super + / shows the keybindings. @@ -61,7 +61,7 @@ Here are all HyDE specific keybindings listed. | Keys | Action | | :--------------------------------------------------- | :------------------------------ | -| CTRL + Q | close focused window | +| SUPER + Q | close focused window | | ALT + F4 | close focused window | | SUPER + Delete | kill hyprland session | | SUPER + W | toggle float | @@ -70,7 +70,7 @@ Here are all HyDE specific keybindings listed. | SUPER + L | lock screen | | SUPER + SHIFT + F | toggle pin on focused window | | ALT + CTRL + Delete | logout menu | -| ALT + Control_R | toggle waybar and reload config | +| SUPER + CTRL + B | toggle waybar and reload config | | SUPER + J | toggle split | ### Group Navigation @@ -301,7 +301,7 @@ For example, to create a keybinding that launches the **HyDE Game Launcher**, ad bind = $mainMod, SPACE, exec, $HOME/.local/lib/hyde/gamelauncher.sh ``` -This will bind the **Game Launcher** to SUPER + Space. +This will bind the **Game Launcher** to SUPER + Space. You can replace `SPACE` with any other key you prefer. The `gamelauncher.sh` script is included by default and lives at: diff --git a/Scripts/dots/hyde.toml b/Scripts/dots/hyde.toml index c66edfcdde..33db2c2bb0 100644 --- a/Scripts/dots/hyde.toml +++ b/Scripts/dots/hyde.toml @@ -95,8 +95,7 @@ target_root = "${HOME}/.local/bin" paths = ["hyde-shell", "hydectl"] [grimblast] -# source = "blob+https://raw.githubusercontent.com/hyprwm/contrib/refs/heads/main/grimblast/grimblast" -source = "blob+https://raw.githubusercontent.com/zspher/contrib/refs/heads/feature-grimblast-toplevel-handle/grimblast/grimblast" +source = "blob+https://raw.githubusercontent.com/hyprwm/contrib/refs/heads/main/grimblast/grimblast" action = "sync" target_root = "${HOME}/.local/lib/hyde/screenshot" paths = "grimblast" diff --git a/tests/README.md b/tests/README.md index 6be9f57cb6..c0a1f5f803 100644 --- a/tests/README.md +++ b/tests/README.md @@ -19,10 +19,13 @@ is adding a file. | Case | Checks | | --- | --- | +| `test_app_wrapper.sh` | Launching through either `app.sh` execution path does not leak an unrelated non-boolean `DEBUG` value into app2unit or xdg-terminal-exec | | `test_binds.sh` | Loads the Lua keybinds against a stubbed Hyprland API: no two binds share a combination once modifiers are folded to what Hyprland matches on, no keysym sits in a modifier position, no bind uses the `code:NN` form the Lua parser rejects, every bind has a description, every `hyde-shell` command it runs exists. Touchpad gestures are checked in the same pass: a valid finger count, a direction and action Hyprland accepts, and no two gestures on the same finger count and direction | | `test_git.sh` | The tree holds no gitlink without a matching `.gitmodules` entry, which would break `git submodule` and anything walking submodules | -| `test_dots.sh` | Every installer metafile under `Scripts/dots` parses, declares the keys the installer needs, uses a known action, and points at a source directory that exists | +| `test_dots.sh` | Every installer metafile under `Scripts/dots` parses, declares the keys the installer needs, uses a known action, and points at a source directory that exists. It also keeps Grimblast on the fixed official source | | `test_lua_syntax.sh` | Every shipped Lua file parses | +| `test_schema.sh` | Generated schema artifacts use the current Lua battery notification daemon rather than the removed shell implementation | +| `test_screenshot_wrapper.sh` | Satty receives a compatible default GTK renderer while preserving explicit renderer overrides | | `test_shell.sh` | Every shipped shell script parses, and shellcheck finds no error-severity problem | ## Dependencies diff --git a/tests/lua/bind_harness.lua b/tests/lua/bind_harness.lua index f2bd48837a..671aec362c 100644 --- a/tests/lua/bind_harness.lua +++ b/tests/lua/bind_harness.lua @@ -203,6 +203,7 @@ local function check(condition, message) end local seen = {} +local by_combo = {} for _, bind in ipairs(binds) do local id = canonical(bind.combo) local previous = seen[id] @@ -212,6 +213,7 @@ for _, bind in ipairs(binds) do string.format("combo %s is bound twice, as %q and %q", id, tostring(previous), bind.combo) ) seen[id] = bind.combo + by_combo[id] = bind local tokens = split(bind.combo) local key = table.remove(tokens) @@ -234,6 +236,70 @@ for _, bind in ipairs(binds) do ) end +-- The Lua migration must preserve the public keymap documented in +-- KEYBINDINGS.md. Structural checks alone cannot catch a valid bind moving to +-- an unexpected key or pointing at the wrong helper. +local required_defaults = { + "SUPER + SHIFT + G", + "SUPER + SHIFT + P", + "SUPER + CTRL + S", + "SUPER + SHIFT + W", + "SUPER + SHIFT + R", + "SUPER + SHIFT + T", + "SUPER + ALT + T", + "ALT + F4", + "SUPER + DELETE", + "SHIFT + F11", + "SUPER + SHIFT + F", + "SUPER + CTRL + H", + "SUPER + CTRL + L", + "SUPER + SHIFT + RIGHT", + "SUPER + SHIFT + LEFT", + "SUPER + SHIFT + UP", + "SUPER + SHIFT + DOWN", + "SUPER + J", + "F10", + "F11", + "F12", + "SUPER + ALT + RIGHT", + "SUPER + ALT + LEFT", + "SUPER + ALT + UP", + "SUPER + ALT + DOWN", + "SUPER + SHIFT + Y", + "SUPER + SHIFT + U", + "SUPER + mouse_down", + "SUPER + mouse_up", + "SUPER + S", + "SUPER + SHIFT + S", + "SUPER + ALT + S" +} + +for _, combo in ipairs(required_defaults) do + check(by_combo[canonical(combo)] ~= nil, string.format("documented combo %s is missing", combo)) +end + +local screenshot_commands = { + ["SUPER + CTRL + S"] = "hyde-shell screenshot sc", + ["SUPER + P"] = "hyde-shell screenshot s", + ["SUPER + CTRL + P"] = "hyde-shell screenshot sf", + ["SUPER + ALT + P"] = "hyde-shell screenshot m", + ["Print"] = "hyde-shell screenshot p" +} + +for combo, expected in pairs(screenshot_commands) do + local bind = by_combo[canonical(combo)] + check(bind ~= nil, string.format("documented screenshot combo %s is missing", combo)) + + if bind then + local args = type(bind.action) == "table" and bind.action.args or nil + local command = args and args[1] + check( + command == expected, + string.format("%s runs %q, expected %q", combo, tostring(command), expected) + ) + end +end + -- Every hyde-shell command reachable from a bind has to exist in the tree. for _, bind in ipairs(binds) do local args = type(bind.action) == "table" and bind.action.args or nil diff --git a/tests/test_app_wrapper.sh b/tests/test_app_wrapper.sh new file mode 100755 index 0000000000..ebac5f7138 --- /dev/null +++ b/tests/test_app_wrapper.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env sh +# The app wrapper must isolate app2unit and xdg-terminal-exec from unrelated +# DEBUG values on both its systemd and direct-exec paths. + +. "$(dirname -- "$0")/lib/common.sh" + +wrapper="$REPO_ROOT/Configs/.local/lib/hyde/app.sh" + +fixture=$(mktemp -d) +trap 'rm -rf "$fixture"' EXIT HUP INT TERM + +cat >"$fixture/app2unit" <<'EOF' +#!/usr/bin/env sh +printf 'APP2UNIT_DEBUG=%s\n' "${APP2UNIT_DEBUG-}" +printf 'XTE_DEBUG=%s\n' "${XTE_DEBUG-}" +while [ "$#" -gt 0 ] && [ "$1" != "--" ]; do + shift +done +[ "$#" -gt 0 ] && shift +exec "$@" +EOF + +cat >"$fixture/xdg-terminal-exec" <<'EOF' +#!/usr/bin/env sh +printf 'APP2UNIT_CONSUMER_DEBUG=%s\n' "${APP2UNIT_DEBUG-${DEBUG-0}}" +printf 'XTE_CONSUMER_DEBUG=%s\n' "${XTE_DEBUG-${DEBUG-0}}" +EOF +chmod +x "$fixture/app2unit" "$fixture/xdg-terminal-exec" + +output=$( + unset APP2UNIT_DEBUG XTE_DEBUG + export DEBUG=release + PATH="$fixture:$PATH" "$wrapper" -- xdg-terminal-exec 2>&1 +) +status=$? + +if [ "$status" -ne 0 ]; then + fail "app wrapper exited with $status" +fi + +printf '%s\n' "$output" | grep -qx 'APP2UNIT_CONSUMER_DEBUG=0' || + fail "app wrapper leaked DEBUG through APP2UNIT_DEBUG" +printf '%s\n' "$output" | grep -qx 'XTE_CONSUMER_DEBUG=0' || + fail "app wrapper leaked DEBUG into xdg-terminal-exec" + +if [ -d /run/systemd/system ]; then + printf '%s\n' "$output" | grep -qx 'APP2UNIT_DEBUG=0' || + fail "app wrapper did not default APP2UNIT_DEBUG to 0" + printf '%s\n' "$output" | grep -qx 'XTE_DEBUG=0' || + fail "app wrapper did not default XTE_DEBUG to 0" +fi + +export_line=$(grep -n '^export APP2UNIT_DEBUG XTE_DEBUG$' "$wrapper" | cut -d: -f1) +systemd_line=$(grep -n '^if \[ -d "/run/systemd/system" \]; then$' "$wrapper" | cut -d: -f1) + +if [ -z "$export_line" ] || [ -z "$systemd_line" ] || [ "$export_line" -ge "$systemd_line" ]; then + fail "scoped debug defaults are not exported before the execution-path branch" +fi + +override_output=$( + export DEBUG=release + export APP2UNIT_DEBUG=1 + export XTE_DEBUG=yes + PATH="$fixture:$PATH" "$wrapper" -- xdg-terminal-exec 2>&1 +) +override_status=$? + +if [ "$override_status" -ne 0 ]; then + fail "app wrapper with explicit debug values exited with $override_status" +fi + +printf '%s\n' "$override_output" | grep -qx 'APP2UNIT_CONSUMER_DEBUG=1' || + fail "app wrapper did not preserve APP2UNIT_DEBUG" +printf '%s\n' "$override_output" | grep -qx 'XTE_CONSUMER_DEBUG=yes' || + fail "app wrapper did not preserve XTE_DEBUG" + +finish diff --git a/tests/test_dots.sh b/tests/test_dots.sh index 980934ab38..60afbee5b5 100755 --- a/tests/test_dots.sh +++ b/tests/test_dots.sh @@ -10,4 +10,14 @@ fi python3 "$TESTS_DIR/python/check_dots.py" || fail "check_dots reported defects" +hyde_metafile="$REPO_ROOT/Scripts/dots/hyde.toml" +official_grimblast='source = "blob+https://raw.githubusercontent.com/hyprwm/contrib/refs/heads/main/grimblast/grimblast"' + +grep -Fqx "$official_grimblast" "$hyde_metafile" || + fail "grimblast is not sourced from the fixed upstream main branch" + +if grep -q 'feature-grimblast-toplevel-handle' "$hyde_metafile"; then + fail "grimblast still uses the double-selection experimental branch" +fi + finish diff --git a/tests/test_schema.sh b/tests/test_schema.sh new file mode 100755 index 0000000000..2164d640cc --- /dev/null +++ b/tests/test_schema.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh +# Generated schema artifacts must not restore commands removed by migrations. + +. "$(dirname -- "$0")/lib/common.sh" + +schema_dir="$REPO_ROOT/Configs/.local/share/hyde/schema" +artifacts=" +schema.toml +config.toml +config.toml.json +config.md +" + +for artifact in $artifacts; do + path="$schema_dir/$artifact" + + if grep -q 'batterynotify\.sh' "$path"; then + fail "$artifact still references the removed batterynotify.sh" + fi + + if ! grep -q 'batterynotify\.lua' "$path"; then + fail "$artifact does not reference batterynotify.lua" + fi +done + +finish diff --git a/tests/test_screenshot_wrapper.sh b/tests/test_screenshot_wrapper.sh new file mode 100755 index 0000000000..a607b03d4a --- /dev/null +++ b/tests/test_screenshot_wrapper.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# Satty needs a compatible GTK renderer when launched from Hyprland's +# environment, but explicit user choices must still win. + +# shellcheck source=tests/lib/common.sh +. "$(dirname -- "$0")/lib/common.sh" + +wrapper="$REPO_ROOT/Configs/.local/lib/hyde/screenshot.sh" +fixture=$(mktemp -d) +trap 'rm -rf "$fixture"' EXIT HUP INT TERM + +mkdir -p "$fixture/bin" "$fixture/lib/hyde/screenshot" "$fixture/runtime" "$fixture/pictures" + +cat >"$fixture/bin/hyde-shell" </dev/null 2>&1; } +print_log() { :; } +send_notifs() { :; } +INIT +fi +EOF + +cat >"$fixture/lib/hyde/screenshot/grimblast" <<'EOF' +#!/usr/bin/env sh +for target_file in "$@"; do :; done +: >"$target_file" +EOF + +cat >"$fixture/bin/satty" <<'EOF' +#!/usr/bin/env sh +printf 'GSK_RENDERER=%s\n' "${GSK_RENDERER-}" +EOF + +chmod +x "$fixture/bin/hyde-shell" "$fixture/bin/satty" "$fixture/lib/hyde/screenshot/grimblast" + +default_output=$(PATH="$fixture/bin:$PATH" "$wrapper" s --no-notify 2>&1) +default_status=$? + +if [ "$default_status" -ne 0 ]; then + fail "screenshot wrapper with default renderer exited with $default_status" +fi + +printf '%s\n' "$default_output" | grep -qx 'GSK_RENDERER=gl' || + fail "Satty did not receive the compatible GL renderer default" + +override_output=$(GSK_RENDERER=cairo PATH="$fixture/bin:$PATH" "$wrapper" s --no-notify 2>&1) +override_status=$? + +if [ "$override_status" -ne 0 ]; then + fail "screenshot wrapper with explicit renderer exited with $override_status" +fi + +printf '%s\n' "$override_output" | grep -qx 'GSK_RENDERER=cairo' || + fail "screenshot wrapper did not preserve the explicit renderer" + +finish