feat(desktop): Hyprland, Waybar, autostart/bindings/idle

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-28 06:48:07 +02:00
commit 6e87d8e186
5 changed files with 1317 additions and 0 deletions

333
modules/desktop/README.md Normal file
View file

@ -0,0 +1,333 @@
# Desktop Directory - Desktop Environment Configuration
The `modules/desktop/` directory contains the desktop environment configuration for Omnixient, centered around the Hyprland compositor. This directory manages the complete desktop experience including window management, user interface, and desktop interactions.
## Desktop Architecture
The desktop system is built in layers:
```
User Interaction Layer (keybindings, gestures)
Application Layer (autostart, window rules)
Compositor Layer (Hyprland core)
System Integration Layer (services, hardware)
```
## Core Desktop Module
### `hyprland.nix`
**Purpose**: Main Hyprland compositor configuration and coordination
**What it provides**:
- Core Hyprland configuration
- Integration with other desktop components
- Theme-aware window management
- Performance optimizations
**Key Features**:
- Wayland-native compositor
- Dynamic tiling window management
- Smooth animations and effects
- GPU-accelerated rendering
- Extensive customization options
**Module Structure**:
```nix
imports = [
./hyprland/bindings.nix
./hyprland/autostart.nix
./hyprland/idle.nix
];
```
## Hyprland Sub-Modules
### `hyprland/bindings.nix`
**Purpose**: Keyboard shortcuts and input bindings
**What it configures**:
- Window management shortcuts
- Application launching bindings
- Workspace navigation
- System control shortcuts
**Key Binding Categories**:
#### Window Management
- `Super + Q`: Close window
- `Super + F`: Toggle fullscreen
- `Super + Space`: Toggle floating
- `Super + V`: Toggle split direction
- `Super + Arrow Keys`: Move window focus
- `Super + Shift + Arrow Keys`: Move windows
#### Application Launching
- `Super + Return`: Terminal (Alacritty)
- `Super + B`: Web browser
- `Super + E`: File manager
- `Super + D`: Application launcher
- `Super + R`: Run dialog
#### Workspace Management
- `Super + 1-9`: Switch to workspace
- `Super + Shift + 1-9`: Move window to workspace
- `Super + Mouse Wheel`: Cycle through workspaces
- `Super + Tab`: Application switcher
#### System Controls
- `Super + L`: Lock screen
- `Super + Shift + E`: Logout menu
- `Volume Keys`: Audio control
- `Brightness Keys`: Display brightness
- `Print`: Screenshot region
- `Shift + Print`: Screenshot full screen
#### Advanced Bindings
- `Super + Alt + Arrow Keys`: Resize windows
- `Super + Mouse`: Move/resize windows
- `Super + Shift + S`: Screenshot with selection
- `Super + P`: Power menu
### `hyprland/autostart.nix`
**Purpose**: Applications and services started with the desktop session
**What it manages**:
- Essential desktop services
- User applications
- Background processes
- System tray applications
**Autostart Categories**:
#### Essential Services
- **Waybar**: Desktop panel/taskbar
- **Mako**: Notification daemon
- **Authentication Agent**: Polkit authentication
- **Network Manager Applet**: Network connectivity
#### Background Services
- **Clipboard Manager**: Clipboard history
- **Wallpaper Setter**: Dynamic wallpapers
- **Idle Manager**: Screen timeout and locking
- **Audio Control**: Volume control daemon
#### User Applications (Optional)
- **File Manager**: Background file operations
- **Chat Applications**: Discord, Slack, etc.
- **Productivity Tools**: Note-taking, calendar
- **Development Tools**: IDEs, terminals
**Configuration Example**:
```nix
wayland.windowManager.hyprland.settings = {
exec-once = [
"waybar"
"mako"
"nm-applet --indicator"
"/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1"
];
};
```
### `hyprland/idle.nix`
**Purpose**: Idle management and screen locking
**What it configures**:
- Screen timeout settings
- Automatic screen locking
- Display power management
- Suspend/hibernate behavior
**Idle Management Features**:
#### Screen Locking
- Automatic lock after inactivity
- Manual lock with keybinding
- Grace period for quick unlock
- Secure lock screen (swaylock)
#### Display Management
- Screen dimming before lock
- Display turn-off timing
- Multiple monitor handling
- Brightness restoration
#### Power Management
- Suspend after extended idle
- Hibernate for long inactivity
- Wake-on-input configuration
- Battery-aware timeouts
**Configuration Options**:
```nix
services.hypridle = {
enable = true;
settings = {
general = {
after_sleep_cmd = "hyprctl dispatch dpms on";
before_sleep_cmd = "loginctl lock-session";
ignore_dbus_inhibit = false;
lock_cmd = "pidof hyprlock || hyprlock";
};
listener = [
{
timeout = 300; # 5 minutes
on-timeout = "brightnessctl -s set 10";
on-resume = "brightnessctl -r";
}
{
timeout = 600; # 10 minutes
on-timeout = "loginctl lock-session";
}
];
};
};
```
## Window Management Features
### Tiling Behavior
- **Dynamic Tiling**: Automatic window arrangement
- **Manual Tiling**: User-controlled window placement
- **Floating Windows**: Support for floating applications
- **Split Layouts**: Horizontal and vertical splits
### Window Rules
- **Application-Specific Rules**: Size, position, workspace assignment
- **Floating Applications**: Always-float for certain apps
- **Workspace Assignment**: Auto-assign apps to specific workspaces
- **Focus Behavior**: Control focus stealing and new window focus
### Animation System
- **Window Animations**: Smooth open/close transitions
- **Workspace Transitions**: Fluid workspace switching
- **Resize Animations**: Smooth window resizing
- **Fade Effects**: Window fade in/out
## Desktop Integration
### Theme Integration
Desktop components automatically adapt to the selected theme:
- Window border colors
- Panel/taskbar theming
- Icon themes
- Cursor themes
### Hardware Integration
- **GPU Acceleration**: Optimal performance on all graphics hardware
- **Multi-Monitor**: Automatic detection and configuration
- **HiDPI Support**: Proper scaling for high-resolution displays
- **Input Devices**: Touchpad gestures, mouse sensitivity
### Audio Integration
- **Media Keys**: Hardware media key support
- **Volume Control**: On-screen volume indicators
- **Audio Device Switching**: Quick audio output switching
- **Notification Sounds**: System sound integration
## Performance Optimization
### GPU Optimization
- **Hardware Acceleration**: GPU-accelerated compositing
- **VSync Configuration**: Tear-free rendering
- **Frame Rate Management**: Adaptive refresh rates
- **Multi-GPU Support**: Optimal GPU selection
### Memory Management
- **Efficient Compositing**: Minimal memory usage
- **Background Process Limits**: Control background applications
- **Cache Management**: Optimal caching strategies
- **Resource Monitoring**: System resource awareness
### Battery Optimization (Laptops)
- **Power-Aware Rendering**: Reduced effects on battery
- **CPU Scaling**: Dynamic performance scaling
- **Display Brightness**: Automatic brightness adjustment
- **Background Process Management**: Suspend non-essential processes
## Customization Options
### Layout Customization
```nix
wayland.windowManager.hyprland.settings = {
general = {
gaps_in = 5;
gaps_out = 10;
border_size = 2;
layout = "dwindle"; # or "master"
};
decoration = {
rounding = 10;
blur = {
enabled = true;
size = 8;
passes = 1;
};
drop_shadow = true;
shadow_range = 4;
shadow_render_power = 3;
};
};
```
### Animation Customization
```nix
animation = {
enabled = true;
bezier = [
"wind, 0.05, 0.9, 0.1, 1.05"
"winIn, 0.1, 1.1, 0.1, 1.1"
"winOut, 0.3, -0.3, 0, 1"
];
animation = [
"windows, 1, 6, wind, slide"
"windowsIn, 1, 6, winIn, slide"
"windowsOut, 1, 5, winOut, slide"
"fade, 1, 10, default"
"workspaces, 1, 5, wind"
];
};
```
## Desktop Components Integration
### Panel (Waybar)
- System status display
- Workspace indicators
- System tray integration
- Custom module support
### Application Launcher
- Quick application access
- Search functionality
- Recent application history
- Customizable appearance
### File Manager Integration
- Desktop file operations
- Trash management
- Network location access
- Archive handling
### Notification System
- Desktop notifications
- Notification history
- Do-not-disturb modes
- Custom notification rules
## Troubleshooting
### Common Issues
- **Performance Problems**: Check GPU acceleration
- **Input Issues**: Verify input device configuration
- **Display Problems**: Check monitor configuration
- **Audio Issues**: Verify PipeWire integration
### Debugging Tools
- `hyprctl`: Hyprland control utility
- `waybar-log`: Panel debugging
- `journalctl`: System logs
- `htop`: Resource monitoring
This desktop configuration provides a modern, efficient, and highly customizable desktop environment that adapts to user preferences while maintaining excellent performance across various hardware configurations.

