Fix hyprwinview overview bind shadowing

Mark the overview keybinds transparent so Hyprland does not shadow the first Super+Tab after a focus-moving bind. The missed first press was reproduced with a ydotool harness as a keybind-level failure: after Super+D, the first Super+Tab did not reach the hyprwinview Lua callback, while the second did. With transparent overview binds, the harness passes consistently.

While touching the overview wrapper, keep the hyprwinview show action explicit and gate diagnostic tracing behind /tmp/hypr-overview-bind.enable. Also use Hyprland's integer notification icon enum values so missing-plugin/debug notifications do not emit invalid icon errors.
This commit is contained in:
2026-05-05 02:38:20 -07:00
parent 8dac748f56
commit eb95ee9faa

View File

@@ -6,6 +6,20 @@ local terminal = "ghostty --gtk-single-instance=false"
local shell_ui_command = "hypr_shell_ui" local shell_ui_command = "hypr_shell_ui"
local launcher_command = shell_ui_command .. " launcher" local launcher_command = shell_ui_command .. " launcher"
local run_menu = shell_ui_command .. " run" local run_menu = shell_ui_command .. " run"
-- Hyprland shadows ordinary keybinds after one fires; without transparent,
-- the first overview chord after a focus-moving bind can be skipped.
local overview_bind_opts = { dont_inhibit = true, transparent = true }
local overview_trace_enabled_path = "/tmp/hypr-overview-bind.enable"
local overview_trace_path = "/tmp/hypr-overview-bind.log"
local notification_icons = {
warning = 0,
info = 1,
hint = 2,
error = 3,
confused = 4,
ok = 5,
none = 6,
}
local max_workspace = 9 local max_workspace = 9
local scratchpad_size_ratio = 0.95 local scratchpad_size_ratio = 0.95
@@ -116,6 +130,24 @@ local function exec(command)
return hl.dsp.exec_cmd(command) return hl.dsp.exec_cmd(command)
end end
local function shell_quote(value)
return "'" .. tostring(value):gsub("'", "'\\''") .. "'"
end
local function overview_trace(label)
local enabled = io.open(overview_trace_enabled_path, "r")
if not enabled then
return
end
enabled:close()
local trace = io.open(overview_trace_path, "a")
if trace then
trace:write(os.date("%Y-%m-%d %H:%M:%S "), label, "\n")
trace:close()
end
end
local function window_selector(window) local function window_selector(window)
if not window or not window.address then if not window or not window.address then
return nil return nil
@@ -124,14 +156,16 @@ local function window_selector(window)
end end
local function hyprexpo(action) local function hyprexpo(action)
action = action or "toggle"
return function() return function()
overview_trace("hyprexpo " .. tostring(action))
if hl.plugin and hl.plugin.hyprexpo and hl.plugin.hyprexpo.expo then if hl.plugin and hl.plugin.hyprexpo and hl.plugin.hyprexpo.expo then
hl.plugin.hyprexpo.expo(action) hl.plugin.hyprexpo.expo(action)
else else
hl.notification.create({ hl.notification.create({
text = "hyprexpo is not loaded", text = "hyprexpo is not loaded",
duration = 1800, duration = 1800,
icon = "warning", icon = notification_icons.warning,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -141,17 +175,29 @@ end
local function hyprwinview(action) local function hyprwinview(action)
return function() return function()
if hl.plugin and hl.plugin.hyprwinview and hl.plugin.hyprwinview.overview then local label = "hyprwinview"
hl.plugin.hyprwinview.overview(action) if type(action) == "table" and action.action then
else label = label .. " " .. tostring(action.action)
hl.notification.create({ elseif type(action) ~= "table" and action ~= nil then
text = "hyprwinview is not loaded", label = label .. " " .. tostring(action)
duration = 1800,
icon = "warning",
color = "rgba(edb443ff)",
font_size = 13,
})
end end
local function invoke()
overview_trace(label)
if hl.plugin and hl.plugin.hyprwinview and hl.plugin.hyprwinview.overview then
hl.plugin.hyprwinview.overview(action)
else
hl.notification.create({
text = "hyprwinview is not loaded",
duration = 1800,
icon = notification_icons.warning,
color = "rgba(edb443ff)",
font_size = 13,
})
end
end
invoke()
end end
end end
@@ -163,7 +209,7 @@ local function workspacehistory(action, arg)
hl.notification.create({ hl.notification.create({
text = "workspacehistory is not loaded", text = "workspacehistory is not loaded",
duration = 1800, duration = 1800,
icon = "warning", icon = notification_icons.warning,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -631,7 +677,7 @@ local function update_monocle_notice()
monocle_notice = hl.notification.create({ monocle_notice = hl.notification.create({
text = text, text = text,
duration = 60000, duration = 60000,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -647,7 +693,7 @@ local function notify_layout(layout)
hl.notification.create({ hl.notification.create({
text = "Layout: " .. layout_name(layout), text = "Layout: " .. layout_name(layout),
duration = 1200, duration = 1200,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -733,6 +779,7 @@ local function monocle_prev()
end end
local function focus_direction(direction) local function focus_direction(direction)
overview_trace("focus_direction " .. direction)
if active_group_size() > 1 or current_layout == monocle_layout then if active_group_size() > 1 or current_layout == monocle_layout then
if direction == "up" or direction == "left" then if direction == "up" or direction == "left" then
monocle_prev() monocle_prev()
@@ -774,7 +821,7 @@ local function notify_tabbed_group(text)
hl.notification.create({ hl.notification.create({
text = text, text = text,
duration = 1800, duration = 1800,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -1032,7 +1079,7 @@ local function enter_workspace_swap_mode()
hl.notification.create({ hl.notification.create({
text = "Swap with workspace 1-9", text = "Swap with workspace 1-9",
duration = 2200, duration = 2200,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -1214,10 +1261,6 @@ local function logical_monitor_dimension(value, scale)
return math.floor((value / scale) + 0.5) return math.floor((value / scale) + 0.5)
end end
local function shell_quote(value)
return "'" .. tostring(value):gsub("'", "'\\''") .. "'"
end
local function split_tsv(line) local function split_tsv(line)
local fields = {} local fields = {}
for field in (line .. "\t"):gmatch("([^\t]*)\t") do for field in (line .. "\t"):gmatch("([^\t]*)\t") do
@@ -1539,7 +1582,7 @@ local function enter_window_picker(mode)
hl.notification.create({ hl.notification.create({
text = empty_text, text = empty_text,
duration = 1800, duration = 1800,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -1555,7 +1598,7 @@ local function enter_window_picker(mode)
hl.notification.create({ hl.notification.create({
text = table.concat(lines, "\n"), text = table.concat(lines, "\n"),
duration = 5000, duration = 5000,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 11, font_size = 11,
}) })
@@ -1580,7 +1623,7 @@ local function gather_focused_class()
hl.notification.create({ hl.notification.create({
text = "Gathered " .. tostring(count) .. " " .. focused.class .. " windows", text = "Gathered " .. tostring(count) .. " " .. focused.class .. " windows",
duration = 1600, duration = 1600,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -1628,7 +1671,7 @@ local function show_active_window_info()
hl.notification.create({ hl.notification.create({
text = "No active window", text = "No active window",
duration = 1800, duration = 1800,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 13, font_size = 13,
}) })
@@ -1647,7 +1690,7 @@ local function show_active_window_info()
hl.notification.create({ hl.notification.create({
text = table.concat(lines, "\n"), text = table.concat(lines, "\n"),
duration = 5000, duration = 5000,
icon = "info", icon = notification_icons.info,
color = "rgba(edb443ff)", color = "rgba(edb443ff)",
font_size = 11, font_size = 11,
}) })
@@ -1973,11 +2016,18 @@ bind(main_mod .. " + SHIFT + C", hl.dsp.window.close())
bind(main_mod .. " + SHIFT + Q", hl.dsp.exit()) bind(main_mod .. " + SHIFT + Q", hl.dsp.exit())
bind(main_mod .. " + E", exec("emacsclient --eval '(emacs-everywhere)'")) bind(main_mod .. " + E", exec("emacsclient --eval '(emacs-everywhere)'"))
bind(main_mod .. " + V", exec("wl-paste | xdotool type --file -")) bind(main_mod .. " + V", exec("wl-paste | xdotool type --file -"))
bind(main_mod .. " + Tab", hyprwinview("toggle filter")) bind(main_mod .. " + Tab", hyprwinview({
bind(main_mod .. " + SHIFT + Tab", hyprwinview("toggle other-workspaces filter")) action = "show",
bind(main_mod .. " + SHIFT + slash", hyprwinview("toggle filter")) start_in_filter_mode = true,
bind("ALT + Tab", hyprexpo("toggle")) }), overview_bind_opts)
bind("ALT + SHIFT + Tab", hyprexpo("bring")) bind(main_mod .. " + SHIFT + Tab", hyprwinview({
action = "show",
include_current_workspace = false,
start_in_filter_mode = true,
}), overview_bind_opts)
bind(main_mod .. " + SHIFT + slash", hyprwinview({ action = "toggle-filter" }), overview_bind_opts)
bind("ALT + Tab", hyprexpo("open"), overview_bind_opts)
bind("ALT + SHIFT + Tab", hyprexpo("bring"), overview_bind_opts)
bind(main_mod .. " + G", exec(shell_ui_command .. " window go")) bind(main_mod .. " + G", exec(shell_ui_command .. " window go"))
bind(main_mod .. " + B", exec(shell_ui_command .. " window bring")) bind(main_mod .. " + B", exec(shell_ui_command .. " window bring"))
bind(main_mod .. " + SHIFT + B", exec(shell_ui_command .. " window replace")) bind(main_mod .. " + SHIFT + B", exec(shell_ui_command .. " window replace"))