commit 97a309bbe3af518b871c796b9a2bf886ce5ad844 Author: Prad Nukala Date: Wed Oct 14 13:32:29 2026 -0400 Import from root chezmoi source diff --git a/config.kdl b/config.kdl new file mode 100644 index 0000000..08726e8 --- /dev/null +++ b/config.kdl @@ -0,0 +1,195 @@ +// ============================================================================ +// NIRI CONFIGURATION - Base for iNiR (ii) +// ============================================================================ +// Minimal base config - customize to your needs +// Wiki: https://github.com/YaLTeR/niri/wiki/Configuration:-Introduction +// ============================================================================ + + +hotkey-overlay { + skip-at-startup +} + +screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" + +include "config.d/10-input-and-cursor.kdl" + +include "config.d/20-layout-and-overview.kdl" + +include "config.d/30-window-rules.kdl" + +include "config.d/40-environment.kdl" + +include "config.d/50-startup.kdl" + +include "config.d/60-animations.kdl" + +include "config.d/70-binds.kdl" + +include "config.d/80-layer-rules.kdl" + +include "config.d/90-outputs.kdl" + +// ============================================================================ +// Layer rules added by iNiR (required for backdrop in overview) +// ============================================================================ + +input { + keyboard { + xkb { + layout "us" + } + repeat-delay 400 + repeat-rate 50 + } + touchpad { + natural-scroll + tap + tap-button-map "left-right-middle" + } + + mod-key "Super" + mod-key-nested "Alt" +} + +// ============================================================================ +// LAYOUT +// ============================================================================ + +layout { + background-color "transparent" + default-column-width { proportion 0.5; } + + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + focus-ring { + width 1.5 + active-color "#7fc8ff" + inactive-color "transparent" + } + + border { + off + width 1.5 + active-color "#ffc87f" + inactive-color "transparent" + urgent-color "#9b0000" + } + + shadow { + off + softness 30 + spread 5 + offset x=0 y=5 + color "#0007" + } + + tab-indicator { + place-within-column + hide-when-single-tab + position "left" // Can be "left", "right", "top", or "bottom" + } + +} + +gestures { + hot-corners { + off + } +} + +cursor { + xcursor-theme "capitaine-cursors-light" + xcursor-size 24 + hide-when-typing +} + +overview { + zoom 0.4 + workspace-shadow { off; } +} +// ============================================================================ +// WINDOW RULES +// ============================================================================ + +window-rule { + geometry-corner-radius 8 + clip-to-geometry true +} + +// ============================================================================ +// ANIMATIONS +// ============================================================================ +// Tuned to complement quickshell's expressive Material motion curves +// QS uses ~500ms for main movements, ~400ms enter, ~200ms exit + +animations { + workspace-switch { + spring damping-ratio=0.78 stiffness=1350 epsilon=0.0001 + } + window-open { + spring damping-ratio=0.82 stiffness=1125 epsilon=0.0001 + } + window-close { + spring damping-ratio=0.88 stiffness=2025 epsilon=0.0001 + } + horizontal-view-movement { + spring damping-ratio=0.80 stiffness=1238 epsilon=0.0001 + } + window-movement { + spring damping-ratio=0.85 stiffness=1463 epsilon=0.0001 + } + window-resize { + spring damping-ratio=0.88 stiffness=1575 epsilon=0.0001 + } + config-notification-open-close { + spring damping-ratio=0.90 stiffness=1800 epsilon=0.0001 + } + screenshot-ui-open { + spring damping-ratio=0.85 stiffness=1688 epsilon=0.0001 + } +} + +// ============================================================================ +// ENVIRONMENT +// ============================================================================ + +environment { + XDG_CURRENT_DESKTOP "niri" + XDG_MENU_PREFIX "plasma-" // Required for Dolphin/KDE app file associations + QT_QPA_PLATFORM "wayland" + ELECTRON_OZONE_PLATFORM_HINT "auto" + QT_LOGGING_RULES "quickshell.dbus.properties=false" + + // Qt theming: kde platform reads colors from kdeglobals (requires plasma-integration pkg) + // The installer falls back to qt6ct only if plasma-integration is not installed + QT_QPA_PLATFORMTHEME "kde" + QT_STYLE_OVERRIDE "Darkly" + + // Quickshell Python virtual environment + INIR_VENV "$HOME/.local/state/quickshell/.venv" + ILLOGICAL_IMPULSE_VIRTUAL_ENV "$HOME/.local/state/quickshell/.venv" +} + +// ============================================================================ +// STARTUP — commands live in config.d/50-startup.kdl +// ============================================================================ + +// Noctalia v5: allows notification actions and window activation from Noctalia. +debug { + honor-xdg-activation-with-invalid-serial +} + + +// ============================================================================ +// KEYBINDINGS +// ============================================================================ + + +include "./noctalia.kdl" + +prefer-no-csd diff --git a/exact_config.d/10-input-and-cursor.kdl b/exact_config.d/10-input-and-cursor.kdl new file mode 100644 index 0000000..d7cb00f --- /dev/null +++ b/exact_config.d/10-input-and-cursor.kdl @@ -0,0 +1,44 @@ +// Outputs (example - disabled by default) +// Run `niri msg outputs` inside a niri session to see connector names and modes. +// Then edit and uncomment this block to pin a specific monitor layout. + +// ============================================================================ +// INPUT +// ============================================================================ + +input { + keyboard { + xkb { + layout "us" + } + repeat-delay 400 + repeat-rate 50 + } + touchpad { + natural-scroll + tap + tap-button-map "left-right-middle" + accel-speed 1.0 + } + + tablet { + map-to-output "eDP-1" + } + + touch { + map-to-output "eDP-1" + } + + mod-key "Super" + mod-key-nested "Alt" +} + +gestures { + +} + +cursor { + xcursor-theme "capitaine-cursors-light" + xcursor-size 24 + hide-when-typing +} diff --git a/exact_config.d/20-layout-and-overview.kdl b/exact_config.d/20-layout-and-overview.kdl new file mode 100644 index 0000000..a19ca5f --- /dev/null +++ b/exact_config.d/20-layout-and-overview.kdl @@ -0,0 +1,57 @@ +layout { + center-focused-column "never" + background-color "transparent" + default-column-width { proportion 0.5; } + + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + focus-ring { + width 1.5 + active-color "#7fc8ff" + inactive-color "transparent" + } + + border { + off + width 1.5 + active-color "#ffc87f" + inactive-color "transparent" + urgent-color "#9b0000" + } + + shadow { + off + softness 30 + spread 5 + offset x=0 y=5 + color "#0007" + } + + tab-indicator { + place-within-column + hide-when-single-tab + position "left" // Can be "left", "right", "top", or "bottom" + } + + +} + +gestures { + hot-corners { + } +} + +cursor { + xcursor-theme "capitaine-cursors-light" + xcursor-size 24 + hide-when-typing +} + +overview { + zoom 0.4 + workspace-shadow { off; } +} diff --git a/exact_config.d/30-window-rules.kdl b/exact_config.d/30-window-rules.kdl new file mode 100644 index 0000000..d12feb0 --- /dev/null +++ b/exact_config.d/30-window-rules.kdl @@ -0,0 +1,103 @@ +// ============================================================================ +// WINDOW RULES +// ============================================================================ + +window-rule { + geometry-corner-radius 10 + clip-to-geometry true +} + +window-rule { + background-effect { + blur true + xray false + } +} + +// Noctalia v5: floating settings window. +window-rule { + match app-id="dev.noctalia.Noctalia" + open-floating true + default-column-width { fixed 1080; } + default-window-height { fixed 920; } +} + +blur { + passes 4 + offset 5.0 + noise 0.02 + saturation 2.0 +} + +window-rule { + match app-id="Folo" + match app-id="Spotify" + match app-id="zen" + match app-id="brave-origin" + match app-id="gemini-desktop" + match app-id="claude-desktop" + opacity 0.9 + open-floating false + draw-border-with-background false + background-effect { + blur true + xray false + } + open-focused true +} + +window-rule { + match app-id="kitty" + match app-id="zed" + match app-id="obsidian" + match app-id="Beeper" + match app-id="chromium" + match app-id="com.mitchellh.ghostty" + opacity 0.9 + open-floating false + draw-border-with-background false + open-focused true + background-effect { + blur true + xray false + } +} + +window-rule { + match app-id="org.gnome.Nautilus" + match app-id="com.gabm.satty" + open-floating true + open-focused true + draw-border-with-background false + default-column-width { proportion 0.5; } +} + + +window-rule { + match title="Picture-in-Picture" app-id="zen" + match title="Picture in picture" + open-floating true + open-focused false + opacity 1.0 + + // default-floating-position x=28 y=28 relative-to="top-right" + default-floating-position x=24 y=24 relative-to="top-right" + open-on-output "eDP-1" + // open-on-output "HDMI-A-1" + // open-on-output "Apple Computer Inc StudioDisplay 0x984262A7" +} + +window-rule { + match app-id="zed" + match app-id="obsidian" + match app-id="sticky-notest-canvas" + match title="Sticky Notes" + match app-id="vacuumtube" + match app-id="Fladder" + match app-id="kitty" + match app-id="kitty-herdr" + match app-id="kitty-tmux" + + open-on-output "Apple Computer Inc StudioDisplay 0x984262A7" +} + diff --git a/exact_config.d/40-environment.kdl b/exact_config.d/40-environment.kdl new file mode 100644 index 0000000..1ffe0bc --- /dev/null +++ b/exact_config.d/40-environment.kdl @@ -0,0 +1,22 @@ +// ============================================================================ +// ENVIRONMENT +// ============================================================================ + +environment { + XDG_CURRENT_DESKTOP "niri" + XDG_MENU_PREFIX "plasma-" // Required for Dolphin/KDE app file associations + QT_QPA_PLATFORM "wayland" + ELECTRON_OZONE_PLATFORM_HINT "auto" + QT_LOGGING_RULES "quickshell.dbus.properties=false" + + // Qt theming: kde platform reads colors from kdeglobals (requires plasma-integration pkg) + // The installer falls back to qt6ct only if plasma-integration is not installed + QT_QPA_PLATFORMTHEME "kde" + QT_STYLE_OVERRIDE "Darkly" + + // Quickshell Python virtual environment + INIR_VENV "$HOME/.local/state/quickshell/.venv" + ILLOGICAL_IMPULSE_VIRTUAL_ENV "$HOME/.local/state/quickshell/.venv" +} + + diff --git a/exact_config.d/50-startup.kdl b/exact_config.d/50-startup.kdl new file mode 100644 index 0000000..7154a9c --- /dev/null +++ b/exact_config.d/50-startup.kdl @@ -0,0 +1,11 @@ +// ============================================================================ +// STARTUP +// ============================================================================ + +// Import XDG_MENU_PREFIX to systemd for Dolphin/KDE app file associations +spawn-at-startup "bash" "-c" "systemctl --user import-environment XDG_MENU_PREFIX && kbuildsycoca6" +spawn-at-startup "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1" +spawn-at-startup "noctalia" +spawn-at-startup "niri-dynamic-workspaces" "daemon" +spawn-at-startup "vicinae" "server" +spawn-at-startup "bash" "-c" "wl-paste --watch cliphist store &" diff --git a/exact_config.d/60-animations.kdl b/exact_config.d/60-animations.kdl new file mode 100644 index 0000000..ed2a530 --- /dev/null +++ b/exact_config.d/60-animations.kdl @@ -0,0 +1,32 @@ +// ============================================================================ +// ANIMATIONS +// ============================================================================ +// Tuned to complement quickshell's expressive Material motion curves +// QS uses ~500ms for main movements, ~400ms enter, ~200ms exit + +animations { + workspace-switch { +spring damping-ratio=1.0 stiffness=4000 epsilon=0.0001 + } + window-open { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } + window-close { + spring damping-ratio=1.0 stiffness=6000 epsilon=0.0001 + } + horizontal-view-movement { + spring damping-ratio=1.0 stiffness=4500 epsilon=0.0001 + } + window-movement { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } + window-resize { + spring damping-ratio=1.0 stiffness=5500 epsilon=0.0001 + } + config-notification-open-close { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } + screenshot-ui-open { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } +} diff --git a/exact_config.d/70-binds.kdl b/exact_config.d/70-binds.kdl new file mode 100644 index 0000000..34292dc --- /dev/null +++ b/exact_config.d/70-binds.kdl @@ -0,0 +1,156 @@ +// ============================================================================ +// KEYBINDINGS +// ============================================================================ + + +binds { + // System + Mod+Tab repeat=false { toggle-overview; } + Mod+Shift+E { quit; } + Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } + + // ii Overview (daemon) + Mod+Space repeat=false { spawn "vicinae" "toggle"; } + Mod+Shift+Space repeat=false { spawn "vicinae" "vicinae://launch/core/search-emojis"; } + Mod+Shift+Return repeat=false { spawn "vicinae" "vicinae://launch/wm/switch-windows"; } + Mod+BackSpace { focus-window-previous; } + + // ii Clipboard + Mod+P { spawn "vicinae" "vicinae://launch/clipboard/history"; } + Mod+Ctrl+R { spawn "noctalia" "msg" "plugin" "prdlk/ostt:recorder" "focused" "toggle"; } + + // ii Region tools + // Goliath: mosh + tmux and the tmux keymaps live in ~/.config/kitty/goliath.conf + Mod+Shift+G { spawn-sh "kitty --class=kitty-goliath --title=goliath --config ~/.config/kitty/goliath.conf"; } + Mod+S { spawn "dot-screenshot" "region"; } + Mod+Shift+S { spawn "dot-screenshot" "window"; } + Mod+Ctrl+S { spawn "dot-screenshot" "monitor-focused"; } + Mod+Ctrl+Shift+S { spawn "dot-screenshot" "monitor-all"; } + // v4: Mod+Period { spawn-sh "qs -c noctalia-shell ipc call controlCenter toggle"; } + // v4: Mod+Comma { spawn-sh "qs -c noctalia-shell ipc call settings toggle"; } + Mod+Period { spawn-sh "noctalia msg panel-toggle control-center"; } + Mod+Comma { spawn-sh "noctalia msg settings-toggle"; } + + Super+Ctrl+A { spawn "vicinae" "vicinae://launch/applications/com.anthropic.Claude"; } + Super+Ctrl+G { spawn "vicinae" "vicinae://launch/applications/gemini-desktop"; } + Super+Alt+Ctrl+H { spawn "niri-launch-ai"; } + Super+Alt+Ctrl+J { spawn "niri-launch-terminal"; } + Super+Alt+Ctrl+K { spawn "niri-launch-browser"; } + Super+Alt+Ctrl+O { spawn "niri-launch" "obsidian"; } + Super+Alt+Ctrl+W { spawn "vicinae" "vicinae://launch/applications/tldraw_offline"; } + Super+Alt+Ctrl+E { spawn "vicinae" "vicinae://launch/applications/com.fastmail.Fastmail"; } + Super+Alt+Ctrl+B { spawn "vicinae" "vicinae://launch/applications/beeper"; } + Super+Alt+Ctrl+G { spawn "vicinae" "vicinae://launch/applications/com.mitchellh.ghostty"; } + Super+Alt+Ctrl+L { spawn "vicinae" "vicinae://launch/applications/WebApp-Linear3312"; } + Super+Alt+Ctrl+M { spawn "vicinae" "vicinae://launch/applications/beeper"; } + Super+Alt+Ctrl+T { spawn "vicinae" "vicinae://launch/applications/todoist"; } + Super+Alt+Ctrl+N { spawn "noctalia" "msg" "panel-open" "noctalia/notes:panel"; } + Super+Alt+Ctrl+F { spawn "vicinae" "vicinae://launch/applications/org.gnome.Nautilus"; } + Super+Alt+Ctrl+Space { spawn "vicinae" "vicinae://launch/applications/io.github.faridjaff.StickyNotesCanvas"; } + Super+Alt+Ctrl+Return { spawn "vicinae" "vicinae://launch/wm/switch-windows"; } + + Super+Shift+Alt+Ctrl+W { spawn "niri-dynamic-workspaces" "switch" "w"; } + Super+Shift+Alt+Ctrl+H { spawn "niri-dynamic-workspaces" "switch" "h"; } + Super+Alt+Ctrl+Y { spawn "niri-launch-webapp"; } + Super+Alt+Ctrl+X { spawn "niri-dynamic-workspaces" "switch" "x"; } + + // ─── Monitors ─── (Vertical) + Mod+Left { focus-monitor-left; } + Mod+Up { focus-monitor-up; } + Mod+Right { focus-monitor-right; } + Mod+Shift+Down { move-column-to-monitor-right; } + Mod+Shift+Up { move-column-to-monitor-left; } + + // ─── Layout ─── + Mod+R { switch-preset-column-width; } + Mod+Shift+R { switch-preset-window-height; } + Mod+Shift+F { maximize-column; } + Mod+F { expand-column-to-available-width; } + Super+C { center-column; } + Mod+Ctrl+C { center-visible-columns; } + Mod+Ctrl+F { fullscreen-window; } + Mod+Ctrl+O { toggle-window-floating; } + + // ─── Window Sizing: hjkl ─── + Alt+Shift+H { set-column-width "-10%"; } + Alt+Shift+J { set-window-height "-10%"; } + Alt+Shift+K { set-window-height "+10%"; } + Alt+Shift+L { set-column-width "+10%"; } + + + + // Window management + Mod+Q repeat=false { spawn "/home/prad/.local/bin/niri-smart-close"; } + + // Focus + Mod+H { focus-column-left-or-last; } + Mod+L { focus-column-right-or-first; } + Mod+J { focus-window-or-workspace-down; } + Mod+K { focus-window-or-workspace-up; } + + // Workspaces + Mod+Shift+J { move-column-to-workspace-down; } + Mod+Shift+K { move-column-to-workspace-up; } + + // Monitors + Super+O { focus-monitor-next; } + Super+Ctrl+J { focus-monitor-next; } + Super+Ctrl+K { focus-monitor-previous; } + Super+Shift+O { move-column-to-monitor-next; } + Mod+Ctrl+Shift+J { move-column-to-monitor-next; } + Mod+Ctrl+Shift+K { move-column-to-monitor-previous; } + + // Columns + Super+Ctrl+H { focus-column-first; } + Super+Ctrl+L { focus-column-last; } + Super+Ctrl+Shift+H { move-column-to-first; } + Super+Ctrl+Shift+L { move-column-to-last; } + + // Tabs + Mod+W { toggle-column-tabbed-display; } + Mod+Shift+H { spawn "/home/prad/.local/bin/niri-smart-move" "left"; } + Mod+Shift+L { spawn "/home/prad/.local/bin/niri-smart-move" "right"; } + + // Screenshots (native) + Print { screenshot; } + Ctrl+Print { screenshot-screen; } + Alt+Print { screenshot-window; } + + // ======================================================================== + // HARDWARE KEYS - Audio, Brightness, Media + // ======================================================================== + // These use noctalia IPC so the OSD (On Screen Display) shows feedback + + Mod+F24 { spawn "voxtype" "record" "toggle" "--profile" "hermes"; } + + // ─── Media Controls ─── + // v4: XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume increase"; } + // v4: XF86AudioLowerVolume allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume decrease"; } + // v4: XF86AudioMute allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume muteOutput"; } + // v4: XF86AudioMicMute allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume muteInput"; } + // v4: XF86AudioNext allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media next"; } + // v4: XF86AudioPrev allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media previous"; } + // v4: XF86AudioPlay allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media playPause"; } + // v4: XF86AudioPause allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media playPause"; } + XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "noctalia msg volume-up"; } + XF86AudioLowerVolume allow-when-locked=true { spawn-sh "noctalia msg volume-down"; } + XF86AudioMute allow-when-locked=true { spawn-sh "noctalia msg volume-mute"; } + XF86AudioMicMute allow-when-locked=true { spawn-sh "noctalia msg mic-mute"; } + XF86AudioNext allow-when-locked=true { spawn-sh "noctalia msg media next"; } + XF86AudioPrev allow-when-locked=true { spawn-sh "noctalia msg media previous"; } + XF86AudioPlay allow-when-locked=true { spawn-sh "noctalia msg media toggle"; } + XF86AudioPause allow-when-locked=true { spawn-sh "noctalia msg media toggle"; } + + // ─── Brightness Controls ─── + // v4: XF86MonBrightnessUp allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call brightness increase"; } + // v4: XF86MonBrightnessDown allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call brightness decrease"; } + XF86MonBrightnessUp allow-when-locked=true { spawn-sh "noctalia msg brightness-up"; } + XF86MonBrightnessDown allow-when-locked=true { spawn-sh "noctalia msg brightness-down"; } + + // Power / Session + // v4: Mod+Shift+Q { spawn-sh "qs -c noctalia-shell ipc call sessionMenu toggle"; } + Mod+Shift+Q hotkey-overlay-title="Session Menu: noctalia session" { spawn-sh "noctalia msg panel-toggle session"; } + +} + + diff --git a/exact_config.d/80-layer-rules.kdl b/exact_config.d/80-layer-rules.kdl new file mode 100644 index 0000000..fee5ce8 --- /dev/null +++ b/exact_config.d/80-layer-rules.kdl @@ -0,0 +1,34 @@ + + + +/* + Noctalia v5: disable xray on all our surfaces so blur looks more realistic. + Noctalia publishes blur regions automatically when ext-background-effects is available. +*/ +layer-rule { + match namespace="^noctalia-(bar-[^\"]+|notification|dock|panel|attached-panel|osd)$" + background-effect { + xray false + //blur false + } +} + +// Option 2 (Stationary Wallpaper): place the regular wallpaper on the backdrop. +layer-rule { + match namespace="^noctalia-wallpaper" + place-within-backdrop true +} + +// Set transparent workspace background color so you see the backdrop at all times. +layout { + background-color "transparent" +} + +// Optionally, disable the workspace shadows in the overview. +overview { + workspace-shadow { + off + } +} + + diff --git a/exact_config.d/90-outputs.kdl b/exact_config.d/90-outputs.kdl new file mode 100644 index 0000000..482966f --- /dev/null +++ b/exact_config.d/90-outputs.kdl @@ -0,0 +1,47 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ +// +// // Apple Display +// output "Apple Computer Inc StudioDisplay 0x984262A7" { +// position x=0 y=0 +// scale 1.5 +// layout { +// center-focused-column "never" +// always-center-single-column true +// gaps 8 +// default-column-width { +// proportion 0.75 +// } +// preset-column-widths { +// proportion 0.25 +// proportion 0.5 +// proportion 0.75 +// } +// } +// } +// +// +// +output "DP-5" { + off +} +// +// +// output "DP-4" { +// off +// } +// ============================================================================ +// OUTPUTS +// ============================================================================ +// The Studio Display exposes a phantom second connector (DP-4/5/6, varies per +// boot) whose only mode is 640x480. Connector name and EDID both shift, so it +// can't be matched in config — this script finds it by mode signature instead. +// spawn-at-startup "/home/prad/.config/niri/scripts/kill-phantom-display.fish" + + +include "91-internal-display.kdl" +// include "92-ultrawide.kdl" +include "93-apple-display.kdl" +include "94-portable-hdmi.kdl" +// include "95-portable-usbc.kdl" diff --git a/exact_config.d/91-internal-display.kdl b/exact_config.d/91-internal-display.kdl new file mode 100644 index 0000000..132c56f --- /dev/null +++ b/exact_config.d/91-internal-display.kdl @@ -0,0 +1,69 @@ + +// Internal Display +output "Tianma Microelectronics Ltd. TL134ADXP03 Unknown" { + position x=0 y=0 + scale 1.5 + variable-refresh-rate on-demand=true + layout { + always-center-single-column true + center-focused-column "never" + gaps 8 + default-column-width { proportion 1.0; } + preset-column-widths { + proportion 0.5 + proportion 1.0 + } + } +} + +workspace "1" { + open-on-output "Tianma Microelectronics Ltd. TL134ADXP03 Unknown" +} + +window-rule { + match app-id="chrome-youtube.com__-Default" + match app-id="chromium" + + draw-border-with-background false + + open-focused true + open-maximized true + open-on-workspace "1" +} + +workspace "2" { + open-on-output "Tianma Microelectronics Ltd. TL134ADXP03 Unknown" +} + +window-rule { + match app-id="org.gnome.Calendar" + match app-id="discord" + match app-id="slack" + match app-id="com-fastmail-fastmail" + match app-id="gemini-desktop" + match app-id="Beeper" + match app-id="com.anthropic.Claude" + match app-id="Hermes" + match app-id="todoist" + + draw-border-with-background false + + open-focused true + open-maximized true + open-on-workspace "1" +} + +workspace "3" { + open-on-output "Tianma Microelectronics Ltd. TL134ADXP03 Unknown" +} + +window-rule { + match app-id="WebApp-CloudflarePersonal7594" + match app-id="WebApp-CloudflareWalletbase8881" + + draw-border-with-background false + + open-focused true + open-maximized true + open-on-workspace "1" +} diff --git a/exact_config.d/92-ultrawide.kdl b/exact_config.d/92-ultrawide.kdl new file mode 100644 index 0000000..777249d --- /dev/null +++ b/exact_config.d/92-ultrawide.kdl @@ -0,0 +1,24 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +output "Samsung Electric Company S34CG50 HNTY501103" { + position x=0 y=0 + mode "3440x1440@100.00" + scale 1 + variable-refresh-rate on-demand=true + layout { + center-focused-column "never" + always-center-single-column true + gaps 16 + default-column-width { + proportion 0.3333 + } + preset-column-widths { + proportion 0.3333 + proportion 0.5 + proportion 0.6667 + } + } +} + diff --git a/exact_config.d/93-apple-display.kdl b/exact_config.d/93-apple-display.kdl new file mode 100644 index 0000000..136e039 --- /dev/null +++ b/exact_config.d/93-apple-display.kdl @@ -0,0 +1,23 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +// Apple Display +output "Apple Computer Inc StudioDisplay 0x984262A7" { + scale 1.75 + layout { + center-focused-column "never" + always-center-single-column true + gaps 8 + default-column-width { + proportion 0.5 + } + preset-column-widths { + proportion 0.25 + proportion 0.3333 + proportion 0.5 + proportion 0.6667 + } + } +} + diff --git a/exact_config.d/94-portable-hdmi.kdl b/exact_config.d/94-portable-hdmi.kdl new file mode 100644 index 0000000..321c925 --- /dev/null +++ b/exact_config.d/94-portable-hdmi.kdl @@ -0,0 +1,22 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +// Portable Display #1 +output "PNP(AOP) 16PM1QB 14490001D3X00" { + transform "90" + layout { + always-center-single-column true + center-focused-column "never" + gaps 2 + default-column-width { + proportion 1.0 + } + preset-column-widths { + proportion 0.5 + proportion 1.0 + } + } +} + + diff --git a/exact_config.d/95-portable-usbc.kdl b/exact_config.d/95-portable-usbc.kdl new file mode 100644 index 0000000..2c1c831 --- /dev/null +++ b/exact_config.d/95-portable-usbc.kdl @@ -0,0 +1,20 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +output "ASUSTek COMPUTER INC ASUS MB16AC M8LMTF195749" { + position x=0 y=0 + layout { + always-center-single-column true + center-focused-column "never" + gaps 2 + default-column-width { + proportion 1.0 + } + preset-column-widths { + proportion 0.5 + proportion 1.0 + } + } +} + diff --git a/noctalia.kdl b/noctalia.kdl new file mode 100644 index 0000000..28d5427 --- /dev/null +++ b/noctalia.kdl @@ -0,0 +1,35 @@ +layout { + + focus-ring { + active-color "#a398b3" + inactive-color "#1e1c21" + urgent-color "#fd4663" + } + + border { + active-color "#a398b3" + inactive-color "#1e1c21" + urgent-color "#fd4663" + } + + shadow { + color "#1e1c2170" + } + + tab-indicator { + active-color "#a398b3" + inactive-color "#4a4158" + urgent-color "#fd4663" + } + + insert-hint { + color "#a398b380" + } +} + +recent-windows { + highlight { + active-color "#a398b3" + urgent-color "#fd4663" + } +} diff --git a/scripts/executable_kill-phantom-display.fish b/scripts/executable_kill-phantom-display.fish new file mode 100755 index 0000000..aecb043 --- /dev/null +++ b/scripts/executable_kill-phantom-display.fish @@ -0,0 +1,20 @@ +#!/usr/bin/env fish +# Turn off the phantom Studio Display leg (DP-4/5/6, varies per boot). +# Its signature is a single 640x480 mode — connector name and EDID are unreliable. +# ponytail: one-shot with retry at startup; doesn't handle mid-session hotplug — +# switch to a `niri msg event-stream` watcher if that starts biting. +for i in (seq 10) + set -l phantoms (niri msg -j outputs 2>/dev/null | jq -r ' + to_entries[] + | select((.value.modes | length) == 1 + and .value.modes[0].width == 640 + and .value.modes[0].height == 480) + | .key') + if test -n "$phantoms" + for out in $phantoms + niri msg output $out off + end + exit 0 + end + sleep 1 +end diff --git a/scripts/executable_ndw-route-workspace.sh b/scripts/executable_ndw-route-workspace.sh new file mode 100755 index 0000000..0e76e78 --- /dev/null +++ b/scripts/executable_ndw-route-workspace.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# ndw-route-workspace.sh +# Routes a niri-dynamic-workspaces workspace to the correct monitor by +# resolving the Apple Studio Display's connector at runtime. +# +# Inputs: NDW_WORKSPACE_KEY env var (set by ndw on_create), or $1. +# Exits silently on unknown keys so it's safe to call for all workspaces. + +set -euo pipefail + +KEY="${NDW_WORKSPACE_KEY:-${1:-}}" +[ -z "$KEY" ] && exit 0 + +INTERNAL="HDMI-A-1" + +# Resolve the external Apple Studio Display connector. +# Match by make+model; fall back to eDP-1 if not currently connected. +resolve_external() { + niri msg --json outputs | jq -r ' + to_entries + | map(select( + .value.make == "Apple Computer Inc" + and .value.model == "StudioDisplay" + )) + | .[0].key // empty + ' +} + +case "$KEY" in + y|g|m|x|z|p|l|a) + target="$INTERNAL" + ;; + b|f|s|w|c|d|o) + target="$(resolve_external)" + [ -z "$target" ] && target="$INTERNAL" # external not connected + ;; + *) + exit 0 + ;; +esac + +exec niri msg action move-workspace-to-monitor "$target" diff --git a/scripts/executable_niri-floating-sidebar.sh b/scripts/executable_niri-floating-sidebar.sh new file mode 100755 index 0000000..c4900be --- /dev/null +++ b/scripts/executable_niri-floating-sidebar.sh @@ -0,0 +1,367 @@ +#!/usr/bin/env bash +set -euo pipefail + +#============================================================================= +# Niri Sidebar Manager +#============================================================================= +# This script manages floating windows in the Niri window manager, +# organizing them into a toggleable sidebar. +#============================================================================= + +### --- DIMENSION SETTINGS --- ### +readonly WIN_W=550 # Floating window width +readonly BASE_SLOTS=4 # Default number of slots in the sidebar +readonly GAP_BETWEEN=15 # Gap between windows +readonly BOTTOM_MARGIN=50 # Bottom screen margin +readonly TOP_MARGIN=30 # Top screen margin +readonly SIDE_MARGIN=20 # Side screen margin +readonly VISIBLE_SLIVER=70 # Pixels visible when sidebar is hidden + +### --- STATE FILES --- ### +# Get current workspace ID +WORKSPACE_ID=$(niri msg --json workspaces | jq -r '.[] | select(.is_focused).id') + +# File paths for state tracking +readonly FLAG_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.floating" +readonly STATE_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.state" +readonly ORDER_STATE_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.order" +readonly HIDE_STATE_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.hide_state" + +### --- SCREEN INFO --- ### +readonly SCREEN_W=$(niri msg --json outputs | jq -r 'to_entries[0].value.logical.width') +readonly SCREEN_H=$(niri msg --json outputs | jq -r 'to_entries[0].value.logical.height') + +#============================================================================= +# FUNCTION: get_focused_window +# Description: Returns JSON info of the currently focused window +#============================================================================= +get_focused_window() { + niri msg --json windows | jq -r '.[] | select(.is_focused)' +} + +#============================================================================= +# FUNCTION: ensure_files_exist +# Description: Creates necessary state files if they don't exist +#============================================================================= +ensure_files_exist() { + touch "$FLAG_FILE" "$STATE_FILE" "$HIDE_STATE_FILE" "$ORDER_STATE_FILE" + + if [ ! -s "$HIDE_STATE_FILE" ]; then + echo "visible" >"$HIDE_STATE_FILE" + fi + + if [ ! -s "$ORDER_STATE_FILE" ]; then + echo "bottom-up" >"$ORDER_STATE_FILE" + fi +} + +#============================================================================= +# FUNCTION: get_floating_windows +# Description: Gets a list of floating window IDs in the current workspace +#============================================================================= +get_floating_windows() { + niri msg --json windows | + jq -r ".[] | select(.is_floating==true and .workspace_id==$WORKSPACE_ID) | .id" +} + +#============================================================================= +# FUNCTION: cleanup_state_file +# Description: Removes closed windows from the state file +# Parameters: +# $1 - List of currently active floating windows +#============================================================================= +cleanup_state_file() { + local actual_floating="$1" + + if [ ! -s "$STATE_FILE" ]; then + return + fi + + local tmp_state + tmp_state=$(mktemp) + + while IFS= read -r line; do + local id_in_file + id_in_file=$(echo "$line" | cut -d: -f1) + + if echo "$actual_floating" | grep -q "^${id_in_file}$"; then + echo "$line" >>"$tmp_state" + fi + done <"$STATE_FILE" + + mv "$tmp_state" "$STATE_FILE" +} + +#============================================================================= +# FUNCTION: calculate_window_dimensions +# Description: Calculates dynamic window height and X position +# Parameters: +# $1 - Window count +# Returns: Sets WIN_H and X global variables +#============================================================================= +calculate_window_dimensions() { + local count="$1" + local slots="$BASE_SLOTS" + + # Increase slots if window count exceeds default + if [ "$count" -gt "$BASE_SLOTS" ]; then + slots="$count" + fi + + # Calculate available vertical space + local total_gaps_space=$(((slots - 1) * GAP_BETWEEN)) + local available_h=$((SCREEN_H - TOP_MARGIN - BOTTOM_MARGIN - total_gaps_space)) + + # Export calculated dimensions + WIN_H=$((available_h / slots)) + X=$((SCREEN_W - WIN_W - SIDE_MARGIN)) +} + +#============================================================================= +# FUNCTION: position_window +# Description: Moves and resizes a specific window +# Parameters: +# $1 - Window ID +# $2 - X position +# $3 - Y position +#============================================================================= +position_window() { + local id="$1" + local x="$2" + local y="$3" + + niri msg action set-window-width "$WIN_W" --id "$id" 2>/dev/null || true + niri msg action set-window-height "$WIN_H" --id "$id" 2>/dev/null || true + niri msg action move-floating-window --id "$id" --x "$x" --y "$y" 2>/dev/null || true +} + +#============================================================================= +# FUNCTION: reorder_sidebar +# Description: Syncs state and updates all window positions on screen +#============================================================================= +reorder_sidebar() { + local actual_floating + actual_floating=$(get_floating_windows) + + cleanup_state_file "$actual_floating" + + local sorted_ids + sorted_ids=$(grep -Ff <(echo "$actual_floating") "$STATE_FILE" 2>/dev/null | cut -d: -f1 || true) + + local count + count=$(echo "$sorted_ids" | grep -c . || echo 0) + + if [ "$count" -eq 0 ]; then + >"$FLAG_FILE" + echo "visible" >"$HIDE_STATE_FILE" + return + fi + + calculate_window_dimensions "$count" + + local order + order=$(cat "$ORDER_STATE_FILE" 2>/dev/null || echo "bottom-up") + + >"$FLAG_FILE" + local index=0 + + while IFS= read -r id; do + [ -z "$id" ] && continue + + local pos_y + if [ "$order" = "top-down" ]; then + pos_y=$((TOP_MARGIN + index * (WIN_H + GAP_BETWEEN))) + else + pos_y=$((SCREEN_H - BOTTOM_MARGIN - WIN_H - index * (WIN_H + GAP_BETWEEN))) + fi + + position_window "$id" "$X" "$pos_y" + echo "${id}:${X}:${pos_y}" >>"$FLAG_FILE" + + index=$((index + 1)) + done <<<"$sorted_ids" + + echo "visible" >"$HIDE_STATE_FILE" +} + +#============================================================================= +# FUNCTION: toggle_float +# Description: Toggles focused window between sidebar and tiling mode +#============================================================================= +toggle_float() { + local focused_json + focused_json=$(get_focused_window) + + local focused_id + focused_id=$(echo "$focused_json" | jq -r '.id') + + if [ -z "$focused_id" ] || [ "$focused_id" = "null" ]; then + echo "Error: No focused window" + return 1 + fi + + if grep -q "^$focused_id:" "$STATE_FILE" 2>/dev/null; then + # Restore to tiling mode + local old_dim + old_dim=$(grep "^$focused_id:" "$STATE_FILE") + + local old_w old_h + old_w=$(echo "$old_dim" | cut -d: -f2) + old_h=$(echo "$old_dim" | cut -d: -f3) + + # Remove from state + sed -i "/^$focused_id:/d" "$STATE_FILE" + + # Action: Move to tiling + niri msg action move-window-to-tiling + + # Restore original dimensions + [ "$old_w" != "null" ] && niri msg action set-column-width "$old_w" 2>/dev/null || true + [ "$old_h" != "null" ] && niri msg action set-window-height "$old_h" 2>/dev/null || true + + reorder_sidebar + echo "✓ Window removed from sidebar" + else + # Add to sidebar + local orig_w orig_h + orig_w=$(echo "$focused_json" | jq -r '.layout.window_size[0] // 800') + orig_h=$(echo "$focused_json" | jq -r '.layout.window_size[1] // 600') + + # Save original size + echo "$focused_id:$orig_w:$orig_h" >>"$STATE_FILE" + + # Action: Move to floating + niri msg action move-window-to-floating + + # Refresh sidebar + reorder_sidebar + + # Keep focus on the window + niri msg action focus-window --id "$focused_id" 2>/dev/null || true + + echo "✓ Window added to sidebar" + fi +} + +#============================================================================= +# FUNCTION: toggle_hide +# Description: Hides/Shows the entire sidebar by pushing windows off-screen +#============================================================================= +toggle_hide() { + + # Save current hide state + local previous_state + previous_state=$(cat "$HIDE_STATE_FILE" 2>/dev/null || echo "visible") + + # Reorder sidebar to fix any desync without breaking hide/show state + local actual_floating + actual_floating=$(get_floating_windows) + + if [ -n "$actual_floating" ]; then + reorder_sidebar + # reorder_sidebar forces visible, restore previous state + echo "$previous_state" >"$HIDE_STATE_FILE" + fi + + if [ ! -s "$FLAG_FILE" ]; then + echo "No floating windows detected" + return 0 + fi + + local current_state + current_state=$(cat "$HIDE_STATE_FILE") + + if [ "$current_state" = "visible" ]; then + # Hide: push windows off-screen + while IFS=: read -r id x y; do + [ -z "$id" ] && continue + local new_x=$((SCREEN_W - VISIBLE_SLIVER)) + niri msg action move-floating-window --id "$id" --x "$new_x" --y "$y" 2>/dev/null || true + done <"$FLAG_FILE" + + echo "hidden" >"$HIDE_STATE_FILE" + echo "✓ Sidebar hidden" + else + # Show: restore original positions + while IFS=: read -r id x y; do + [ -z "$id" ] && continue + niri msg action move-floating-window --id "$id" --x "$x" --y "$y" 2>/dev/null || true + done <"$FLAG_FILE" + + echo "visible" >"$HIDE_STATE_FILE" + echo "✓ Sidebar visible" + fi +} + +#============================================================================= +# FUNCTION: flip_sidebar_order +# Description: Flip the order of the sidebar +#============================================================================= + +flip_sidebar_order() { + local current + current=$(cat "$ORDER_STATE_FILE" 2>/dev/null || echo "bottom-up") + + if [ "$current" = "bottom-up" ]; then + echo "top-down" >"$ORDER_STATE_FILE" + else + echo "bottom-up" >"$ORDER_STATE_FILE" + fi + + reorder_sidebar + echo "✓ Sidebar order flipped" +} + +#============================================================================= +# FUNCTION: show_usage +# Description: Displays help information +#============================================================================= +show_usage() { + cat </dev/null 2>&1 || true +[ "$(win)" != "$w0" ] && exit 0 + +# 2) occupied workspace in that direction (skip the empty trailing one) +wss=$(niri msg --json workspaces) +wins=$(niri msg --json windows) +cwsid=$(jq -r 'map(select(.is_focused)) | .[0].id' <<<"$wss") +real_neighbor=$(jq -n --argjson wss "$wss" --argjson wins "$wins" \ + --argjson cwsid "$cwsid" --arg dir "$dir" ' + ($wss[] | select(.id==$cwsid)) as $c + | [ $wss[] + | select(.output==$c.output) + | select(if $dir=="down" then .idx>$c.idx else .idx<$c.idx end) + | .id as $wid + | select([$wins[] | select(.workspace_id==$wid)] | length > 0) ] + | length > 0') + +if [ "$real_neighbor" = "true" ]; then + niri msg action "focus-workspace-$dir" >/dev/null 2>&1 || true + exit 0 +fi + +# 3) adjacent monitor… or wrap to the far-end monitor +o0=$(out); niri msg action "focus-monitor-$dir" >/dev/null 2>&1 || true +[ "$(out)" != "$o0" ] && exit 0 +while :; do + prev=$(out) + niri msg action "focus-monitor-$opp" >/dev/null 2>&1 || true + [ "$(out)" = "$prev" ] && break +done diff --git a/scripts/executable_niri-move.sh b/scripts/executable_niri-move.sh new file mode 100755 index 0000000..e279201 --- /dev/null +++ b/scripts/executable_niri-move.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Cascade move: column → workspace (incl. empty trailing) → monitor (cycles) +# usage: niri-move.sh up|down +set -euo pipefail +dir="${1:?usage: niri-move.sh up|down}" +opp=$([ "$dir" = down ] && echo up || echo down) + +cur=$(niri msg --json focused-window) +[ "$cur" = "null" ] && exit 0 + +out() { niri msg --json focused-output | jq -r '.name // "none"'; } +sig() { niri msg --json focused-window | jq -rc '[.workspace_id, (.layout.pos_in_scrolling_layout // null)]'; } + +# 1) reorder within the column +s0=$(sig); niri msg action "move-window-$dir" >/dev/null 2>&1 || true +[ "$(sig)" != "$s0" ] && exit 0 + +# 2) workspace in that direction (including the empty trailing one) +s0=$(sig); niri msg action "move-window-to-workspace-$dir" >/dev/null 2>&1 || true +[ "$(sig)" != "$s0" ] && exit 0 + +# 3) adjacent monitor… or wrap to the far-end monitor +o0=$(out); niri msg action "move-window-to-monitor-$dir" >/dev/null 2>&1 || true +[ "$(out)" != "$o0" ] && exit 0 +while :; do + prev=$(out) + niri msg action "move-window-to-monitor-$opp" >/dev/null 2>&1 || true + [ "$(out)" = "$prev" ] && break +done