From e77dec2d942eb3cb622a5519f1f1810bd9b7c634 Mon Sep 17 00:00:00 2001 From: "RingOfStorms (Joshua Bell)" Date: Fri, 19 Sep 2025 17:11:15 -0500 Subject: [PATCH] i3 draft --- common/desktop_environment/i3/default.nix | 64 +++++++++ .../i3/home_manager/i3.nix | 121 ++++++++++++++++++ .../i3/home_manager/polybar.nix | 27 ++++ common/desktop_environment/i3/polybar/config | 51 ++++++++ .../desktop_environment/i3/polybar/launch.sh | 6 + hosts/lio/i3_customizations.nix | 50 ++++++++ 6 files changed, 319 insertions(+) create mode 100644 common/desktop_environment/i3/default.nix create mode 100644 common/desktop_environment/i3/home_manager/i3.nix create mode 100644 common/desktop_environment/i3/home_manager/polybar.nix create mode 100644 common/desktop_environment/i3/polybar/config create mode 100644 common/desktop_environment/i3/polybar/launch.sh create mode 100644 hosts/lio/i3_customizations.nix diff --git a/common/desktop_environment/i3/default.nix b/common/desktop_environment/i3/default.nix new file mode 100644 index 0000000..0644a40 --- /dev/null +++ b/common/desktop_environment/i3/default.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, ... }: +let + ccfg = import ../../config.nix; + cfg_path = [ + ccfg.custom_config_key + "desktopEnvironment" + "i3" + ]; + cfg = lib.attrsets.getAttrFromPath cfg_path config; +in +with lib; +{ + options = { + enable = lib.mkEnableOption "i3 (X11) desktop environment"; + terminalCommand = mkOption { + type = lib.types.str; + default = "foot"; + description = "The terminal command to use."; + }; + extraOptions = mkOption { + type = lib.types.attrs; + default = { }; + description = "Extra options for i3 configuration."; + }; + }; + + config = lib.mkIf cfg.enable { + home-manager = { + sharedModules = [ ./home_manager ]; + }; + + services.greetd = { + enable = true; + vt = 2; + settings = { + default_session = { + command = "${pkgs.greetd.tuigreet}/bin/tuigreet --time --remember --remember-session --cmd '${pkgs.dbus}/bin/dbus-run-session ${pkgs.xorg.xinit}/bin/xinit ${pkgs.i3}/bin/i3'}"; + user = "greeter"; + }; + }; + }; + + # X server + services.xserver.enable = true; + services.xserver.displayManager = { + # kept undefined to allow user selection; greetd is enabled above + }; + + # Environment variables for X11 + environment.sessionVariables = { + XDG_SESSION_TYPE = "x11"; + XDG_CURRENT_DESKTOP = "i3"; + XDG_SESSION_DESKTOP = "i3"; + }; + + environment.systemPackages = with pkgs; [ i3 i3status i3lock i3-gaps polybar maim xclip xterm ]; + + # Enable backlight/brightness control, audio, etc., similar to sway defaults + environment.systemPackages = lib.mkForce (with pkgs; [ polybar maim xclip i3 i3status i3lock i3-gaps pavucontrol btop nemo feh rofi ]); + + # Allow users to add extra options into the generated i3 config + # extraOptions can be appended by home-manager fragment + }; +} diff --git a/common/desktop_environment/i3/home_manager/i3.nix b/common/desktop_environment/i3/home_manager/i3.nix new file mode 100644 index 0000000..c23da74 --- /dev/null +++ b/common/desktop_environment/i3/home_manager/i3.nix @@ -0,0 +1,121 @@ +{ config, lib, pkgs, ... }: +let + ccfg = import ../../config.nix; + cfg_path = [ + ccfg.custom_config_key + "desktopEnvironment" + "i3" + ]; + cfg = lib.attrsets.getAttrFromPath cfg_path config; +in +{ + config = lib.mkIf cfg.enable { + programs.i3 = { + enable = true; + package = pkgs.i3; # i3 window manager + windowManager.command = "i3"; + extraConfig = lib.mkForce ('' +# Generated from sway configuration +set $mod Mod4 +set $term ${cfg.terminalCommand} +set $menu rofi -show drun + +# Input +# Caps lock as escape is handled system-wide in NixOS + +# Focus +bindsym $mod+h focus left +bindsym $mod+l focus right +bindsym $mod+k focus up +bindsym $mod+j focus down + +# Apps +bindsym $mod+Return exec $term +bindsym $mod+space exec ${cfg.menu} +bindsym $mod+q kill +bindsym $mod+Shift+Escape exit +bindsym $mod+Shift+q exec i3lock +bindsym $mod+f floating toggle + +# Workspaces +set $ws1 "1: " +set $ws2 "2: " +set $ws3 "3: " +set $ws4 "4: " +set $ws5 "5: " +set $ws6 "6" +set $ws7 "7" +set $ws8 "8" +set $ws9 "9" +set $ws10 "10" + +bindsym $mod+1 workspace $ws1 +bindsym $mod+n workspace $ws1 +bindsym $mod+2 workspace $ws2 +bindsym $mod+m workspace $ws2 +bindsym $mod+3 workspace $ws3 +bindsym $mod+comma workspace $ws3 +bindsym $mod+4 workspace $ws4 +bindsym $mod+period workspace $ws4 +bindsym $mod+5 workspace $ws5 +bindsym $mod+slash workspace $ws5 +bindsym $mod+6 workspace $ws6 +bindsym $mod+7 workspace $ws7 +bindsym $mod+8 workspace $ws8 +bindsym $mod+9 workspace $ws9 +bindsym $mod+0 workspace $ws10 + +# Move windows +bindsym $mod+Shift+h move left +bindsym $mod+Shift+l move right +bindsym $mod+Shift+k move up +bindsym $mod+Shift+j move down +bindsym $mod+Shift+1 move container to workspace $ws1 +bindsym $mod+Shift+n move container to workspace $ws1 +bindsym $mod+Shift+2 move container to workspace $ws2 +bindsym $mod+Shift+m move container to workspace $ws2 +bindsym $mod+Shift+3 move container to workspace $ws3 +bindsym $mod+Shift+comma move container to workspace $ws3 +bindsym $mod+Shift+4 move container to workspace $ws4 +bindsym $mod+Shift+period move container to workspace $ws4 +bindsym $mod+Shift+5 move container to workspace $ws5 +bindsym $mod+Shift+slash move container to workspace $ws5 +bindsym $mod+Shift+6 move container to workspace $ws6 +bindsym $mod+Shift+7 move container to workspace $ws7 +bindsym $mod+Shift+8 move container to workspace $ws8 +bindsym $mod+Shift+9 move container to workspace $ws9 +bindsym $mod+Shift+0 move container to workspace $ws10 + +# Mouse +floating_modifier $mod + +# Screenshot (uses grim/slurp on Wayland; on X11 use maim) +bindsym Print exec --no-startup-id maim -s | xclip -selection clipboard -t image/png + +# Startup +exec --no-startup-id ${pkgs.bash}/bin/sh -c '~/.config/polybar/launch.sh' + +# gaps, borders handled by i3-gaps if available +include ~/.config/i3/custom.conf +'') ; + }; + + home.file = { + ".config/i3/config" = { + text = builtins.toString (config.programs.i3.extraConfig); + }; + ".config/i3/custom.conf" = { + text = let + extra = cfg.extraOptions or {}; + mkWorkspaceAssign = ws: out: "workspace \"${ws}\" output ${out}\n"; + wsAssigns = if extra.workspaceOutputAssign == null then "" else + lib.concatStringsSep "" (lib.map (v: mkWorkspaceAssign v.workspace v.output) extra.workspaceOutputAssign); + startupLines = if extra.startup == null then "" else + lib.concatStringsSep "" (lib.map (s: "exec --no-startup-id ${s.command}\n") extra.startup); + in wsAssigns + startupLines; + }; + }; + + environment.systemPackages = with pkgs; [ i3 i3status polybar maim xclip i3lock i3-gaps ]; + }; +} diff --git a/common/desktop_environment/i3/home_manager/polybar.nix b/common/desktop_environment/i3/home_manager/polybar.nix new file mode 100644 index 0000000..f9ad455 --- /dev/null +++ b/common/desktop_environment/i3/home_manager/polybar.nix @@ -0,0 +1,27 @@ +{ config, lib, pkgs, ... }: +let + ccfg = import ../../config.nix; + cfg_path = [ + ccfg.custom_config_key + "desktopEnvironment" + "i3" + "polybar" + ]; + cfg = lib.attrsets.getAttrFromPath cfg_path config; +in +{ + config = lib.mkIf cfg.enable { + home.file = { + ".config/polybar/config" = { + text = builtins.readFile ../polybar/config; + }; + ".config/polybar/launch.sh" = { + text = builtins.readFile ../polybar/launch.sh; + executable = true; + }; + }; + + home.packages = [ pkgs.polybar ]; + services.xserver.windowManager.i3.enable = true; + }; +} diff --git a/common/desktop_environment/i3/polybar/config b/common/desktop_environment/i3/polybar/config new file mode 100644 index 0000000..3145c9c --- /dev/null +++ b/common/desktop_environment/i3/polybar/config @@ -0,0 +1,51 @@ +[bar/top] +width = 100% +height = 28 +background = #1a1b26 +foreground = #c0caf5 +modules-left = workspace +modules-center = date cpu memory +modules-right = pulseaudio battery network + +environment = { + TERM = xterm-256color +} + +[module/workspace] +type = internal/xworkspaces +pin-workspaces = true +wrap-scroll = false +; icons for numbers +format-underline = #7dcae4 +label = %name% +label-foreground = #c0caf5 + +[module/date] +type = internal/date +interval = 5 +format = %b %d, %H:%M + +[module/cpu] +type = internal/cpu +format = 󰻠 %percentage:2.0%% + +[module/memory] +type = internal/memory +format = 󰍛 %used_percent%% + +[module/pulseaudio] +type = internal/pulseaudio +format = {volume}% + +[module/battery] +type = internal/battery +battery = BAT0 +adapter = AC +format-charging = %percentage%% +format-discharging = %percentage%% + +[module/network] +type = internal/network +interface = auto +format-connected = 󰤨 %essid% (%signal_strength%%) +format-disconnected = 󰖪 Disconnected diff --git a/common/desktop_environment/i3/polybar/launch.sh b/common/desktop_environment/i3/polybar/launch.sh new file mode 100644 index 0000000..b394ebb --- /dev/null +++ b/common/desktop_environment/i3/polybar/launch.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Launch polybar on each connected monitor +MONITORS=$(xrandr --query | grep " connected" | cut -d' ' -f1) +for m in $MONITORS; do + MONITOR=$m polybar --reload top & +done diff --git a/hosts/lio/i3_customizations.nix b/hosts/lio/i3_customizations.nix new file mode 100644 index 0000000..b82cbc8 --- /dev/null +++ b/hosts/lio/i3_customizations.nix @@ -0,0 +1,50 @@ +{ ... }: +let + i3ExtraOptions = { + startup = [ + { + command = "exec sh -c 'sleep 0.01; i3-msg workspace 7; sleep 0.02; i3-msg workspace 1'"; + } + ]; + + # Example: map workspaces 1–6 to DP-1 and 7–10 to DP-2 + workspaceOutputAssign = [ + { workspace = "1"; output = "DP-1"; } + { workspace = "2"; output = "DP-1"; } + { workspace = "3"; output = "DP-1"; } + { workspace = "4"; output = "DP-1"; } + { workspace = "5"; output = "DP-1"; } + { workspace = "6"; output = "DP-1"; } + { workspace = "7"; output = "DP-2"; } + { workspace = "8"; output = "DP-2"; } + { workspace = "9"; output = "DP-2"; } + { workspace = "10"; output = "DP-2"; } + ]; + + # Optional output settings + output = { + "DP-1" = { + scale = "1"; + pos = "0 0"; + mode = "3840x2160@97.983Hz"; + bg = "${./wallpapers/pixel_neon.png} fill"; + }; + "DP-2" = { + scale = "1"; + transform = "270"; + pos = "-1440 -640"; + mode = "3440x1440@99.982Hz"; + bg = "${./wallpapers/pixel_neon_v.png} fill"; + }; + }; + }; +in +{ + options = { }; + + config = { + environment.systemPackages = [ ]; + + ringofstorms_common.desktopEnvironment.i3.extraOptions = i3ExtraOptions; + }; +}