hyprland: clean session startup and scratchpads

This commit is contained in:
2026-05-01 22:18:37 -07:00
parent b153adcb8c
commit 0750934622
2 changed files with 156 additions and 40 deletions

View File

@@ -8,7 +8,8 @@ local launcher_command = shell_ui_command .. " launcher"
local run_menu = shell_ui_command .. " run"
local max_workspace = 9
local scratchpad_top_margin = 60
local scratchpad_size_ratio = 0.95
local dropdown_height_ratio = 0.5
local columns_layout = "nStack"
local large_main_layout = "master"
local grid_layout = "grid"
@@ -221,13 +222,12 @@ local function apply_hyprwinview_config()
app_icon_backplate_col = "rgba(00000066)",
app_icon_backplate_padding = 6,
animation = "workspace_zoom",
animation_in_ms = 340,
animation_out_ms = 170,
animation_speed = 0.5,
animation_in_ms = 280,
animation_out_ms = 220,
animation_speed = 1.0,
animation_scale = 0.94,
animation_stagger_ms = 16,
animation_stagger_max_ms = 120,
animation_workspace_zoom_stage_ratio = 0.50,
},
},
})
@@ -1076,6 +1076,53 @@ 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 monitor_workarea(monitor)
local width = logical_monitor_dimension(monitor.width, monitor.scale)
local height = logical_monitor_dimension(monitor.height, monitor.scale)
local reserved = monitor.reserved or {}
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 = {}
@@ -1099,20 +1146,21 @@ local function apply_scratchpad_geometry(name, window, target_monitor)
return
end
local workarea = monitor_workarea(monitor)
local width
local height
local x
local y
if def.dropdown then
width = monitor.width
height = math.floor(monitor.height * 0.5)
x = monitor.x
y = monitor.y + scratchpad_top_margin
width = workarea.width
height = math.floor(workarea.height * dropdown_height_ratio)
x = workarea.x
y = workarea.y
else
width = math.floor(monitor.width * 0.95)
height = math.min(math.floor(monitor.height * 0.95), monitor.height - scratchpad_top_margin)
x = monitor.x + math.floor((monitor.width - width) / 2)
y = monitor.y + scratchpad_top_margin
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)
@@ -1954,7 +2002,7 @@ hl.on("hyprland.start", function()
apply_hyprexpo_config()
apply_hyprwinview_config()
apply_rules()
hl.exec_cmd("sh -lc 'export IMALISON_SESSION_TYPE=wayland; dbus-update-activation-environment --systemd XDG_RUNTIME_DIR WAYLAND_DISPLAY DISPLAY XAUTHORITY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP XDG_SESSION_TYPE IMALISON_SESSION_TYPE; systemctl --user start graphical-session.target hyprland-session.target'")
hl.exec_cmd("sh -lc '/run/current-system/sw/bin/uwsm finalize HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE XAUTHORITY IMALISON_SESSION_TYPE=wayland IMALISON_WINDOW_MANAGER=hyprland || dbus-update-activation-environment --systemd XDG_RUNTIME_DIR WAYLAND_DISPLAY DISPLAY XAUTHORITY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE IMALISON_SESSION_TYPE IMALISON_WINDOW_MANAGER; systemctl --user start hyprland-session.target'")
hl.exec_cmd("hypridle")
hl.exec_cmd("wl-paste --type text --watch cliphist store")
hl.exec_cmd("wl-paste --type image --watch cliphist store")

View File

@@ -5,10 +5,90 @@
makeEnable,
inputs,
...
}:
let
}: let
system = pkgs.stdenv.hostPlatform.system;
hyprlandInput = inputs.hyprland;
baseHyprlandPackage = hyprlandInput.packages.${system}.hyprland;
cleanupStaleGraphicalSession = pkgs.writeShellScript "cleanup-stale-graphical-session" ''
set -u
# Only clean targets that are plainly stale. If a compositor is still
# running, let the active session own its own shutdown path.
if ${pkgs.procps}/bin/pgrep -u "$(${pkgs.coreutils}/bin/id -u)" -f '(^|/)(Hyprland|\.Hyprland-wrapped|river|kwin_wayland)( |$)' >/dev/null 2>&1; then
exit 0
fi
${pkgs.systemd}/bin/systemctl --user stop \
hyprland-session.target \
river-xmonad-session.target \
graphical-session.target \
graphical-session-pre.target \
tray.target \
2>/dev/null || true
${pkgs.systemd}/bin/systemctl --user unset-environment \
WAYLAND_DISPLAY \
DISPLAY \
XAUTHORITY \
HYPRLAND_INSTANCE_SIGNATURE \
XDG_CURRENT_DESKTOP \
XDG_SESSION_DESKTOP \
XDG_SESSION_TYPE \
IMALISON_SESSION_TYPE \
IMALISON_WINDOW_MANAGER \
2>/dev/null || true
${pkgs.systemd}/bin/systemctl --user reset-failed 2>/dev/null || true
'';
makeHyprlandLuaPackage = package:
(pkgs.symlinkJoin {
name = "${package.name}-lua-config";
inherit (package) version;
paths = [package];
passthru =
(package.passthru or {})
// {
providedSessions = package.passthru.providedSessions or ["hyprland"];
};
postBuild = ''
mkdir -p "$out/bin" "$out/share/wayland-sessions"
printf '%s\n' \
'#!${pkgs.runtimeShell}' \
'config_path="''${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprland.lua"' \
'exec "${package}/bin/Hyprland" --config "$config_path" "$@"' \
> "$out/bin/start-hyprland-lua"
chmod +x "$out/bin/start-hyprland-lua"
printf '%s\n' \
'#!${pkgs.runtimeShell}' \
'${cleanupStaleGraphicalSession}' \
'exec ${pkgs.uwsm}/bin/uwsm start -e -D Hyprland hyprland.desktop' \
> "$out/bin/start-hyprland-uwsm-clean"
chmod +x "$out/bin/start-hyprland-uwsm-clean"
rm -f "$out/share/wayland-sessions/hyprland.desktop"
substitute \
"${package}/share/wayland-sessions/hyprland.desktop" \
"$out/share/wayland-sessions/hyprland.desktop" \
--replace-fail \
"Exec=${package}/bin/start-hyprland" \
"Exec=$out/bin/start-hyprland-lua"
rm -f "$out/share/wayland-sessions/hyprland-uwsm.desktop"
substitute \
"${package}/share/wayland-sessions/hyprland-uwsm.desktop" \
"$out/share/wayland-sessions/hyprland-uwsm.desktop" \
--replace-fail \
"Exec=uwsm start -e -D Hyprland hyprland.desktop" \
"Exec=$out/bin/start-hyprland-uwsm-clean"
'';
})
// {
override = {enableXWayland ? true, ...} @ args:
makeHyprlandLuaPackage (package.override args);
overrideAttrs = f: makeHyprlandLuaPackage (package.overrideAttrs f);
};
hyprlandPackage = makeHyprlandLuaPackage baseHyprlandPackage;
hyprlandPluginPackages = [
inputs.hyprNStack.packages.${system}.hyprNStack
inputs.hyprland-plugins-lua.packages.${system}.hyprexpo
@@ -20,7 +100,7 @@ let
runtimeInputs = [
pkgs.python3
pkgs.rofi
hyprlandInput.packages.${system}.hyprland
hyprlandPackage
];
text = ''
exec python3 ${../dotfiles/lib/bin/hypr_rofi_window} "$@"
@@ -78,7 +158,6 @@ let
options = "persist";
rules = "float;size monitor_w monitor_h*0.5;move 0 60;noborder;noshadow;animation slide";
};
};
enabledModule = makeEnable config "myModules.hyprland" true {
# Install both shell service units so `desktop_shell_ui set ...` can switch
@@ -98,7 +177,7 @@ let
programs.hyprland = {
enable = true;
# Keep Hyprland and plugins on a matched flake input for ABI compatibility.
package = hyprlandInput.packages.${system}.hyprland;
package = hyprlandPackage;
# Let UWSM manage the Hyprland session targets
withUWSM = true;
};
@@ -106,13 +185,7 @@ let
home-manager.sharedModules = [
inputs.hyprscratch.homeModules.default
(
{ config, lib, ... }:
let
hyprConfig =
name:
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/dotfiles/dotfiles/config/hypr/${name}";
in
{
{lib, ...}: {
services.kanshi = {
enable = true;
systemdTarget = "graphical-session.target";
@@ -166,23 +239,18 @@ let
};
};
xdg.configFile."hypr/hyprland.lua" = {
force = true;
source = hyprConfig "hyprland.lua";
};
xdg.configFile."hypr/hypridle.conf".source = hyprConfig "hypridle.conf";
xdg.configFile."hypr/hyprlock.conf".source = hyprConfig "hyprlock.conf";
xdg.configFile."hypr/scripts".enable = false;
xdg.configFile."systemd/user/wayland-wm@hyprland.desktop.service.d/10-cleanup-stale-session.conf".text = ''
[Service]
ExecStopPost=${cleanupStaleGraphicalSession}
'';
}
)
];
# Hyprland-specific packages
environment.systemPackages =
with pkgs;
environment.systemPackages = with pkgs;
[
# Hyprland utilities
hyprpaper # Wallpaper