View file

@ -0,0 +1,575 @@
{
config,
pkgs,
lib,
inputs,
...
}:
let
inherit (lib)
mkEnableOption
mkOption
mkIf
mkMerge
types
optionals
optionalString
;
cfg = config.omni.desktop;
omni = config.omni.lib;
user = config.omni.user;
in
{
imports = [
./hyprland/autostart.nix
./hyprland/bindings.nix
./hyprland/idle.nix
];
options.omni.desktop = {
enable = mkEnableOption "Omnixient Hyprland desktop environment";
monitors = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "DP-1,1920x1080@144,0x0,1" ];
description = "Monitor configuration for Hyprland";
};
defaultTerminal = mkOption {
type = types.str;
default = "ghostty";
description = "Default terminal emulator";
};
defaultBrowser = mkOption {
type = types.str;
default = "chromium";
description = "Default web browser";
};
wallpaper = mkOption {
type = types.nullOr types.path;
default = null;
description = "Path to wallpaper image (optional)";
};
idleSuspend = mkOption {
type = types.bool;
default = false;
description = "Enable system suspend after idle timeout";
};
};
config = mkIf (cfg.enable) {
# Enable Hyprland at the system level.
#
# `programs.hyprland.portalPackage` is set to the xdg-desktop-portal-hyprland
# built by the same Hyprland flake input that provides `package`, so
# the auto-added portal (from the upstream programs.hyprland module)
# matches the hyprland binary's source. Mixing sources causes two
# copies of the same package in the closure and a systemd user-unit
# symlink collision when both try to install
# xdg-desktop-portal-hyprland.service.
programs.hyprland = {
enable = true;
xwayland.enable = true;
package = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.hyprland;
portalPackage = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.xdg-desktop-portal-hyprland;
};
# XDG portal for Wayland. We DON'T add xdg-desktop-portal-hyprland
# here — `programs.hyprland.enable = true` already adds it via the
# upstream module's `xdg.portal.extraPortals = [ cfg.portalPackage ]`.
# Adding it again would create a duplicate.
xdg.portal = {
enable = true;
extraPortals = [
pkgs.xdg-desktop-portal-gtk
];
config.common.default = "*";
};
# Session variables
environment.sessionVariables = {
NIXOS_OZONE_WL = "1";
MOZ_ENABLE_WAYLAND = "1";
QT_QPA_PLATFORM = "wayland";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
GDK_BACKEND = "wayland";
WLR_NO_HARDWARE_CURSORS = "1";
TERMINAL = cfg.defaultTerminal;
BROWSER = cfg.defaultBrowser;
EDITOR = "nvim";
};
# Essential packages for Hyprland desktop
environment.systemPackages = with pkgs; [
wayland
wayland-protocols
wayland-utils
wlroots
hyprland-protocols
hyprpaper
hyprlock
hypridle
hyprpicker
waybar
wofi
rofi
walker
mako
libnotify
wl-clipboard
cliphist
wlr-randr
kanshi
grim
slurp
satty
wf-recorder
networkmanagerapplet
blueman
pasystray
impala
pamixer
pulsemixer
pavucontrol
wiremix
awww
nautilus
pkgs.thunar
ranger
yazi
polkit_gnome
adwaita-icon-theme
papirus-icon-theme
bibata-cursors
brightnessctl
playerctl
];
# --- Home-manager Hyprland config (structured, mergeable by themes) ---
home-manager.users.${user} = {
wayland.windowManager.hyprland = {
enable = true;
package = config.programs.hyprland.package;
# Keep the legacy hyprlang config format (home.stateVersion < 26.05).
# Switching to "lua" is a separate, deliberate migration.
configType = "hyprlang";
systemd.enable = true;
settings = {
# Monitor config — user monitors + fallback
monitor = cfg.monitors ++ [ ",preferred,auto,1" ];
input = {
kb_layout = "us";
kb_options = "caps:escape";
follow_mouse = 1;
mouse_refocus = false;
sensitivity = 0;
touchpad = {
natural_scroll = true;
disable_while_typing = true;
tap-to-click = true;
scroll_factor = 0.5;
};
};
general = {
gaps_in = 5;
gaps_out = 10;
border_size = 2;
layout = "dwindle";
allow_tearing = false;
};
decoration = {
rounding = 10;
blur = {
enabled = true;
size = 6;
passes = 2;
new_optimizations = true;
ignore_opacity = true;
};
# Hyprland 0.40+ moved shadow options from flat
# `drop_shadow`/`shadow_range`/`shadow_render_power` into a
# nested `shadow { enabled; range; render_power; color }`
# block. Theme modules contribute `shadow.color`.
shadow = {
enabled = true;
range = 20;
render_power = 3;
};
dim_inactive = false;
dim_strength = 0.1;
};
animations = {
enabled = true;
bezier = [
"overshot, 0.05, 0.9, 0.1, 1.05"
"smoothOut, 0.5, 0, 0.99, 0.99"
"smoothIn, 0.5, -0.5, 0.68, 1.5"
];
animation = [
"windows, 1, 5, overshot, slide"
"windowsOut, 1, 4, smoothOut, slide"
"windowsIn, 1, 4, smoothIn, slide"
"windowsMove, 1, 4, default"
"border, 1, 10, default"
"borderangle, 1, 8, default"
"fade, 1, 7, default"
"workspaces, 1, 6, default"
];
};
dwindle = {
preserve_split = true;
force_split = 2;
};
# NOTE: Hyprland 0.49+ removed the entire `gestures` section
# in favor of new `gesture` keyword bindings (similar to
# `bind`). Touchpad workspace-swipe will need to be re-added
# via the new syntax — tracking as a follow-up. The old
# block was:
# gestures = { workspace_swipe = true; ... };
misc = {
force_default_wallpaper = 0;
disable_hyprland_logo = true;
disable_splash_rendering = true;
mouse_move_enables_dpms = true;
key_press_enables_dpms = true;
enable_swallow = true;
swallow_regex = "^(ghostty|alacritty|kitty|footclient)$";
};
windowrule = [
"opacity 0.9 override 0.9 override, match:class (ghostty|Alacritty|kitty)"
"opacity 0.9 override 0.9 override, match:class (Code|code-oss)"
"float on, match:class (pavucontrol|nm-connection-editor|blueman-manager)"
"float on, match:class (org.gnome.Calculator|gnome-calculator)"
"float on, match:title (Picture-in-Picture)"
"pin on, match:title (Picture-in-Picture)"
"float on, match:class (imv|mpv|vlc)"
"center on, match:class (imv|mpv|vlc)"
"float on, match:class (com.gabm.satty)"
"size 800 600, match:class (com.gabm.satty)"
"center on, match:class (com.gabm.satty)"
"workspace 4, match:class (Spotify)"
"workspace 5, match:class (org.telegram.desktop)"
];
};
};
# Waybar
programs.waybar = {
enable = true;
systemd.enable = true;
settings = [
{
reload_style_on_change = true;
layer = "top";
position = "top";
spacing = 0;
height = 26;
modules-left = [
"custom/omni"
"hyprland/workspaces"
];
modules-center = [ "clock" ];
modules-right = [
"group/tray-expander"
"custom/screenshot"
"bluetooth"
"network"
"pulseaudio"
"cpu"
"backlight"
"battery"
"custom/power"
];
"custom/omni" = {
format = "󱄅";
on-click = "walker";
on-click-right = "${cfg.defaultTerminal}";
tooltip-format = "App Launcher";
};
"custom/screenshot" = {
format = "󰹑";
on-click = "bash -c 'f=~/Pictures/Screenshots/screenshot_$(date +%Y-%m-%d-%H%M%S).png; grim -g \"$(slurp)\" \"$f\" && satty --filename \"$f\" --output-filename \"$f\" --copy-command wl-copy'";
on-click-right = "bash -c 'f=~/Pictures/Screenshots/screenshot_$(date +%Y-%m-%d-%H%M%S).png; grim \"$f\" && satty --filename \"$f\" --output-filename \"$f\" --copy-command wl-copy'";
tooltip-format = "Screenshot (right-click: fullscreen)";
};
"hyprland/workspaces" = {
on-click = "activate";
format = "{icon}";
format-icons = {
"1" = "1";
"2" = "2";
"3" = "3";
"4" = "4";
"5" = "5";
"6" = "6";
"7" = "7";
"8" = "8";
"9" = "9";
"10" = "0";
active = "󱓻";
default = "";
};
persistent-workspaces = {
"1" = [ ];
"2" = [ ];
"3" = [ ];
"4" = [ ];
"5" = [ ];
};
};
clock = {
format = "{:L%A %H:%M}";
format-alt = "{:L%d %B W%V %Y}";
tooltip = false;
};
network = {
format-icons = [
"󰤯"
"󰤟"
"󰤢"
"󰤥"
"󰤨"
];
format = "{icon}";
format-wifi = "{icon}";
format-ethernet = "󰀂";
format-disconnected = "󰤮";
tooltip-format-wifi = "{essid} ({frequency} GHz)\n{bandwidthDownBytes} {bandwidthUpBytes}";
tooltip-format-ethernet = "{bandwidthDownBytes} {bandwidthUpBytes}";
tooltip-format-disconnected = "Disconnected";
interval = 3;
on-click = "${cfg.defaultTerminal} -e impala";
};
bluetooth = {
format = "";
format-off = "󰂲";
format-disabled = "󰂲";
format-connected = "󰂱";
format-no-controller = "";
tooltip-format = "Devices connected: {num_connections}";
on-click = "${cfg.defaultTerminal} -e bluetui";
};
pulseaudio = {
format = "{icon}";
format-muted = "󰝟";
format-icons = {
headphone = "󰋋";
headset = "󰋎";
default = [
"󰕿"
"󰖀"
"󰕾"
];
};
tooltip-format = "Playing at {volume}%";
scroll-step = 5;
on-click = "${cfg.defaultTerminal} -e wiremix";
on-click-right = "pamixer -t";
};
cpu = {
interval = 5;
format = "󰍛";
on-click = "${cfg.defaultTerminal} -e btop";
};
backlight = {
format = "{icon}";
format-icons = [
""
""
""
""
""
""
""
""
""
];
tooltip-format = "Brightness: {percent}%";
};
battery = {
format = "{icon}";
format-discharging = "{icon}";
format-charging = "{icon}";
format-plugged = "";
format-full = "󰂅";
format-icons = {
charging = [
"󰢜"
"󰂆"
"󰂇"
"󰂈"
"󰢝"
"󰂉"
"󰢞"
"󰂊"
"󰂋"
"󰂅"
];
default = [
"󰁺"
"󰁻"
"󰁼"
"󰁽"
"󰁾"
"󰁿"
"󰂀"
"󰂁"
"󰂂"
"󰁹"
];
};
tooltip-format-discharging = "{power:>1.0f}W {capacity}%";
tooltip-format-charging = "{power:>1.0f}W {capacity}%";
interval = 5;
states = {
warning = 20;
critical = 10;
};
on-click = "${pkgs.writeShellScript "power-menu" ''
choice=$(printf "Lock\nLogout\nReboot\nShutdown" | ${pkgs.wofi}/bin/wofi --dmenu --prompt "Power" --width 200 --height 200)
case "$choice" in
Lock) hyprlock ;;
Logout) hyprctl dispatch exit ;;
Reboot) systemctl reboot ;;
Shutdown) systemctl poweroff ;;
esac
''}";
};
"group/tray-expander" = {
orientation = "inherit";
drawer = {
transition-duration = 600;
children-class = "tray-group-item";
};
modules = [
"custom/expand-icon"
"tray"
];
};
"custom/expand-icon" = {
format = "";
tooltip = false;
};
tray = {
icon-size = 12;
spacing = 17;
};
"custom/power" = {
format = "";
tooltip-format = "Power menu";
on-click = "${pkgs.writeShellScript "power-menu-btn" ''
choice=$(printf "Lock\nLogout\nReboot\nShutdown" | ${pkgs.wofi}/bin/wofi --dmenu --prompt "Power" --width 200 --height 200)
case "$choice" in
Lock) hyprlock ;;
Logout) hyprctl dispatch exit ;;
Reboot) systemctl reboot ;;
Shutdown) systemctl poweroff ;;
esac
''}";
};
}
];
style = lib.mkDefault ''
* {
font-family: "JetBrainsMono Nerd Font";
font-size: 12px;
border: none;
border-radius: 0;
min-height: 0;
}
window#waybar {
background: rgba(30, 30, 46, 0.9);
color: #cdd6f4;
}
.modules-left {
margin-left: 8px;
}
.modules-right {
margin-right: 8px;
}
#workspaces button {
all: initial;
color: #cdd6f4;
padding: 0 6px;
margin: 0 1.5px;
min-width: 9px;
}
#workspaces button.empty {
opacity: 0.5;
}
#workspaces button.active {
color: #cba6f7;
}
#custom-omni {
margin: 0 12px 0 4px;
font-size: 14px;
color: #cba6f7;
}
#cpu,
#battery,
#pulseaudio,
#backlight {
min-width: 12px;
margin: 0 7.5px;
}
#custom-power {
min-width: 12px;
margin: 0 4px 0 7.5px;
color: #f38ba8;
}
#bluetooth {
margin-right: 17px;
}
#network {
margin-right: 13px;
}
#custom-screenshot {
margin-right: 17px;
}
#custom-expand-icon {
margin-right: 18px;
}
#tray {
margin-right: 16px;
}
#clock {
margin-left: 8.75px;
}
#custom-power:hover {
color: #1e1e2e;
background: #f38ba8;
border-radius: 5px;
}
#battery.charging { color: #a6e3a1; }
#battery.warning:not(.charging) { color: #fab387; }
#battery.critical:not(.charging) {
color: #f38ba8;
animation: blink 0.5s linear infinite alternate;
}
@keyframes blink {
to { background-color: #f38ba8; color: #1e1e2e; }
}
tooltip {
padding: 2px;
}
'';
};
};
};
}

