From 892b62a3129a6ae30fa6b039e3f88d370d418319 Mon Sep 17 00:00:00 2001 From: Arpit Chakladar Date: Sat, 25 Jul 2026 11:50:05 +0530 Subject: feat(hyprland): migrate config to Lua, fix API calls, switch to hyprpaper - Set configType = "lua" for Hyprland 0.55+ Lua config format - Rewrite window rules to use hl.window_rule({...}) table API - Convert keybindings to hl.bind() with _args + mkLuaInline - Fix dispatchers: hl.dsp.focus (not window.focus), hl.dsp.focus({workspace=}) (not workspace.switch) - Replace swaybg with services.hyprpaper module for wallpaper - Fix border colors to use base07 (white) / base03 (grey) with rgba() format - Reduce default font size from 16 to 12 --- modules/desktop/default.nix | 18 +--- modules/desktop/hyprland/default.nix | 126 ++++++++++++++++++++++++++ modules/desktop/hyprland/keybindings.nix | 147 +++++++++++++++++++++++++++++++ modules/desktop/i3/default.nix | 103 ---------------------- modules/desktop/i3/keybindings.nix | 90 ------------------- modules/desktop/xdg/default.nix | 25 ++++-- modules/fonts/default.nix | 2 +- 7 files changed, 294 insertions(+), 217 deletions(-) create mode 100644 modules/desktop/hyprland/default.nix create mode 100644 modules/desktop/hyprland/keybindings.nix delete mode 100644 modules/desktop/i3/default.nix delete mode 100644 modules/desktop/i3/keybindings.nix (limited to 'modules') diff --git a/modules/desktop/default.nix b/modules/desktop/default.nix index eb2eea6..a2fdfc8 100644 --- a/modules/desktop/default.nix +++ b/modules/desktop/default.nix @@ -1,4 +1,4 @@ -# Desktop - Desktop environment configuration (i3, GTK, polybar) +# Desktop - Desktop environment configuration (i3/Hyprland, GTK, polybar) { lib, config, @@ -6,10 +6,10 @@ }: { imports = [ - ./i3 ./gtk ./polybar ./xdg + ./hyprland ]; options.desktop = { @@ -18,19 +18,5 @@ config = lib.mkIf config.desktop.enable { xdg.enable = true; - xsession.enable = true; - - home.file.".xinitrc" = { - text = '' - #!/usr/bin/env sh - - [ -f ~/.Xresources ] && xrdb -merge ~/.Xresources - [ -f ~/.profile ] && . ~/.profile - [ -f ~/.xsession ] && . ~/.xsession - - exec ${config.xsession.windowManager.i3.package}/bin/i3 - ''; - executable = true; - }; }; } diff --git a/modules/desktop/hyprland/default.nix b/modules/desktop/hyprland/default.nix new file mode 100644 index 0000000..bd80157 --- /dev/null +++ b/modules/desktop/hyprland/default.nix @@ -0,0 +1,126 @@ +{ + config, + lib, + pkgs, + ... +}: +let + toHyprColor = hex: "rgba(${lib.removePrefix "#" hex}ff)"; +in +{ + imports = [ + ./keybindings.nix + ]; + + options.desktop.hyprland = { + enable = lib.mkEnableOption "Hyprland Wayland compositor"; + }; + + config = lib.mkIf config.desktop.hyprland.enable { + wayland.windowManager.hyprland = { + enable = true; + configType = "lua"; + xwayland.enable = true; + systemd.enable = true; + + settings = { + mainMod = { + _var = "SUPER"; + }; + + config = { + general = with config.scheme.withHashtag; { + gaps_in = 5; + gaps_out = 5; + border_size = 1; + col = { + active_border = { + colors = [ (toHyprColor base07) ]; + angle = 45; + }; + inactive_border = toHyprColor base03; + }; + layout = "dwindle"; + }; + + decoration = { + rounding = 0; + }; + + input = { + follow_mouse = 1; + kb_layout = "us"; + }; + + dwindle = { + preserve_split = true; + }; + }; + + window_rule = [ + { + name = "float-file-explorer"; + match.class = "^(file-explorer)$"; + float = true; + } + { + name = "size-file-explorer"; + match.class = "^(file-explorer)$"; + size = "1280 720"; + } + { + name = "center-file-explorer"; + match.class = "^(file-explorer)$"; + center = true; + } + + { + name = "float-application-launcher"; + match.class = "^(application-launcher)$"; + float = true; + } + { + name = "size-application-launcher"; + match.class = "^(application-launcher)$"; + size = "800 600"; + } + { + name = "center-application-launcher"; + match.class = "^(application-launcher)$"; + center = true; + } + + { + name = "float-keybindings-viewer"; + match.class = "^(keybindings-viewer)$"; + float = true; + } + { + name = "size-keybindings-viewer"; + match.class = "^(keybindings-viewer)$"; + size = "1280 720"; + } + { + name = "center-keybindings-viewer"; + match.class = "^(keybindings-viewer)$"; + center = true; + } + ]; + }; + }; + + services.hyprpaper = lib.mkIf config.media.feh.enable { + enable = true; + settings = { + preload = [ "${../../../assets/sapling.png}" ]; + wallpaper = [ ",${../../../assets/sapling.png}" ]; + }; + }; + + home.packages = with pkgs; [ + grim + slurp + wl-clipboard + ]; + }; +} diff --git a/modules/desktop/hyprland/keybindings.nix b/modules/desktop/hyprland/keybindings.nix new file mode 100644 index 0000000..09ba822 --- /dev/null +++ b/modules/desktop/hyprland/keybindings.nix @@ -0,0 +1,147 @@ +{ + config, + lib, + ... +}: +let + lua = lib.generators.mkLuaInline; + + bind = key: dispatcher: { + _args = [ + (lua "mainMod .. \" + ${key}\"") + (lua dispatcher) + ]; + }; + + bindRawFlags = key: dispatcher: flags: { + _args = [ + key + (lua dispatcher) + flags + ]; + }; + + execLua = cmd: "hl.dsp.exec_cmd(\"${cmd}\")"; + + execLuaSingle = cmd: "hl.dsp.exec_cmd('${cmd}')"; +in +{ + config.wayland.windowManager.hyprland.settings.bind = lib.flatten [ + # --- General Applications --- + (lib.optionals (config.terminal.fzf.enable && config.terminal.kitty.enable) [ + (bind "R" ( + execLua "${lib.getExe config.terminal.kitty.package} --class application-launcher -e ${lib.getExe config.scripts.fzf-launcher.package}" + )) + ]) + (lib.optionals config.terminal.kitty.enable [ + (bind "Return" (execLua "${lib.getExe config.terminal.kitty.package}")) + (bind "S" ( + execLua "${lib.getExe config.terminal.kitty.package} --title 'Keybindings' --class keybindings-viewer -e ${lib.getExe config.scripts.i3-keybindings.package}" + )) + ]) + (lib.optionals (config.terminal.kitty.enable && config.file-management.yazi.enable) [ + (bind "F" ( + execLua "${lib.getExe config.terminal.kitty.package} --class file-explorer --title 'Yazi' -e ${lib.getExe config.file-management.yazi.package}" + )) + ]) + (bind "Q" "hl.dsp.window.close()") + + # --- Media / Hardware Keys --- + (lib.optionals config.system.brightnessctl.enable [ + (bindRawFlags "XF86MonBrightnessDown" + (execLuaSingle "${lib.getExe config.system.brightnessctl.package} set 5%-") + { + locked = true; + repeating = true; + } + ) + (bindRawFlags "XF86MonBrightnessUp" + (execLuaSingle "${lib.getExe config.system.brightnessctl.package} set +5%") + { + locked = true; + repeating = true; + } + ) + ]) + (lib.optionals config.media.pamixer.enable [ + (bindRawFlags "XF86AudioLowerVolume" + (execLuaSingle "${lib.getExe config.media.pamixer.package} --decrease 5") + { + locked = true; + repeating = true; + } + ) + (bindRawFlags "XF86AudioRaiseVolume" + (execLuaSingle "${lib.getExe config.media.pamixer.package} --increase 5") + { + locked = true; + repeating = true; + } + ) + (bindRawFlags "XF86AudioMute" + (execLuaSingle "${lib.getExe config.media.pamixer.package} --toggle-mute") + { + locked = true; + repeating = true; + } + ) + ]) + (lib.optionals config.media.playerctl.enable [ + (bindRawFlags "XF86AudioPlay" + (execLuaSingle "${lib.getExe config.media.playerctl.package} play-pause") + { + locked = true; + repeating = true; + } + ) + ]) + + # --- Window Management (Vim-style) --- + (bind "H" "hl.dsp.focus({ direction = \"l\" })") + (bind "J" "hl.dsp.focus({ direction = \"d\" })") + (bind "K" "hl.dsp.focus({ direction = \"u\" })") + (bind "L" "hl.dsp.focus({ direction = \"r\" })") + + (bind "SHIFT + H" "hl.dsp.window.move({ direction = \"l\" })") + (bind "SHIFT + J" "hl.dsp.window.move({ direction = \"d\" })") + (bind "SHIFT + K" "hl.dsp.window.move({ direction = \"u\" })") + (bind "SHIFT + L" "hl.dsp.window.move({ direction = \"r\" })") + + (bind "CTRL + H" "hl.dsp.window.resize({ x = -20, y = 0 })") + (bind "CTRL + J" "hl.dsp.window.resize({ x = 0, y = 20 })") + (bind "CTRL + K" "hl.dsp.window.resize({ x = 0, y = -20 })") + (bind "CTRL + L" "hl.dsp.window.resize({ x = 20, y = 0 })") + + (bind "D" "hl.dsp.window.float({ action = \"toggle\" })") + (bind "M" "hl.dsp.window.fullscreen()") + + # --- Workspaces --- + (bind "1" "hl.dsp.focus({ workspace = 1 })") + (bind "2" "hl.dsp.focus({ workspace = 2 })") + (bind "3" "hl.dsp.focus({ workspace = 3 })") + (bind "4" "hl.dsp.focus({ workspace = 4 })") + (bind "5" "hl.dsp.focus({ workspace = 5 })") + (bind "6" "hl.dsp.focus({ workspace = 6 })") + (bind "7" "hl.dsp.focus({ workspace = 7 })") + (bind "8" "hl.dsp.focus({ workspace = 8 })") + (bind "9" "hl.dsp.focus({ workspace = 9 })") + (bind "0" "hl.dsp.focus({ workspace = 10 })") + + (bind "SHIFT + 1" "hl.dsp.window.move({ workspace = 1 })") + (bind "SHIFT + 2" "hl.dsp.window.move({ workspace = 2 })") + (bind "SHIFT + 3" "hl.dsp.window.move({ workspace = 3 })") + (bind "SHIFT + 4" "hl.dsp.window.move({ workspace = 4 })") + (bind "SHIFT + 5" "hl.dsp.window.move({ workspace = 5 })") + (bind "SHIFT + 6" "hl.dsp.window.move({ workspace = 6 })") + (bind "SHIFT + 7" "hl.dsp.window.move({ workspace = 7 })") + (bind "SHIFT + 8" "hl.dsp.window.move({ workspace = 8 })") + (bind "SHIFT + 9" "hl.dsp.window.move({ workspace = 9 })") + (bind "SHIFT + 0" "hl.dsp.window.move({ workspace = 10 })") + + # --- Screenshots --- + (bind "P" (execLuaSingle "grim -g \"$(slurp)\" - | wl-copy")) + (bind "SHIFT + P" ( + execLuaSingle "mkdir -p ~/Pictures/Screenshots && grim -g \"$(slurp)\" ~/Pictures/Screenshots/screenshot-$(date +%Y%m%d-%H%M%S).png" + )) + ]; +} diff --git a/modules/desktop/i3/default.nix b/modules/desktop/i3/default.nix deleted file mode 100644 index b3d0672..0000000 --- a/modules/desktop/i3/default.nix +++ /dev/null @@ -1,103 +0,0 @@ -# i3 - Window manager configuration (gaps, colors, startup, keybindings) -{ - config, - lib, - pkgs, - ... -}: -{ - config = lib.mkIf config.desktop.enable { - xsession.windowManager.i3 = { - enable = true; - config = with config.scheme.withHashtag; { - modifier = "Mod4"; # Super - - bars = [ ]; - - gaps = { - inner = 10; - top = 50; # NOTE: Based on height of polybar - outer = 0; - }; - - window = { - border = 1; - titlebar = false; - }; - - colors = { - focused = { - border = base03; - background = base03; - text = base07; - indicator = base03; - childBorder = base03; - }; - focusedInactive = { - border = base02; - background = base02; - text = base05; - indicator = base02; - childBorder = base02; - }; - unfocused = { - border = base02; - background = base02; - text = base05; - indicator = base02; - childBorder = base02; - }; - }; - - defaultWorkspace = "workspace number 1"; - - window.commands = [ - { - command = "floating enable, resize set 1280 720, move position center"; - criteria.class = "file-explorer"; - } - { - command = "floating enable, resize set 800 600, move position center"; - criteria.class = "application-launcher"; - } - { - command = "floating enable, resize set 1280 720, move position center"; - criteria.class = "keybindings-viewer"; - } - ]; - - focus.followMouse = true; - - startup = [ - { - command = "xrandr -q | grep -w 'connected' | cut -d' ' -f1 | xargs -I{} i3-msg \"workspace 1 output {}\""; - always = false; - notification = false; - } - { - command = - if config.media.feh.enable then - "${lib.getExe pkgs.feh} --bg-scale ${../../../assets/sapling.png}" - else - "xsetroot -solid \"${config.scheme.withHashtag.base00}\""; - always = true; - notification = false; - } - ]; - - keybindings = lib.mkOptionDefault ( - import ./keybindings.nix { - inherit - lib - config - ; - } - ); - }; - extraConfig = '' - exec_always --no-startup-id xrandr -q | grep -w 'connected' | cut -d' ' -f1 | xargs -I{} i3-msg "workspace 1 output {}" - exec_always --no-startup-id "polybar-msg cmd restart" - ''; - }; - }; -} diff --git a/modules/desktop/i3/keybindings.nix b/modules/desktop/i3/keybindings.nix deleted file mode 100644 index 8857e7d..0000000 --- a/modules/desktop/i3/keybindings.nix +++ /dev/null @@ -1,90 +0,0 @@ -# Keybindings - i3 keyboard shortcuts (app launchers, vim directions, workspaces) -{ - lib, - config, -}: -let - mod = "Mod4"; -in -{ - # --- General Applications --- - "${mod}+r" = - lib.mkIf (config.terminal.fzf.enable && config.terminal.kitty.enable) - "exec ${lib.getExe config.terminal.kitty.package} --class application-launcher -e ${lib.getExe config.scripts.fzf-launcher.package}"; - "${mod}+Return" = - lib.mkIf config.terminal.kitty.enable "exec ${lib.getExe config.terminal.kitty.package}"; - "${mod}+f" = - lib.mkIf (config.terminal.kitty.enable && config.file-management.yazi.enable) - "exec ${lib.getExe config.terminal.kitty.package} --class file-explorer --title 'Yazi' -e ${lib.getExe config.file-management.yazi.package}"; - "${mod}+s" = - lib.mkIf config.terminal.kitty.enable "exec ${lib.getExe config.terminal.kitty.package} --title 'Keybindings' --class keybindings-viewer -e ${lib.getExe config.scripts.i3-keybindings.package}"; - "${mod}+q" = "kill"; - - # --- Media / Hardware Keys --- - "XF86MonBrightnessDown" = - lib.mkIf config.system.brightnessctl.enable "exec ${lib.getExe config.system.brightnessctl.package} set 5%-"; - "XF86MonBrightnessUp" = - lib.mkIf config.system.brightnessctl.enable "exec ${lib.getExe config.system.brightnessctl.package} set +5%"; - "XF86AudioLowerVolume" = - lib.mkIf config.media.pamixer.enable "exec ${lib.getExe config.media.pamixer.package} --decrease 5"; - "XF86AudioRaiseVolume" = - lib.mkIf config.media.pamixer.enable "exec ${lib.getExe config.media.pamixer.package} --increase 5"; - "XF86AudioMute" = - lib.mkIf config.media.pamixer.enable "exec ${lib.getExe config.media.pamixer.package} --toggle-mute"; - "XF86AudioPlay" = - lib.mkIf config.media.playerctl.enable "exec ${lib.getExe config.media.playerctl.package} play-pause"; - - # --- Window Management (Vim-style) --- - # Focus - "${mod}+h" = "focus left"; - "${mod}+j" = "focus down"; - "${mod}+k" = "focus up"; - "${mod}+l" = "focus right"; - - # Move/Swap - "${mod}+Shift+h" = "move left"; - "${mod}+Shift+j" = "move down"; - "${mod}+Shift+k" = "move up"; - "${mod}+Shift+l" = "move right"; - - # Resize - "${mod}+Control+h" = "resize shrink width 20 px or 20 ppt"; - "${mod}+Control+j" = "resize grow height 20 px or 20 ppt"; - "${mod}+Control+k" = "resize shrink height 20 px or 20 ppt"; - "${mod}+Control+l" = "resize grow width 20 px or 20 ppt"; - - # Layout Modes - "${mod}+d" = "floating toggle, resize set 1280 720, move position center"; - "${mod}+m" = "fullscreen toggle"; - - # --- Workspaces --- - # Switch to workspace - "${mod}+1" = "workspace number 1"; - "${mod}+2" = "workspace number 2"; - "${mod}+3" = "workspace number 3"; - "${mod}+4" = "workspace number 4"; - "${mod}+5" = "workspace number 5"; - "${mod}+6" = "workspace number 6"; - "${mod}+7" = "workspace number 7"; - "${mod}+8" = "workspace number 8"; - "${mod}+9" = "workspace number 9"; - "${mod}+0" = "workspace number 10"; - - # Move window to workspace - "${mod}+Shift+1" = "move container to workspace number 1; workspace number 1"; - "${mod}+Shift+2" = "move container to workspace number 2; workspace number 2"; - "${mod}+Shift+3" = "move container to workspace number 3; workspace number 3"; - "${mod}+Shift+4" = "move container to workspace number 4; workspace number 4"; - "${mod}+Shift+5" = "move container to workspace number 5; workspace number 5"; - "${mod}+Shift+6" = "move container to workspace number 6; workspace number 6"; - "${mod}+Shift+7" = "move container to workspace number 7; workspace number 7"; - "${mod}+Shift+8" = "move container to workspace number 8; workspace number 8"; - "${mod}+Shift+9" = "move container to workspace number 9; workspace number 9"; - "${mod}+Shift+0" = "move container to workspace number 10; workspace number 10"; - - # --- Screenshots --- - "${mod}+p" = - lib.mkIf config.media.maim.enable "exec \"${lib.getExe config.media.maim.package} -s | xclip -selection clipboard -t image/png\""; - "${mod}+Shift+p" = - lib.mkIf config.media.maim.enable "exec \"mkdir -p ~/Pictures/Screenshots && ${lib.getExe config.media.maim.package} -s ~/Pictures/Screenshots/screenshot-$(date +%Y%m%d-%H%M%S).png\""; -} diff --git a/modules/desktop/xdg/default.nix b/modules/desktop/xdg/default.nix index bf5ac02..5edaf03 100644 --- a/modules/desktop/xdg/default.nix +++ b/modules/desktop/xdg/default.nix @@ -5,19 +5,30 @@ pkgs, ... }: +let + # Hyprland ships its own portal for screensharing/screencasting + portalPkgs = + with pkgs; + [ + xdg-desktop-portal-termfilechooser + ] + ++ lib.optionals config.desktop.hyprland.enable [ + xdg-desktop-portal-hyprland + ] + ++ lib.optionals (!config.desktop.hyprland.enable) [ + xdg-desktop-portal-gtk + ]; + + defaultPortal = if config.desktop.hyprland.enable then "hyprland" else "gtk"; +in { config = lib.mkIf config.desktop.enable { xdg.portal = { enable = true; - extraPortals = with pkgs; [ - xdg-desktop-portal-termfilechooser - xdg-desktop-portal-gtk - ]; + extraPortals = portalPkgs; config.common = { "org.freedesktop.impl.portal.FileChooser" = [ "termfilechooser" ]; - default = [ - "gtk" - ]; + default = [ defaultPortal ]; }; xdgOpenUsePortal = true; }; diff --git a/modules/fonts/default.nix b/modules/fonts/default.nix index 89e1318..2f77b2a 100644 --- a/modules/fonts/default.nix +++ b/modules/fonts/default.nix @@ -27,7 +27,7 @@ size = lib.mkOption { type = lib.types.int; description = "Default font size."; - default = 16; + default = 12; }; }; -- cgit v1.2.3