hyprland: add workspace history plugin

This commit is contained in:
2026-04-30 01:33:08 -07:00
parent 34906469b9
commit f6026b5cac
7 changed files with 637 additions and 1307 deletions

View File

@@ -1,506 +0,0 @@
# Hyprland Configuration
# XMonad-like dynamic tiling using hy3 plugin
# Based on XMonad configuration from xmonad.hs
# =============================================================================
# PLUGINS (Hyprland pinned to 0.53.0 to match hy3)
# =============================================================================
# Load the plugin before parsing keybinds/layouts that depend on it
plugin = /run/current-system/sw/lib/libhy3.so
plugin = /run/current-system/sw/lib/libhyprexpo.so
# =============================================================================
# MONITORS
# =============================================================================
monitor=,preferred,auto,1
# =============================================================================
# PROGRAMS
# =============================================================================
$terminal = ghostty --gtk-single-instance=false
$fileManager = dolphin
$shellUi = hypr_shell_ui
$menu = $shellUi launcher
$runMenu = $shellUi run
# =============================================================================
# ENVIRONMENT VARIABLES
# =============================================================================
env = XCURSOR_SIZE,24
env = QT_QPA_PLATFORMTHEME,qt6ct
env = HYPR_MAX_WORKSPACE,9
# =============================================================================
# INPUT CONFIGURATION
# =============================================================================
input {
kb_layout = us
kb_variant =
kb_model =
kb_options =
kb_rules =
follow_mouse = 1
touchpad {
natural_scroll = no
}
sensitivity = 0
}
# Cursor warping behavior
cursor {
persistent_warps = true
}
# =============================================================================
# GENERAL SETTINGS
# =============================================================================
general {
gaps_in = 5
gaps_out = 10
border_size = 0
col.active_border = rgba(edb443ee) rgba(33ccffee) 45deg
col.inactive_border = rgba(595959aa)
# Use hy3 layout for XMonad-like dynamic tiling
layout = hy3
allow_tearing = false
}
# =============================================================================
# DECORATION
# =============================================================================
decoration {
rounding = 5
blur {
enabled = true
size = 3
passes = 1
}
# Fade inactive windows (like XMonad's fadeInactive)
active_opacity = 1.0
inactive_opacity = 0.9
}
# =============================================================================
# ANIMATIONS
# =============================================================================
animations {
enabled = yes
# Hyprland supports bezier curves, not true spring physics.
# Use a mild overshoot plus GNOME-like window animation style.
bezier = overshoot, 0.05, 0.9, 0.1, 1.1
bezier = smoothOut, 0.36, 1, 0.3, 1
bezier = smoothInOut, 0.42, 0, 0.58, 1
bezier = linear, 0, 0, 1, 1
# SPEED is in deciseconds (e.g. 6 == 600ms).
animation = windows, 1, 6, overshoot, gnomed
animation = windowsIn, 1, 6, overshoot, gnomed
animation = windowsOut, 1, 5, smoothInOut, gnomed
animation = windowsMove, 1, 6, smoothOut
animation = border, 0
animation = borderangle, 0
animation = fade, 1, 5, smoothOut
animation = workspaces, 1, 6, smoothOut, slidefade 15%
animation = specialWorkspace, 1, 6, smoothOut, slidevert
}
# =============================================================================
# MASTER LAYOUT CONFIGURATION
# =============================================================================
master {
new_status = slave
mfact = 0.5
orientation = left
}
# Dwindle layout (alternative - binary tree like i3)
dwindle {
pseudotile = yes
preserve_split = yes
}
# =============================================================================
# WORKSPACE RULES (SMART GAPS)
# =============================================================================
# Replace no_gaps_when_only (removed in newer Hyprland)
# Remove gaps when there's only one visible tiled window (ignore special workspaces)
workspace = w[tv1]s[false], gapsout:0, gapsin:0
workspace = f[1]s[false], gapsout:0, gapsin:0
# Group/tabbed window configuration (built-in alternative to hy3 tabs)
group {
col.border_active = rgba(edb443ff)
col.border_inactive = rgba(091f2eff)
groupbar {
enabled = true
font_size = 12
height = 22
col.active = rgba(edb443ff)
col.inactive = rgba(091f2eff)
text_color = rgba(091f2eff)
}
}
# =============================================================================
# HY3/HYPREXPO PLUGIN CONFIG
# =============================================================================
plugin {
hy3 {
# Disable autotile to get XMonad-like manual control
autotile {
enable = false
}
# Tab configuration
tabs {
height = 22
padding = 6
render_text = true
text_font = "Sans"
text_height = 10
text_padding = 3
col.active = rgba(edb443ff)
col.inactive = rgba(091f2eff)
col.urgent = rgba(ff0000ff)
col.text.active = rgba(091f2eff)
col.text.inactive = rgba(ffffffff)
col.text.urgent = rgba(ffffffff)
}
}
hyprexpo {
# Always include workspace 1 in the overview grid
workspace_method = first 1
# Only show workspaces with windows
skip_empty = true
# Show numeric workspace labels in the expo grid
show_workspace_numbers = true
# 3 columns -> 3x3 grid when 9 workspaces are visible
columns = 3
}
}
# =============================================================================
# MISC
# =============================================================================
misc {
force_default_wallpaper = 0
disable_hyprland_logo = true
}
# =============================================================================
# BINDS OPTIONS
# =============================================================================
binds {
# Keep workspace history so "previous" can toggle back reliably.
allow_workspace_cycles = true
workspace_back_and_forth = true
}
# =============================================================================
# WINDOW RULES
# =============================================================================
# Float dialogs
windowrule = match:class ^()$, match:title ^()$, float on
windowrule = match:title ^(Picture-in-Picture)$, float on
windowrule = match:title ^(Open File)$, float on
windowrule = match:title ^(Save File)$, float on
windowrule = match:title ^(Confirm)$, float on
# Rumno OSD/notifications: treat as an overlay, not a "real" managed window.
# (Matches both class and title because rumno may set either depending on backend.)
windowrule = match:class ^(.*[Rr]umno.*)$, float on
windowrule = match:class ^(.*[Rr]umno.*)$, pin on
windowrule = match:class ^(.*[Rr]umno.*)$, center on
windowrule = match:class ^(.*[Rr]umno.*)$, decorate off
windowrule = match:class ^(.*[Rr]umno.*)$, no_shadow on
windowrule = match:title ^(.*[Rr]umno.*)$, float on
windowrule = match:title ^(.*[Rr]umno.*)$, pin on
windowrule = match:title ^(.*[Rr]umno.*)$, center on
windowrule = match:title ^(.*[Rr]umno.*)$, decorate off
windowrule = match:title ^(.*[Rr]umno.*)$, no_shadow on
# Scratchpad sizing handled by hyprscratch exec rules (see hyprland.nix)
# Using hyprscratch rules instead of windowrule to avoid affecting child windows (e.g. Slack meets)
# =============================================================================
# KEY BINDINGS
# =============================================================================
# Modifier keys
$mainMod = SUPER
$modAlt = SUPER ALT
$hyper = SUPER CTRL ALT
# -----------------------------------------------------------------------------
# Program Launching
# -----------------------------------------------------------------------------
bind = $mainMod, P, exec, $menu
bind = $mainMod SHIFT, P, exec, $runMenu
bind = $hyper SHIFT, N, exec, $shellUi control-center
bind = $hyper CTRL, N, exec, $shellUi settings
bind = $mainMod SHIFT, Return, exec, $terminal
# -----------------------------------------------------------------------------
# Overview (Hyprexpo)
# -----------------------------------------------------------------------------
bind = $mainMod, TAB, hyprexpo:expo, toggle
bind = $mainMod SHIFT, TAB, hyprexpo:expo, bring
bind = $mainMod, Q, exec, hyprctl reload
bind = $mainMod SHIFT, C, killactive,
bind = $mainMod SHIFT, Q, exit,
# Emacs-everywhere (like XMonad's emacs-everywhere)
bind = $mainMod, E, exec, emacsclient --eval '(emacs-everywhere)'
bind = $mainMod, V, exec, wl-paste | xdotool type --file -
# Chrome/Browser
bind = $modAlt, C, exec, google-chrome-stable
# -----------------------------------------------------------------------------
# SCRATCHPADS (managed by hyprscratch daemon with auto-dismiss)
# -----------------------------------------------------------------------------
bind = $modAlt, E, exec, hyprscratch toggle element
bind = $modAlt, H, exec, hyprscratch toggle htop
bind = $modAlt, K, exec, hyprscratch toggle slack
bind = $modAlt, S, exec, hyprscratch toggle spotify
bind = $modAlt, T, exec, hyprscratch toggle transmission
bind = $modAlt, V, exec, hyprscratch toggle volume
bind = $modAlt, grave, exec, hyprscratch toggle dropdown
# Hidden workspace (like XMonad's NSP)
bind = $mainMod, X, movetoworkspace, special:NSP
bind = $mainMod SHIFT, X, togglespecialworkspace, NSP
# -----------------------------------------------------------------------------
# DIRECTIONAL NAVIGATION (WASD - like XMonad Navigation2D)
# Using hy3 dispatchers for proper tree-based navigation
# -----------------------------------------------------------------------------
# Focus movement (Mod + WASD) - hy3:movefocus navigates the tree
bind = $mainMod, W, hy3:movefocus, u
bind = $mainMod, S, hy3:movefocus, d
bind = $mainMod, A, hy3:movefocus, l
bind = $mainMod, D, hy3:movefocus, r
# Move windows (Mod + Shift + WASD)
bind = $mainMod SHIFT, W, hy3:movewindow, u
bind = $mainMod SHIFT, S, hy3:movewindow, d
bind = $mainMod SHIFT, A, hy3:movewindow, l
bind = $mainMod SHIFT, D, hy3:movewindow, r
# Resize windows (Mod + Ctrl + WASD)
binde = $mainMod CTRL, W, resizeactive, 0 -50
binde = $mainMod CTRL, S, resizeactive, 0 50
binde = $mainMod CTRL, A, resizeactive, -50 0
binde = $mainMod CTRL, D, resizeactive, 50 0
# Screen/Monitor focus (Hyper + WASD)
bind = $hyper, W, focusmonitor, u
bind = $hyper, S, focusmonitor, d
bind = $hyper, A, focusmonitor, l
bind = $hyper, D, focusmonitor, r
# Move window to monitor and follow (Hyper + Shift + WASD)
bind = $hyper SHIFT, W, movewindow, mon:u
bind = $hyper SHIFT, S, movewindow, mon:d
bind = $hyper SHIFT, A, movewindow, mon:l
bind = $hyper SHIFT, D, movewindow, mon:r
# -----------------------------------------------------------------------------
# LAYOUT CONTROL (XMonad-like with hy3)
# -----------------------------------------------------------------------------
# Create groups with different orientations (like XMonad layouts)
# hy3:makegroup creates a split/tab group from focused window
bind = $mainMod, Space, hy3:changegroup, toggletab
bind = $mainMod SHIFT, Space, hy3:changegroup, opposite
# Create specific group types
bind = $mainMod, H, hy3:makegroup, h
bind = $mainMod SHIFT, V, hy3:makegroup, v
# Mod+Ctrl+Space mirrors Mod+Space (tabs instead of fullscreen)
bind = $mainMod CTRL, Space, hy3:changegroup, toggletab
# Change group type (cycle h -> v -> tab)
bind = $mainMod, slash, hy3:changegroup, h
bind = $mainMod SHIFT, slash, hy3:changegroup, v
# Tab navigation (like XMonad's focus next/prev in tabbed)
bind = $mainMod, bracketright, hy3:focustab, r, wrap
bind = $mainMod, bracketleft, hy3:focustab, l, wrap
# Move window within tab group (hy3 has no movetab dispatcher)
bind = $mainMod SHIFT, bracketright, hy3:movewindow, r, visible
bind = $mainMod SHIFT, bracketleft, hy3:movewindow, l, visible
# Expand focus to parent group (like XMonad's focus parent)
bind = $mainMod, grave, hy3:expand, expand
bind = $mainMod SHIFT, grave, hy3:expand, base
# Toggle floating
bind = $mainMod, T, togglefloating,
# Resize split ratio (hy3 uses resizeactive for splits)
binde = $mainMod, comma, resizeactive, -50 0
binde = $mainMod, period, resizeactive, 50 0
# Equalize window sizes on workspace (hy3)
bind = $mainMod SHIFT, equal, hy3:equalize, workspace
# Kill group - removes the focused window from its group
bind = $mainMod, N, hy3:killactive
# hy3:setswallow - set a window to swallow newly spawned windows
bind = $mainMod CTRL, M, hy3:setswallow, toggle
# -----------------------------------------------------------------------------
# WORKSPACE CONTROL
# -----------------------------------------------------------------------------
# Switch workspaces (1-9 only) on the currently focused monitor.
bind = $mainMod, 1, focusworkspaceoncurrentmonitor, 1
bind = $mainMod, 2, focusworkspaceoncurrentmonitor, 2
bind = $mainMod, 3, focusworkspaceoncurrentmonitor, 3
bind = $mainMod, 4, focusworkspaceoncurrentmonitor, 4
bind = $mainMod, 5, focusworkspaceoncurrentmonitor, 5
bind = $mainMod, 6, focusworkspaceoncurrentmonitor, 6
bind = $mainMod, 7, focusworkspaceoncurrentmonitor, 7
bind = $mainMod, 8, focusworkspaceoncurrentmonitor, 8
bind = $mainMod, 9, focusworkspaceoncurrentmonitor, 9
# Move window to workspace
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
# Move and follow to workspace (like XMonad's shiftThenView)
bind = $mainMod CTRL, 1, movetoworkspacesilent, 1
bind = $mainMod CTRL, 1, focusworkspaceoncurrentmonitor, 1
bind = $mainMod CTRL, 2, movetoworkspacesilent, 2
bind = $mainMod CTRL, 2, focusworkspaceoncurrentmonitor, 2
bind = $mainMod CTRL, 3, movetoworkspacesilent, 3
bind = $mainMod CTRL, 3, focusworkspaceoncurrentmonitor, 3
bind = $mainMod CTRL, 4, movetoworkspacesilent, 4
bind = $mainMod CTRL, 4, focusworkspaceoncurrentmonitor, 4
bind = $mainMod CTRL, 5, movetoworkspacesilent, 5
bind = $mainMod CTRL, 5, focusworkspaceoncurrentmonitor, 5
bind = $mainMod CTRL, 6, movetoworkspacesilent, 6
bind = $mainMod CTRL, 6, focusworkspaceoncurrentmonitor, 6
bind = $mainMod CTRL, 7, movetoworkspacesilent, 7
bind = $mainMod CTRL, 7, focusworkspaceoncurrentmonitor, 7
bind = $mainMod CTRL, 8, movetoworkspacesilent, 8
bind = $mainMod CTRL, 8, focusworkspaceoncurrentmonitor, 8
bind = $mainMod CTRL, 9, movetoworkspacesilent, 9
bind = $mainMod CTRL, 9, focusworkspaceoncurrentmonitor, 9
# Toggle to the previous workspace on the current monitor using Hyprland's
# built-in per-monitor workspace history.
bind = $mainMod, backslash, workspace, previous_per_monitor
# Move to next screen (like XMonad's shiftToNextScreenX)
bind = $mainMod, Z, focusmonitor, +1
bind = $mainMod SHIFT, Z, movewindow, mon:+1
# -----------------------------------------------------------------------------
# WINDOW MANAGEMENT
# -----------------------------------------------------------------------------
bind = $mainMod, G, exec, $shellUi window go
bind = $mainMod, B, exec, $shellUi window bring
bind = $mainMod SHIFT, B, exec, $shellUi window replace
# -----------------------------------------------------------------------------
# MEDIA KEYS
# -----------------------------------------------------------------------------
# Volume control (matching XMonad: Mod+I=up, Mod+K=down, Mod+U=mute)
binde = , XF86AudioRaiseVolume, exec, set_volume --unmute --change-volume +5
binde = , XF86AudioLowerVolume, exec, set_volume --unmute --change-volume -5
bind = , XF86AudioMute, exec, set_volume --toggle-mute
binde = $mainMod, I, exec, set_volume --unmute --change-volume +5
binde = $mainMod, K, exec, set_volume --unmute --change-volume -5
bind = $mainMod, U, exec, set_volume --toggle-mute
# Media player controls (matching XMonad: Mod+;=play, Mod+L=next, Mod+J=prev)
bind = $mainMod, semicolon, exec, playerctl play-pause
bind = , XF86AudioPlay, exec, playerctl play-pause
bind = , XF86AudioPause, exec, playerctl play-pause
bind = $mainMod, L, exec, playerctl next
bind = , XF86AudioNext, exec, playerctl next
bind = $mainMod, J, exec, playerctl previous
bind = , XF86AudioPrev, exec, playerctl previous
# Mute current window (like XMonad's toggle_mute_current_window)
bind = $hyper SHIFT, Q, exec, toggle_mute_current_window.sh
bind = $hyper CTRL, Q, exec, toggle_mute_current_window.sh only
# Brightness control
binde = , XF86MonBrightnessUp, exec, brightness.sh up
binde = , XF86MonBrightnessDown, exec, brightness.sh down
# -----------------------------------------------------------------------------
# UTILITY BINDINGS
# -----------------------------------------------------------------------------
bind = $hyper, V, exec, cliphist list | rofi -dmenu -p "Clipboard" | cliphist decode | wl-copy
bind = $hyper, P, exec, rofi-pass
bind = $hyper, H, exec, grim -g "$(slurp)" - | swappy -f -
bind = $hyper, C, exec, shell_command.sh
bind = $hyper, X, exec, rofi_command.sh
bind = $hyper SHIFT, L, exec, hyprlock
bind = $hyper, K, exec, rofi_kill_process.sh
bind = $hyper SHIFT, K, exec, rofi_kill_all.sh
bind = $hyper, R, exec, rofi-systemd
bind = $hyper, slash, exec, toggle_taffybar
bind = $hyper, 9, exec, start_synergy.sh
bind = $hyper, I, exec, rofi_select_input.hs
bind = $hyper, backslash, exec, /home/imalison/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle
bind = $hyper, O, exec, rofi_paswitch
bind = $hyper, comma, exec, rofi_wallpaper.sh
bind = $hyper, Y, exec, rofi_agentic_skill
# Reload config
bind = $mainMod, R, exec, hyprctl reload
# -----------------------------------------------------------------------------
# MOUSE BINDINGS
# -----------------------------------------------------------------------------
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# Scroll through workspaces
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1
# =============================================================================
# AUTOSTART
# =============================================================================
# Wire Hyprland into Home Manager's standard user-session targets.
# `graphical-session.target` pulls in most tray/SNI applets (which in turn pull in `tray.target`).
# Keep the systemd user manager in sync with the current Hyprland session before
# starting any session-bound units. Separate `exec-once` commands race.
exec-once = 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'
# Force a fresh daemon after compositor restarts so hyprscratch doesn't keep a stale socket.
exec-once = systemctl --user restart hyprscratch.service
exec-once = hypridle
# Clipboard history daemon
exec-once = wl-paste --type text --watch cliphist store
exec-once = wl-paste --type image --watch cliphist store

