Add Hyprland configuration files and scripts for Wayland setup. Barely functional WIP

This commit is contained in:
Chris Toph 2025-03-22 18:32:03 -04:00
parent 668d4988b5
commit a959dacc78
13 changed files with 725 additions and 4 deletions

View file

@ -0,0 +1,119 @@
{
config,
lib,
pkgs,
...
}:
{
#INFO: Reference bind flags: https://wiki.hyprland.org/Configuring/Binds/#bind-flags
wayland.windowManager.hyprland.settings =
let
# -- Functions --
defaultApp =
type: "${pkgs.gtk3}/bin/gtk-launch $(${pkgs.xdg-utils}/bin/xdg-mime query default ${type})";
exec = script: "${pkgs.fish}/bin/fish ${script}";
xdg-open = command: "${pkgs.xdg-utils}/bin/xdg-open ${command}";
# -- Script Launchers --
# colorpicker = exec ./scripts/colorpicker.fish;
# lockscreen = exec ./scripts/lockscreen.fish;
# notify = exec ./scripts/notify.fish;
terminal = exec ./scripts/terminal.fish;
# wlogout = exec ./scripts/wlogout.fish;
# -- Commands or Binaries --
browser = defaultApp "x-scheme-handler/https";
editor = "code";
menu = "${pkgs.walker}/bin/walker --modules applications,ssh";
files = xdg-open "$HOME";
pactl = lib.getExe' pkgs.pulseaudio "pactl";
#playerctl = lib.getExe pkgs.playerctl; # installed via /home/common/optional/desktops/playerctl.nix
#swaylock = "lib.getExe pkgs.swaylock;
#makoctl = "${config.services.mako.package}/bin/makoctl";
#gtk-play = "${pkgs.libcanberra-gtk3}/bin/canberra-gtk-play";
#notify-send = "${pkgs.libnotify}/bin/notify-send";
# This shits too long
lowerVol = "XF86AudioLowerVolume";
raiseVol = "XF86AudioRaiseVolume";
in
{
## Mouse Binds ##
bindm = [
", mouse:275, movewindow"
", mouse:276, resizewindow"
];
## Non-consuming Binds ##
bindn = [
];
## Repeat Binds ##
binde = [
# Resize active window 5 pixels in direction
"SUPER_ALT, left, resizeactive, -20 0"
"SUPER_ALT, right, resizeactive, 20 0"
"SUPER_ALT, up, resizeactive, 0 -20"
"SUPER_ALT, down, resizeactive, 0 20"
# -- Volume --
", ${raiseVol}, exec, ${pactl} set-sink-volume @DEFAULT_SINK@ +5%"
", ${lowerVol}, exec, ${pactl} set-sink-volume @DEFAULT_SINK@ -5%"
", ${raiseVol}, exec, ${pactl} set-source-volume @DEFAULT_SOURCE@ +5%"
", ${lowerVol}, exec, ${pactl} set-source-volume @DEFAULT_SOURCE@ -5%"
];
## One-shot Binds ##
bind = [
# -- Terminal --
"SUPER, T, exec, ${terminal}"
"SUPER_SHIFT, T, exec, ${terminal}" # floating
"SUPER_ALT, T, exec, ${terminal}" # select size?
# -- Apps --
"SUPER, F, exec, ${files}"
"SUPER, E, exec, ${editor}"
"SUPER, W, exec, ${browser}"
"SUPER, N, exec, nm-connection-editor"
# "SUPER, P, exec, ${colorpicker}"
# -- Menu --
"SUPER, SUPER_L, exec, ${menu}"
# "SUPER, V, exec, ${menu}"
# -- System --
# "SUPER, X, exec, ${wlogout}"
# "SUPER, L, exec, ${lockscreen}"
"SUPER, L, exec, hyprlock"
"SUPER, Q, killactive,"
"CTRL_ALT, Delete, exit,"
# -- Window Management --
"SUPER_SHIFT, F, fullscreen, 0"
# "SUPER, F, exec, ${notify} 'Fullscreen Mode'"
"SUPER, Backspace, togglefloating,"
"SUPER, Backspace, centerwindow,"
"SUPER, left, movefocus, l"
"SUPER, right, movefocus, r"
"SUPER, up, movefocus, u"
"SUPER, down, movefocus, d"
"SUPER_SHIFT, left, movewindow, l"
"SUPER_SHIFT, right, movewindow, r"
"SUPER_SHIFT, up, movewindow, u"
"SUPER_SHIFT, down, movewindow, d"
"SUPER_SHIFT, P, pin,"
# "SUPER_SHIFT, P, exec, ${notify} 'Toggled Pin'"
"SUPER_SHIFT, S, swapnext"
# "SUPER_SHIFT, O, toggleopaque"
# -- Workspaces --
", Home, overview:toggle"
# "SUPER, A, "
# TODO: use hycov for alt tab, https://github.com/bighu630/hycov
"ALT, Tab, cyclenext,"
"ALT, Tab, bringactivetotop,"
];
};
}

