{ pkgs, lib, myConfig, ... }: let gamingMonitor = "DP-1"; gaming-focus = pkgs.writeShellScriptBin "gaming-focus" '' # If already on gaming workspace on the gaming monitor, go back current=$(${pkgs.hyprland}/bin/hyprctl activeworkspace -j | ${pkgs.jq}/bin/jq -r '.name') focused=$(${pkgs.hyprland}/bin/hyprctl monitors -j | ${pkgs.jq}/bin/jq -r '.[] | select(.focused) | .name') if [[ "$current" == "gaming" && "$focused" == "${gamingMonitor}" ]]; then ${pkgs.hyprland}/bin/hyprctl dispatch workspace previous exit 0 fi # Close special workspace on gaming monitor if open special=$(${pkgs.hyprland}/bin/hyprctl monitors -j | ${pkgs.jq}/bin/jq -r '.[] | select(.name == "${gamingMonitor}") | .specialWorkspace.name') if [[ -n "$special" ]]; then # Gaming workspace is already underneath — just close the special overlay ${pkgs.hyprland}/bin/hyprctl --batch "dispatch focusmonitor ${gamingMonitor};dispatch togglespecialworkspace ''${special#special:}" else ${pkgs.hyprland}/bin/hyprctl --batch "dispatch focusmonitor ${gamingMonitor};dispatch workspace name:gaming" fi ''; # Games that should have `stayfocused` applied (to avoid multi-monitor focus issues) stayFocusedGames = [ # "Deadlock" # "project8" # "citadel" ]; mkGameRules = selector: [ "match:${selector}, monitor ${gamingMonitor}" "match:${selector}, fullscreen on" "match:${selector}, immediate on" "match:${selector}, tile on" ]; stayFocusedRules = lib.flatten (map ( game: [ "match:title ^(${game})$, stay_focused on" "match:class ^(${game})$, stay_focused on" ] ) stayFocusedGames); in { home.packages = with pkgs; [ protonup-qt protontricks mangohud gaming-focus # via ]; programs.mangohud = { enable = true; settings = { full = true; no_display = true; # Don't show by default (toggle with Shift+F12) cpu_temp = true; gpu_temp = true; ram = true; vram = true; }; }; wayland.windowManager.hyprland.settings = { workspace = [ "name:gaming, monitor:${gamingMonitor}, default:true" ]; exec-once = [ "[workspace special:steam silent] steam" ]; bindd = [ "SUPER, A, Toggle Steam, togglespecialworkspace, steam" "SUPER SHIFT, A, Move to Steam Special Workspace, movetoworkspace, special:steam" "SUPER, G, Switch to Gaming Workspace, exec, gaming-focus" "SUPER SHIFT, G, Move to Gaming Workspace, movetoworkspace, name:gaming" ]; windowrule = [ "match:class ^(steam)$, hyprbars:no_bar on" "match:class ^(steam_app_\\d+)$, hyprbars:no_bar on" # --- STEAM GENERAL RULES --- # Default ALL steam class windows to float. This catches all dialogs & properties windows. "match:class ^(steam)$, float on" # Suppress focus stealing from dialogs/etc. "match:class ^(steam)$, no_initial_focus on" "match:class ^(steam)$, suppress_event activate fullscreen maximize" # --- STEAM CLIENT OVERRIDE --- # Override the float for the main Steam client, tile it, and move it to the special workspace. "match:class ^(steam)$, tile on" "match:class ^(steam)$, workspace special:steam" # --- STEAM GAME OVERRIDES --- # Override the float for actual games and move them to the gaming workspace. # 1. Auto-detected steam_app games (like Deadlock). "match:class ^(steam_app_\\d+)$, monitor ${gamingMonitor}" "match:class ^(steam_app_\\d+)$, tile on" "match:class ^(steam_app_\\d+)$, fullscreen on" "match:class ^(steam_app_\\d+)$, immediate on" "match:class ^(steam_app_\\d+)$, workspace name:gaming" # 2. Behavior-detected manual games (e.g. ARC Raiders). # This moves any steam game to the gaming workspace and tiles it when it becomes fullscreen. "match:class ^(steam)$, match:fullscreen true, tile on" "match:class ^(steam)$, match:fullscreen true, workspace name:gaming" ] # Other auto-detected non-steam games ++ (mkGameRules "class ^(gamescope)$") ++ (mkGameRules "class ^(lutris)$") ++ (mkGameRules "class ^(heroic)$") ++ (mkGameRules "class ^wine-.*$") ++ (mkGameRules "title ^Wine .*$") ++ (mkGameRules "initial_title ^(?i)godot.*$") # ++ [ # "monitor 0, initialTitle:^(?i)godot.*$" # "fullscreen, initialTitle:^(?i)godot.*$" # "tile, initialTitle:^(?i)godot.*$" # ] # Stayfocused rules ++ stayFocusedRules; }; }