diff --git a/dotfiles/config/hypr/hyprland.conf b/dotfiles/config/hypr/hyprland.conf deleted file mode 100644 index fb7ceff2..00000000 --- a/dotfiles/config/hypr/hyprland.conf +++ /dev/null @@ -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 diff --git a/dotfiles/config/hypr/hyprland.lua b/dotfiles/config/hypr/hyprland.lua index 5aaed885..5b5b8b13 100644 --- a/dotfiles/config/hypr/hyprland.lua +++ b/dotfiles/config/hypr/hyprland.lua @@ -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) diff --git a/dotfiles/config/hypr/workspace-history-plugin/CMakeLists.txt b/dotfiles/config/hypr/workspace-history-plugin/CMakeLists.txt new file mode 100644 index 00000000..430597d6 --- /dev/null +++ b/dotfiles/config/hypr/workspace-history-plugin/CMakeLists.txt @@ -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) diff --git a/dotfiles/config/hypr/workspace-history-plugin/src/main.cpp b/dotfiles/config/hypr/workspace-history-plugin/src/main.cpp new file mode 100644 index 00000000..f0b99dec --- /dev/null +++ b/dotfiles/config/hypr/workspace-history-plugin/src/main.cpp @@ -0,0 +1,406 @@ +#define WLR_USE_UNSTABLE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +inline HANDLE PHANDLE = nullptr; + +namespace { + +constexpr int MAX_WORKSPACE = 9; + +struct SCycleState { + std::string monitorKey; + int originalWorkspace = 0; + int previewWorkspace = 0; + std::vector 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> m_histories; + std::optional m_cycle; + + static std::optional 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& history, int workspace) { + return std::ranges::contains(history, workspace); + } + + static std::vector promote(std::vector 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(size); + auto next = static_cast(current) + direction; + next = ((next % signedSize) + signedSize) % signedSize; + return static_cast(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 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(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(); +} diff --git a/nixos/flake.lock b/nixos/flake.lock index 8d892695..6a3930e1 100644 --- a/nixos/flake.lock +++ b/nixos/flake.lock @@ -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": { diff --git a/nixos/flake.nix b/nixos/flake.nix index 0c40a699..9dc7e685 100644 --- a/nixos/flake.nix +++ b/nixos/flake.nix @@ -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 diff --git a/nixos/hyprland.nix b/nixos/hyprland.nix index ded5a4f7..8dd764bf 100644 --- a/nixos/hyprland.nix +++ b/nixos/hyprland.nix @@ -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`. - ''; - }; - }; -}