View File

@@ -16,6 +16,7 @@ local current_layout = columns_layout
local enable_nstack = true
local enable_hyprexpo = true
local enable_hyprwinview = true
local enable_workspace_history = true
local configure_nstack_plugin_from_lua = false
local workspace_layouts = {}
local minimized_windows = {}
@@ -25,8 +26,6 @@ local window_picker_candidates = {}
local stack_update_timer = nil
local monocle_notice = nil
local scratchpad_pending = {}
local monitor_workspace_history = {}
local workspace_history_cycle = nil
local scratchpads = {
htop = {
@@ -121,6 +120,22 @@ local function hyprwinview(action)
end
end
local function workspacehistory(action, arg)
return function()
if hl.plugin and hl.plugin.workspacehistory and hl.plugin.workspacehistory[action] then
hl.plugin.workspacehistory[action](arg)
else
hl.notification.create({
text = "workspacehistory is not loaded",
duration = 1800,
icon = "warning",
color = "rgba(edb443ff)",
font_size = 13,
})
end
end
end
local function apply_nstack_config()
if verify_config or not enable_nstack or not configure_nstack_plugin_from_lua then
return
@@ -159,6 +174,7 @@ local function apply_hyprexpo_config()
bg_col = "rgba(111111ff)",
workspace_method = "center current",
skip_empty = false,
max_workspace = max_workspace,
show_workspace_numbers = true,
workspace_number_color = "rgba(edb443ff)",
gesture_distance = 200,
@@ -177,19 +193,15 @@ local function apply_hyprwinview_config()
hyprwinview = {
gap_size = 24,
margin = 48,
bg_col = "rgba(101014ee)",
background = "rgba(10101499)",
background_blur = 0,
border_col = "rgba(ffffff33)",
hover_border_col = "rgba(66ccffee)",
border_size = 3,
keys_left = "a,h,left",
keys_right = "d,l,right",
keys_up = "w,k,up",
keys_down = "s,j,down",
keys_go = "return,enter,space,g",
keys_bring = "b,shift+return,shift+space",
keys_close = "escape,q",
window_order = "application",
show_app_icon = 1,
app_icon_size = 48,
app_icon_theme_source = "auto",
app_icon_position = "bottom right",
app_icon_margin_x = 12,
app_icon_margin_y = 12,
@@ -199,9 +211,30 @@ local function apply_hyprwinview_config()
app_icon_offset_y = 0,
app_icon_backplate_col = "rgba(00000066)",
app_icon_backplate_padding = 6,
animation = "workspace_zoom",
animation_in_ms = 180,
animation_out_ms = 140,
animation_scale = 0.94,
animation_stagger_ms = 16,
animation_stagger_max_ms = 120,
},
},
})
if hl.plugin and hl.plugin.hyprwinview and hl.plugin.hyprwinview.configure then
hl.plugin.hyprwinview.configure({
keys = {
left = { "a", "h", "left" },
right = { "d", "l", "right" },
up = { "w", "k", "up" },
down = { "s", "j", "down" },
go = { "return", "enter", "space", "g", "f" },
bring = { "b", "shift+return", "shift+space" },
bring_replace = { "shift + b" },
close = { "escape", "q" },
},
})
end
end
local function active_workspace()
@@ -290,6 +323,27 @@ local function is_scratchpad_window(window)
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
end
if left.name and right.name and tostring(left.name) == tostring(right.name) then
return true
end
return left.id and right.id and left.id == right.id
end
local function is_minimized_workspace(workspace)
if not workspace then
return false
@@ -578,129 +632,6 @@ local function focus_workspace(workspace_id)
hl.dsp.focus({ workspace = tostring(workspace_id), on_current_monitor = true })()
end
local function monitor_key(monitor)
if not monitor then
return "unknown"
end
return tostring(monitor.name or monitor.id or "unknown")
end
local function workspace_history_workspace_id(workspace)
if not workspace or not workspace.id or workspace.id < 1 or workspace.id > max_workspace then
return nil
end
return workspace.id
end
local function workspace_history_monitor_key(workspace)
return monitor_key(workspace and workspace.monitor or hl.get_active_monitor())
end
local function remove_workspace_history_id(history, workspace_id)
for index = #history, 1, -1 do
if history[index] == workspace_id then
table.remove(history, index)
end
end
end
local function remember_workspace_for_monitor(workspace)
workspace = workspace or active_workspace()
if workspace_history_cycle then
return
end
local workspace_id = workspace_history_workspace_id(workspace)
if not workspace_id then
return
end
local key = workspace_history_monitor_key(workspace)
local history = monitor_workspace_history[key] or {}
if history[1] ~= workspace_id then
remove_workspace_history_id(history, workspace_id)
table.insert(history, 1, workspace_id)
end
monitor_workspace_history[key] = history
end
local function clone_workspace_history(history)
local clone = {}
for index, workspace_id in ipairs(history or {}) do
clone[index] = workspace_id
end
return clone
end
local function workspace_history_cycle_start()
if workspace_history_cycle then
return workspace_history_cycle
end
remember_workspace_for_monitor()
local workspace = active_workspace()
local workspace_id = workspace_history_workspace_id(workspace)
if not workspace_id then
return nil
end
local key = workspace_history_monitor_key(workspace)
local history = clone_workspace_history(monitor_workspace_history[key])
if history[1] ~= workspace_id then
remove_workspace_history_id(history, workspace_id)
table.insert(history, 1, workspace_id)
end
if #history < 2 then
return nil
end
workspace_history_cycle = {
monitor_key = key,
original_workspace = workspace_id,
history = history,
index = 2,
}
return workspace_history_cycle
end
local function cycle_workspace_history(direction)
local cycle = workspace_history_cycle_start()
if not cycle then
hl.dsp.focus({ workspace = "previous_per_monitor" })()
return
end
local workspace_id = cycle.history[cycle.index]
if not workspace_id then
return
end
focus_workspace(workspace_id)
cycle.index = ((cycle.index - 1 + direction) % #cycle.history) + 1
end
local function commit_workspace_history_cycle()
if not workspace_history_cycle then
return
end
workspace_history_cycle = nil
remember_workspace_for_monitor()
end
local function cancel_workspace_history_cycle()
local cycle = workspace_history_cycle
if not cycle then
return
end
workspace_history_cycle = nil
focus_workspace(cycle.original_workspace)
end
local function move_window_to_workspace(workspace_id, follow, window)
local target_window = window or hl.get_active_window()
local target_selector = window_selector(target_window)
@@ -1155,7 +1086,29 @@ end
local function scratchpad_is_visible(window)
local workspace = active_workspace()
return workspace and window and window.workspace == 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 adopt_matching_scratchpad_window(window)
@@ -1489,6 +1442,7 @@ local function toggle_scratchpad(name)
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(),
@@ -1510,6 +1464,7 @@ local function toggle_scratchpad(name)
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
@@ -1527,6 +1482,9 @@ end
if enable_hyprwinview and not verify_config then
hl.plugin.load("/run/current-system/sw/lib/libhyprwinview.so")
end
if enable_workspace_history and not verify_config then
hl.plugin.load("/run/current-system/sw/lib/libhypr-workspace-history.so")
end
hl.env("XCURSOR_SIZE", "24")
hl.env("HYPRCURSOR_SIZE", "24")
@@ -1705,6 +1663,7 @@ bind(main_mod .. " + SHIFT + Q", hl.dsp.exit())
bind(main_mod .. " + E", exec("emacsclient --eval '(emacs-everywhere)'"))
bind(main_mod .. " + V", exec("wl-paste | xdotool type --file -"))
bind(main_mod .. " + Tab", hyprwinview("toggle"))
bind(main_mod .. " + SHIFT + Tab", hyprwinview("toggle other-workspaces"))
bind("ALT + Tab", hyprexpo("toggle"))
bind("ALT + SHIFT + Tab", hyprexpo("bring"))
bind(main_mod .. " + G", exec(shell_ui_command .. " window go"))
@@ -1871,14 +1830,9 @@ for i = 1, 9 do
end)
end
bind(main_mod .. " + backslash", function()
cycle_workspace_history(1)
end)
bind(main_mod .. " + slash", function()
cycle_workspace_history(-1)
end)
bind(main_mod .. " + Super_L", commit_workspace_history_cycle, { release = true })
bind(main_mod .. " + Escape", cancel_workspace_history_cycle)
bind(main_mod .. " + backslash", workspacehistory("cycle", 1))
bind(main_mod .. " + slash", workspacehistory("cycle", -1))
bind(main_mod .. " + Escape", workspacehistory("cancel"))
bind(main_mod .. " + Z", hl.dsp.focus({ monitor = "+1" }))
bind(main_mod .. " + SHIFT + Z", hl.dsp.window.move({ monitor = "+1" }))
bind(main_mod .. " + mouse_down", function()
@@ -1920,6 +1874,7 @@ bind(hyper .. " + R", exec("rofi-systemd"))
bind(hyper .. " + slash", exec("toggle_taffybar"))
bind(hyper .. " + I", exec("rofi_select_input.hs"))
bind(hyper .. " + backslash", exec("/home/imalison/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle"))
bind(hyper .. " + SHIFT + backslash", workspacehistory("debug"))
bind(hyper .. " + O", exec("rofi_paswitch"))
bind(hyper .. " + comma", exec("rofi_wallpaper.sh"))
bind(hyper .. " + Y", exec("rofi_agentic_skill"))
@@ -1937,7 +1892,6 @@ hl.on("hyprland.start", function()
hl.exec_cmd("hypridle")
hl.exec_cmd("wl-paste --type text --watch cliphist store")
hl.exec_cmd("wl-paste --type image --watch cliphist store")
remember_workspace_for_monitor()
write_layout_state()
schedule_nstack_count_update()
end)
@@ -1953,7 +1907,6 @@ hl.on("window.kill", schedule_nstack_count_update)
hl.on("window.move_to_workspace", schedule_nstack_count_update)
hl.on("workspace.active", sync_layout_for_active_workspace)
hl.on("monitor.focused", sync_layout_for_active_workspace)
hl.on("workspace.active", remember_workspace_for_monitor)
hl.on("window.open", update_monocle_notice)
hl.on("window.destroy", update_monocle_notice)

View File

@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.27)
project(hypr-workspace-history
DESCRIPTION "Workspace history cycling plugin for Hyprland"
VERSION 0.1.0
LANGUAGES CXX
)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(hypr-workspace-history SHARED src/main.cpp)
find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET
hyprland
wayland-server
xkbcommon
)
target_link_libraries(hypr-workspace-history PRIVATE rt PkgConfig::deps)
install(TARGETS hypr-workspace-history)