View file

@ -0,0 +1,240 @@
{
config,
inputs,
lib,
pkgs,
...
}:
{
imports = lib.custom.scanPaths ./.;
wayland.windowManager.hyprland = {
enable = true;
# withUWSM = true; # One day, but not today
package = inputs.hyprland.packages."${pkgs.system}".hyprland;
systemd = {
enable = true;
variables = [ "--all" ];
extraCommands = lib.mkBefore [
"systemctl --user stop graphical-session.target"
"systemctl --user start hyprland-session.target"
];
};
plugins = [
# inputs.hycov.packages.${pkgs.system}.hycov
(inputs.hyprspace.packages.${pkgs.system}.Hyprspace.overrideAttrs {
dontUseCmakeConfigure = true;
})
];
settings = {
#
# ========== Environment Vars ==========
#
env = [
"NIXOS_OZONE_WL, 1" # for ozone-based and electron apps to run on wayland
"MOZ_ENABLE_WAYLAND, 1" # for firefox to run on wayland
"MOZ_WEBRENDER, 1" # for firefox to run on wayland
"XDG_SESSION_TYPE,wayland"
"WLR_NO_HARDWARE_CURSORS,1"
"WLR_RENDERER_ALLOW_SOFTWARE,1"
"QT_QPA_PLATFORM,wayland"
"HYPRCURSOR_THEME,rose-pine-hyprcursor" # this will be better than default for now
];
## Monitor ##
# parse the monitor spec defined in home/<user>/<host>/default.nix
monitor = (
map (
m:
"${m.name},${
if m.enabled then
"${toString m.width}x${toString m.height}@${toString m.refreshRate},${toString m.x}x${toString m.y},1,transform,${toString m.transform},vrr,${toString m.vrr}"
else
"disable"
}"
) (config.monitors)
);
#FIXME(hyprland): adapt this to work with new monitor module
#FIXME(hyprland): ws1 still appears on both DP-1 and DP-3 on reboot
# workspace = [
# "1, monitor:DP-1, default:true, persistent:true"
# "2, monitor:DP-1, default:true"
# "3, monitor:DP-1, default:true"
# "4, monitor:DP-1, default:true"
# "5, monitor:DP-1, default:true"
# "6, monitor:DP-1, default:true"
# "7, monitor:DP-1, default:true"
# "8, monitor:DP-2, default:true, persistent:true"
# "9, monitor:HDMI-A-1, default:true, persistent:true"
# "0, monitor:DP-3, default:true, persistent:true"
# ];
#
# ========== Behavior ==========
#
binds = {
workspace_center_on = 1; # Whether switching workspaces should center the cursor on the workspace (0) or on the last active window for that workspace (1)
movefocus_cycles_fullscreen = false; # If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.
};
input = {
follow_mouse = 2;
# follow_mouse options:
# 0 - Cursor movement will not change focus.
# 1 - Cursor movement will always change focus to the window under the cursor.
# 2 - Cursor focus will be detached from keyboard focus. Clicking on a window will move keyboard focus to that window.
# 3 - Cursor focus will be completely separate from keyboard focus. Clicking on a window will not change keyboard focus.
mouse_refocus = false;
kb_options = "fkeys:basic_13-24";
};
cursor.inactive_timeout = 10;
misc = {
disable_hyprland_logo = true;
animate_manual_resizes = true;
animate_mouse_windowdragging = true;
#disable_autoreload = true;
new_window_takes_over_fullscreen = 2; # 0 - behind, 1 - takes over, 2 - unfullscreen/unmaxize
middle_click_paste = false;
};
#
# ========== Appearance ==========
#
#FIXME-rice colors conflict with stylix
general = {
gaps_in = 6;
gaps_out = 6;
border_size = 0;
#col.inactive-border = "0x00000000";
#col.active-border = "0x0000000";
resize_on_border = true;
hover_icon_on_border = true;
allow_tearing = true; # used to reduce latency and/or jitter in games
};
decoration = {
active_opacity = 1.0;
inactive_opacity = 0.85;
fullscreen_opacity = 1.0;
rounding = 10;
blur = {
enabled = true;
size = 4;
passes = 2;
new_optimizations = true;
popups = true;
};
shadow = {
enabled = true;
range = 12;
offset = "3 3";
#color = "0x88ff9400";
#color_inactive = "0x8818141d";
};
};
# group = {
#groupbar = {
# };
#};
#
# ========== Auto Launch ==========
#
# exec-once = ''${startupScript}/path'';
# To determine path, run `which foo`
exec-once = [
''${pkgs.waypaper}/bin/waypaper --restore''
];
#
# ========== Layer Rules ==========
#
layer = [
#"blur, rofi"
#"ignorezero, rofi"
#"ignorezero, logout_dialog"
];
#
# ========== Window Rules ==========
#
windowrule = [
# Dialogs
"float, title:^(Open File)(.*)$"
"float, title:^(Select a File)(.*)$"
"float, title:^(Choose wallpaper)(.*)$"
"float, title:^(Open Folder)(.*)$"
"float, title:^(Save As)(.*)$"
"float, title:^(Library)(.*)$"
"float, title:^(Accounts)(.*)$"
];
windowrulev2 = [
"float, class:^(galculator)$"
"float, class:^(waypaper)$"
"float, class:^(keymapp)$"
#
# ========== Always opaque ==========
#
"opaque, class:^([Gg]imp)$"
"opaque, class:^([Ff]lameshot)$"
"opaque, class:^([Ii]nkscape)$"
"opaque, class:^([Bb]lender)$"
"opaque, class:^([Oo][Bb][Ss])$"
"opaque, class:^([Ss]team)$"
"opaque, class:^([Ss]team_app_*)$"
"opaque, class:^([Vv]lc)$"
# Remove transparency from video
"opaque, title:^(Netflix)(.*)$"
"opaque, title:^(.*YouTube.*)$"
"opaque, title:^(Picture-in-Picture)$"
#
# ========== Scratch rules ==========
#
#"size 80% 85%, workspace:^(special:special)$"
#"center, workspace:^(special:special)$"
#
# ========== Steam rules ==========
#
"stayfocused, title:^()$,class:^([Ss]team)$"
"minsize 1 1, title:^()$,class:^([Ss]team)$"
"immediate, class:^([Ss]team_app_*)$"
"workspace 7, class:^([Ss]team_app_*)$"
"monitor 0, class:^([Ss]team_app_*)$"
#
# ========== Fameshot rules ==========
#
# flameshot currently doesn't have great wayland support so needs some tweaks
#"rounding 0, class:^([Ff]lameshot)$"
#"noborder, class:^([Ff]lameshot)$"
#"float, class:^([Ff]lameshot)$"
#"move 0 0, class:^([Ff]lameshot)$"
#"suppressevent fullscreen, class:^([Ff]lameshot)$"
# "monitor:DP-1, ${flameshot}"
#
# ========== Workspace Assignments ==========
#
"workspace 8, class:^(virt-manager)$"
"workspace 8, class:^(obsidian)$"
"workspace 9, class:^(brave-browser)$"
"workspace 9, class:^(signal)$"
"workspace 9, class:^(org.telegram.desktop)$"
"workspace 9, class:^(discord)$"
"workspace 0, title:^([Ss]potify*)$"
"workspace special, class:^(yubioath-flutter)$"
];
# load at the end of the hyperland set
# extraConfig = '''';
plugin = {
};
};
};
}