View file

@ -0,0 +1,61 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (lib) mkIf optionals;
cfg = config.omni.desktop;
omni = config.omni.lib;
user = config.omni.user;
in
{
config = mkIf (cfg.enable) {
home-manager.users.${user} = {
wayland.windowManager.hyprland.settings = {
exec-once = [
# NOTE: do NOT add "waybar" here. Waybar is managed by the
# systemd user service from `programs.waybar.systemd.enable
# = true` in modules/desktop/hyprland.nix. Launching it
# from `exec-once` AS WELL produces two stacked bars on
# screen. The keybinding to restart waybar
# (`systemctl --user restart waybar` in bindings.nix) also
# assumes the systemd-managed instance.
"gnome-keyring-daemon --start --components=secrets,pkcs11"
"mako"
"awww init"
"nm-applet --indicator"
"blueman-applet"
"wl-paste --type text --watch cliphist store"
"wl-paste --type image --watch cliphist store"
"${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"
"mkdir -p ~/Pictures/Screenshots"
"hypridle"
"swayosd-server"
"[workspace 1 silent] ${cfg.defaultTerminal} -e tmux"
"[workspace 1 silent] ${cfg.defaultBrowser}"
]
++ optionals (omni.isEnabled "media") [
"[workspace 4 silent] spotify"
]
++ optionals (omni.isEnabled "communication") [
"[workspace 5 silent] signal-desktop --password-store=gnome-libsecret"
"[workspace 5 silent] element-desktop --password-store=gnome-libsecret"
"[workspace 5 silent] ferdium --password-store=gnome-libsecret"
# nixpkgs ships the binary as `Telegram` (capital T), not
# `telegram-desktop`. It's Qt, so it doesn't take the
# --password-store flag the Electron apps below use.
"[workspace 5 silent] Telegram"
];
exec =
[ ]
++ optionals (cfg.wallpaper != null) [
"awww img ${toString cfg.wallpaper} --transition-type wipe"
];
};
};
};
}

