{ lib, pkgs, config, ...}: let inherit (lib) mkIf mkEnableOption mkOption types optionals mergeAttrs mergeAttrsList optionalAttrs; cfg = config.chuj.stuff.i3; user = config.chuj.system.user; in { options.chuj.stuff.i3 = { enable = mkEnableOption "i3"; workspaceOutput = mkOption { type = types.attrsOf types.str; default = {}; }; communicators = mkOption { type = types.submodule { options = { autostart = mkOption { type = types.bool; default = false; }; workspace = mkOption { type = types.str; default = ""; }; }; }; default = {}; }; battery = mkEnableOption "battery"; mediaKeys = mkOption { type = types.submodule { options = let mkKeyOpt = default: mkOption { inherit default; type = types.str; }; in { musicMenu = mkKeyOpt "F5"; musicPlay = mkKeyOpt "F7"; musicPrev = mkKeyOpt "F6"; musicNext = mkKeyOpt "F8"; audioMute = mkKeyOpt "F9"; audioDown = mkKeyOpt "F10"; audioUp = mkKeyOpt "F11"; }; }; default = {}; }; }; config = let HOME = config.home-manager.users.${user}.home.homeDirectory; in mkIf cfg.enable { services.xserver.windowManager.i3.enable = true; home-manager.users.${user} = { xsession.windowManager.i3 = { enable = true; config = rec { assigns = mkIf (cfg.communicators.workspace != "") { ${cfg.communicators.workspace} = [ { class = "discord"; } { class = "SchildiChat"; } { class = "element"; } ]; }; window = { border = 1; titlebar = true; }; floating = { border = 1; titlebar = true; criteria = [ { class = "zenity"; } { class = "fceux"; } { title = "Friends List"; } ]; }; gaps = { inner = 0; outer = 0; }; fonts = { names = [ "JetBrains Mono NL" ]; size = 10.0; }; defaultWorkspace = "workspace number 1"; workspaceOutputAssign = lib.mapAttrsToList (workspace: output: { inherit workspace output; }) cfg.workspaceOutput; focus = { followMouse = true; mouseWarping = true; newWindow = "urgent"; }; startup = [] ++ optionals config.chuj.stuff.dunst.enable [{ command = "dunst &"; notification = false; }] ++ optionals config.chuj.stuff.flameshot.enable [{ command = "flameshot &"; notification = false; }] ++ optionals cfg.communicators.autostart [ # { command = "i3-msg \"workspace ${cfg.communicators.workspace}; append_layout ${../../files/i3_communicators_layout.json}\""; notification = false; } # { command = "discord &"; notification = false; } { command = "schildichat-desktop &"; notification = false; } ] ++ optionals config.chuj.stuff.mpd.enable [ { command = "${pkgs.writeShellScriptBin "mpdstatus" '' trap "echo SIG" USR1 EXIT while true; do sleep 1 & wait status=$(mpc status | sed -n 2p | cut -d' ' -f1) title=$(basename "$(mpc current -f '%file%')" .mp3) echo "$status $title" > /tmp/i3-mpd-status-stuff echo update!! done ''}/bin/mpdstatus &"; notification = false; } ]; modes = let cmd_and_center = cmd: "exec --no-startup-id i3-msg '${cmd}' && i3-center-mouse-on-focus"; in { resize = { "Left" = cmd_and_center "resize shrink width 10 px or 10 ppt"; "Right" = cmd_and_center "resize grow width 10 px or 10 ppt"; "Up" = cmd_and_center "resize shrink height 10 px or 10 ppt"; "Down" = cmd_and_center "resize grow height 10 px or 10 ppt"; "Escape" = "mode default"; }; }; modifier = "Mod4"; floating.modifier = "Mod4"; keybindings = with config.chuj.stuff.i3.mediaKeys; let mod = modifier; execns = "exec --no-startup-id"; cmd_and_center = cmd: "${execns} i3-msg '${cmd}' && i3custom-center-mouse-on-focus"; killall = "${pkgs.killall}/bin/killall"; update_mpdstatus = "${killall} -USR1 mpdstatus && sleep 0.05"; # hack as fack xd update_i3status = "${killall} -USR1 i3status"; in mergeAttrs { # Program keybinds "${mod}+Return" = ''${execns} ${if config.chuj.stuff.alacritty.enable then "alacritty" else "i3-sensible-terminal"}''; "${mod}+Shift+s" = mkIf config.chuj.stuff.flameshot.enable "${execns} flameshot gui"; "${mod}+b" = mkIf config.chuj.stuff.firefox.enable "${execns} firefox"; "${mod}+d" = "${execns} dmenu_run"; "--release ${mod}+k" = "${execns} xkill"; # Volume control "Ctrl+${audioMute}" = "${execns} pamixer --toggle-mute && ${update_i3status}"; "Ctrl+${audioDown}" = "${execns} pamixer --decrease 5 && ${update_i3status}"; "Ctrl+${audioUp}" = "${execns} pamixer --increase 5 && ${update_i3status}"; # General i3 keybindings "${mod}+f" = cmd_and_center "fullscreen toggle"; "${mod}+r" = "mode resize"; "${mod}+Shift+q" = cmd_and_center "kill"; "${mod}+Shift+r" = "restart"; "${mod}+Shift+e" = "${execns} i3-nagbar -t warning -m 'exit?' -b 'yes' 'i3-msg exit'"; # Mouse bindings "--border button3" = "${execns} i3custom-window-actions"; "${mod}+Left" = cmd_and_center "focus left"; "${mod}+Right" = cmd_and_center "focus right"; "${mod}+Up" = cmd_and_center "focus up"; "${mod}+Down" = cmd_and_center "focus down"; "${mod}+Shift+Left" = cmd_and_center "move left"; "${mod}+Shift+Right" = cmd_and_center "move right"; "${mod}+Shift+Up" = cmd_and_center "move up"; "${mod}+Shift+Down" = cmd_and_center "move down"; "${mod}+q" = cmd_and_center "layout stacking"; "${mod}+w" = cmd_and_center "layout tabbed"; "${mod}+e" = cmd_and_center "layout toggle split"; "${mod}+Shift+space" = "floating toggle; ${execns} i3custom-center-mouse-on-focus"; "${mod}+space" = cmd_and_center "focus mode_toggle"; "${mod}+1" = cmd_and_center "workspace number 1"; "${mod}+2" = cmd_and_center "workspace number 2"; "${mod}+3" = cmd_and_center "workspace number 3"; "${mod}+4" = cmd_and_center "workspace number 4"; "${mod}+5" = cmd_and_center "workspace number 5"; "${mod}+6" = cmd_and_center "workspace number 6"; "${mod}+7" = cmd_and_center "workspace number 7"; "${mod}+8" = cmd_and_center "workspace number 8"; "${mod}+9" = cmd_and_center "workspace number 9"; "${mod}+0" = cmd_and_center "workspace number 10"; "${mod}+Shift+1" = cmd_and_center "move container to workspace number 1"; "${mod}+Shift+2" = cmd_and_center "move container to workspace number 2"; "${mod}+Shift+3" = cmd_and_center "move container to workspace number 3"; "${mod}+Shift+4" = cmd_and_center "move container to workspace number 4"; "${mod}+Shift+5" = cmd_and_center "move container to workspace number 5"; "${mod}+Shift+6" = cmd_and_center "move container to workspace number 6"; "${mod}+Shift+7" = cmd_and_center "move container to workspace number 7"; "${mod}+Shift+8" = cmd_and_center "move container to workspace number 8"; "${mod}+Shift+9" = cmd_and_center "move container to workspace number 9"; "${mod}+Shift+0" = cmd_and_center "move container to workspace number 10"; } (optionalAttrs config.chuj.stuff.mpd.enable { # MPD controls "Ctrl+${musicMenu}" = "exec mpdfdial.sh && ${update_mpdstatus} && ${update_i3status}"; "Ctrl+${musicPrev}" = "exec mpc prev && ${update_mpdstatus} && ${update_i3status}"; "Ctrl+${musicPlay}" = "exec mpc toggle && ${update_mpdstatus} && ${update_i3status}"; "Ctrl+${musicNext}" = "exec mpc next && ${update_mpdstatus} && ${update_i3status}"; "Ctrl+Shift+${musicPrev}" = "exec mpc seek -3"; "Ctrl+Shift+${musicPlay}" = "exec mpc clear && ${update_mpdstatus} && ${update_i3status}"; "Ctrl+Shift+${musicNext}" = "exec mpc seek +3"; "Ctrl+Shift+${audioDown}" = ''exec mpc volume -5 && dunstify "mpc $(mpc volume)" -r 420''; "Ctrl+Shift+${audioUp}" = ''exec mpc volume +5 && dunstify "mpc $(mpc volume)" -r 420''; }); bars = [ { inherit fonts; trayOutput = "primary"; statusCommand = "${pkgs.i3status}/bin/i3status"; } ]; }; }; programs.i3status = { enable = true; enableDefault = false; general = { interval = 1; colors = true; color_good = "#91d956"; color_bad = "#f43841"; color_degraded = "#ffdd33"; output_format = "i3bar"; }; modules = mergeAttrsList [ { "cpu_usage" = { position = 0; settings = { format = "cpu: %usage"; }; }; "memory" = { position = 1; settings = { format = "mem: %used"; threshold_degraded = "1G"; format_degraded = "MEMORY < %available"; }; }; "volume master" = { position = 2; settings = { color_degraded = "#333333"; format = "vol: %volume"; format_muted = "vol: ---"; }; }; "tztime local" = { position = 4; settings = { format = "%Y-%m-%d %H:%M:%S (%A)"; }; }; } (optionalAttrs cfg.battery { "battery 0" = { position = 3; settings = { format = "bat%status: %percentage"; status_chr = "(+)"; status_bat = ""; status_unk = "(?)"; status_full = "(+)"; status_idle = ""; low_threshold = 30; }; }; }) (optionalAttrs config.chuj.stuff.mpd.enable { "read_file mpd" = { position = -1; settings = { format = "%content"; format_bad = "mpdstatus file not found, restart i3"; path = "/tmp/i3-mpd-status-stuff"; color_good = "#ffffff"; }; }; }) ]; }; home.packages = with pkgs; [ (pkgs.writeShellScriptBin "i3custom-center-mouse-on-focus" '' eval $(xdotool getwindowfocus getwindowgeometry --shell) MX=$(($X + $WIDTH / 2)) MY=$(($Y + $HEIGHT / 2)) xdotool mousemove $MX $MY '') (pkgs.writeShellScriptBin "i3custom-window-actions" '' ${pkgs.yad}/bin/yad --splash --mouse \ --title="i3 window actions" \ --gtkrc="${HOME}/.config/i3/i3gtk.css" \ --text="i3 window actions" \ --button float:0 --button kill:1 case $? in 0) i3-msg "floating toggle";; 1) i3-msg "kill";; -1) ;; esac '') (pkgs.writeShellScriptBin "i3custom-floating-toggle" '' i3-msg "mark --add _; [con_mark=f] floating disable, border pixel 1, mark --add --toggle _; [con_mark=_] floating enable, border normal; mark --add --toggle f;" '') ]; home.file = { ".config/i3/i3gtk.css".source = ../../files/i3gtk.css; }; }; }; }