{ pkgs, config, lib, ... }: let cfg = config.grimmShared; sway_conf = with lib; types.submodule ( { config, ... }: rec { options = { keybinds = mkOption { type = types.attrsOf types.str; default = { }; description = "set of keybinds assigning key combo to action"; }; autolaunch = mkOption { type = types.listOf (types.either types.nonEmptyStr types.package); default = [ ]; description = "set of commands to be run at sway startup"; }; execAlways = mkOption { type = types.listOf (types.either types.nonEmptyStr types.package); default = [ ]; description = "set of commands to be run at sway reload"; }; extraConfig = mkOption { type = types.str; default = ""; description = "additional sway config to be included"; }; definitions = mkOption { type = types.attrsOf types.str; default = { }; description = "set of definitions assigning variable to value"; }; modes = mkOption { type = types.attrsOf sway_conf; default = { }; description = "possible modes to switch to, e.g. resize"; }; }; } ); build_screen_def = fps_func: with lib; let output_def = mapAttrsToList ( name: value: "output ${value.id} mode ${value.mode}@${toString (fps_func value.fps)}Hz" + (optionalString (value.pos != null) " position ${value.pos}") ) cfg.screens; in '' for pid in $(${pkgs.procps}/bin/pgrep sway -x) do uid=$(id -u $(${pkgs.procps}/bin/ps -o user= -p $pid)) export SWAYSOCK="/run/user/$uid/sway-ipc.$uid.$pid.sock" if [[ -e "$SWAYSOCK" ]] ; then echo "sock is $SWAYSOCK" ${config.programs.sway.package}/bin/swaymsg '${concatMapStrings (s: s + " ; ") output_def}' fi done ''; inherit (lib) getExe; fps_min = fps: with lib; if isInt fps then fps else (foldl' min 2147483647 fps); fps_max = fps: with lib; if isInt fps then fps else (foldl' max 0 fps); init_screens_min_fps = with lib; pkgs.writeShellScriptBin "init-screens-min" (build_screen_def fps_min); init_screens_max_fps = with lib; pkgs.writeShellScriptBin "init-screens-max" (build_screen_def fps_max); init_screens_auto = pkgs.writeShellScriptBin "init-screens-auto" "which run-on-ac && which run-on-bat && run-on-ac ${getExe init_screens_max_fps} && run-on-bat ${getExe init_screens_min_fps} || ${getExe init_screens_max_fps}"; in { config = let bar_conf_file = if (lib.isPath cfg.sway.bar.config) then cfg.sway.bar.config else pkgs.writers.writeJSON "config.json" cfg.sway.bar.config; waybar_full = pkgs.writeShellScriptBin "waybar-full" ( (lib.getExe config.programs.waybar.package) + (lib.optionalString (!isNull cfg.sway.bar.config) " -c ${bar_conf_file}") + (lib.optionalString (!isNull cfg.sway.bar.style) " -s ${cfg.sway.bar.style}") ); bar_config = '' bar { swaybar_command ${getExe waybar_full} } ''; dbus-sway-environment = pkgs.writeShellScriptBin "dbus-sway-environment" '' dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway systemctl --user stop xdg-desktop-portal xdg-desktop-portal-wlr systemctl --user start xdg-desktop-portal xdg-desktop-portal-wlr ''; build_conf = with lib; sway_conf: let build_definition_lines = mapAttrsToList (name: value: "set \$${name} ${value}"); build_keybind_lines = mapAttrsToList (key: value: "bindsym ${key} ${value}"); build_exec_lines = e: map (item: "${e} " + (if isString item then item else (getExe item))); build_mode_lines = mapAttrsToList ( name: value: '' mode "${name}" { ${concatLines (map (item: " " + item) (build_conf value))}}'' ); in ( [ ] ++ (build_definition_lines sway_conf.definitions) ++ (build_keybind_lines sway_conf.keybinds) ++ (build_exec_lines "exec" sway_conf.autolaunch) ++ (build_exec_lines "exec_always" sway_conf.execAlways) ++ (build_mode_lines sway_conf.modes) ++ optional (sway_conf.extraConfig != "") sway_conf.extraConfig ); sway_conf = lib.concatLines ( (build_conf cfg.sway.config) ++ lib.optional cfg.sway.bar.enable bar_config ++ (lib.mapAttrsToList ( name: value: "output ${value.id} mode ${value.mode}" + (lib.optionalString (value.pos != null) " position ${value.pos}") ) cfg.screens) ); conf_path = "sway.conf"; in with cfg; lib.mkIf (enable && sway.enable) { environment.etc."${conf_path}".text = sway_conf; grimmShared.sway.config.execAlways = [ dbus-sway-environment init_screens_auto ]; environment.systemPackages = [ waybar_full dbus-sway-environment init_screens_min_fps init_screens_max_fps init_screens_auto ] ++ (with pkgs; [ procps slurp libnotify ]); systemd.services.reload-sway = { description = "Reload all running sway instances"; wantedBy = [ "multi-user.target" ]; serviceConfig.Type = "oneshot"; script = '' for pid in $(${pkgs.procps}/bin/pgrep sway -x) do uid=$(id -u $(${pkgs.procps}/bin/ps -o user= -p $pid)) export SWAYSOCK="/run/user/$uid/sway-ipc.$uid.$pid.sock" if [[ -e "$SWAYSOCK" ]] ; then echo "sock is $SWAYSOCK" ${config.programs.sway.package}/bin/swaymsg reload fi done rm -rf /home/*/.cache/rmenu ''; reloadTriggers = [ config.environment.etc."${conf_path}".source ]; }; programs.waybar.enable = true; programs.dconf.enable = true; programs.sway = { enable = true; wrapperFeatures = { gtk = true; base = true; }; extraPackages = with pkgs; [ swaylock swayidle wl-clipboard wf-recorder dmenu wmenu waybar-mpris ]; extraOptions = [ "--config" "/etc/${conf_path}" ]; extraSessionCommands = '' # source /etc/profile # test -f $HOME/.profile && source $HOME/.profile systemctl --user import-environment export XDG_CURRENT_DESKTOP=sway export SDL_VIDEODRIVER=wayland export QT_QPA_PLATFORM=wayland export QT_WAYLAND_DISABLE_WINDOWDECORATION="1" export _JAVA_AWT_WM_NONREPARENTING=1 export MOZ_ENABLE_WAYLAND=1 # export WLR_RENDERER=vulkan # export DRI_PRIME=1 export NIXOS_OZONE_WL=1 ''; }; }; options.grimmShared.sway = with lib; { enable = mkEnableOption "grimm-sway"; bar = { enable = mkEnableOption "grimm-sway-bar"; style = mkOption { type = types.nullOr types.path; default = null; description = "waybar style sheet to use"; }; config = mkOption { type = types.nullOr (types.either types.path types.attrs); default = null; description = "waybar config to use"; }; }; config = mkOption { type = sway_conf; description = "sway config to use"; }; }; }