diff --git a/users/simon/base.nix b/users/simon/base.nix index 90c09e0..f4bfd10 100644 --- a/users/simon/base.nix +++ b/users/simon/base.nix @@ -31,6 +31,7 @@ in home-manager.users.simon = { pkgs, ... }: { imports = [ ./modules/alacritty.nix + ./modules/sway.nix ./modules/zathura.nix ]; diff --git a/users/simon/files/waybar/style.css b/users/simon/files/waybar/style.css new file mode 100644 index 0000000..a60e9af --- /dev/null +++ b/users/simon/files/waybar/style.css @@ -0,0 +1,153 @@ +* { + border-radius: 0; + border: none; + font-family: "Iosevka Nerd Font"; + font-size: 12px; + min-height: 0; + transition-property: none; +} + +window#waybar { + background-color: @base03@; + color: @base0@; +} + +#workspaces button { + padding: 0 5px; + background-color: @base03@; + color: inherit; + border-bottom: 2px solid transparent; +} + +#workspaces button:hover { + background: @base02@; + box-shadow: inherit; + text-shadow: inherit; +} + +#workspaces button.focused { + border-bottom: 2px solid @green@; +} + +#workspaces button.urgent { + background-color: @red@; +} + +#mode { + background-color: @base02@; + font-style: italic; +} + +/* all modules on the right */ +#waybar > box > box:nth-child(3) > widget > label { + padding: 0 10px; +} + +#battery.charging { + color: @base02@; + background-color: @green@; +} + +@keyframes blink { + to { + background-color: @base3@; + color: @base00@; + } +} + +#battery.critical:not(.charging), +#temperature.critical { + background-color: @red@; + animation-name: blink; + animation-duration: 0.5s; + /* FIXME use nearest neighbor interpolation if possible */ + animation-timing-function: cubic-bezier(1, 0, 0, 1); + animation-iteration-count: infinite; + animation-direction: alternate; +} + +#cpu { + background-color: @cyan@; + color: @base02@ +} + +#memory { + background-color: @yellow@; + color: @base02@ +} + +#backlight { + background-color: @base3@; + color: @base00@; +} + +#network { + background-color: @violet@; + color: @base02@ +} + +#custom-vpn { + background-color: @blue@; + color: @base02@ +} + +#network.disconnected { + background-color: @red@; +} + +#network.speed { + background-color: @green@; +} + +#pulseaudio { + background-color: @base3@; + color: @base00@; +} + +#pulseaudio.muted { + background-color: @base03@; + color: @base0@; +} + +#temperature { + background-color: @magenta@; + color: @base02@; +} + +#idle_inhibitor.activated { + background-color: @base3@; + color: @base03@; +} + +#mpd { + background-color: @green@; + color: @base02@; +} + +#mpd.disconnected { + background-color: @red@; +} + +#mpd.stopped { + background-color: @orange@; +} + +#mpd.paused { + background-color: @yellow@; +} + +#custom-redshift { + color: @base02@; +} + +#custom-redshift.active { + background-color: @red@; +} + +#custom-redshift.inactive { + background-color: @blue@; +} + +#tray { + padding: 0 5px; +} diff --git a/users/simon/modules/sway.nix b/users/simon/modules/sway.nix new file mode 100644 index 0000000..0f76c24 --- /dev/null +++ b/users/simon/modules/sway.nix @@ -0,0 +1,402 @@ +{ config, pkgs, ... }: +let + common = import ./common.nix; + solarized = common.colorschemes.solarized; + + wallpaper = "${config.xdg.configHome}/sway/wallpaper"; # Symlink to the current wallpaper + cfg = config.wayland.windowManager.sway.config; + thinsp = " "; +in +{ + wayland.windowManager.sway = { + enable = true; + + config = { + modifier = "Mod4"; + + terminal = "alacritty"; + + menu = "${pkgs.dmenu-wayland}/bin/dmenu-wl_path | ${pkgs.dmenu-wayland}/bin/dmenu-wl -nb '#002b36' -nf '#839496' -sb '#859900' -sf '#073642' | ${pkgs.findutils}/bin/xargs swaymsg exec --"; + + output = { + "*".bg = "${wallpaper} fill"; + # FIXME: maybe use kanshi + eDP-1 = { + resolution = "1920x1080"; + position = "0,424"; + }; + "Dell Inc. DELL U2410 F525M0A104NL" = { + resolution = "1920x1200"; + position = "1920,0"; + }; + }; + + input."type:keyboard" = { + xkb_layout = "de"; + xkb_options = "compose:caps"; + xkb_numlock = "enable"; + }; + + keybindings = { + # Basics + "${cfg.modifier}+Return" = "exec ${cfg.terminal}"; + "${cfg.modifier}+Shift+c" = "kill"; + "${cfg.modifier}+r" = "exec ${cfg.menu}"; + "${cfg.modifier}+Control+r" = "reload"; + "${cfg.modifier}+Shift+q" = "exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'"; + + # Focus + "${cfg.modifier}+${cfg.left}" = "focus left"; + "${cfg.modifier}+${cfg.down}" = "focus down"; + "${cfg.modifier}+${cfg.up}" = "focus up"; + "${cfg.modifier}+${cfg.right}" = "focus right"; + + "${cfg.modifier}+Left" = "focus left"; + "${cfg.modifier}+Down" = "focus down"; + "${cfg.modifier}+Up" = "focus up"; + "${cfg.modifier}+Right" = "focus right"; + + # Moving + "${cfg.modifier}+Shift+${cfg.left}" = "move left"; + "${cfg.modifier}+Shift+${cfg.down}" = "move down"; + "${cfg.modifier}+Shift+${cfg.up}" = "move up"; + "${cfg.modifier}+Shift+${cfg.right}" = "move right"; + + "${cfg.modifier}+Shift+Left" = "move left"; + "${cfg.modifier}+Shift+Down" = "move down"; + "${cfg.modifier}+Shift+Up" = "move up"; + "${cfg.modifier}+Shift+Right" = "move right"; + + # Workspaces + "${cfg.modifier}+1" = "workspace number 1"; + "${cfg.modifier}+2" = "workspace number 2"; + "${cfg.modifier}+3" = "workspace number 3"; + "${cfg.modifier}+4" = "workspace number 4"; + "${cfg.modifier}+5" = "workspace number 5"; + "${cfg.modifier}+6" = "workspace number 6"; + "${cfg.modifier}+7" = "workspace number 7"; + "${cfg.modifier}+8" = "workspace number 8"; + "${cfg.modifier}+9" = "workspace number 9"; + "${cfg.modifier}+0" = "workspace number 10"; + + "${cfg.modifier}+Shift+1" = "move container to workspace number 1"; + "${cfg.modifier}+Shift+2" = "move container to workspace number 2"; + "${cfg.modifier}+Shift+3" = "move container to workspace number 3"; + "${cfg.modifier}+Shift+4" = "move container to workspace number 4"; + "${cfg.modifier}+Shift+5" = "move container to workspace number 5"; + "${cfg.modifier}+Shift+6" = "move container to workspace number 6"; + "${cfg.modifier}+Shift+7" = "move container to workspace number 7"; + "${cfg.modifier}+Shift+8" = "move container to workspace number 8"; + "${cfg.modifier}+Shift+9" = "move container to workspace number 9"; + "${cfg.modifier}+Shift+0" = "move container to workspace number 10"; + + # Moving workspaces between outputs + "${cfg.modifier}+Control+${cfg.left}" = "move workspace to output left"; + "${cfg.modifier}+Control+${cfg.down}" = "move workspace to output down"; + "${cfg.modifier}+Control+${cfg.up}" = "move workspace to output up"; + "${cfg.modifier}+Control+${cfg.right}" = "move workspace to output right"; + + "${cfg.modifier}+Control+Left" = "move workspace to output left"; + "${cfg.modifier}+Control+Down" = "move workspace to output down"; + "${cfg.modifier}+Control+Up" = "move workspace to output up"; + "${cfg.modifier}+Control+Right" = "move workspace to output right"; + + # Splits + "${cfg.modifier}+b" = "splith"; + "${cfg.modifier}+v" = "splitv"; + + # Layouts + "${cfg.modifier}+s" = "layout stacking"; + "${cfg.modifier}+t" = "layout tabbed"; + "${cfg.modifier}+e" = "layout toggle split"; + "${cfg.modifier}+f" = "fullscreen toggle"; + + "${cfg.modifier}+a" = "focus parent"; + + "${cfg.modifier}+Control+space" = "floating toggle"; + "${cfg.modifier}+space" = "focus mode_toggle"; + + # Scratchpad + "${cfg.modifier}+Shift+minus" = "move scratchpad"; + "${cfg.modifier}+minus" = "scratchpad show"; + + # Resize mode + "${cfg.modifier}+d" = "mode resize"; + + # Multimedia Keys + "XF86AudioMute" = "exec ${pkgs.pulseaudio}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle"; + "XF86AudioMicMute" = "exec ${pkgs.pulseaudio}/bin/pactl set-source-mute @DEFAULT_SOURCE@ toggle"; + "--locked XF86MonBrightnessDown" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%-"; + "--locked XF86MonBrightnessUp" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set +5%"; + "XF86AudioRaiseVolume" = "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ +5%"; + "XF86AudioLowerVolume" = "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ -5%"; + + "XF86AudioPrev" = "exec ${pkgs.mpc_cli}/bin/mpc next"; + "XF86AudioNext" = "exec ${pkgs.mpc_cli}/bin/mpc prev"; + "XF86AudioPlay" = "exec ${pkgs.mpc_cli}/bin/mpc toggle"; + + # Locking and DPMS + "${cfg.modifier}+y" = "exec ${pkgs.swaylock}/bin/swaylock -f -i ${wallpaper}"; + "--locked ${cfg.modifier}+q" = ''exec 'test $(swaymsg -t get_outputs | ${pkgs.jq}/bin/jq "[.[].dpms] | any") = "true" && swaymsg "output * dpms off" || swaymsg "output * dpms on"''; + }; + + bars = [ + { command = "waybar"; } + ]; + + assigns = { + "2" = [ + { app_id = "firefox"; } + #{ class="Chromium"; } + ]; + "3" = [ + { app_id = "net.sourceforge.mumble."; } + { class = "Claws-mail"; } + ]; + "4" = [ + { app_id = "anki"; } + { app_id = "libreoffice-startcenter"; } + { app_id = "net.sourceforge.gscan2pdf"; } + { app_id = "org.pwmt.zathura"; } + { app_id = "xournalpp"; } + ]; + "5" = [ + { app_id = "audacious"; } + { app_id = "pavucontrol"; } + ]; + "8" = [ + { app_id = "darktable"; } + { app_id = "org.inkscape.Inkscape"; } + { class = "Blender"; } + { class = "Gimp"; } + { class = "krita"; } + ]; + }; + + window.border = 1; + + floating = { + titlebar = true; + border = 1; + }; + + colors = { + focused = rec { border = "#93a1a1"; background = "#073642"; text = "#93a1a1"; indicator = "#2aa198"; childBorder = background; }; + focusedInactive = rec { border = "#839496"; background = "#002b36"; text = "#839496"; indicator = "#2aa198"; childBorder = background; }; + unfocused = rec { border = "#839496"; background = "#002b36"; text = "#839496"; indicator = "#2aa198"; childBorder = background; }; + urgent = rec { border = "#073642"; background = "#dc322f"; text = "#073642"; indicator = "#2aa198"; childBorder = background; }; + }; + + fonts = [ "monospace 10" ]; + }; + + extraConfig = '' + # Auto lock + exec ${pkgs.swayidle}/bin/swayidle -w \ + timeout 300 "swaylock -f -i ${wallpaper}" \ + timeout 300 'swaymsg "output * dpms off"' \ + resume 'swaymsg "output * dpms on"' \ + before-sleep "swaylock -f -i ${wallpaper}" + + # Cursor + seat seat0 xcursor_theme Adwaita + + exec ${pkgs.mako}/bin/mako + ''; + + extraSessionCommands = '' + export CLUTTER_BACKEND=wayland + export GDK_BACKEND=wayland + export MOZ_ENABLE_WAYLAND=1 + export QT_QPA_PLATFORM=wayland-egl + export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 + export SDL_VIDEODRIVER=wayland + export WLR_NO_HARDWARE_CURSORS=1 + export _JAVA_AWT_WM_NONREPARENTING=1 + ''; + }; + home.file = { + # home-manager’s waybar module performs additional checks that are overly strict + ".config/waybar/config".text = builtins.toJSON { + layer = "top"; + position = "top"; + height = 24; + + modules-center = [ ]; + modules-left = [ + "sway/workspaces" + "sway/mode" + ]; + modules-right = [ + "tray" + "custom/redshift" + "idle_inhibitor" + "backlight" + "mpd" + "pulseaudio" + "network" + "custom/vpn" + "network#speed" + "memory" + "cpu" + "temperature" + "battery" + "clock" + ]; + + "sway/workspaces" = { + disable-scroll = true; + }; + "sway/mode" = { + format = "{}"; + }; + + tray = { + spacing = 5; + }; + "custom/redshift" = { + interval = 10; + exec = "systemctl --user show redshift | grep -q ActiveState=active && echo '{\"tooltip\": \"Redshift active\", \"class\": \"active\"}' || echo '{\"tooltip\": \"Redshift inactive\", \"class\": \"inactive\"}'"; + on-click = "systemctl --user show redshift | grep -q ActiveState=active && systemctl --user stop redshift || systemctl --user start redshift"; + return-type = "json"; + format = ""; + tooltip = false; + }; + idle_inhibitor = { + format = "{icon}"; + format-icons = { + activated = " "; + deactivated = " "; + }; + }; + backlight = { + format = "{percent}% {icon}"; + format-icons = [ " " " " " " " " " " " " " " ]; + on-scroll-up = "brightnessctl set +5%"; + on-scroll-down = "brightnessctl set 5%-"; + }; + mpd = { + format = "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} – {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) "; + format-disconnected = "Disconnected "; + format-stopped = "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped "; + unknown-tag = "N/A"; + interval = 2; + tooltip-format = "MPD (connected)"; + tooltip-format-disconnected = "MPD (disconnected)"; + consume-icons = { + on = " "; + }; + random-icons = { + off = "劣 "; + on = "列 "; + }; + repeat-icons = { + on = "凌 "; + }; + single-icons = { + on = "綾 "; + }; + state-icons = { + paused = ""; + playing = "契"; + }; + }; + pulseaudio = { + format = "{volume}% {icon} {format_source}"; + format-bluetooth = "{volume}% {icon} {format_source}"; + format-bluetooth-muted = "遼 {icon} {format_source}"; # FIXME: see below + format-muted = "遼 {format_source}"; # FIXME: use normal mute icon (ﱝ ), which for some reason is displayed right of the source? + format-source = "{volume}% ${thinsp}"; + format-source-muted = "${thinsp}"; + format-icons = { + car = " "; + default = [ "奄" "奔" "墳" ]; + hands-free = " "; + headphone = " "; + headset = " "; + phone = " "; + portable = " "; + }; + on-click = "pavucontrol"; + }; + network = { + format-wifi = "{essid} ({signalStrength}%) 直 "; + format-ethernet = "{ifname}: {ipaddr}/{cidr}  "; + format-linked = "{ifname} (No IP)  "; + format-disconnected = "Disconnected ⚠ "; + format-alt = "{ifname}: {ipaddr}/{cidr}"; + tooltip = false; + on-click-right = "alacritty -e nmtui"; + }; + "custom/vpn" = { + interval = 10; + exec = "ip -j link | jq --unbuffered --compact-output '[[.[].ifname | select(. | startswith(\"mullvad\"))][] | split(\"-\")[1] + \" ${thinsp}\"] as $conns | { text: ($conns[0] // \"\"), class: (if $conns | length > 0 then \"connected\" else \"disconnected\" end) }'"; + return-type = "json"; + format = "{}"; + tooltip = false; + }; + "network#speed" = { + interval = 2; + format = "{bandwidthDownBits:>8}  {bandwidthUpBits:>8} 祝"; + format-alt = "{bandwidthDownOctets:>8}  {bandwidthUpOctets:>8} 祝"; + format-disconnected = " 0b/s 祝 0b/s"; + tooltip = false; + }; + memory = { + interval = 2; + format = "{:2}%  "; + }; + cpu = { + interval = 2; + format = "{usage:2}% ﬙ "; + tooltip = false; + }; + temperature = { + critical-threshold = 80; + format = "{temperatureC}°C {icon}"; + format-icons = [ "" "" "" "" "" ]; + }; + battery = { + interval = 5; + format = "{capacity}% {icon}"; + format-charging = "{capacity}% "; + format-plugged = "{capacity}% ﮣ"; + format-alt = "{time} {icon}"; + format-icons = [ "" "" "" "" "" "" "" "" "" "" "" ]; + states = { + critical = 15; + good = 95; + warning = 30; + }; + }; + clock = { + format = "{:%H:%M %Z}"; + format-alt = "{:%Y-%m-%d (%a)}"; + tooltip-format = "{:%Y %B}\n{calendar}"; + }; + }; + ".config/waybar/style.css".source = pkgs.substituteAll ({ + src = ../files/waybar/style.css; + } // solarized); + ".zprofile".text = '' + if [[ -z $WAYLAND_DISPLAY ]] && [[ $(tty) = /dev/tty1 ]] && command -v sway >/dev/null ; then + systemctl --user start graphical-session.target + export XDG_SESSION_TYPE="wayland" + exec sway + fi + ''; + }; + + programs.mako = { + enable = true; + + backgroundColor = solarized.base03; + borderColor = solarized.base02; + textColor = solarized.base0; + progressColor = "over ${solarized.base02}"; + + groupBy = "app-name"; + + defaultTimeout = 5000; + }; +}