Extract Hyprland scratchpad module

This commit is contained in:
2026-05-12 00:03:14 -07:00
parent 973b67f185
commit ddaa3a78ac
5 changed files with 431 additions and 426 deletions

View File

@@ -21,6 +21,7 @@ package.path = table.concat({
local modules = {
"hyprland.state",
"hyprland.scratchpads",
"hyprland.core",
"hyprland.layouts",
"hyprland.windows",

View File

@@ -275,53 +275,6 @@ function M.setup(ctx)
return workspace and not workspace.special and workspace.id and workspace.id >= 1
end
local function lower_contains(value, needle)
if not needle or needle == "" then
return true
end
value = string.lower(tostring(value or ""))
needle = string.lower(tostring(needle))
return value:find(needle, 1, true) ~= nil
end
local function lower_contains_any(value, needles)
if type(needles) ~= "table" then
return lower_contains(value, needles)
end
for _, needle in ipairs(needles) do
if lower_contains(value, needle) then
return true
end
end
return false
end
local function scratchpad_window_matches(window, def)
return window
and lower_contains_any(window.class, def.classes or def.class)
and lower_contains(window.title, def.title)
end
local function is_scratchpad_window(window)
for _, def in pairs(scratchpads) do
if scratchpad_window_matches(window, def) then
return true
end
end
return false
end
local function matching_scratchpad_name(window)
for name, def in pairs(scratchpads) do
if scratchpad_window_matches(window, def) then
return name
end
end
return nil
end
local function same_workspace(left, right)
if not left or not right then
return false
@@ -554,11 +507,6 @@ function M.setup(ctx)
ctx.current_workspace_layout = current_workspace_layout
ctx.write_layout_state = write_layout_state
ctx.is_normal_workspace = is_normal_workspace
ctx.lower_contains = lower_contains
ctx.lower_contains_any = lower_contains_any
ctx.scratchpad_window_matches = scratchpad_window_matches
ctx.is_scratchpad_window = is_scratchpad_window
ctx.matching_scratchpad_name = matching_scratchpad_name
ctx.same_workspace = same_workspace
ctx.is_minimized_workspace = is_minimized_workspace
ctx.is_minimized_window = is_minimized_window

View File

@@ -0,0 +1,430 @@
local M = {}
function M.setup(ctx)
local _ENV = ctx
scratchpad_size_ratio = 0.95
dropdown_height_ratio = 0.5
scratchpad_pending = {}
monitor_reserved_cache_path = (os.getenv("XDG_RUNTIME_DIR") or "/tmp") .. "/hyprland-monitor-reserved.tsv"
scratchpad_fallback_reserved_top = 60
scratchpads = {
codex = {
command = "codex-desktop",
class = "codex-desktop",
},
htop = {
command = "alacritty --class htop-scratch --title htop -e htop",
class = "htop-scratch",
},
volume = {
command = "pavucontrol",
class = "org.pulseaudio.pavucontrol",
},
spotify = {
command = "spotify",
class = "spotify",
},
element = {
command = "element-desktop",
classes = { "Element", "electron" },
title = "Element",
},
slack = {
command = "slack",
class = "Slack",
},
messages = {
command = "google-chrome-stable --profile-directory=Default --app=https://messages.google.com/web/conversations",
class = "chrome-messages.google.com",
},
transmission = {
command = "transmission-gtk",
class = "transmission-gtk",
},
dropdown = {
command = "ghostty --config-file=/home/imalison/.config/ghostty/dropdown",
class = "com.mitchellh.ghostty.dropdown",
dropdown = true,
},
}
local function lower_contains(value, needle)
if not needle or needle == "" then
return true
end
value = string.lower(tostring(value or ""))
needle = string.lower(tostring(needle))
return value:find(needle, 1, true) ~= nil
end
local function lower_contains_any(value, needles)
if type(needles) ~= "table" then
return lower_contains(value, needles)
end
for _, needle in ipairs(needles) do
if lower_contains(value, needle) then
return true
end
end
return false
end
local function scratchpad_window_matches(window, def)
return window
and lower_contains_any(window.class, def.classes or def.class)
and lower_contains(window.title, def.title)
end
local function is_scratchpad_window(window)
for _, def in pairs(scratchpads) do
if scratchpad_window_matches(window, def) then
return true
end
end
return false
end
local function matching_scratchpad_name(window)
for name, def in pairs(scratchpads) do
if scratchpad_window_matches(window, def) then
return name
end
end
return nil
end
local function scratchpad_workspace(name)
return "special:scratch-" .. name
end
local function as_number(value, default)
local number = tonumber(value)
if number == nil then
return default
end
return number
end
local function logical_monitor_dimension(value, scale)
value = as_number(value, 0)
scale = as_number(scale, 1)
if scale <= 0 then
scale = 1
end
return math.floor((value / scale) + 0.5)
end
local function split_tsv(line)
local fields = {}
for field in (line .. "\t"):gmatch("([^\t]*)\t") do
fields[#fields + 1] = field
end
return fields
end
local function monitor_from_reserved_fields(monitor, fields)
if not monitor or not monitor.name or fields[1] ~= monitor.name or #fields < 10 then
return nil
end
return {
name = monitor.name,
x = tonumber(fields[2]),
y = tonumber(fields[3]),
width = tonumber(fields[4]),
height = tonumber(fields[5]),
scale = tonumber(fields[6]),
reserved = {
tonumber(fields[7]),
tonumber(fields[8]),
tonumber(fields[9]),
tonumber(fields[10]),
},
}
end
local function monitor_from_reserved_lines(monitor, lines)
if not monitor or not monitor.name then
return nil
end
for line in lines do
local cached = monitor_from_reserved_fields(monitor, split_tsv(line))
if cached then
return cached
end
end
return nil
end
local function monitor_from_reserved_cache(monitor)
if verify_config or not monitor or not monitor.name then
return nil
end
local file = io.open(monitor_reserved_cache_path, "r")
if not file then
return nil
end
local cached = monitor_from_reserved_lines(monitor, file:lines())
file:close()
return cached
end
local function refresh_monitor_reserved_cache(delay)
if verify_config then
return
end
local command = string.format(
[=[sleep %.2f; cache="${XDG_RUNTIME_DIR:-/tmp}/hyprland-monitor-reserved.tsv"; tmp="$cache.tmp"; /run/current-system/sw/bin/hyprctl -j monitors 2>/dev/null | /run/current-system/sw/bin/jq -r '.[] | [.name, .x, .y, .width, .height, .scale, .reserved[0], .reserved[1], .reserved[2], .reserved[3]] | @tsv' > "$tmp" && mv "$tmp" "$cache"]=],
as_number(delay, 0)
)
hl.exec_cmd("sh -lc " .. shell_quote(command))
end
local function monitor_workarea(monitor)
monitor = monitor_from_reserved_cache(monitor) or monitor
local width = logical_monitor_dimension(monitor.width, monitor.scale)
local height = logical_monitor_dimension(monitor.height, monitor.scale)
local reserved = monitor.reserved or { 0, scratchpad_fallback_reserved_top, 0, 0 }
local left = math.floor(as_number(reserved[1], 0))
local top = math.floor(as_number(reserved[2], 0))
local right = math.floor(as_number(reserved[3], 0))
local bottom = math.floor(as_number(reserved[4], 0))
local work_width = width - left - right
local work_height = height - top - bottom
if work_width <= 0 then
left = 0
right = 0
work_width = width
end
if work_height <= 0 then
top = 0
bottom = 0
work_height = height
end
return {
x = math.floor(as_number(monitor.x, 0)) + left,
y = math.floor(as_number(monitor.y, 0)) + top,
width = work_width,
height = work_height,
}
end
local function matching_scratchpad_windows(name)
local def = scratchpads[name]
local windows = {}
if not def then
return windows
end
for _, window in ipairs(hl.get_windows()) do
if scratchpad_window_matches(window, def) then
windows[#windows + 1] = window
end
end
return windows
end
local function apply_scratchpad_geometry(name, window, target_monitor)
local def = scratchpads[name]
local monitor = target_monitor or hl.get_active_monitor()
if not def or not window or not monitor then
return
end
local workarea = monitor_workarea(monitor)
local width
local height
local x
local y
if def.dropdown then
width = workarea.width
height = math.floor(workarea.height * dropdown_height_ratio)
x = workarea.x
y = workarea.y
else
width = math.floor(workarea.width * scratchpad_size_ratio)
height = math.floor(workarea.height * scratchpad_size_ratio)
x = workarea.x + math.floor((workarea.width - width) / 2)
y = workarea.y + math.floor((workarea.height - height) / 2)
end
local selector = window_selector(window)
dispatch(hl.dsp.window.float({ action = "enable", window = selector }))
dispatch(hl.dsp.window.tag({ tag = "+scratchpad", window = selector }))
dispatch(hl.dsp.window.tag({ tag = "+scratchpad-" .. name, window = selector }))
dispatch(hl.dsp.window.resize({ x = width, y = height, relative = false, window = selector }))
dispatch(hl.dsp.window.move({ x = x, y = y, relative = false, window = selector }))
if def.dropdown then
dispatch(hl.dsp.window.set_prop({ prop = "border_size", value = "0", window = selector }))
dispatch(hl.dsp.window.set_prop({ prop = "no_shadow", value = "1", window = selector }))
end
end
local function schedule_scratchpad_geometry(name, window, target_monitor)
hl.timer(function()
apply_scratchpad_geometry(name, window, target_monitor)
end, { timeout = 50, type = "oneshot" })
end
local function hide_scratchpad_window(name, window)
remove_minimized_window(window)
move_window_to_workspace(scratchpad_workspace(name), false, window)
end
local function show_scratchpad_window(name, window, workspace, target_monitor)
workspace = workspace or active_workspace()
if not workspace then
return
end
remove_minimized_window(window)
move_window_to_workspace(workspace.id, false, window)
dispatch(hl.dsp.focus({ window = window_selector(window) }))
schedule_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor())
end
local function scratchpad_is_visible(window)
local workspace = active_workspace()
return workspace and window and same_workspace(window.workspace, workspace)
end
-- Active scratchpads are scratchpad windows visible on the active workspace.
-- Invoking a different scratchpad replaces that active set.
local function active_scratchpad_windows(except_name)
local windows = {}
for _, window in ipairs(hl.get_windows()) do
local name = matching_scratchpad_name(window)
if name and name ~= except_name and scratchpad_is_visible(window) then
windows[#windows + 1] = {
name = name,
window = window,
}
end
end
return windows
end
local function hide_active_scratchpads(except_name)
for _, active in ipairs(active_scratchpad_windows(except_name)) do
hide_scratchpad_window(active.name, active.window)
end
end
local function refresh_active_scratchpad_geometries()
local monitor = hl.get_active_monitor()
for _, active in ipairs(active_scratchpad_windows()) do
schedule_scratchpad_geometry(active.name, active.window, monitor)
end
end
local function refresh_active_scratchpad_geometries_later(timeout)
hl.timer(refresh_active_scratchpad_geometries, { timeout = timeout or 300, type = "oneshot" })
end
local function refresh_shell_workarea_and_scratchpads()
refresh_monitor_reserved_cache(0.15)
refresh_active_scratchpad_geometries_later(400)
end
local function adopt_matching_scratchpad_window(window)
if not window then
return
end
for name, def in pairs(scratchpads) do
if scratchpad_window_matches(window, def) then
if scratchpad_pending[name] then
local pending = scratchpad_pending[name]
scratchpad_pending[name] = nil
show_scratchpad_window(name, window, pending.workspace or active_workspace(), pending.monitor or hl.get_active_monitor())
elseif scratchpad_is_visible(window) then
schedule_scratchpad_geometry(name, window, hl.get_active_monitor())
end
end
end
end
local function toggle_scratchpad(name)
local def = scratchpads[name]
if not def then
return
end
if current_layout == monocle_layout then
set_layout(columns_layout)
end
local windows = matching_scratchpad_windows(name)
if #windows == 0 then
hide_active_scratchpads(name)
scratchpad_pending[name] = {
monitor = hl.get_active_monitor(),
workspace = active_workspace(),
}
hl.exec_cmd(def.command)
return
end
local any_visible = false
for _, window in ipairs(windows) do
if scratchpad_is_visible(window) then
any_visible = true
break
end
end
if any_visible then
for _, window in ipairs(windows) do
hide_scratchpad_window(name, window)
end
else
hide_active_scratchpads(name)
local workspace = active_workspace()
local target_monitor = hl.get_active_monitor()
for _, window in ipairs(windows) do
show_scratchpad_window(name, window, workspace, target_monitor)
end
end
end
ctx.lower_contains = lower_contains
ctx.lower_contains_any = lower_contains_any
ctx.scratchpad_window_matches = scratchpad_window_matches
ctx.is_scratchpad_window = is_scratchpad_window
ctx.matching_scratchpad_name = matching_scratchpad_name
ctx.scratchpad_workspace = scratchpad_workspace
ctx.as_number = as_number
ctx.logical_monitor_dimension = logical_monitor_dimension
ctx.split_tsv = split_tsv
ctx.monitor_from_reserved_fields = monitor_from_reserved_fields
ctx.monitor_from_reserved_lines = monitor_from_reserved_lines
ctx.monitor_from_reserved_cache = monitor_from_reserved_cache
ctx.refresh_monitor_reserved_cache = refresh_monitor_reserved_cache
ctx.monitor_workarea = monitor_workarea
ctx.matching_scratchpad_windows = matching_scratchpad_windows
ctx.apply_scratchpad_geometry = apply_scratchpad_geometry
ctx.schedule_scratchpad_geometry = schedule_scratchpad_geometry
ctx.hide_scratchpad_window = hide_scratchpad_window
ctx.show_scratchpad_window = show_scratchpad_window
ctx.scratchpad_is_visible = scratchpad_is_visible
ctx.active_scratchpad_windows = active_scratchpad_windows
ctx.hide_active_scratchpads = hide_active_scratchpads
ctx.refresh_active_scratchpad_geometries = refresh_active_scratchpad_geometries
ctx.refresh_active_scratchpad_geometries_later = refresh_active_scratchpad_geometries_later
ctx.refresh_shell_workarea_and_scratchpads = refresh_shell_workarea_and_scratchpads
ctx.adopt_matching_scratchpad_window = adopt_matching_scratchpad_window
ctx.toggle_scratchpad = toggle_scratchpad
end
return M

View File

@@ -30,8 +30,6 @@ return {
},
max_workspace = 9,
scratchpad_size_ratio = 0.95,
dropdown_height_ratio = 0.5,
columns_layout = columns_layout,
large_main_layout = large_main_layout,
grid_layout = grid_layout,
@@ -58,48 +56,4 @@ return {
window_picker_candidates = {},
stack_update_timer = nil,
monocle_notice = nil,
scratchpad_pending = {},
monitor_reserved_cache_path = (os.getenv("XDG_RUNTIME_DIR") or "/tmp") .. "/hyprland-monitor-reserved.tsv",
scratchpad_fallback_reserved_top = 60,
scratchpads = {
codex = {
command = "codex-desktop",
class = "codex-desktop",
},
htop = {
command = "alacritty --class htop-scratch --title htop -e htop",
class = "htop-scratch",
},
volume = {
command = "pavucontrol",
class = "org.pulseaudio.pavucontrol",
},
spotify = {
command = "spotify",
class = "spotify",
},
element = {
command = "element-desktop",
classes = { "Element", "electron" },
title = "Element",
},
slack = {
command = "slack",
class = "Slack",
},
messages = {
command = "google-chrome-stable --profile-directory=Default --app=https://messages.google.com/web/conversations",
class = "chrome-messages.google.com",
},
transmission = {
command = "transmission-gtk",
class = "transmission-gtk",
},
dropdown = {
command = "ghostty --config-file=/home/imalison/.config/ghostty/dropdown",
class = "com.mitchellh.ghostty.dropdown",
dropdown = true,
},
},
}

View File

@@ -102,184 +102,6 @@ function M.setup(ctx)
minimized_windows = hydrated
end
local function window_workspace_name(window)
return window and window.workspace and window.workspace.name or ""
end
local function scratchpad_workspace(name)
return "special:scratch-" .. name
end
local function as_number(value, default)
local number = tonumber(value)
if number == nil then
return default
end
return number
end
local function logical_monitor_dimension(value, scale)
value = as_number(value, 0)
scale = as_number(scale, 1)
if scale <= 0 then
scale = 1
end
return math.floor((value / scale) + 0.5)
end
local function split_tsv(line)
local fields = {}
for field in (line .. "\t"):gmatch("([^\t]*)\t") do
fields[#fields + 1] = field
end
return fields
end
local function monitor_from_reserved_fields(monitor, fields)
if not monitor or not monitor.name or fields[1] ~= monitor.name or #fields < 10 then
return nil
end
return {
name = monitor.name,
x = tonumber(fields[2]),
y = tonumber(fields[3]),
width = tonumber(fields[4]),
height = tonumber(fields[5]),
scale = tonumber(fields[6]),
reserved = {
tonumber(fields[7]),
tonumber(fields[8]),
tonumber(fields[9]),
tonumber(fields[10]),
},
}
end
local function monitor_from_reserved_lines(monitor, lines)
if not monitor or not monitor.name then
return nil
end
for line in lines do
local cached = monitor_from_reserved_fields(monitor, split_tsv(line))
if cached then
return cached
end
end
return nil
end
local function monitor_from_reserved_cache(monitor)
if verify_config or not monitor or not monitor.name then
return nil
end
local file = io.open(monitor_reserved_cache_path, "r")
if not file then
return nil
end
local cached = monitor_from_reserved_lines(monitor, file:lines())
file:close()
return cached
end
local function refresh_monitor_reserved_cache(delay)
if verify_config then
return
end
local command = string.format(
[=[sleep %.2f; cache="${XDG_RUNTIME_DIR:-/tmp}/hyprland-monitor-reserved.tsv"; tmp="$cache.tmp"; /run/current-system/sw/bin/hyprctl -j monitors 2>/dev/null | /run/current-system/sw/bin/jq -r '.[] | [.name, .x, .y, .width, .height, .scale, .reserved[0], .reserved[1], .reserved[2], .reserved[3]] | @tsv' > "$tmp" && mv "$tmp" "$cache"]=],
as_number(delay, 0)
)
hl.exec_cmd("sh -lc " .. shell_quote(command))
end
local function monitor_workarea(monitor)
monitor = monitor_from_reserved_cache(monitor) or monitor
local width = logical_monitor_dimension(monitor.width, monitor.scale)
local height = logical_monitor_dimension(monitor.height, monitor.scale)
local reserved = monitor.reserved or { 0, scratchpad_fallback_reserved_top, 0, 0 }
local left = math.floor(as_number(reserved[1], 0))
local top = math.floor(as_number(reserved[2], 0))
local right = math.floor(as_number(reserved[3], 0))
local bottom = math.floor(as_number(reserved[4], 0))
local work_width = width - left - right
local work_height = height - top - bottom
if work_width <= 0 then
left = 0
right = 0
work_width = width
end
if work_height <= 0 then
top = 0
bottom = 0
work_height = height
end
return {
x = math.floor(as_number(monitor.x, 0)) + left,
y = math.floor(as_number(monitor.y, 0)) + top,
width = work_width,
height = work_height,
}
end
local function matching_scratchpad_windows(name)
local def = scratchpads[name]
local windows = {}
if not def then
return windows
end
for _, window in ipairs(hl.get_windows()) do
if scratchpad_window_matches(window, def) then
windows[#windows + 1] = window
end
end
return windows
end
local function apply_scratchpad_geometry(name, window, target_monitor)
local def = scratchpads[name]
local monitor = target_monitor or hl.get_active_monitor()
if not def or not window or not monitor then
return
end
local workarea = monitor_workarea(monitor)
local width
local height
local x
local y
if def.dropdown then
width = workarea.width
height = math.floor(workarea.height * dropdown_height_ratio)
x = workarea.x
y = workarea.y
else
width = math.floor(workarea.width * scratchpad_size_ratio)
height = math.floor(workarea.height * scratchpad_size_ratio)
x = workarea.x + math.floor((workarea.width - width) / 2)
y = workarea.y + math.floor((workarea.height - height) / 2)
end
local selector = window_selector(window)
dispatch(hl.dsp.window.float({ action = "enable", window = selector }))
dispatch(hl.dsp.window.tag({ tag = "+scratchpad", window = selector }))
dispatch(hl.dsp.window.tag({ tag = "+scratchpad-" .. name, window = selector }))
dispatch(hl.dsp.window.resize({ x = width, y = height, relative = false, window = selector }))
dispatch(hl.dsp.window.move({ x = x, y = y, relative = false, window = selector }))
if def.dropdown then
dispatch(hl.dsp.window.set_prop({ prop = "border_size", value = "0", window = selector }))
dispatch(hl.dsp.window.set_prop({ prop = "no_shadow", value = "1", window = selector }))
end
end
local function float_active_window_preserving_tiled_geometry()
local geometry = tiled_window_geometry(hl.get_active_window())
dispatch(hl.dsp.window.float({ action = "enable", window = geometry and geometry.selector or nil }))
@@ -319,90 +141,6 @@ function M.setup(ctx)
dispatch(hl.dsp.window.pin({ action = "enable", window = selector }))
end
local function schedule_scratchpad_geometry(name, window, target_monitor)
hl.timer(function()
apply_scratchpad_geometry(name, window, target_monitor)
end, { timeout = 50, type = "oneshot" })
end
local function hide_scratchpad_window(name, window)
remove_minimized_window(window)
move_window_to_workspace(scratchpad_workspace(name), false, window)
end
local function show_scratchpad_window(name, window, workspace, target_monitor)
workspace = workspace or active_workspace()
if not workspace then
return
end
remove_minimized_window(window)
move_window_to_workspace(workspace.id, false, window)
dispatch(hl.dsp.focus({ window = window_selector(window) }))
schedule_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor())
end
local function scratchpad_is_visible(window)
local workspace = active_workspace()
return workspace and window and same_workspace(window.workspace, workspace)
end
-- Active scratchpads are scratchpad windows visible on the active workspace.
-- Invoking a different scratchpad replaces that active set.
local function active_scratchpad_windows(except_name)
local windows = {}
for _, window in ipairs(hl.get_windows()) do
local name = matching_scratchpad_name(window)
if name and name ~= except_name and scratchpad_is_visible(window) then
windows[#windows + 1] = {
name = name,
window = window,
}
end
end
return windows
end
local function hide_active_scratchpads(except_name)
for _, active in ipairs(active_scratchpad_windows(except_name)) do
hide_scratchpad_window(active.name, active.window)
end
end
local function refresh_active_scratchpad_geometries()
local monitor = hl.get_active_monitor()
for _, active in ipairs(active_scratchpad_windows()) do
schedule_scratchpad_geometry(active.name, active.window, monitor)
end
end
local function refresh_active_scratchpad_geometries_later(timeout)
hl.timer(refresh_active_scratchpad_geometries, { timeout = timeout or 300, type = "oneshot" })
end
local function refresh_shell_workarea_and_scratchpads()
refresh_monitor_reserved_cache(0.15)
refresh_active_scratchpad_geometries_later(400)
end
local function adopt_matching_scratchpad_window(window)
if not window then
return
end
for name, def in pairs(scratchpads) do
if scratchpad_window_matches(window, def) then
if scratchpad_pending[name] then
local pending = scratchpad_pending[name]
scratchpad_pending[name] = nil
show_scratchpad_window(name, window, pending.workspace or active_workspace(), pending.monitor or hl.get_active_monitor())
elseif scratchpad_is_visible(window) then
schedule_scratchpad_geometry(name, window, hl.get_active_monitor())
end
end
end
end
local function current_minimized_windows()
hydrate_minimized_windows()
@@ -705,49 +443,6 @@ function M.setup(ctx)
minimized_windows = remaining
end
local function toggle_scratchpad(name)
local def = scratchpads[name]
if not def then
return
end
if current_layout == monocle_layout then
set_layout(columns_layout)
end
local windows = matching_scratchpad_windows(name)
if #windows == 0 then
hide_active_scratchpads(name)
scratchpad_pending[name] = {
monitor = hl.get_active_monitor(),
workspace = active_workspace(),
}
hl.exec_cmd(def.command)
return
end
local any_visible = false
for _, window in ipairs(windows) do
if scratchpad_is_visible(window) then
any_visible = true
break
end
end
if any_visible then
for _, window in ipairs(windows) do
hide_scratchpad_window(name, window)
end
else
hide_active_scratchpads(name)
local workspace = active_workspace()
local target_monitor = hl.get_active_monitor()
for _, window in ipairs(windows) do
show_scratchpad_window(name, window, workspace, target_monitor)
end
end
end
ctx.same_class_windows = same_class_windows
ctx.short_text = short_text
ctx.normal_windows = normal_windows
@@ -755,32 +450,10 @@ function M.setup(ctx)
ctx.remove_minimized_window = remove_minimized_window
ctx.add_minimized_window = add_minimized_window
ctx.hydrate_minimized_windows = hydrate_minimized_windows
ctx.window_workspace_name = window_workspace_name
ctx.scratchpad_workspace = scratchpad_workspace
ctx.as_number = as_number
ctx.logical_monitor_dimension = logical_monitor_dimension
ctx.split_tsv = split_tsv
ctx.monitor_from_reserved_fields = monitor_from_reserved_fields
ctx.monitor_from_reserved_lines = monitor_from_reserved_lines
ctx.monitor_from_reserved_cache = monitor_from_reserved_cache
ctx.refresh_monitor_reserved_cache = refresh_monitor_reserved_cache
ctx.monitor_workarea = monitor_workarea
ctx.matching_scratchpad_windows = matching_scratchpad_windows
ctx.apply_scratchpad_geometry = apply_scratchpad_geometry
ctx.float_active_window_preserving_tiled_geometry = float_active_window_preserving_tiled_geometry
ctx.float_and_drag_active_window = float_and_drag_active_window
ctx.float_and_resize_active_window = float_and_resize_active_window
ctx.toggle_pinned_active_window = toggle_pinned_active_window
ctx.schedule_scratchpad_geometry = schedule_scratchpad_geometry
ctx.hide_scratchpad_window = hide_scratchpad_window
ctx.show_scratchpad_window = show_scratchpad_window
ctx.scratchpad_is_visible = scratchpad_is_visible
ctx.active_scratchpad_windows = active_scratchpad_windows
ctx.hide_active_scratchpads = hide_active_scratchpads
ctx.refresh_active_scratchpad_geometries = refresh_active_scratchpad_geometries
ctx.refresh_active_scratchpad_geometries_later = refresh_active_scratchpad_geometries_later
ctx.refresh_shell_workarea_and_scratchpads = refresh_shell_workarea_and_scratchpads
ctx.adopt_matching_scratchpad_window = adopt_matching_scratchpad_window
ctx.current_minimized_windows = current_minimized_windows
ctx.restore_minimized_window = restore_minimized_window
ctx.window_picker_candidates_for = window_picker_candidates_for
@@ -795,7 +468,6 @@ function M.setup(ctx)
ctx.restore_all_minimized = restore_all_minimized
ctx.minimize_other_classes = minimize_other_classes
ctx.restore_focused_class = restore_focused_class
ctx.toggle_scratchpad = toggle_scratchpad
end
return M