diff --git a/home.nix b/home.nix index ea4906f..e7e6e82 100644 --- a/home.nix +++ b/home.nix @@ -99,7 +99,7 @@ in ./modules/tmux.nix ./modules/wezterm.nix ./modules/xdg.nix - ./modules/hyprland.nix + ./modules/hyprland ./modules/yazi.nix ./modules/zsh.nix ]; diff --git a/hosts/configuration.nix b/hosts/configuration.nix index d4c4912..183ffb8 100644 --- a/hosts/configuration.nix +++ b/hosts/configuration.nix @@ -20,6 +20,7 @@ XDG_CONFIG_HOME = "$HOME/.config"; XDG_DATA_HOME = "$HOME/.local/share"; XDG_STATE_HOME = "$HOME/.local/state"; + WLR_NO_HARDWARE_CURSORS = "1"; }; programs.hyprland.enable = true; diff --git a/hosts/desktop/default.nix b/hosts/desktop/default.nix index 044fd7c..6de5718 100644 --- a/hosts/desktop/default.nix +++ b/hosts/desktop/default.nix @@ -49,7 +49,9 @@ hardware.bluetooth.enable = true; environment.sessionVariables = { - WLR_NO_HARDWARE_CURSORS = "1"; + # Resolves jellyfin black screen under hyprland + # See also: https://github.com/jellyfin/jellyfin-media-player/issues/165#issuecomment-1030690851 + QT_QPA_PLATFORM = "xcb"; }; time.hardwareClockInLocalTime = true; diff --git a/modules/discord.nix b/modules/discord.nix index cd2a682..78f0638 100644 --- a/modules/discord.nix +++ b/modules/discord.nix @@ -3,10 +3,8 @@ { home.packages = with pkgs; [ - (discord.override { - withOpenASAR = true; - }) # because you *always* want your friends around - webcord + discord # because you *always* want your friends around + # webcord betterdiscordctl # sudo apt upgrade discord (betterdiscordctl install) ]; diff --git a/modules/hyprland.nix b/modules/hyprland.nix deleted file mode 100644 index a68718a..0000000 --- a/modules/hyprland.nix +++ /dev/null @@ -1,62 +0,0 @@ -{config, pkgs, osConfig, ...}: - -let - -in -{ - - home.packages = with pkgs; [ - swww - ]; - - wayland.windowManager.hyprland = { - enable = true; - package = pkgs.hyprland; - # Whether to enable XWayland - xwayland.enable = true; - - # Optional - # Whether to enable hyprland-session.target on hyprland startup - systemd.enable = true; - # Whether to enable patching wlroots for better Nvidia support - enableNvidiaPatches = true; - - extraConfig = if (osConfig.networking.hostName == "NicksNixDesktop") then - '' - monitor=DP-2, 2560x1440@144, 1920x0, 1 - monitor=DP-3, 1920x1080@60, 0x360,1 - '' - else '' - - ''; - - settings = { - exec-once = [ - "${pkgs.swww}/bin/swww init & sleep 0.5 & ${pkgs.swww}/bin/swww /home/nixolas/Downloads/RecountERD.png" - ]; - - decoration = { - shadow_offset = "0 5"; - "col.shadow" = "rgba(00000099)"; - }; - - "$mod" = "SUPER"; - - bindm = [ - # mouse movements - "$mod, mouse:272, movewindow" - "$mod, mouse:273, resizewindow" - "$mod ALT, mouse:272, resizewindow" - ]; - - bind = [ - "$mod, RETURN, exec, kitty" - "$mod, r, exec, rofi -show run window" - "$mod, q, killactive" - "$mod_SHIFT, p, exit" - # "$mod, Q, exec, firefox" - ]; - }; - }; - -} diff --git a/modules/hyprland/default.nix b/modules/hyprland/default.nix new file mode 100644 index 0000000..aac61f3 --- /dev/null +++ b/modules/hyprland/default.nix @@ -0,0 +1,90 @@ +{config, lib, pkgs, osConfig, ...}: + +let + +in +{ + + imports = [ + ./ewwbar.nix + ./keybinds.nix + ]; + + home.packages = with pkgs; [ + swww + ]; + + wayland.windowManager.hyprland = { + enable = true; + package = pkgs.hyprland; + # Whether to enable XWayland + xwayland.enable = true; + + # Optional + # Whether to enable hyprland-session.target on hyprland startup + systemd.enable = true; + # Whether to enable patching wlroots for better Nvidia support + enableNvidiaPatches = true; + + extraConfig = if (osConfig.networking.hostName == "NicksNixDesktop") then + '' + monitor=DP-2, 2560x1440@144, 1920x0, 1 + monitor=DP-3, 1920x1080@60, 0x360,1 + + env = LIBVA_DRIVER_NAME,nvidia + env = XDG_SESSION_TYPE,wayland + env = GBM_BACKEND,nvidia-drm + env = WLR_NO_HARDWARE_CURSORS,1 + '' + else '' + + ''; + + settings = { + "$mod" = "SUPER"; + + exec-once = [ + "${pkgs.swww}/bin/swww init & sleep 0.5 & ${pkgs.swww}/bin/swww /home/nixolas/Downloads/RecountERD.png" + "eww open bar" + ]; + + input = { + kb_layout = "us"; + sensitivity = -0.85; + accel_profile = "adaptive"; + touchpad.disable_while_typing = true; + }; + + general = { + gaps_in = 5; + gaps_out = 10; + border_size = 1.7; + "col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg"; + }; + + # https://wiki.hyprland.org/Configuring/Variables/#animations + animations = { + enabled = true; + animation = [ + "windowsOut, 1, 7, default, popin 80%" + "border, 1, 10, default" + "borderangle, 1, 8, default" + "fade, 1, 7, default" + "workspaces, 1, 6, default" + ]; + }; + + # https://wiki.hyprland.org/Configuring/Variables/#decoration + decoration = { + shadow_offset = "0 5"; + rounding = 5; + "col.shadow" = "rgba(00000099)"; + }; + + # https://wiki.hyprland.org/Configuring/Variables/#gestures + gestures = { workspace_swipe = false; }; + + }; + }; + +} diff --git a/modules/hyprland/eww-config/eww.scss b/modules/hyprland/eww-config/eww.scss new file mode 100644 index 0000000..d2abe6d --- /dev/null +++ b/modules/hyprland/eww-config/eww.scss @@ -0,0 +1,54 @@ +* { + all: unset; //Unsets everything so you can style everything from scratch +} + +//Global Styles +.bar { + background-color: #3a3a3a; + color: #b0b4bc; + padding: 10px; +} + +// Styles on classes (see eww.yuck for more information) + +.sidestuff slider { + all: unset; + color: #ffd5cd; +} + +.metric scale trough highlight { + all: unset; + background-color: #D35D6E; + color: #000000; + border-radius: 10px; +} +.metric scale trough { + all: unset; + background-color: #4e4e4e; + border-radius: 50px; + min-height: 3px; + min-width: 50px; + margin-left: 10px; + margin-right: 20px; +} +.metric scale trough highlight { + all: unset; + background-color: #D35D6E; + color: #000000; + border-radius: 10px; +} +.metric scale trough { + all: unset; + background-color: #4e4e4e; + border-radius: 50px; + min-height: 3px; + min-width: 50px; + margin-left: 10px; + margin-right: 20px; +} +.label-ram { + font-size: large; +} +.workspaces button:hover { + color: #D35D6E; +} diff --git a/modules/hyprland/eww-config/eww.yuck b/modules/hyprland/eww-config/eww.yuck new file mode 100644 index 0000000..85ef210 --- /dev/null +++ b/modules/hyprland/eww-config/eww.yuck @@ -0,0 +1,76 @@ +(defwidget bar [] + (centerbox :orientation "h" + (workspaces) + (music) + (sidestuff))) + +(defwidget sidestuff [] + (box :class "sidestuff" :orientation "h" :space-evenly false :halign "end" + (metric :label "🔊" + :value volume + :onchange "amixer -D pulse sset Master {}%") + (metric :label "" + :value {EWW_RAM.used_mem_perc} + :onchange "") + (metric :label "💾" + :value {round((1 - (EWW_DISK["/"].free / EWW_DISK["/"].total)) * 100, 0)} + :onchange "") + time)) + +(deflisten workspaces :initial "[]" "bash ./scripts/get-workspaces") +(deflisten current_workspace :initial "1" "bash ./scripts/get-active-workspace") +(defwidget workspaces [] + (eventbox :onscroll "bash ./scripts/change-active-workspace {} ${current_workspace}" :class "workspaces-widget" + (box :space-evenly true + (label :text "${workspaces}${current_workspace}" :visible false) + (for workspace in workspaces + (eventbox :onclick "hyprctl dispatch workspace ${workspace.id}" + (box :class "workspace-entry ${workspace.id == current_workspace ? "current" : ""} ${workspace.windows > 0 ? "occupied" : "empty"}" + (label :text "${workspace.id}") + ) + ) + ) + ) + ) + ) + +(defwidget music [] + (box :class "music" + :orientation "h" + :space-evenly false + :halign "center" + {music != "" ? "🎵${music}" : ""})) + + +(defwidget metric [label value onchange] + (box :orientation "h" + :class "metric" + :space-evenly false + (box :class "label" label) + (scale :min 0 + :max 101 + :active {onchange != ""} + :value value + :onchange onchange))) + + + +(deflisten music :initial "" + "playerctl --follow metadata --format '{{ artist }} - {{ title }}' || true") + +(defpoll volume :interval "1s" + "scripts/getvol") + +(defpoll time :interval "10s" + "date '+%H:%M %b %d, %Y'") + +(defwindow bar + :monitor 0 + :windowtype "dock" + :geometry (geometry :x "0%" + :y "0%" + :width "90%" + :height "10px" + :anchor "top center") + :reserve (struts :side "top" :distance "4%") + (bar)) diff --git a/modules/hyprland/eww-config/scripts/change-active-workspace b/modules/hyprland/eww-config/scripts/change-active-workspace new file mode 100755 index 0000000..af2ce35 --- /dev/null +++ b/modules/hyprland/eww-config/scripts/change-active-workspace @@ -0,0 +1,21 @@ +#! /bin/bash +function clamp { + min=$1 + max=$2 + val=$3 + python -c "print(max($min, min($val, $max)))" +} + +direction=$1 +current=$2 +if test "$direction" = "down" +then + target=$(clamp 1 10 $(($current+1))) + echo "jumping to $target" + hyprctl dispatch workspace $target +elif test "$direction" = "up" +then + target=$(clamp 1 10 $(($current-1))) + echo "jumping to $target" + hyprctl dispatch workspace $target +fi diff --git a/modules/hyprland/eww-config/scripts/get-active-workspace b/modules/hyprland/eww-config/scripts/get-active-workspace new file mode 100755 index 0000000..7bb8fe3 --- /dev/null +++ b/modules/hyprland/eww-config/scripts/get-active-workspace @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +hyprctl monitors -j | jq '.[] | select(.focused) | .activeWorkspace.id' + +socat -u UNIX-CONNECT:/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | + stdbuf -o0 awk -F '>>|,' -e '/^workspace>>/ {print $2}' -e '/^focusedmon>>/ {print $3}' diff --git a/modules/hyprland/eww-config/scripts/get-workspaces b/modules/hyprland/eww-config/scripts/get-workspaces new file mode 100755 index 0000000..570ff6e --- /dev/null +++ b/modules/hyprland/eww-config/scripts/get-workspaces @@ -0,0 +1,11 @@ +#!/bin/bash + +spaces (){ + WORKSPACE_WINDOWS=$(hyprctl workspaces -j | jq 'map({key: .id | tostring, value: .windows}) | from_entries') + seq 1 10 | jq --argjson windows "${WORKSPACE_WINDOWS}" --slurp -Mc 'map(tostring) | map({id: ., windows: ($windows[.]//0)})' +} + +spaces +socat -u UNIX-CONNECT:/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | while read -r line; do + spaces +done diff --git a/modules/hyprland/ewwbar.nix b/modules/hyprland/ewwbar.nix new file mode 100644 index 0000000..051b2f1 --- /dev/null +++ b/modules/hyprland/ewwbar.nix @@ -0,0 +1,20 @@ +{pkgs, ...}: + +let + +in +{ + + home.packages = with pkgs; [ + playerctl + alsa-utils + socat + jq + ]; + + programs.eww = { + enable = true; + package = pkgs.eww-wayland; + configDir = ./eww-config; + }; +} diff --git a/modules/hyprland/keybinds.nix b/modules/hyprland/keybinds.nix new file mode 100644 index 0000000..419045b --- /dev/null +++ b/modules/hyprland/keybinds.nix @@ -0,0 +1,66 @@ +{lib, ...}: + +let + workspaces = + (map toString (lib.range 0 9)) ++ + (map (n: "F${toString n}") (lib.range 1 12)); + # Map keys to hyprland directions + directions = rec { + left = "l"; right = "r"; up = "u"; down = "d"; + h = left; l = right; k = up; j = down; + }; + +in + { + wayland.windowManager.hyprland.settings = { + bindm = [ + # mouse movements + "$mod, mouse:272, movewindow" + "$mod, mouse:273, resizewindow" + "$mod ALT, mouse:272, resizewindow" + ]; + + bind = [ + "$mod, RETURN, exec, kitty" + "$mod, r, exec, rofi -show run window" + "$mod, q, killactive" + "$mod_SHIFT, p, exit" + + "$mod, SPACE, togglefloating" + "$mod, ;, fullscreen" + + # scroll through existing workspaces + "$mod, mouse_down, workspace, e+1" + "$mod, mouse_up, workspace, e-1" + ] ++ + # Change workspace + (map (n: + "$mod,${n},workspace,name:${n}" + ) workspaces) ++ + # Move window to workspace + (map (n: + "$modSHIFT,${n},movetoworkspacesilent,name:${n}" + ) workspaces) ++ + # Move focus + (lib.mapAttrsToList (key: direction: + "$mod,${key},movefocus,${direction}" + ) directions) ++ + # Swap windows + (lib.mapAttrsToList (key: direction: + "$modSHIFT,${key},swapwindow,${direction}" + ) directions) ++ + # Move windows + (lib.mapAttrsToList (key: direction: + "$modCONTROL,${key},movewindoworgroup,${direction}" + ) directions) ++ + # Move monitor focus + (lib.mapAttrsToList (key: direction: + "$modALT,${key},focusmonitor,${direction}" + ) directions) ++ + # Move workspace to other monitor + (lib.mapAttrsToList (key: direction: + "$modALTSHIFT,${key},movecurrentworkspacetomonitor,${direction}" + ) directions); + }; + } +