{ config, lib, pkgs, ... }: let mod = "Mod4"; solarized = import ../common/solarized.nix; # TODO pull this out into lib emacsclient = eval: pkgs.writeShellScript "emacsclient-eval" '' msg=$(emacsclient --eval '${eval}' 2>&1) echo "''${msg:1:-1}" ''; screenlayout = { home = pkgs.writeShellScript "screenlayout_home.sh" '' xrandr \ --output eDP-1 --mode 1920x1200 --pos 0x960 --rotate normal \ --output DP-3 --primary --mode 3840x2160 --pos 1920x0 --rotate normal \ --output DP-1 --off \ --output DP-2 --off \ --output DP-4 --off ''; }; inherit (builtins) map; inherit (lib) mkMerge range; in { options = with lib; { system.machine = { wirelessInterface = mkOption { description = '' Name of the primary wireless interface. Used by i3status, etc. ''; default = "wlp3s0"; type = types.str; }; i3FontSize = mkOption { description = "Font size to use in i3 window decorations etc."; default = 6; type = types.int; }; battery = mkOption { description = "Does this system have a battery?"; default = true; type = types.bool; }; }; }; config = let fontName = "MesloLGSDZ"; fontSize = config.system.machine.i3FontSize; fonts = { names = [ fontName ]; size = fontSize * 1.0; }; decorationFont = "${fontName} ${toString fontSize}"; in { home.packages = with pkgs; [ rofi rofi-pass python3Packages.py3status i3lock i3status dconf # for gtk # Screenshots maim # GIFs picom peek (pkgs.writeShellScriptBin "lock" '' playerctl pause ${pkgs.i3lock}/bin/i3lock -c 222222 '') ]; xsession.scriptPath = ".xsession"; xsession.windowManager.i3 = { enable = true; config = { modifier = mod; keybindings = mkMerge ( (map (n: { "${mod}+${toString n}" = "workspace ${toString n}"; "${mod}+Shift+${toString n}" = "move container to workspace ${toString n}"; }) (range 0 9)) ++ [ (rec { "${mod}+h" = "focus left"; "${mod}+j" = "focus down"; "${mod}+k" = "focus up"; "${mod}+l" = "focus right"; "${mod}+semicolon" = "focus parent"; "${mod}+Shift+h" = "move left"; "${mod}+Shift+j" = "move down"; "${mod}+Shift+k" = "move up"; "${mod}+Shift+l" = "move right"; "${mod}+Shift+x" = "kill"; "${mod}+Return" = "exec alacritty"; "${mod}+Shift+s" = "split h"; "${mod}+Shift+v" = "split v"; "${mod}+e" = "layout toggle split"; "${mod}+w" = "layout tabbed"; "${mod}+s" = "layout stacking"; "${mod}+f" = "fullscreen"; "${mod}+Shift+r" = "restart"; "${mod}+r" = "mode resize"; # Marks "${mod}+Shift+m" = ''exec i3-input -F "mark %s" -l 1 -P 'Mark: ' ''; "${mod}+m" = ''exec i3-input -F '[con_mark="%s"] focus' -l 1 -P 'Go to: ' ''; # Screenshots "${mod}+q" = "exec \"maim | xclip -selection clipboard -t image/png\""; "${mod}+Shift+q" = "exec \"maim -s | xclip -selection clipboard -t image/png\""; "${mod}+Ctrl+q" = "exec ${pkgs.writeShellScript "peek.sh" '' ${pkgs.picom}/bin/picom & picom_pid=$! ${pkgs.peek}/bin/peek || true kill -SIGINT $picom_pid ''}"; # Launching applications "${mod}+u" = "exec ${pkgs.writeShellScript "rofi" '' rofi \ -modi 'combi' \ -combi-modi "window,drun,ssh,run" \ -font '${decorationFont}' \ -show combi ''}"; # Passwords "${mod}+p" = "exec rofi-pass -font '${decorationFont}'"; # Media "XF86AudioPlay" = "exec playerctl play-pause"; "XF86AudioNext" = "exec playerctl next"; "XF86AudioPrev" = "exec playerctl previous"; "XF86AudioRaiseVolume" = "exec pulseaudio-ctl up"; "XF86AudioLowerVolume" = "exec pulseaudio-ctl down"; "XF86AudioMute" = "exec pulseaudio-ctl mute"; # Lock Pause = "exec lock"; # Brightness "XF86MonBrightnessDown" = "exec ${pkgs.brightnessctl}/bin/brightnessctl -q s 5%-"; "XF86MonBrightnessUp" = "exec ${pkgs.brightnessctl}/bin/brightnessctl -q s 5%+"; # Sleep/hibernate # "${mod}+Escape" = "exec systemctl suspend"; # "${mod}+Shift+Escape" = "exec systemctl hibernate"; # Scratch buffer "${mod}+minus" = "scratchpad show"; "${mod}+Shift+minus" = "move scratchpad"; "${mod}+space" = "focus mode_toggle"; "${mod}+Shift+space" = "floating toggle"; # Screen Layout "${mod}+Shift+t" = "exec xrandr --auto"; "${mod}+t" = "exec ${screenlayout.home}"; "${mod}+Ctrl+t" = "exec ${pkgs.writeShellScript "fix_term.sh" '' xrandr --output eDP-1 --off && ${screenlayout.home} ''}"; # Notifications "${mod}+Shift+n" = "exec killall -SIGUSR1 .dunst-wrapped"; "${mod}+n" = "exec killall -SIGUSR2 .dunst-wrapped"; "Control+space" = "exec ${pkgs.dunst}/bin/dunstctl close"; "Control+Shift+space" = "exec ${pkgs.dunst}/bin/dunstctl close-all"; "Control+grave" = "exec ${pkgs.dunst}/bin/dunstctl history-pop"; "Control+Shift+period" = "exec ${pkgs.dunst}/bin/dunstctl action"; }) ] ); inherit fonts; colors = with solarized; rec { focused = { border = base01; background = base01; text = base3; indicator = red; childBorder = base02; }; focusedInactive = focused // { border = base03; background = base03; # text = base1; }; unfocused = focusedInactive; background = base03; }; modes.resize = { l = "resize shrink width 5 px or 5 ppt"; k = "resize grow height 5 px or 5 ppt"; j = "resize shrink height 5 px or 5 ppt"; h = "resize grow width 5 px or 5 ppt"; Return = "mode \"default\""; }; bars = [{ statusCommand = let i3status-conf = pkgs.writeText "i3status.conf" '' general { output_format = i3bar colors = true color_good = "#859900" interval = 1 } order += "external_script current_task" order += "external_script inbox" order += "spotify" order += "volume_status" order += "wireless ${config.system.machine.wirelessInterface}" # order += "ethernet enp3s0f0" order += "cpu_usage" ${lib.optionalString (config.system.machine.battery) '' order += "battery 0" ''} # order += "volume master" order += "time" order += "tztime utc" mpd { format = "%artist - %album - %title" } wireless ${config.system.machine.wirelessInterface} { format_up = "W: (%quality - %essid - %bitrate) %ip" format_down = "W: -" } ethernet enp3s0f0 { format_up = "E: %ip" format_down = "E: -" } battery 0 { format = "%status %percentage" path = "/sys/class/power_supply/BAT%d/uevent" low_threshold = 10 } cpu_usage { format = "CPU: %usage" } load { format = "%5min" } time { format = " %a %h %d ⌚ %I:%M " } spotify { color_playing = "#fdf6e3" color_paused = "#93a1a1" format_stopped = "" format_down = "" format = "{title} - {artist} ({album})" } external_script inbox { script_path = '${emacsclient "(grfn/num-inbox-items-message)"}' format = 'Inbox: {output}' cache_timeout = 120 color = "#93a1a1" } external_script current_task { script_path = '${emacsclient "(grfn/org-current-clocked-in-task-message)"}' # format = '{output}' cache_timeout = 60 color = "#93a1a1" } tztime utc { timezone = "UTC" format = " %H·%M " } volume_status { format = "☊ {percentage}" format_muted = "☊ X" # device = "default" # mixer_idx = 0 } ''; in "py3status -c ${i3status-conf}"; inherit fonts; position = "top"; colors = with solarized; rec { background = base03; statusline = base3; separator = base1; activeWorkspace = { border = base03; background = base1; text = base3; }; focusedWorkspace = activeWorkspace; inactiveWorkspace = activeWorkspace // { background = base01; }; urgentWorkspace = activeWorkspace // { background = red; }; }; }]; }; }; services.dunst = { enable = true; settings = with solarized; { global = { font = "MesloLGSDZ ${toString (config.system.machine.i3FontSize * 1.5)}"; allow_markup = true; format = "<b>%s</b>\n%b"; sort = true; alignment = "left"; geometry = "600x15-40+40"; idle_threshold = 120; separator_color = "frame"; separator_height = 1; word_wrap = true; padding = 8; horizontal_padding = 8; max_icon_size = 45; }; frame = { width = 0; color = "#aaaaaa"; }; urgency_low = { background = base03; foreground = base3; timeout = 5; }; urgency_normal = { background = base02; foreground = base3; timeout = 7; }; urgency_critical = { background = red; foreground = base3; timeout = 0; }; }; }; gtk = { enable = true; iconTheme.name = "Adwaita"; theme.name = "Adwaita"; }; }; }