View File

@@ -0,0 +1,406 @@
#define WLR_USE_UNSTABLE
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/debug/log/Logger.hpp>
#include <hyprland/src/desktop/Workspace.hpp>
#include <hyprland/src/desktop/state/FocusState.hpp>
#include <hyprland/src/devices/IKeyboard.hpp>
#include <hyprland/src/event/EventBus.hpp>
#include <hyprland/src/helpers/Monitor.hpp>
#include <hyprland/src/managers/KeybindManager.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <lua.hpp>
#include <algorithm>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <map>
#include <optional>
#include <sstream>
#include <string>
#include <vector>
inline HANDLE PHANDLE = nullptr;
namespace {
constexpr int MAX_WORKSPACE = 9;
struct SCycleState {
std::string monitorKey;
int originalWorkspace = 0;
int previewWorkspace = 0;
std::vector<int> history;
size_t nextIndex = 0;
};
class CWorkspaceHistory {
public:
void seedActiveWorkspaces() {
if (!g_pCompositor)
return;
for (const auto& monitor : g_pCompositor->m_monitors) {
if (monitor && monitor->m_activeWorkspace)
remember(monitor->m_activeWorkspace);
}
writeDebug("seed");
}
void observe(PHLWORKSPACE workspace) {
const auto workspaceId = workspaceID(workspace);
if (!workspaceId) {
writeDebug("observe-skipped-non-normal-workspace");
return;
}
const auto key = monitorKey(workspace);
if (!m_cycle || m_cycle->monitorKey != key) {
remember(workspace);
return;
}
if (contains(m_cycle->history, *workspaceId)) {
m_cycle->previewWorkspace = *workspaceId;
writeDebug("cycle-observe-preview");
return;
}
m_cycle.reset();
remember(workspace);
writeDebug("remember-after-cycle-abandoned");
}
SDispatchResult cycle(int direction) {
auto* cycle = startCycle();
if (!cycle)
return {};
if (cycle->history.size() < 2) {
writeDebug("cycle-skipped-short-history");
return {};
}
const auto target = cycle->history[cycle->nextIndex];
cycle->previewWorkspace = target;
const auto result = focusWorkspace(target);
if (!result.success) {
writeDebug("cycle-focus-failed");
return result;
}
cycle->nextIndex = wrappedIndex(cycle->nextIndex, direction, cycle->history.size());
writeDebug(std::string("cycle-preview-") + std::to_string(target));
return {};
}
SDispatchResult commit() {
if (!m_cycle) {
writeDebug("commit-skipped-no-cycle");
return {};
}
auto cycle = *m_cycle;
m_cycle.reset();
m_histories[cycle.monitorKey] = promote(cycle.history, cycle.previewWorkspace);
writeDebug("commit");
return {};
}
SDispatchResult cancel() {
if (!m_cycle) {
writeDebug("cancel-skipped-no-cycle");
return {};
}
const auto original = m_cycle->originalWorkspace;
m_cycle.reset();
focusWorkspace(original);
writeDebug("cancel");
return {};
}
void onKey(IKeyboard::SKeyEvent event) {
if (!m_cycle || event.state != WL_KEYBOARD_KEY_STATE_RELEASED || !g_pKeybindManager)
return;
if (g_pKeybindManager->keycodeToModifier(event.keycode + 8) == HL_MODIFIER_META)
commit();
}
std::string snapshot(const std::string& reason) const {
std::stringstream out;
out << "reason=" << reason << "\n";
const auto monitor = Desktop::focusState() ? Desktop::focusState()->monitor() : nullptr;
const auto workspace = monitor ? monitor->m_activeWorkspace : nullptr;
out << "active_monitor=" << monitorKey(monitor) << "\n";
out << "active_workspace=" << (workspace ? std::to_string(workspace->m_id) : "?") << "\n";
for (const auto& [key, history] : m_histories) {
out << "history." << key << "=";
for (size_t i = 0; i < history.size(); ++i) {
if (i > 0)
out << ",";
out << history[i];
}
out << "\n";
}
if (m_cycle) {
out << "cycle.monitor=" << m_cycle->monitorKey << "\n";
out << "cycle.original=" << m_cycle->originalWorkspace << "\n";
out << "cycle.preview=" << m_cycle->previewWorkspace << "\n";
out << "cycle.next_index=" << (m_cycle->nextIndex + 1) << "\n";
out << "cycle.history=";
for (size_t i = 0; i < m_cycle->history.size(); ++i) {
if (i > 0)
out << ",";
out << m_cycle->history[i];
}
out << "\n";
} else {
out << "cycle=none\n";
}
return out.str();
}
void showDebug() const {
HyprlandAPI::addNotification(PHANDLE, snapshot("notification"), CHyprColor{0.4, 0.8, 1.0, 1.0}, 6000);
}
private:
std::map<std::string, std::vector<int>> m_histories;
std::optional<SCycleState> m_cycle;
static std::optional<int> workspaceID(PHLWORKSPACE workspace) {
if (!workspace || workspace->m_id < 1 || workspace->m_id > MAX_WORKSPACE)
return std::nullopt;
return workspace->m_id;
}
static std::string monitorKey(PHLMONITOR monitor) {
if (!monitor)
return "unknown";
if (!monitor->m_name.empty())
return monitor->m_name;
return std::to_string(monitor->m_id);
}
static std::string monitorKey(PHLWORKSPACE workspace) {
if (!workspace || !workspace->m_monitor)
return monitorKey(Desktop::focusState() ? Desktop::focusState()->monitor() : nullptr);
return monitorKey(workspace->m_monitor.lock());
}
static bool contains(const std::vector<int>& history, int workspace) {
return std::ranges::contains(history, workspace);
}
static std::vector<int> promote(std::vector<int> history, int workspace) {
std::erase(history, workspace);
history.insert(history.begin(), workspace);
return history;
}
static size_t wrappedIndex(size_t current, int direction, size_t size) {
const auto signedSize = static_cast<int>(size);
auto next = static_cast<int>(current) + direction;
next = ((next % signedSize) + signedSize) % signedSize;
return static_cast<size_t>(next);
}
PHLWORKSPACE activeWorkspace() const {
const auto monitor = Desktop::focusState() ? Desktop::focusState()->monitor() : nullptr;
return monitor ? monitor->m_activeWorkspace : nullptr;
}
void remember(PHLWORKSPACE workspace) {
const auto workspaceId = workspaceID(workspace);
if (!workspaceId) {
writeDebug("remember-skipped-non-normal-workspace");
return;
}
const auto key = monitorKey(workspace);
auto& history = m_histories[key];
const bool changed = history.empty() || history.front() != *workspaceId;
history = promote(history, *workspaceId);
if (changed)
writeDebug("remember");
}
SCycleState* startCycle() {
if (m_cycle)
return &*m_cycle;
const auto workspace = activeWorkspace();
remember(workspace);
const auto workspaceId = workspaceID(workspace);
if (!workspaceId) {
writeDebug("cycle-start-skipped-non-normal-workspace");
return nullptr;
}
const auto key = monitorKey(workspace);
auto history = promote(m_histories[key], *workspaceId);
if (history.size() < 2) {
writeDebug("cycle-start-skipped-short-history");
return nullptr;
}
m_cycle = SCycleState{
.monitorKey = key,
.originalWorkspace = *workspaceId,
.previewWorkspace = *workspaceId,
.history = history,
.nextIndex = 1,
};
writeDebug("cycle-start");
return &*m_cycle;
}
static SDispatchResult focusWorkspace(int workspace) {
if (!g_pKeybindManager)
return {.success = false, .error = "keybind manager is unavailable"};
const auto dispatcher = g_pKeybindManager->m_dispatchers.find("focusworkspaceoncurrentmonitor");
if (dispatcher == g_pKeybindManager->m_dispatchers.end())
return {.success = false, .error = "focusworkspaceoncurrentmonitor dispatcher is unavailable"};
return dispatcher->second(std::to_string(workspace));
}
static std::optional<std::string> runtimePath(const std::string& name) {
const auto runtimeDir = std::getenv("XDG_RUNTIME_DIR");
if (!runtimeDir)
return std::nullopt;
return std::string(runtimeDir) + "/" + name;
}
void writeDebug(const std::string& reason) const {
const auto statePath = runtimePath("hyprland-workspace-history-state");
const auto logPath = runtimePath("hyprland-workspace-history.log");
if (!statePath || !logPath)
return;
const auto body = snapshot(reason);
std::ofstream state(*statePath, std::ios::trunc);
if (state)
state << body;
std::ofstream log(*logPath, std::ios::app);
if (log) {
const auto now = std::time(nullptr);
log << "--- " << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S") << " ---\n";
log << body;
}
}
};
CWorkspaceHistory g_workspaceHistory;
SDispatchResult dispatchCycle(std::string arg) {
int direction = 1;
if (arg == "-1" || arg == "previous" || arg == "prev" || arg == "reverse")
direction = -1;
return g_workspaceHistory.cycle(direction);
}
SDispatchResult dispatchCommit(std::string) {
return g_workspaceHistory.commit();
}
SDispatchResult dispatchCancel(std::string) {
return g_workspaceHistory.cancel();
}
SDispatchResult dispatchDebug(std::string) {
g_workspaceHistory.showDebug();
return {};
}
int luaCycle(lua_State* L) {
const auto result = g_workspaceHistory.cycle(static_cast<int>(luaL_optinteger(L, 1, 1)));
if (!result.success)
return luaL_error(L, "%s", result.error.c_str());
return 0;
}
int luaCommit(lua_State* L) {
const auto result = g_workspaceHistory.commit();
if (!result.success)
return luaL_error(L, "%s", result.error.c_str());
return 0;
}
int luaCancel(lua_State* L) {
const auto result = g_workspaceHistory.cancel();
if (!result.success)
return luaL_error(L, "%s", result.error.c_str());
return 0;
}
int luaDebug(lua_State*) {
g_workspaceHistory.showDebug();
return 0;
}
void failNotification(const std::string& reason) {
HyprlandAPI::addNotification(PHANDLE, "[workspace-history] " + reason, CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000);
}
}
APICALL EXPORT std::string PLUGIN_API_VERSION() {
return HYPRLAND_API_VERSION;
}
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
PHANDLE = handle;
const std::string hash = __hyprland_api_get_hash();
const std::string clientHash = __hyprland_api_get_client_hash();
if (hash != clientHash) {
failNotification("version mismatch between Hyprland headers and running Hyprland");
throw std::runtime_error("[workspace-history] version mismatch");
}
static auto workspaceHook = Event::bus()->m_events.workspace.active.listen([](PHLWORKSPACE workspace) { g_workspaceHistory.observe(workspace); });
static auto keyboardHook = Event::bus()->m_events.input.keyboard.key.listen([](IKeyboard::SKeyEvent event, Event::SCallbackInfo&) { g_workspaceHistory.onKey(event); });
static auto startHook = Event::bus()->m_events.start.listen([] { g_workspaceHistory.seedActiveWorkspaces(); });
static auto reloadHook = Event::bus()->m_events.config.reloaded.listen([] { g_workspaceHistory.seedActiveWorkspaces(); });
static auto monitorHook = Event::bus()->m_events.monitor.focused.listen([](PHLMONITOR monitor) {
if (monitor && monitor->m_activeWorkspace)
g_workspaceHistory.observe(monitor->m_activeWorkspace);
});
HyprlandAPI::addDispatcherV2(PHANDLE, "workspacehistory:cycle", ::dispatchCycle);
HyprlandAPI::addDispatcherV2(PHANDLE, "workspacehistory:commit", ::dispatchCommit);
HyprlandAPI::addDispatcherV2(PHANDLE, "workspacehistory:cancel", ::dispatchCancel);
HyprlandAPI::addDispatcherV2(PHANDLE, "workspacehistory:debug", ::dispatchDebug);
HyprlandAPI::addLuaFunction(PHANDLE, "workspacehistory", "cycle", ::luaCycle);
HyprlandAPI::addLuaFunction(PHANDLE, "workspacehistory", "commit", ::luaCommit);
HyprlandAPI::addLuaFunction(PHANDLE, "workspacehistory", "cancel", ::luaCancel);
HyprlandAPI::addLuaFunction(PHANDLE, "workspacehistory", "debug", ::luaDebug);
g_workspaceHistory.seedActiveWorkspaces();
HyprlandAPI::addNotification(PHANDLE, "[workspace-history] Initialized", CHyprColor{0.2, 1.0, 0.2, 1.0}, 3000);
return {"hypr-workspace-history", "Workspace history cycling with modifier-release commits", "Ivan Malison", "0.1.0"};
}
APICALL EXPORT void PLUGIN_EXIT() {
g_workspaceHistory.commit();
}

