first pass of hyprland config
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# `config`
|
||||
|
||||
My tool and machine configuration ranging from `~/.config` symlinks to libraries which support my daily workflows.
|
||||
|
||||
The [`setup`](../setup) and [`scwrypts`](../scwrypts) handle the setup / maintenance details, but contained herein:
|
||||
|
||||
<!------------------------------------------------------------------------------------------------------------>
|
||||
| Submodule | Description |
|
||||
| ------------------------------------ | -------------------------------------------------------------------- |
|
||||
| [`bin`](./bin) | goes on my `${PATH}`; used in limited cases |
|
||||
| [`colorschemes`](./colorschemes) | my colorscheme YAML definitions which style all my desktop apps; uses the [spec established in `dotwryn/scwrypts`](../scwrypts/dotwryn/desktop/colorscheme/coloscheme.module.zsh) |
|
||||
| [`desktop`](./desktop) | utilities which configure, support, or launch a desktop environment |
|
||||
| [`etc`](./etc) | config files linked back to `/etc` on the local system |
|
||||
| [`host-overrides`](./host-overrides) | hostname-based values overrides for `etc`, `user`, and `bin` |
|
||||
| [`user`](./user) | config files linked back to `${XDG_CONFIG_HOME:-${HOME}/.config` |
|
||||
<!------------------------------------------------------------------------------------------------------------>
|
||||
@@ -0,0 +1,48 @@
|
||||
# config : bin
|
||||
|
||||
This directory contains shell one-offs which solve focused problems.
|
||||
Generally, `scwrypts` are a better source for long-term maintenance, but, for a _few selected scenarios_, a raw shell script is preferred.
|
||||
This is typically due to:
|
||||
|
||||
1. The simplicity of the script outweighs the maintenance overhead for an equivalent `scwrypt`
|
||||
2. The overhead of `scwrypts` causes excessive slowdowns for quick, simple tasks
|
||||
|
||||
## Reference / Usage
|
||||
|
||||
All scripts in this directory support and can be used in one of two ways:
|
||||
|
||||
1. Direct reference through `${DOTWRYN}/config/bin/${script_name}`
|
||||
2. Symlinked on the user's `${PATH}`
|
||||
|
||||
### Direct Reference
|
||||
|
||||
Anytime a raw script is referenced throughout the `dotwryn` repository, it should be referenced with _direct reference_.
|
||||
`dotwryn`-internal operations must not assume the user has a symlink to any of these functions.
|
||||
|
||||
### Symlink
|
||||
|
||||
An API for human users!
|
||||
All the scripts in this directory allow for symlinking.
|
||||
|
||||
```zsh
|
||||
# you can decide where it goes
|
||||
ln -s "${DOTWRYN}/config/bin/${script_name}" "${somewhere_on_users_path}/${local_script_name}"
|
||||
|
||||
# since ~/.local/bin is on MY ${PATH} (and I want it to have the same name)
|
||||
cd ~/.local/bin
|
||||
ln -s "${DOTWRYN}/config/bin/${script_name}"
|
||||
```
|
||||
|
||||
<!--
|
||||
## NOTES TO AGENTS
|
||||
|
||||
Do not add new bin/ scripts without explicit approval and review from the human maintainer.
|
||||
|
||||
### Direct Reference : It's actually a scwrypt
|
||||
|
||||
If a `scwrypt` intends to reference one of these scripts directly, STOP.
|
||||
This is an indicator that the `bin/` script must be built or refactored [in `scwrypts`](../scwrypts).
|
||||
|
||||
- If the `bin/` script in question is a _new_ script, proceed to develop it as a scwrypt.
|
||||
- If the `bin/` script in question is an _existing_ script, you must now confirm with the human maintainer on how to proceed.
|
||||
-->
|
||||
@@ -0,0 +1,41 @@
|
||||
--
|
||||
-- dotwryn hyprland configuration library
|
||||
--
|
||||
|
||||
local DOTWRYN = os.getenv("DOTWRYN")
|
||||
local dotwryn = {
|
||||
DOTWRYN = DOTWRYN,
|
||||
|
||||
colorscheme = dofile(DOTWRYN .. "/scwrypts/dotwryn/desktop/colorscheme/colorscheme.lua").load(),
|
||||
scwrypts = dofile(DOTWRYN .. "/config/desktop/hyprland/scwrypts.lua"),
|
||||
|
||||
font = {
|
||||
family = table.concat({
|
||||
"Pokémoji Color",
|
||||
"Monaspace Argon",
|
||||
}, ", "),
|
||||
|
||||
size = 11,
|
||||
},
|
||||
}
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
local config_filepaths = {}
|
||||
|
||||
local config_dir = (DOTWRYN .. "/config/desktop/hyprland/config.lua.d")
|
||||
local config_dir_quoted = config_dir:gsub("'", "'\\''")
|
||||
|
||||
assert(io.open(config_dir, "r"), "error reading hyprland config.lua.d : " .. config_dir)
|
||||
|
||||
local find = io.popen("find '" .. config_dir_quoted .. "' -mindepth 1 -maxdepth 1 -type f -name '*.lua'")
|
||||
for config_filepath in find:lines() do
|
||||
table.insert(config_filepaths, config_filepath)
|
||||
end
|
||||
find:close()
|
||||
|
||||
table.sort(config_filepaths)
|
||||
|
||||
for _, config_filepath in ipairs(config_filepaths) do
|
||||
assert(loadfile(config_filepath))(dotwryn)
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- hyprland-base configuration
|
||||
--
|
||||
|
||||
hl.config({
|
||||
ecosystem = {
|
||||
no_update_news = true,
|
||||
no_donation_nag = true,
|
||||
},
|
||||
|
||||
input = {
|
||||
kb_layout = "us",
|
||||
},
|
||||
|
||||
misc = {
|
||||
font_family = dotwryn.font.family,
|
||||
force_default_wallpaper = 0,
|
||||
disable_hyprland_logo = true,
|
||||
disable_splash_rendering = true,
|
||||
},
|
||||
})
|
||||
|
||||
hl.monitor({
|
||||
output = "",
|
||||
mode = "preferred",
|
||||
position = "auto",
|
||||
scale = "auto",
|
||||
})
|
||||
|
||||
------------------------------------------
|
||||
|
||||
hl.bind("SUPER + SHIFT + e", hl.dsp.exec_cmd("qs ipc call logout show"))
|
||||
hl.bind("CTRL + ALT + Delete", hl.dsp.exit())
|
||||
hl.bind("SUPER + SHIFT + r", hl.dsp.exec_cmd("hyprctl reload"))
|
||||
hl.bind("SUPER + SHIFT + c", hl.dsp.exec_cmd("hyprctl reload"))
|
||||
@@ -0,0 +1,25 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- high-dpi scaling : XWayland apps render at 1x and scale themselves
|
||||
--
|
||||
|
||||
hl.config({
|
||||
xwayland = {
|
||||
force_zero_scaling = true,
|
||||
},
|
||||
})
|
||||
|
||||
-- force_zero_scaling leaves steam at 1x; match the active monitor's scale instead
|
||||
local set_steam_scaling = function()
|
||||
local monitor = hl.get_active_monitor()
|
||||
if monitor == nil or monitor.scale == nil or monitor.scale <= 0 then return end
|
||||
|
||||
hl.env("STEAM_FORCE_DESKTOPUI_SCALING", tostring(monitor.scale))
|
||||
end
|
||||
|
||||
set_steam_scaling()
|
||||
|
||||
for _, event in ipairs({ "monitor.added", "monitor.removed", "monitor.layout_changed" }) do
|
||||
hl.on(event, set_steam_scaling)
|
||||
end
|
||||
@@ -0,0 +1,12 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
|
||||
hl.config({ animations = { enabled = true } })
|
||||
|
||||
hl.curve("easeOutQuint", { type = "bezier", points = { {0.23, 1}, {0.32, 1} } })
|
||||
|
||||
hl.animation({ leaf = "global", enabled = false })
|
||||
hl.animation({ leaf = "windows", enabled = true, speed = 3, bezier = "easeOutQuint", style = "slide" })
|
||||
hl.animation({ leaf = "layers", enabled = true, speed = 3, bezier = "easeOutQuint", style = "popin" })
|
||||
hl.animation({ leaf = "workspaces", enabled = true, speed = 3, bezier = "easeOutQuint", style = "slide" })
|
||||
hl.animation({ leaf = "border", enabled = true, speed = 3, bezier = "easeOutQuint" })
|
||||
@@ -0,0 +1,79 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- as a long-time i3wm user, my dwindle configuration contains tries to
|
||||
-- make the transition feel smooth
|
||||
--
|
||||
-- <https://wiki.hypr.land/Configuring/Layouts/Dwindle-Layout/>
|
||||
--
|
||||
|
||||
local colors = {
|
||||
active = {
|
||||
border = dotwryn.colorscheme.get_hex(".dwindle.colors.active.border", ".i3.focused.border", ".material.secondary.500", ".ansi.green.bright"),
|
||||
text = dotwryn.colorscheme.get_hex(".dwindle.colors.active.text", ".i3.focused.text", ".material.foreground.secondary.500", ".foreground"),
|
||||
locked = dotwryn.colorscheme.get_hex(".dwindle.colors.active.locked", ".i3.urgent.border", ".material.error.500", ".ansi.red.bright"),
|
||||
},
|
||||
|
||||
inactive = {
|
||||
border = dotwryn.colorscheme.get_hex(".dwindle.colors.inactive.border", ".i3.unfocused.border", ".material.primary.700", ".ansi.yellow.bright"),
|
||||
text = dotwryn.colorscheme.get_hex(".dwindle.colors.inactive.text", ".i3.unfocused.text", ".material.foreground.primary.700", ".foreground"),
|
||||
locked = dotwryn.colorscheme.get_hex(".dwindle.colors.inactive.locked", ".i3.inactive.border", ".material.primary.700", ".ansi.yellow.bright"),
|
||||
},
|
||||
}
|
||||
|
||||
hl.config({
|
||||
general = {
|
||||
layout = "dwindle",
|
||||
|
||||
border_size = 4,
|
||||
gaps_in = 0,
|
||||
gaps_out = 0,
|
||||
|
||||
resize_on_border = false,
|
||||
|
||||
col = {
|
||||
active_border = colors.active.border,
|
||||
inactive_border = colors.inactive.border,
|
||||
},
|
||||
},
|
||||
|
||||
dwindle = { preserve_split = true },
|
||||
input = { follow_mouse = 1 },
|
||||
binds = { movefocus_cycles_groupfirst = true },
|
||||
|
||||
decoration = {
|
||||
rounding = 0,
|
||||
shadow = { enabled = false },
|
||||
blur = { enabled = false },
|
||||
},
|
||||
|
||||
-- currently treating dwindle "groups" like an i3 "tabbed"
|
||||
group = {
|
||||
col = {
|
||||
border_active = colors.active.border,
|
||||
border_inactive = colors.inactive.border,
|
||||
border_locked_active = colors.active.locked,
|
||||
border_locked_inactive = colors.inactive.locked,
|
||||
},
|
||||
|
||||
groupbar = {
|
||||
font_family = dotwryn.font.family,
|
||||
font_size = dotwryn.font.size,
|
||||
height = 22,
|
||||
gradients = true,
|
||||
rounding = 0,
|
||||
gradient_rounding = 0,
|
||||
render_titles = true,
|
||||
|
||||
text_color = colors.active.text,
|
||||
text_color_inactive = colors.inactive.text,
|
||||
|
||||
col = {
|
||||
active = colors.active.border,
|
||||
inactive = colors.inactive.border,
|
||||
locked_active = colors.active.locked,
|
||||
locked_inactive = colors.inactive.locked,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,44 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- i3wm & vim-style window navigation
|
||||
--
|
||||
|
||||
-- moves a window through groups to recreate i3wm tab behavior
|
||||
local move_window = function(direction)
|
||||
return function()
|
||||
local window = hl.get_active_window()
|
||||
local group = window ~= nil and window.group or nil
|
||||
|
||||
if group ~= nil and group.size > 1 and (direction == "left" or direction == "right") then
|
||||
local at_edge = (direction == "left" and group.current_index <= 1)
|
||||
or (direction == "right" and group.current_index >= group.size)
|
||||
if not at_edge then
|
||||
hl.dispatch(hl.dsp.group.move_window({ forward = direction == "right" }))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
hl.dispatch(hl.dsp.window.move({ direction = direction, group_aware = true }))
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------
|
||||
|
||||
for key, direction in pairs({ h = "left", j = "down", k = "up", l = "right" }) do
|
||||
hl.bind("SUPER + " .. key, hl.dsp.focus({ direction = direction }))
|
||||
hl.bind("SUPER + SHIFT + " .. key, move_window(direction))
|
||||
end
|
||||
|
||||
hl.bind("SUPER + f", hl.dsp.window.fullscreen({ mode = "fullscreen" }))
|
||||
|
||||
hl.bind("SUPER + q", hl.dsp.window.close())
|
||||
|
||||
-- i3 'layout toggle split'
|
||||
hl.bind("SUPER + e", hl.dsp.layout("togglesplit"))
|
||||
|
||||
-- i3 'layout tabbed' / 'layout stacking' : both toggle a group
|
||||
hl.bind("SUPER + w", hl.dsp.group.toggle())
|
||||
hl.bind("SUPER + s", hl.dsp.group.toggle())
|
||||
|
||||
-- (no equivalent) bindsym $mod+BackSpace open
|
||||
@@ -0,0 +1,28 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- i3wm-style resize mode
|
||||
--
|
||||
|
||||
local resize = function(x, y)
|
||||
return function()
|
||||
local monitor = hl.get_active_monitor()
|
||||
local scale = (monitor ~= nil and monitor.scale ~= nil and monitor.scale > 0) and monitor.scale or 1
|
||||
local step_x = monitor ~= nil and math.floor(monitor.width / scale * 0.1) or 10
|
||||
local step_y = monitor ~= nil and math.floor(monitor.height / scale * 0.1) or 10
|
||||
hl.dispatch(hl.dsp.window.resize({ x = x * step_x, y = y * step_y, relative = true }))
|
||||
end
|
||||
end
|
||||
|
||||
hl.bind("SUPER + r", hl.dsp.submap("resize"))
|
||||
|
||||
hl.define_submap("resize", function()
|
||||
hl.bind("h", resize( 1, 0), { repeating = true })
|
||||
hl.bind("j", resize( 0, -1), { repeating = true })
|
||||
hl.bind("k", resize( 0, 1), { repeating = true })
|
||||
hl.bind("l", resize(-1, 0), { repeating = true })
|
||||
|
||||
hl.bind("Return", hl.dsp.submap("reset"))
|
||||
hl.bind("Escape", hl.dsp.submap("reset"))
|
||||
hl.bind("SUPER + r", hl.dsp.submap("reset"))
|
||||
end)
|
||||
@@ -0,0 +1,128 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- i3wm-style floating windows and scratchpad
|
||||
--
|
||||
|
||||
hl.bind("SUPER + SHIFT + space", hl.dsp.window.float({ action = "toggle" }))
|
||||
|
||||
hl.bind("SUPER + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
||||
hl.bind("SUPER + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
||||
|
||||
local SCRATCHPAD = "special:scratchpad"
|
||||
|
||||
local SCRATCHPAD_FILTERS = {
|
||||
terminal = { "^Alacritty$", "^kitty$" },
|
||||
games = { "^steam$", "^dolphin%-emu$", "^Visualboyadvance%-m$", "^steam_app_" },
|
||||
}
|
||||
|
||||
local matches_filter = function(class, filter)
|
||||
if filter == nil then
|
||||
for name, _ in pairs(SCRATCHPAD_FILTERS) do
|
||||
if matches_filter(class, name) then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
for _, pattern in ipairs(SCRATCHPAD_FILTERS[filter]) do
|
||||
if class ~= nil and class:match(pattern) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local workspace_selector = function(workspace)
|
||||
return workspace.id > 0 and tostring(workspace.id) or ("name:" .. workspace.name)
|
||||
end
|
||||
|
||||
local scratchpad_shown = {}
|
||||
local scratchpad_queue = {}
|
||||
|
||||
local scratchpad_enqueue = function(address)
|
||||
for index, queued in ipairs(scratchpad_queue) do
|
||||
if queued == address then table.remove(scratchpad_queue, index) break end
|
||||
end
|
||||
table.insert(scratchpad_queue, address)
|
||||
end
|
||||
|
||||
local scratchpad_windows = function()
|
||||
local stashed = {}
|
||||
for _, window in ipairs(hl.get_workspace_windows(SCRATCHPAD)) do stashed[window.address] = window end
|
||||
|
||||
local ordered = {}
|
||||
for _, address in ipairs(scratchpad_queue) do
|
||||
if stashed[address] ~= nil then
|
||||
table.insert(ordered, stashed[address])
|
||||
stashed[address] = nil
|
||||
end
|
||||
end
|
||||
for address, window in pairs(stashed) do
|
||||
table.insert(ordered, window)
|
||||
scratchpad_enqueue(address)
|
||||
end
|
||||
return ordered
|
||||
end
|
||||
|
||||
local scratchpad_fit = function(selector)
|
||||
local monitor = hl.get_active_monitor()
|
||||
if monitor ~= nil then
|
||||
local scale = (monitor.scale ~= nil and monitor.scale > 0) and monitor.scale or 1
|
||||
hl.dispatch(hl.dsp.window.resize({
|
||||
window = selector,
|
||||
x = math.floor(monitor.width / scale * 0.75),
|
||||
y = math.floor(monitor.height / scale * 0.75),
|
||||
}))
|
||||
end
|
||||
hl.dispatch(hl.dsp.window.center({ window = selector }))
|
||||
end
|
||||
|
||||
hl.bind("SUPER + SHIFT + Tab", function()
|
||||
local window = hl.get_active_window()
|
||||
if window == nil then return end
|
||||
|
||||
local selector = "address:" .. window.address
|
||||
hl.dispatch(hl.dsp.window.float({ window = selector, action = "enable" }))
|
||||
scratchpad_fit(selector)
|
||||
hl.dispatch(hl.dsp.window.move({ window = selector, workspace = SCRATCHPAD, follow = false }))
|
||||
scratchpad_shown[window.address] = nil
|
||||
scratchpad_enqueue(window.address)
|
||||
end)
|
||||
|
||||
local scratchpad_show = function(filter)
|
||||
return function()
|
||||
local workspace = hl.get_active_workspace()
|
||||
if workspace == nil then return end
|
||||
|
||||
local active = hl.get_active_window()
|
||||
local candidates = {}
|
||||
if filter == nil and active ~= nil and scratchpad_shown[active.address] then
|
||||
table.insert(candidates, active.address)
|
||||
end
|
||||
for address, _ in pairs(scratchpad_shown) do table.insert(candidates, address) end
|
||||
|
||||
for _, address in ipairs(candidates) do
|
||||
local window = hl.get_window("address:" .. address)
|
||||
if window == nil or window.workspace == nil or window.workspace.name == SCRATCHPAD then
|
||||
scratchpad_shown[address] = nil
|
||||
elseif window.workspace.id == workspace.id and (filter == nil or matches_filter(window.class, filter)) then
|
||||
hl.dispatch(hl.dsp.window.move({ window = "address:" .. address, workspace = SCRATCHPAD, follow = false }))
|
||||
scratchpad_shown[address] = nil
|
||||
scratchpad_enqueue(address)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
for _, window in ipairs(scratchpad_windows()) do
|
||||
if matches_filter(window.class, filter) then
|
||||
local selector = "address:" .. window.address
|
||||
hl.dispatch(hl.dsp.window.move({ window = selector, workspace = workspace_selector(workspace), follow = false }))
|
||||
scratchpad_fit(selector)
|
||||
hl.dispatch(hl.dsp.focus({ window = selector }))
|
||||
scratchpad_shown[window.address] = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hl.bind("SUPER + Tab", scratchpad_show(nil))
|
||||
hl.bind("SUPER + x", scratchpad_show("terminal"))
|
||||
hl.bind("SUPER + SHIFT + x", scratchpad_show("games"))
|
||||
@@ -0,0 +1,32 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- desktop workspace settings
|
||||
--
|
||||
|
||||
dotwryn.workspace_defaults = {
|
||||
gaps = { inner = "0.5%", outer = "1%" },
|
||||
}
|
||||
|
||||
dotwryn.workspaces = {
|
||||
{ key = "1", name = "1" },
|
||||
{ key = "2", name = "2", gaps = { enabled = false } },
|
||||
{ key = "3", name = "3" },
|
||||
{ key = "4", name = "4" },
|
||||
{ key = "5", name = "5" },
|
||||
{ key = "6", name = "6" },
|
||||
{ key = "7", name = "7" },
|
||||
{ key = "8", name = "8" },
|
||||
{ key = "9", name = "9" },
|
||||
|
||||
{ key = "g", name = "100", label = "🎮", vertical = true, },
|
||||
{ key = "0", name = "name:🎧", vertical = true, },
|
||||
}
|
||||
|
||||
for _, workspace in ipairs(dotwryn.workspaces) do
|
||||
if workspace.label ~= nil then
|
||||
hl.workspace_rule({ workspace = workspace.name, default_name = workspace.label })
|
||||
end
|
||||
|
||||
hl.bind("SUPER + SHIFT + " .. workspace.key, hl.dsp.window.move({ workspace = workspace.name, follow = false }))
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- workspace navigation with per-switch slide direction
|
||||
--
|
||||
|
||||
local VERTICAL_WORKSPACES = {} -- by target ("100", "name:🎧") and display name ("🎮", "🎧")
|
||||
for _, workspace in ipairs(dotwryn.workspaces) do
|
||||
if workspace.vertical then
|
||||
VERTICAL_WORKSPACES[workspace.name] = true
|
||||
VERTICAL_WORKSPACES[workspace.label or (workspace.name:gsub("^name:", ""))] = true
|
||||
end
|
||||
end
|
||||
|
||||
function animate_workspace_focus(name)
|
||||
local active = hl.get_active_workspace()
|
||||
local vertical = VERTICAL_WORKSPACES[name]
|
||||
or (active ~= nil and VERTICAL_WORKSPACES[active.name])
|
||||
|
||||
hl.animation({ leaf = "workspaces", enabled = true, speed = 3, bezier = "easeOutQuint", style = vertical and "slidevert" or "slide" })
|
||||
hl.dispatch(hl.dsp.focus({ workspace = name }))
|
||||
end
|
||||
|
||||
for _, workspace in ipairs(dotwryn.workspaces) do
|
||||
if workspace.name ~= "2" then -- (special case below)
|
||||
hl.bind("SUPER + " .. workspace.key, function() animate_workspace_focus(workspace.name) end)
|
||||
end
|
||||
end
|
||||
|
||||
-- workspace 2 is home to the 'omni' tmux session; open a terminal if nothing is attached
|
||||
hl.bind("SUPER + 2", function()
|
||||
animate_workspace_focus("2")
|
||||
hl.dispatch(hl.dsp.exec_cmd("[[ $(tmux -L omni.socket list-clients 2>/dev/null | wc -l) -eq 0 ]] && $TERMINAL"))
|
||||
end)
|
||||
@@ -0,0 +1,73 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
--
|
||||
-- provides per-workspace gaps settings
|
||||
--
|
||||
|
||||
local get_gaps_config = function(workspace)
|
||||
local gaps = {}
|
||||
for key, value in pairs(dotwryn.workspace_defaults.gaps) do gaps[key] = value end
|
||||
for key, value in pairs(workspace.gaps or {}) do gaps[key] = value end
|
||||
return gaps
|
||||
end
|
||||
|
||||
local to_pixels = function(value)
|
||||
local percent = type(value) == "string" and tonumber((value:gsub("%%$", ""))) or nil
|
||||
if percent == nil then return value end
|
||||
|
||||
local monitor = hl.get_active_monitor()
|
||||
if monitor == nil then return 0 end -- (recomputed once a monitor shows up)
|
||||
|
||||
local scale = (monitor.scale ~= nil and monitor.scale > 0) and monitor.scale or 1
|
||||
return math.floor(math.min(monitor.width, monitor.height) / scale * percent / 100)
|
||||
end
|
||||
|
||||
local gaps_rules = {}
|
||||
local set_gaps = function(workspace, inner, outer)
|
||||
if gaps_rules[workspace] ~= nil then gaps_rules[workspace].rule:set_enabled(false) end
|
||||
gaps_rules[workspace] = {
|
||||
inner = inner,
|
||||
outer = outer,
|
||||
rule = hl.workspace_rule({ workspace = workspace, gaps_in = inner, gaps_out = outer }),
|
||||
}
|
||||
end
|
||||
|
||||
local apply_gaps = function()
|
||||
for _, workspace in ipairs(dotwryn.workspaces) do
|
||||
local gaps = get_gaps_config(workspace)
|
||||
if gaps.enabled == false then
|
||||
set_gaps(workspace.name, 0, 0)
|
||||
else
|
||||
set_gaps(workspace.name, to_pixels(gaps.inner), to_pixels(gaps.outer))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
apply_gaps()
|
||||
|
||||
for _, event in ipairs({ "monitor.added", "monitor.removed", "monitor.layout_changed" }) do
|
||||
hl.on(event, apply_gaps)
|
||||
end
|
||||
|
||||
hl.window_rule({
|
||||
name = "smart-no-borders",
|
||||
match = { float = false, group = false, workspace = "s[false] w[tv1]" },
|
||||
border_size = 0,
|
||||
})
|
||||
|
||||
local GAPS_STEP = "0.5%"
|
||||
|
||||
local adjust_gaps = function(direction)
|
||||
return function()
|
||||
local workspace = hl.get_active_workspace()
|
||||
if workspace == nil then return end
|
||||
|
||||
local name = workspace.id > 0 and tostring(workspace.id) or ("name:" .. workspace.name)
|
||||
local current = gaps_rules[name] or { inner = 0, outer = 0 }
|
||||
local delta = direction * math.max(1, to_pixels(GAPS_STEP))
|
||||
set_gaps(name, math.max(0, current.inner + delta), math.max(0, current.outer + delta))
|
||||
end
|
||||
end
|
||||
|
||||
hl.bind("SUPER + z", adjust_gaps( 1), { repeating = true })
|
||||
hl.bind("SUPER + SHIFT + z", adjust_gaps(-1), { repeating = true })
|
||||
@@ -0,0 +1,56 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
|
||||
local bind = function(bindings, ...)
|
||||
for keys, dispatcher in pairs(bindings) do
|
||||
hl.bind(keys, dispatcher, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local set_background =
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
bind({
|
||||
["XF86AudioRewind"] = hl.dsp.exec_cmd("playerctl previous"),
|
||||
["XF86AudioPrev"] = hl.dsp.exec_cmd("playerctl previous"),
|
||||
["XF86AudioForward"] = hl.dsp.exec_cmd("playerctl next"),
|
||||
["XF86AudioNext"] = hl.dsp.exec_cmd("playerctl next"),
|
||||
["XF86AudioPlay"] = hl.dsp.exec_cmd("playerctl play-pause"),
|
||||
|
||||
["XF86AudioMute"] = hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"),
|
||||
["XF86AudioMicMute"] = hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"),
|
||||
}, { locked = true })
|
||||
|
||||
------------------------------------------
|
||||
|
||||
bind({
|
||||
["XF86AudioRaiseVolume"] = hl.dsp.exec_cmd("qs ipc call volume up"), -- ../../../user/quickshell/VolumeOsd.qml "going past 100%"
|
||||
["XF86AudioLowerVolume"] = hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 10%-"),
|
||||
}, { locked = true, repeating = true })
|
||||
|
||||
------------------------------------------
|
||||
|
||||
bind({
|
||||
["SUPER + SHIFT + m"] = dotwryn.scwrypts.hyprland.launch_or_show("slack"),
|
||||
["SUPER + SHIFT + d"] = dotwryn.scwrypts.hyprland.launch_or_show("fluxer", "-c", "Fluxer"),
|
||||
["SUPER + c"] = dotwryn.scwrypts.hyprland.launch_or_show("google-voice-desktop"),
|
||||
["SUPER + m"] = dotwryn.scwrypts.hyprland.launch_or_show("youtube-music-desktop-app", "-c", "YouTube Music Desktop App"),
|
||||
["SUPER + SHIFT + s"] = dotwryn.scwrypts.hyprland.launch_or_show("signal"),
|
||||
["SUPER + a"] = dotwryn.scwrypts.hyprland.launch_or_show("pavucontrol", "-s", "0.5", "-c", "pavucontrol"),
|
||||
["SUPER + SHIFT + o"] = dotwryn.scwrypts.hyprland.launch_or_show("obs", "-c", "^obs", "-n", "-l"),
|
||||
["SUPER + Return"] = hl.dsp.exec_cmd("$TERMINAL"),
|
||||
|
||||
["SUPER + p"] = dotwryn.scwrypts.hyprland.set_background("random"),
|
||||
["SUPER + SHIFT + p"] = dotwryn.scwrypts.hyprland.set_background("theme"),
|
||||
|
||||
["SUPER + SHIFT + minus"] = hl.dsp.exec_cmd("pidof hyprlock || hyprlock"),
|
||||
["SUPER + space"] = hl.dsp.exec_cmd("rofi -theme $DOTWRYN/config/rofi.theme.rasi -modes drun,run -show run"),
|
||||
["SUPER + backslash"] = dotwryn.scwrypts.hyprland.screenshot(),
|
||||
|
||||
--
|
||||
-- global application shortcuts (wayland apps can't grab global keys)
|
||||
--
|
||||
|
||||
["ALT + SHIFT + space"] = hl.dsp.exec_cmd("1password --quick-access"),
|
||||
})
|
||||
@@ -0,0 +1,25 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
|
||||
hl.window_rule({ name = "float-modal", match = { modal = true }, float = true })
|
||||
|
||||
hl.window_rule({
|
||||
name = "float-dialog-titles",
|
||||
match = { title = "^(About|Organizer|Preferences|Task Dialog|Toolbox|Web Console).*$" },
|
||||
float = true,
|
||||
})
|
||||
|
||||
hl.window_rule({
|
||||
name = "screenshot-flameshot", -- scwrypts hyprland screenshot
|
||||
match = { class = "^flameshot$" },
|
||||
float = true,
|
||||
move = "0 0",
|
||||
pin = true,
|
||||
no_anim = true,
|
||||
})
|
||||
|
||||
hl.window_rule({
|
||||
name = "games-workspace",
|
||||
match = { class = "^steam_app_.*$" },
|
||||
workspace = "100", -- 🎮
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
|
||||
local hostnamectl = io.popen("hostnamectl --static")
|
||||
local HOSTNAME = hostnamectl:read("l")
|
||||
hostnamectl:close()
|
||||
|
||||
local dofile_if_exists = function(path)
|
||||
local file = io.open(path, "r")
|
||||
if file == nil then return end
|
||||
file:close()
|
||||
dofile(path)
|
||||
end
|
||||
|
||||
------------------------------------------
|
||||
|
||||
dofile_if_exists(dotwryn.DOTWRYN .. "/config/local/" .. HOSTNAME .. "/user/hypr/host.lua")
|
||||
dofile_if_exists((os.getenv("XDG_CONFIG_HOME") or (os.getenv("HOME") .. "/.config")) .. "/hypr/local.lua")
|
||||
@@ -0,0 +1,12 @@
|
||||
local dotwryn = ... -- ../config.lua
|
||||
---------------------------------------------------------------------
|
||||
|
||||
hl.on("hyprland.start", function()
|
||||
hl.dispatch(dotwryn.scwrypts.hyprland.set_background("theme")) -- (starts hyprpaper if it isn't running)
|
||||
hl.dispatch(dotwryn.scwrypts.wayland.sync_gtk_settings()) -- gtk theme from settings.ini
|
||||
hl.exec_cmd("quickshell")
|
||||
hl.exec_cmd("1password --silent")
|
||||
hl.dispatch(dotwryn.scwrypts.tmux.omni())
|
||||
hl.exec_cmd("/usr/lib/xfce-polkit/xfce-polkit")
|
||||
hl.exec_cmd("command -v apps && apps") -- host-local background apps ($DOTWRYN/config/local/<hostname>/bin/apps)
|
||||
end)
|
||||
@@ -0,0 +1,78 @@
|
||||
--
|
||||
-- custom (temporary?) interface to scwrypts for hyprland lua
|
||||
--
|
||||
|
||||
local scwrypts = function(args_meta, args_scwrypt, environment)
|
||||
local get_quoted = function(args)
|
||||
local quoted_args = {}
|
||||
for _, arg in ipairs(args) do
|
||||
table.insert(quoted_args, "'" .. arg:gsub("'", "'\\''") .. "'")
|
||||
end
|
||||
return table.concat(quoted_args, " ")
|
||||
end
|
||||
|
||||
local environment_names = {}
|
||||
for name, _ in pairs(environment or {}) do table.insert(environment_names, name) end
|
||||
table.sort(environment_names)
|
||||
|
||||
local environment_assignments = {}
|
||||
for _, name in ipairs(environment_names) do
|
||||
table.insert(environment_assignments, name .. "=" .. get_quoted({ environment[name] }))
|
||||
end
|
||||
|
||||
return table.concat({
|
||||
table.concat(environment_assignments, " "),
|
||||
get_quoted({ os.getenv("DOTWRYN") .. "/zsh/plugins/scwrypts/scwrypts" }),
|
||||
get_quoted(args_meta or {}),
|
||||
"--",
|
||||
get_quoted(args_scwrypt or {}),
|
||||
}, " ")
|
||||
end
|
||||
|
||||
------------------------------------------
|
||||
|
||||
local scwrypts_desktop = function(args_meta, args_scwrypt)
|
||||
return scwrypts(args_meta, args_scwrypt, {
|
||||
SCWRYPTS_LOG_LEVEL = "0",
|
||||
DESKTOP__SFX_PATH = os.getenv("HOME") .. "/Media/sfx",
|
||||
})
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
local hyprland = {
|
||||
launch_or_show = function(program, ...)
|
||||
return hl.dsp.exec_cmd(scwrypts_desktop({ 'hyprland', 'launch-or-show' }, { program, ... }))
|
||||
end,
|
||||
|
||||
screenshot = function(...)
|
||||
return hl.dsp.exec_cmd(scwrypts_desktop({ 'hyprland', 'screenshot' }, { ... }))
|
||||
end,
|
||||
|
||||
set_background = function(...)
|
||||
return hl.dsp.exec_cmd(scwrypts_desktop({ 'hyprland', 'set-background' }, { ... }))
|
||||
end,
|
||||
}
|
||||
|
||||
local wayland = {
|
||||
sync_gtk_settings = function(...)
|
||||
return hl.dsp.exec_cmd(scwrypts({ 'sync-gtk-settings' }, { ... }))
|
||||
end,
|
||||
}
|
||||
|
||||
local tmux = {
|
||||
omni = function()
|
||||
return hl.dsp.exec_cmd(scwrypts({ 'omni', 'tmux' }, { '--background' }))
|
||||
end,
|
||||
}
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
scwrypts = scwrypts,
|
||||
scwrypts_desktop = scwrypts_desktop,
|
||||
|
||||
hyprland = hyprland,
|
||||
wayland = wayland,
|
||||
tmux = tmux,
|
||||
}
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env zsh
|
||||
# hyprland session; TTY alias is 'starth'
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
source "${DOTWRYN}/config/desktop/server/common.zsh"
|
||||
#####################################################################
|
||||
|
||||
export XDG_CURRENT_DESKTOP=Hyprland
|
||||
export XDG_SESSION_DESKTOP=Hyprland
|
||||
export DESKTOP_SESSION=hyprland
|
||||
|
||||
#####################################################################
|
||||
|
||||
systemctl --user start hyprland-session.target
|
||||
cd; start-hyprland
|
||||
systemctl --user stop hyprland-session.target
|
||||
Regular → Executable
+4
-1
@@ -1,5 +1,8 @@
|
||||
#!/bin/zsh
|
||||
source "${DOTWRYN}/config/xinitrc.common"
|
||||
# KDE plasma session; TTY alias is 'starti'; also default 'startx' target
|
||||
export XDG_SESSION_TYPE=x11
|
||||
source "${DOTWRYN}/config/desktop/server/common.zsh"
|
||||
#####################################################################
|
||||
|
||||
export DESKTOP_SESSION=i3
|
||||
export XDG_CURRENT_DESKTOP=i3
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/zsh
|
||||
# KDE plasma session; TTY alias is 'startk'
|
||||
export XDG_SESSION_TYPE=x11
|
||||
source "$DOTWRYN/config/desktop/server/common.zsh"
|
||||
#####################################################################
|
||||
|
||||
export DESKTOP_SESSION=plasma
|
||||
exec startplasma-x11
|
||||
@@ -0,0 +1,47 @@
|
||||
#
|
||||
# shared by every desktop session (config/desktop/*/session)
|
||||
#
|
||||
|
||||
case "${XDG_SESSION_TYPE}" in
|
||||
( x11 | wayland ) ;;
|
||||
( '' )
|
||||
echo "ERROR : XDG_SESSION_TYPE must be set to one of 'x11' or 'wayland' (currently unset)" >&2
|
||||
return 1
|
||||
;;
|
||||
( * )
|
||||
echo "ERROR : XDG_SESSION_TYPE must be 'x11' or 'wayland' (got '${XDG_SESSION_TYPE}')" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#####################################################################
|
||||
|
||||
for PREFERRED_TERMINAL in \
|
||||
alacritty \
|
||||
kitty \
|
||||
;
|
||||
do
|
||||
command -v ${PREFERRED_TERMINAL} &>/dev/null \
|
||||
&& export TERMINAL="$(which ${PREFERRED_TERMINAL})" \
|
||||
&& break
|
||||
done
|
||||
unset PREFERRED_TERMINAL
|
||||
|
||||
#####################################################################
|
||||
|
||||
for PREFERRED_BROWSER in \
|
||||
brave \
|
||||
firefox \
|
||||
google-chrome-stable \
|
||||
google-chrome \
|
||||
;
|
||||
do
|
||||
command -v ${PREFERRED_BROWSER} &>/dev/null \
|
||||
&& export BROWSER="$(which ${PREFERRED_BROWSER})" \
|
||||
&& break
|
||||
done
|
||||
unset PREFERRED_BROWSER
|
||||
|
||||
#####################################################################
|
||||
|
||||
source "${DOTWRYN}/config/desktop/server/${XDG_SESSION_TYPE}.zsh"
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# currently empty; the previous server-level configurations are
|
||||
# owned by the "Wayland Compositor" instead rather than the server
|
||||
#
|
||||
true
|
||||
@@ -1,32 +1,3 @@
|
||||
#!/bin/zsh
|
||||
#####################################################################
|
||||
|
||||
for PREFERRED_TERMINAL in \
|
||||
alacritty \
|
||||
kitty \
|
||||
;
|
||||
do
|
||||
command -v ${PREFERRED_TERMINAL} &>/dev/null \
|
||||
&& export TERMINAL="$(which ${PREFERRED_TERMINAL})" \
|
||||
&& break
|
||||
done
|
||||
unset PREFERRED_TERMINAL
|
||||
|
||||
#####################################################################
|
||||
|
||||
for PREFERRED_BROWSER in \
|
||||
brave \
|
||||
firefox \
|
||||
google-chrome-stable \
|
||||
google-chrome \
|
||||
;
|
||||
do
|
||||
command -v ${PREFERRED_BROWSER} &>/dev/null \
|
||||
&& export BROWSER="$(which ${PREFERRED_BROWSER})" \
|
||||
&& break
|
||||
done
|
||||
unset PREFERRED_BROWSER
|
||||
|
||||
#####################################################################
|
||||
|
||||
for XINITRC_FILE in $(find /etc/X11/xinit/xinitrc.d | sort); do source "${XINITRC_FILE}"; done
|
||||
@@ -47,7 +18,7 @@ for BACKGROUND_APPLICATION in \
|
||||
"${DOTWRYN}/config/local/$(hostnamectl --static)/bin/default" \
|
||||
;
|
||||
do
|
||||
command -v ${BACKGROUND_APPLCATION} && exec ${BACKGROUND_APPLICATION} &
|
||||
command -v ${BACKGROUND_APPLICATION} && exec ${BACKGROUND_APPLICATION} &
|
||||
done
|
||||
|
||||
#####################################################################
|
||||
@@ -0,0 +1,17 @@
|
||||
# sound effect names -> files in DESKTOP__SFX_PATH
|
||||
#
|
||||
# shared by:
|
||||
# - scwrypts 'media audio/play-sfx' (i3, login/dock scripts, automation)
|
||||
# - quickshell VolumeOsd.qml (hyprland volume / mute feedback)
|
||||
#
|
||||
# <name> <file>
|
||||
backlight yaru-audio-volume-change.oga
|
||||
gamedock gamedock.oga
|
||||
homedock homedock.oga
|
||||
login yaru-desktop-login.oga
|
||||
logout smooth-desktop-login.oga
|
||||
mute smooth-dialog-warning.oga
|
||||
notify yaru-complete.oga
|
||||
undock yaru-desktop-login.oga
|
||||
volume yaru-message.oga
|
||||
volume-max smooth-dialog-warning.oga
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/zsh
|
||||
source "${HOME}/.zshrc" &>/dev/null
|
||||
source "${DOTWRYN}/config/xinitrc.i3wm"
|
||||
source "${DOTWRYN}/config/desktop/i3wm/session"
|
||||
|
||||
@@ -7,8 +7,10 @@ set -sg repeat-time 0
|
||||
|
||||
set-option -g default-shell /bin/zsh
|
||||
|
||||
set-option -ga update-environment HYPRLAND_INSTANCE_SIGNATURE
|
||||
|
||||
# quick reload
|
||||
bind-key r source-file ~/.tmux.conf\; display "TMUX CONFIG RELOADED"
|
||||
bind-key r source-file ~/.config/tmux/tmux.conf\; display "TMUX CONFIG RELOADED"
|
||||
|
||||
# force color
|
||||
set -g default-terminal "tmux-256color"
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/zsh
|
||||
source "$DOTWRYN/config/xinitrc.common"
|
||||
|
||||
export DESKTOP_SESSION=plasma
|
||||
exec startplasma-x11
|
||||
@@ -0,0 +1,40 @@
|
||||
#####################################################################
|
||||
|
||||
DEPENDENCIES+=(hyprctl)
|
||||
|
||||
#####################################################################
|
||||
|
||||
${scwryptsmodule}() {
|
||||
eval "$(utils.parse.autosetup)"
|
||||
##########################################
|
||||
|
||||
local result="$(hyprctl eval "$(printf '%s\n' "${ARGS[@]}")")"
|
||||
|
||||
[[ "${result}" == ok ]] \
|
||||
|| echo.error "hyprctl eval failed : ${result}" \
|
||||
|| return 1
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
|
||||
${scwryptsmodule}.parse() { return 0; }
|
||||
|
||||
${scwryptsmodule}.parse.locals() {
|
||||
local ARGS=()
|
||||
}
|
||||
|
||||
${scwryptsmodule}.parse.usage() {
|
||||
USAGE__description='
|
||||
run hyprland lua in the current hyprland instance (one statement per
|
||||
argument, evaluated together); fails unless hyprland replies "ok"
|
||||
'
|
||||
|
||||
USAGE__args='
|
||||
\$@ lua statements (e.g. "hl.dispatch(hl.dsp.window.center({}))")
|
||||
'
|
||||
}
|
||||
|
||||
${scwryptsmodule}.parse.validate() {
|
||||
[[ "${#ARGS[@]}" -gt 0 ]] \
|
||||
|| echo.error 'at least one lua statement is required'
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#####################################################################
|
||||
|
||||
DEPENDENCIES+=(hyprctl jq)
|
||||
|
||||
#####################################################################
|
||||
|
||||
${scwryptsmodule}() {
|
||||
eval "$(utils.parse.autosetup)"
|
||||
##########################################
|
||||
|
||||
hyprctl -j clients \
|
||||
| jq -r --arg class "${CLIENT_CLASS}" '.[] | select(.class | test($class; "i")) | .address' \
|
||||
;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
|
||||
${scwryptsmodule}.parse() { return 0; }
|
||||
|
||||
${scwryptsmodule}.parse.locals() {
|
||||
local ARGS=()
|
||||
local CLIENT_CLASS
|
||||
}
|
||||
|
||||
${scwryptsmodule}.parse.usage() {
|
||||
USAGE__description='
|
||||
print the address of every hyprland window whose class matches
|
||||
(one per line; case-insensitive regex)
|
||||
'
|
||||
|
||||
USAGE__args='
|
||||
\$1 window class regex
|
||||
'
|
||||
}
|
||||
|
||||
${scwryptsmodule}.parse.validate() {
|
||||
CLIENT_CLASS="${ARGS[1]}"
|
||||
|
||||
[[ "${CLIENT_CLASS}" ]] \
|
||||
|| echo.error 'window class is required'
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# interact with the running hyprland instance
|
||||
#
|
||||
|
||||
|
||||
# run hyprland lua (hyprctl eval) with error checking
|
||||
use desktop/wayland/hyprland/eval --group dotwryn
|
||||
|
||||
# list window addresses matching a class regex
|
||||
use desktop/wayland/hyprland/get-window-addresses --group dotwryn
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env zsh
|
||||
use notify
|
||||
use desktop/wayland/hyprland --group dotwryn
|
||||
|
||||
DEPENDENCIES+=(jq)
|
||||
#####################################################################
|
||||
|
||||
USAGE__usage+=' <path-executable> [...options...]'
|
||||
|
||||
USAGE__options="
|
||||
-c, --client <string> if different from the executable name, the window class (regex)
|
||||
|
||||
-s, --scale <value> (default: 0.8 or 0.5 if screen width >3000px)
|
||||
-x, --x-offset <value> (default: 0.0)
|
||||
-y, --y-offset <value> (default: 0.0)
|
||||
|
||||
-a, --always-launch invoke executable even if a window of client-class exists
|
||||
-n, --no-resize don't resize the window (ignores -sxy flags)
|
||||
-l, --no-center leave the window wherever it was last positioned
|
||||
|
||||
--has-statusbar-icon (accepted for i3 compatibility; no effect)
|
||||
"
|
||||
|
||||
USAGE__description="
|
||||
Hyprland port of 'desktop/xorg/i3/launch-or-show'.
|
||||
|
||||
Makes it easy to bind appications to key shortcuts without having to
|
||||
spin up redundant instances. Each application gets its own special
|
||||
workspace (hyprland's scratchpad), named after the executable:
|
||||
1) starts the application if it is not running
|
||||
2) moves all instances of the application to its special workspace
|
||||
3) (toggle) hides the special workspace if it is showing
|
||||
4) (toggle) shows the special workspace (resized and centered) if it is hidden
|
||||
"
|
||||
|
||||
#####################################################################
|
||||
|
||||
MAIN() {
|
||||
local SCWRYPTS_NOTIFICATION_ENGINES=(echo notify.desktop)
|
||||
|
||||
local application client_class
|
||||
local x_offset=0.0 y_offset=0.0 scale
|
||||
local always_launch=false resize=true center=true
|
||||
|
||||
local _s _p=0
|
||||
while [[ "${#}" -gt 0 ]]
|
||||
do
|
||||
_s=1
|
||||
case "${1}" in
|
||||
( -c | --client ) _s=2; client_class="${2}" ;;
|
||||
( -x | --x-offset ) _s=2; x_offset="${2}" ;;
|
||||
( -y | --y-offset ) _s=2; y_offset="${2}" ;;
|
||||
( -s | --scale ) _s=2; scale="${2}" ;;
|
||||
|
||||
( -a | --always-launch ) always_launch=true ;;
|
||||
( -n | --no-resize ) resize=false ;;
|
||||
( -l | --no-center ) center=false ;;
|
||||
|
||||
( --has-statusbar-icon ) ;;
|
||||
|
||||
( -h | --help ) USAGE; return 0 ;;
|
||||
|
||||
( * )
|
||||
case "$((_p+=1))" in
|
||||
( 1 ) application="${1}" ;;
|
||||
( * ) echo.error "extra positional argument '${1}'" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
shift "${_s}" || echo.error "missing value for argument '${1}'" || shift "${#}"
|
||||
done
|
||||
unset _s _p
|
||||
|
||||
[[ "${application}" ]] || echo.error 'path-executable required'
|
||||
[[ "${client_class}" ]] || client_class="${application}"
|
||||
|
||||
[[ "${application}" ]] && {
|
||||
utils.dependencies.check "${application}" \
|
||||
|| notify.error "${application} not found"
|
||||
}
|
||||
|
||||
utils.check-errors --fail
|
||||
|
||||
##########################################
|
||||
|
||||
local special_workspace="special:${application:t}"
|
||||
|
||||
local monitor="$(hyprctl -j monitors | jq -c '.[] | select(.focused)')"
|
||||
[[ "${scale}" ]] || {
|
||||
[[ "$(jq -r '.width' <<< "${monitor}")" -gt 3000 ]] \
|
||||
&& scale=0.5 \
|
||||
|| scale=0.8 \
|
||||
;
|
||||
}
|
||||
|
||||
##########################################
|
||||
|
||||
local addresses=($(dotwryn.desktop.wayland.hyprland.get-window-addresses "${client_class}"))
|
||||
|
||||
[[ "${always_launch}" == true ]] || [[ "${#addresses[@]}" -eq 0 ]] && {
|
||||
echo.status 'launching application'
|
||||
hyprctl dispatch "hl.dsp.exec_cmd(\"${application}\")" >/dev/null
|
||||
|
||||
echo.status 'waiting for application window'
|
||||
local wait_count
|
||||
for wait_count in {1..50}
|
||||
do
|
||||
[[ "$(dotwryn.desktop.wayland.hyprland.get-window-addresses "${client_class}" | wc -l)" -gt "${#addresses[@]}" ]] && break
|
||||
sleep 0.1
|
||||
done
|
||||
addresses=($(dotwryn.desktop.wayland.hyprland.get-window-addresses "${client_class}"))
|
||||
}
|
||||
|
||||
[[ "${#addresses[@]}" -gt 0 ]] \
|
||||
|| notify.error "no '${client_class}' window found for ${application}" \
|
||||
|| return 1
|
||||
|
||||
##########################################
|
||||
|
||||
echo.status 'moving windows to special workspace'
|
||||
local address lua=()
|
||||
for address in "${addresses[@]}"
|
||||
do
|
||||
lua+=(
|
||||
"hl.dispatch(hl.dsp.window.float({ window = \"address:${address}\", action = \"enable\" }))"
|
||||
"hl.dispatch(hl.dsp.window.move({ window = \"address:${address}\", workspace = \"${special_workspace}\", follow = false }))"
|
||||
)
|
||||
done
|
||||
|
||||
local shown_special="$(jq -r '.specialWorkspace.name' <<< "${monitor}")"
|
||||
[[ "${shown_special}" == "${special_workspace}" ]] && {
|
||||
echo.status 'hiding special workspace'
|
||||
lua+=("hl.dispatch(hl.dsp.workspace.toggle_special(\"${application:t}\"))")
|
||||
dotwryn.desktop.wayland.hyprland.eval "${lua[@]}"
|
||||
return $?
|
||||
}
|
||||
|
||||
echo.status 'showing special workspace'
|
||||
lua+=("hl.dispatch(hl.dsp.workspace.toggle_special(\"${application:t}\"))")
|
||||
|
||||
[[ "${resize}" == true ]] && {
|
||||
local window_size=($(jq -r \
|
||||
--argjson f "${scale}" --argjson x "${x_offset}" --argjson y "${y_offset}" \
|
||||
'"\((.width / .scale * $f + $x) | floor) \((.height / .scale * $f + $y) | floor)"' \
|
||||
<<< "${monitor}"
|
||||
))
|
||||
echo.debug "window size: ${window_size[*]}"
|
||||
|
||||
for address in "${addresses[@]}"
|
||||
do
|
||||
lua+=("hl.dispatch(hl.dsp.window.resize({ window = \"address:${address}\", x = ${window_size[1]}, y = ${window_size[2]} }))")
|
||||
done
|
||||
}
|
||||
|
||||
[[ "${center}" == true ]] && {
|
||||
for address in "${addresses[@]}"
|
||||
do
|
||||
lua+=("hl.dispatch(hl.dsp.window.center({ window = \"address:${address}\" }))")
|
||||
done
|
||||
}
|
||||
|
||||
dotwryn.desktop.wayland.hyprland.eval "${lua[@]}"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env zsh
|
||||
use notify
|
||||
|
||||
DEPENDENCIES+=(hyprlock)
|
||||
#####################################################################
|
||||
|
||||
USAGE__description='
|
||||
Hyprland port of "desktop/xorg/i3/lock"; locks the session with hyprlock
|
||||
(themed by ~/.config/hypr/hyprlock.conf and the active colorscheme)
|
||||
'
|
||||
|
||||
#####################################################################
|
||||
|
||||
MAIN() {
|
||||
local SCWRYPTS_NOTIFICATION_ENGINES=(echo notify.desktop)
|
||||
|
||||
pgrep -x hyprlock &>/dev/null && return 0
|
||||
|
||||
hyprlock \
|
||||
|| notify.error 'something went wrong; unable to lock' \
|
||||
;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env zsh
|
||||
use notify
|
||||
|
||||
DEPENDENCIES+=(qs)
|
||||
#####################################################################
|
||||
|
||||
USAGE__description='
|
||||
Hyprland port of "desktop/xorg/i3/logout"; asks for confirmation
|
||||
(quickshell LogoutPrompt) before exiting hyprland
|
||||
'
|
||||
|
||||
#####################################################################
|
||||
|
||||
MAIN() {
|
||||
local SCWRYPTS_NOTIFICATION_ENGINES=(echo notify.desktop)
|
||||
|
||||
qs ipc call logout show \
|
||||
|| notify.error 'unable to show logout prompt (is quickshell running?)' \
|
||||
;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env zsh
|
||||
use notify
|
||||
|
||||
DEPENDENCIES+=(flameshot hyprctl jq)
|
||||
#####################################################################
|
||||
|
||||
USAGE__description='
|
||||
Hyprland equivalent of the i3 flameshot screenshot; freezes the
|
||||
focused monitor in flameshot to select / annotate / copy / save
|
||||
'
|
||||
|
||||
#####################################################################
|
||||
|
||||
MAIN() {
|
||||
local SCWRYPTS_NOTIFICATION_ENGINES=(echo notify.desktop)
|
||||
|
||||
# flameshot screens are numbered from 0 in output order (hyprland ids are not)
|
||||
local screen_number
|
||||
screen_number="$(hyprctl monitors -j | jq -r 'sort_by(.id) | to_entries[] | select(.value.focused) | .key')"
|
||||
[ "${screen_number}" ] \
|
||||
|| { notify.error 'unable to determine focused monitor'; return 1; }
|
||||
|
||||
flameshot screen --edit --number "${screen_number}" \
|
||||
|| notify.error 'unable to take screenshot' \
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env zsh
|
||||
use notify
|
||||
use scwrypts/get-realpath
|
||||
|
||||
DEPENDENCIES+=(hyprctl)
|
||||
REQUIRED_ENV+=(DESKTOP__WALLPAPER_PATH)
|
||||
#####################################################################
|
||||
|
||||
USAGE__usage+=' [wallpaper]'
|
||||
|
||||
USAGE__args+='
|
||||
$1 one of:
|
||||
random : any wallpaper (default)
|
||||
theme : the wallpaper named after the active colorscheme (e.g. main.jpg)
|
||||
(optional \$2 : use this theme name instead)
|
||||
<file> : a wallpaper file within DESKTOP__WALLPAPER_PATH
|
||||
'
|
||||
|
||||
USAGE__description='
|
||||
Hyprland port of "desktop/xorg/i3/set-background"; sets the wallpaper
|
||||
on every monitor through hyprpaper
|
||||
'
|
||||
|
||||
#####################################################################
|
||||
|
||||
MAIN() {
|
||||
local SCWRYPTS_NOTIFICATION_ENGINES=(echo notify.desktop)
|
||||
|
||||
# env values are literal (e.g. '$HOME/Pictures/bg'); resolve before use
|
||||
local wallpaper_path="$(scwrypts.get-realpath "${DESKTOP__WALLPAPER_PATH}")"
|
||||
|
||||
[[ -d "${wallpaper_path}" ]] \
|
||||
|| echo.error "no such directory for DESKTOP__WALLPAPER_PATH='${DESKTOP__WALLPAPER_PATH}'" \
|
||||
|| return 1
|
||||
|
||||
local selection="${1:-random}"
|
||||
local wallpaper
|
||||
|
||||
case "${selection}" in
|
||||
( random )
|
||||
wallpaper="$(find "${wallpaper_path}" -type f | shuf -n1)"
|
||||
;;
|
||||
( theme )
|
||||
# optional $2 : theme name (default: the active theme)
|
||||
local theme_name="${2:-$(cat -- "${DOTWRYN}/config/colorschemes/active/name.txt" 2>/dev/null)}"
|
||||
wallpaper="$(find "${wallpaper_path}" -type f -name "${theme_name}.*" | head -n1)"
|
||||
[[ "${wallpaper}" ]] \
|
||||
|| echo.error "no wallpaper for theme '${theme_name}' in wallpaper path" \
|
||||
|| return 2
|
||||
;;
|
||||
( * )
|
||||
wallpaper="${wallpaper_path}/${selection}"
|
||||
[[ -f "${wallpaper}" ]] \
|
||||
|| echo.error "no such wallpaper '${selection}' in wallpaper path" \
|
||||
|| return 2
|
||||
;;
|
||||
esac
|
||||
|
||||
[[ "${wallpaper}" ]] \
|
||||
|| echo.error "no wallpapers found in '${wallpaper_path}'" \
|
||||
|| return 3
|
||||
|
||||
pgrep -x hyprpaper &>/dev/null || {
|
||||
hyprctl dispatch 'hl.dsp.exec_cmd("hyprpaper")' >/dev/null
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# empty monitor : fallback for any monitor without a specific wallpaper
|
||||
hyprctl hyprpaper wallpaper ", ${wallpaper}, cover" >/dev/null \
|
||||
|| notify.error "unable to set wallpaper '${wallpaper}'" \
|
||||
;
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env zsh
|
||||
DEPENDENCIES+=(gsettings)
|
||||
#####################################################################
|
||||
|
||||
USAGE__description='
|
||||
On X11, GTK reads its theme from ~/.config/gtk-3.0/settings.ini (written by
|
||||
lxappearance). Wayland GTK apps read gsettings instead, so copy the values
|
||||
across; settings.ini stays the single source of truth for both sessions.
|
||||
'
|
||||
|
||||
#####################################################################
|
||||
|
||||
MAIN() {
|
||||
local settings_file="${XDG_CONFIG_HOME:-${HOME}/.config}/gtk-3.0/settings.ini"
|
||||
|
||||
[[ -f "${settings_file}" ]] \
|
||||
|| echo.error "no gtk settings found at '${settings_file}'" \
|
||||
|| return 1
|
||||
|
||||
local ini_key gsettings_key value
|
||||
for ini_key gsettings_key in \
|
||||
gtk-theme-name gtk-theme \
|
||||
gtk-icon-theme-name icon-theme \
|
||||
gtk-font-name font-name \
|
||||
gtk-cursor-theme-name cursor-theme \
|
||||
;
|
||||
do
|
||||
value="$(sed -n "s/^${ini_key}=//p" "${settings_file}" | tail -n1)"
|
||||
[[ "${value}" ]] || continue
|
||||
|
||||
gsettings set org.gnome.desktop.interface "${gsettings_key}" "${value}" \
|
||||
&& echo.status "${gsettings_key} : ${value}" \
|
||||
|| echo.error "unable to set ${gsettings_key}" \
|
||||
;
|
||||
done
|
||||
|
||||
# libadwaita / portal-aware apps (electron, gtk4) follow color-scheme rather than the theme name
|
||||
local theme="$(gsettings get org.gnome.desktop.interface gtk-theme)"
|
||||
case "${theme:l}" in
|
||||
( *dark* ) gsettings set org.gnome.desktop.interface color-scheme prefer-dark ;;
|
||||
( * ) gsettings set org.gnome.desktop.interface color-scheme default ;;
|
||||
esac
|
||||
|
||||
[[ "${ERRORS}" -eq 0 ]]
|
||||
}
|
||||
@@ -28,21 +28,14 @@ ${scwryptsmodule}.parse() {
|
||||
[[ ${POSITIONAL_ARGS} -eq 0 ]] || return 0
|
||||
|
||||
((POSITIONAL_ARGS+=1))
|
||||
case $1 in
|
||||
( backlight ) SFX_FILE="${DESKTOP__SFX_PATH}/yaru-audio-volume-change.oga" ;;
|
||||
( gamedock ) SFX_FILE="${DESKTOP__SFX_PATH}/gamedock.oga" ;;
|
||||
( homedock ) SFX_FILE="${DESKTOP__SFX_PATH}/homedock.oga" ;;
|
||||
( login ) SFX_FILE="${DESKTOP__SFX_PATH}/yaru-desktop-login.oga" ;;
|
||||
( logout ) SFX_FILE="${DESKTOP__SFX_PATH}/smooth-desktop-login.oga" ;;
|
||||
( mute ) SFX_FILE="${DESKTOP__SFX_PATH}/smooth-dialog-warning.oga" ;;
|
||||
( notify ) SFX_FILE="${DESKTOP__SFX_PATH}/yaru-complete.oga" ;;
|
||||
( undock ) SFX_FILE="${DESKTOP__SFX_PATH}/yaru-desktop-login.oga" ;;
|
||||
( volume ) SFX_FILE="${DESKTOP__SFX_PATH}/yaru-message.oga" ;;
|
||||
|
||||
( * )
|
||||
SFX_FILE="$1"
|
||||
;;
|
||||
esac
|
||||
# mapped names live in $DOTWRYN/config/sfx.map (shared with the hyprland quickshell)
|
||||
local mapped_file="$(awk -v name="${1}" '!/^#/ && $1 == name { print $2; exit }' "${DOTWRYN}/config/sfx.map" 2>/dev/null)"
|
||||
|
||||
[[ "${mapped_file}" ]] \
|
||||
&& SFX_FILE="${DESKTOP__SFX_PATH}/${mapped_file}" \
|
||||
|| SFX_FILE="${1}" \
|
||||
;
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ set -g default-terminal "tmux-256color"
|
||||
set -g mouse off
|
||||
set -sg escape-time 0
|
||||
set-option -g default-shell /bin/zsh
|
||||
set-option -ga update-environment HYPRLAND_INSTANCE_SIGNATURE
|
||||
set-option -gw xterm-keys on
|
||||
set-window-option -g mode-keys vi
|
||||
set-window-option -g status-keys vi
|
||||
|
||||
Reference in New Issue
Block a user