From 6977f6f39979c4314aec7635384f16a9b9018716 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Sat, 29 Jun 2024 02:28:20 +0200 Subject: [PATCH] WIP: home/{hyprland,waybar}: init --- flake.nix | 2 + home/home.nix | 10 +- home/programs/hyprland.nix | 342 +++++++++++++++++++++++++++ home/programs/neovim.nix | 1 + home/programs/waybar.nix | 239 +++++++++++++++++++ home/services/dunst.nix | 6 +- hosts/common/default.nix | 23 +- hosts/kasei/configuration.nix | 4 +- overlays/wayland-ime-integration.nix | 20 ++ 9 files changed, 631 insertions(+), 16 deletions(-) create mode 100644 home/programs/hyprland.nix create mode 100644 home/programs/waybar.nix create mode 100644 overlays/wayland-ime-integration.nix diff --git a/flake.nix b/flake.nix index 2d9ddff..f7697ef 100644 --- a/flake.nix +++ b/flake.nix @@ -101,6 +101,8 @@ inherit (nonrecursive-unstable-pkgs) atuin wstunnel; }) + (import ./overlays/wayland-ime-integration.nix) + # https://github.com/NixOS/nixpkgs/pull/251706 (self: super: { mozc = self.qt6Packages.callPackage ./package-overrides/mozc.nix { }; diff --git a/home/home.nix b/home/home.nix index c07d23f..3674623 100644 --- a/home/home.nix +++ b/home/home.nix @@ -35,12 +35,14 @@ in { ./programs/alacritty.nix ./programs/emacs ./programs/firefox.nix + ./programs/hyprland.nix ./programs/ncmpcpp.nix ./programs/newsboat ./programs/qutebrowser.nix ./programs/rofi.nix ./programs/taskwarrior.nix ./programs/vscode.nix + ./programs/waybar.nix # ./programs/xmobar ./programs/xmonad ./programs/zathura.nix @@ -49,11 +51,11 @@ in { ./services/dunst.nix ./services/fcitx5.nix ./services/mpd.nix - ./services/picom.nix - ./services/polybar.nix - ./services/screen-locker.nix + # ./services/picom.nix + # ./services/polybar.nix + # ./services/screen-locker.nix # ./services/stalonetray.nix - ./services/sxhkd.nix + # ./services/sxhkd.nix ./services/tumblerd.nix ]; diff --git a/home/programs/hyprland.nix b/home/programs/hyprland.nix new file mode 100644 index 0000000..d974e8b --- /dev/null +++ b/home/programs/hyprland.nix @@ -0,0 +1,342 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.wayland.windowManager.hyprland; +in +{ + home.sessionVariables = { + WLR_NO_HARDWARE_CURSORS = "1"; + WLR_RENDERER_ALLOW_SOFTWARE = "1"; + XDG_CURRENT_DESKTOP = "Hyprland"; + XDG_SESSION_DESKTOP = "Hyprland"; + XDG_SESSION_TYPE = "wayland"; + GDK_BACKEND = "wayland,x11,*"; + QT_QPA_PLATFORM = "wayland;xcb"; + NIXOS_OZONE_WL = "1"; + MOZ_ENABLE_WAYLAND = "1"; + SDL_VIDEODRIVER = "wayland"; + OZONE_PLATFORM = "wayland"; + CLUTTER_BACKEND = "wayland"; + QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; + # QT_QPA_PLATFORMTHEME = "qt6ct"; + QT_AUTO_SCREEN_SCALE_FACTOR = "1"; + + LIBVA_DRIVER_NAME = "nvidia"; + GBM_BACKEND = "nvidia-drm"; + __GLX_VENDOR_LIBRARY_NAME = "nvidia"; + }; + + home.packages = with pkgs; [ + wl-clipboard-rs + ]; + + programs.hyprlock = { + enable = true; + settings = { + general = { + disable_loading_bar = true; + grace = 300; + hide_cursor = true; + no_fade_in = false; + }; + + background = [ + { + path = "screenshot"; + blur_passes = 3; + blur_size = 8; + } + ]; + + input-field = [ + { + 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; + placeholder_text = ''Password...''; + shadow_passes = 2; + } + ]; + }; + }; + + services.hypridle = { + enable = true; + settings = { + general = { + ignore_dbus_inhibit = false; + lock_cmd = "pidof hyprlock || hyprlock"; + before_sleep_cmd = "loginctl lock-session"; + after_sleep_cmd = "hyprctl dispatch dpms on"; + }; + + listener = [ + { + timeout = 900; + on-timeout = "hyprlock"; + } + { + timeout = 1200; + on-timeout = "hyprctl dispatch dpms off"; + on-resume = "hyprctl dispatch dpms on"; + } + ]; + }; + }; + + wayland.windowManager.hyprland = { + enable = true; + + settings = let + scratchpads = [ + (rec { + title = "Floating terminal"; + class = "floatingTerminal"; + command = "alacritty --class ${class} -e tmux new-session -A -s f"; + size = { h = 90; w = 95; }; + keys = [ + "$mod, RETURN" + "$mod, SPACE" + ]; + }) + (rec { + title = "Ncmpcpp"; + class = "floatingNcmpcpp"; + command = "alacritty --class ${class} -e ncmpcpp"; + size = { h = 95; w = 95; }; + keys = [ "$mod, Q" ]; + }) + # "$mod, W, emacs" + # "$mod, E, filebrowser" + # "$mod, X, taskwarriortui" + ]; + in { + "$mod" = "SUPER"; + + # https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h + bind = [ + "$mod SHIFT, Q, exit" + "$mod, R, exec, ${pkgs.rofi}/bin/rofi -show drun" + "$mod, T, togglefloating" + + # TODO: fix this for upcoming releases + "$mod, F, fullscreen, 2" + "$mod, C, exec, hyprctl reload" + + "$mod, BACKSPACE, exec, ${lib.getExe (pkgs.writeShellApplication { + name = "hyprland-kill-windows-except-scratchpads"; + runtimeInputs = [ cfg.package pkgs.jq ]; + text = '' + ACTIVE_WINDOW_CLASS=$(hyprctl activewindow -j | jq -r '.class') + + case "$ACTIVE_WINDOW_CLASS" in + ${lib.pipe scratchpads [ + (map ({ class , ... }: '' + '${class}') + hyprctl dispatch togglespecialworkspace '${class}Ws' + ;; + '')) + (map (lib.splitString "\n")) + (lib.flatten) + (map (x: " " + x)) + (lib.concatStringsSep "\n") + ]} + *) + hyprctl dispatch killactive + ;; + esac + ''; + })}" + + "$mod SHIFT, RETURN, exec, alacritty --class termTerminal -e tmux new-session -A -s term" + "$mod SHIFT, SPACE, exec, alacritty --class termTerminal -e tmux new-session -A -s term" + + "$mod, j, layoutmsg,cyclenext" + "$mod, k, layoutmsg,cycleprev" + "$mod SHIFT, j, layoutmsg, swapnext" + "$mod SHIFT, k, layoutmsg, swapprev" + + "$mod, 1, focusworkspaceoncurrentmonitor, 1" + "$mod, 2, focusworkspaceoncurrentmonitor, 2" + "$mod, 3, focusworkspaceoncurrentmonitor, 3" + "$mod, 4, focusworkspaceoncurrentmonitor, 4" + "$mod, 5, focusworkspaceoncurrentmonitor, 5" + "$mod, 6, focusworkspaceoncurrentmonitor, 6" + "$mod, 7, focusworkspaceoncurrentmonitor, 7" + "$mod, 8, focusworkspaceoncurrentmonitor, 8" + "$mod, 9, focusworkspaceoncurrentmonitor, 9" + + "$mod SHIFT, 1, movetoworkspacesilent, 1" + "$mod SHIFT, 2, movetoworkspacesilent, 2" + "$mod SHIFT, 3, movetoworkspacesilent, 3" + "$mod SHIFT, 4, movetoworkspacesilent, 4" + "$mod SHIFT, 5, movetoworkspacesilent, 5" + "$mod SHIFT, 6, movetoworkspacesilent, 6" + "$mod SHIFT, 7, movetoworkspacesilent, 7" + "$mod SHIFT, 8, movetoworkspacesilent, 8" + "$mod SHIFT, 9, movetoworkspacesilent, 9" + + "$mod, b, exec, ${pkgs.fcitx5}/bin/fcitx5-remote -s mozc" + "$mod, n, exec, ${pkgs.fcitx5}/bin/fcitx5-remote -s keyboard-no" + "$mod, m, exec, ${pkgs.fcitx5}/bin/fcitx5-remote -s keyboard-us" + + # TODO: ensure exists in environment + "$mod, l, exec, loginctl lock-session" + + # TODO: fix + # "super + minus" = "${pkgs.xcalib}/bin/xcalib -invert -alter" + + # TODO: fix + ", Print, exec, ${lib.getExe pkgs.grimblast} copy area" + + # "SHIFT, Print, exec, ${lib.getExe pkgs.grimblast} copy area" + # "shift + @Print" = "${pkgs.maim}/bin/maim --hidecursor --nokeyboard $SCREENSHOT_DIR/$(date +%s).png" + + # TODO: Add boomer as package + # "super + @Print" = "boomer" + ] + ++ + (lib.pipe scratchpads [ + (map ({ keys, command, class, ... }: + (map (key: let + # TODO: rewrite the scratchpad logic to move windows back and forth + # from the special workspaces, rather than overlay the workspaces. + # + # TODO: don't invoke the program upon close toggling the scratchpad + # + # TODO: ensure program becomes in focus upon open toggling the scratchpad + invokeIfNotRunningAndToggleWorkspace = pkgs.writeShellApplication { + name = "hyprland-toggle-scratchpad-${class}"; + runtimeInputs = [ cfg.package pkgs.jq ]; + text = '' + SCRATCHPAD_EXISTS=$(hyprctl clients -j | jq -r '[.[].class]|any(. == "${class}")') + + if [ "$SCRATCHPAD_EXISTS" != "true" ]; then + ${command} & + fi + + hyprctl dispatch togglespecialworkspace '${class}Ws' + ''; + }; + in "${key}, exec, ${lib.getExe invokeIfNotRunningAndToggleWorkspace}" + ) keys) + )) + lib.flatten + ]); + + bindl = [ + "$mod, p, exec, ${pkgs.mpc_cli}/bin/mpc toggle" + ",XF86AudioPlay, exec, ${pkgs.mpc_cli}/bin/mpc toggle" + ",XF86AudioPrev, exec, ${pkgs.mpc_cli}/bin/mpc prev" + ",XF86AudioNext, exec, ${pkgs.mpc_cli}/bin/mpc next" + ]; + + bindle = [ + ",XF86MonBrightnessUp, exec, ${lib.getExe pkgs.brightnessctl} s +5%" + ",XF86MonBrightnessDown, exec, ${lib.getExe pkgs.brightnessctl} s 5%-" + ",XF86AudioLowerVolume, exec, ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%-" + ",XF86AudioRaiseVolume, exec, ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%+" + "$mod ,F7, exec, ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%-" + "$mod ,F8, exec, ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 2%+" + ]; + + windowrulev2 = [ + "float,class:(Rofi)" + + "workspace 2,class:(firefox)" + "workspace 2,class:(google-chrome)" + + "workspace 3,class:(Emacs)" + "workspace 3,class:(Code)" + "workspace 3,class:(code-url-handler)" + + "workspace 5,class:(discord)" + "workspace 5,class:(Element)" + ] + ++ + (lib.pipe scratchpads [ + (map ({ class, size, ... }: [ + "workspace special:${class}Ws, class:^${class}$" + "float, class:^${class}$" + "size ${toString size.w}% ${toString size.h}%, class:^${class}$" + "move ${toString ((100 - size.w) / 2)}% ${toString ((100 - size.h) / 2)}%, class:^${class}$" + ])) + lib.flatten + ]); + + monitor = [ + "DP-2, 1920x1080@144.00Hz, 0x0, 1" + "DVI-D-1, 1920x1080@144.00Hz, 1920x0, 1" + ",preferred,auto,1" + ]; + + general = { + gaps_in = 5; + gaps_out = 15; + + border_size = 2; + + "col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg"; + "col.inactive_border" = "rgba(595959aa)"; + + resize_on_border = false; + allow_tearing = false; + layout = "master"; + }; + + decoration = { + rounding = 10; + + # Change transparency of focused and unfocused windows + active_opacity = 1.0; + inactive_opacity = 1.0; + + drop_shadow = true; + shadow_range = 4; + shadow_render_power = 3; + "col.shadow" = "rgba(1a1a1aee)"; + + # https://wiki.hyprland.org/Configuring/Variables/#blur + blur = { + enabled = true; + size = 3; + passes = 1; + + vibrancy = 0.1696; + }; + }; + + animations.enabled = false; + + master = { + new_status = "slave"; + }; + + misc = { + force_default_wallpaper = 0; # Set to 0 or 1 to disable the anime mascot wallpapers + disable_hyprland_logo = false; # If true disables the random hyprland logo / anime girl background. :( + }; + + input ={ + kb_layout = "us"; + kb_variant = ""; + kb_model = ""; + kb_options = ""; + kb_rules = ""; + + follow_mouse = 1; + + sensitivity = 0; # -1.0 - 1.0, 0 means no modification. + + touchpad = { + natural_scroll = false; + }; + }; + }; + }; +} diff --git a/home/programs/neovim.nix b/home/programs/neovim.nix index 2f20a39..c48116b 100644 --- a/home/programs/neovim.nix +++ b/home/programs/neovim.nix @@ -17,6 +17,7 @@ vim-surround vim-fugitive vim-css-color + vim-wayland-clipboard semshi { plugin = goyo-vim; diff --git a/home/programs/waybar.nix b/home/programs/waybar.nix new file mode 100644 index 0000000..d3dcf66 --- /dev/null +++ b/home/programs/waybar.nix @@ -0,0 +1,239 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.programs.waybar; + cfgs = cfg.settings.mainBar; +in +{ + programs.waybar = { + enable = true; + systemd.enable = true; + + settings = { + mainBar = { + layer = "top"; + position = "top"; + height = 30; + + # TODO: configure this per machine + output = [ "DP-2" ]; + + modules-left = [ "hyprland/workspaces" ]; + modules-center = [ "clock" ]; + modules-right = [ "mpd" "cpu" "memory" "wireplumber" "pulseaudio/slider" "tray" ]; + + "hyprland/workspaces" = { + all-outputs = true; + disable-scroll = true; + persistent-workspaces = { + ${lib.head cfgs.output} = [ 1 2 3 4 5 6 7 8 ]; + }; + }; + + "mpd" = { + format = "{filename}"; + }; + + "cpu" = { + format = "[#] {usage}%"; + }; + + "memory" = { + format = "{used}/{total}Gb"; + }; + + "wireplumber" = { + format = "{volume}% {icon}"; + format-muted = "[M]"; + }; + + "pulseaudio/slider" = { + orientation = "horizontal"; + }; + + "tray" = { + icon-size = 20; + spacing = 8; + }; + }; + }; + + style = let + c = config.colors.defaultColorSet; + in '' + * { + font-family: FiraCode, FontAwesome, Roboto, Helvetica, Arial, sans-serif; + font-size: 13px; + } + + window#waybar { + background-color: ${c.background}; + color: ${c.foreground}; + } + + #pulseaudio-slider trough { + min-height: 10px; + min-width: 100px; + } + + /**** DEFAULT ****/ + + window#waybar.hidden { + opacity: 0.2; + } + + button { + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -3px transparent; + /* Avoid rounded borders under each button name */ + border: none; + border-radius: 0; + } + + /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ + button:hover { + background: inherit; + box-shadow: inset 0 -3px #ffffff; + } + + + #workspaces button.empty { + color: ${c.yellow}; + } + + #workspaces button { + padding: 0 5px; + color: ${c.magenta}; + background-color: transparent; + } + + #workspaces button.visible { + color: ${c.green}; + } + + #workspaces button.urgent { + background-color: ${c.red}; + } + + #workspaces button:hover { + background: rgba(0, 0, 0, 0.2); + } + + #mode { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; + } + + #clock, + #battery, + #cpu, + #memory, + #disk, + #temperature, + #backlight, + #network, + #pulseaudio, + #wireplumber, + #custom-media, + #tray, + #mode, + #idle_inhibitor, + #scratchpad, + #power-profiles-daemon, + #mpd { + padding: 0 10px; + color: ${c.foreground}; + } + + #window, + #workspaces { + margin: 0 4px; + } + + /* If workspaces is the leftmost module, omit left margin */ + .modules-left > widget:first-child > #workspaces { + margin-left: 0; + } + + /* If workspaces is the rightmost module, omit right margin */ + .modules-right > widget:last-child > #workspaces { + margin-right: 0; + } + + #clock { + background-color: #64727D; + } + + #cpu { + background-color: ${c.cyan}; + color: #000000; + } + + #memory { + background-color: ${c.yellow}; + color: #000000; + } + + #network { + background-color: #2980b9; + } + + #network.disconnected { + background-color: #f53c3c; + } + + #pulseaudio { + background-color: #f1c40f; + color: #000000; + } + + #pulseaudio.muted { + background-color: #90b1b1; + color: #2a5c45; + } + + #wireplumber { + background-color: #fff0f5; + color: #000000; + } + + #wireplumber.muted { + background-color: #f53c3c; + } + + #tray { + background-color: #2980b9; + } + + #tray > .passive { + -gtk-icon-effect: dim; + } + + #tray > .needs-attention { + -gtk-icon-effect: highlight; + background-color: #eb4d4b; + } + + #mpd { + background-color: #66cc99; + color: #2a5c45; + } + + #mpd.disconnected { + background-color: #f53c3c; + } + + #mpd.stopped { + background-color: #90b1b1; + } + + #mpd.paused { + background-color: #51a37a; + } + ''; + # background-color: rgba(0,0,0,0); + # border-bottom: 3px solid rgba(100, 114, 125, 0.5); + + #style = '' + #''; + }; +} diff --git a/home/services/dunst.nix b/home/services/dunst.nix index fb0f14f..e07f46e 100644 --- a/home/services/dunst.nix +++ b/home/services/dunst.nix @@ -13,9 +13,9 @@ class = "Dunst"; browser = "${pkgs.xdg-utils}/bin/xdg-open"; - offset = let - status-bar-height = config.services.polybar.settings."bar/top".height; - in "15x${toString (status-bar-height + 10)}"; + # offset = let + # status-bar-height = config.services.polybar.settings."bar/top".height; + # in "15x${toString (status-bar-height + 10)}"; corner_radius = 0; font = "Droid Sans 9"; diff --git a/hosts/common/default.nix b/hosts/common/default.nix index 12975d2..874e502 100644 --- a/hosts/common/default.nix +++ b/hosts/common/default.nix @@ -270,7 +270,14 @@ in { touchpad.disableWhileTyping = true; }; - displayManager.defaultSession = "none+xmonad"; + displayManager = { + enable = true; + defaultSession = "none+xmonad"; + sddm = { + enable = !config.machineVars.headless; + wayland.enable = true; + }; + }; xserver = { enable = !config.machineVars.headless; @@ -280,12 +287,12 @@ in { options = "caps:escape"; }; - desktopManager = { - xterm.enable = false; - xfce.enable = !config.machineVars.headless; - }; + # desktopManager = { + # xterm.enable = false; + # xfce.enable = !config.machineVars.headless; + # }; - displayManager.lightdm.enable = !config.machineVars.headless; + # displayManager.lightdm.enable = !config.machineVars.headless; windowManager.xmonad = { enable = true; @@ -295,9 +302,7 @@ in { dbus ]; }; - }; - }; programs = { @@ -306,6 +311,8 @@ in { tmux.enable = true; zsh.enable = true; + hyprland.enable = true; + gnupg.agent.enable = true; gnupg.agent.pinentryPackage = pkgs.pinentry-curses; diff --git a/hosts/kasei/configuration.nix b/hosts/kasei/configuration.nix index cc2f15b..cbb81e4 100644 --- a/hosts/kasei/configuration.nix +++ b/hosts/kasei/configuration.nix @@ -12,6 +12,8 @@ system.stateVersion = "22.05"; + security.pam.services.hyprlock = {}; + boot.binfmt.emulatedSystems = [ "x86_64-windows" "aarch64-linux" @@ -73,7 +75,7 @@ services = { openssh = { enable = true; - settings.X11Forwarding = true; + # settings.X11Forwarding = true; }; xserver.videoDrivers = [ "amdgpu" ]; tailscale.enable = true; diff --git a/overlays/wayland-ime-integration.nix b/overlays/wayland-ime-integration.nix new file mode 100644 index 0000000..cc87c67 --- /dev/null +++ b/overlays/wayland-ime-integration.nix @@ -0,0 +1,20 @@ +final: prev: let + inherit (prev) lib; + + wrapWithWaylandIMEFlag = pkg: let + binaryName = lib.removePrefix "${lib.getBin pkg}/bin/" (lib.getExe pkg); + in pkg.overrideAttrs (prev': { + postInstall = (prev'.postInstall or "") + '' + wrapProgram "$out/bin/${binaryName}" \ + --add-flags "--enable-wayland-ime" + ''; + }); + + programList = [ + "element-desktop" + "vscode" + "chromium" + "discord" + ]; +in + lib.genAttrs programList (name: wrapWithWaylandIMEFlag prev.${name})