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;
+ };
+}