516 lines
21 KiB
Nix
516 lines
21 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
with lib; {
|
|
options.lwad.applications.i3 = {
|
|
enable = mkEnableOption "i3wm";
|
|
modifiers = {
|
|
primary = mkOption {
|
|
default = "Mod4";
|
|
description = "Primary modifier to use.";
|
|
type = types.str;
|
|
};
|
|
alternative = mkOption {
|
|
default = "Mod1";
|
|
description = "Alternative modifier to use.";
|
|
type = types.str;
|
|
};
|
|
};
|
|
};
|
|
imports = [
|
|
./audioControls.nix
|
|
./autoRun.nix
|
|
./backlight.nix
|
|
./displayProperties.nix
|
|
./moveDisplayUp.nix
|
|
./outputWorkspaceMappings.nix
|
|
];
|
|
config = let cfg = config.lwad.applications.i3;
|
|
in mkIf cfg.enable {
|
|
home-manager.users.${config.lwad.definitions.username} =
|
|
let colors = config.lwad.definitions.theme.colors;
|
|
in {
|
|
programs.rofi = {
|
|
enable = true;
|
|
font = "FiraCode Nerd Font 11";
|
|
location = "top";
|
|
package = pkgs.rofi;
|
|
terminal = config.lwad.applications.terminalEmulator.default;
|
|
theme = builtins.toFile "rofi-theme" ''
|
|
* {
|
|
/* Colors. */
|
|
red: rgba ( 190, 42, 73, 100 % );
|
|
blue: rgba ( 167, 214, 247, 100 % );
|
|
|
|
/* Selected entry (normal). */
|
|
selected-normal-foreground: ${colors.text};
|
|
selected-normal-background: ${colors.menu_background};
|
|
|
|
/* Selected entry (active). */
|
|
selected-active-foreground: @selected-normal-foreground;
|
|
selected-active-background: @selected-normal-background;
|
|
|
|
/* Selected entry (urgent). */
|
|
selected-urgent-foreground: @selected-normal-foreground;
|
|
selected-urgent-background: @selected-normal-background;
|
|
|
|
/* Unselected entry (normal). */
|
|
foreground: ${colors.text};
|
|
background: ${colors.background};
|
|
normal-foreground: @foreground;
|
|
normal-background: @background;
|
|
|
|
/* Unselected entry (active). */
|
|
active-foreground: @normal-foreground;
|
|
active-background: @normal-background;
|
|
|
|
/* Unselected entry (urgent). */
|
|
urgent-foreground: @normal-foreground;
|
|
urgent-background: @normal-background;
|
|
|
|
/* Unselected entry (alternate). */
|
|
alternate-normal-foreground: @normal-foreground;
|
|
alternate-normal-background: @normal-background;
|
|
|
|
/* Unselected entry (alternate active). */
|
|
alternate-active-foreground: @normal-foreground;
|
|
alternate-active-background: @normal-background;
|
|
|
|
/* Unselected entry (alternate urgent). */
|
|
alternate-urgent-foreground: @normal-foreground;
|
|
alternate-urgent-background: @normal-background;
|
|
|
|
/* Search box. */
|
|
background-color: @normal-background;
|
|
|
|
/* Other. */
|
|
spacing: 0;
|
|
border-color: ${colors.highlight};
|
|
separatorcolor: @normal-background;
|
|
|
|
/* Unknown. */
|
|
lightfg: rgba ( 0, 0, 0, 0 % );
|
|
lightbg: rgba ( 0, 0, 0, 0 % );
|
|
}
|
|
window {
|
|
background-color: @background;
|
|
border: 3;
|
|
padding: 3;
|
|
}
|
|
mainbox {
|
|
border: 0;
|
|
padding: 0;
|
|
}
|
|
message {
|
|
border: 2px 0px 0px ;
|
|
border-color: @separatorcolor;
|
|
padding: 1px ;
|
|
}
|
|
textbox {
|
|
text-color: @foreground;
|
|
}
|
|
listview {
|
|
fixed-height: 0;
|
|
border: 2px 0px 0px ;
|
|
border-color: @separatorcolor;
|
|
scrollbar: true;
|
|
padding: 2px 0px 0px ;
|
|
}
|
|
element {
|
|
border: 0;
|
|
padding: @spacing;
|
|
}
|
|
element-text {
|
|
background-color: inherit;
|
|
text-color: inherit;
|
|
}
|
|
element.normal.normal {
|
|
background-color: @normal-background;
|
|
text-color: @normal-foreground;
|
|
}
|
|
element.normal.urgent {
|
|
background-color: @urgent-background;
|
|
text-color: @urgent-foreground;
|
|
}
|
|
element.normal.active {
|
|
background-color: @active-background;
|
|
text-color: @active-foreground;
|
|
}
|
|
element.selected.normal {
|
|
background-color: @selected-normal-background;
|
|
text-color: @selected-normal-foreground;
|
|
}
|
|
element.selected.urgent {
|
|
background-color: @selected-urgent-background;
|
|
text-color: @selected-urgent-foreground;
|
|
}
|
|
element.selected.active {
|
|
background-color: @selected-active-background;
|
|
text-color: @selected-active-foreground;
|
|
}
|
|
element.alternate.normal {
|
|
background-color: @alternate-normal-background;
|
|
text-color: @alternate-normal-foreground;
|
|
}
|
|
element.alternate.urgent {
|
|
background-color: @alternate-urgent-background;
|
|
text-color: @alternate-urgent-foreground;
|
|
}
|
|
element.alternate.active {
|
|
background-color: @alternate-active-background;
|
|
text-color: @alternate-active-foreground;
|
|
}
|
|
scrollbar {
|
|
width: 0;
|
|
border: 0;
|
|
handle-color: @normal-foreground;
|
|
handle-width: 0;
|
|
padding: 0;
|
|
}
|
|
mode-switcher {
|
|
border: 2px 0px 0px ;
|
|
border-color: @separatorcolor;
|
|
}
|
|
button {
|
|
spacing: 0;
|
|
text-color: @normal-foreground;
|
|
}
|
|
button.selected {
|
|
background-color: @selected-normal-background;
|
|
text-color: @selected-normal-foreground;
|
|
}
|
|
inputbar {
|
|
spacing: 0;
|
|
text-color: @normal-foreground;
|
|
padding: 1px ;
|
|
}
|
|
case-indicator {
|
|
spacing: 0;
|
|
text-color: @normal-foreground;
|
|
}
|
|
entry {
|
|
spacing: 0;
|
|
text-color: @normal-foreground;
|
|
}
|
|
prompt {
|
|
spacing: 0;
|
|
text-color: @normal-foreground;
|
|
}
|
|
inputbar {
|
|
children: [ prompt,textbox-prompt-colon,entry,case-indicator ];
|
|
}
|
|
textbox-prompt-colon {
|
|
expand: false;
|
|
str: ":";
|
|
margin: 0px 0.3em 0em 0em ;
|
|
text-color: @normal-foreground;
|
|
}
|
|
'';
|
|
};
|
|
xsession.windowManager.i3 = {
|
|
enable = true;
|
|
config = let
|
|
mod = cfg.modifiers.primary;
|
|
alt = cfg.modifiers.alternative;
|
|
in {
|
|
bars = mkForce [ ];
|
|
colors = {
|
|
background = colors.near_black;
|
|
focused = {
|
|
background = colors.near_black;
|
|
border = colors.highlight;
|
|
childBorder = colors.highlight;
|
|
indicator = colors.highlight_darker;
|
|
text = colors.text;
|
|
};
|
|
focusedInactive = {
|
|
background = colors.near_black;
|
|
border = colors.near_black;
|
|
childBorder = colors.near_black;
|
|
indicator = colors.near_black;
|
|
text = colors.text;
|
|
};
|
|
placeholder = {
|
|
background = colors.near_black;
|
|
border = colors.near_black;
|
|
childBorder = colors.near_black;
|
|
indicator = colors.near_black;
|
|
text = colors.text;
|
|
};
|
|
unfocused = {
|
|
background = colors.near_black;
|
|
border = colors.near_black;
|
|
childBorder = colors.near_black;
|
|
indicator = colors.near_black;
|
|
text = colors.text;
|
|
};
|
|
urgent = {
|
|
background = colors.near_black;
|
|
border = "#F8E85F";
|
|
childBorder = "#F8E85F";
|
|
indicator = "#F4631A";
|
|
text = colors.text;
|
|
};
|
|
};
|
|
floating = {
|
|
modifier = mod;
|
|
titlebar = false;
|
|
};
|
|
keybindings = mkMerge [
|
|
# Meta.
|
|
{
|
|
"${mod}+Shift+c" = "reload";
|
|
"${mod}+Shift+r" = "restart";
|
|
}
|
|
# Focus movement.
|
|
{
|
|
"${mod}+1" = "workspace 1";
|
|
"${mod}+2" = "workspace 2";
|
|
"${mod}+3" = "workspace 3";
|
|
"${mod}+4" = "workspace 4";
|
|
"${mod}+5" = "workspace 5";
|
|
"${alt}+1" = "workspace 6";
|
|
"${alt}+2" = "workspace 7";
|
|
"${alt}+3" = "workspace 8";
|
|
"${alt}+4" = "workspace 9";
|
|
"${alt}+5" = "workspace 10";
|
|
"${mod}+h" = "focus left";
|
|
"${mod}+j" = "focus down";
|
|
"${mod}+k" = "focus up";
|
|
"${mod}+l" = "focus right";
|
|
"${mod}+a" = "focus parent";
|
|
"${mod}+x" = "focus child";
|
|
"${mod}+space" = "focus mode_toggle";
|
|
}
|
|
# Window movement.
|
|
{
|
|
"${mod}+Shift+1" = "move container to workspace 1";
|
|
"${mod}+Shift+2" = "move container to workspace 2";
|
|
"${mod}+Shift+3" = "move container to workspace 3";
|
|
"${mod}+Shift+4" = "move container to workspace 4";
|
|
"${mod}+Shift+5" = "move container to workspace 5";
|
|
"${alt}+Shift+1" = "move container to workspace 6";
|
|
"${alt}+Shift+2" = "move container to workspace 7";
|
|
"${alt}+Shift+3" = "move container to workspace 8";
|
|
"${alt}+Shift+4" = "move container to workspace 9";
|
|
"${alt}+Shift+5" = "move container to workspace 10";
|
|
"${mod}+Shift+h" = "move left";
|
|
"${mod}+Shift+j" = "move down";
|
|
"${mod}+Shift+k" = "move up";
|
|
"${mod}+Shift+l" = "move right";
|
|
"${mod}+Shift+space" = "floating toggle";
|
|
}
|
|
# Window other.
|
|
{
|
|
"${mod}+Shift+q" = "kill";
|
|
"${mod}+f" = "fullscreen toggle";
|
|
"${mod}+e" = "layout toggle split";
|
|
"${mod}+v" = "split v";
|
|
}
|
|
# Scratchpad management.
|
|
{
|
|
"${mod}+w" = "exec --no-startup-id ${
|
|
let
|
|
i3-msg = "${pkgs.i3}/bin/i3-msg";
|
|
jq = "${pkgs.jq}/bin/jq";
|
|
in pkgs.writeScript "show_from_scratchpad.sh" ''
|
|
class="$(${i3-msg} -t get_tree | ${jq} '.nodes | map(select(.name == "__i3")) | .[].nodes[].nodes[].floating_nodes[].nodes[].window_properties.class' --raw-output | ${pkgs.coreutils}/bin/sort | ${pkgs.coreutils}/bin/uniq | ${pkgs.rofi}/bin/rofi -dmenu -p "Window Class" -i)"
|
|
[[ "$class" != "" ]] && ${i3-msg} [ class="$class" ] scratchpad show
|
|
''
|
|
}";
|
|
"${mod}+Shift+w" = "exec --no-startup-id ${
|
|
let
|
|
i3-msg = "${pkgs.i3}/bin/i3-msg";
|
|
jq = "${pkgs.jq}/bin/jq";
|
|
in pkgs.writeScript "move_to_scratchpad.sh" ''
|
|
${i3-msg} "move scratchpad" > /dev/null
|
|
|
|
last_window_id=$(${i3-msg} -t get_tree \
|
|
| ${jq} 'recurse(.nodes[]) | select(.name == "__i3_scratch").floating_nodes[-1].nodes[0].id')
|
|
|
|
if [ "$last_window_id" != "null" ]; then
|
|
${i3-msg} "[con_id=\"$last_window_id\"] scratchpad show, resize set 1280 px 75 ppt, move position center, move scratchpad" > /dev/null
|
|
fi
|
|
''
|
|
}";
|
|
"${mod}+Tab" = ''[class="(Alacritty|kitty)"] scratchpad show'';
|
|
}
|
|
# Draw to float.
|
|
{
|
|
"${mod}+q" = "exec --no-startup-id ${
|
|
let xdotool = "${pkgs.xdotool}/bin/xdotool";
|
|
in pkgs.writeScript "float_on_selection.sh" ''
|
|
color="${colors.highlight}"
|
|
color="''${color:1}"
|
|
eval "$(${pkgs.perl}/bin/perl -e "printf('R=%.3f G=%.3f B=%.3f ',0x''${color:0:2}/255,0x''${color:2:2}/255,0x''${color:4:2}/255)")"
|
|
|
|
slopped="$(${pkgs.slop}/bin/slop -t 0 -c ''${R},''${G},''${B} -b 2 -f "X=%x Y=%y W=%w H=%h")"
|
|
[[ "$slopped" == "" ]] && exit 1
|
|
|
|
eval "$slopped"
|
|
${pkgs.i3}/bin/i3-msg floating enable \
|
|
&& ${xdotool} getactivewindow windowmove $X $Y \
|
|
&& ${xdotool} getactivewindow windowsize $W $H
|
|
''
|
|
}";
|
|
}
|
|
# Launch.
|
|
{
|
|
"${mod}+Return" = mkIf
|
|
(config.lwad.applications.terminalEmulator.default != null)
|
|
"exec --no-startup-id ${config.lwad.applications.terminalEmulator.default}";
|
|
"${mod}+Shift+Return" =
|
|
"exec --no-startup-id ${pkgs.pcmanfm}/bin/pcmanfm";
|
|
"${mod}+d" =
|
|
"exec --no-startup-id ${pkgs.rofi}/bin/rofi -show drun";
|
|
"${alt}+Shift+s" = mkIf
|
|
config.lwad.applications.terminalEmulator.alacritty.enable
|
|
"exec --no-startup-id alacritty -e sh -c '(read target && ssh \"$target\")'";
|
|
"${mod}+s" = "exec --no-startup-id ${
|
|
pkgs.writeScript "web_search.sh" ''
|
|
searchString=$(${pkgs.rofi}/bin/rofi -dmenu -p "Search" -i -theme-str "listview {lines: 0;}" | ${pkgs.jq}/bin/jq -Rsj @uri | ${pkgs.gnused}/bin/sed -e "s/%0A\$//")
|
|
[[ "$searchString" == "" ]] || ${pkgs.librewolf}/bin/librewolf --new-tab "https://duckduckgo.com/?q=''${searchString}"
|
|
''
|
|
}";
|
|
}
|
|
# Screenshots.
|
|
{
|
|
"${mod}+shift+s" = " exec --no-startup-id ${
|
|
let scrot = "${pkgs.scrot}/bin/scrot";
|
|
in pkgs.writeScript "copy_screenshot.sh" ''
|
|
SCREENSHOT_FILE="/tmp/$(date +"%y%m%d%H%M%S").png"
|
|
|
|
case "$(echo -e "desktop\nwindow\nselection" | ${pkgs.rofi}/bin/rofi -dmenu -p "Screenshot Type" -i)" in
|
|
desktop)
|
|
${scrot} -F "$SCREENSHOT_FILE" || exit 1
|
|
;;
|
|
window)
|
|
${scrot} -u -b -F "$SCREENSHOT_FILE" || exit 1
|
|
;;
|
|
selection)
|
|
color="${colors.highlight}"
|
|
color="''${color:1}"
|
|
eval "$(${pkgs.perl}/bin/perl -e "printf('R=%.3f G=%.3f B=%.3f ',0x''${color:0:2}/255,0x''${color:2:2}/255,0x''${color:4:2}/255)")"
|
|
|
|
slopped="$(${pkgs.slop}/bin/slop -t 0 -c ''${R},''${G},''${B} -b 2 -f "X=%x Y=%y W=%w H=%h")"
|
|
[[ "$slopped" == "" ]] && exit 1
|
|
|
|
eval "$slopped"
|
|
${scrot} -F "$SCREENSHOT_FILE" -a $X,$Y,$W,$H
|
|
;;
|
|
*)
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
${pkgs.xclip}/bin/xclip -selection clipboard -i "$SCREENSHOT_FILE" -t image/png
|
|
''
|
|
}";
|
|
}
|
|
# Media.
|
|
(let
|
|
change_volume = command: step: boost:
|
|
"exec --no-startup-id ${pamixer} ${
|
|
if boost then "--allow-boost" else ""
|
|
} -${command} ${
|
|
if (command == "t") then "" else toString step
|
|
} && ${show_volume_notification} ${command}";
|
|
pamixer = "${pkgs.pamixer}/bin/pamixer";
|
|
playerctl = "${pkgs.playerctl}/bin/playerctl";
|
|
show_volume_notification =
|
|
pkgs.writeScript "show_volume_notification.sh" ''
|
|
volume="$(${pamixer} --get-volume)"
|
|
|
|
if [[ $(${pamixer} --get-mute) == "true" ]]; then
|
|
icon="audio-volume-muted"
|
|
elif [[ "$1" == "down" ]]; then
|
|
icon="audio-volume-medium"
|
|
else
|
|
icon="audio-volume-high"
|
|
fi
|
|
|
|
${pkgs.dunst}/bin/dunstify -a "changeVolume" -u low -i "$icon" -h string:x-dunst-stack-tag:changeVolume -h int:value:"$volume" "$volume%" -t 750
|
|
'';
|
|
in {
|
|
"${alt}+k" = "${change_volume "i" 2 false}";
|
|
"${alt}+j" = "${change_volume "d" 2 false}";
|
|
"${alt}+shift+k" = "${change_volume "i" 10 false}";
|
|
"${alt}+shift+j" = "${change_volume "d" 10 false}";
|
|
"${alt}+control+k" = "${change_volume "i" 2 true}";
|
|
"${alt}+control+j" = "${change_volume "d" 2 true}";
|
|
"${alt}+control+shift+k" = "${change_volume "i" 10 true}";
|
|
"${alt}+control+shift+j" = "${change_volume "d" 10 true}";
|
|
"XF86AudioRaiseVolume" = "${change_volume "i" 2 false}";
|
|
"XF86AudioLowerVolume" = "${change_volume "d" 2 false}";
|
|
"XF86AudioMute" = "${change_volume "t" 0 false}";
|
|
"XF86AudioPlay" =
|
|
"exec --no-startup-id ${playerctl} play-pause";
|
|
"XF86AudioPause" =
|
|
"exec --no-startup-id ${playerctl} play-pause";
|
|
"XF86AudioPrev" = "exec --no-startup-id ${playerctl} previous";
|
|
"XF86AudioNext" = "exec --no-startup-id ${playerctl} next";
|
|
})
|
|
# Modes.
|
|
{
|
|
"${mod}+p" = "mode power";
|
|
"${mod}+r" = "mode resize";
|
|
}
|
|
];
|
|
modes = {
|
|
resize = {
|
|
"h" = "resize shrink width 20 px";
|
|
"j" = "resize grow height 20 px";
|
|
"k" = "resize shrink height 20 px";
|
|
"l" = "resize grow width 20 px";
|
|
"Escape" = ''mode "default"'';
|
|
};
|
|
power = let
|
|
systemctl = "${pkgs.systemd}/bin/systemctl";
|
|
lockCommand =
|
|
"pkill xcompmgr; XSECURELOCK_PASSWORD_PROMPT=time_hex ${pkgs.xsecurelock}/bin/xsecurelock && (${pkgs.xcompmgr}/bin/xcompmgr & sleep 1 && ${pkgs.i3}/bin/i3-msg restart)";
|
|
in {
|
|
"l" = ''exec --no-startup-id "${lockCommand}", mode "default"'';
|
|
"e" = ''
|
|
exec --no-startup-id ${pkgs.i3}/bin/i3-msg exit, mode "default"'';
|
|
"s" = ''
|
|
exec --no-startup-id "${lockCommand}", exec --no-startup-id ${systemctl} suspend, mode "default"'';
|
|
"r" =
|
|
''exec --no-startup-id ${systemctl} reboot, mode "default"'';
|
|
"Shift+s" = ''
|
|
exec --no-startup-id ${systemctl} poweroff, mode "default"'';
|
|
"Escape" = ''mode "default"'';
|
|
};
|
|
};
|
|
startup = [
|
|
{
|
|
command = "${pkgs.caffeine-ng}/bin/caffeine start --activate";
|
|
notification = false;
|
|
}
|
|
{
|
|
command = "${pkgs.xcompmgr}/bin/xcompmgr";
|
|
notification = false;
|
|
}
|
|
];
|
|
window = {
|
|
commands = [{
|
|
command = "floating disable";
|
|
criteria = {
|
|
class = "librewolf";
|
|
floating = true;
|
|
title = "^Extension:.*Bitwarden.*";
|
|
};
|
|
}];
|
|
hideEdgeBorders = "smart";
|
|
titlebar = false;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
services.xserver = {
|
|
displayManager.defaultSession = "none+i3";
|
|
windowManager.i3 = {
|
|
enable = true;
|
|
package = pkgs.i3;
|
|
};
|
|
};
|
|
};
|
|
}
|