View file

@ -0,0 +1,200 @@
#
# Dunst
# Notification Daemon
#
{ pkgs, ... }:
{
home.packages = builtins.attrValues {
inherit (pkgs) libnotify; # required by dunst
};
services.dunst = {
enable = true;
# waylandDisplay = ""; # set the service's WAYLAND_DISPLAY environment variable
# configFile = "";
iconTheme = {
name = "Adwaita";
package = pkgs.adwaita-icon-theme;
size = "16x16";
};
settings = {
global = {
# Allow a small subset of html markup:<b></b>, <i></i>, <s></s>, and <u></u>.
# For a complete reference see
# <http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>.
# If markup is not allowed, those tags will be stripped out of the message.
allow_markup = "yes";
# The format of the message. Possible variables are:
# %a appname
# %s summary
# %b body
# %i iconname (including its path)
# %I iconname (without its path)
# %p progress value if set ([ 0%] to [100%]) or nothing
# Markup is allowed
format = "%I %s %p\\n%b";
#TODO dynamic fonts
#font = "Droid Sans 12";
alignment = "left"; # Options are "left", "center", and "right".
sort = "yes"; # Sort messages by urgency.
indicate_hidden = "yes"; # Show how many messages are currently hidden (because of geometry).
# The frequency with which text that is longer than the notification
# window allows bounces back and forth.
# This option conflicts with "word_wrap".
# Set to 0 to disable.
bounce_freq = 5;
# Show age of message if message is older than show_age_threshold
# seconds.
# Set to -1 to disable.
show_age_threshold = 60;
# Split notifications into multiple lines if they don't fit into
# geometry.
word_wrap = "no";
# Ignore newlines '\n' in notifications.
ignore_newline = "no";
# The geometry of the window:
# [{width}]x{height}[+/-{x}+/-{y}]
# The geometry of the message window.
# The height is measured in number of notifications everything else
# in pixels. If the width is omitted but the height is given
# ("-geometry x2"), the message window expands over the whole screen
# (dmenu-like). If width is 0, the window expands to the longest
# message displayed. A positive x is measured from the left, a
# negative from the right side of the screen. Y is measured from
# the top and down respectevly.
# The width can be negative. In this case the actual width is the
# screen width minus the width defined in within the geometry option.
geometry = "0x4-25+25";
# Shrink window if it's smaller than the width. Will be ignored if
# width is 0.
shrink = "yes";
# Display notification on focused monitor. Possible modes are:
# mouse: follow mouse pointer
# keyboard: follow window with keyboard focus
# none: don't follow anything
#
# "keyboard" needs a windowmanager that exports the _NET_ACTIVE_WINDOW property.
# This should be the case for almost all modern windowmanagers.
#
# If this option is set to mouse or keyboard, the monitor option will be ignored.
follow = "mouse";
# Should a notification popped up from history be sticky or timeout
# as if it would normally do.
sticky_history = "yes";
# Maximum amount of notifications kept in history
history_length = 20;
# Display indicators for URLs (U) and actions (A).
show_indicators = "yes";
# The height of a single line. If the height is smaller than the
# font height, it will get raised to the font height.
# This adds empty space above and under the text.
line_height = 0;
# Draw a line of "separator_height" pixel height between two
# notifications. Set to 0 to disable.
separator_height = 1;
# Padding between text and separator.
padding = 8;
# Horizontal padding.
horizontal_padding = 10;
# The transparency of the window. Range: [0; 100].
# This option will only work if a compositing windowmanager is
# present (e.g. xcompmgr, compiz, etc.).
transparency = 15;
# Define a color for the separator.
# possible values are:
# * auto: dunst tries to find a color fitting to the background;
# * foreground: use the same color as the foreground;
# * frame: use the same color as the frame;
# * anything else will be interpreted as a X color.
# separator_color = "#454947";
# Print a notification on startup.
# This is mainly for error detection, since dbus (re-)starts dunst
# automatically after a crash.
#set to true for debugging
startup_notification = false;
# Align icons left/right/off
icon_position = "left";
width = 300;
height = 300;
offset = "30x50";
#origin = "top-right";
origin = "top-center";
#TODO dynamic theme colours
# frame_color = "#dc7f41";
# Browser for opening urls in context menu.
browser = "firefox";
};
frame = {
width = 2;
#TODO dynamic colours
# color = "#dc7f41";
};
shortcuts = {
# Shortcuts are specified as [modifier+][modifier+]...key
# Available modifiers are "ctrl", "mod1" (the alt-key), "mod2",
# "mod3" and "mod4" (windows-key).
# Xev might be helpful to find names for keys.
# Close notification.
close = "mod1+space";
# Close all notifications.
close_all = "ctrl+mod1+space";
# Redisplay last message(s).
history = "ctrl+mod4+h";
# Context menu.
context = "ctrl+mod1+c";
};
urgency_low = {
#TODO dynamic colours
# background = "#1e1e20";
# foreground = "#c5c8c6";
timeout = 10;
};
urgency_normal = {
#TODO dynamic colours
# background = "#1e1e20";
# foreground = "#c5c8c6";
timeout = 10;
};
urgency_critical = {
#TODO dynamic colours
# background = "#1e1e20";
# foreground = "#c5c8c6";
timeout = 0;
};
};
};
}

