dotfiles

My PC Dotfiles & Website
commit 4e4c2518a7530fcb658100e204a266df83c61310
parent 3437057a6a446fa57b26ea727c76922c38bf8f86
Author: maydayv7 <maydayv7@gmail.com>
Date:   Thu, 14 Aug 2025 23:07:15 +0530

feat!: Add Configuration for Niri WM

- Use `rofi-wayland` as launcher
- Share configuration with Hyprland

Diffstat:

MCHANGELOG.md | 6++++++
MREADME.md | 18++++++++++--------
Mdevices/valkyrie/default.nix | 2+-
Mfiles/flake.nix | 19++++++++++++++++---
Dfiles/hyprland/theme/wlogout.css | 32--------------------------------
Afiles/niri/rofi.rasi | 314+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afiles/niri/theme/drawer.css | 26++++++++++++++++++++++++++
Afiles/niri/theme/waybar.css | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rfiles/hyprland/pcmanfm.conf -> files/pcmanfm.conf | 0
Afiles/wlogout.css | 32++++++++++++++++++++++++++++++++
Mflake.lock | 124++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mflake.nix | 5+++++
Amodules/gui/desktop/common/apps/browser.nix | 24++++++++++++++++++++++++
Amodules/gui/desktop/common/apps/files.nix | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/common/apps/login.nix | 32++++++++++++++++++++++++++++++++
Rmodules/gui/desktop/hyprland/apps/media.nix -> modules/gui/desktop/common/apps/media.nix | 0
Rmodules/gui/desktop/hyprland/apps/misc.nix -> modules/gui/desktop/common/apps/misc.nix | 0
Amodules/gui/desktop/common/apps/notify.nix | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/common/apps/panel.nix | 18++++++++++++++++++
Amodules/gui/desktop/common/apps/security.nix | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/common/apps/style.nix | 31+++++++++++++++++++++++++++++++
Amodules/gui/desktop/common/apps/terminal.nix | 41+++++++++++++++++++++++++++++++++++++++++
Rmodules/gui/desktop/hyprland/apps/text.nix -> modules/gui/desktop/common/apps/text.nix | 0
Amodules/gui/desktop/common/apps/utilities.nix | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rmodules/gui/desktop/hyprland/theme.nix -> modules/gui/desktop/common/theme.nix | 0
Dmodules/gui/desktop/hyprland/apps/browser.nix | 21---------------------
Dmodules/gui/desktop/hyprland/apps/files.nix | 130-------------------------------------------------------------------------------
Amodules/gui/desktop/hyprland/apps/idle.nix | 44++++++++++++++++++++++++++++++++++++++++++++
Dmodules/gui/desktop/hyprland/apps/notify.nix | 83-------------------------------------------------------------------------------
Mmodules/gui/desktop/hyprland/apps/panel.nix | 800+++++++++++++++++++++++++++++++++++++++----------------------------------------
Dmodules/gui/desktop/hyprland/apps/security.nix | 138-------------------------------------------------------------------------------
Dmodules/gui/desktop/hyprland/apps/settings.nix | 208-------------------------------------------------------------------------------
Dmodules/gui/desktop/hyprland/apps/terminal.nix | 42------------------------------------------
Mmodules/gui/desktop/hyprland/apps/utilities.nix | 77+++++++----------------------------------------------------------------------
Mmodules/gui/desktop/hyprland/default.nix | 81+++++++++++++++++++++++--------------------------------------------------------
Amodules/gui/desktop/hyprland/settings/apps.nix | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dmodules/gui/desktop/hyprland/settings/keybindings.nix | 201-------------------------------------------------------------------------------
Amodules/gui/desktop/hyprland/settings/keybinds.nix | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/niri/apps/launcher.nix | 30++++++++++++++++++++++++++++++
Amodules/gui/desktop/niri/apps/panel.nix | 374+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/niri/apps/utilities.nix | 24++++++++++++++++++++++++
Amodules/gui/desktop/niri/default.nix | 45+++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/niri/settings/apps.nix | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/niri/settings/default.nix | 38++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/niri/settings/keybinds.nix | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/gui/desktop/niri/settings/style.nix | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmodules/hardware/gpu.nix | 10+++++++---
Mpackages/flake.nix | 1+
Mscripts/hyprutils.nix | 168-------------------------------------------------------------------------------
Ascripts/sysutils.nix | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
50 files changed, 3103 insertions(+), 1573 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -1,5 +1,11 @@ ## 2025 +### August + +- Add Configuration for Niri WM + - Use `rofi-wayland` as launcher + - Share configuration with Hyprland + ### July - Add Hyprland Shaders diff --git a/README.md b/README.md @@ -81,7 +81,7 @@ This [repository](https://github.com/maydayv7/dotfiles) contains the configurati #### Notable Features - Supports multiple users and devices -- Configuration for multiple Desktop Environments +- Configuration for multiple DEs and Compositors - Incorporates PipeWire, Wayland, ...! - Automatically builds and deploys my [Website](./site) - Credentials management using the [`sops-nix`](https://github.com/Mic92/sops-nix) module and [`gnupg`](https://gnupg.org/) keys @@ -100,13 +100,14 @@ This [repository](https://github.com/maydayv7/dotfiles) contains the configurati ## Programs -| Type | Programs | -| :------- | :--------------------------------------------------------------------------------------------------------------------------: | -| Editors | [`nano`](https://www.nano-editor.org/), [`micro`](https://micro-editor.github.io), [VS Code](https://code.visualstudio.com/) | -| Shells | [`bash`](https://www.gnu.org/software/bash/), [`zsh`](https://www.zsh.org) | -| Terminal | [Ghostty](https://ghostty.org/), [Kitty](https://sw.kovidgoyal.net/kitty/) | -| Browser | [Firefox](https://www.mozilla.org/en-US/firefox/) | -| Desktops | [GNOME](https://www.gnome.org), [Hyprland](https://hyprland.org/), [Pantheon](https://elementary.io/) | +| Type | Programs | +| :---------- | :--------------------------------------------------------------------------------------------------------------------------: | +| Editors | [`nano`](https://www.nano-editor.org/), [`micro`](https://micro-editor.github.io), [VS Code](https://code.visualstudio.com/) | +| Shells | [`bash`](https://www.gnu.org/software/bash/), [`zsh`](https://www.zsh.org) | +| Terminal | [Ghostty](https://ghostty.org/), [Kitty](https://sw.kovidgoyal.net/kitty/) | +| Browser | [Firefox](https://www.mozilla.org/en-US/firefox/) | +| Desktops | [GNOME](https://www.gnome.org), [Pantheon](https://elementary.io/) | +| Compositors | [Hyprland](https://hypr.land/), [Niri](https://github.com/YaLTeR/niri) | ## Structure @@ -120,6 +121,7 @@ $ nix flake show github:maydayv7/dotfiles ├───apps │ └───x86_64-linux +│ ├───sysutils: app │ ├───hyprutils: app │ ├───install: app │ └───nixos: app diff --git a/devices/valkyrie/default.nix b/devices/valkyrie/default.nix @@ -74,7 +74,7 @@ }; gui = { - desktop = "hyprland"; + desktop = "niri"; display = "eDP-1"; wallpaper = "Quasar"; fancy = true; diff --git a/files/flake.nix b/files/flake.nix @@ -85,9 +85,6 @@ # Keybinds Viewer kebihelp = readFile ./hyprland/kebihelp.json; - # PcmanFM File Manager - pcmanfm = readFile ./hyprland/pcmanfm.conf; - # Greeter Configuration greeter = readFile ./hyprland/greeter.conf; } @@ -126,6 +123,19 @@ # Nano Text Editor nano = readFile ./nanorc; + # Niri WM + niri = { + rofi = readFile ./niri/rofi.rasi; + } + // map.files { + directory = ./niri/theme; + apply = readFile; + extension = ".css"; + }; + + # PcmanFM File Manager + pcmanfm = readFile ./pcmanfm.conf; + # Custom Proprietary Files proprietary = inputs.proprietary.files; inherit (proprietary) wallpapers; @@ -153,6 +163,9 @@ # My Personal Website website = ../site; + # Logout Menu + wlogout = readFile ./wlogout.css; + # YouTube youtube = readFile ./ytmusic.json; }; diff --git a/files/hyprland/theme/wlogout.css b/files/hyprland/theme/wlogout.css @@ -1,32 +0,0 @@ -* { - background: none; -} - -window { - background-color: rgba(0, 0, 0, 0.5); -} - -button { - background: rgba(0, 0, 0, 0.05); - border-radius: 8px; - box-shadow: - inset 0 0 0 1px rgba(255, 255, 255, 0.1), - 0 0 rgba(0, 0, 0, 0.5); - transition: background-color 0.2s ease-in-out; - margin: 1rem; -} - -button:focus, -button:hover { - background-color: rgba(255, 255, 255, 0.2); -} - -button:active { - background-color: rgba(255, 255, 255, 0.5); -} - -label { - font-size: 10rem; - margin: 5rem; - color: #@base05; -} diff --git a/files/niri/rofi.rasi b/files/niri/rofi.rasi @@ -0,0 +1,314 @@ +/** + * Rofi Configuration + * Source: https://github.com/adi1090x/rofi + **/ + +configuration { + modi: "drun,filebrowser,window,calc,emoji"; + show-icons: true; + display-drun: " Apps"; + display-filebrowser: " Files"; + display-window: " Windows"; + display-calc: " Calc"; + display-emoji: " Emoji"; + drun-display-format: "{name}"; + window-format: "{w} · {c} · {t}"; + cache-dir: "~/.cache/rofi"; +} + +/* Global Properties */ +* { + background: #@base01; + background-alt: #@base02; + foreground: #@base05; + selected: #@base0D; + active: #@base0C; + urgent: #@base08; + + border-colour: var(selected); + handle-colour: var(selected); + background-colour: var(background); + foreground-colour: var(foreground); + alternate-background: var(background-alt); + normal-background: var(background); + normal-foreground: var(foreground); + urgent-background: var(urgent); + urgent-foreground: var(background); + active-background: var(active); + active-foreground: var(background); + selected-normal-background: var(selected); + selected-normal-foreground: var(background); + selected-urgent-background: var(active); + selected-urgent-foreground: var(background); + selected-active-background: var(urgent); + selected-active-foreground: var(background); + alternate-normal-background: var(background); + alternate-normal-foreground: var(foreground); + alternate-urgent-background: var(urgent); + alternate-urgent-foreground: var(background); + alternate-active-background: var(active); + alternate-active-foreground: var(background); +} + +/* Main Window */ +window { + /* Properties for 'window' widget */ + transparency: "real"; + location: center; + anchor: center; + fullscreen: false; + width: 800px; + x-offset: 0px; + y-offset: 0px; + + /* Properties for all widgets */ + enabled: true; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 10px; + border-color: @border-colour; + cursor: "default"; + background-color: @background-colour; +} + +/* Main Box */ +mainbox { + enabled: true; + spacing: 10px; + margin: 0px; + padding: 20px; + border: 0px solid; + border-radius: 0px 0px 0px 0px; + border-color: @border-colour; + background-color: transparent; + children: [ "inputbar", "message", "custombox" ]; +} + +/* Custom Box */ +custombox { + spacing: 10px; + background-color: @background-colour; + text-color: @foreground-colour; + orientation: horizontal; + children: [ "mode-switcher", "listview" ]; +} + +/* Input Bar */ +inputbar { + enabled: true; + spacing: 10px; + margin: 0px; + padding: 8px 12px; + border: 0px solid; + border-radius: 8px; + border-color: @border-colour; + background-color: @alternate-background; + text-color: @foreground-colour; + children: [ "textbox-prompt-colon", "entry" ]; +} + +prompt { + enabled: true; + background-color: inherit; + text-color: inherit; +} +textbox-prompt-colon { + enabled: true; + padding: 5px 0px; + expand: false; + str: ""; + background-color: inherit; + text-color: inherit; +} +entry { + enabled: true; + padding: 5px 0px; + background-color: inherit; + text-color: inherit; + cursor: text; + placeholder: "Search..."; + placeholder-color: inherit; +} +num-filtered-rows { + enabled: true; + expand: false; + background-color: inherit; + text-color: inherit; +} +textbox-num-sep { + enabled: true; + expand: false; + str: "/"; + background-color: inherit; + text-color: inherit; +} +num-rows { + enabled: true; + expand: false; + background-color: inherit; + text-color: inherit; +} +case-indicator { + enabled: true; + background-color: inherit; + text-color: inherit; +} + +/* List View */ +listview { + enabled: true; + columns: 1; + lines: 8; + cycle: true; + dynamic: true; + scrollbar: true; + layout: vertical; + reverse: false; + fixed-height: true; + fixed-columns: true; + + spacing: 5px; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; + cursor: "default"; +} +scrollbar { + handle-width: 5px ; + handle-color: @handle-colour; + border-radius: 10px; + background-color: @alternate-background; +} + +/* Elements */ +element { + enabled: true; + spacing: 10px; + margin: 0px; + padding: 10px; + border: 0px solid; + border-radius: 8px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; + cursor: pointer; +} +element normal.normal { + background-color: var(normal-background); + text-color: var(normal-foreground); +} +element normal.urgent { + background-color: var(urgent-background); + text-color: var(urgent-foreground); +} +element normal.active { + background-color: var(active-background); + text-color: var(active-foreground); +} +element selected.normal { + background-color: var(selected-normal-background); + text-color: var(selected-normal-foreground); +} +element selected.urgent { + background-color: var(selected-urgent-background); + text-color: var(selected-urgent-foreground); +} +element selected.active { + background-color: var(selected-active-background); + text-color: var(selected-active-foreground); +} +element alternate.normal { + background-color: var(alternate-normal-background); + text-color: var(alternate-normal-foreground); +} +element alternate.urgent { + background-color: var(alternate-urgent-background); + text-color: var(alternate-urgent-foreground); +} +element alternate.active { + background-color: var(alternate-active-background); + text-color: var(alternate-active-foreground); +} +element-icon { + background-color: transparent; + text-color: inherit; + size: 24px; + cursor: inherit; +} +element-text { + background-color: transparent; + text-color: inherit; + highlight: inherit; + cursor: inherit; + vertical-align: 0.5; + horizontal-align: 0.0; +} + +/* Mode Switcher */ +mode-switcher{ + enabled: true; + expand: false; + orientation: vertical; + spacing: 10px; + margin: 0px; + padding: 0px 0px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; +} +button { + padding: 0px 20px 0px 20px; + border: 0px solid; + border-radius: 8px; + border-color: @border-colour; + background-color: @alternate-background; + text-color: inherit; + vertical-align: 0.5; + horizontal-align: 0.0; + cursor: pointer; +} +button selected { + background-color: var(selected-normal-background); + text-color: var(selected-normal-foreground); +} + +/* Message */ +message { + enabled: true; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 0px 0px 0px 0px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; +} +textbox { + padding: 12px; + border: 0px solid; + border-radius: 8px; + border-color: @border-colour; + background-color: @alternate-background; + text-color: @foreground-colour; + vertical-align: 0.5; + horizontal-align: 0.0; + highlight: none; + placeholder-color: @foreground-colour; + blink: true; + markup: true; +} +error-message { + padding: 10px; + border: 2px solid; + border-radius: 8px; + border-color: @border-colour; + background-color: @background-colour; + text-color: @foreground-colour; +} diff --git a/files/niri/theme/drawer.css b/files/niri/theme/drawer.css @@ -0,0 +1,26 @@ +/* nwg-drawer Styling */ + +window { + background-color: alpha(#@base00, 0.8); +} + +button, +image { + background: none; + border: none; +} + +button:hover { + background-color: rgba(255, 255, 255, 0.5); +} + +#pinned-box { + padding-bottom: 5px; + border-bottom: 1px dotted gray; +} + +#files-box { + padding: 5px; + border: 1px dotted gray; + border-radius: 10px; +} diff --git a/files/niri/theme/waybar.css b/files/niri/theme/waybar.css @@ -0,0 +1,196 @@ +* { + font-size: 16px; + font-weight: 500; + border-radius: 10px; + min-height: 0; + min-width: 0; +} +window#waybar { + background-color: alpha(@base00, 0.9); + border: 2px solid @base00; +} +tooltip { + background: alpha(@base00, 0.9); + color: @base05; + border: 1px solid @base0D; +} + +#custom-logo { + color: #ffffff; +} + +#user * { + padding: 0 0.5em; +} +#user { + background-color: @base0F; + color: @base00; +} +#custom-power { + color: @base08; +} + +#workspaces button { + color: @base00; + background-color: @base07; + border: 2px solid @base00; + padding: 3px; + margin: 1px 0; +} +#workspaces button.current_output { + border: 2px solid @base02; +} +#workspaces button.active { + background-color: @base05; + border: 2px solid @base04; +} +#workspaces button.empty { + color: @base07; + background-color: transparent; +} + +#window { + background-color: @base0C; +} +#window * { + padding-left: 0.5em; +} +#window label { + padding: 0; + margin: 0; +} +window#waybar.empty #window { + background-color: transparent; +} + +#custom-dropdown { + color: #ffffff; +} +#tray { + color: #ffffff; + margin: 0; + padding: 0; +} +#tray * { + margin-bottom: 8px; +} +#keyboard-state { + color: @base05; + opacity: 0.8; + border: 2px solid @base04; +} + +#bluetooth { + color: #ffffff; + background-color: transparent; +} +#bluetooth.disabled { + background-color: transparent; +} + +#network { + background-color: @base0B; + color: @base00; +} +#network.disconnected { + background-color: @base06; +} + +#media .drawer box { + margin-right: 0px; +} +#wireplumber { + background-color: @base09; + color: @base00; +} +#wireplumber.muted { + background-color: @base06; +} +#mpris { + color: @base05; +} + +#backlight { + background-color: @base0E; + color: @base00; +} + +#battery { + background-color: @base0A; + color: @base00; +} +@keyframes blink { + to { + background-color: #ffffff; + } +} +#battery.critical:not(.charging) { + background-color: @base08; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; +} +#power-profiles-daemon.performance { + color: @base08; +} +#power-profiles-daemon.balanced { + color: @base0A; +} +#power-profiles-daemon.power-saver { + color: @base0B; +} + +#custom-weather { + color: @base00; + background-color: @base05; +} + +#clock { + background-color: @base0D; + color: @base00; +} + +#custom-dunst { + color: @base0A; +} + +#idle_inhibitor { + color: @base09; + background-color: transparent; +} + +#backlight, +#battery, +#bluetooth, +#clock, +#custom-dropdown, +#custom-dunst, +#custom-logo, +#custom-power, +#custom-weather, +#idle_inhibitor, +#keyboard-state, +#mpris, +#network, +#power-profiles-daemon, +#user, +#wireplumber { + padding: 3px; + margin: 2px; +} + +#clock { + padding-left: 0.4em; +} + +#window { + margin: 2px; + padding-top: 3px; + padding-bottom: 3px; +} + +#workspaces { + margin: 3px 2px; +} diff --git a/files/hyprland/pcmanfm.conf b/files/pcmanfm.conf diff --git a/files/wlogout.css b/files/wlogout.css @@ -0,0 +1,32 @@ +* { + background: none; +} + +window { + background-color: rgba(0, 0, 0, 0.7); +} + +button { + background: rgba(0, 0, 0, 0.05); + border-radius: 8px; + box-shadow: + inset 0 0 0 1px rgba(255, 255, 255, 0.1), + 0 0 rgba(0, 0, 0, 0.5); + transition: background-color 0.2s ease-in-out; + margin: 1rem; +} + +button:focus, +button:hover { + background-color: rgba(255, 255, 255, 0.2); +} + +button:active { + background-color: rgba(255, 255, 255, 0.5); +} + +label { + font-size: 10rem; + margin: 5rem; + color: #@base05; +} diff --git a/flake.lock b/flake.lock @@ -975,6 +975,62 @@ "type": "github" } }, + "niri": { + "inputs": { + "niri-stable": "niri-stable", + "niri-unstable": "niri-unstable", + "nixpkgs": "nixpkgs_2", + "nixpkgs-stable": "nixpkgs-stable_2", + "xwayland-satellite-stable": "xwayland-satellite-stable", + "xwayland-satellite-unstable": "xwayland-satellite-unstable" + }, + "locked": { + "lastModified": 1755079053, + "narHash": "sha256-2f9STIOJkASzzsWweu5JrQhb+fP0fyQjkp/3J/8Pk2U=", + "owner": "sodiboo", + "repo": "niri-flake", + "rev": "9dabff6fe20b1a58a4bb739917b09e046af70cea", + "type": "github" + }, + "original": { + "owner": "sodiboo", + "repo": "niri-flake", + "type": "github" + } + }, + "niri-stable": { + "flake": false, + "locked": { + "lastModified": 1748151941, + "narHash": "sha256-z4viQZLgC2bIJ3VrzQnR+q2F3gAOEQpU1H5xHtX/2fs=", + "owner": "YaLTeR", + "repo": "niri", + "rev": "8ba57fcf25d2fc9565131684a839d58703f1dae7", + "type": "github" + }, + "original": { + "owner": "YaLTeR", + "ref": "v25.05.1", + "repo": "niri", + "type": "github" + } + }, + "niri-unstable": { + "flake": false, + "locked": { + "lastModified": 1755074352, + "narHash": "sha256-I+kpboTzfMwRVK76OoTmHStrGuzJPcmvZKxmlmL9q+A=", + "owner": "YaLTeR", + "repo": "niri", + "rev": "af9ce533100b49e8bc879b557ab830f5d3a18805", + "type": "github" + }, + "original": { + "owner": "YaLTeR", + "repo": "niri", + "type": "github" + } + }, "nixcord": { "inputs": { "flake-compat": "flake-compat_4", @@ -1046,8 +1102,40 @@ "type": "github" } }, + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1754937576, + "narHash": "sha256-3sWA5WJybUE16kIMZ3+uxcxKZY/JRR4DFBqLdSLBo7w=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ddae11e58c0c345bf66efbddbf2192ed0e58f896", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { + "lastModified": 1754725699, + "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { "lastModified": 1753939845, "narHash": "sha256-K2ViRJfdVGE8tpJejs8Qpvvejks1+A4GQej/lBk5y7I=", "owner": "nixos", @@ -1179,6 +1267,7 @@ "impermanence": "impermanence", "index": "index", "minecraft": "minecraft", + "niri": "niri", "nixcord": "nixcord", "nixpkgs": [ "stable" @@ -1567,7 +1656,7 @@ "inputs": { "flake-compat": "flake-compat_5", "lib-aggregate": "lib-aggregate", - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs_3" }, "locked": { "lastModified": 1754053564, @@ -1644,6 +1733,39 @@ "repo": "xdg-desktop-portal-hyprland", "type": "github" } + }, + "xwayland-satellite-stable": { + "flake": false, + "locked": { + "lastModified": 1748488455, + "narHash": "sha256-IiLr1alzKFIy5tGGpDlabQbe6LV1c9ABvkH6T5WmyRI=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "3ba30b149f9eb2bbf42cf4758d2158ca8cceef73", + "type": "github" + }, + "original": { + "owner": "Supreeeme", + "ref": "v0.6", + "repo": "xwayland-satellite", + "type": "github" + } + }, + "xwayland-satellite-unstable": { + "flake": false, + "locked": { + "lastModified": 1754533920, + "narHash": "sha256-fCZ68Yud1sUCq6UNXj0SDyiBgVA8gJUE+14ZFGsFJG8=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "e0d1dad25a158551ab58547b2ece4b7d5a19929c", + "type": "github" + }, + "original": { + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix @@ -235,6 +235,9 @@ home-manager.follows = "home"; }; }; + + ## Niri + niri.url = "github:sodiboo/niri-flake"; }; ## Configuration ## @@ -293,6 +296,7 @@ "https://nixpkgs-wayland.cachix.org" "https://hyprland.cachix.org" "https://hyprshell.cachix.org" + "https://niri.cachix.org" "https://catppuccin.cachix.org" ]; @@ -306,6 +310,7 @@ "nixpkgs-wayland.cachix.org-1:3lwxaILxMRkVhehr5StQprHdEo4IrE8sRho9R9HOLYA=" "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" "hyprshell.cachix.org-1:seKSn/sAyobGjsRqe6deRKP/VZcsTorGt5/QqCeQrvU=" + "niri.cachix.org-1:Wv0OmO7PsuocRKzfDoJ3mulSl7Z6oezYhGhR+3W2964=" "catppuccin.cachix.org-1:noG/4HkbhJb+lUAdKrph6LaozJvAeEEZj4N732IysmU=" ]; }; diff --git a/modules/gui/desktop/common/apps/browser.nix b/modules/gui/desktop/common/apps/browser.nix @@ -0,0 +1,24 @@ +{ + theme, + ... +}: +{ + ## Browser Configuration + apps.list = [ "firefox" ]; + user.homeConfig = { + home.file.".mozilla/firefox/default/chrome/userChrome.css".text = '' + #TabsToolbar { + -moz-window-dragging: no-drag; + } + ''; + + # Theme + programs.firefox.policies.ExtensionSettings = { + name = with theme; "${name}-${variant}-${accent}"; + value = { + installation_mode = "normal_installed"; + install_url = "https://addons.mozilla.org/en-US/firefox/downloads/latest/{d49033ac-8969-488c-afb0-5cdb73957f41}/latest.xpi"; + }; + }; + }; +} diff --git a/modules/gui/desktop/common/apps/files.nix b/modules/gui/desktop/common/apps/files.nix @@ -0,0 +1,130 @@ +{ + config, + lib, + util, + pkgs, + files, + ... +}: +let + inherit (lib) + hm + getExe + getExe' + replaceStrings + ; + + inherit (config.gui) icons; + terminal = "kitty"; + nemo = pkgs.nemo-with-extensions; +in +{ + ## File Manager Configuration + services.dbus.packages = [ nemo ]; + environment.systemPackages = [ + nemo + ] + ++ (with pkgs; [ + cinnamon-desktop + bulky + file-roller + lxqt.pcmanfm-qt + ]); + + user = { + persist.directories = [ + ".config/nemo" + ".local/share/nemo" + ".config/pcmanfm-qt" + ]; + + homeConfig = { + xdg.mimeApps.defaultApplications = util.build.mime { + archive = [ "org.gnome.FileRoller.desktop" ]; + directory = [ "nemo.desktop" ]; + }; + + # Settings + dconf.settings = { + "org/gtk/gtk4/settings/file-chooser".sort-directories-first = true; + "org/nemo/search".search-reverse-sort = false; + "org/nemo/desktop".show-desktop-icons = false; + "org/nemo/plugins".disabled-actions = [ "change-background.nemo_action" ]; + "org/nemo/icon-view".captions = [ + "size" + "type" + "date_modified" + ]; + + "org/nemo/preferences" = { + click-policy = "double"; + date-format = "informal"; + inherit-folder-viewer = true; + quick-renames-with-pause-in-between = true; + show-advanced-permissions = true; + show-new-folder-icon-toolbar = false; + show-show-thumbnails-toolbar = true; + tooltips-in-icon-view = true; + tooltips-in-list-view = false; + tooltips-show-access-date = true; + tooltips-show-birth-date = true; + tooltips-show-file-type = true; + tooltips-show-mod-date = true; + }; + + "org/nemo/preferences/menu-config" = { + background-menu-open-in-terminal = false; + selection-menu-open-in-terminal = false; + }; + }; + + home = { + # Bulk Renamer + activation.nemo-rename = hm.dag.entryAfter [ "writeBoundary" ] '' + if [[ -v DBUS_SESSION_BUS_ADDRESS ]] + then + export DCONF_DBUS_RUN_SESSION="" + else + export DCONF_DBUS_RUN_SESSION="${getExe' pkgs.dbus "dbus-run-session"} --dbus-daemon=${getExe' pkgs.dbus "dbus-daemon"}" + fi + + run $DCONF_DBUS_RUN_SESSION ${getExe pkgs.dconf} write /org/nemo/preferences/bulk-rename-tool "b'bulky'" + unset DCONF_DBUS_RUN_SESSION + ''; + + file = { + # Open in Terminal + ".local/share/nemo/actions/terminal.nemo_action".text = '' + [Nemo Action] + Name=Open in Terminal + Comment=Opens ${terminal} in the selected folder + Exec=${terminal} --working-directory=%F + Icon-Name=${terminal} + Selection=any + Extensions=dir; + EscapeSpaces=true + ''; + + # Desktop Icons + ".config/pcmanfm-qt/default/settings.conf".text = + replaceStrings + [ + "@icon" + "@font" + "@terminal" + "@wallpaper" + "@archiver" + ] + [ + icons.name + config.stylix.fonts.sansSerif.name + terminal + (builtins.toString files.images.transparent) + "file-roller" + ] + files.pcmanfm; + }; + }; + }; + }; +} diff --git a/modules/gui/desktop/common/apps/login.nix b/modules/gui/desktop/common/apps/login.nix @@ -0,0 +1,32 @@ +{ + lib, + pkgs, + theme ? import ./theme.nix pkgs, + ... +}: +let + inherit (lib) mkForce; +in +{ + ## Login Configuration ## + stylix.targets.regreet.enable = true; + environment.persist.directories = [ "/var/lib/regreet" ]; + programs.regreet = { + enable = true; + package = pkgs.greetd.regreet; + settings.commands = { + reboot = [ + "systemctl" + "reboot" + ]; + poweroff = [ + "systemctl" + "poweroff" + ]; + }; + + extraCss = mkForce ""; + theme = mkForce theme.gtk; + iconTheme = mkForce theme.icons; + }; +} diff --git a/modules/gui/desktop/hyprland/apps/media.nix b/modules/gui/desktop/common/apps/media.nix diff --git a/modules/gui/desktop/hyprland/apps/misc.nix b/modules/gui/desktop/common/apps/misc.nix diff --git a/modules/gui/desktop/common/apps/notify.nix b/modules/gui/desktop/common/apps/notify.nix @@ -0,0 +1,88 @@ +{ + config, + lib, + theme, + ... +}: +let + inherit (lib) mkForce; + inherit (theme) icons; + inherit (config.lib.stylix) colors; +in +{ + ## Notifications Configuration + # Phone Connect + user.persist.directories = [ ".config/kdeconnect" ]; + programs.kdeconnect.enable = true; + user.homeConfig = { + services.kdeconnect = { + enable = true; + indicator = true; + }; + + # Notifications Daemon + stylix.targets.dunst.enable = true; + services.dunst = + let + system = { + fullscreen = "show"; + highlight = "#${colors.base07}"; + history_ignore = "yes"; + override_pause_level = 70; + }; + in + { + enable = true; + iconTheme = icons; + settings = { + global = { + alignment = "center"; + corner_radius = 10; + follow = "mouse"; + format = "<b>%s</b>\\n%b"; + frame_width = 1; + horizontal_padding = 8; + icon_corner_radius = 10; + icon_position = "left"; + icon_theme = icons.name; + indicate_hidden = "yes"; + markup = "yes"; + max_icon_size = 64; + mouse_left_click = "do_action"; + mouse_middle_click = "close_all"; + mouse_right_click = "close_current"; + offset = "10x5"; + padding = 8; + progress_bar_corner_radius = 10; + separator_height = 1; + show_indicators = false; + shrink = "no"; + transparency = 10; + word_wrap = "yes"; + }; + + urgency_low.frame_color = mkForce "#${colors.base0E}"; + urgency_normal.frame_color = mkForce "#${colors.base0D}"; + fullscreen_delay.fullscreen = "delay"; + utility = { + appname = "utility"; + } + // system; + upower = { + appname = "poweralertd"; + new_icon = "/run/current-system/sw/share/icons/${icons.name}/24x24/apps/preferences-system-power.svg"; + } + // system; + + hyprland = { + appname = "grimblast"; + } + // system; + niri = { + appname = "niri"; + } + // system; + }; + }; + }; +} diff --git a/modules/gui/desktop/common/apps/panel.nix b/modules/gui/desktop/common/apps/panel.nix @@ -0,0 +1,18 @@ +{ pkgs, ... }: +{ + ## Panel Configuration + user.homeConfig = { + stylix.targets.waybar = { + enable = true; + font = "sansSerif"; + addCss = false; + }; + + home.packages = [ pkgs.wttrbar ]; + programs.waybar = { + enable = true; + systemd.enable = true; + package = pkgs.unstable.waybar; + }; + }; +} diff --git a/modules/gui/desktop/common/apps/security.nix b/modules/gui/desktop/common/apps/security.nix @@ -0,0 +1,110 @@ +{ + config, + lib, + util, + pkgs, + files, + ... +}: +let + inherit (lib) getExe getExe'; + locker = pkgs.swaylock-effects; +in +{ + ## Security Configuration + # User Authentication + security = { + soteria.enable = true; + pam.services.swaylock.text = "auth include login"; + }; + + user.homeConfig = { + # Locker + stylix.targets.swaylock = { + enable = true; + useImage = true; + }; + + programs.swaylock = { + enable = true; + package = locker; + settings = { + clock = true; + indicator = true; + font = config.stylix.fonts.sansSerif.name; + effect-vignette = "0.3:1"; + }; + }; + + # Idle Daemon + services.swayidle = + let + pause = "${getExe pkgs.playerctl} pause -a;"; + lock = + pre: flag: + "sh -c 'if ! ${getExe' pkgs.procps "pgrep"} -x swaylock; then ${pre} ${getExe locker} -f ${flag}; fi'"; + in + { + enable = true; + extraArgs = [ "-w" ]; + events = [ + { + event = "before-sleep"; + command = lock pause ""; + } + { + event = "lock"; + command = lock pause "--fade-in 0.2 --grace 15 --grace-no-mouse"; + } + ]; + }; + + # Logout + programs.wlogout = { + enable = true; + style = util.build.theme { + inherit (config.lib.stylix) colors; + file = files.wlogout; + }; + + layout = [ + { + label = "lock"; + action = "loginctl lock-session"; + text = ""; + keybind = "l"; + } + { + label = "logout"; + action = "loginctl terminate-user $USER"; + text = "↶"; + keybind = "e"; + } + { + label = "shutdown"; + action = "systemctl poweroff"; + text = "⏻"; + keybind = "s"; + } + { + label = "reboot"; + action = "systemctl reboot"; + text = "↺"; + keybind = "r"; + } + { + label = "suspend"; + action = "systemctl suspend"; + text = ""; + keybind = "u"; + } + { + label = "hibernate"; + action = "systemctl hibernate"; + text = ""; + keybind = "h"; + } + ]; + }; + }; +} diff --git a/modules/gui/desktop/common/apps/style.nix b/modules/gui/desktop/common/apps/style.nix @@ -0,0 +1,31 @@ +{ + pkgs, + files, + theme, + ... +}: +{ + ## Desktop Integration + stylix.base16Scheme = files.colors.catppuccin; + environment.systemPackages = [ pkgs.custom.cursors ]; + gui = with theme; { + inherit (theme) icons; + + gtk = { + enable = true; + theme = gtk; + }; + + qt = { + enable = true; + theme = qt; + style = "kvantum"; + }; + }; + + # GTK Apps + user.homeConfig.dconf.settings."org/gnome/desktop/wm/preferences" = { + action-double-click-titlebar = "none"; + button-layout = "appmenu"; + }; +} diff --git a/modules/gui/desktop/common/apps/terminal.nix b/modules/gui/desktop/common/apps/terminal.nix @@ -0,0 +1,41 @@ +{ + pkgs, + theme, + ... +}: +{ + ## Terminal Configuration + user.homeConfig = { + programs.kitty = { + enable = true; + themeFile = with theme; "${name-alt}-${variant-alt}"; + keybindings = { + "ctrl+c" = "copy_or_interrupt"; + "kitty_mod+f" = + "launch --allow-remote-control kitty +kitten search/search.py @active-kitty-window-id"; + }; + + settings = { + kitty_mod = "ctrl+shift"; + confirm_os_window_close = 2; + copy_on_select = "clipboard"; + placement_strategy = "center"; + scrollback_lines = 10000; + enable_audio_bell = "no"; + visual_bell_duration = "0.1"; + + cursor_shape = "beam"; + cursor_shape_unfocused = "underline"; + tab_bar_style = "powerline"; + tab_powerline_style = "round"; + window_padding_width = 10; + }; + }; + + home.file.".config/kitty/search".source = pkgs.custom.kitty-search; + stylix.targets.kitty = { + enable = true; + variant256Colors = true; + }; + }; +} diff --git a/modules/gui/desktop/hyprland/apps/text.nix b/modules/gui/desktop/common/apps/text.nix diff --git a/modules/gui/desktop/common/apps/utilities.nix b/modules/gui/desktop/common/apps/utilities.nix @@ -0,0 +1,94 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) getExe; + inherit (config.lib.stylix) colors; +in +{ + environment.systemPackages = with pkgs; [ + # Apps + clipse + font-manager + gnome-clocks + gnome-disk-utility + hyprpicker + nwg-drawer + overskride + qalculate-gtk + remmina + resources + smile + + # Utilities + custom.sysutils + pavucontrol + wev + wlclock + wl-clipboard + wl-screenrec + wlr-randr + + # Network Settings + (gnome-control-center.overrideAttrs (old: { + postInstall = old.postInstall + '' + dir=$out/share/applications + for panel in $dir/* + do + [ "$panel" = "$dir/gnome-network-panel.desktop" ] && continue + [ "$panel" = "$dir/gnome-wifi-panel.desktop" ] && continue + [ "$panel" = "$dir/gnome-wwan-panel.desktop" ] && continue + [ "$panel" = "$dir/gnome-sharing-panel.desktop" ] && continue + [ "$panel" = "$dir/gnome-wacom-panel.desktop" ] && continue + rm "$panel" + done + ''; + })) + ]; + + ## Essential Utilities + # Power + services = { + power-profiles-daemon.enable = true; + upower.enable = true; + }; + + # Backlight + hardware.brillo.enable = true; + user.groups = [ + "input" + "video" + ]; + + user = { + homeConfig = { + systemd.user.services.wlclock = + let + target = [ "graphical-session.target" ]; + in + { + Install.WantedBy = target; + Unit = { + Description = "Desktop Clock"; + After = target; + }; + Service.ExecStart = + with colors; + "${getExe pkgs.wlclock} --layer bottom --exclusive-zone true --position top-right --margin 10 --size 300 --corner-radius 10 --border-size 2 --hand-width 7 --marking-width 3 --background-colour #${base00}4d --clock-colour #${base0D} --border-colour #${base00}"; + }; + + # Network Settings + xdg.desktopEntries."org.gnome.Settings" = { + name = "Network Settings"; + comment = "Gnome Control Center"; + icon = "org.gnome.Settings"; + exec = "env XDG_CURRENT_DESKTOP=gnome gnome-control-center"; + categories = [ "X-Preferences" ]; + terminal = false; + }; + }; + }; +} diff --git a/modules/gui/desktop/hyprland/theme.nix b/modules/gui/desktop/common/theme.nix diff --git a/modules/gui/desktop/hyprland/apps/browser.nix b/modules/gui/desktop/hyprland/apps/browser.nix @@ -1,21 +0,0 @@ -{ theme, ... }: -{ - ## Browser Configuration - apps.list = [ "firefox" ]; - user.homeConfig = { - home.file.".mozilla/firefox/default/chrome/userChrome.css".text = '' - #TabsToolbar { - -moz-window-dragging: no-drag; - } - ''; - - # Theme - programs.firefox.policies.ExtensionSettings = { - name = with theme; "${name}-${variant}-${accent}"; - value = { - installation_mode = "normal_installed"; - install_url = "https://addons.mozilla.org/en-US/firefox/downloads/latest/{d49033ac-8969-488c-afb0-5cdb73957f41}/latest.xpi"; - }; - }; - }; -} diff --git a/modules/gui/desktop/hyprland/apps/files.nix b/modules/gui/desktop/hyprland/apps/files.nix @@ -1,130 +0,0 @@ -{ - config, - lib, - util, - pkgs, - files, - ... -}: -let - inherit (lib) - hm - getExe - getExe' - replaceStrings - ; - - inherit (config.gui) icons; - terminal = "kitty"; - nemo = pkgs.nemo-with-extensions; -in -{ - ## File Manager Configuration - services.dbus.packages = [ nemo ]; - environment.systemPackages = [ - nemo - ] - ++ (with pkgs; [ - cinnamon-desktop - bulky - file-roller - lxqt.pcmanfm-qt - ]); - - user = { - persist.directories = [ - ".config/nemo" - ".local/share/nemo" - ".config/pcmanfm-qt" - ]; - - homeConfig = { - xdg.mimeApps.defaultApplications = util.build.mime { - archive = [ "org.gnome.FileRoller.desktop" ]; - directory = [ "nemo.desktop" ]; - }; - - # Settings - dconf.settings = { - "org/gtk/gtk4/settings/file-chooser".sort-directories-first = true; - "org/nemo/search".search-reverse-sort = false; - "org/nemo/desktop".show-desktop-icons = false; - "org/nemo/plugins".disabled-actions = [ "change-background.nemo_action" ]; - "org/nemo/icon-view".captions = [ - "size" - "type" - "date_modified" - ]; - - "org/nemo/preferences" = { - click-policy = "double"; - date-format = "informal"; - inherit-folder-viewer = true; - quick-renames-with-pause-in-between = true; - show-advanced-permissions = true; - show-new-folder-icon-toolbar = false; - show-show-thumbnails-toolbar = true; - tooltips-in-icon-view = true; - tooltips-in-list-view = false; - tooltips-show-access-date = true; - tooltips-show-birth-date = true; - tooltips-show-file-type = true; - tooltips-show-mod-date = true; - }; - - "org/nemo/preferences/menu-config" = { - background-menu-open-in-terminal = false; - selection-menu-open-in-terminal = false; - }; - }; - - home = { - # Bulk Renamer - activation.nemo-rename = hm.dag.entryAfter [ "writeBoundary" ] '' - if [[ -v DBUS_SESSION_BUS_ADDRESS ]] - then - export DCONF_DBUS_RUN_SESSION="" - else - export DCONF_DBUS_RUN_SESSION="${getExe' pkgs.dbus "dbus-run-session"} --dbus-daemon=${getExe' pkgs.dbus "dbus-daemon"}" - fi - - run $DCONF_DBUS_RUN_SESSION ${getExe pkgs.dconf} write /org/nemo/preferences/bulk-rename-tool "b'bulky'" - unset DCONF_DBUS_RUN_SESSION - ''; - - file = { - # Open in Terminal - ".local/share/nemo/actions/terminal.nemo_action".text = '' - [Nemo Action] - Name=Open in Terminal - Comment=Opens ${terminal} in the selected folder - Exec=${terminal} --working-directory=%F - Icon-Name=${terminal} - Selection=any - Extensions=dir; - EscapeSpaces=true - ''; - - # Desktop Icons - ".config/pcmanfm-qt/default/settings.conf".text = - replaceStrings - [ - "@icon" - "@font" - "@terminal" - "@wallpaper" - "@archiver" - ] - [ - icons.name - config.stylix.fonts.sansSerif.name - terminal - (builtins.toString files.images.transparent) - "file-roller" - ] - files.hyprland.pcmanfm; - }; - }; - }; - }; -} diff --git a/modules/gui/desktop/hyprland/apps/idle.nix b/modules/gui/desktop/hyprland/apps/idle.nix @@ -0,0 +1,44 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) getExe getExe'; + locker = pkgs.swaylock-effects; +in +{ + ## Idle Timeout + user.homeConfig.services.swayidle.timeouts = + let + lock = + pre: flag: + "sh -c 'if ! ${getExe' pkgs.procps "pgrep"} -x swaylock; then ${pre} ${getExe locker} -f ${flag}; fi'"; + + audio = + command: + "${pkgs.writeShellScript "audio" '' + ${getExe pkgs.playerctl} status | ${getExe pkgs.gnugrep} Playing + if [ $? == 1 ]; then ${command}; fi + ''}"; # Check if audio is playing + shader = getExe pkgs.hyprshade; + dpms = "${getExe' config.programs.hyprland.package "hyprctl"} dispatch dpms"; + in + [ + { + timeout = 240; # Dim display + command = audio "${shader} on dim"; + resumeCommand = "${shader} off"; + } + { + timeout = 300; # Turn off display + command = audio "${dpms} off"; + resumeCommand = "${dpms} on"; + } + { + timeout = 500; # Suspend device + command = audio "${dpms} on && ${lock "" ""} && ${getExe' pkgs.systemd "systemctl"} suspend"; + } + ]; +} diff --git a/modules/gui/desktop/hyprland/apps/notify.nix b/modules/gui/desktop/hyprland/apps/notify.nix @@ -1,83 +0,0 @@ -{ - config, - lib, - theme, - ... -}: -let - inherit (lib) mkForce; - inherit (theme) icons; - inherit (config.lib.stylix) colors; -in -{ - ## Notifications Configuration - # Phone Connect - user.persist.directories = [ ".config/kdeconnect" ]; - programs.kdeconnect.enable = true; - user.homeConfig = { - services.kdeconnect = { - enable = true; - indicator = true; - }; - - # Notifications Daemon - stylix.targets.dunst.enable = true; - services.dunst = - let - system = { - fullscreen = "show"; - highlight = "#${colors.base07}"; - history_ignore = "yes"; - override_pause_level = 70; - }; - in - { - enable = true; - iconTheme = icons; - settings = { - global = { - alignment = "center"; - corner_radius = 10; - follow = "mouse"; - format = "<b>%s</b>\\n%b"; - frame_width = 1; - horizontal_padding = 8; - icon_corner_radius = 10; - icon_position = "left"; - icon_theme = icons.name; - indicate_hidden = "yes"; - markup = "yes"; - max_icon_size = 64; - mouse_left_click = "do_action"; - mouse_middle_click = "close_all"; - mouse_right_click = "close_current"; - offset = "5x5"; - padding = 8; - progress_bar_corner_radius = 10; - separator_height = 1; - show_indicators = false; - shrink = "no"; - transparency = 10; - word_wrap = "yes"; - }; - - urgency_low.frame_color = mkForce "#${colors.base0E}"; - urgency_normal.frame_color = mkForce "#${colors.base0D}"; - fullscreen_delay.fullscreen = "delay"; - screenshot = { - appname = "grimblast"; - } - // system; - utility = { - appname = "utility"; - } - // system; - upower = { - appname = "poweralertd"; - new_icon = "/run/current-system/sw/share/icons/${icons.name}/24x24/apps/preferences-system-power.svg"; - } - // system; - }; - }; - }; -} diff --git a/modules/gui/desktop/hyprland/apps/panel.nix b/modules/gui/desktop/hyprland/apps/panel.nix @@ -10,454 +10,442 @@ let in { ## Panel Configuration - user.homeConfig = { - stylix.targets.waybar = { - enable = true; - font = "sansSerif"; - addCss = false; - }; - - home.packages = [ pkgs.wttrbar ]; - programs.waybar = { - enable = true; - systemd.enable = true; - package = pkgs.unstable.waybar; - style = files.hyprland.waybar; - - # Panel - settings = - let - shared = { - layer = "top"; - position = "top"; - - height = 30; - spacing = 3; - margin-top = 2; - margin-right = 5; - margin-bottom = 1; - margin-left = 5; - - "custom/logo" = { - format = "󱄅"; - tooltip = false; - on-click = "nwg-drawer"; - }; + user.homeConfig.programs.waybar = { + style = files.hyprland.waybar; + + # Panel + settings = + let + shared = { + layer = "top"; + position = "top"; + + height = 30; + spacing = 3; + margin-top = 2; + margin-right = 5; + margin-bottom = 1; + margin-left = 5; + + "custom/logo" = { + format = "󱄅"; + tooltip = false; + on-click = "nwg-drawer"; + }; - "group/users" = { - orientation = "horizontal"; - modules = [ - "user" - "custom/power" - ]; - drawer.transition-left-to-right = true; - }; + "group/users" = { + orientation = "horizontal"; + modules = [ + "user" + "custom/power" + ]; + drawer.transition-left-to-right = true; + }; - user = { - format = "{user}"; - icon = true; - height = 30; - width = 30; - open-on-click = true; - }; + user = { + format = "{user}"; + icon = true; + height = 30; + width = 30; + open-on-click = true; + }; - "custom/power" = { - format = "⏻"; - tooltip = false; - on-click = "wlogout -p layer-shell"; - }; + "custom/power" = { + format = "⏻"; + tooltip = false; + on-click = "wlogout -p layer-shell"; + }; - "hyprland/workspaces" = { - all-outputs = false; - show-special = true; - format = "<small>{name}</small>{icon}"; - on-scroll-up = "hyprctl dispatch workspace m+1"; - on-scroll-down = "hyprctl dispatch workspace m-1"; - ignore-workspaces = [ - "special:scratch_.*" - "special:minimized" - ]; - format-icons = { - default = ""; - special = " "; - "1" = " "; - "2" = " "; - "3" = " "; - "4" = " "; - "5" = " "; - "6" = " "; - "7" = " "; - "8" = " "; - "9" = " "; - }; + "hyprland/workspaces" = { + all-outputs = false; + show-special = true; + format = "<small>{name}</small>{icon}"; + on-scroll-up = "hyprctl dispatch workspace m+1"; + on-scroll-down = "hyprctl dispatch workspace m-1"; + ignore-workspaces = [ + "special:scratch_.*" + "special:minimized" + ]; + format-icons = { + default = ""; + special = " "; + "1" = " "; + "2" = " "; + "3" = " "; + "4" = " "; + "5" = " "; + "6" = " "; + "7" = " "; + "8" = " "; + "9" = " "; }; + }; - "hyprland/submap" = { - always-on = false; - tooltip = false; - format = " {}"; - on-click = "hyprctl dispatch submap reset"; - }; + "hyprland/submap" = { + always-on = false; + tooltip = false; + format = " {}"; + on-click = "hyprctl dispatch submap reset"; + }; - "hyprland/window" = { - format = "{class}"; - icon = false; - separate-outputs = true; - }; + "hyprland/window" = { + format = "{class}"; + icon = false; + separate-outputs = true; + }; - "wlr/taskbar" = { - format = "{icon}"; - icon-size = 20; - all-outputs = false; - active-first = false; - icon-theme = theme.icons.name; - markup = true; - tooltip-format = "Name: <big><b>{name}</b></big> <i>{short_state}</i>\nTitle: <b>{title}</b>"; - on-click = "activate"; - on-click-middle = "minimize"; - on-click-right = "close"; - ignore-list = [ - "kitty-clip" - "kitty-dropterm" - ]; - }; + "wlr/taskbar" = { + format = "{icon}"; + icon-size = 20; + all-outputs = false; + active-first = false; + icon-theme = theme.icons.name; + markup = true; + tooltip-format = "Name: <big><b>{name}</b></big> <i>{short_state}</i>\nTitle: <b>{title}</b>"; + on-click = "activate"; + on-click-middle = "minimize"; + on-click-right = "close"; + ignore-list = [ + "kitty-clip" + "kitty-dropterm" + ]; + }; - "custom/minimized" = { - format = ""; - on-click = "hyprutils toggle minimized"; - }; + "custom/minimized" = { + format = ""; + on-click = "hyprutils toggle minimized"; + }; - "group/menu" = { - orientation = "horizontal"; - modules = [ - "custom/hide" - "keyboard-state" - "tray" - ]; - drawer = { - click-to-reveal = true; - transition-left-to-right = true; - }; + "group/menu" = { + orientation = "horizontal"; + modules = [ + "custom/hide" + "keyboard-state" + "tray" + ]; + drawer = { + click-to-reveal = true; + transition-left-to-right = true; }; + }; - "custom/hide" = { - format = ""; - tooltip = false; - }; + "custom/hide" = { + format = ""; + tooltip = false; + }; - tray.icon-size = 14; - keyboard-state = { - numlock = true; - capslock = true; - format = { - numlock = " N {icon}"; - capslock = "󰪛 {icon}"; - }; - format-icons = { - locked = ""; - unlocked = ""; - }; + tray.icon-size = 14; + keyboard-state = { + numlock = true; + capslock = true; + format = { + numlock = " N {icon}"; + capslock = "󰪛 {icon}"; }; - - bluetooth = { - format = ""; - format-disabled = "󰂳"; - format-connected = "󰂱 {num_connections}"; - tooltip-format = " {status}"; - tooltip-format-connected = "{device_enumerate}"; - tooltip-format-enumerate-connected = " {device_alias} 󰂄 {device_battery_percentage}%"; - on-click = "overskride"; + format-icons = { + locked = ""; + unlocked = ""; }; + }; - network = - let - tooltip = "Strength: <b>{signaldBm}dBm ({signalStrength}%)</b>\nFrequency: <b>{frequency}MHz</b>\nInterface: <b>{ifname}</b>\nIP: <b>{ipaddr}/{cidr}</b>\nGateway: <b>{gwaddr}</b>\nNetmask: <b>{netmask}</b>"; - in - { - format = "{ifname}"; - format-disconnected = "󰌙"; - format-wifi = "{icon}"; - format-ethernet = "󰌘"; - format-icons = [ - "󰤯" - "󰤟" - "󰤢" - "󰤥" - "󰤨" - ]; - format-linked = "󰈁 {ifname}"; - tooltip-format-wifi = "Network: <big><b>{essid}</b></big>\n${tooltip}"; - tooltip-format-ethernet = "Network: <big><b>Wired</b></big>\n${tooltip}"; - tooltip-format-disconnected = "󰌙 Disconnected"; - on-click = "sh -c 'env XDG_CURRENT_DESKTOP=GNOME gnome-control-center wifi'"; - }; - - "group/media" = { - orientation = "horizontal"; - modules = [ - "wireplumber" - "mpris" - ]; - drawer = { - transition-left-to-right = false; - transition-duration = 1000; - }; - }; + bluetooth = { + format = ""; + format-disabled = "󰂳"; + format-connected = "󰂱 {num_connections}"; + tooltip-format = " {status}"; + tooltip-format-connected = "{device_enumerate}"; + tooltip-format-enumerate-connected = " {device_alias} 󰂄 {device_battery_percentage}%"; + on-click = "overskride"; + }; - wireplumber = { - max-volume = 150; - scroll-step = 1; - reverse-scrolling = 1; - format = "{icon}"; - tooltip-format = "Volume: {volume}%\nDevice: {node_name}"; + network = + let + tooltip = "Strength: <b>{signaldBm}dBm ({signalStrength}%)</b>\nFrequency: <b>{frequency}MHz</b>\nInterface: <b>{ifname}</b>\nIP: <b>{ipaddr}/{cidr}</b>\nGateway: <b>{gwaddr}</b>\nNetmask: <b>{netmask}</b>"; + in + { + format = "{ifname}"; + format-disconnected = "󰌙"; + format-wifi = "{icon}"; + format-ethernet = "󰌘"; format-icons = [ - "󰕿" - "󰖀" - "󰕾" + "󰤯" + "󰤟" + "󰤢" + "󰤥" + "󰤨" ]; - format-muted = ""; - on-click = "pavucontrol"; + format-linked = "󰈁 {ifname}"; + tooltip-format-wifi = "Network: <big><b>{essid}</b></big>\n${tooltip}"; + tooltip-format-ethernet = "Network: <big><b>Wired</b></big>\n${tooltip}"; + tooltip-format-disconnected = "󰌙 Disconnected"; + on-click = "sh -c 'env XDG_CURRENT_DESKTOP=GNOME gnome-control-center wifi'"; }; - mpris = { - dynamic-len = 20; - dynamic-order = [ - "title" - "artist" - "length" - ]; - dynamic-separator = " - "; - format = " {player}"; - format-paused = "󰏤 <i>{player}</i>"; - format-stopped = ""; - tooltip-format-stopped = "Not Playing"; - on-click = "hyprutils media toggle"; - on-click-right = "hyprutils media next"; - on-click-middle = "hyprutils media previous"; + "group/media" = { + orientation = "horizontal"; + modules = [ + "wireplumber" + "mpris" + ]; + drawer = { + transition-left-to-right = false; + transition-duration = 1000; }; + }; - "group/display" = { - orientation = "horizontal"; - modules = [ - "backlight" - "custom/temperature" - ]; - drawer.transition-left-to-right = false; - }; + wireplumber = { + max-volume = 150; + scroll-step = 1; + reverse-scrolling = 1; + format = "{icon}"; + tooltip-format = "Volume: {volume}%\nDevice: {node_name}"; + format-icons = [ + "󰕿" + "󰖀" + "󰕾" + ]; + format-muted = ""; + on-click = "pavucontrol"; + }; - backlight = { - format = "{icon}"; - tooltip-format = "Backlight: {percent}%"; - format-icons = [ - "" - "" - "" - "" - "" - "" - "" - "" - "" - ]; - on-scroll-up = "hyprutils brightness down"; - on-scroll-down = "hyprutils brightness up"; - on-click = "nwg-displays"; - }; + mpris = { + dynamic-len = 20; + dynamic-order = [ + "title" + "artist" + "length" + ]; + dynamic-separator = " - "; + format = " {player}"; + format-paused = "󰏤 <i>{player}</i>"; + format-stopped = ""; + tooltip-format-stopped = "Not Playing"; + on-click = "sysutils media toggle"; + on-click-right = "sysutils media next"; + on-click-middle = "sysutils media previous"; + }; - "custom/temperature" = { - format = ""; - tooltip = false; - on-scroll-up = "hyprutils temperature up"; - on-scroll-down = "hyprutils temperature down"; - on-click = "hyprutils temperature reset"; - }; + "group/display" = { + orientation = "horizontal"; + modules = [ + "backlight" + "custom/temperature" + ]; + drawer.transition-left-to-right = false; + }; - "group/power" = { - orientation = "horizontal"; - modules = [ - "battery" - "power-profiles-daemon" - ]; - drawer.transition-left-to-right = false; - }; + backlight = { + format = "{icon}"; + tooltip-format = "Backlight: {percent}%"; + format-icons = [ + "" + "" + "" + "" + "" + "" + "" + "" + "" + ]; + on-scroll-up = "sysutils brightness down"; + on-scroll-down = "sysutils brightness up"; + on-click = "nwg-displays"; + }; - battery = { - interval = 5; - align = 0; - rotate = 0; - format = "{icon}"; - tooltip-format = "Battery: {capacity}%"; - format-charging = ""; - format-icons = [ - "" - "" - "" - "" - "" - ]; - on-click-right = "hyprutils toggle fancy"; - states = { - good = 80; - warning = 20; - critical = 10; - }; - }; + "custom/temperature" = { + format = ""; + tooltip = false; + on-scroll-up = "hyprutils temperature up"; + on-scroll-down = "hyprutils temperature down"; + on-click = "hyprutils temperature reset"; + }; - power-profiles-daemon = { - format = "{icon}"; - tooltip = true; - tooltip-format = "Power Profile: {profile}"; - format-icons = { - default = ""; - performance = "󱄟"; - balanced = ""; - power-saver = ""; - }; + "group/power" = { + orientation = "horizontal"; + modules = [ + "battery" + "power-profiles-daemon" + ]; + drawer.transition-left-to-right = false; + }; + + battery = { + interval = 5; + align = 0; + rotate = 0; + format = "{icon}"; + tooltip-format = "Battery: {capacity}%"; + format-charging = ""; + format-icons = [ + "" + "" + "" + "" + "" + ]; + on-click-right = "hyprutils toggle fancy"; + states = { + good = 80; + warning = 20; + critical = 10; }; + }; - "custom/weather" = { - format = "{}°"; - return-type = "json"; - exec = "wttrbar --date-format %d/%m --nerd"; - tooltip = true; - interval = 3600; - signal = 7; - on-click = "pkill -RTMIN+7 waybar"; + power-profiles-daemon = { + format = "{icon}"; + tooltip = true; + tooltip-format = "Power Profile: {profile}"; + format-icons = { + default = ""; + performance = "󱄟"; + balanced = ""; + power-saver = ""; }; + }; - clock = { - interval = 1; - format = "󰅐 {:%H:%M:%S} "; - format-alt = "󰅐 {:%I:%M  %A, %d %B %Y} "; - tooltip-format = "<tt><small>{calendar}</small></tt>"; - calendar = { - mode = "year"; - mode-mon-col = 3; - weeks-pos = "left"; - on-scroll = 1; - format = with config.lib.stylix.colors; { - months = "<span color='#${base06}'><b>{}</b></span>"; - days = "<span color='#${base05}'><b>{}</b></span>"; - weeks = "<span color='#${base0C}'><b>W{}</b></span>"; - weekdays = "<span color='#${base0A}'><b>{}</b></span>"; - today = "<span color='#${base08}'><b><u>{}</u></b></span>"; - }; - }; + "custom/weather" = { + format = "{}°"; + return-type = "json"; + exec = "wttrbar --date-format %d/%m --nerd"; + tooltip = true; + interval = 600; + signal = 7; + on-click = "pkill -RTMIN+7 waybar"; + }; - actions = { - on-click-right = "mode"; - on-click-forward = "tz_up"; - on-click-backward = "tz_down"; - on-scroll-up = "shift_down"; - on-scroll-down = "shift_up"; + clock = { + interval = 1; + format = "󰅐 {:%H:%M:%S} "; + format-alt = "󰅐 {:%I:%M  %A, %d %B %Y} "; + tooltip-format = "<tt><small>{calendar}</small></tt>"; + calendar = { + mode = "year"; + mode-mon-col = 3; + weeks-pos = "left"; + on-scroll = 1; + format = with config.lib.stylix.colors; { + months = "<span color='#${base06}'><b>{}</b></span>"; + days = "<span color='#${base05}'><b>{}</b></span>"; + weeks = "<span color='#${base0C}'><b>W{}</b></span>"; + weekdays = "<span color='#${base0A}'><b>{}</b></span>"; + today = "<span color='#${base08}'><b><u>{}</u></b></span>"; }; }; - "group/notify" = { - orientation = "horizontal"; - modules = [ - "custom/dunst" - "idle_inhibitor" - ]; - drawer.transition-left-to-right = false; + actions = { + on-click-right = "mode"; + on-click-forward = "tz_up"; + on-click-backward = "tz_down"; + on-scroll-up = "shift_down"; + on-scroll-down = "shift_up"; }; + }; - "custom/dunst" = - let - run = - text: - "${ - pkgs.writeShellApplication { - name = "notify"; - inherit text; - runtimeInputs = with pkgs; [ - coreutils - dunst - ]; - } - }/bin/notify"; - in - { - tooltip = false; - on-click = "dunstctl history-pop"; - restart-interval = 1; - on-click-right = run '' - if dunstctl is-paused | grep -q "false" - then - dunstctl set-pause-level 50 - else - dunstctl set-pause-level 0 - fi - ''; - exec = run '' - COUNT=$(dunstctl count waiting) - ENABLED="" - DISABLED="" - if [ "$COUNT" != 0 ]; then DISABLED=" $COUNT"; fi - if dunstctl is-paused | grep -q "false"; then echo "$ENABLED"; else echo "$DISABLED"; fi - ''; - }; + "group/notify" = { + orientation = "horizontal"; + modules = [ + "custom/dunst" + "idle_inhibitor" + ]; + drawer.transition-left-to-right = false; + }; - idle_inhibitor = { - format = "{icon}"; - on-click = "hyprutils toggle service swayidle"; - tooltip-format-activated = "Idle Inhibitor: On"; - tooltip-format-deactivated = "Idle Inhibitor: Off"; - format-icons = { - activated = ""; - deactivated = ""; - }; + "custom/dunst" = + let + run = + text: + "${ + pkgs.writeShellApplication { + name = "notify"; + inherit text; + runtimeInputs = with pkgs; [ + coreutils + dunst + ]; + } + }/bin/notify"; + in + { + tooltip = false; + on-click = "dunstctl history-pop"; + restart-interval = 1; + on-click-right = run '' + if dunstctl is-paused | grep -q "false" + then + dunstctl set-pause-level 50 + else + dunstctl set-pause-level 0 + fi + ''; + exec = run '' + COUNT=$(dunstctl count waiting) + ENABLED="" + DISABLED="" + if [ "$COUNT" != 0 ]; then DISABLED=" $COUNT"; fi + if dunstctl is-paused | grep -q "false"; then echo "$ENABLED"; else echo "$DISABLED"; fi + ''; }; - modules-left = [ - "custom/logo" - "group/users" - "hyprland/workspaces" - "hyprland/submap" - "hyprland/window" - ]; + idle_inhibitor = { + format = "{icon}"; + on-click = "sysutils toggle service swayidle"; + tooltip-format-activated = "Idle Inhibitor: On"; + tooltip-format-deactivated = "Idle Inhibitor: Off"; + format-icons = { + activated = ""; + deactivated = ""; + }; + }; - modules-center = [ - "wlr/taskbar" - "custom/minimized" + modules-left = [ + "custom/logo" + "group/users" + "hyprland/workspaces" + "hyprland/submap" + "hyprland/window" + ]; + + modules-center = [ + "wlr/taskbar" + "custom/minimized" + ]; + }; + in + [ + ( + shared + // { + output = display; + modules-right = [ + "group/menu" + "bluetooth" + "network" + "group/media" + "group/display" + "group/power" + "custom/weather" + "clock" + "group/notify" ]; - }; - in - [ - ( - shared - // { - output = display; - modules-right = [ - "group/menu" - "bluetooth" - "network" - "group/media" - "group/display" - "group/power" - "custom/weather" - "clock" - "group/notify" - ]; - } - ) - ( - shared - // { - output = "!" + display; - modules-right = [ - "group/menu" - "bluetooth" - "network" - "group/media" - "group/power" - "custom/weather" - "clock" - "group/notify" - ]; - } - ) - ]; - }; + } + ) + ( + shared + // { + output = "!" + display; + modules-right = [ + "group/menu" + "bluetooth" + "network" + "group/media" + "group/power" + "custom/weather" + "clock" + "group/notify" + ]; + } + ) + ]; }; } diff --git a/modules/gui/desktop/hyprland/apps/security.nix b/modules/gui/desktop/hyprland/apps/security.nix @@ -1,138 +0,0 @@ -{ - config, - lib, - util, - pkgs, - files, - ... -}: -let - inherit (lib) getExe getExe'; - locker = pkgs.swaylock-effects; -in -{ - ## Security Configuration - # User Authentication - security = { - soteria.enable = true; - pam.services.swaylock.text = "auth include login"; - }; - - user.homeConfig = { - # Locker - stylix.targets.swaylock = { - enable = true; - useImage = true; - }; - - programs.swaylock = { - enable = true; - package = locker; - settings = { - clock = true; - indicator = true; - font = config.stylix.fonts.sansSerif.name; - effect-vignette = "0.3:1"; - }; - }; - - # Idle Daemon - services.swayidle = - let - pause = "${getExe pkgs.playerctl} pause -a;"; - lock = - pre: flag: - "sh -c 'if ! ${getExe' pkgs.procps "pgrep"} -x swaylock; then ${pre} ${getExe locker} -f ${flag}; fi'"; - in - { - enable = true; - extraArgs = [ "-w" ]; - events = [ - { - event = "before-sleep"; - command = lock pause ""; - } - { - event = "lock"; - command = lock pause "--fade-in 0.2 --grace 15 --grace-no-mouse"; - } - ]; - - timeouts = - let - audio = - command: - "${pkgs.writeShellScript "audio" '' - ${getExe pkgs.playerctl} status | ${getExe pkgs.gnugrep} Playing - if [ $? == 1 ]; then ${command}; fi - ''}"; # Check if audio is playing - shader = getExe pkgs.hyprshade; - dpms = "${getExe' config.programs.hyprland.package "hyprctl"} dispatch dpms"; - in - [ - { - timeout = 240; # Dim display - command = audio "${shader} on dim"; - resumeCommand = "${shader} off"; - } - { - timeout = 300; # Turn off display - command = audio "${dpms} off"; - resumeCommand = "${dpms} on"; - } - { - timeout = 500; # Suspend device - command = audio "${dpms} on && ${lock "" ""} && ${getExe' pkgs.systemd "systemctl"} suspend"; - } - ]; - }; - - # Logout - programs.wlogout = { - enable = true; - style = util.build.theme { - inherit (config.lib.stylix) colors; - file = files.hyprland.wlogout; - }; - - layout = [ - { - label = "lock"; - action = "loginctl lock-session"; - text = ""; - keybind = "l"; - } - { - label = "logout"; - action = "loginctl terminate-user $USER"; - text = "↶"; - keybind = "e"; - } - { - label = "shutdown"; - action = "systemctl poweroff"; - text = "⏻"; - keybind = "s"; - } - { - label = "reboot"; - action = "systemctl reboot"; - text = "↺"; - keybind = "r"; - } - { - label = "suspend"; - action = "systemctl suspend"; - text = ""; - keybind = "u"; - } - { - label = "hibernate"; - action = "systemctl hibernate"; - text = ""; - keybind = "h"; - } - ]; - }; - }; -} diff --git a/modules/gui/desktop/hyprland/apps/settings.nix b/modules/gui/desktop/hyprland/apps/settings.nix @@ -1,208 +0,0 @@ -{ - config, - lib, - util, - pkgs, - files, - theme, - ... -}: -let - inherit (builtins) map toString; - inherit (lib) flatten getExe; - inherit (config.gui) cursors display; - cursor = "${cursors.name}-Hyprcursor"; -in -{ - ## App Environment - xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; - - # Desktop Integration - stylix.base16Scheme = files.colors.catppuccin; - environment.systemPackages = [ pkgs.custom.cursors ]; - gui = with theme; { - inherit (theme) icons; - - gtk = { - enable = true; - theme = gtk; - }; - - qt = { - enable = true; - theme = qt; - style = "kvantum"; - }; - }; - - user.homeConfig = { - # GTK Apps - dconf.settings."org/gnome/desktop/wm/preferences" = { - action-double-click-titlebar = "none"; - button-layout = "appmenu"; - }; - - # Cursor - xdg.dataFile."icons/${cursor}".source = "${cursors.package}/share/icons/${cursor}"; - wayland.windowManager.hyprland.settings = { - env = [ - "HYPRCURSOR_THEME, ${cursor}" - "HYPRCURSOR_SIZE, ${toString cursors.size}" - - # QT Apps - "QT_WAYLAND_DISABLE_WINDOWDECORATION, 1" - - # Screenshot - "SLURP_ARGS, -dc ${config.lib.stylix.colors.base0D}" - ]; - - ## Autostart - exec-once = [ - "uwsm finalize" - "hyprctl setcursor ${cursor} ${toString cursors.size}" - ] - ++ (map (app: "uwsm app -t service -u ${util.build.until " " app}.service -- " + app) [ - "hyprutils daemon" - - # Pyprland - "pypr" - - # Application Drawer - "nwg-drawer -r" - - # Desktop Icons - "pcmanfm-qt --desktop" - ]); - - ## Shortcuts - bind = - let - toggle = app: "pkill ${app} || uwsm app -u ${app}.scope -- ${app}"; - runOnce = app: "pgrep ${app} || uwsm app -u ${app}.scope -- ${app}"; - in - [ - # Applications - "$mod, F, exec, nemo" - "$mod, T, exec, kitty" - "$mod, W, exec, firefox" - "$mod, Return, exec, ${runOnce "resources"}" - "$mod SHIFT, equal, exec, pypr toggle calc" - ", XF86Calculator, exec, qalculate-gtk" - - # Utilities - "$mod, A, exec, nwg-drawer" - "$mod, slash, exec, ${toggle "kebihelp"} show -a" - "$mod SHIFT, C, exec, ${runOnce "hyprpicker"} -arf hex" - "$mod SHIFT, B, exec, ${runOnce "overskride"}" - "$mod, D, exec, ${runOnce "nwg-displays"}" - "$mod SHIFT, P, exec, pavucontrol" - "$mod SHIFT, N, exec, sh -c 'env XDG_CURRENT_DESKTOP=GNOME gnome-control-center wifi'" - "$mod, Escape, exec, ${toggle "wlogout"} -p layer-shell" - - # Tools - "$mod SHIFT, A, exec, hyprutils toggle service waybar" - "$mod SHIFT, D, exec, hyprutils toggle monitor ${display}" - "$mod, N, exec, dunstctl history-pop" - "$mod, S, exec, hyprutils toggle shader" - "$mod SHIFT, T, exec, pypr toggle term" - "$mod, V, exec, pypr show clip" - "$mod, backslash, exec, pypr toggle emoji" - ]; - - ## Permissions - permission = [ - "${config.programs.hyprland.portalPackage}/libexec/.xdg-desktop-portal-hyprland-wrapped, screencopy, allow" - "${getExe pkgs.grim}, screencopy, allow" - "${getExe pkgs.wl-screenrec}, screencopy, allow" - ]; - - ## Layer Rules - layerrule = [ - "noanim, ^(hyprpicker)$" - "blur, ^(hyprshell_overview)$" - "dimaround, ^(hyprshell_overview)$" - "blur, ^(logout_dialog)$" - "animation fade, ^(logout_dialog)$" - "blur, ^(nwg-drawer)$" - "dimaround, ^(nwg-drawer)$" - "animation fade, ^(nwg-drawer)$" - "blur, ^(waybar)$" - "ignorealpha, ^(waybar)$" - "blur, ^(wlclock)$" - "ignorealpha, ^(wlclock)$" - ]; - - ## Window Rules - windowrulev2 = flatten ( - [ - # Settings - "stayfocused, class:^(gnome-control-center)$" - - # Keybinds Viewer - "pin, title:^(Kebihelp)$" - "stayfocused, title:^(Kebihelp)$" - "opacity 0.9 override, title:^(Kebihelp)" - - # Browser Windows - "float, title:^(Picture-in-Picture)$" - "workspace special silent, title:^(Sharing Indicator)$" - "workspace special silent, title:^(.*is sharing (your screen|a window)\.)$" - - # Media Consumption - "idleinhibit focus, class:^(mpv|.*celluloid.*|.+exe)$" - "idleinhibit focus, class:^(firefox|google-chrome)$, title:^(.*YouTube.*)$" - "idleinhibit fullscreen, class:^(firefox|google-chrome)$" - - # Screen Tearing - "immediate, class:^(.+exe)$" - - # Prompt Windows - "float, class:^(xdg-desktop-portal-gtk)" - "dimaround, class:^(xdg-desktop-portal-gtk)" - ] - ++ (map - (class: [ - "pin, class:^(${class})" - "dimaround, class:^(${class})" - "stayfocused, class:^(${class})" - ]) - [ - "pinentry-" - "gay.vaskel.Soteria" - "gcr-prompter" - ] - ) - ++ (map - (class: [ - # Utilities - "float, class:^(${class})" - "pin, class:^(${class})" - "persistentsize, class:^(${class})" - ]) - [ - "io.github.kaii_lb.Overskride" - "nwg-displays" - "org.pulseaudio.pavucontrol" - "gnome-control-center" - "org.gnome.Settings" - ] - ) - ++ (map - (title: [ - # Dialogs - "float, title:^(${title})(.*)$" - ]) - [ - "Library" - "Open File" - "Open Folder" - "Save As" - "Save File" - "Select a File" - ".*Properties" - ] - ) - ); - }; - }; -} diff --git a/modules/gui/desktop/hyprland/apps/terminal.nix b/modules/gui/desktop/hyprland/apps/terminal.nix @@ -1,42 +0,0 @@ -{ - pkgs, - theme, - ... -}: -{ - ## Terminal Configuration - user.homeConfig = { - programs.kitty = { - enable = true; - themeFile = with theme; "${name-alt}-${variant-alt}"; - keybindings = { - "ctrl+c" = "copy_or_interrupt"; - "kitty_mod+f" = - "launch --allow-remote-control kitty +kitten search/search.py @active-kitty-window-id"; - }; - - settings = { - kitty_mod = "ctrl+shift"; - confirm_os_window_close = 2; - copy_on_select = "clipboard"; - placement_strategy = "center"; - scrollback_lines = 10000; - enable_audio_bell = "no"; - visual_bell_duration = "0.1"; - - cursor_shape = "beam"; - cursor_shape_unfocused = "underline"; - tab_bar_style = "powerline"; - tab_powerline_style = "round"; - window_padding_width = 10; - }; - }; - - home.file.".config/kitty/search".source = pkgs.custom.kitty-search; - wayland.windowManager.hyprland.settings.misc.swallow_regex = "^(kitty)$"; - stylix.targets.kitty = { - enable = true; - variant256Colors = true; - }; - }; -} diff --git a/modules/gui/desktop/hyprland/apps/utilities.nix b/modules/gui/desktop/hyprland/apps/utilities.nix @@ -13,19 +13,8 @@ in { environment.systemPackages = with pkgs; [ # Apps - clipse custom.kebihelp - font-manager - gnome-clocks - gnome-disk-utility - hyprpicker nwg-displays - nwg-drawer - overskride - qalculate-gtk - remmina - resources - smile # Utilities custom.hyprutils @@ -34,45 +23,9 @@ in hyprkeys hyprshade hyprsunset - pavucontrol pyprland slurp waycorner - wev - wlclock - wl-clipboard - wl-screenrec - wlr-randr - - # Network Settings - (gnome-control-center.overrideAttrs (old: { - postInstall = old.postInstall + '' - dir=$out/share/applications - for panel in $dir/* - do - [ "$panel" = "$dir/gnome-network-panel.desktop" ] && continue - [ "$panel" = "$dir/gnome-wifi-panel.desktop" ] && continue - [ "$panel" = "$dir/gnome-wwan-panel.desktop" ] && continue - [ "$panel" = "$dir/gnome-sharing-panel.desktop" ] && continue - [ "$panel" = "$dir/gnome-wacom-panel.desktop" ] && continue - rm "$panel" - done - ''; - })) - ]; - - ## Essential Utilities - # Power - services = { - power-profiles-daemon.enable = true; - upower.enable = true; - }; - - # Backlight - hardware.brillo.enable = true; - user.groups = [ - "input" - "video" ]; user = { @@ -116,35 +69,19 @@ in }; }; - systemd.user.services = + systemd.user.services.waycorner = let target = [ "graphical-session.target" ]; - run = about: command: { - Install.WantedBy = target; - Service.ExecStart = command; - Unit = { - Description = about; - After = target; - }; - }; in { - waycorner = run "Hot Corners" (getExe pkgs.waycorner); - wlclock = - with colors; - run "Desktop Clock" "${getExe pkgs.wlclock} --layer bottom --exclusive-zone true --position top-right --margin 10 --size 300 --corner-radius 10 --border-size 2 --hand-width 7 --marking-width 3 --background-colour #${base00}4d --clock-colour #${base0D} --border-colour #${base00}"; + Install.WantedBy = target; + Unit = { + Description = "Hot Corners"; + After = target; + }; + Service.ExecStart = getExe pkgs.waycorner; }; - # Network Settings - xdg.desktopEntries."org.gnome.Settings" = { - name = "Network Settings"; - comment = "Gnome Control Center"; - icon = "org.gnome.Settings"; - exec = "env XDG_CURRENT_DESKTOP=gnome gnome-control-center"; - categories = [ "X-Preferences" ]; - terminal = false; - }; - home.file = with files.hyprland; { # Application Drawer ".config/nwg-drawer/drawer.css".text = drawer; diff --git a/modules/gui/desktop/hyprland/default.nix b/modules/gui/desktop/hyprland/default.nix @@ -15,83 +15,48 @@ let replaceStrings ; + inherit (util.map.modules) list; inherit (config.gui) desktop; - theme = import ./theme.nix pkgs; in { ## Hyprland Configuration ## config = mkIf (desktop == "hyprland") ( mkMerge ( # App Configuration - (builtins.map (path: import path (args // { inherit theme; })) (util.map.modules.list ./apps)) + (builtins.map (path: import path (args // { theme = import ../common/theme.nix pkgs; })) ( + list ../common/apps ++ list ./apps + )) ++ [ ## Environment Setup rec { - programs = { - # WM - hyprland = { - enable = true; - withUWSM = true; - xwayland.enable = true; - package = pkgs.hyprworld.hyprland; - portalPackage = pkgs.hyprworld.xdg-desktop-portal-hyprland; - }; - - # Login - regreet = { - enable = true; - package = pkgs.greetd.regreet; - settings.commands = { - reboot = [ - "systemctl" - "reboot" - ]; - poweroff = [ - "systemctl" - "poweroff" - ]; - }; - }; + # WM + programs.hyprland = { + enable = true; + withUWSM = true; + xwayland.enable = true; + package = pkgs.hyprworld.hyprland; + portalPackage = pkgs.hyprworld.xdg-desktop-portal-hyprland; }; - # Session services = { - displayManager.defaultSession = "Desktop"; - xserver = { - desktopManager.runXdgAutostartIfNone = true; - displayManager.session = [ - { - name = "Desktop"; - manage = "desktop"; - start = "uwsm start -S -F Hyprland &> /dev/null"; - } - ]; - }; + xserver.desktopManager.runXdgAutostartIfNone = true; # Greeter - greetd.settings.default_session.command = - with programs; - mkForce "${getExe hyprland.package} --config ${ - pkgs.writeText "greeter.conf" ( - replaceStrings [ "@greeter" ] [ (getExe regreet.package) ] ( - util.build.theme { - inherit (config.lib.stylix) colors; - file = files.hyprland.greeter; - } - ) + greetd.settings.default_session.command = mkForce "${getExe programs.hyprland.package} --config ${ + pkgs.writeText "greeter.conf" ( + replaceStrings [ "@greeter" ] [ (getExe config.programs.regreet.package) ] ( + util.build.theme { + inherit (config.lib.stylix) colors; + file = files.hyprland.greeter; + } ) - } &> /dev/null"; + ) + } &> /dev/null"; }; } { - # Greeter - environment.persist.directories = [ "/var/lib/regreet" ]; - stylix.targets.regreet.enable = true; - programs.regreet = { - extraCss = mkForce ""; - theme = mkForce theme.gtk; - iconTheme = mkForce theme.icons; - }; + # App Environment + xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; # Settings user = { diff --git a/modules/gui/desktop/hyprland/settings/apps.nix b/modules/gui/desktop/hyprland/settings/apps.nix @@ -0,0 +1,181 @@ +{ + sys, + lib, + util, + pkgs, + ... +}: +let + inherit (builtins) map toString; + inherit (lib) flatten getExe; + inherit (sys.gui) cursors display; + cursor = "${cursors.name}-Hyprcursor"; +in +{ + ## App Environment + # Cursor + xdg.dataFile."icons/${cursor}".source = "${cursors.package}/share/icons/${cursor}"; + wayland.windowManager.hyprland.settings = { + env = [ + "HYPRCURSOR_THEME, ${cursor}" + "HYPRCURSOR_SIZE, ${toString cursors.size}" + + # QT Apps + "QT_WAYLAND_DISABLE_WINDOWDECORATION, 1" + + # Screenshot + "SLURP_ARGS, -dc ${sys.lib.stylix.colors.base0D}" + ]; + + # Window Swallowing + misc.swallow_regex = "^(kitty)$"; + + ## Autostart + exec-once = [ + "uwsm finalize" + "hyprctl setcursor ${cursor} ${toString cursors.size}" + ] + ++ (map (app: "uwsm app -t service -u ${util.build.until " " app}.service -- " + app) [ + "hyprutils daemon" + + # Pyprland + "pypr" + + # Application Drawer + "nwg-drawer -r" + + # Desktop Icons + "pcmanfm-qt --desktop" + ]); + + ## Shortcuts + bind = + let + toggle = app: "pkill ${app} || uwsm app -u ${app}.scope -- ${app}"; + runOnce = app: "pgrep ${app} || uwsm app -u ${app}.scope -- ${app}"; + in + [ + # Applications + "$mod, F, exec, nemo" + "$mod, T, exec, kitty" + "$mod, W, exec, firefox" + "$mod, Return, exec, ${runOnce "resources"}" + "$mod SHIFT, equal, exec, pypr toggle calc" + ", XF86Calculator, exec, qalculate-gtk" + + # Utilities + "$mod, A, exec, nwg-drawer" + "$mod, slash, exec, ${toggle "kebihelp"} show -a" + "$mod SHIFT, C, exec, ${runOnce "hyprpicker"} -arf hex" + "$mod SHIFT, B, exec, ${runOnce "overskride"}" + "$mod, D, exec, ${runOnce "nwg-displays"}" + "$mod SHIFT, P, exec, pavucontrol" + "$mod SHIFT, N, exec, sh -c 'env XDG_CURRENT_DESKTOP=GNOME gnome-control-center wifi'" + "$mod, Escape, exec, ${toggle "wlogout"} -p layer-shell" + + # Tools + "$mod SHIFT, A, exec, sysutils toggle service waybar" + "$mod SHIFT, D, exec, hyprutils toggle monitor ${display}" + "$mod, N, exec, dunstctl history-pop" + "$mod, S, exec, hyprutils toggle shader" + "$mod SHIFT, T, exec, pypr toggle term" + "$mod, V, exec, pypr show clip" + "$mod, backslash, exec, pypr toggle emoji" + ]; + + ## Permissions + permission = [ + "${sys.programs.hyprland.portalPackage}/libexec/.xdg-desktop-portal-hyprland-wrapped, screencopy, allow" + "${getExe pkgs.grim}, screencopy, allow" + "${getExe pkgs.wl-screenrec}, screencopy, allow" + ]; + + ## Layer Rules + layerrule = [ + "noanim, ^(hyprpicker)$" + "blur, ^(hyprshell_overview)$" + "dimaround, ^(hyprshell_overview)$" + "blur, ^(logout_dialog)$" + "animation fade, ^(logout_dialog)$" + "blur, ^(nwg-drawer)$" + "dimaround, ^(nwg-drawer)$" + "animation fade, ^(nwg-drawer)$" + "blur, ^(waybar)$" + "ignorealpha, ^(waybar)$" + "blur, ^(wlclock)$" + "ignorealpha, ^(wlclock)$" + ]; + + ## Window Rules + windowrulev2 = flatten ( + [ + # Settings + "stayfocused, class:^(gnome-control-center)$" + + # Keybinds Viewer + "pin, title:^(Kebihelp)$" + "stayfocused, title:^(Kebihelp)$" + "opacity 0.9 override, title:^(Kebihelp)" + + # Browser Windows + "float, title:^(Picture-in-Picture)$" + "workspace special silent, title:^(Sharing Indicator)$" + "workspace special silent, title:^(.*is sharing (your screen|a window)\.)$" + + # Media Consumption + "idleinhibit focus, class:^(mpv|.*celluloid.*|.+exe)$" + "idleinhibit focus, class:^(firefox|google-chrome)$, title:^(.*YouTube.*)$" + "idleinhibit fullscreen, class:^(firefox|google-chrome)$" + + # Screen Tearing + "immediate, class:^(.+exe)$" + + # Prompt Windows + "float, class:^(xdg-desktop-portal-gtk)" + "dimaround, class:^(xdg-desktop-portal-gtk)" + ] + ++ (map + (class: [ + "pin, class:^(${class})" + "dimaround, class:^(${class})" + "stayfocused, class:^(${class})" + ]) + [ + "pinentry-" + "gay.vaskel.Soteria" + "gcr-prompter" + ] + ) + ++ (map + (class: [ + # Utilities + "float, class:^(${class})" + "pin, class:^(${class})" + "persistentsize, class:^(${class})" + ]) + [ + "io.github.kaii_lb.Overskride" + "nwg-displays" + "org.pulseaudio.pavucontrol" + "gnome-control-center" + "org.gnome.Settings" + ] + ) + ++ (map + (title: [ + # Dialogs + "float, title:^(${title})(.*)$" + ]) + [ + "Library" + "Open File" + "Open Folder" + "Save As" + "Save File" + "Select a File" + ".*Properties" + ] + ) + ); + }; +} diff --git a/modules/gui/desktop/hyprland/settings/keybindings.nix b/modules/gui/desktop/hyprland/settings/keybindings.nix @@ -1,201 +0,0 @@ -_: -let - inherit (builtins) concatLists genList toString; -in -{ - ## Compositor Binds ## - wayland.windowManager.hyprland = { - ## Keybindings - settings = { - "$mod" = "SUPER"; - bind = [ - # Compositor Commands - "ALT, F4, killactive," - "$mod, Q, killactive," - "$mod SHIFT, Q, forcekillactive," - "$mod SHIFT, E, fullscreen," - "$mod, C, centerwindow" - "$mod, C, movecursortocorner, 2" - "$mod, E, fullscreen, 1" - "$mod, P, pin" - "$mod, Space, togglesplit" - "$mod SHIFT, S, toggleswallow" - - # Window Focus - "$mod, left, movefocus, l" - "$mod, right, movefocus, r" - "$mod, up, movefocus, u" - "$mod, down, movefocus, d" - "ALT, A, focusurgentorlast" - "ALT, A, alterzorder, top" - - # Window Swap - "$mod SHIFT, left, swapwindow, l" - "$mod SHIFT, right, swapwindow, r" - "$mod SHIFT, up, swapwindow, u" - "$mod SHIFT, down, swapwindow, d" - - # Window Groups - "$mod SHIFT, space, togglegroup" - "ALT, grave, changegroupactive, f" - "ALT SHIFT, grave, changegroupactive, b" - "$mod CTRL, left, moveintogroup, l" - "$mod CTRL, right, moveintogroup, r" - "$mod CTRL, up, moveintogroup, u" - "$mod CTRL, down, moveintogroup, d" - - # Floating Mode - "$mod, semicolon, togglefloating," - "$mod, apostrophe, exec, hyprutils toggle float" - - # Cycle Workspaces - "$mod, comma, split:workspace, m-1" - "$mod, period, split:workspace, m+1" - "$mod CTRL, comma, split:workspace, r-1" - "$mod CTRL, period, split:workspace, r+1" - "$mod, mouse_up, split:workspace, r-1" - "$mod, mouse_down, split:workspace, r+1" - - # Special Workspace - "$mod, 0, togglespecialworkspace, Stash" - "$mod SHIFT, 0, exec, pypr toggle_special Stash" - - # Move Window to Workspace - "$mod SHIFT, comma, split:movetoworkspace, r-1" - "$mod SHIFT, period, split:movetoworkspace, r+1" - - # Cycle Monitors - "$mod ALT, comma, focusmonitor, l" - "$mod ALT, period, focusmonitor, r" - - # Move Window to Monitor - "$mod SHIFT ALT, comma, movewindow, mon:-1" - "$mod SHIFT ALT, period, movewindow, mon:+1" - - # Screen Lock - "$mod, L, exec, loginctl lock-session" - - # Window Minimization - "ALT, Q, movetoworkspacesilent, special:minimized" - "ALT SHIFT, Q, exec, hyprutils toggle minimized" - - # Screenshot - '', Print, exec, sh -c "pgrep slurp || grimblast --notify --freeze copysave area"'' - "CTRL, Print, exec, grimblast --notify --cursor copysave active" - "SHIFT, Print, exec, grimblast --notify --cursor copysave output" - ] - ++ - # Workspaces - (concatLists ( - genList ( - n: - let - num = toString (n + 1); - in - [ - "$mod, ${num}, split:workspace, ${num}" - "$mod SHIFT, ${num}, split:movetoworkspace, ${num}" - ] - ) 9 - )); - - # Mouse - bindm = [ - "$mod, mouse:272, movewindow" - "$mod, mouse:273, resizewindow" - ]; - - # Ignore Locked State - bindl = [ - # Media Controls - ", XF86AudioPlay, exec, hyprutils media toggle" - ", XF86AudioPrev, exec, hyprutils media previous" - ", XF86AudioNext, exec, hyprutils media next" - - # Volume - ", XF86AudioMute, exec, hyprutils volume mute" - - # Keyboard Backlight - ", XF86KbdBrightnessUp, exec, hyprutils backlight up" - ", XF86KbdBrightnessDown, exec, hyprutils backlight down" - - # Touchpad - ", XF86TouchpadToggle, exec, hyprutils toggle touchpad" - ]; - - # Repeat on Hold - bindle = [ - # Volume - ", XF86AudioRaiseVolume, exec, hyprutils volume up" - ", XF86AudioLowerVolume, exec, hyprutils volume down" - - # Backlight - ", XF86MonBrightnessUp, exec, hyprutils brightness up" - ", XF86MonBrightnessDown, exec, hyprutils brightness down" - - # Magnifier - "$mod, equal, exec, pypr zoom ++0.5" - "$mod, minus, exec, pypr zoom --0.5" - "$mod SHIFT, minus, exec, pypr zoom" - ]; - }; - - ## Submaps - extraConfig = '' - # Inhibit Keybinds - bind = $mod SHIFT, Escape, exec, hyprutils toggle service waycorner - bind = $mod SHIFT, Escape, submap, Inhibit - submap = Inhibit - bind = $mod SHIFT, Escape, exec, hyprutils toggle service waycorner - bind = $mod SHIFT, Escape, submap, reset - submap = reset - - # Window Resize - bind = $mod, R, submap, Resize - submap = Resize - binde = , right, resizeactive, 10 0 - binde = , left, resizeactive, -10 0 - binde = , up, resizeactive, 0 -10 - binde = , down, resizeactive, 0 10 - bindm = , mouse:272, resizewindow - bind = , escape, submap, reset - bind = $mod, R, submap, reset - submap = reset - - # Window Movement - bind = $mod, M, submap, Move - submap = Move - bindm = , mouse:272, movewindow - bind = , C, centerwindow - bind = , P, pin - bind = , left, movewindoworgroup, l - bind = , right, movewindoworgroup, r - bind = , up, movewindoworgroup, u - bind = , down, movewindoworgroup, d - bind = SHIFT, left, moveactive, -30 0 - bind = SHIFT, right, moveactive, 30 0 - bind = SHIFT, up, moveactive, 0 -30 - bind = SHIFT, down, moveactive, 0 30 - bind = , comma, split:movetoworkspace, r-1 - bind = , period, split:movetoworkspace, r+1 - bind = , escape, submap, reset - bind = $mod, M, submap, reset - submap = reset - - # Window Minimization - submap = Minimized - bind = , left, movefocus, l - bind = , right, movefocus, r - bind = , up, movefocus, u - bind = , down, movefocus, d - bind = , Q, killactive, - bind = , Return, movetoworkspace, +0 - bind = , Return, submap, reset - bind = , mouse:272, movetoworkspace, +0 - bind = , mouse:272, submap, reset - bind = , escape, togglespecialworkspace, minimized - bind = , escape, submap, reset - submap = reset - ''; - }; -} diff --git a/modules/gui/desktop/hyprland/settings/keybinds.nix b/modules/gui/desktop/hyprland/settings/keybinds.nix @@ -0,0 +1,201 @@ +_: +let + inherit (builtins) concatLists genList toString; +in +{ + ## Compositor Binds ## + wayland.windowManager.hyprland = { + ## Keybindings + settings = { + "$mod" = "SUPER"; + bind = [ + # Compositor Commands + "ALT, F4, killactive," + "$mod, Q, killactive," + "$mod SHIFT, Q, forcekillactive," + "$mod SHIFT, E, fullscreen," + "$mod, C, centerwindow" + "$mod, C, movecursortocorner, 2" + "$mod, E, fullscreen, 1" + "$mod, P, pin" + "$mod, Space, togglesplit" + "$mod SHIFT, S, toggleswallow" + + # Window Focus + "$mod, left, movefocus, l" + "$mod, right, movefocus, r" + "$mod, up, movefocus, u" + "$mod, down, movefocus, d" + "ALT, A, focusurgentorlast" + "ALT, A, alterzorder, top" + + # Window Swap + "$mod SHIFT, left, swapwindow, l" + "$mod SHIFT, right, swapwindow, r" + "$mod SHIFT, up, swapwindow, u" + "$mod SHIFT, down, swapwindow, d" + + # Window Groups + "$mod SHIFT, space, togglegroup" + "ALT, grave, changegroupactive, f" + "ALT SHIFT, grave, changegroupactive, b" + "$mod CTRL, left, moveintogroup, l" + "$mod CTRL, right, moveintogroup, r" + "$mod CTRL, up, moveintogroup, u" + "$mod CTRL, down, moveintogroup, d" + + # Floating Mode + "$mod, semicolon, togglefloating," + "$mod, apostrophe, exec, hyprutils toggle float" + + # Cycle Workspaces + "$mod, comma, split:workspace, m-1" + "$mod, period, split:workspace, m+1" + "$mod CTRL, comma, split:workspace, r-1" + "$mod CTRL, period, split:workspace, r+1" + "$mod, mouse_up, split:workspace, r-1" + "$mod, mouse_down, split:workspace, r+1" + + # Special Workspace + "$mod, 0, togglespecialworkspace, Stash" + "$mod SHIFT, 0, exec, pypr toggle_special Stash" + + # Move Window to Workspace + "$mod SHIFT, comma, split:movetoworkspace, r-1" + "$mod SHIFT, period, split:movetoworkspace, r+1" + + # Cycle Monitors + "$mod ALT, comma, focusmonitor, l" + "$mod ALT, period, focusmonitor, r" + + # Move Window to Monitor + "$mod SHIFT ALT, comma, movewindow, mon:-1" + "$mod SHIFT ALT, period, movewindow, mon:+1" + + # Screen Lock + "$mod, L, exec, loginctl lock-session" + + # Window Minimization + "ALT, Q, movetoworkspacesilent, special:minimized" + "ALT SHIFT, Q, exec, hyprutils toggle minimized" + + # Screenshot + '', Print, exec, sh -c "pgrep slurp || grimblast --notify --freeze copysave area"'' + "CTRL, Print, exec, grimblast --notify --cursor copysave active" + "SHIFT, Print, exec, grimblast --notify --cursor copysave output" + ] + ++ + # Workspaces + (concatLists ( + genList ( + n: + let + num = toString (n + 1); + in + [ + "$mod, ${num}, split:workspace, ${num}" + "$mod SHIFT, ${num}, split:movetoworkspace, ${num}" + ] + ) 9 + )); + + # Mouse + bindm = [ + "$mod, mouse:272, movewindow" + "$mod, mouse:273, resizewindow" + ]; + + # Ignore Locked State + bindl = [ + # Media Controls + ", XF86AudioPlay, exec, sysutils media toggle" + ", XF86AudioPrev, exec, sysutils media previous" + ", XF86AudioNext, exec, sysutils media next" + + # Volume + ", XF86AudioMute, exec, sysutils volume mute" + + # Keyboard Backlight + ", XF86KbdBrightnessUp, exec, sysutils backlight up" + ", XF86KbdBrightnessDown, exec, sysutils backlight down" + + # Touchpad + ", XF86TouchpadToggle, exec, hyprutils toggle touchpad" + ]; + + # Repeat on Hold + bindle = [ + # Volume + ", XF86AudioRaiseVolume, exec, sysutils volume up" + ", XF86AudioLowerVolume, exec, sysutils volume down" + + # Backlight + ", XF86MonBrightnessUp, exec, sysutils brightness up" + ", XF86MonBrightnessDown, exec, sysutils brightness down" + + # Magnifier + "$mod, equal, exec, pypr zoom ++0.5" + "$mod, minus, exec, pypr zoom --0.5" + "$mod SHIFT, minus, exec, pypr zoom" + ]; + }; + + ## Submaps + extraConfig = '' + # Inhibit Keybinds + bind = $mod SHIFT, Escape, exec, sysutils toggle service waycorner + bind = $mod SHIFT, Escape, submap, Inhibit + submap = Inhibit + bind = $mod SHIFT, Escape, exec, sysutils toggle service waycorner + bind = $mod SHIFT, Escape, submap, reset + submap = reset + + # Window Resize + bind = $mod, R, submap, Resize + submap = Resize + binde = , right, resizeactive, 10 0 + binde = , left, resizeactive, -10 0 + binde = , up, resizeactive, 0 -10 + binde = , down, resizeactive, 0 10 + bindm = , mouse:272, resizewindow + bind = , escape, submap, reset + bind = $mod, R, submap, reset + submap = reset + + # Window Movement + bind = $mod, M, submap, Move + submap = Move + bindm = , mouse:272, movewindow + bind = , C, centerwindow + bind = , P, pin + bind = , left, movewindoworgroup, l + bind = , right, movewindoworgroup, r + bind = , up, movewindoworgroup, u + bind = , down, movewindoworgroup, d + bind = SHIFT, left, moveactive, -30 0 + bind = SHIFT, right, moveactive, 30 0 + bind = SHIFT, up, moveactive, 0 -30 + bind = SHIFT, down, moveactive, 0 30 + bind = , comma, split:movetoworkspace, r-1 + bind = , period, split:movetoworkspace, r+1 + bind = , escape, submap, reset + bind = $mod, M, submap, reset + submap = reset + + # Window Minimization + submap = Minimized + bind = , left, movefocus, l + bind = , right, movefocus, r + bind = , up, movefocus, u + bind = , down, movefocus, d + bind = , Q, killactive, + bind = , Return, movetoworkspace, +0 + bind = , Return, submap, reset + bind = , mouse:272, movetoworkspace, +0 + bind = , mouse:272, submap, reset + bind = , escape, togglespecialworkspace, minimized + bind = , escape, submap, reset + submap = reset + ''; + }; +} diff --git a/modules/gui/desktop/niri/apps/launcher.nix b/modules/gui/desktop/niri/apps/launcher.nix @@ -0,0 +1,30 @@ +{ + config, + util, + pkgs, + files, + ... +}: +{ + ## Launcher Configuration + user = { + persist.directories = [ ".cache/rofi" ]; + homeConfig = { + programs.rofi = { + enable = true; + package = pkgs.rofi-wayland; + configPath = ".config/rofi/main.rasi"; + plugins = with pkgs; [ + rofi-calc + rofi-emoji-wayland + ]; + }; + + stylix.targets.rofi.enable = true; + home.file.".config/rofi/config.rasi".text = util.build.theme { + inherit (config.lib.stylix) colors; + file = files.niri.rofi; + }; + }; + }; +} diff --git a/modules/gui/desktop/niri/apps/panel.nix b/modules/gui/desktop/niri/apps/panel.nix @@ -0,0 +1,374 @@ +{ + config, + pkgs, + files, + ... +}: +let + inherit (config.gui) display; +in +{ + ## Panel Configuration + user.homeConfig.programs.waybar = { + style = files.niri.waybar; + + # Panel + settings = + let + shared = { + layer = "top"; + position = "left"; + + width = 30; + spacing = 3; + margin-top = 5; + margin-right = 0; + margin-bottom = 5; + margin-left = 3; + + "custom/logo" = { + format = "󱄅"; + tooltip = false; + on-click = "nwg-drawer"; + }; + + "group/users" = { + orientation = "vertical"; + modules = [ + "user" + "custom/power" + ]; + drawer.transition-left-to-right = false; + }; + + user = { + format = "{user}"; + icon = false; + open-on-click = true; + }; + + "custom/power" = { + format = "⏻"; + tooltip = false; + on-click = "wlogout -p layer-shell"; + }; + + "niri/workspaces" = { + all-outputs = false; + format = "<small>{value}</small>"; + }; + + "niri/window" = { + format = ""; + icon = true; + icon-size = 24; + separate-outputs = true; + }; + + "group/menu" = { + orientation = "vertical"; + modules = [ + "custom/hide" + "tray" + "keyboard-state" + ]; + drawer = { + click-to-reveal = true; + transition-left-to-right = false; + }; + }; + + "custom/hide" = { + format = ""; + tooltip = false; + }; + + tray.icon-size = 14; + keyboard-state = { + numlock = true; + capslock = true; + format = { + numlock = " N\n{icon}"; + capslock = "󰪛\n{icon}"; + }; + format-icons = { + locked = ""; + unlocked = ""; + }; + }; + + bluetooth = { + format = ""; + format-disabled = "󰂳"; + format-connected = "󰂱 {num_connections}"; + tooltip-format = " {status}"; + tooltip-format-connected = "{device_enumerate}"; + tooltip-format-enumerate-connected = " {device_alias} 󰂄 {device_battery_percentage}%"; + on-click = "overskride"; + }; + + network = + let + tooltip = "Strength: <b>{signaldBm}dBm ({signalStrength}%)</b>\nFrequency: <b>{frequency}MHz</b>\nInterface: <b>{ifname}</b>\nIP: <b>{ipaddr}/{cidr}</b>\nGateway: <b>{gwaddr}</b>\nNetmask: <b>{netmask}</b>"; + in + { + format = "{ifname}"; + format-disconnected = "󰌙"; + format-wifi = "{icon}"; + format-ethernet = "󰌘"; + format-icons = [ + "󰤯" + "󰤟" + "󰤢" + "󰤥" + "󰤨" + ]; + format-linked = "󰈁 {ifname}"; + tooltip-format-wifi = "Network: <big><b>{essid}</b></big>\n${tooltip}"; + tooltip-format-ethernet = "Network: <big><b>Wired</b></big>\n${tooltip}"; + tooltip-format-disconnected = "󰌙 Disconnected"; + on-click = "sh -c 'env XDG_CURRENT_DESKTOP=GNOME gnome-control-center wifi'"; + }; + + "group/media" = { + orientation = "vertical"; + modules = [ + "wireplumber" + "mpris" + ]; + drawer = { + transition-left-to-right = true; + transition-duration = 1000; + }; + }; + + wireplumber = { + max-volume = 150; + scroll-step = 1; + reverse-scrolling = 1; + format = "{icon}"; + tooltip-format = "Volume: {volume}%\nDevice: {node_name}"; + format-icons = [ + "󰕿" + "󰖀" + "󰕾" + ]; + format-muted = ""; + on-click = "pavucontrol"; + }; + + mpris = { + dynamic-len = 20; + dynamic-order = [ + "title" + "artist" + "length" + ]; + dynamic-separator = " - "; + format = ""; + format-paused = "󰏤"; + format-stopped = ""; + tooltip-format-stopped = "Not Playing"; + on-click = "sysutils media toggle"; + on-click-right = "sysutils media next"; + on-click-middle = "sysutils media previous"; + }; + + backlight = { + format = "{icon}"; + tooltip-format = "Backlight: {percent}%"; + format-icons = [ + "" + "" + "" + "" + "" + "" + "" + "" + "" + ]; + on-scroll-up = "sysutils brightness down"; + on-scroll-down = "sysutils brightness up"; + }; + + "group/power" = { + orientation = "vertical"; + modules = [ + "battery" + "power-profiles-daemon" + ]; + drawer.transition-left-to-right = true; + }; + + battery = { + interval = 5; + format = "{icon}"; + tooltip-format = "Battery: {capacity}%"; + format-charging = ""; + format-icons = [ + "" + "" + "" + "" + "" + ]; + states = { + good = 80; + warning = 20; + critical = 10; + }; + }; + + power-profiles-daemon = { + format = "{icon}"; + tooltip = true; + tooltip-format = "Power Profile: {profile}"; + format-icons = { + default = ""; + performance = "󱄟"; + balanced = ""; + power-saver = ""; + }; + }; + + "custom/weather" = { + format = "{}"; + return-type = "json"; + exec = "wttrbar --date-format %d/%m --nerd --vertical-view"; + tooltip = true; + interval = 600; + signal = 7; + on-click = "pkill -RTMIN+7 waybar"; + }; + + clock = { + interval = 1; + format = "󰅐\n{:%H\n%M\n%S} "; + format-alt = "󰅐\n{:%I\n%M\n\n%d\n%m\n%y} "; + tooltip-format = "<tt><small>{calendar}</small></tt>"; + calendar = { + mode = "year"; + mode-mon-col = 3; + weeks-pos = "left"; + on-scroll = 1; + format = with config.lib.stylix.colors; { + months = "<span color='#${base06}'><b>{}</b></span>"; + days = "<span color='#${base05}'><b>{}</b></span>"; + weeks = "<span color='#${base0C}'><b>W{}</b></span>"; + weekdays = "<span color='#${base0A}'><b>{}</b></span>"; + today = "<span color='#${base08}'><b><u>{}</u></b></span>"; + }; + }; + + actions = { + on-click-right = "mode"; + on-click-forward = "tz_up"; + on-click-backward = "tz_down"; + on-scroll-up = "shift_down"; + on-scroll-down = "shift_up"; + }; + }; + + "group/notify" = { + orientation = "vertical"; + modules = [ + "custom/dunst" + "idle_inhibitor" + ]; + drawer.transition-left-to-right = true; + }; + + "custom/dunst" = + let + run = + text: + "${ + pkgs.writeShellApplication { + name = "notify"; + inherit text; + runtimeInputs = with pkgs; [ + coreutils + dunst + ]; + } + }/bin/notify"; + in + { + tooltip = false; + on-click = "dunstctl history-pop"; + restart-interval = 1; + on-click-right = run '' + if dunstctl is-paused | grep -q "false" + then + dunstctl set-pause-level 50 + else + dunstctl set-pause-level 0 + fi + ''; + exec = run '' + COUNT=$(dunstctl count waiting) + ENABLED="" + DISABLED="" + if [ "$COUNT" != 0 ]; then DISABLED="\n$COUNT"; fi + if dunstctl is-paused | grep -q "false"; then echo "$ENABLED"; else echo "$DISABLED"; fi + ''; + }; + + idle_inhibitor = { + format = "{icon}"; + on-click = "sysutils toggle service swayidle"; + tooltip-format-activated = "Idle Inhibitor: On"; + tooltip-format-deactivated = "Idle Inhibitor: Off"; + format-icons = { + activated = ""; + deactivated = ""; + }; + }; + + modules-right = [ + "group/menu" + "group/users" + "custom/logo" + ]; + + modules-center = [ + "niri/window" + "niri/workspaces" + ]; + }; + in + [ + ( + shared + // { + output = display; + modules-left = [ + "group/notify" + "clock" + "custom/weather" + "group/power" + "backlight" + "group/media" + "network" + "bluetooth" + ]; + } + ) + ( + shared + // { + output = "!" + display; + modules-left = [ + "group/notify" + "clock" + "group/power" + "group/media" + "network" + "bluetooth" + ]; + } + ) + ]; + }; +} diff --git a/modules/gui/desktop/niri/apps/utilities.nix b/modules/gui/desktop/niri/apps/utilities.nix @@ -0,0 +1,24 @@ +{ + config, + util, + files, + ... +}: +{ + user.homeConfig = { + # Wallpaper + stylix.targets.wpaperd.enable = true; + services = { + wpaperd.enable = true; + + # Notifications + dunst.settings.global.origin = "top-left"; + }; + + # Application Drawer + home.file.".config/nwg-drawer/drawer.css".text = util.build.theme { + inherit (config.lib.stylix) colors; + file = files.niri.drawer; + }; + }; +} diff --git a/modules/gui/desktop/niri/default.nix b/modules/gui/desktop/niri/default.nix @@ -0,0 +1,45 @@ +{ + config, + lib, + util, + inputs, + pkgs, + ... +}@args: +let + inherit (lib) mkIf mkMerge; + inherit (util.map.modules) list; + inherit (config.gui) desktop; +in +{ + ## Niri Configuration ## + config = mkIf (desktop == "niri") ( + mkMerge ( + # App Configuration + (builtins.map (path: import path (args // { theme = import ../common/theme.nix pkgs; })) ( + list ../common/apps ++ list ./apps + )) + ++ [ + ## Environment Setup + { + # WM + programs.niri = { + enable = true; + package = pkgs.niri-stable; + }; + } + { + # Settings + user.homeConfig = { + imports = [ + inputs.niri.homeModules.config + ./settings + ]; + + programs.niri = { inherit (config.programs.niri) package; }; + }; + } + ] + ) + ); +} diff --git a/modules/gui/desktop/niri/settings/apps.nix b/modules/gui/desktop/niri/settings/apps.nix @@ -0,0 +1,74 @@ +{ config, ... }: +{ + programs.niri.settings = { + ## Autostart + spawn-at-startup = + let + sh = command: [ + "sh" + "-c" + command + ]; + in + [ + { + command = [ + "pcmanfm-qt" + "--desktop" + ]; + } + { command = sh "nwg-drawer -r"; } + ]; + + ## Keybindings + binds = + with config.lib.niri.actions; + let + sh = spawn "sh" "-c"; + toggle = app: args: sh "pkill ${app} || ${app} ${args}"; + runOnce = app: args: sh "pgrep ${app} || ${app} ${args}"; + in + { + # Applications + "Super+space".action = toggle "rofi" "-show"; + "Super+A".action = spawn "nwg-drawer"; + "Super+F".action = spawn "nemo"; + "Super+T".action = spawn "kitty"; + "Super+W".action = spawn "firefox"; + "Super+Return".action = runOnce "resources" ""; + "XF86Calculator".action = spawn "qalculate-gtk"; + + # Utilities + "Super+N".action = spawn "dunstctl" "history-pop"; + "Super+V".action = spawn "kitty" "--class=clipboard" "-e" "clipse"; + "Super+Shift+C".action = runOnce "hyprpicker" "-arf hex"; + "Super+Shift+B".action = runOnce "overskride" ""; + "Super+Shift+N".action = sh "env XDG_CURRENT_DESKTOP=GNOME gnome-control-center wifi"; + "Super+Shift+P".action = spawn "pavucontrol"; + "Super+Escape".action = toggle "wlogout" "-p layer-shell"; + }; + + ## Window Rules + window-rules = [ + { + matches = [ + { app-id = "clipboard"; } + { app-id = "qalculate-gtk"; } + ]; + open-floating = true; + default-floating-position = { + relative-to = "right"; + x = 5; + y = 0; + }; + } + { + matches = [ + { app-id = "com.saivert.pwvucontrol"; } + { app-id = "com.github.wwmm.easyeffects"; } + ]; + open-floating = true; + } + ]; + }; +} diff --git a/modules/gui/desktop/niri/settings/default.nix b/modules/gui/desktop/niri/settings/default.nix @@ -0,0 +1,38 @@ +{ util, ... }: +{ + imports = util.map.modules.list ./.; + programs.niri.settings = { + hotkey-overlay.skip-at-startup = true; + screenshot-path = "~/Pictures/Screenshots/%Y-%m-%d-%H%M%S.png"; + + input = { + keyboard.numlock = true; + warp-mouse-to-focus.enable = true; + workspace-auto-back-and-forth = true; + focus-follows-mouse = { + enable = true; + max-scroll-amount = "25%"; + }; + }; + + layout = { + tab-indicator = { + enable = true; + place-within-column = true; + }; + + default-column-width.proportion = 0.5; + preset-column-widths = [ + { proportion = 1.0 / 3.0; } + { proportion = 0.5; } + { proportion = 2.0 / 3.0; } + ]; + preset-window-heights = [ + { proportion = 1.0 / 3.0; } + { proportion = 0.5; } + { proportion = 2.0 / 3.0; } + { proportion = 1.0; } + ]; + }; + }; +} diff --git a/modules/gui/desktop/niri/settings/keybinds.nix b/modules/gui/desktop/niri/settings/keybinds.nix @@ -0,0 +1,65 @@ +{ config, ... }: +{ + programs.niri.settings = { + input.power-key-handling.enable = false; + binds = + with config.lib.niri.actions; + let + sh = spawn "sh" "-c"; + in + { + # Compositor + "Super+slash".action = show-hotkey-overlay; + "Super+Q".action = close-window; + "Super+C".action = center-window; + "Super+Shift+E".action = fullscreen-window; + "Super+equal".action = switch-preset-column-width; + "Super+minus".action = switch-preset-window-height; + "Super+Shift+equal".action = maximize-column; + "Super+Shift+minus".action = set-column-width "+10%"; + "Super+semicolon".action = toggle-window-floating; + "Super+apostrophe".action = switch-focus-between-floating-and-tiling; + "Super+Shift+Tab".action = toggle-column-tabbed-display; + + "Super+Tab".action = toggle-overview; + "Super+Right".action = focus-column-or-monitor-right; + "Super+Left".action = focus-column-or-monitor-left; + "Super+Up".action = focus-window-or-workspace-up; + "Super+Down".action = focus-window-or-workspace-down; + + "Super+Shift+Right".action = consume-or-expel-window-right; + "Super+Shift+Left".action = consume-or-expel-window-left; + "Super+Shift+Up".action = move-window-up-or-to-workspace-up; + "Super+Shift+Down".action = move-window-down-or-to-workspace-down; + "Super+Shift+Return".action = move-window-to-monitor-next; + + "Super+1".action = focus-workspace 1; + "Super+2".action = focus-workspace 2; + "Super+3".action = focus-workspace 3; + "Super+4".action = focus-workspace 4; + "Super+5".action = focus-workspace 5; + "Super+6".action = focus-workspace 6; + "Super+7".action = focus-workspace 7; + "Super+8".action = focus-workspace 8; + "Super+9".action = focus-workspace 9; + "Super+0".action = focus-workspace 10; + + "Print".action = screenshot; + "Shift+Print".action.screenshot-screen = [ ]; # https://github.com/sodiboo/niri-flake/issues/922 + "Ctrl+Print".action = screenshot-window; + + # Controls + "Super+L".action = sh "loginctl lock-session"; + "XF86AudioPlay".action = sh "sysutils media toggle"; + "XF86AudioPrev".action = sh "sysutils media previous"; + "XF86AudioNext".action = sh "sysutils media next"; + "XF86AudioMute".action = sh "sysutils volume mute"; + "XF86AudioRaiseVolume".action = sh "sysutils volume up"; + "XF86AudioLowerVolume".action = sh "sysutils volume down"; + "XF86MonBrightnessUp".action = sh "sysutils brightness up"; + "XF86MonBrightnessDown".action = sh "sysutils brightness down"; + "XF86KbdBrightnessUp".action = sh "sysutils backlight up"; + "XF86KbdBrightnessDown".action = sh "sysutils backlight down"; + }; + }; +} diff --git a/modules/gui/desktop/niri/settings/style.nix b/modules/gui/desktop/niri/settings/style.nix @@ -0,0 +1,65 @@ +{ sys, ... }: +with sys.lib.stylix.colors; +{ + programs.niri.settings = { + prefer-no-csd = true; + cursor = with sys.stylix.cursor; { + inherit size; + theme = name; + }; + + overview.backdrop-color = "#" + base00; + layout = { + gaps = 7; + background-color = "#" + base00; + insert-hint.display.color = "#" + base05; + + shadow = { + enable = true; + spread = 4; + softness = 8; + offset = { + x = 0; + y = 0; + }; + }; + + focus-ring = { + width = 2; + active.color = "#" + base0D; + }; + + border = { + width = 2; + active.color = "#" + base0D; + inactive.color = "#" + base03; + }; + + tab-indicator = { + position = "left"; + length.total-proportion = 1.0; + width = 7; + gap = 7; + gaps-between-tabs = 7; + corner-radius = 7; + }; + }; + + window-rules = [ + { + clip-to-geometry = true; + draw-border-with-background = false; + geometry-corner-radius = + let + radius = 7.0; + in + { + bottom-left = radius; + bottom-right = radius; + top-left = radius; + top-right = radius; + }; + } + ]; + }; +} diff --git a/modules/hardware/gpu.nix b/modules/hardware/gpu.nix @@ -1,6 +1,7 @@ { config, lib, + pkgs, ... }: let @@ -24,9 +25,12 @@ in config = mkMerge [ (mkIf (cfg.gpu == "nvidia") { services.xserver.videoDrivers = mkForce [ "nvidia" ]; - environment.variables = { - "__GLX_VENDOR_LIBRARY_NAME" = "nvidia"; - "LIBVA_DRIVER_NAME" = "nvidia"; + environment = { + systemPackages = [ pkgs.btop-cuda ]; + variables = { + "__GLX_VENDOR_LIBRARY_NAME" = "nvidia"; + "LIBVA_DRIVER_NAME" = "nvidia"; + }; }; boot = { diff --git a/packages/flake.nix b/packages/flake.nix @@ -49,6 +49,7 @@ in // hyprspace.packages."${system}"; }) minecraft.overlay + niri.overlays.niri ]; }; } diff --git a/scripts/hyprutils.nix b/scripts/hyprutils.nix @@ -13,17 +13,12 @@ let # Usage # help - Show this information - brightness [up,down] - Screen Brightness Controls temperature [up,down] - Display Temperature Controls - backlight [up,down] - Keyboard Backlight Controls - volume [up,down,mute] - Volume Controls - media [next,previous,toggle] - Media Controls toggle  fancy - Toggle Compositor Effects float - Toggle window floating in current workspace minimized - Show minimized windows monitor 'name' - Toggle specified Monitor - service ['name'] - Toggle SystemD Service shader - Toggle Compositor Shader touchpad - Toggle touchpad ''; @@ -64,7 +59,6 @@ recursiveUpdate coreutils gnugrep socat - wget dunst zenity @@ -73,19 +67,12 @@ recursiveUpdate hyprsunset custom.hyprshellevents - alsa-utils - brightnessctl - brillo libnotify - playerctl - systemd ]; text = '' set +eu ${files.scripts.commands} - show_album_art=true - show_music_in_volume_indicator=true notify() { notify-send -a "utility" -t 1000 -h string:x-dunst-stack-tag:"$1" "''${@:2}" @@ -99,24 +86,6 @@ recursiveUpdate error "$1" "Try 'hyprutils help' for more information" } - get_media_icon() { - media_icon="audio-speakers" - if $show_album_art - then - temp media-icon 1 - url=$(playerctl -f "{{mpris:artUrl}}" metadata) - if [[ "$url" == "file://"* ]] - then - media_icon="''${url/file:\/\//}" - elif [[ "$url" == "http://"* ]] || [[ "$url" == "https://"* ]] - then - filename="$(echo "$url" | sed "s/.*\///")" - if [ ! -f "$TEMP/$filename" ]; then wget -O "$TEMP/$filename" "$url"; fi - media_icon="$TEMP/$filename" - fi - fi - } - case "$1" in "") error "Expected an Option" "${help}";; "help") echo -e "## Hyprland Utility Script ##\n${help}";; @@ -124,45 +93,6 @@ recursiveUpdate info "Monitoring Hyprland Socket..." socat -u UNIX-CONNECT:"$XDG_RUNTIME_DIR"/hypr/"$HYPRLAND_INSTANCE_SIGNATURE"/.socket2.sock EXEC:"shellevents ${daemon}",nofork ;; - "brightness") - brightness_notification() { - brightness=$(brillo | grep -Po '[0-9]{1,3}' | head -n 1) - notify brightness -i "display" -h int:value:"$brightness" "🔅 $brightness%" - } - case "$2" in - "up") - brillo -u 300000 -A 5 - brightness_notification - ;; - "down") - brillo -u 300000 -U 5 - brightness_notification - ;; - "") fail "Expected an Option" ;; - *) fail "Unexpected Option 'brightness $2'" ;; - esac - ;; - "backlight") - backlight_notification() { - backlight="$(cat /sys/class/leds/*::kbd_backlight/brightness)" - light=0; if [ "$backlight" -eq 1 ]; then light=33; fi - if [ "$backlight" -eq 2 ]; then light=67; fi - if [ "$backlight" -eq 3 ]; then light=100; fi - notify backlight -i "keyboard" -h int:value:"$light" "🔅 $light%" - } - case "$2" in - "up") - brightnessctl -d "*::kbd_backlight" set 33%+ - backlight_notification - ;; - "down") - brightnessctl -d "*::kbd_backlight" set 33%- - backlight_notification - ;; - "") fail "Expected an Option" ;; - *) fail "Unexpected Option 'brightness $2'" ;; - esac - ;; "temperature") temperature_notification() { temperature=$(hyprctl hyprsunset temperature) @@ -186,89 +116,6 @@ recursiveUpdate *) fail "Unexpected Option 'temperature $2'" ;; esac ;; - "volume") - volume_notification() { - volume=$(amixer get Master | grep '%' | head -n 1 | cut -d '[' -f 2 | cut -d '%' -f 1) - mute=$(amixer get Master | grep '%' | grep -oE '[^ ]+$' | grep off | head -n1) - if [ "$volume" -eq 0 ] || [ "$mute" == "[off]" ] - then - volume_icon="🔇" - elif [ "$volume" -lt 50 ] - then - volume_icon="🔉" - else - volume_icon="🔊" - fi - - song_title=$(playerctl -f "{{title}}" metadata) - get_media_icon - if $show_music_in_volume_indicator && [ -n "$song_title" ] - then - song_artist=$(playerctl -f "{{artist}}" metadata) - if [ -z "$song_artist" ] - then - notify volume -h int:value:"$volume" -i "$media_icon" "$volume_icon $volume%" "$song_title" - else - notify volume -h int:value:"$volume" -i "$media_icon" "$volume_icon $volume%" "$song_title\nBy $song_artist" - fi - else - notify volume -h int:value:"$volume" -i "$media_icon" "$volume_icon $volume%" - fi - } - case "$2" in - "up") - amixer set Master on - amixer sset Master 5%+ - volume_notification - ;; - "down") - amixer set Master on - amixer sset Master 5%- - volume_notification - ;; - "mute") - amixer set Master 1+ toggle - volume_notification - ;; - "") fail "Expected an Option" ;; - *) fail "Unexpected Option 'volume $2'" ;; - esac - ;; - "media") - music_notification() { - song_title=$(playerctl -f "{{title}}" metadata) - song_artist=$(playerctl -f "{{artist}}" metadata) - song_album=$(playerctl -f "{{album}}" metadata) - get_media_icon - if [ -z "$song_album" ] - then - if [ -z "$song_artist" ] - then - notify music -i "$media_icon" "$song_title" - else - notify music -i "$media_icon" "$song_title" "By $song_artist" - fi - else - notify music -i "$media_icon" "$song_title" "By $song_artist from $song_album" - fi - } - case "$2" in - "next") - playerctl next - sleep 0.5 && music_notification - ;; - "previous") - playerctl previous - sleep 0.5 && music_notification - ;; - "toggle") - playerctl play-pause - music_notification - ;; - "") fail "Expected an Option" ;; - *) fail "Unexpected Option 'media $2'" ;; - esac - ;; "toggle") case "$2" in "fancy") @@ -316,21 +163,6 @@ recursiveUpdate fi hyprctl reload ;; - "service") - if [ -z "$3" ] - then - fail "Expected service name" - fi - - if systemctl --user is-active "$3" - then - systemctl --user stop "$3" - notify service -i "system-config-services" "Stopped $3" - else - systemctl --user start "$3" - notify service -i "system-config-services" "Started $3" - fi - ;; "shader") hyprshade off mapfile SHADERS < <(hyprshade ls) diff --git a/scripts/sysutils.nix b/scripts/sysutils.nix @@ -0,0 +1,233 @@ +{ + lib, + pkgs, + files, + ... +}: +let + inherit (lib) licenses recursiveUpdate; + + help = '' + # Legend # + xxx - Command [action] - Description + + # Usage # + help - Show this information + brightness [up,down] - Screen Brightness Controls + backlight [up,down] - Keyboard Backlight Controls + volume [up,down,mute] - Volume Controls + media [next,previous,toggle] - Media Controls + toggle  + service ['name'] - Toggle SystemD Service + ''; +in +recursiveUpdate + { + meta = { + mainProgram = "sysutils"; + description = "System Utility Script"; + homepage = files.path.repo; + license = licenses.gpl3Only; + maintainers = [ "maydayv7" ]; + }; + } + ( + pkgs.writeShellApplication { + name = "sysutils"; + runtimeInputs = with pkgs; [ + coreutils + gnugrep + wget + + alsa-utils + brightnessctl + brillo + dunst + libnotify + playerctl + systemd + ]; + + text = '' + set +eu + ${files.scripts.commands} + show_album_art=true + show_music_in_volume_indicator=true + + notify() { + notify-send -a "utility" -t 1000 -h string:x-dunst-stack-tag:"$1" "''${@:2}" + } + + fail() { + error "$1" "Try 'sysutils help' for more information" + } + + get_media_icon() { + media_icon="audio-speakers" + if $show_album_art + then + temp media-icon 1 + url=$(playerctl -f "{{mpris:artUrl}}" metadata) + if [[ "$url" == "file://"* ]] + then + media_icon="''${url/file:\/\//}" + elif [[ "$url" == "http://"* ]] || [[ "$url" == "https://"* ]] + then + filename="$(echo "$url" | sed "s/.*\///")" + if [ ! -f "$TEMP/$filename" ]; then wget -O "$TEMP/$filename" "$url"; fi + media_icon="$TEMP/$filename" + fi + fi + } + + case "$1" in + "") error "Expected an Option" "${help}";; + "help") echo -e "## System Utility Script ##\n${help}";; + "brightness") + brightness_notification() { + brightness=$(brillo | grep -Po '[0-9]{1,3}' | head -n 1) + notify brightness -i "display" -h int:value:"$brightness" "🔅 $brightness%" + } + case "$2" in + "up") + brillo -u 300000 -A 5 + brightness_notification + ;; + "down") + brillo -u 300000 -U 5 + brightness_notification + ;; + "") fail "Expected an Option" ;; + *) fail "Unexpected Option 'brightness $2'" ;; + esac + ;; + "backlight") + backlight_notification() { + backlight="$(cat /sys/class/leds/*::kbd_backlight/brightness)" + light=0; if [ "$backlight" -eq 1 ]; then light=33; fi + if [ "$backlight" -eq 2 ]; then light=67; fi + if [ "$backlight" -eq 3 ]; then light=100; fi + notify backlight -i "keyboard" -h int:value:"$light" "🔅 $light%" + } + case "$2" in + "up") + brightnessctl -d "*::kbd_backlight" set 33%+ + backlight_notification + ;; + "down") + brightnessctl -d "*::kbd_backlight" set 33%- + backlight_notification + ;; + "") fail "Expected an Option" ;; + *) fail "Unexpected Option 'brightness $2'" ;; + esac + ;; + "volume") + volume_notification() { + volume=$(amixer get Master | grep '%' | head -n 1 | cut -d '[' -f 2 | cut -d '%' -f 1) + mute=$(amixer get Master | grep '%' | grep -oE '[^ ]+$' | grep off | head -n1) + if [ "$volume" -eq 0 ] || [ "$mute" == "[off]" ] + then + volume_icon="🔇" + elif [ "$volume" -lt 50 ] + then + volume_icon="🔉" + else + volume_icon="🔊" + fi + + song_title=$(playerctl -f "{{title}}" metadata) + get_media_icon + if $show_music_in_volume_indicator && [ -n "$song_title" ] + then + song_artist=$(playerctl -f "{{artist}}" metadata) + if [ -z "$song_artist" ] + then + notify volume -h int:value:"$volume" -i "$media_icon" "$volume_icon $volume%" "$song_title" + else + notify volume -h int:value:"$volume" -i "$media_icon" "$volume_icon $volume%" "$song_title\nBy $song_artist" + fi + else + notify volume -h int:value:"$volume" -i "$media_icon" "$volume_icon $volume%" + fi + } + case "$2" in + "up") + amixer set Master on + amixer sset Master 5%+ + volume_notification + ;; + "down") + amixer set Master on + amixer sset Master 5%- + volume_notification + ;; + "mute") + amixer set Master 1+ toggle + volume_notification + ;; + "") fail "Expected an Option" ;; + *) fail "Unexpected Option 'volume $2'" ;; + esac + ;; + "media") + music_notification() { + song_title=$(playerctl -f "{{title}}" metadata) + song_artist=$(playerctl -f "{{artist}}" metadata) + song_album=$(playerctl -f "{{album}}" metadata) + get_media_icon + if [ -z "$song_album" ] + then + if [ -z "$song_artist" ] + then + notify music -i "$media_icon" "$song_title" + else + notify music -i "$media_icon" "$song_title" "By $song_artist" + fi + else + notify music -i "$media_icon" "$song_title" "By $song_artist from $song_album" + fi + } + case "$2" in + "next") + playerctl next + sleep 0.5 && music_notification + ;; + "previous") + playerctl previous + sleep 0.5 && music_notification + ;; + "toggle") + playerctl play-pause + music_notification + ;; + "") fail "Expected an Option" ;; + *) fail "Unexpected Option 'media $2'" ;; + esac + ;; + "toggle") + case "$2" in + "service") + if [ -z "$3" ] + then + fail "Expected service name" + fi + + if systemctl --user is-active "$3" + then + systemctl --user stop "$3" + notify service -i "system-config-services" "Stopped $3" + else + systemctl --user start "$3" + notify service -i "system-config-services" "Started $3" + fi + ;; + "") fail "Expected an Option" ;; + *) fail "Unexpected Option 'toggle $2'" ;; + esac + ;; + *) fail "Unexpected Option '$1'" ;; + esac + ''; + } + )