{ lib, config, pkgs, inputs, ... }: let cfg = config.wayming.gamescoperun; # Use shared lib functions inherit (lib.wayming) toCliArgs toEnvCommands getMonitorDefaults; # Get monitor defaults monitorDefaults = getMonitorDefaults config.wayming.monitors; inherit (monitorDefaults) WIDTH HEIGHT REFRESH_RATE VRR HDR ; # Select gamescope packages based on useGit option gamescopePackages = if cfg.useGit then { gamescope = inputs.chaotic.legacyPackages.${pkgs.system}.gamescope_git; gamescope-wsi = inputs.chaotic.legacyPackages.${pkgs.system}.gamescope-wsi_git; } else { gamescope = pkgs.gamescope; gamescope-wsi = pkgs.gamescope-wsi or null; }; # Base options with monitor-derived defaults defaultBaseOptions = { backend = "sdl"; fade-out-duration = 200; fullscreen = true; immediate-flips = true; nested-refresh = REFRESH_RATE; output-height = HEIGHT; output-width = WIDTH; rt = true; } // lib.optionalAttrs HDR { hdr-enabled = true; hdr-debug-force-output = true; hdr-itm-enable = true; } // lib.optionalAttrs VRR { adaptive-sync = true; }; # Merge user options with defaults finalBaseOptions = defaultBaseOptions // cfg.baseOptions; defaultEnvironment = { ENABLE_GAMESCOPE_WSI = 1; GAMESCOPE_WAYLAND_DISPLAY = "gamescope-0"; PROTON_USE_SDL = 1; PROTON_USE_WAYLAND = 1; SDL_VIDEODRIVER = "wayland"; AMD_VULKAN_ICD = "RADV"; RADV_PERFTEST = "aco"; DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1 = 1; DISABLE_LAYER_NV_OPTIMUS_1 = 1; } // lib.optionalAttrs HDR { ENABLE_HDR_WSI = 1; DXVK_HDR = 1; PROTON_ENABLE_HDR = 1; }; # Merge user environment with defaults finalEnvironment = defaultEnvironment // cfg.environment; # The gamescoperun script gamescoperun = pkgs.writeScriptBin "gamescoperun" '' #!${lib.getExe pkgs.fish} # Check if we're already inside a Gamescope session if set -q GAMESCOPE_WAYLAND_DISPLAY echo "Already inside Gamescope session ($GAMESCOPE_WAYLAND_DISPLAY), running command directly..." exec $argv end # Set environment variables for the gamescope session ${toEnvCommands finalEnvironment} # Define and parse arguments using fish's built-in argparse argparse -i 'x/extra-args=' -- $argv if test $status -ne 0 exit 1 end # Check if we have a command to run if test (count $argv) -eq 0 echo "Usage: gamescoperun [-x|--extra-args \"\"] [args...]" echo "" echo "Examples:" echo " gamescoperun heroic" echo " gamescoperun -x \"--fsr-upscaling-sharpness 5\" steam" echo " GAMESCOPE_EXTRA_OPTS=\"--fsr\" gamescoperun steam (legacy)" exit 1 end # Combine base args, extra args from CLI, and extra args from env (for legacy) set -l final_args ${toCliArgs finalBaseOptions} # Add args from -x/--extra-args flag, splitting the string into a list if set -q _flag_extra_args set -a final_args (string split ' ' -- $_flag_extra_args) end # For legacy support, add args from GAMESCOPE_EXTRA_OPTS if it exists if set -q GAMESCOPE_EXTRA_OPTS set -a final_args (string split ' ' -- $GAMESCOPE_EXTRA_OPTS) end # Show the command being executed echo -e "\033[1;36m[gamescoperun]\033[0m Running: \033[1;34m${lib.getExe gamescopePackages.gamescope}\033[0m $final_args \033[1;32m--\033[0m $argv" # Execute gamescope with the final arguments and the command exec ${lib.getExe gamescopePackages.gamescope} $final_args -- $argv ''; in { options.wayming.gamescoperun = { enable = lib.mkEnableOption "gamescoperun, a wrapper for gamescope"; useGit = lib.mkOption { type = lib.types.bool; default = true; description = "Use git versions of gamescope from chaotic-nyx for latest features"; }; baseOptions = lib.mkOption { type = with lib.types; attrsOf (oneOf [ str int bool ]); default = { }; example = { "fsr-upscaling" = true; "output-width" = 2560; }; description = '' Base command-line options to always pass to gamescope. Option names must match gamescope's flags exactly (e.g., "hdr-enabled"). Monitor-derived options (width, height, refresh rate, HDR, VRR) are set automatically but can be overridden here. ''; }; environment = lib.mkOption { type = with lib.types; attrsOf (oneOf [ str int ]); default = { }; description = '' Environment variables to set within the gamescoperun script. HDR-related variables are set automatically based on monitor configuration but can be overridden here. ''; }; package = lib.mkOption { type = lib.types.package; readOnly = true; default = gamescoperun; description = "The configured gamescoperun package"; }; }; config = lib.mkIf cfg.enable { # Install both gamescope and gamescope-wsi home.packages = [ cfg.package ] ++ [ gamescopePackages.gamescope ] ++ lib.optionals (gamescopePackages.gamescope-wsi != null) [ gamescopePackages.gamescope-wsi ]; # Assertion to ensure monitors are configured if gamescoperun is enabled assertions = [ { assertion = cfg.enable -> (lib.length config.wayming.monitors > 0); message = "wayming.gamescoperun requires at least one monitor to be configured in wayming.monitors"; } { assertion = cfg.enable -> (lib.length (lib.filter (m: m.primary) config.wayming.monitors) == 1); message = "wayming.gamescoperun requires exactly one primary monitor to be configured"; } ]; }; }