View file

@ -0,0 +1,33 @@
{
pkgs,
...
}:
{
home.pointerCursor = {
gtk.enable = true;
# x11.enable = true;
package = pkgs.bibata-cursors;
name = "Bibata-Modern-Classic";
size = 16;
};
gtk = {
enable = true;
theme = {
package = pkgs.flat-remix-gtk;
name = "Flat-Remix-GTK-Grey-Darkest";
};
iconTheme = {
package = pkgs.adwaita-icon-theme;
name = "Adwaita";
};
font = {
name = "Sans";
size = 14;
};
};
}

View file

@ -0,0 +1,38 @@
{ lib, ... }:
{
programs.hyprlock = {
enable = true;
settings = {
general = {
disable_loading_bar = true;
immediate_render = true;
hide_cursor = false;
no_fade_in = true;
};
background = lib.mkDefault [
{
path = "screenshot";
blur_passes = 3;
blur_size = 8;
}
];
input-field = lib.mkDefault [
{
size = "200, 50";
position = "0, -80";
monitor = "";
dots_center = true;
fade_on_empty = false;
font_color = "rgb(202, 211, 245)";
inner_color = "rgb(91, 96, 120)";
outer_color = "rgb(24, 25, 38)";
outline_thickness = 5;
shadow_passes = 2;
}
];
};
};
}

