Make scratchpad exclusivity stateful
This commit is contained in:
@@ -260,8 +260,15 @@ Required behavior:
|
|||||||
- A named scratchpad exists for volume.
|
- A named scratchpad exists for volume.
|
||||||
- A named scratchpad exists for x.com.
|
- A named scratchpad exists for x.com.
|
||||||
- Scratchpads appear near-fullscreen and centered by default.
|
- Scratchpads appear near-fullscreen and centered by default.
|
||||||
- Regular scratchpads can be tiled into the normal workspace when desired,
|
- Floating scratchpad behavior is a state of a window, not a property of its
|
||||||
while retaining their summon/dismiss toggles.
|
application class. Floating any window at scratchpad geometry enters that
|
||||||
|
state; tiling it leaves that state.
|
||||||
|
- Invoking a scratchpad replaces only another window currently in floating
|
||||||
|
scratchpad mode. Other floating windows are left alone.
|
||||||
|
- Regular scratchpad targets can be tiled into the normal workspace when
|
||||||
|
desired, while retaining their shortcut association.
|
||||||
|
- Summoning a scratchpad target with its shortcut always restores floating
|
||||||
|
scratchpad mode, even if the window was previously tiled.
|
||||||
- Toggling a scratchpad deactivates fullscreen/tabbed state first.
|
- Toggling a scratchpad deactivates fullscreen/tabbed state first.
|
||||||
- Floating scratchpads are hidden from normal workspace and window listings.
|
- Floating scratchpads are hidden from normal workspace and window listings.
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ function M.setup(ctx)
|
|||||||
dropdown_animation_frames = 18
|
dropdown_animation_frames = 18
|
||||||
dropdown_animation_frame_ms = 16
|
dropdown_animation_frame_ms = 16
|
||||||
scratchpad_pending = {}
|
scratchpad_pending = {}
|
||||||
|
scratchpad_mode_tag = "scratchpad"
|
||||||
monitor_reserved_cache_path = (os.getenv("XDG_RUNTIME_DIR") or "/tmp") .. "/hyprland-monitor-reserved.tsv"
|
monitor_reserved_cache_path = (os.getenv("XDG_RUNTIME_DIR") or "/tmp") .. "/hyprland-monitor-reserved.tsv"
|
||||||
scratchpad_fallback_reserved_top = 60
|
scratchpad_fallback_reserved_top = 60
|
||||||
|
|
||||||
@@ -100,15 +101,23 @@ function M.setup(ctx)
|
|||||||
return def.allow_tiling ~= false and window and window.floating == false
|
return def.allow_tiling ~= false and window and window.floating == false
|
||||||
end
|
end
|
||||||
|
|
||||||
local function is_scratchpad_window(window)
|
local function window_has_scratchpad_tag(window)
|
||||||
for _, def in pairs(scratchpads) do
|
for _, tag in ipairs((window and window.tags) or {}) do
|
||||||
if scratchpad_window_matches(window, def) and not tiled_scratchpad_is_normal_window(window, def) then
|
if tag == scratchpad_mode_tag then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function window_is_floating_scratchpad(window)
|
||||||
|
return window and window.floating == true and window_has_scratchpad_tag(window)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_scratchpad_window(window)
|
||||||
|
return window_is_floating_scratchpad(window)
|
||||||
|
end
|
||||||
|
|
||||||
local function matching_scratchpad_name(window)
|
local function matching_scratchpad_name(window)
|
||||||
for name, def in pairs(scratchpads) do
|
for name, def in pairs(scratchpads) do
|
||||||
if scratchpad_window_matches(window, def) then
|
if scratchpad_window_matches(window, def) then
|
||||||
@@ -122,6 +131,31 @@ function M.setup(ctx)
|
|||||||
return "name:scratch-hidden-" .. name
|
return "name:scratch-hidden-" .. name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function mark_window_as_floating_scratchpad(window, name)
|
||||||
|
local selector = window_selector(window)
|
||||||
|
if not selector then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
dispatch(hl.dsp.window.float({ action = "enable", window = selector }))
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "+" .. scratchpad_mode_tag, window = selector }))
|
||||||
|
if name then
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "+scratchpad-" .. name, window = selector }))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clear_floating_scratchpad_state(window)
|
||||||
|
local selector = window_selector(window)
|
||||||
|
if not selector then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "-" .. scratchpad_mode_tag, window = selector }))
|
||||||
|
for name in pairs(scratchpads) do
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "-scratchpad-" .. name, window = selector }))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function as_number(value, default)
|
local function as_number(value, default)
|
||||||
local number = tonumber(value)
|
local number = tonumber(value)
|
||||||
if number == nil then
|
if number == nil then
|
||||||
@@ -337,9 +371,7 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
local selector = window_selector(window)
|
local selector = window_selector(window)
|
||||||
|
|
||||||
dispatch(hl.dsp.window.float({ action = "enable", window = selector }))
|
mark_window_as_floating_scratchpad(window, name)
|
||||||
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 = geometry.width, y = geometry.height, relative = false, window = selector }))
|
dispatch(hl.dsp.window.resize({ x = geometry.width, y = geometry.height, relative = false, window = selector }))
|
||||||
dispatch(hl.dsp.window.move({ x = geometry.x, y = geometry.y, relative = false, window = selector }))
|
dispatch(hl.dsp.window.move({ x = geometry.x, y = geometry.y, relative = false, window = selector }))
|
||||||
if def.dropdown then
|
if def.dropdown then
|
||||||
@@ -382,7 +414,8 @@ function M.setup(ctx)
|
|||||||
|
|
||||||
local function hide_scratchpad_window(name, window)
|
local function hide_scratchpad_window(name, window)
|
||||||
remove_minimized_window(window)
|
remove_minimized_window(window)
|
||||||
move_window_to_workspace(scratchpad_workspace(name), false, window)
|
name = name or matching_scratchpad_name(window)
|
||||||
|
move_window_to_workspace(name and scratchpad_workspace(name) or "special:NSP", false, window)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function scratchpad_show_workspace(workspace)
|
local function scratchpad_show_workspace(workspace)
|
||||||
@@ -401,6 +434,7 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
|
|
||||||
remove_minimized_window(window)
|
remove_minimized_window(window)
|
||||||
|
mark_window_as_floating_scratchpad(window, name)
|
||||||
if scratchpads[name] and scratchpads[name].dropdown then
|
if scratchpads[name] and scratchpads[name].dropdown then
|
||||||
apply_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor(), "above")
|
apply_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor(), "above")
|
||||||
end
|
end
|
||||||
@@ -408,8 +442,10 @@ function M.setup(ctx)
|
|||||||
dispatch(hl.dsp.focus({ window = window_selector(window) }))
|
dispatch(hl.dsp.focus({ window = window_selector(window) }))
|
||||||
if scratchpads[name] and scratchpads[name].dropdown then
|
if scratchpads[name] and scratchpads[name].dropdown then
|
||||||
animate_dropdown_scratchpad_down(name, window, target_monitor or hl.get_active_monitor())
|
animate_dropdown_scratchpad_down(name, window, target_monitor or hl.get_active_monitor())
|
||||||
elseif should_apply_scratchpad_geometry(name, window, opts) then
|
else
|
||||||
schedule_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor(), nil, nil, opts)
|
schedule_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor(), nil, nil, {
|
||||||
|
force_geometry = true,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -418,17 +454,17 @@ function M.setup(ctx)
|
|||||||
return workspace and window and same_workspace(window.workspace, workspace)
|
return workspace and window and same_workspace(window.workspace, workspace)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Active scratchpads are scratchpad windows visible on the active workspace.
|
-- Scratchpad exclusivity belongs to a window's current presentation state,
|
||||||
-- Invoking a different scratchpad replaces that active set.
|
-- not its class. Invoking a named shortcut replaces any other window that is
|
||||||
|
-- visibly in floating scratchpad mode, including an otherwise ordinary app.
|
||||||
local function active_scratchpad_windows(except_name)
|
local function active_scratchpad_windows(except_name)
|
||||||
local windows = {}
|
local windows = {}
|
||||||
for _, window in ipairs(hl.get_windows()) do
|
for _, window in ipairs(hl.get_windows()) do
|
||||||
local name = matching_scratchpad_name(window)
|
local name = matching_scratchpad_name(window)
|
||||||
if
|
if
|
||||||
name
|
(except_name == nil or name ~= except_name)
|
||||||
and name ~= except_name
|
|
||||||
and scratchpad_is_visible(window)
|
and scratchpad_is_visible(window)
|
||||||
and not tiled_scratchpad_is_normal_window(window, scratchpads[name])
|
and window_is_floating_scratchpad(window)
|
||||||
then
|
then
|
||||||
windows[#windows + 1] = {
|
windows[#windows + 1] = {
|
||||||
name = name,
|
name = name,
|
||||||
@@ -474,7 +510,7 @@ function M.setup(ctx)
|
|||||||
show_scratchpad_window(name, window, pending.workspace or active_workspace(), pending.monitor or hl.get_active_monitor(), {
|
show_scratchpad_window(name, window, pending.workspace or active_workspace(), pending.monitor or hl.get_active_monitor(), {
|
||||||
force_geometry = true,
|
force_geometry = true,
|
||||||
})
|
})
|
||||||
elseif scratchpad_is_visible(window) then
|
elseif scratchpad_is_visible(window) and window_is_floating_scratchpad(window) then
|
||||||
schedule_scratchpad_geometry(name, window, hl.get_active_monitor())
|
schedule_scratchpad_geometry(name, window, hl.get_active_monitor())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -584,9 +620,13 @@ function M.setup(ctx)
|
|||||||
ctx.lower_contains_any = lower_contains_any
|
ctx.lower_contains_any = lower_contains_any
|
||||||
ctx.scratchpad_window_matches = scratchpad_window_matches
|
ctx.scratchpad_window_matches = scratchpad_window_matches
|
||||||
ctx.tiled_scratchpad_is_normal_window = tiled_scratchpad_is_normal_window
|
ctx.tiled_scratchpad_is_normal_window = tiled_scratchpad_is_normal_window
|
||||||
|
ctx.window_has_scratchpad_tag = window_has_scratchpad_tag
|
||||||
|
ctx.window_is_floating_scratchpad = window_is_floating_scratchpad
|
||||||
ctx.is_scratchpad_window = is_scratchpad_window
|
ctx.is_scratchpad_window = is_scratchpad_window
|
||||||
ctx.matching_scratchpad_name = matching_scratchpad_name
|
ctx.matching_scratchpad_name = matching_scratchpad_name
|
||||||
ctx.scratchpad_workspace = scratchpad_workspace
|
ctx.scratchpad_workspace = scratchpad_workspace
|
||||||
|
ctx.mark_window_as_floating_scratchpad = mark_window_as_floating_scratchpad
|
||||||
|
ctx.clear_floating_scratchpad_state = clear_floating_scratchpad_state
|
||||||
ctx.as_number = as_number
|
ctx.as_number = as_number
|
||||||
ctx.logical_monitor_dimension = logical_monitor_dimension
|
ctx.logical_monitor_dimension = logical_monitor_dimension
|
||||||
ctx.split_tsv = split_tsv
|
ctx.split_tsv = split_tsv
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ function M.setup(ctx)
|
|||||||
action = "set",
|
action = "set",
|
||||||
window = selector,
|
window = selector,
|
||||||
}))
|
}))
|
||||||
dispatch(hl.dsp.window.float({ action = "enable", window = selector }))
|
mark_window_as_floating_scratchpad(window, matching_scratchpad_name(window))
|
||||||
dispatch(hl.dsp.window.resize({ x = geometry.width, y = geometry.height, relative = false, window = selector }))
|
dispatch(hl.dsp.window.resize({ x = geometry.width, y = geometry.height, relative = false, window = selector }))
|
||||||
dispatch(hl.dsp.window.move({ x = geometry.x, y = geometry.y, relative = false, window = selector }))
|
dispatch(hl.dsp.window.move({ x = geometry.x, y = geometry.y, relative = false, window = selector }))
|
||||||
end
|
end
|
||||||
@@ -153,6 +153,7 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if window.floating then
|
if window.floating then
|
||||||
|
clear_floating_scratchpad_state(window)
|
||||||
dispatch(hl.dsp.window.float({ action = "disable", window = selector }))
|
dispatch(hl.dsp.window.float({ action = "disable", window = selector }))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user