View file

@ -0,0 +1,169 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (lib) mkIf optionals;
cfg = config.omni.desktop;
omni = config.omni.lib;
user = config.omni.user;
terminal = cfg.defaultTerminal;
browser = cfg.defaultBrowser;
in
{
config = mkIf (cfg.enable) {
home-manager.users.${user} = {
wayland.windowManager.hyprland.settings = {
"$mainMod" = "SUPER";
bind = [
# Application launches
"$mainMod, Return, exec, ${terminal}"
"$mainMod, B, exec, ${browser}"
"$mainMod, E, exec, thunar"
"$mainMod, R, exec, walker"
"$mainMod, D, exec, walker"
# Window management
"$mainMod, Q, killactive"
"$mainMod, F, fullscreen, 1"
"$mainMod SHIFT, F, fullscreen, 0"
"$mainMod, Space, togglefloating"
"$mainMod, P, pseudo"
"$mainMod, J, layoutmsg, togglesplit"
"$mainMod, G, togglegroup"
"$mainMod, Tab, changegroupactive"
# Focus (vim keys)
"$mainMod, h, movefocus, l"
"$mainMod, l, movefocus, r"
"$mainMod, k, movefocus, u"
"$mainMod, j, movefocus, d"
# Focus (arrow keys)
"$mainMod, left, movefocus, l"
"$mainMod, right, movefocus, r"
"$mainMod, up, movefocus, u"
"$mainMod, down, movefocus, d"
# Move windows (vim keys)
"$mainMod SHIFT, h, movewindow, l"
"$mainMod SHIFT, l, movewindow, r"
"$mainMod SHIFT, k, movewindow, u"
"$mainMod SHIFT, j, movewindow, d"
# Move windows (arrow keys)
"$mainMod SHIFT, left, movewindow, l"
"$mainMod SHIFT, right, movewindow, r"
"$mainMod SHIFT, up, movewindow, u"
"$mainMod SHIFT, down, movewindow, d"
# Workspaces
"$mainMod, 1, workspace, 1"
"$mainMod, 2, workspace, 2"
"$mainMod, 3, workspace, 3"
"$mainMod, 4, workspace, 4"
"$mainMod, 5, workspace, 5"
"$mainMod, 6, workspace, 6"
"$mainMod, 7, workspace, 7"
"$mainMod, 8, workspace, 8"
"$mainMod, 9, workspace, 9"
"$mainMod, 0, workspace, 10"
# Move to workspace
"$mainMod SHIFT, 1, movetoworkspace, 1"
"$mainMod SHIFT, 2, movetoworkspace, 2"
"$mainMod SHIFT, 3, movetoworkspace, 3"
"$mainMod SHIFT, 4, movetoworkspace, 4"
"$mainMod SHIFT, 5, movetoworkspace, 5"
"$mainMod SHIFT, 6, movetoworkspace, 6"
"$mainMod SHIFT, 7, movetoworkspace, 7"
"$mainMod SHIFT, 8, movetoworkspace, 8"
"$mainMod SHIFT, 9, movetoworkspace, 9"
"$mainMod SHIFT, 0, movetoworkspace, 10"
# Scroll workspaces
"$mainMod, mouse_down, workspace, e+1"
"$mainMod, mouse_up, workspace, e-1"
# Screenshots (grim + satty for annotation)
", Print, exec, grim -g \"$(slurp)\" - | satty -f - --output-filename ~/Pictures/Screenshots/$(date +'screenshot_%Y-%m-%d-%H%M%S.png')"
"SHIFT, Print, exec, grim - | satty -f - --output-filename ~/Pictures/Screenshots/$(date +'screenshot_%Y-%m-%d-%H%M%S.png')"
"$mainMod, Print, exec, grim -g \"$(slurp)\" - | wl-copy"
# Screen recording
"$mainMod SHIFT, R, exec, wf-recorder -g \"$(slurp)\" -f ~/Videos/recording_$(date +'%Y-%m-%d-%H%M%S.mp4')"
# Lock screen
"$mainMod, L, exec, hyprlock"
# System / Power
"$mainMod SHIFT, Q, exit,"
"$mainMod SHIFT, P, exec, systemctl poweroff"
"$mainMod SHIFT, B, exec, systemctl reboot"
"$mainMod ALT, R, exec, systemctl --user restart waybar"
# Clipboard
"$mainMod, Y, exec, cliphist list | walker --dmenu | cliphist decode | wl-copy"
"$mainMod, V, exec, cliphist list | wofi --dmenu | cliphist decode | wl-copy"
# Color picker
"$mainMod SHIFT, C, exec, hyprpicker -a"
# Scratchpad
"$mainMod, S, togglespecialworkspace, magic"
"$mainMod SHIFT, S, movetoworkspace, special:magic"
# Theme cycling
"$mainMod ALT, T, exec, omni-theme-bg-next"
"$mainMod ALT SHIFT, T, exec, omni-theme-next"
]
# Coding shortcuts
++ optionals (omni.isEnabled "coding") [
"$mainMod, C, exec, code"
"$mainMod SHIFT, C, exec, ${terminal} -e nvim"
]
# Communication shortcuts
++ optionals (omni.isEnabled "communication") [
"$mainMod CTRL, D, exec, discord"
"$mainMod CTRL SHIFT, D, exec, slack"
];
# Resize with vim/arrow keys
binde = [
"$mainMod CTRL, h, resizeactive, -50 0"
"$mainMod CTRL, l, resizeactive, 50 0"
"$mainMod CTRL, k, resizeactive, 0 -50"
"$mainMod CTRL, j, resizeactive, 0 50"
"$mainMod CTRL, left, resizeactive, -50 0"
"$mainMod CTRL, right, resizeactive, 50 0"
"$mainMod CTRL, up, resizeactive, 0 -50"
"$mainMod CTRL, down, resizeactive, 0 50"
];
# Mouse bindings
bindm = [
"$mainMod, mouse:272, movewindow"
"$mainMod, mouse:273, resizewindow"
];
# Media/brightness keys (locked — work even when input inhibited)
bindl = [
", XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
", XF86MonBrightnessUp, exec, brightnessctl set 10%+"
", XF86MonBrightnessDown, exec, brightnessctl set 10%-"
", XF86AudioPlay, exec, playerctl play-pause"
", XF86AudioNext, exec, playerctl next"
", XF86AudioPrev, exec, playerctl previous"
];
};
};
};
}