641
nixos/flake.lock generated
View File

@@ -46,39 +46,6 @@
"systems"
]
},
"locked": {
"lastModified": 1765900596,
"narHash": "sha256-+hn8v9jkkLP9m+o0Nm5SiEq10W0iWDSotH2XfjU45fA=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "d83c97f8f5c0aae553c1489c7d9eff3eadcadace",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "aquamarine",
"type": "github"
}
},
"aquamarine_2": {
"inputs": {
"hyprutils": [
"hyprland-lua-config",
"hyprutils"
],
"hyprwayland-scanner": [
"hyprland-lua-config",
"hyprwayland-scanner"
],
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776876344,
"narHash": "sha256-Ubqb/agkuMJK+k19gjQgHux/eOYRc1sRGoOZOho8+VY=",
@@ -301,22 +268,6 @@
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1761588595,
"narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1767039857,
@@ -332,7 +283,7 @@
"type": "github"
}
},
"flake-compat_3": {
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1696426674,
@@ -348,7 +299,7 @@
"type": "github"
}
},
"flake-compat_4": {
"flake-compat_3": {
"flake": false,
"locked": {
"lastModified": 1767039857,
@@ -364,7 +315,7 @@
"type": "github"
}
},
"flake-compat_5": {
"flake-compat_4": {
"flake": false,
"locked": {
"lastModified": 1767039857,
@@ -504,7 +455,7 @@
},
"flake-utils_2": {
"inputs": {
"systems": "systems_3"
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
@@ -661,28 +612,6 @@
}
},
"gitignore_2": {
"inputs": {
"nixpkgs": [
"hyprland-lua-config",
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_3": {
"inputs": {
"nixpkgs": [
"imalison-taffybar",
@@ -731,7 +660,7 @@
"hercules-ci-effects_2": {
"inputs": {
"flake-parts": "flake-parts_5",
"nixpkgs": "nixpkgs_7"
"nixpkgs": "nixpkgs_6"
},
"locked": {
"lastModified": 1701009247,
@@ -768,42 +697,21 @@
"type": "github"
}
},
"hy3": {
"inputs": {
"hyprland": [
"hyprland"
]
},
"locked": {
"lastModified": 1767957561,
"narHash": "sha256-N0kFdc6tSE0yFeQ/Iit3KNrz4nf2K5xvP3juL7SUyhc=",
"owner": "outfoxxed",
"repo": "hy3",
"rev": "3287049e79e9e51431de8c09f9192a18afa1bf35",
"type": "github"
},
"original": {
"owner": "outfoxxed",
"ref": "hl0.53.0",
"repo": "hy3",
"type": "github"
}
},
"hyprNStack": {
"inputs": {
"hyprland": [
"hyprland-lua-config"
"hyprland"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1777475074,
"narHash": "sha256-shgepEMtMB532/df5QfociNzTiqimuoBbJssw0WPVH4=",
"lastModified": 1777498784,
"narHash": "sha256-u/FCBctT/CqPYc9uZyI+bhDKQSBCV8L/z8u6IEC2iiU=",
"owner": "colonelpanic8",
"repo": "hyprNStack",
"rev": "d43c8a506b32dc5057fdce0569c38f401c01eb60",
"rev": "e2b07d6a7b472a0dd5bef00a1c0c186ccd2f46c6",
"type": "github"
},
"original": {
@@ -828,35 +736,6 @@
"systems"
]
},
"locked": {
"lastModified": 1753964049,
"narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprcursor",
"type": "github"
}
},
"hyprcursor_2": {
"inputs": {
"hyprlang": [
"hyprland-lua-config",
"hyprlang"
],
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776511930,
"narHash": "sha256-fCpwFiTW0rT7oKJqr3cqHMnkwypSwQKpbtUEtxdkgrM=",
@@ -886,35 +765,6 @@
"systems"
]
},
"locked": {
"lastModified": 1763733840,
"narHash": "sha256-JnET78yl5RvpGuDQy3rCycOCkiKoLr5DN1fPhRNNMco=",
"owner": "hyprwm",
"repo": "hyprgraphics",
"rev": "8f1bec691b2d198c60cccabca7a94add2df4ed1a",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprgraphics",
"type": "github"
}
},
"hyprgraphics_2": {
"inputs": {
"hyprutils": [
"hyprland-lua-config",
"hyprutils"
],
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776426399,
"narHash": "sha256-RUESLKNikIeEq9ymGJ6nmcDXiSFQpUW1IhJ245nL3xM=",
@@ -946,17 +796,16 @@
"xdph": "xdph"
},
"locked": {
"lastModified": 1767021696,
"narHash": "sha256-1jZK7hqNhQRqhj+2eb/JvnBoARxUgoVXKLSwp2RPmNQ=",
"ref": "refs/tags/v0.53.0",
"rev": "ea444c35bb23b6e34505ab6753e069de7801cc25",
"revCount": 6756,
"lastModified": 1777497195,
"narHash": "sha256-I9z3somAUJ5jGwv4ZBjADco8CmdglEUqYs0AgJ5LSDs=",
"ref": "refs/heads/main",
"rev": "56d7a43102b53f79a2311662783d5dd94cb2f1a5",
"revCount": 7215,
"submodules": true,
"type": "git",
"url": "https://github.com/hyprwm/Hyprland"
},
"original": {
"ref": "refs/tags/v0.53.0",
"submodules": true,
"type": "git",
"url": "https://github.com/hyprwm/Hyprland"
@@ -994,52 +843,6 @@
"systems"
]
},
"locked": {
"lastModified": 1765643131,
"narHash": "sha256-CCGohW5EBIRy4B7vTyBMqPgsNcaNenVad/wszfddET0=",
"owner": "hyprwm",
"repo": "hyprland-guiutils",
"rev": "e50ae912813bdfa8372d62daf454f48d6df02297",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-guiutils",
"type": "github"
}
},
"hyprland-guiutils_2": {
"inputs": {
"aquamarine": [
"hyprland-lua-config",
"aquamarine"
],
"hyprgraphics": [
"hyprland-lua-config",
"hyprgraphics"
],
"hyprlang": [
"hyprland-lua-config",
"hyprlang"
],
"hyprtoolkit": "hyprtoolkit_2",
"hyprutils": [
"hyprland-lua-config",
"hyprutils"
],
"hyprwayland-scanner": [
"hyprland-lua-config",
"hyprwayland-scanner"
],
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776426575,
"narHash": "sha256-KI6nIfVihn/DPaeB5Et46Xg3dkNHrrEtUd5LBBVomB0=",
@@ -1054,75 +857,11 @@
"type": "github"
}
},
"hyprland-lua-config": {
"inputs": {
"aquamarine": "aquamarine_2",
"hyprcursor": "hyprcursor_2",
"hyprgraphics": "hyprgraphics_2",
"hyprland-guiutils": "hyprland-guiutils_2",
"hyprland-protocols": "hyprland-protocols_2",
"hyprlang": "hyprlang_2",
"hyprutils": "hyprutils_2",
"hyprwayland-scanner": "hyprwayland-scanner_2",
"hyprwire": "hyprwire_2",
"nixpkgs": "nixpkgs_3",
"pre-commit-hooks": "pre-commit-hooks_2",
"systems": "systems_2",
"xdph": "xdph_2"
},
"locked": {
"lastModified": 1777207870,
"narHash": "sha256-Jld5Lp1HdjRVYJgAnW3vwOPcRUgbfP+IzhcpUjFR2Ns=",
"ref": "refs/pull/13817/head",
"rev": "c35a8a565bf14fcf71b34663e7bd7683ca3facfd",
"revCount": 7174,
"submodules": true,
"type": "git",
"url": "https://github.com/hyprwm/Hyprland"
},
"original": {
"ref": "refs/pull/13817/head",
"submodules": true,
"type": "git",
"url": "https://github.com/hyprwm/Hyprland"
}
},
"hyprland-plugins": {
"hyprland-plugins-lua": {
"inputs": {
"hyprland": [
"hyprland"
],
"nixpkgs": [
"hyprland-plugins",
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland-plugins",
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1777471981,
"narHash": "sha256-cd3pQg+vKv6vht4xzButsi/Kaw9P4d3itm46jYXyiDM=",
"owner": "colonelpanic8",
"repo": "hyprland-plugins",
"rev": "725e354bbee982566068b5b90fec4fcd787c1036",
"type": "github"
},
"original": {
"owner": "colonelpanic8",
"ref": "hyprexpo-v0.53.0-custom",
"repo": "hyprland-plugins",
"type": "github"
}
},
"hyprland-plugins-lua": {
"inputs": {
"hyprland": [
"hyprland-lua-config"
],
"nixpkgs": [
"hyprland-plugins-lua",
"hyprland",
@@ -1135,11 +874,11 @@
]
},
"locked": {
"lastModified": 1777492340,
"narHash": "sha256-9uRI/opXD+zOK2BLlzQ2NluRJL1SRSdUO2tlvbUJ7Ys=",
"lastModified": 1777528408,
"narHash": "sha256-X350VUh+dkogkRP9vwbOrYEsEVHVD0rwjWsuOImcTI8=",
"owner": "colonelpanic8",
"repo": "hyprland-plugins",
"rev": "ca1992973b5fb8ab95e88e8ffba16792c41568ae",
"rev": "c50ed7b75e9c99b5a01de3ac17aa91d767af6dda",
"type": "github"
},
"original": {
@@ -1160,31 +899,6 @@
"systems"
]
},
"locked": {
"lastModified": 1765214753,
"narHash": "sha256-P9zdGXOzToJJgu5sVjv7oeOGPIIwrd9hAUAP3PsmBBs=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "3f3860b869014c00e8b9e0528c7b4ddc335c21ab",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-protocols",
"type": "github"
}
},
"hyprland-protocols_2": {
"inputs": {
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1772460177,
"narHash": "sha256-/6G/MsPvtn7bc4Y32pserBT/Z4SUUdBd4XYJpOEKVR4=",
@@ -1214,35 +928,6 @@
"systems"
]
},
"locked": {
"lastModified": 1764612430,
"narHash": "sha256-54ltTSbI6W+qYGMchAgCR6QnC1kOdKXN6X6pJhOWxFg=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "0d00dc118981531aa731150b6ea551ef037acddd",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprlang",
"type": "github"
}
},
"hyprlang_2": {
"inputs": {
"hyprutils": [
"hyprland-lua-config",
"hyprutils"
],
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776426736,
"narHash": "sha256-rl7i4aY+9p8LysJp7o8uRWahCkpFznCgGHXszlTw7b0=",
@@ -1316,58 +1001,6 @@
"systems"
]
},
"locked": {
"lastModified": 1764592794,
"narHash": "sha256-7CcO+wbTJ1L1NBQHierHzheQGPWwkIQug/w+fhTAVuU=",
"owner": "hyprwm",
"repo": "hyprtoolkit",
"rev": "5cfe0743f0e608e1462972303778d8a0859ee63e",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprtoolkit",
"type": "github"
}
},
"hyprtoolkit_2": {
"inputs": {
"aquamarine": [
"hyprland-lua-config",
"hyprland-guiutils",
"aquamarine"
],
"hyprgraphics": [
"hyprland-lua-config",
"hyprland-guiutils",
"hyprgraphics"
],
"hyprlang": [
"hyprland-lua-config",
"hyprland-guiutils",
"hyprlang"
],
"hyprutils": [
"hyprland-lua-config",
"hyprland-guiutils",
"hyprutils"
],
"hyprwayland-scanner": [
"hyprland-lua-config",
"hyprland-guiutils",
"hyprwayland-scanner"
],
"nixpkgs": [
"hyprland-lua-config",
"hyprland-guiutils",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"hyprland-guiutils",
"systems"
]
},
"locked": {
"lastModified": 1772462885,
"narHash": "sha256-5pHXrQK9zasMnIo6yME6EOXmWGFMSnCITcfKshhKJ9I=",
@@ -1394,36 +1027,11 @@
]
},
"locked": {
"lastModified": 1766160771,
"narHash": "sha256-roINUGikWRqqgKrD4iotKbGj3ZKJl3hjMz5l/SyKrHw=",
"lastModified": 1777492286,
"narHash": "sha256-PwuoEJQcjSKJNP5T55qhfDwIP0tw5zxEhfu8GDfKfeg=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "5ac060bfcf2f12b3a6381156ebbc13826a05b09f",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprutils",
"type": "github"
}
},
"hyprutils_2": {
"inputs": {
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776428866,
"narHash": "sha256-XfRlBolGtjvalTHJp3XvvpYLBjkMhaZLLU0WqZ91Fcg=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "eedd60805cd96d4442586f2ba5fe51d549b12674",
"rev": "ec5c0c709706bad5b82f667fd8758eae442577ce",
"type": "github"
},
"original": {
@@ -1444,11 +1052,11 @@
]
},
"locked": {
"lastModified": 1763640274,
"narHash": "sha256-Uan1Nl9i4TF/kyFoHnTq1bd/rsWh4GAK/9/jDqLbY5A=",
"lastModified": 1777148232,
"narHash": "sha256-Uv0WZLhu89SafuSOmYDA7akrPt4wBRmsa1ucasO5aXg=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "f6cf414ca0e16a4d30198fd670ec86df3c89f671",
"rev": "fec9cf1abcc1011e46f0a0986f46bf93c6bf8b92",
"type": "github"
},
"original": {
@@ -1457,28 +1065,33 @@
"type": "github"
}
},
"hyprwayland-scanner_2": {
"hyprwinview": {
"inputs": {
"hyprland": [
"hyprland"
],
"nixpkgs": [
"hyprland-lua-config",
"hyprwinview",
"hyprland",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"hyprwinview",
"hyprland",
"systems"
]
},
"locked": {
"lastModified": 1776430932,
"narHash": "sha256-Yv3RPiUvl7CAsJgwIVsqcj7akn1gLyJP1F/mocof5hA=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "4c2fcc06dc9722c97dbb54ba649c69b18ce83d2e",
"lastModified": 1777536892,
"narHash": "sha256-L4DF6j0gstnGN6nngU93F2XM7QmF0/G+gD9KC4jl53g=",
"owner": "colonelpanic8",
"repo": "hyprwinview",
"rev": "1e88a0f318263bcc9c2e461e44436597ed73de79",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"owner": "colonelpanic8",
"repo": "hyprwinview",
"type": "github"
}
},
@@ -1497,35 +1110,6 @@
"systems"
]
},
"locked": {
"lastModified": 1766253200,
"narHash": "sha256-26qPwrd3od+xoYVywSB7hC2cz9ivN46VPLlrsXyGxvE=",
"owner": "hyprwm",
"repo": "hyprwire",
"rev": "1079777525b30a947c8d657fac158e00ae85de9d",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprwire",
"type": "github"
}
},
"hyprwire_2": {
"inputs": {
"hyprutils": [
"hyprland-lua-config",
"hyprutils"
],
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776728575,
"narHash": "sha256-z9eGphrArEBpl1O/GCH0wlY6z4K9vA6yWh2gAS6qytU=",
@@ -1629,10 +1213,10 @@
},
"nix": {
"inputs": {
"flake-compat": "flake-compat_4",
"flake-compat": "flake-compat_3",
"flake-parts": "flake-parts",
"git-hooks-nix": "git-hooks-nix",
"nixpkgs": "nixpkgs_5",
"nixpkgs": "nixpkgs_4",
"nixpkgs-23-11": "nixpkgs-23-11",
"nixpkgs-regression": "nixpkgs-regression"
},
@@ -1689,7 +1273,7 @@
},
"nixos-wsl": {
"inputs": {
"flake-compat": "flake-compat_5",
"flake-compat": "flake-compat_4",
"nixpkgs": [
"nixpkgs"
]
@@ -1792,11 +1376,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1766070988,
"narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=",
"lastModified": 1776877367,
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c6245e83d836d0433170a16eb185cefe0572f8b8",
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
"type": "github"
},
"original": {
@@ -1807,22 +1391,6 @@
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1776548001,
"narHash": "sha256-ZSK0NL4a1BwVbbTBoSnWgbJy9HeZFXLYQizjb2DPF24=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b12141ef619e0a9c1c84dc8c684040326f27cdcc",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1776877367,
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
@@ -1838,7 +1406,7 @@
"type": "github"
}
},
"nixpkgs_5": {
"nixpkgs_4": {
"locked": {
"lastModified": 1771903837,
"narHash": "sha256-jEA8WggGKtMFeNeCKq3NK8cLEjJmG6/RLUElYYbBZ0E=",
@@ -1851,7 +1419,7 @@
"url": "https://channels.nixos.org/nixos-25.11/nixexprs.tar.xz"
}
},
"nixpkgs_6": {
"nixpkgs_5": {
"locked": {
"lastModified": 1776877367,
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
@@ -1867,7 +1435,7 @@
"type": "github"
}
},
"nixpkgs_7": {
"nixpkgs_6": {
"locked": {
"lastModified": 1697723726,
"narHash": "sha256-SaTWPkI8a5xSHX/rrKzUe+/uVNy6zCGMXgoeMb7T9rg=",
@@ -1883,7 +1451,7 @@
"type": "github"
}
},
"nixpkgs_8": {
"nixpkgs_7": {
"locked": {
"lastModified": 1703255338,
"narHash": "sha256-Z6wfYJQKmDN9xciTwU3cOiOk+NElxdZwy/FiHctCzjU=",
@@ -1903,7 +1471,7 @@
"inputs": {
"flake-parts": "flake-parts_4",
"hercules-ci-effects": "hercules-ci-effects_2",
"nixpkgs": "nixpkgs_8",
"nixpkgs": "nixpkgs_7",
"osx-kvm": "osx-kvm"
},
"locked": {
@@ -1947,7 +1515,7 @@
"noctalia",
"nixpkgs"
],
"systems": "systems_4",
"systems": "systems_3",
"treefmt-nix": "treefmt-nix"
},
"locked": {
@@ -2094,29 +1662,6 @@
"nixpkgs"
]
},
"locked": {
"lastModified": 1765911976,
"narHash": "sha256-t3T/xm8zstHRLx+pIHxVpQTiySbKqcQbK+r+01XVKc0=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "b68b780b69702a090c8bb1b973bab13756cc7a27",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"pre-commit-hooks_2": {
"inputs": {
"flake-compat": "flake-compat_2",
"gitignore": "gitignore_2",
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
]
},
"locked": {
"lastModified": 1776796298,
"narHash": "sha256-PcRvlWayisPSjd0UcRQbhG8Oqw78AcPE6x872cPRHN8=",
@@ -2131,10 +1676,10 @@
"type": "github"
}
},
"pre-commit-hooks_3": {
"pre-commit-hooks_2": {
"inputs": {
"flake-compat": "flake-compat_3",
"gitignore": "gitignore_3",
"flake-compat": "flake-compat_2",
"gitignore": "gitignore_2",
"nixpkgs": [
"imalison-taffybar",
"nixpkgs"
@@ -2213,13 +1758,11 @@
"git-ignore-nix": "git-ignore-nix",
"git-sync-rs": "git-sync-rs",
"home-manager": "home-manager",
"hy3": "hy3",
"hyprNStack": "hyprNStack",
"hyprland": "hyprland",
"hyprland-lua-config": "hyprland-lua-config",
"hyprland-plugins": "hyprland-plugins",
"hyprland-plugins-lua": "hyprland-plugins-lua",
"hyprscratch": "hyprscratch",
"hyprwinview": "hyprwinview",
"imalison-taffybar": "imalison-taffybar",
"kanshi-sni": "kanshi-sni",
"keepbook": "keepbook",
@@ -2227,13 +1770,13 @@
"nixified-ai": "nixified-ai",
"nixos-hardware": "nixos-hardware",
"nixos-wsl": "nixos-wsl",
"nixpkgs": "nixpkgs_6",
"nixpkgs": "nixpkgs_5",
"nixtheplanet": "nixtheplanet",
"noctalia": "noctalia",
"notifications-tray-icon": "notifications-tray-icon",
"org-agenda-api": "org-agenda-api",
"railbird-secrets": "railbird-secrets",
"systems": "systems_5",
"systems": "systems_4",
"vscode-server": "vscode-server",
"xmonad": "xmonad_2",
"xmonad-contrib": "xmonad-contrib_2"
@@ -2309,21 +1852,6 @@
}
},
"systems_2": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
@@ -2338,7 +1866,7 @@
"type": "github"
}
},
"systems_4": {
"systems_3": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
@@ -2353,7 +1881,7 @@
"type": "github"
}
},
"systems_5": {
"systems_4": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
@@ -2371,7 +1899,7 @@
"taffybar": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_4",
"nixpkgs": "nixpkgs_3",
"weeder-nix": "weeder-nix",
"xmonad": "xmonad",
"xmonad-contrib": "xmonad-contrib"
@@ -2442,7 +1970,7 @@
"taffybar",
"nixpkgs"
],
"pre-commit-hooks": "pre-commit-hooks_3"
"pre-commit-hooks": "pre-commit-hooks_2"
},
"locked": {
"lastModified": 1764753633,
@@ -2486,52 +2014,11 @@
]
},
"locked": {
"lastModified": 1761431178,
"narHash": "sha256-xzjC1CV3+wpUQKNF+GnadnkeGUCJX+vgaWIZsnz9tzI=",
"lastModified": 1777035886,
"narHash": "sha256-m1TNuBoSXUBSKhD9UVMkU90M0wFTPTfvIOOltO8IM8A=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "4b8801228ff958d028f588f0c2b911dbf32297f9",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"type": "github"
}
},
"xdph_2": {
"inputs": {
"hyprland-protocols": [
"hyprland-lua-config",
"hyprland-protocols"
],
"hyprlang": [
"hyprland-lua-config",
"hyprlang"
],
"hyprutils": [
"hyprland-lua-config",
"hyprutils"
],
"hyprwayland-scanner": [
"hyprland-lua-config",
"hyprwayland-scanner"
],
"nixpkgs": [
"hyprland-lua-config",
"nixpkgs"
],
"systems": [
"hyprland-lua-config",
"systems"
]
},
"locked": {
"lastModified": 1776608502,
"narHash": "sha256-UH8YoQxx4hFOm6qjMdjRQNRvSejFIR/wBZ8fW1p9sME=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "4a293523d36dfa367e67ec304cc718ea66a8fec2",
"rev": "ecfcdcc781f48821d83e1e2a0e30d7beca0eeb5e",
"type": "github"
},
"original": {

View File

@@ -93,35 +93,25 @@
# Hyprland and plugins from official flakes for proper plugin compatibility
hyprland = {
url = "git+https://github.com/hyprwm/Hyprland?submodules=1&ref=refs/tags/v0.53.0";
};
hyprland-lua-config = {
# Experimental Lua config branch from PR 13817.
url = "git+https://github.com/hyprwm/Hyprland?submodules=1&ref=refs/pull/13817/head";
url = "git+https://github.com/hyprwm/Hyprland?submodules=1";
};
hyprNStack = {
url = "github:colonelpanic8/hyprNStack?ref=hyprland-lua-integration";
inputs = {
hyprland.follows = "hyprland-lua-config";
hyprland.follows = "hyprland";
nixpkgs.follows = "nixpkgs";
};
};
hy3 = {
url = "github:outfoxxed/hy3?ref=hl0.53.0";
inputs.hyprland.follows = "hyprland";
};
hyprland-plugins = {
url = "github:colonelpanic8/hyprland-plugins?ref=hyprexpo-v0.53.0-custom";
inputs.hyprland.follows = "hyprland";
};
hyprland-plugins-lua = {
url = "github:colonelpanic8/hyprland-plugins?ref=codex/fix-main-ci";
inputs.hyprland.follows = "hyprland-lua-config";
inputs.hyprland.follows = "hyprland";
};
hyprwinview = {
url = "github:colonelpanic8/hyprwinview";
inputs.hyprland.follows = "hyprland";
};
hyprscratch = {
@@ -161,26 +151,11 @@
};
};
taffybar = {
# Use a remote, lockfile-pinned input so rebuilds are reproducible across
# machines. For local development, use `nixos-rebuild --override-input taffybar path:...`.
url = "github:taffybar/taffybar";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-utils.follows = "flake-utils";
xmonad.follows = "xmonad";
xmonad-contrib.follows = "xmonad-contrib";
weeder-nix.url = "github:NorfairKing/weeder-nix";
weeder-nix.inputs.pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
};
};
imalison-taffybar = {
url = "path:../dotfiles/config/taffybar";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-utils.follows = "flake-utils";
taffybar.follows = "taffybar";
xmonad.follows = "xmonad";
};
};
@@ -243,7 +218,6 @@
nixpkgs,
nixos-hardware,
home-manager,
taffybar,
xmonad,
nixtheplanet,
xmonad-contrib,
@@ -252,8 +226,6 @@
agenix,
imalison-taffybar,
hyprland,
hy3,
hyprland-plugins,
org-agenda-api,
flake-utils,
...
@@ -504,6 +476,26 @@
containerLib = import ../org-agenda-api/container.nix {
inherit pkgs system tangledConfig org-agenda-api orgApiRev dotfilesRev;
};
hyprlandPkgs = import nixpkgs {
inherit system;
overlays = [ hyprland.overlays.hyprland-packages ];
};
hyprWorkspaceHistory = hyprlandPkgs.hyprlandPlugins.mkHyprlandPlugin {
pluginName = "hypr-workspace-history";
version = "0.1.0";
src = builtins.path {
path = ../dotfiles/config/hypr/workspace-history-plugin;
name = "hypr-workspace-history-source";
};
inherit (hyprland.packages.${system}.hyprland) nativeBuildInputs;
meta = {
description = "Workspace history cycling plugin for Hyprland";
license = lib.licenses.bsd3;
platforms = lib.platforms.linux;
};
};
in {
packages = {
colonelpanic-org-agenda-api = containerLib.containers.colonelpanic;
@@ -511,16 +503,21 @@
} // lib.optionalAttrs pkgs.stdenv.isLinux {
hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack;
hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo;
hyprwinview = inputs.hyprwinview.packages.${system}.hyprwinview;
hypr-workspace-history = hyprWorkspaceHistory;
};
checks = lib.optionalAttrs pkgs.stdenv.isLinux {
hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack;
hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo;
hyprland-lua-config-syntax = pkgs.runCommand "hyprland-lua-config-syntax" {
hyprwinview = inputs.hyprwinview.packages.${system}.hyprwinview;
hypr-workspace-history = hyprWorkspaceHistory;
hyprland-config-syntax = pkgs.runCommand "hyprland-config-syntax" {
nativeBuildInputs = [ pkgs.lua5_4 ];
} ''
luac -p ${../dotfiles/config/hypr/hyprland.lua}
if grep -n 'hyprctl' ${../dotfiles/config/hypr/hyprland.lua} | grep -v 'hyprctl reload'; then
cp ${../dotfiles/config/hypr/hyprland.lua} hyprland.lua
luac -p hyprland.lua
if grep -n 'hyprctl' hyprland.lua | grep -v 'hyprctl reload' | grep -v 'hyprctl dispatch hyprwinview:overview'; then
echo "hyprland.lua should not shell out to hyprctl for window/workspace manipulation" >&2
exit 1
fi
@@ -629,7 +626,7 @@
end,
}
dofile("${../dotfiles/config/hypr/hyprland.lua}")
dofile("./hyprland.lua")
for _, callback in ipairs(callbacks) do
callback()
@@ -637,8 +634,8 @@
LUA
touch "$out"
'';
hyprland-lua-verify-config = let
hyprlandPackage = inputs.hyprland-lua-config.packages.${system}.hyprland;
hyprland-verify-config = let
hyprlandPackage = inputs.hyprland.packages.${system}.hyprland;
hyprNStackPackage = inputs.hyprNStack.packages.${system}.hyprNStack;
in pkgs.runCommand "hyprland-lua-verify-config" {} ''
cp ${../dotfiles/config/hypr/hyprland.lua} hyprland.lua

View File

@@ -7,16 +7,13 @@
...
}:
let
cfg = config.myModules.hyprland;
system = pkgs.stdenv.hostPlatform.system;
enableExternalPluginPackages = !cfg.useLuaConfigBranch;
hyprlandInput =
if cfg.useLuaConfigBranch
then inputs.hyprland-lua-config
else inputs.hyprland;
luaPluginPackages = lib.optionals cfg.useLuaConfigBranch [
hyprlandInput = inputs.hyprland;
hyprlandPluginPackages = [
inputs.hyprNStack.packages.${system}.hyprNStack
inputs.hyprland-plugins-lua.packages.${system}.hyprexpo
inputs.hyprwinview.packages.${system}.hyprwinview
inputs.self.packages.${system}.hypr-workspace-history
];
hyprRofiWindow = pkgs.writeShellApplication {
name = "hypr_rofi_window";
@@ -159,22 +156,17 @@ let
};
programs.hyprscratch = {
enable = !cfg.useLuaConfigBranch;
enable = false;
settings = { };
};
xdg.configFile."hyprscratch/config.conf" = lib.mkIf (!cfg.useLuaConfigBranch) {
xdg.configFile."hyprscratch/config.conf" = lib.mkIf false {
text = lib.hm.generators.toHyprconf {
attrs = hyprscratchSettings;
};
};
xdg.configFile."hypr/hyprland.conf" = {
force = true;
source = hyprConfig "hyprland.conf";
};
xdg.configFile."hypr/hyprland.lua" = lib.mkIf cfg.useLuaConfigBranch {
xdg.configFile."hypr/hyprland.lua" = {
force = true;
source = hyprConfig "hyprland.lua";
};
@@ -212,29 +204,7 @@ let
hyprShellUi
jq
]
++ luaPluginPackages
++ lib.optionals enableExternalPluginPackages [
# External plugin packages are pinned to the stable 0.53 stack.
# Keep hy3 on the stable stack; the Lua branch uses hyprNStack and the
# forked Lua-compatible hyprexpo input instead.
inputs.hy3.packages.${system}.hy3
inputs.hyprland-plugins.packages.${system}.hyprexpo
];
++ hyprlandPluginPackages;
};
in
enabledModule
// {
options = lib.recursiveUpdate enabledModule.options {
myModules.hyprland.useLuaConfigBranch = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Use the experimental Hyprland PR 13817 Lua-config branch for the
Hyprland package itself. The experimental package set excludes hy3, and
includes the Lua-branch builds of hyprNStack and hyprexpo instead. When
a sibling `hyprland.lua` is present, the Lua config manager picks it
before `hyprland.conf`.
'';
};
};
}