Import from root chezmoi source
This commit is contained in:
commit
97a309bbe3
21 files changed
+1394
No files matched your search
+195
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
|
||||
@@ -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 &"
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
Executable
+20
@@ -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
|
||||
Executable
+42
@@ -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"
|
||||
Executable
+367
@@ -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 <<EOF
|
||||
Usage: $0 {toggle|hide|help}
|
||||
|
||||
Commands:
|
||||
toggle Toggle focused window between sidebar and tiling mode
|
||||
hide Hide/show the entire sidebar
|
||||
flip Flip sidebar order (top-down / bottom-up)
|
||||
reorder Syncs state and updates all window positions on screen
|
||||
help Show this help message
|
||||
|
||||
Examples:
|
||||
$0 toggle # Add/remove current window
|
||||
$0 hide # Show/hide all floating windows
|
||||
EOF
|
||||
}
|
||||
|
||||
#=============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
#=============================================================================
|
||||
main() {
|
||||
ensure_files_exist
|
||||
|
||||
case "${1:-}" in
|
||||
toggle)
|
||||
toggle_float
|
||||
;;
|
||||
hide)
|
||||
toggle_hide
|
||||
;;
|
||||
flip)
|
||||
flip_sidebar_order
|
||||
;;
|
||||
reorder)
|
||||
reorder_sidebar
|
||||
;;
|
||||
help | --help | -h)
|
||||
show_usage
|
||||
;;
|
||||
*)
|
||||
echo "❌ Invalid command"
|
||||
echo ""
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
# Cascade focus: window → occupied workspace → monitor (cycles at edges)
|
||||
# Skips the trailing empty workspace — jumps to the monitor instead.
|
||||
# usage: niri-focus.sh up|down
|
||||
set -euo pipefail
|
||||
dir="${1:?usage: niri-focus.sh up|down}"
|
||||
opp=$([ "$dir" = down ] && echo up || echo down)
|
||||
|
||||
out() { niri msg --json focused-output | jq -r '.name // "none"'; }
|
||||
win() { niri msg --json focused-window | jq -r '.id // "none"'; }
|
||||
|
||||
# 1) window within the column
|
||||
w0=$(win); niri msg action "focus-window-$dir" >/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
|
||||
Executable
+29
@@ -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
|
||||
Reference in new issue
Block a user