View file

@ -0,0 +1,179 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (lib) mkIf optionals;
cfg = config.omni.desktop;
user = config.omni.user;
in
{
config = mkIf (cfg.enable) {
home-manager.users.${user} = {
# Hypridle — screen dimming, locking, DPMS, optional suspend
services.hypridle = {
enable = true;
settings = {
general = {
lock_cmd = "pidof hyprlock || hyprlock";
before_sleep_cmd = "loginctl lock-session";
after_sleep_cmd = "hyprctl dispatch dpms on";
};
listener = [
# Dim screen after 5 minutes
{
timeout = 300;
on-timeout = "brightnessctl -s set 10%";
on-resume = "brightnessctl -r";
}
# Lock screen after 10 minutes
{
timeout = 600;
on-timeout = "loginctl lock-session";
}
# Turn off screen after 15 minutes
{
timeout = 900;
on-timeout = "hyprctl dispatch dpms off";
on-resume = "hyprctl dispatch dpms on";
}
]
++ optionals cfg.idleSuspend [
# Suspend after 30 minutes
{
timeout = 1800;
on-timeout = "systemctl suspend";
}
];
};
};
# Hyprlock — lock screen appearance
programs.hyprlock = {
enable = true;
settings = {
general = {
disable_loading_bar = true;
grace = 5;
hide_cursor = false;
no_fade_in = false;
};
background = [
{
monitor = "";
path = if cfg.wallpaper != null then toString cfg.wallpaper else "~/Pictures/wallpaper.jpg";
blur_passes = 3;
blur_size = 8;
noise = 0.0117;
contrast = 0.8916;
brightness = 0.8172;
vibrancy = 0.1696;
vibrancy_darkness = 0.0;
}
];
image = [
{
monitor = "";
path = "~/.face";
size = 150;
rounding = -1;
border_size = 4;
border_color = "rgb(221, 221, 221)";
position = "0, 200";
halign = "center";
valign = "center";
}
];
label = [
# Time
{
monitor = "";
text = ''cmd[update:30000] echo "$TIME"'';
color = "rgba(200, 200, 200, 1.0)";
font_size = 55;
font_family = "JetBrainsMono Nerd Font";
position = "-100, -40";
halign = "right";
valign = "bottom";
shadow_passes = 5;
shadow_size = 10;
}
# Date
{
monitor = "";
text = ''cmd[update:43200000] echo "$(date +"%A, %d %B %Y")"'';
color = "rgba(200, 200, 200, 1.0)";
font_size = 25;
font_family = "JetBrainsMono Nerd Font";
position = "-100, -150";
halign = "right";
valign = "bottom";
shadow_passes = 5;
shadow_size = 10;
}
# Username
{
monitor = "";
text = user;
color = "rgba(200, 200, 200, 1.0)";
font_size = 20;
font_family = "JetBrainsMono Nerd Font";
position = "0, 80";
halign = "center";
valign = "center";
shadow_passes = 5;
shadow_size = 10;
}
# Hostname
{
monitor = "";
text = ''cmd[update:60000] echo "$(uname -n)"'';
color = "rgba(200, 200, 200, 0.8)";
font_size = 16;
font_family = "JetBrainsMono Nerd Font";
position = "100, 40";
halign = "left";
valign = "bottom";
shadow_passes = 5;
shadow_size = 10;
}
];
input-field = [
{
monitor = "";
size = "200, 50";
outline_thickness = 3;
dots_size = 0.33;
dots_spacing = 0.15;
dots_center = false;
dots_rounding = -1;
outer_color = "rgb(151515)";
inner_color = "rgb(200, 200, 200)";
font_color = "rgb(10, 10, 10)";
fade_on_empty = true;
fade_timeout = 1000;
placeholder_text = "<i>Input Password...</i>";
hide_input = false;
rounding = -1;
check_color = "rgb(204, 136, 34)";
fail_color = "rgb(204, 34, 34)";
fail_text = "<i>$FAIL <b>($ATTEMPTS)</b></i>";
fail_timeout = 2000;
position = "0, -20";
halign = "center";
valign = "center";
}
];
};
};
};
};
}