From 403f7aa6856539e5c232387d0dc904e465369418 Mon Sep 17 00:00:00 2001 From: lnb Date: Tue, 12 May 2026 12:04:28 +0530 Subject: [PATCH 01/14] fix: show escaped text for selected entry in clipboard --- dots/.config/quickshell/ii/modules/ii/overview/SearchItem.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/ii/overview/SearchItem.qml b/dots/.config/quickshell/ii/modules/ii/overview/SearchItem.qml index 6ca0f43b5..42649b9a3 100644 --- a/dots/.config/quickshell/ii/modules/ii/overview/SearchItem.qml +++ b/dots/.config/quickshell/ii/modules/ii/overview/SearchItem.qml @@ -226,7 +226,7 @@ RippleButton { color: root.colForeground horizontalAlignment: Text.AlignLeft elide: Text.ElideRight - text: root.selected ? root.itemName : root.displayContent + text: root.selected ? StringUtils.escapeHtml(root.itemName) : root.displayContent } } Loader { // Clipboard image preview From b85ed8691afb362721ea94757879b834c4156bae Mon Sep 17 00:00:00 2001 From: PetLucy Date: Tue, 12 May 2026 15:23:17 -0500 Subject: [PATCH 02/14] Fix monitor scale type Changes the default monitor scale value from `"1"` to `1`. This fixes the typo in the default monitor configuration. --- dots/.config/hypr/hyprland/general.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/hypr/hyprland/general.lua b/dots/.config/hypr/hyprland/general.lua index fab1e5d2b..b6764a8bb 100644 --- a/dots/.config/hypr/hyprland/general.lua +++ b/dots/.config/hypr/hyprland/general.lua @@ -3,7 +3,7 @@ hl.monitor({ output = "", mode = "preferred", position = "auto", - scale = "1" + scale = 1 }) hl.gesture({ From 215ac747d8541519d3ad09011b44f264b9fa7385 Mon Sep 17 00:00:00 2001 From: VietNguyenx <101798660+VietNguyenVN@users.noreply.github.com> Date: Fri, 15 May 2026 00:31:29 +0700 Subject: [PATCH 03/14] Update keybinds.lua --- dots/.config/hypr/hyprland/keybinds.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/dots/.config/hypr/hyprland/keybinds.lua b/dots/.config/hypr/hyprland/keybinds.lua index d6fec3485..28435e68a 100644 --- a/dots/.config/hypr/hyprland/keybinds.lua +++ b/dots/.config/hypr/hyprland/keybinds.lua @@ -3,9 +3,6 @@ require("hyprland.variables") if is_file_exists(HOME .. "/.config/hypr/custom/variables.lua") then require("custom.variables") end -if is_file_exists(HOME .. "/.config/hypr/custom/keybinds.lua") then - require("custom.keybinds") -end local qsScripts = "$HOME/.config/quickshell/$qsConfig/scripts" local hyprScripts = "$HOME/.config/hypr/hyprland/scripts" From c0706258b1ff22c70f6c0e51c4b812e63703f620 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 May 2026 23:27:26 +0200 Subject: [PATCH 04/14] add back some repetitive keybinds to cheatsheet --- dots/.config/hypr/hyprland/keybinds.lua | 182 +++++++++++------- .../ii/cheatsheet/CheatsheetKeybinds.qml | 7 + .../cheatsheet/CheatsheetKeybindsCategory.qml | 74 +++++-- 3 files changed, 173 insertions(+), 90 deletions(-) diff --git a/dots/.config/hypr/hyprland/keybinds.lua b/dots/.config/hypr/hyprland/keybinds.lua index 28435e68a..174127019 100644 --- a/dots/.config/hypr/hyprland/keybinds.lua +++ b/dots/.config/hypr/hyprland/keybinds.lua @@ -16,8 +16,10 @@ hl.bind("SUPER + SUPER_R", hl.dsp.exec_cmd(qsIsAlive .. " || pkill fuzzel || fuz hl.bind("SUPER_L", hl.dsp.global("quickshell:workspaceNumber"), { ignore_mods = true, transparent = true }) hl.bind("SUPER_R", hl.dsp.global("quickshell:workspaceNumber"), { ignore_mods = true, transparent = true }) -hl.bind("SUPER_L", hl.dsp.global("quickshell:workspaceNumber"), { ignore_mods = true, transparent = true, release = true }) -hl.bind("SUPER_R", hl.dsp.global("quickshell:workspaceNumber"), { ignore_mods = true, transparent = true, release = true }) +hl.bind("SUPER_L", hl.dsp.global("quickshell:workspaceNumber"), + { ignore_mods = true, transparent = true, release = true }) +hl.bind("SUPER_R", hl.dsp.global("quickshell:workspaceNumber"), + { ignore_mods = true, transparent = true, release = true }) hl.bind("SUPER + Tab", hl.dsp.global("quickshell:overviewWorkspacesToggle"), { description = "Shell: Toggle overview" }) hl.bind("SUPER + V", hl.dsp.global("quickshell:overviewClipboardToggle")) hl.bind("SUPER + Period", hl.dsp.global("quickshell:overviewEmojiToggle")) @@ -45,9 +47,9 @@ hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO { locked = true, repeating = true }) hl.bind("CTRL + SUPER + T", hl.dsp.global("quickshell:wallpaperSelectorToggle"), - { description = "Shell: Toggle wallpaper selector" }) + { description = "Shell: Change wallpaper" }) hl.bind("CTRL + SUPER + ALT + T", hl.dsp.global("quickshell:wallpaperSelectorRandom"), - { description = "Shell: Select random wallpaper" }) + { description = "Shell: Random wallpaper" }) hl.bind("CTRL + SUPER + SHIFT + D", hl.dsp.global("quickshell:toggleLightDark"), { description = "Shell: Toggle light/dark mode" }) hl.bind("CTRL + SUPER + T", hl.dsp.exec_cmd(qsIsAlive .. " || " .. qsScripts .. "/colors/switchwall.sh")) @@ -58,10 +60,10 @@ hl.bind("CTRL + SUPER + P", hl.dsp.global("quickshell:panelFamilyCycle"), { desc --##! Utilities --# Screenshot, Record, OCR, Color picker, Clipboard history hl.bind("SUPER + V", hl.dsp.exec_cmd( - qsIsAlive .. " || pkill fuzzel || cliphist list | fuzzel --match-mode fzf --dmenu | cliphist decode | wl-copy"), + qsIsAlive .. " || pkill fuzzel || cliphist list | fuzzel --match-mode fzf --dmenu | cliphist decode | wl-copy"), { description = "Utilities: Clipboard history >> clipboard" }) hl.bind("SUPER + Period", hl.dsp.exec_cmd( - qsIsAlive .. " || pkill fuzzel || " .. hyprScripts .. "/fuzzel-emoji.sh copy"), + qsIsAlive .. " || pkill fuzzel || " .. hyprScripts .. "/fuzzel-emoji.sh copy"), { description = "Utilities: Emoji >> clipboard" }) hl.bind("SUPER + SHIFT + S", hl.dsp.global("quickshell:regionScreenshot"), { description = "Utilities: Screen snip" }) hl.bind("SUPER + SHIFT + S", @@ -103,6 +105,47 @@ hl.bind("SUPER + SHIFT + ALT + mouse:273", hl.dsp.exec_cmd(hyprScripts .. "/ai/p { description = "Utilities: Generate AI summary for selected text" }) -- (requires a running ollama model) +--##! Screen +--# Zoom +local function zoomfunction(value) + local zoomvalue = hl.get_config("cursor:zoom_factor") + if (zoomvalue + value) > 3.0 then + hl.config({ cursor = { zoom_factor = 3.0 } }) + elseif (zoomvalue + value) < 1.0 then + hl.config({ cursor = { zoom_factor = 1.0 } }) + else + hl.config({ cursor = { zoom_factor = zoomvalue + value } }) + end +end +hl.bind("SUPER + Minus", function() zoomfunction(-0.3) end, { repeating = true, description = "Screen: Zoom out" }) +hl.bind("SUPER + Equal", function() zoomfunction(0.3) end, { repeating = true, description = "Screen: Zoom in" }) + +--# Zoom with keypad +hl.bind("SUPER + code:82", function() zoomfunction(-0.3) end, { repeating = true }) +hl.bind("SUPER + code:86", function() zoomfunction(0.3) end, { repeating = true }) + +--##! Media +local mediaNextCommand = +"playerctl next || playerctl position `bc <<< \"100 * $(playerctl metadata mpris:length) / 1000000 / 100\"`" +hl.bind("SUPER + SHIFT + N", hl.dsp.exec_cmd(mediaNextCommand), { locked = true, description = "Media: Next track" }) +hl.bind("XF86AudioNext", hl.dsp.exec_cmd(mediaNextCommand), { locked = true }) +hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true }) +hl.bind("SUPER + SHIFT + ALT + mouse:275", hl.dsp.exec_cmd("playerctl previous")) +hl.bind("SUPER + SHIFT + ALT + mouse:276", hl.dsp.exec_cmd(mediaNextCommand)) +hl.bind("SUPER + SHIFT + B", hl.dsp.exec_cmd("playerctl previous"), + { locked = true, description = "Media: Previous track" }) +hl.bind("SUPER + SHIFT + P", hl.dsp.exec_cmd("playerctl play-pause"), + { locked = true, description = "Media: Play/pause media" }) +hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SINK@ toggle"), { locked = true }) +hl.bind("SUPER + SHIFT + M", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SINK@ toggle"), + { locked = true, description = "Media: Toggle mute" }) +hl.bind("ALT + XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SOURCE@ toggle"), { locked = true }) +hl.bind("XF86AudioMicMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SOURCE@ toggle"), { locked = true }) +hl.bind("SUPER + ALT + M", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SOURCE@ toggle"), + { locked = true, description = "Media: Toggle mic" }) + --#! --##! Window --# Focusing @@ -110,21 +153,30 @@ hl.bind("SUPER + mouse:272", hl.dsp.window.drag(), { mouse = true, description = hl.bind("SUPER + mouse:274", hl.dsp.window.drag(), { mouse = true }) hl.bind("SUPER + mouse:273", hl.dsp.window.resize(), { mouse = true, description = "Window: Resize" }) --#/# bind = SUPER + ←/↑/→/↓,, -- Focus in direction -for i = 1, 6 do - local arrowkey = { "Left", "Right", "Up", "Down", "BracketLeft", "BracketRight" } - local focusdir = { "l", "r", "u", "d", "l", "r" } +for i = 1, 4 do + local arrowkey = { "Left", "Right", "Up", "Down" } + local focusdir = { "l", "r", "u", "d" } + hl.bind("SUPER + " .. arrowkey[i], hl.dsp.focus({ direction = focusdir[i] }), + { description = "Window: Focus " .. arrowkey[i] }) +end +for i = 1, 2 do + local arrowkey = { "BracketLeft", "BracketRight" } + local focusdir = { "l", "r" } hl.bind("SUPER + " .. arrowkey[i], hl.dsp.focus({ direction = focusdir[i] })) end --#/# bind = SUPER + SHIFT, ←/↑/→/↓,, -- Move in direction for i = 1, 4 do local arrowkey = { "Left", "Right", "Up", "Down" } local focusdir = { "l", "r", "u", "d" } - hl.bind("SUPER + SHIFT + " .. arrowkey[i], hl.dsp.window.move({ direction = focusdir[i] })) + hl.bind("SUPER + SHIFT + " .. arrowkey[i], hl.dsp.window.move({ direction = focusdir[i] }), + { description = "Window: Move " .. arrowkey[i] }) end hl.bind("ALT + F4", - function() hl.exec_cmd( - "notify-send \"Wrong close keybind\" \"Super+Q to close. Use Alt+F4 for Windows VMs\" -a Hyprland") end, + function() + hl.exec_cmd( + "notify-send \"Wrong close keybind\" \"Super+Q to close. Use Alt+F4 for Windows VMs\" -a Hyprland") + end, { non_consuming = true }) hl.bind("SUPER + Q", hl.dsp.window.close(), { description = "Window: Close" }) hl.bind("SUPER + SHIFT + ALT + Q", hl.dsp.exec_cmd("hyprctl kill"), { description = "Window: Forcefully zap a window" }) @@ -144,7 +196,12 @@ hl.bind("SUPER + ALT + F", hl.dsp.window.fullscreen_state({ internal = 0, client hl.bind("SUPER + P", hl.dsp.window.pin(), { description = "Window: Pin" }) --#/# bind = SUPER+ALT, Hash,, -- Send to workspace -- (1, 2, 3,...) ---# We use raw keycodes because some keyboard layouts register number keys as different chars. The codes can be verified with `wev` +for i = 1, 10 do + hl.bind("SUPER + ALT + " .. (i % 10), function() + hl.dispatch(hl.dsp.window.move({ workspace = workspace_in_group(i), follow = false })) + end, { description = "Window: Send to workspace " .. i }) +end +--# We also use raw keycodes because some keyboard layouts register number keys as different chars. The codes can be verified with `wev` for i = 1, 10 do local numberkey = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 } hl.bind("SUPER + ALT + code:" .. numberkey[i], function() @@ -163,27 +220,37 @@ end for i = 1, 4 do local key = { "SUPER + SHIFT + mouse_", "SUPER + ALT + mouse_" } local keycombos = { key[1] .. "down", key[1] .. "up", key[2] .. "down", key[2] .. "up" } - local prefix = { "r-", "r+", "-", "+" } + local prefix = { "r-", "r+", "r-", "r+" } hl.bind(keycombos[i], hl.dsp.window.move({ workspace = prefix[i] .. "1" })) end --#/# bind = SUPER+SHIFT, Page_↑/↓,, -- Send to workspace left/right -for i = 1, 6 do - local key = { "SUPER + ALT + Page_", "SUPER + SHIFT + Page_", "CTRL + SUPER + SHIFT + " } - local keycombos = { key[1] .. "down", key[1] .. "up", key[2] .. "down", key[2] .. "up", key[3] .. "Right", key[3] .. - "Left" } - local prefix = { "+", "-", "r+", "r-", "r+", "r-" } +for i = 1, 2 do + local keydirs = { "Up", "Down" } + local prefix = { "r-", "r+" } + local descdir = { "left", "right" } + hl.bind("SUPER + SHIFT + Page_" .. keydirs[i], hl.dsp.window.move({ workspace = prefix[i] .. "1" }), {description = "Window: Send to workspace " .. descdir[i]}) +end +for i = 1, 4 do + local key = { "SUPER + ALT + Page_", "CTRL + SUPER + SHIFT + " } + local keycombos = { key[1] .. "down", key[1] .. "up", key[2] .. "Right", key[2] .. "Left" } + local prefix = { "r+", "r-", "r+", "r-" } hl.bind(keycombos[i], hl.dsp.window.move({ workspace = prefix[i] .. "1" })) -- # [hidden] end hl.bind("SUPER + ALT + S", - hl.dsp.window.move({ workspace = "special:special", follow = false }), {description = "Window: Send to scratchpad"}) + hl.dsp.window.move({ workspace = "special:special", follow = false }), { description = "Window: Send to scratchpad" }) hl.bind("CTRL + SUPER + S", hl.dsp.workspace.toggle_special("special")) --##! Workspace --# Switching --#/# bind = SUPER, Hash,, -- Focus workspace -- (1, 2, 3,...) ---# We use raw keycodes because some keyboard layouts register number keys as different chars. The codes can be verified with `wev` +for i = 1, 10 do + hl.bind("SUPER + " .. (i % 10), function() + hl.dispatch(hl.dsp.focus({ workspace = workspace_in_group(i) })) + end, { description = "Workspace: Focus " .. i }) +end +--# We also use raw keycodes because some keyboard layouts register number keys as different chars. The codes can be verified with `wev` for i = 1, 10 do local numberkey = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 } hl.bind("SUPER + code:" .. numberkey[i], function() @@ -200,11 +267,16 @@ end --#/# bind = CTRL+SUPER, ←/→,, -- Focus left/right --#/# bind = CTRL+SUPER+ALT, ←/→,, -- # [hidden] Focus busy left/right -for i = 1, 4 do - local key = { "CTRL + SUPER + ", "CTRL + SUPER + ALT + " } - local keycombos = { key[1] .. "Right", key[1] .. "Left", key[2] .. "Right", key[2] .. "Left" } - local prefix = { "r+", "r-", "m+", "m-" } - hl.bind(keycombos[i], hl.dsp.focus({ workspace = prefix[i] .. "1" })) +for i = 1, 2 do + local keys = { "Left", "Right" } + local prefix = { "r-", "r+" } + local descdir = { "left", "right" } + hl.bind("CTRL + SUPER + " .. keys[i], hl.dsp.focus({ workspace = prefix[i] .. "1" }), {description = "Workspace: Focus " .. descdir[i]}) +end +for i = 1, 2 do + local keys = { "Left", "Right" } + local prefix = { "m-", "m+" } + hl.bind("CTRL + SUPER + ALT + " .. keys[i], hl.dsp.focus({ workspace = prefix[i] .. "1" })) end --#/# bind = SUPER, Page_↑/↓,, -- Focus left/right for i = 1, 4 do @@ -235,11 +307,11 @@ hl.define_submap("virtual-machine", function() local currentsubmap = hl.get_current_submap() if currentsubmap == "virtual-machine" then hl.dispatch(hl.dsp.exec_cmd( - "notify-send 'Exited Virtual Machine submap' 'Keybinds re-enabled' -a 'Hyprland'")) + "notify-send 'Exited Virtual Machine submap' 'Keybinds re-enabled' -a 'Hyprland'")) hl.dispatch(hl.dsp.submap("reset")) elseif currentsubmap == "" then hl.dispatch(hl.dsp.exec_cmd( - "notify-send 'Entered Virtual Machine submap' 'Keybinds disabled. hit SUPER+ALT+F1 to escape' -a 'Hyprland'")) + "notify-send 'Entered Virtual Machine submap' 'Keybinds disabled. hit SUPER+ALT+F1 to escape' -a 'Hyprland'")) hl.dispatch(hl.dsp.submap("virtual-machine")) end end, { submap_universal = true }) @@ -250,63 +322,25 @@ end) --# Testing hl.bind("SUPER + ALT + F11", hl.dsp.exec_cmd( - "bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | shuf -n 1); ACTION=$(notify-send \"Test notification with body image\" \"This notification should contain your user account image and Discord icon. Oh and here is a random image in your Pictures folder: \\\"Testing\" -a \"Hyprland\" -p -h \"string:image-path:/var/lib/AccountsService/icons/$USER\" -t 6000 -i \"discord\" -A \"openImage=Profile image\" -A \"action2=Open the random image\" -A \"action3=Useless button\"); [[ $ACTION == *openImage ]] && xdg-open \"/var/lib/AccountsService/icons/$USER\"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"'") -) -- # [hidden] + "bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | shuf -n 1); ACTION=$(notify-send \"Test notification with body image\" \"This notification should contain your user account image and Discord icon. Oh and here is a random image in your Pictures folder: \\\"Testing\" -a \"Hyprland\" -p -h \"string:image-path:/var/lib/AccountsService/icons/$USER\" -t 6000 -i \"discord\" -A \"openImage=Profile image\" -A \"action2=Open the random image\" -A \"action3=Useless button\"); [[ $ACTION == *openImage ]] && xdg-open \"/var/lib/AccountsService/icons/$USER\"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"'") +) -- # [hidden] hl.bind("SUPER + ALT + F12", hl.dsp.exec_cmd( - "bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | shuf -n 1); ACTION=$(notify-send \"Test notification\" \"This notification should contain a random image in your Pictures folder and Discord icon.\nFlick right to dismiss!\" -a \"Discord (fake)\" -p -h \"string:image-path:$RANDOM_IMAGE\" -t 6000 -i \"discord\" -A \"openImage=Profile image\" -A \"action2=Useless button\"); [[ $ACTION == *openImage ]] && xdg-open \"/var/lib/AccountsService/icons/$USER\"'") -) -- # [hidden] + "bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | shuf -n 1); ACTION=$(notify-send \"Test notification\" \"This notification should contain a random image in your Pictures folder and Discord icon.\nFlick right to dismiss!\" -a \"Discord (fake)\" -p -h \"string:image-path:$RANDOM_IMAGE\" -t 6000 -i \"discord\" -A \"openImage=Profile image\" -A \"action2=Useless button\"); [[ $ACTION == *openImage ]] && xdg-open \"/var/lib/AccountsService/icons/$USER\"'") +) -- # [hidden] hl.bind("SUPER + ALT + Equal", - hl.dsp.exec_cmd("notify-send 'Urgent notification' 'Ah hell no' -u critical -a 'Hyprland keybind'")) -- # [hidden] + hl.dsp.exec_cmd("notify-send 'Urgent notification' 'Ah hell no' -u critical -a 'Hyprland keybind'")) -- # [hidden] --##! Session -hl.bind("SUPER + L", hl.dsp.exec_cmd("loginctl lock-session"), { description = "Misc: Lock" }) +hl.bind("SUPER + L", hl.dsp.exec_cmd("loginctl lock-session"), { description = "Session: Lock" }) hl.bind("SUPER + SHIFT + L", hl.dsp.exec_cmd("systemctl suspend || loginctl suspend"), - { locked = true, description = "Misc: Suspend system" }) -- Sleep + { locked = true, description = "Session: Sleep" }) -- Sleep -- hl.bind("switch:on:Lid Switch", hl.dsp.exec_cmd("systemctl suspend || loginctl suspend"), {locked = true} ) -- # [hidden] Suspend when laptop lid is closed, uncomment if for whatever reason it's not the default behavior hl.bind("CTRL + SHIFT + ALT + SUPER + Delete", hl.dsp.exec_cmd("systemctl poweroff || loginctl poweroff"), - { description = "Misc: Shutdown" }) -- # [hidden] Power off + { description = "Session: Shut down" }) -- # [hidden] Power off ---##! Screen ---# Zoom -local function zoomfunction(value) - local zoomvalue = hl.get_config("cursor:zoom_factor") - if (zoomvalue + value) > 3.0 then - hl.config({ cursor = { zoom_factor = 3.0 } }) - elseif (zoomvalue + value) < 1.0 then - hl.config({ cursor = { zoom_factor = 1.0 } }) - else - hl.config({ cursor = { zoom_factor = zoomvalue + value } }) - end -end -hl.bind("SUPER + Minus", function() zoomfunction(-0.3) end, { repeating = true, description = "Misc: Zoom out" }) -hl.bind("SUPER + Equal", function() zoomfunction(0.3) end, { repeating = true, description = "Misc: Zoom in" }) ---# Zoom with keypad -hl.bind("SUPER + code:82", function() zoomfunction(-0.3) end, { repeating = true }) -hl.bind("SUPER + code:86", function() zoomfunction(0.3) end, { repeating = true }) - ---##! Media -local mediaNextCommand = -"playerctl next || playerctl position `bc <<< \"100 * $(playerctl metadata mpris:length) / 1000000 / 100\"`" -hl.bind("SUPER + SHIFT + N", hl.dsp.exec_cmd(mediaNextCommand), { locked = true, description = "Misc: Next track" }) -hl.bind("XF86AudioNext", hl.dsp.exec_cmd(mediaNextCommand), { locked = true }) -hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true }) -hl.bind("SUPER + SHIFT + ALT + mouse:275", hl.dsp.exec_cmd("playerctl previous")) -hl.bind("SUPER + SHIFT + ALT + mouse:276", hl.dsp.exec_cmd(mediaNextCommand)) -hl.bind("SUPER + SHIFT + B", hl.dsp.exec_cmd("playerctl previous"), { locked = true, description = "Misc: Previous track" }) -hl.bind("SUPER + SHIFT + P", hl.dsp.exec_cmd("playerctl play-pause"), - { locked = true, description = "Misc: Play/pause media" }) -hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) -hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) -hl.bind("XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SINK@ toggle"), { locked = true }) -hl.bind("SUPER + SHIFT + M", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SINK@ toggle"), - { locked = true, description = "Misc: Toggle mute" }) -hl.bind("ALT + XF86AudioMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SOURCE@ toggle"), { locked = true }) -hl.bind("XF86AudioMicMute", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SOURCE@ toggle"), { locked = true }) -hl.bind("SUPER + ALT + M", hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_SOURCE@ toggle"), - { locked = true, description = "Misc: Toggle mic" }) --##! Apps hl.bind("SUPER + Return", hl.dsp.exec_cmd(terminal), { description = "App: Terminal" }) hl.bind("SUPER + T", hl.dsp.exec_cmd(terminal)) diff --git a/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml index 62d51333a..337230aba 100644 --- a/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml +++ b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml @@ -16,6 +16,7 @@ Item { StyledFlickable { id: flickable + clip: true anchors.fill: parent anchors.margins: Appearance.rounding.small contentHeight: height @@ -34,4 +35,10 @@ Item { } } } + + ScrollEdgeFade { + target: flickable + vertical: false + color: Appearance.colors.colLayer0Base + } } diff --git a/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybindsCategory.qml b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybindsCategory.qml index cb58ba4ca..724daee54 100644 --- a/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybindsCategory.qml +++ b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybindsCategory.qml @@ -8,6 +8,8 @@ import QtQuick import QtQuick.Layouts import Quickshell +// Notes: +// We deal with keybinds being numbered 1, 2, etc by discarding 2+, keeping 1 and replacing it with a generic "" Column { id: root required property string categoryName @@ -61,11 +63,11 @@ Column { property var keyBlacklist: ["SUPER_L", "SUPER_R"] property var keySubstitutions: Object.assign({ "Super": "", - "Mouse_up": "Scroll ↓", // ikr, weird - "Mouse_down": "Scroll ↑", // trust me bro - "Mouse:272": "LMB", - "Mouse:273": "RMB", - "Mouse:275": "MouseBack", + "mouse_up": "Scroll ↓", // ikr, weird + "mouse_down": "Scroll ↑", // trust me bro + "mouse:272": "LMB", + "mouse:273": "RMB", + "mouse:275": "MouseBack", "Slash": "/", "Hash": "#", "Return": "Enter", @@ -93,6 +95,7 @@ Column { return list; } + visible: repeater.model.length > 0 spacing: titleSpacing StyledText { @@ -100,14 +103,59 @@ Column { font.pixelSize: Appearance.font.pixelSize.title } + function hasDescription(bind) { + return bind.description?.length > 0; + } + + function isCategory(bind, categoryName) { + return bind.description.substring(0, bind.description.indexOf(":")) === categoryName; + } + + function isUncategorized(bind) { + return bind.description.indexOf(":") === -1; + } + + function containsNonFirstRepetitive(bind) { + const key = bind.key; + if (key.includes("mouse") || key.includes("page")) return false; + // Contains non-1 number + if (/\d/.test(key) && !key.includes("1")) return true; + // Contains non-left direction + if (/^(right|up|down)\b/i.test(key)) return true; + return false; + } + + function containsFirstRepetitive(bind) { + const key = bind.key; + return key.includes("1") || /left/i.test(key); + } + + function transformKey(key) { + const replaced = root.keySubstitutions[key] || key; + const denumbered = replaced.replace("1", ""); + const dedirectioned = denumbered.replace("Left", ""); + return dedirectioned; + } + + function transformDescription(bind, categoryName) { + const description = bind.description + const regex = new RegExp("\\s*" + categoryName + "\\s*:\\s*"); + const decategorized = description.replace(regex, ""); + if (!containsFirstRepetitive(bind)) return decategorized; + const denumbered = decategorized.replace("1", ""); + const dedirectioned = denumbered.replace(/ \b(left|right|up|down)\b/i, " "); + return dedirectioned; + } + Column { spacing: 4 Repeater { + id: repeater model: { if (!root.isCategorized) { - return HyprlandKeybinds.keybinds.filter(bind => bind.description?.length > 0 && bind.description.indexOf(":") === -1); + return HyprlandKeybinds.keybinds.filter(bind => root.hasDescription(bind) && root.isUncategorized(bind) && !root.containsNonFirstRepetitive(bind)); } - return HyprlandKeybinds.keybinds.filter(bind => bind.description?.length > 0 && bind.description.substring(0, bind.description.indexOf(":")) === root.categoryName); + return HyprlandKeybinds.keybinds.filter(bind => root.hasDescription(bind) && root.isCategory(bind, root.categoryName) && !root.containsNonFirstRepetitive(bind)); } delegate: BindLine { required property var modelData @@ -138,7 +186,7 @@ Column { } delegate: KeyboardKey { required property var modelData - key: modelData + key: root.transformKey(modelData) pixelSize: Config.options.cheatsheet.fontSize.key } } @@ -152,10 +200,7 @@ Column { id: keybindKey anchors.verticalCenter: parent.verticalCenter visible: !keyBlacklist.includes(bindLine.keyData.key) - key: { - const k = StringUtils.toTitleCase(bindLine.keyData.key) - return root.keySubstitutions[k] || k - } + key: root.transformKey(bindLine.keyData.key) pixelSize: Config.options.cheatsheet.fontSize.key color: Appearance.colors.colOnLayer0 } @@ -169,10 +214,7 @@ Column { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left font.pixelSize: Config.options.cheatsheet.fontSize.comment || Appearance.font.pixelSize.smaller - text: { - const regex = new RegExp("\\s*" + bindLine.categoryName + "\\s*:\\s*"); - return bindLine.keyData.description.replace(regex, ""); - } + text: root.transformDescription(bindLine.keyData, bindLine.categoryName) } } } From d4d78a5e62c6a9b85e32b2eab966b2658e33435f Mon Sep 17 00:00:00 2001 From: zzalli Date: Sun, 17 May 2026 15:36:14 +0300 Subject: [PATCH 05/14] fix(hyprsunset): remove vestigial Hyprland.dispatch broken under .lua schema --- dots/.config/quickshell/ii/services/Hyprsunset.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/dots/.config/quickshell/ii/services/Hyprsunset.qml b/dots/.config/quickshell/ii/services/Hyprsunset.qml index 8531b991d..5f422c91e 100644 --- a/dots/.config/quickshell/ii/services/Hyprsunset.qml +++ b/dots/.config/quickshell/ii/services/Hyprsunset.qml @@ -166,7 +166,6 @@ Singleton { target: Config.options.light.night function onColorTemperatureChanged() { if (!root.temperatureActive) return; - Hyprland.dispatch(`hyprctl hyprsunset temperature ${Config.options.light.night.colorTemperature}`); Quickshell.execDetached(["hyprctl", "hyprsunset", "temperature", `${Config.options.light.night.colorTemperature}`]); } } From d4e777911e32f8ebbf71c92ce5d0060163fb8a02 Mon Sep 17 00:00:00 2001 From: GregorVal <106101599+GregorVal@users.noreply.github.com> Date: Sun, 17 May 2026 14:46:26 +0200 Subject: [PATCH 06/14] Fix: XDG_DATA_DIRS now expands correctly Previously the environmental variable would become literally *:$XDG_DATA_DIRS Now the variable is expanded correctly --- dots/.config/hypr/hyprland/env.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dots/.config/hypr/hyprland/env.lua b/dots/.config/hypr/hyprland/env.lua index f3df2e630..9e40a4e48 100644 --- a/dots/.config/hypr/hyprland/env.lua +++ b/dots/.config/hypr/hyprland/env.lua @@ -4,7 +4,8 @@ local home_dir = os.getenv("HOME") hl.env("ELECTRON_OZONE_PLATFORM_HINT", "auto") -- Applications -hl.env("XDG_DATA_DIRS", home_dir .. "/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share:$XDG_DATA_DIRS") +local xdg_data_dirs_old = os.getenv("XDG_DATA_DIRS") or "" +hl.env("XDG_DATA_DIRS", home_dir .. "/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share:" .. xdg_data_dirs_old) -- Themes hl.env("QT_QPA_PLATFORM", "wayland;xcb") From 25fe0ab01e8849698df0da4c4ca000807bf5a258 Mon Sep 17 00:00:00 2001 From: Zhengjie Min Date: Wed, 20 May 2026 11:32:13 -0400 Subject: [PATCH 07/14] fix(hyprland): restore nwg-display entry --- dots/.config/hypr/hyprland.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dots/.config/hypr/hyprland.lua b/dots/.config/hypr/hyprland.lua index 9e87ce3fb..be49ff3db 100644 --- a/dots/.config/hypr/hyprland.lua +++ b/dots/.config/hypr/hyprland.lua @@ -8,7 +8,7 @@ require("hyprland.services") -- Environment variables -- require("hyprland.env") if is_file_exists(HOME .. "/.config/hypr/custom/env.lua") then - require("custom.env") + require("custom.env") end -- Default configurations -- @@ -20,21 +20,21 @@ require("hyprland.keybinds") -- Custom configurations -- if is_file_exists(HOME .. "/.config/hypr/custom/execs.lua") then - require("custom.execs") + require("custom.execs") end if is_file_exists(HOME .. "/.config/hypr/custom/general.lua") then - require("custom.general") + require("custom.general") end if is_file_exists(HOME .. "/.config/hypr/custom/rules.lua") then - require("custom.rules") + require("custom.rules") end if is_file_exists(HOME .. "/.config/hypr/custom/keybinds.lua") then - require("custom.keybinds") + require("custom.keybinds") end --- nwg-displays support: re-add the files if it updates later --- require("workspaces") --- require("monitors") +-- nwg-displays support -- +require("workspaces") +require("monitors") -- Shell overrides -- require("hyprland.shellOverrides.main") From 20d1ff065b1201d5130e994a7df53e2ddfdf6069 Mon Sep 17 00:00:00 2001 From: Zhengjie Min Date: Wed, 20 May 2026 11:38:00 -0400 Subject: [PATCH 08/14] style: space indent --- dots/.config/hypr/hyprland.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dots/.config/hypr/hyprland.lua b/dots/.config/hypr/hyprland.lua index be49ff3db..8f37dd2b5 100644 --- a/dots/.config/hypr/hyprland.lua +++ b/dots/.config/hypr/hyprland.lua @@ -8,7 +8,7 @@ require("hyprland.services") -- Environment variables -- require("hyprland.env") if is_file_exists(HOME .. "/.config/hypr/custom/env.lua") then - require("custom.env") + require("custom.env") end -- Default configurations -- @@ -20,16 +20,16 @@ require("hyprland.keybinds") -- Custom configurations -- if is_file_exists(HOME .. "/.config/hypr/custom/execs.lua") then - require("custom.execs") + require("custom.execs") end if is_file_exists(HOME .. "/.config/hypr/custom/general.lua") then - require("custom.general") + require("custom.general") end if is_file_exists(HOME .. "/.config/hypr/custom/rules.lua") then - require("custom.rules") + require("custom.rules") end if is_file_exists(HOME .. "/.config/hypr/custom/keybinds.lua") then - require("custom.keybinds") + require("custom.keybinds") end -- nwg-displays support -- From 8f9cf67be7715010998e077ded8a339d539c1060 Mon Sep 17 00:00:00 2001 From: Jihed Kdiss Date: Thu, 21 May 2026 14:16:22 +0100 Subject: [PATCH 09/14] fix(screenCorners): remove shadowing screen property to fix multi-monitor corner rendering --- .../quickshell/ii/modules/ii/screenCorners/ScreenCorners.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/ii/screenCorners/ScreenCorners.qml b/dots/.config/quickshell/ii/modules/ii/screenCorners/ScreenCorners.qml index 1e1ec07ba..f8b1e2436 100644 --- a/dots/.config/quickshell/ii/modules/ii/screenCorners/ScreenCorners.qml +++ b/dots/.config/quickshell/ii/modules/ii/screenCorners/ScreenCorners.qml @@ -21,7 +21,6 @@ Scope { component CornerPanelWindow: PanelWindow { id: cornerPanelWindow - property var screen: QsWindow.window?.screen property var brightnessMonitor: Brightness.getMonitorForScreen(screen) property bool fullscreen visible: (Config.options.appearance.fakeScreenRounding === 1 || (Config.options.appearance.fakeScreenRounding === 2 && !fullscreen)) From 6eaa869fac8dbd6af1dd8ecc8be93d2079e38a4d Mon Sep 17 00:00:00 2001 From: RamonBritoDev Date: Thu, 21 May 2026 16:23:40 +0000 Subject: [PATCH 10/14] fix(qs): NotificationItem polish() loop on Qt 6.11 summaryText.Layout.fillWidth depended on summaryRow.implicitWidth, its own parent RowLayout, creating a circular dependency: summaryText.Layout.fillWidth -> changes summaryText.width -> changes summaryRow.implicitWidth -> re-evaluates summaryText.Layout.fillWidth (loop) Qt 6.10 tolerated this through layout settling heuristics, but Qt 6.11.1 detects the loop and emits "ColumnLayout called polish() inside updatePolish() of ColumnLayout" warnings repeatedly, pinning CPU at 100% and freezing the sidebar/notification UI when opened. Use root.width (the stable width inherited from the parent ListView) as the reference for the elision threshold instead of the recursive summaryRow.implicitWidth. --- .../quickshell/ii/modules/common/widgets/NotificationItem.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml b/dots/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml index bb1bab787..23be8287c 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/NotificationItem.qml @@ -153,7 +153,7 @@ Item { // Notification item area implicitHeight: summaryText.implicitHeight StyledText { id: summaryText - Layout.fillWidth: summaryTextMetrics.width >= summaryRow.implicitWidth * root.summaryElideRatio + Layout.fillWidth: summaryTextMetrics.width >= root.width * root.summaryElideRatio visible: !root.onlyNotification font.pixelSize: root.fontSize color: Appearance.colors.colOnLayer3 From ce809512100c267238d6f57bc52b73ff2e7e4f85 Mon Sep 17 00:00:00 2001 From: "Love, Trevor S" Date: Fri, 22 May 2026 11:34:10 -0700 Subject: [PATCH 11/14] fix: hypridle dispatch commands for Lua-based Hyprland --- dots/.config/hypr/hypridle.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dots/.config/hypr/hypridle.conf b/dots/.config/hypr/hypridle.conf index 85ea6186f..68a50b20b 100644 --- a/dots/.config/hypr/hypridle.conf +++ b/dots/.config/hypr/hypridle.conf @@ -5,7 +5,7 @@ $suspend_cmd = systemctl suspend || loginctl suspend general { lock_cmd = $lock_cmd before_sleep_cmd = loginctl lock-session - after_sleep_cmd = hyprctl dispatch global quickshell:lockFocus + after_sleep_cmd = hyprctl dispatch 'hl.dsp.global("quickshell:lockFocus")' inhibit_sleep = 3 } @@ -16,8 +16,8 @@ listener { listener { timeout = 600 # 10mins - on-timeout = hyprctl dispatch dpms off - on-resume = hyprctl dispatch dpms on + on-timeout = hyprctl dispatch 'hl.dsp.dpms(false)' + on-resume = hyprctl dispatch 'hl.dsp.dpms(true)' } listener { From 54a1d172d7b0906fa8a97096faaa7f9f0ab065d4 Mon Sep 17 00:00:00 2001 From: Minh <97237370+end-4@users.noreply.github.com> Date: Sun, 24 May 2026 22:55:17 +0200 Subject: [PATCH 12/14] add file existence check for nwg displays include --- dots/.config/hypr/hyprland.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dots/.config/hypr/hyprland.lua b/dots/.config/hypr/hyprland.lua index 8f37dd2b5..3e54e8e3d 100644 --- a/dots/.config/hypr/hyprland.lua +++ b/dots/.config/hypr/hyprland.lua @@ -33,8 +33,12 @@ if is_file_exists(HOME .. "/.config/hypr/custom/keybinds.lua") then end -- nwg-displays support -- -require("workspaces") -require("monitors") +if is_file_exists(HOME .. "/.config/hypr/workspaces.lua") then + require("workspaces") +end +if is_file_exists(HOME .. "/.config/hypr/monitors.lua") then + require("monitors") +end -- Shell overrides -- require("hyprland.shellOverrides.main") From 9b149e6fefb0c20516d3d0b2fb9ddadcc2f1996e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 24 May 2026 23:34:21 +0200 Subject: [PATCH 13/14] qs: sidebar: quick toggle: friendlier/shorter default state text --- .../quickToggles/androidStyle/AndroidQuickToggleButton.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml index 017d02aa4..3245f042e 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml @@ -24,7 +24,7 @@ GroupButton { // Declared in specific toggles property QuickToggleModel toggleModel property string name: toggleModel?.name ?? "" - property string statusText: (toggleModel?.hasStatusText) ? (toggleModel?.statusText || (toggled ? Translation.tr("Active") : Translation.tr("Inactive"))) : "" + property string statusText: (toggleModel?.hasStatusText) ? (toggleModel?.statusText || (toggled ? Translation.tr("On") : Translation.tr("Off"))) : "" property string tooltipText: toggleModel?.tooltipText ?? "" property string buttonIcon: toggleModel?.icon ?? "close" property bool available: toggleModel?.available ?? true From a15f2a8a39856198b3b273431d0c9c6ab6c5c58a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 24 May 2026 23:37:01 +0200 Subject: [PATCH 14/14] add a weak anti flashbang variant --- .../quickToggles/AntiFlashbangToggle.qml | 8 ++-- .../services/HyprlandAntiFlashbangShader.qml | 21 ++++++++- .../anti-flashbang-weak.glsl | 47 +++++++++++++++++++ 3 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 dots/.config/quickshell/ii/services/hyprlandAntiFlashbangShader/anti-flashbang-weak.glsl diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/AntiFlashbangToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/AntiFlashbangToggle.qml index 64f8c4e72..3aa345124 100644 --- a/dots/.config/quickshell/ii/modules/common/models/quickToggles/AntiFlashbangToggle.qml +++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/AntiFlashbangToggle.qml @@ -5,13 +5,13 @@ import qs.modules.common.functions import qs.modules.common.widgets QuickToggleModel { - name: Translation.tr("Anti-flashbang") - tooltipText: Translation.tr("Anti-flashbang") - icon: "flash_off" + name: HyprlandAntiFlashbangShader.enabled ? (HyprlandAntiFlashbangShader.weak ? Translation.tr("Anti-flash: Weak") : Translation.tr("Anti-flash: Strong")) : Translation.tr("Anti-flashbang") + tooltipText: `${Translation.tr("Anti-flashbang")}: ${HyprlandAntiFlashbangShader.enabled ? (HyprlandAntiFlashbangShader.weak ? Translation.tr("Weak") : Translation.tr("Strong")) : Translation.tr("Off")}` + icon: HyprlandAntiFlashbangShader.enabled ? (!HyprlandAntiFlashbangShader.weak ? "flash_off" : "sunny_snowing") : "flash_on" toggled: HyprlandAntiFlashbangShader.enabled mainAction: () => { - HyprlandAntiFlashbangShader.toggle() + HyprlandAntiFlashbangShader.cycle() } hasMenu: true } diff --git a/dots/.config/quickshell/ii/services/HyprlandAntiFlashbangShader.qml b/dots/.config/quickshell/ii/services/HyprlandAntiFlashbangShader.qml index eea2123b9..e8efb46d9 100644 --- a/dots/.config/quickshell/ii/services/HyprlandAntiFlashbangShader.qml +++ b/dots/.config/quickshell/ii/services/HyprlandAntiFlashbangShader.qml @@ -10,7 +10,9 @@ Singleton { id: root readonly property string shaderPath: Quickshell.shellPath("services/hyprlandAntiFlashbangShader/anti-flashbang.glsl") - property bool enabled: confOpt.value == shaderPath + readonly property string weakShaderPath: Quickshell.shellPath("services/hyprlandAntiFlashbangShader/anti-flashbang-weak.glsl") + property bool enabled: confOpt.value == shaderPath || weak + property bool weak: confOpt.value == weakShaderPath function enable() { HyprlandConfig.setMany({ @@ -19,6 +21,13 @@ Singleton { }); } + function enableWeak() { + HyprlandConfig.setMany({ + "decoration:screen_shader": root.weakShaderPath, + "debug:damage_tracking": 1, + }); + } + function disable() { HyprlandConfig.resetMany([ "decoration:screen_shader", @@ -30,6 +39,16 @@ Singleton { if (root.enabled) disable() else enable() } + + function cycle() { + if (!enabled) { + enableWeak(); + } else if (weak) { + enable(); + } else { + disable(); + } + } HyprlandConfigOption { id: confOpt diff --git a/dots/.config/quickshell/ii/services/hyprlandAntiFlashbangShader/anti-flashbang-weak.glsl b/dots/.config/quickshell/ii/services/hyprlandAntiFlashbangShader/anti-flashbang-weak.glsl new file mode 100644 index 000000000..6ab4a30fa --- /dev/null +++ b/dots/.config/quickshell/ii/services/hyprlandAntiFlashbangShader/anti-flashbang-weak.glsl @@ -0,0 +1,47 @@ +#version 300 es +precision highp float; + +in vec2 v_texcoord; +uniform sampler2D tex; +out vec4 fragColor; + +float overlayOpacityForBrightness(float x) { + // Note: range 0 to 1 + + // Will a fancy curve help?... I'll have to experiment more at night + // float y = pow(x, 2.0) * 0.75; + // float y = (1.0 - exp(-x))*1.19; + // float y = (1.0 - exp(-pow((x-0.15), 0.6)))*1.18; + + float y = x*0.42; + return min(max(y, 0.001), 1.0); +} + +void main() { + // 1. Get the current pixel color + vec4 pixColor = texture(tex, v_texcoord); + + // 2. Calculate average screen brightness + vec3 totalRGB = vec3(0.0); + float samples = 0.0; + + // We use a nested loop to create a 10x10 grid (100 samples) + // This is dense enough to catch small icons/text but light enough to run fast. + for(float x = 0.05; x < 1.0; x += 0.1) { + for(float y = 0.05; y < 1.0; y += 0.1) { + totalRGB += texture(tex, vec2(x, y)).rgb; + samples++; + } + } + + vec3 avgColor = totalRGB / samples; + float globalBrightness = dot(avgColor, vec3(0.2126, 0.7152, 0.0722)); + + // 3. Get the specific opacity for this brightness level + float opacity = overlayOpacityForBrightness(globalBrightness); + + // 4. Apply the "black overlay" effect + vec3 outColor = mix(pixColor.rgb, vec3(0.0), opacity); + + fragColor = vec4(outColor, pixColor.a); +}