View file

@ -0,0 +1,7 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.playerctl ];
services.playerctld = {
enable = true;
};
}

View file

@ -0,0 +1 @@
{ }

View file

@ -0,0 +1,3 @@
#!/usr/bin/env fish
foot

View file

@ -9,9 +9,11 @@
## Host-specific Optional Configs ##
../common/optional/browsers
../common/optional/gnome
# ../common/optional/development
# ../common/optional/gnome
../common/optional/hyprland
../common/optional/development
# ../common/optional/gaming
../common/optional/vscode-server.nix
../common/optional/xdg.nix # file associations
];
@ -20,7 +22,17 @@
inherit (pkgs)
## Tools ##
inspector
wezterm
foot
;
};
monitors = [
{
name = "Virtual-1";
width = 2560;
height = 1440;
refreshRate = 60;
primary = true;
}
];
}

View file

@ -0,0 +1,21 @@
{
inputs,
pkgs,
lib,
...
}:
{
imports = lib.custom.scanPaths ./.;
programs.hyprland = {
enable = true;
# withUWSM = true; # One day, but not today
package = inputs.hyprland.packages."${pkgs.system}".hyprland;
portalPackage = inputs.hyprland.packages.${pkgs.system}.xdg-desktop-portal-hyprland;
};
environment.systemPackages = [
inputs.rose-pine-hyprcursor.packages.${pkgs.system}.default
];
}

View file

@ -0,0 +1,35 @@
#
# greeter -> tuigreet https://github.com/apognu/tuigreet?tab=readme-ov-file
# display manager -> greetd https://man.sr.ht/~kennylevinsen/greetd/
#
{
config,
pkgs,
lib,
...
}:
let
hostSpec = config.hostSpec.username;
default = {
command = "${pkgs.greetd.tuigreet}/bin/tuigreet --asterisks --time --time-format '%I:%M %p | %a %h | %F' --cmd Hyprland";
user = "toph";
};
initial = {
command = "${pkgs.hyprland}/bin/Hyprland";
user = "toph";
};
in
{
# environment.systemPackages = [ pkgs.greetd.tuigreet ];
services.greetd = {
enable = true;
restart = true;
settings = rec {
default_session = default;
initial_session = initial;
};
};
}

View file

@ -0,0 +1,11 @@
{ pkgs, ... }:
{
# general packages related to wayland
environment.systemPackages = with pkgs; [
grim # screen capture component, required by flameshot
waypaper # wayland packages(nitrogen analog for wayland)
swww # backend wallpaper daemon required by waypaper
wl-clipboard-rs
wlr-randr
];
}

View file

@ -28,7 +28,8 @@ in
## Optional Configs ##
"hosts/common/optional/audio.nix" # pipewire and cli controls
# "hosts/common/optional/gaming.nix" # steam, gamescope, gamemode, and related hardware
"hosts/common/optional/gnome.nix" # desktop
# "hosts/common/optional/gnome.nix" # desktop
"hosts/common/optional/hyprland" # desktop
# "hosts/common/optional/nvtop.nix" # GPU monitor (not available in home-manager)
# "hosts/common/optional/plymouth.nix" # fancy boot screen