diff --git a/flake.lock b/flake.lock
index 3386095..097a0ba 100755
--- a/flake.lock
+++ b/flake.lock
@@ -24,11 +24,11 @@
},
"bleedingpkgs": {
"locked": {
- "lastModified": 1724117083,
- "narHash": "sha256-26Zgap4D9E8PRL9jvc4Df9POMNGFS9fMwKz+SiGrlXI=",
+ "lastModified": 1724277913,
+ "narHash": "sha256-88IaCyNgVQHq1WoyK1mSOzedz3UAfwhtDLUca7qGB3I=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "44f636f8cb95238dabd5f33d00557329c0681cd5",
+ "rev": "4c97b427ece2d45026ab6c5264adb67c763e7927",
"type": "github"
},
"original": {
@@ -57,11 +57,11 @@
},
"catppuccin": {
"locked": {
- "lastModified": 1724048768,
- "narHash": "sha256-OZ9OXsPQi+fNdMM7SBPtU8OB1ntLzOvUwA/3zYJY6Eo=",
+ "lastModified": 1724156255,
+ "narHash": "sha256-rpUCeS/QZwQdJmDrvCm0hRi8bFvQNQKAnIMK5ZDBfpM=",
"owner": "catppuccin",
"repo": "nix",
- "rev": "ff4128f8ea57879050145cf077a27b9d3a9cbf33",
+ "rev": "8886a68edadb1d93c7101337f995ffce4b410ff2",
"type": "github"
},
"original": {
@@ -404,11 +404,11 @@
"homebrew-cask": {
"flake": false,
"locked": {
- "lastModified": 1724120139,
- "narHash": "sha256-vVE53gBCJPc3/dj7OHvQ7mNuUk1bWVpNR4c0jKe+K9U=",
+ "lastModified": 1724279485,
+ "narHash": "sha256-izbAx5wx4QS332G9dJ/E1U/NA9nrUjS0qS6b1thPQuE=",
"owner": "homebrew",
"repo": "homebrew-cask",
- "rev": "606d3429e6fae79849c0eaf4bbcf05ff1570051a",
+ "rev": "761ddda3d71597c6b594af9416492fbf67ec813e",
"type": "github"
},
"original": {
@@ -420,11 +420,11 @@
"homebrew-core": {
"flake": false,
"locked": {
- "lastModified": 1724119620,
- "narHash": "sha256-p+M24z3IDeIJBppaWWTpaz63WMGvi3HGW/mQHQVYpgM=",
+ "lastModified": 1724279403,
+ "narHash": "sha256-k/OW0HDkdJHfo1E52PyfeEyBDH0LwXuM1VmmFxCvYk0=",
"owner": "homebrew",
"repo": "homebrew-core",
- "rev": "cd06a79081ce6e08b475e01315cdf1cb51952d77",
+ "rev": "7270362c593e96b2368834f6a87cd0d904874eb9",
"type": "github"
},
"original": {
@@ -502,11 +502,11 @@
]
},
"locked": {
- "lastModified": 1723859949,
- "narHash": "sha256-kiaGz4deGYKMjJPOji/JVvSP/eTefrIA3rAjOnOpXl4=",
+ "lastModified": 1724219898,
+ "narHash": "sha256-7PwlnEQDIbww8+nk0CHLeYTYMA23F/CkynHsX7Mxk+s=",
"owner": "LnL7",
"repo": "nix-darwin",
- "rev": "076b9a905af8a52b866c8db068d6da475839d97b",
+ "rev": "d6703b988728b89456b32bac242c8689902e5a5b",
"type": "github"
},
"original": {
@@ -651,11 +651,11 @@
"treefmt-nix": "treefmt-nix"
},
"locked": {
- "lastModified": 1724118730,
- "narHash": "sha256-UwtVD2FyD7FjfLLmqGLsCBCQgLC1Jj78e1PhiVb0MJk=",
+ "lastModified": 1724222231,
+ "narHash": "sha256-IFlMn1lgVsZQZC9WklY9YKcCdI0mUxSYZ7EfkaKCsQU=",
"owner": "nix-community",
"repo": "nixvim",
- "rev": "39081a41067a7bdb66f6f85a3fee9693ff8a21b1",
+ "rev": "b7f419a759f70126e220533b724cc17e8528b184",
"type": "github"
},
"original": {
@@ -773,11 +773,11 @@
},
"stablepkgs": {
"locked": {
- "lastModified": 1723938990,
- "narHash": "sha256-9tUadhnZQbWIiYVXH8ncfGXGvkNq3Hag4RCBEMUk7MI=",
+ "lastModified": 1724098845,
+ "narHash": "sha256-D5HwjQw/02fuXbR4LCTo64koglP2j99hkDR79/3yLOE=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "c42fcfbdfeae23e68fc520f9182dde9f38ad1890",
+ "rev": "f1bad50880bae73ff2d82fafc22010b4fc097a9c",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 95eda5d..8282dc3 100755
--- a/flake.nix
+++ b/flake.nix
@@ -3,38 +3,52 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
+
stablepkgs.url = "github:nixos/nixpkgs/nixos-24.05";
+
bleedingpkgs.url = "github:nixos/nixpkgs/master";
- nix-darwin.url = "github:LnL7/nix-darwin";
- nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
+
+ nix-darwin = {
+ url = "github:LnL7/nix-darwin";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
nix-homebrew.url = "github:zhaofengli-wip/nix-homebrew";
+
homebrew-core = {
url = "github:homebrew/homebrew-core";
flake = false;
};
+
homebrew-cask = {
url = "github:homebrew/homebrew-cask";
flake = false;
};
+
catppuccin.url = "github:catppuccin/nix";
+
lanzaboote = {
url = "github:nix-community/lanzaboote/v0.4.1";
# Optional but recommended to limit the size of your system closure.
inputs.nixpkgs.follows = "nixpkgs";
};
+
lix-module = {
url = "https://git.lix.systems/lix-project/nixos-module/archive/2.90.0.tar.gz";
inputs.nixpkgs.follows = "nixpkgs";
};
+
apple-silicon = {
url = "github:tpwrules/nixos-apple-silicon";
inputs.nixpkgs.follows = "nixpkgs";
};
+
nixvim = {
url = "github:nix-community/nixvim";
inputs.nixpkgs.follows = "nixpkgs";
@@ -54,85 +68,33 @@
nix-homebrew,
apple-silicon,
...
- } @ inputs: rec {
- formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.alejandra;
+ } @ inputs: let
+ in rec {
+ formatter = with nixpkgs.legacyPackages; {
+ x86_64-linux = x86_64-linux.alejandra;
+ aarch64-linux = aarch64-linux.alejandra;
+ aarch64-darwin = aarch64-darwin.alejandra;
+ };
+
nixosConfigurations = {
demeter = nixpkgs.lib.nixosSystem {
- specialArgs = {inherit inputs;};
system = "x86_64-linux";
+ specialArgs = {
+ inherit inputs;
+ system = "x86_64-linux";
+ };
modules = [
./hosts/demeter
- ./modules/nixos/gaming
- ./modules/nixos/audio
- ./modules/nixos/networking
- ./modules/nixos/fonts
- ./modules/nixos/greeter
- ./modules/nixos/core
- ./overlays
-
- catppuccin.nixosModules.catppuccin
- lix-module.nixosModules.default
- lanzaboote.nixosModules.lanzaboote
- home-manager.nixosModules.home-manager
- {
- home-manager.useGlobalPkgs = true;
- home-manager.useUserPackages = true;
- home-manager.backupFileExtension = "backup";
- home-manager.users.youwen = {
- imports = [
- ./users/youwen/linux/desktop
- ./users/youwen/linux/packages/x86_64
- ./users/youwen/linux/programs
- ./users/youwen/common/neofetch
- ./users/youwen/common/neovim
- ./users/youwen/common
- inputs.catppuccin.homeManagerModules.catppuccin
- inputs.nixvim.homeManagerModules.nixvim
- ];
- };
- }
];
};
+
callisto = nixpkgs.lib.nixosSystem {
- specialArgs = {inherit inputs;};
- system = "aarch64-linux";
+ specialArgs = {
+ inherit inputs;
+ system = "aarch64-linux";
+ };
modules = [
./hosts/callisto
- ./modules/nixos/audio
- ./modules/nixos/networking
- ./modules/nixos/fonts
- ./modules/nixos/greeter
- ./modules/nixos/core
-
- apple-silicon.nixosModules.apple-silicon-support
- catppuccin.nixosModules.catppuccin
- lix-module.nixosModules.default
- home-manager.nixosModules.home-manager
- {
- home-manager.useGlobalPkgs = true;
- home-manager.useUserPackages = true;
- home-manager.backupFileExtension = "backup";
- home-manager.users.youwen = {
- imports = [
- ./users/youwen/common
- ./users/youwen/common/neofetch/asahi-only.nix
- ./users/youwen/linux/laptop
- ./users/youwen/linux/packages/aarch-64
- ./users/youwen/common/neovim
-
- inputs.catppuccin.homeManagerModules.catppuccin
- inputs.nixvim.homeManagerModules.nixvim
- ];
- };
- }
- {
- nixpkgs.overlays = [
- (self: super: {
- signal-desktop =
- bleedingpkgs.legacyPackages.${self.system}.signal-desktop;
- })
- ];
- }
];
};
adrastea = nixpkgs.lib.nixosSystem {
@@ -140,65 +102,13 @@
system = "x86_64-linux";
modules = [
./hosts/adrastea
- ./modules/nixos/gaming
- ./modules/nixos/audio
- ./modules/nixos/networking
- ./modules/nixos/fonts
- ./modules/nixos/greeter
- ./modules/nixos/core
-
- catppuccin.nixosModules.catppuccin
- lix-module.nixosModules.default
- # lanzaboote.nixosModules.lanzaboote
- home-manager.nixosModules.home-manager
- {
- home-manager.useGlobalPkgs = true;
- home-manager.useUserPackages = true;
- home-manager.backupFileExtension = "backup";
- home-manager.users.youwen = {
- imports = [
- ./users/youwen/linux/laptop
- ./users/youwen/linux/packages/x86_64
- ./users/youwen/linux/programs
- ./users/youwen/common/neovim
- ./users/youwen/common
- ./users/youwen/common/neofetch
- ./hosts/adrastea/home-manager-overrides.nix
- inputs.catppuccin.homeManagerModules.catppuccin
- inputs.nixvim.homeManagerModules.nixvim
- ];
- };
- }
];
};
};
- formatter.aarch64-darwin = nixpkgs.legacyPackages.aarch64-darwin.alejandra;
- formatter.aarch64-linux = nixpkgs.legacyPackages.aarch64-linux.alejandra;
- # Build darwin flake using:
- # $ darwin-rebuild build --flake .#Youwens-MacBook-Pro
darwinConfigurations.phobos = nix-darwin.lib.darwinSystem {
specialArgs = {inherit inputs;};
modules = [
./hosts/phobos
- home-manager.darwinModules.home-manager
- {
- home-manager.useGlobalPkgs = true;
- home-manager.useUserPackages = true;
- home-manager.users.youwen.imports = [
- ./users/youwen/darwin/darwin-home.nix
- ./users/youwen/common/core.nix
- ./users/youwen/common/neofetch
- ./users/youwen/common/neovim
- ];
- home-manager.backupFileExtension = "backup";
-
- # Optionally, use home-manager.extraSpecialArgs to pass
- # arguments to home.nix
- }
- nix-homebrew.darwinModules.nix-homebrew
- ./modules/darwin/homebrew.nix
- ./modules/darwin/yabai.nix
- ./modules/darwin/skhd.nix
];
};
};
diff --git a/hosts/adrastea/configuration.nix b/hosts/adrastea/configuration.nix
new file mode 100755
index 0000000..be473ef
--- /dev/null
+++ b/hosts/adrastea/configuration.nix
@@ -0,0 +1,227 @@
+# Edit this configuration file to define what should be installed on
+# your system. Help is available in the configuration.nix(5) man page
+# and in the NixOS manual (accessible by running ‘nixos-help’).
+{
+ config,
+ inputs,
+ pkgs,
+ lib,
+ ...
+}: {
+ imports = [
+ # Include the results of the hardware scan.
+ ./hardware-configuration.nix
+ ];
+
+ # Bootloader.
+ boot.loader = {
+ efi.canTouchEfiVariables = true;
+ timeout = 15;
+ # Lanzaboote currently replaces the systemd-boot module.
+ # This setting is usually set to true in configuration.nix
+ # generated at installation time. So we force it to false
+ # for now.
+ systemd-boot = {
+ enable = true;
+ consoleMode = "auto";
+ };
+ };
+
+ # boot.lanzaboote = {
+ # enable = false;
+ # pkiBundle = "/etc/secureboot";
+ # };
+
+ services.keyd = {
+ enable = true;
+ keyboards = {
+ default = {
+ ids = ["*"];
+ settings = {
+ main = {
+ capslock = "esc";
+ leftalt = "leftcontrol";
+ leftcontrol = "leftalt";
+ };
+ };
+ };
+ };
+ };
+
+ boot.initrd.luks.devices."luks-52d1be6d-b32f-41e0-a6d7-2ff52599fe7c".device = "/dev/disk/by-uuid/52d1be6d-b32f-41e0-a6d7-2ff52599fe7c";
+
+ services.tlp.enable = true;
+
+ networking.hostName = "adrastea"; # Define your hostname.
+ # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
+
+ # select kernel
+ boot.kernelPackages = pkgs.linuxPackages_zen;
+
+ # Configure network proxy if necessary
+ # networking.proxy.default = "http://user:password@proxy:port/";
+ # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
+
+ # Enable networking
+ networking.networkmanager.enable = true;
+
+ # Set your time zone.
+ time.timeZone = "America/Los_Angeles";
+
+ # Select internationalisation properties.
+ i18n.defaultLocale = "en_US.UTF-8";
+
+ i18n.extraLocaleSettings = {
+ LC_ADDRESS = "en_US.UTF-8";
+ LC_IDENTIFICATION = "en_US.UTF-8";
+ LC_MEASUREMENT = "en_US.UTF-8";
+ LC_MONETARY = "en_US.UTF-8";
+ LC_NAME = "en_US.UTF-8";
+ LC_NUMERIC = "en_US.UTF-8";
+ LC_PAPER = "en_US.UTF-8";
+ LC_TELEPHONE = "en_US.UTF-8";
+ LC_TIME = "en_US.UTF-8";
+ };
+
+ systemd.services = {NetworkManager-wait-online.enable = false;};
+
+ # Enable the X11 windowing system.
+ # You can disable this if you're only using the Wayland session.
+ services.xserver.enable = false;
+
+ programs.nix-ld = {
+ enable = true;
+ libraries = with pkgs; [icu xorg.libXtst xorg.libXi];
+ };
+
+ hardware.nvidia = {
+ modesetting.enable = true;
+ powerManagement.enable = true;
+ powerManagement.finegrained = false;
+ open = false;
+ nvidiaSettings = true;
+ prime = {
+ amdgpuBusId = "PCI:4:0:0";
+ nvidiaBusId = "PCI:1:0:0";
+ offload = {
+ enable = true;
+ enableOffloadCmd = true;
+ };
+ };
+ };
+
+ hardware.graphics.enable = true;
+
+ hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.stable;
+
+ services.xserver.videoDrivers = ["nvidia"];
+
+ # services.desktopManager.plasma6.enable = true;
+
+ # Configure keymap in X11
+ services.xserver = {
+ xkb.layout = "us";
+ xkb.variant = "";
+ };
+
+ # Enable CUPS to print documents.
+ services.printing.enable = true;
+
+ # Enable touchpad support (enabled default in most desktopManager).
+ # services.xserver.libinput.enable = true;
+
+ # Define a user account. Don't forget to set a password with ‘passwd’.
+ users.users.youwen = {
+ isNormalUser = true;
+ description = "Youwen Wu";
+ extraGroups = ["networkmanager" "wheel" "nixos" "realtime"];
+ };
+
+ users.groups.realtime = {};
+
+ nix.settings = {
+ trusted-users = ["root" "youwen"];
+ experimental-features = ["nix-command" "flakes"];
+ };
+
+ services.udev.extraRules = ''
+ KERNEL=="cpu_dma_latency", GROUP="realtime"
+ '';
+
+ security.pam.loginLimits = [
+ {
+ domain = "@realtime";
+ type = "-";
+ item = "rtprio";
+ value = 98;
+ }
+ {
+ domain = "@realtime";
+ type = "-";
+ item = "memlock";
+ value = "unlimited";
+ }
+ {
+ domain = "@realtime";
+ type = "-";
+ item = "nice";
+ value = -11;
+ }
+ ];
+
+ # Allow unfree packages
+ nixpkgs.config.allowUnfree = true;
+
+ # List packages installed in system profile. To search, run:
+ # $ nix search wget
+ environment.systemPackages = with pkgs; [
+ neovim
+ wget
+ git
+ curl
+ librewolf
+ gnumake
+ gcc
+ cachix
+ gnupg
+ openssh
+ python3
+ steam-run
+
+ # deps for neovim compilation
+ lua51Packages.lua
+ lua51Packages.luarocks
+ tree-sitter
+ ];
+
+ environment.variables = {
+ EDITOR = "nvim";
+ NIX_AUTO_RUN = 1;
+ };
+
+ # tells electron apps to use Wayland
+ environment.sessionVariables.NIXOS_OZONE_WL = "1";
+
+ # Some programs need SUID wrappers, can be configured further or are
+ # started in user sessions.
+ # programs.mtr.enable = true;
+ programs.gnupg.agent = {
+ enable = true;
+ enableSSHSupport = true;
+ };
+
+ programs.dconf.enable = true;
+
+ programs.hyprland.enable = true;
+
+ programs.zsh.enable = false;
+ programs.fish.enable = true;
+ users.users.youwen.shell = pkgs.fish;
+ # This value determines the NixOS release from which the default
+ # settings for stateful data, like file locations and database versions
+ # on your system were taken. It‘s perfectly fine and recommended to leave
+ # this value at the release version of the first install of this system.
+ # Before changing this value read the documentation for this option
+ # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+ system.stateVersion = "24.05"; # Did you read the comment?
+}
diff --git a/hosts/adrastea/default.nix b/hosts/adrastea/default.nix
old mode 100755
new mode 100644
index be473ef..f7c9779
--- a/hosts/adrastea/default.nix
+++ b/hosts/adrastea/default.nix
@@ -1,227 +1,35 @@
-# Edit this configuration file to define what should be installed on
-# your system. Help is available in the configuration.nix(5) man page
-# and in the NixOS manual (accessible by running ‘nixos-help’).
-{
- config,
- inputs,
- pkgs,
- lib,
- ...
-}: {
- imports = [
- # Include the results of the hardware scan.
- ./hardware-configuration.nix
- ];
+{inputs, ...}: {
+ imports = with inputs; [
+ ./configuration.nix
+ ../../modules/nixos/gaming
+ ../../modules/nixos/audio
+ ../../modules/nixos/networking
+ ../../modules/nixos/fonts
+ ../../modules/nixos/greeter
+ ../../modules/nixos/core
+ ../../overlays
- # Bootloader.
- boot.loader = {
- efi.canTouchEfiVariables = true;
- timeout = 15;
- # Lanzaboote currently replaces the systemd-boot module.
- # This setting is usually set to true in configuration.nix
- # generated at installation time. So we force it to false
- # for now.
- systemd-boot = {
- enable = true;
- consoleMode = "auto";
- };
- };
-
- # boot.lanzaboote = {
- # enable = false;
- # pkiBundle = "/etc/secureboot";
- # };
-
- services.keyd = {
- enable = true;
- keyboards = {
- default = {
- ids = ["*"];
- settings = {
- main = {
- capslock = "esc";
- leftalt = "leftcontrol";
- leftcontrol = "leftalt";
- };
- };
+ catppuccin.nixosModules.catppuccin
+ lix-module.nixosModules.default
+ # lanzaboote.nixosModules.lanzaboote
+ home-manager.nixosModules.home-manager
+ {
+ home-manager.useGlobalPkgs = true;
+ home-manager.useUserPackages = true;
+ home-manager.backupFileExtension = "backup";
+ home-manager.users.youwen = {
+ imports = [
+ ./home-manager-extras
+ ../../users/youwen/linux/laptop
+ ../../users/youwen/linux/packages/x86_64
+ ../../users/youwen/linux/programs
+ ../../users/youwen/common/neovim
+ ../../users/youwen/common
+ ../../users/youwen/common/neofetch
+ inputs.catppuccin.homeManagerModules.catppuccin
+ inputs.nixvim.homeManagerModules.nixvim
+ ];
};
- };
- };
-
- boot.initrd.luks.devices."luks-52d1be6d-b32f-41e0-a6d7-2ff52599fe7c".device = "/dev/disk/by-uuid/52d1be6d-b32f-41e0-a6d7-2ff52599fe7c";
-
- services.tlp.enable = true;
-
- networking.hostName = "adrastea"; # Define your hostname.
- # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
-
- # select kernel
- boot.kernelPackages = pkgs.linuxPackages_zen;
-
- # Configure network proxy if necessary
- # networking.proxy.default = "http://user:password@proxy:port/";
- # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
-
- # Enable networking
- networking.networkmanager.enable = true;
-
- # Set your time zone.
- time.timeZone = "America/Los_Angeles";
-
- # Select internationalisation properties.
- i18n.defaultLocale = "en_US.UTF-8";
-
- i18n.extraLocaleSettings = {
- LC_ADDRESS = "en_US.UTF-8";
- LC_IDENTIFICATION = "en_US.UTF-8";
- LC_MEASUREMENT = "en_US.UTF-8";
- LC_MONETARY = "en_US.UTF-8";
- LC_NAME = "en_US.UTF-8";
- LC_NUMERIC = "en_US.UTF-8";
- LC_PAPER = "en_US.UTF-8";
- LC_TELEPHONE = "en_US.UTF-8";
- LC_TIME = "en_US.UTF-8";
- };
-
- systemd.services = {NetworkManager-wait-online.enable = false;};
-
- # Enable the X11 windowing system.
- # You can disable this if you're only using the Wayland session.
- services.xserver.enable = false;
-
- programs.nix-ld = {
- enable = true;
- libraries = with pkgs; [icu xorg.libXtst xorg.libXi];
- };
-
- hardware.nvidia = {
- modesetting.enable = true;
- powerManagement.enable = true;
- powerManagement.finegrained = false;
- open = false;
- nvidiaSettings = true;
- prime = {
- amdgpuBusId = "PCI:4:0:0";
- nvidiaBusId = "PCI:1:0:0";
- offload = {
- enable = true;
- enableOffloadCmd = true;
- };
- };
- };
-
- hardware.graphics.enable = true;
-
- hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.stable;
-
- services.xserver.videoDrivers = ["nvidia"];
-
- # services.desktopManager.plasma6.enable = true;
-
- # Configure keymap in X11
- services.xserver = {
- xkb.layout = "us";
- xkb.variant = "";
- };
-
- # Enable CUPS to print documents.
- services.printing.enable = true;
-
- # Enable touchpad support (enabled default in most desktopManager).
- # services.xserver.libinput.enable = true;
-
- # Define a user account. Don't forget to set a password with ‘passwd’.
- users.users.youwen = {
- isNormalUser = true;
- description = "Youwen Wu";
- extraGroups = ["networkmanager" "wheel" "nixos" "realtime"];
- };
-
- users.groups.realtime = {};
-
- nix.settings = {
- trusted-users = ["root" "youwen"];
- experimental-features = ["nix-command" "flakes"];
- };
-
- services.udev.extraRules = ''
- KERNEL=="cpu_dma_latency", GROUP="realtime"
- '';
-
- security.pam.loginLimits = [
- {
- domain = "@realtime";
- type = "-";
- item = "rtprio";
- value = 98;
- }
- {
- domain = "@realtime";
- type = "-";
- item = "memlock";
- value = "unlimited";
- }
- {
- domain = "@realtime";
- type = "-";
- item = "nice";
- value = -11;
}
];
-
- # Allow unfree packages
- nixpkgs.config.allowUnfree = true;
-
- # List packages installed in system profile. To search, run:
- # $ nix search wget
- environment.systemPackages = with pkgs; [
- neovim
- wget
- git
- curl
- librewolf
- gnumake
- gcc
- cachix
- gnupg
- openssh
- python3
- steam-run
-
- # deps for neovim compilation
- lua51Packages.lua
- lua51Packages.luarocks
- tree-sitter
- ];
-
- environment.variables = {
- EDITOR = "nvim";
- NIX_AUTO_RUN = 1;
- };
-
- # tells electron apps to use Wayland
- environment.sessionVariables.NIXOS_OZONE_WL = "1";
-
- # Some programs need SUID wrappers, can be configured further or are
- # started in user sessions.
- # programs.mtr.enable = true;
- programs.gnupg.agent = {
- enable = true;
- enableSSHSupport = true;
- };
-
- programs.dconf.enable = true;
-
- programs.hyprland.enable = true;
-
- programs.zsh.enable = false;
- programs.fish.enable = true;
- users.users.youwen.shell = pkgs.fish;
- # This value determines the NixOS release from which the default
- # settings for stateful data, like file locations and database versions
- # on your system were taken. It‘s perfectly fine and recommended to leave
- # this value at the release version of the first install of this system.
- # Before changing this value read the documentation for this option
- # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
- system.stateVersion = "24.05"; # Did you read the comment?
}
diff --git a/hosts/adrastea/home-manager-overrides.nix b/hosts/adrastea/home-manager-extras/default.nix
similarity index 100%
rename from hosts/adrastea/home-manager-overrides.nix
rename to hosts/adrastea/home-manager-extras/default.nix
diff --git a/hosts/callisto/asahi-fix.patch b/hosts/callisto/asahi-fix.patch
new file mode 100644
index 0000000..03c87c8
--- /dev/null
+++ b/hosts/callisto/asahi-fix.patch
@@ -0,0 +1,5062 @@
+diff --git a/.gitignore b/.gitignore
+index 78f794fc..2e158a4e 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -37,3 +37,5 @@ gmon.out
+ PKGBUILD
+
+ src/version.h
++hyprpm/Makefile
++hyprctl/Makefile
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index fc8eafd5..f26a5c3c 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -62,7 +62,7 @@ else()
+ endif()
+
+ include_directories(. "src/" "subprojects/udis86/" "protocols/")
+-set(CMAKE_CXX_STANDARD 23)
++set(CMAKE_CXX_STANDARD 26)
+ add_compile_options(
+ -Wall
+ -Wextra
+@@ -117,6 +117,7 @@ pkg_check_modules(
+ libliftoff
+ libudev
+ gbm
++ gio-2.0
+ hyprlang>=0.3.2
+ hyprcursor>=0.1.7
+ hyprutils>=0.2.1)
+@@ -329,7 +330,7 @@ install(
+ CODE "execute_process( \
+ COMMAND ${CMAKE_COMMAND} -E create_symlink \
+ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
+- ${CMAKE_INSTALL_FULL_BINDIR}/hyprland
++ \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \
+ )")
+
+ # session file
+diff --git a/README.md b/README.md
+index fc2bd206..f271c29c 100644
+--- a/README.md
++++ b/README.md
+@@ -1,6 +1,6 @@
+
+
+-
++
+
+
+
+@@ -125,7 +125,6 @@ easy IPC, much more QoL stuff than other compositors and more...
+
+
+
+-[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
+ [Preview A]: https://i.ibb.co/C1yTb0r/falf.png
+ [Preview B]: https://linfindel.github.io/cdn/hyprland-preview-b.png
+ [Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
+diff --git a/flake.lock b/flake.lock
+index 5c384d4d..c70d31d1 100644
+--- a/flake.lock
++++ b/flake.lock
+@@ -16,11 +16,11 @@
+ ]
+ },
+ "locked": {
+- "lastModified": 1722347739,
+- "narHash": "sha256-rAoh+K6KG+b1DwSWtqRVocdojnH6nGk6q07mNltoUSM=",
++ "lastModified": 1723920171,
++ "narHash": "sha256-dVCMrAe+D/5S91erhwQj2DSzHOVzAanWqoy+vPWB9DY=",
+ "owner": "hyprwm",
+ "repo": "aquamarine",
+- "rev": "7c3565f9bedc7cb601cc0baa14792247e4dc1d5a",
++ "rev": "71d49670fe246cdaff4860b0effba0ab9f163b72",
+ "type": "github"
+ },
+ "original": {
+@@ -42,11 +42,11 @@
+ ]
+ },
+ "locked": {
+- "lastModified": 1721330371,
+- "narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=",
++ "lastModified": 1722623071,
++ "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=",
+ "owner": "hyprwm",
+ "repo": "hyprcursor",
+- "rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc",
++ "rev": "912d56025f03d41b1ad29510c423757b4379eb1c",
+ "type": "github"
+ },
+ "original": {
+@@ -116,11 +116,11 @@
+ ]
+ },
+ "locked": {
+- "lastModified": 1722098849,
+- "narHash": "sha256-D3wIZlBNh7LuZ0NaoCpY/Pvu+xHxIVtSN+KkWZYvvVs=",
++ "lastModified": 1722869141,
++ "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=",
+ "owner": "hyprwm",
+ "repo": "hyprutils",
+- "rev": "5dcbbc1e3de40b2cecfd2007434d86e924468f1f",
++ "rev": "0252fd13e78e60fb0da512a212e56007515a49f7",
+ "type": "github"
+ },
+ "original": {
+@@ -154,11 +154,11 @@
+ },
+ "nixpkgs": {
+ "locked": {
+- "lastModified": 1722185531,
+- "narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=",
++ "lastModified": 1723637854,
++ "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+- "rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d",
++ "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9",
+ "type": "github"
+ },
+ "original": {
+diff --git a/flake.nix b/flake.nix
+index 9c20b3f5..9e1e3ab4 100644
+--- a/flake.nix
++++ b/flake.nix
+@@ -95,7 +95,7 @@
+ devShells = eachSystem (system: {
+ default =
+ pkgsFor.${system}.mkShell.override {
+- stdenv = pkgsFor.${system}.gcc13Stdenv;
++ stdenv = pkgsFor.${system}.gcc14Stdenv;
+ } {
+ name = "hyprland-shell";
+ nativeBuildInputs = with pkgsFor.${system}; [
+diff --git a/hyprctl/Makefile b/hyprctl/Makefile
+deleted file mode 100644
+index 9798320c..00000000
+--- a/hyprctl/Makefile
++++ /dev/null
+@@ -1,4 +0,0 @@
+-all:
+- $(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
+-clean:
+- rm ./hyprctl
+diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp
+index 336d479e..5d5113b8 100644
+--- a/hyprctl/main.cpp
++++ b/hyprctl/main.cpp
+@@ -26,6 +26,7 @@
+ #include
+ #include
+ #include
++#include
+ using namespace Hyprutils::String;
+
+ #include "Strings.hpp"
+@@ -113,7 +114,7 @@ int rollingRead(const int socket) {
+
+ constexpr size_t BUFFER_SIZE = 8192;
+ std::array buffer = {0};
+- int sizeWritten = 0;
++ long sizeWritten = 0;
+ std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
+ while (!sigintReceived) {
+ sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
+diff --git a/meson.build b/meson.build
+index 886f4f9c..6a9b7ac5 100644
+--- a/meson.build
++++ b/meson.build
+@@ -6,7 +6,7 @@ project('Hyprland', 'cpp', 'c',
+ 'optimization=3',
+ 'buildtype=release',
+ 'debug=false',
+- 'cpp_std=c++23',
++ 'cpp_std=c++26',
+ ])
+
+ datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"'
+@@ -34,6 +34,8 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland'))
+ xcb_res_dep = dependency('xcb-res', required: get_option('xwayland'))
+ xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
+
++gio_dep = dependency('gio-2.0', required:true)
++
+ cmake = import('cmake')
+ udis = cmake.subproject('udis86')
+ udis86 = udis.dependency('libudis86')
+diff --git a/nix/default.nix b/nix/default.nix
+index e4e12f43..9bae9d83 100644
+--- a/nix/default.nix
++++ b/nix/default.nix
+@@ -71,6 +71,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
+ src = lib.cleanSource ../.;
+ };
+
++ patches = [
++ # forces GCC to use -std=c++26
++ ./stdcxx.patch
++ ];
++
+ postPatch = ''
+ # Fix hardcoded paths to /usr installation
+ sed -i "s#/usr#$out#" src/render/OpenGL.cpp
+diff --git a/nix/overlays.nix b/nix/overlays.nix
+index d8979b45..36206f46 100644
+--- a/nix/overlays.nix
++++ b/nix/overlays.nix
+@@ -31,7 +31,7 @@ in {
+ date = mkDate (self.lastModifiedDate or "19700101");
+ in {
+ hyprland = final.callPackage ./default.nix {
+- stdenv = final.gcc13Stdenv;
++ stdenv = final.gcc14Stdenv;
+ version = "${version}+date=${date}_${self.shortRev or "dirty"}";
+ commit = self.rev or "";
+ inherit date;
+diff --git a/nix/stdcxx.patch b/nix/stdcxx.patch
+new file mode 100644
+index 00000000..032e494d
+--- /dev/null
++++ b/nix/stdcxx.patch
+@@ -0,0 +1,12 @@
++diff --git a/CMakeLists.txt b/CMakeLists.txt
++index cfbd431f..73e8e0c2 100644
++--- a/CMakeLists.txt
+++++ b/CMakeLists.txt
++@@ -64,6 +64,7 @@ endif()
++ include_directories(. "src/" "subprojects/udis86/" "protocols/")
++ set(CMAKE_CXX_STANDARD 26)
++ add_compile_options(
+++ -std=c++26
++ -Wall
++ -Wextra
++ -Wno-unused-parameter
+diff --git a/src/Compositor.cpp b/src/Compositor.cpp
+index 49408597..9d247a56 100644
+--- a/src/Compositor.cpp
++++ b/src/Compositor.cpp
+@@ -305,6 +305,10 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
+
+ setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
+ setenv("XDG_SESSION_TYPE", "wayland", 1);
++ if (!getenv("XDG_CURRENT_DESKTOP")) {
++ setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1);
++ m_bDesktopEnvSet = true;
++ }
+
+ initManagers(STAGE_BASICINIT);
+
+@@ -393,6 +397,7 @@ void CCompositor::initAllSignals() {
+ }
+
+ g_pConfigManager->m_bWantsMonitorReload = true;
++ g_pCursorManager->syncGsettings();
+ } else {
+ Debug::log(LOG, "Session got deactivated!");
+
+@@ -421,9 +426,10 @@ void CCompositor::cleanEnvironment() {
+ // in main
+ unsetenv("HYPRLAND_CMD");
+ unsetenv("XDG_BACKEND");
+- unsetenv("XDG_CURRENT_DESKTOP");
++ if (m_bDesktopEnvSet)
++ unsetenv("XDG_CURRENT_DESKTOP");
+
+- if (m_pAqBackend->hasSession()) {
++ if (m_pAqBackend->hasSession() && !envEnabled("HYPRLAND_NO_SD_VARS")) {
+ const auto CMD =
+ #ifdef USES_SYSTEMD
+ "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
+@@ -552,6 +558,10 @@ void CCompositor::initManagers(eManagersInitStage stage) {
+
+ g_pConfigManager->init();
+ g_pWatchdog = std::make_unique(); // requires config
++ // wait for watchdog to initialize to not hit data races in reading config values.
++ while (!g_pWatchdog->m_bWatchdogInitialized) {
++ std::this_thread::yield();
++ }
+
+ Debug::log(LOG, "Creating the PointerManager!");
+ g_pPointerManager = std::make_unique();
+@@ -649,7 +659,11 @@ void CCompositor::prepareFallbackOutput() {
+ void CCompositor::startCompositor() {
+ signal(SIGPIPE, SIG_IGN);
+
+- if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
++ if (
++ /* Session-less Hyprland usually means a nest, don't update the env in that case */
++ m_pAqBackend->hasSession() &&
++ /* Activation environment management is not disabled */
++ !envEnabled("HYPRLAND_NO_SD_VARS")) {
+ const auto CMD =
+ #ifdef USES_SYSTEMD
+ "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
+@@ -683,9 +697,9 @@ void CCompositor::startCompositor() {
+ g_pEventLoopManager->enterLoop();
+ }
+
+-CMonitor* CCompositor::getMonitorFromID(const int& id) {
++CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) {
+ for (auto& m : m_vMonitors) {
+- if (m->ID == (uint64_t)id) {
++ if (m->ID == id) {
+ return m.get();
+ }
+ }
+@@ -845,8 +859,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
+ if (properties & FLOATING_ONLY)
+ return floating(false);
+
+- const int64_t WORKSPACEID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID();
+- const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
++ const WORKSPACEID WSPID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID();
++ const auto PWORKSPACE = getWorkspaceByID(WSPID);
+
+ if (PWORKSPACE->m_bHasFullscreenWindow)
+ return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
+@@ -860,7 +874,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
+ if (special != w->onSpecialWorkspace())
+ continue;
+
+- if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
++ if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
+ !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) {
+ if (w->hasPopupAt(pos))
+ return w;
+@@ -872,7 +886,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
+ continue;
+
+ CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
+- if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
++ if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
+ !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow)
+ return w;
+ }
+@@ -1207,7 +1221,7 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) {
+ return nullptr;
+ }
+
+-PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const int& ID) {
++PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) {
+ for (auto& w : m_vWindows) {
+ if (w->workspaceID() == ID && w->isFullscreen())
+ return w;
+@@ -1231,7 +1245,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) {
+ return PMONITOR->activeWorkspace->m_iID == w->m_iID;
+ }
+
+-PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) {
++PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) {
+ for (auto& w : m_vWorkspaces) {
+ if (w->m_iID == id && !w->inert())
+ return w;
+@@ -1255,7 +1269,7 @@ void CCompositor::sanityCheckWorkspaces() {
+ }
+ }
+
+-int CCompositor::getWindowsOnWorkspace(const int& id, std::optional onlyTiled, std::optional onlyVisible) {
++int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) {
+ int no = 0;
+ for (auto& w : m_vWindows) {
+ if (w->workspaceID() != id || !w->m_bIsMapped)
+@@ -1270,7 +1284,7 @@ int CCompositor::getWindowsOnWorkspace(const int& id, std::optional onlyTi
+ return no;
+ }
+
+-int CCompositor::getGroupsOnWorkspace(const int& id, std::optional onlyTiled, std::optional onlyVisible) {
++int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) {
+ int no = 0;
+ for (auto& w : m_vWindows) {
+ if (w->workspaceID() != id || !w->m_bIsMapped)
+@@ -1295,7 +1309,7 @@ PHLWINDOW CCompositor::getUrgentWindow() {
+ return nullptr;
+ }
+
+-bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) {
++bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) {
+ for (auto& w : m_vWindows) {
+ if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent)
+ return true;
+@@ -1304,7 +1318,7 @@ bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) {
+ return false;
+ }
+
+-PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) {
++PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) {
+ for (auto& w : m_vWindows) {
+ if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden())
+ return w;
+@@ -1313,7 +1327,7 @@ PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) {
+ return nullptr;
+ }
+
+-PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const int& id) {
++PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) {
+ const auto PWORKSPACE = getWorkspaceByID(id);
+
+ if (!PWORKSPACE)
+@@ -1401,12 +1415,12 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
+ }
+ }
+
+-void CCompositor::cleanupFadingOut(const int& monid) {
++void CCompositor::cleanupFadingOut(const MONITORID& monid) {
+ for (auto& ww : m_vWindowsFadingOut) {
+
+ auto w = ww.lock();
+
+- if (w->m_iMonitorID != (long unsigned int)monid)
++ if (w->m_iMonitorID != monid)
+ continue;
+
+ if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) {
+@@ -1702,8 +1716,8 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
+ return nullptr;
+ }
+
+-int CCompositor::getNextAvailableNamedWorkspace() {
+- int lowest = -1337 + 1;
++WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() {
++ WORKSPACEID lowest = -1337 + 1;
+ for (auto& w : m_vWorkspaces) {
+ if (w->m_iID < -1 && w->m_iID < lowest)
+ lowest = w->m_iID;
+@@ -1927,18 +1941,18 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
+ pWindow->updateWindowDecos();
+ }
+
+-int CCompositor::getNextAvailableMonitorID(std::string const& name) {
++MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) {
+ // reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor
+ if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; }))
+ return m_mMonitorIDMap[name];
+
+ // otherwise, find minimum available ID that is not in the map
+- std::unordered_set usedIDs;
++ std::unordered_set usedIDs;
+ for (auto const& monitor : m_vRealMonitors) {
+ usedIDs.insert(monitor->ID);
+ }
+
+- uint64_t nextID = 0;
++ MONITORID nextID = 0;
+ while (usedIDs.count(nextID) > 0) {
+ nextID++;
+ }
+@@ -2078,7 +2092,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
+ return m_vMonitors[currentPlace].get();
+ } else if (isNumber(name)) {
+ // change by ID
+- int monID = -1;
++ MONITORID monID = MONITOR_INVALID;
+ try {
+ monID = std::stoi(name);
+ } catch (std::exception& e) {
+@@ -2087,7 +2101,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
+ return nullptr;
+ }
+
+- if (monID > -1 && monID < (int)m_vMonitors.size()) {
++ if (monID > -1 && monID < (MONITORID)m_vMonitors.size()) {
+ return getMonitorFromID(monID);
+ } else {
+ Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1");
+@@ -2121,7 +2135,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
+ const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false;
+
+ // fix old mon
+- int nextWorkspaceOnMonitorID = -1;
++ WORKSPACEID nextWorkspaceOnMonitorID = WORKSPACE_INVALID;
+ if (!SWITCHINGISACTIVE)
+ nextWorkspaceOnMonitorID = pWorkspace->m_iID;
+ else {
+@@ -2132,7 +2146,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
+ }
+ }
+
+- if (nextWorkspaceOnMonitorID == -1) {
++ if (nextWorkspaceOnMonitorID == WORKSPACE_INVALID) {
+ nextWorkspaceOnMonitorID = 1;
+
+ while (getWorkspaceByID(nextWorkspaceOnMonitorID) || [&]() -> bool {
+@@ -2219,9 +2233,9 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
+ EMIT_HOOK_EVENT("moveWorkspace", (std::vector{pWorkspace, pMonitor}));
+ }
+
+-bool CCompositor::workspaceIDOutOfBounds(const int64_t& id) {
+- int64_t lowestID = INT64_MAX;
+- int64_t highestID = INT64_MIN;
++bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) {
++ WORKSPACEID lowestID = INT64_MAX;
++ WORKSPACEID highestID = INT64_MIN;
+
+ for (auto& w : m_vWorkspaces) {
+ if (w->m_bIsSpecialWorkspace)
+@@ -2370,7 +2384,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) {
+ return nullptr;
+ }
+
+-void CCompositor::updateWorkspaceWindowDecos(const int& id) {
++void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) {
+ for (auto& w : m_vWindows) {
+ if (w->workspaceID() != id)
+ continue;
+@@ -2379,7 +2393,7 @@ void CCompositor::updateWorkspaceWindowDecos(const int& id) {
+ }
+ }
+
+-void CCompositor::updateWorkspaceWindowData(const int& id) {
++void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) {
+ const auto PWORKSPACE = getWorkspaceByID(id);
+ const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
+
+@@ -2599,7 +2613,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
+ return Vector2D(X, Y);
+ }
+
+-void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
++void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) {
+ for (auto& w : m_vWindows) {
+ if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) {
+ g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
+@@ -2607,7 +2621,7 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
+ }
+ }
+
+-PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name, bool isEmtpy) {
++PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmtpy) {
+ const auto NAME = name == "" ? std::to_string(id) : name;
+ auto monID = monid;
+
+@@ -2625,7 +2639,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, co
+ return PWORKSPACE;
+ }
+
+-void CCompositor::renameWorkspace(const int& id, const std::string& name) {
++void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name) {
+ const auto PWORKSPACE = getWorkspaceByID(id);
+
+ if (!PWORKSPACE)
+@@ -2656,12 +2670,12 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
+ m_pLastMonitor = pMonitor->self;
+ }
+
+-bool CCompositor::isWorkspaceSpecial(const int& id) {
++bool CCompositor::isWorkspaceSpecial(const WORKSPACEID& id) {
+ return id >= SPECIAL_WORKSPACE_START && id <= -2;
+ }
+
+-int CCompositor::getNewSpecialID() {
+- int highest = SPECIAL_WORKSPACE_START;
++WORKSPACEID CCompositor::getNewSpecialID() {
++ WORKSPACEID highest = SPECIAL_WORKSPACE_START;
+ for (auto& ws : m_vWorkspaces) {
+ if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) {
+ highest = ws->m_iID;
+@@ -2918,39 +2932,6 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
+ return {};
+ }
+
+-static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) {
+- static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor");
+- static auto firstMonitorAdded = std::chrono::system_clock::now();
+- static bool cursorDefaultDone = false;
+- static bool firstLaunch = true;
+-
+- const auto POS = PNEWMONITOR->middle();
+-
+- // by default, cursor should be set to first monitor detected
+- // this is needed as a default if the monitor given in config above doesn't exist
+- if (firstLaunch) {
+- firstLaunch = false;
+- g_pCompositor->warpCursorTo(POS, true);
+- g_pInputManager->refocus();
+- }
+-
+- if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY)
+- return;
+-
+- // after 10s, don't set cursor to default monitor
+- auto timePassedSec = std::chrono::duration_cast(std::chrono::system_clock::now() - firstMonitorAdded);
+- if (timePassedSec.count() > 10) {
+- cursorDefaultDone = true;
+- return;
+- }
+-
+- if (*PCURSORMONITOR == monitorName) {
+- cursorDefaultDone = true;
+- g_pCompositor->warpCursorTo(POS, true);
+- g_pInputManager->refocus();
+- }
+-}
+-
+ void CCompositor::onNewMonitor(SP output) {
+ // add it to real
+ auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared());
+@@ -2965,7 +2946,7 @@ void CCompositor::onNewMonitor(SP output) {
+ PNEWMONITOR->output = output;
+ PNEWMONITOR->self = PNEWMONITOR;
+ const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false;
+- PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(output->name);
++ PNEWMONITOR->ID = FALLBACK ? MONITOR_INVALID : g_pCompositor->getNextAvailableMonitorID(output->name);
+ PNEWMONITOR->isUnsafeFallback = FALLBACK;
+
+ EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR);
+@@ -2986,11 +2967,9 @@ void CCompositor::onNewMonitor(SP output) {
+ g_pConfigManager->m_bWantsMonitorReload = true;
+ g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR);
+
+- checkDefaultCursorWarp(PNEWMONITOR, output->name);
+-
+ for (auto& w : g_pCompositor->m_vWindows) {
+ if (w->m_iMonitorID == PNEWMONITOR->ID) {
+- w->m_iLastSurfaceMonitorID = -1;
++ w->m_iLastSurfaceMonitorID = MONITOR_INVALID;
+ w->updateSurfaceScaleTransformDetails();
+ }
+ }
+diff --git a/src/Compositor.hpp b/src/Compositor.hpp
+index 295935c4..a570a06e 100644
+--- a/src/Compositor.hpp
++++ b/src/Compositor.hpp
+@@ -46,55 +46,56 @@ class CCompositor {
+ CCompositor();
+ ~CCompositor();
+
+- wl_display* m_sWLDisplay;
+- wl_event_loop* m_sWLEventLoop;
+- int m_iDRMFD = -1;
+- bool m_bInitialized = false;
+- SP m_pAqBackend;
+-
+- std::string m_szHyprTempDataRoot = "";
+-
+- std::string m_szWLDisplaySocket = "";
+- std::string m_szInstanceSignature = "";
+- std::string m_szInstancePath = "";
+- std::string m_szCurrentSplash = "error";
+-
+- std::vector> m_vMonitors;
+- std::vector> m_vRealMonitors; // for all monitors, even those turned off
+- std::vector m_vWindows;
+- std::vector m_vLayers;
+- std::vector m_vWorkspaces;
+- std::vector m_vWindowsFadingOut;
+- std::vector m_vSurfacesFadingOut;
+-
+- std::unordered_map m_mMonitorIDMap;
+-
+- void initServer(std::string socketName, int socketFd);
+- void startCompositor();
+- void stopCompositor();
+- void cleanup();
+- void createLockFile();
+- void removeLockFile();
+- void bumpNofile();
+- void restoreNofile();
+-
+- WP m_pLastFocus;
+- PHLWINDOWREF m_pLastWindow;
+- WP m_pLastMonitor;
+-
+- std::vector m_vWindowFocusHistory; // first element is the most recently focused.
+-
+- bool m_bReadyToProcess = false;
+- bool m_bSessionActive = true;
+- bool m_bDPMSStateON = true;
+- bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
+- bool m_bNextIsUnsafe = false;
+- CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
+- bool m_bIsShuttingDown = false;
++ wl_display* m_sWLDisplay;
++ wl_event_loop* m_sWLEventLoop;
++ int m_iDRMFD = -1;
++ bool m_bInitialized = false;
++ SP m_pAqBackend;
++
++ std::string m_szHyprTempDataRoot = "";
++
++ std::string m_szWLDisplaySocket = "";
++ std::string m_szInstanceSignature = "";
++ std::string m_szInstancePath = "";
++ std::string m_szCurrentSplash = "error";
++
++ std::vector> m_vMonitors;
++ std::vector> m_vRealMonitors; // for all monitors, even those turned off
++ std::vector m_vWindows;
++ std::vector m_vLayers;
++ std::vector m_vWorkspaces;
++ std::vector m_vWindowsFadingOut;
++ std::vector m_vSurfacesFadingOut;
++
++ std::unordered_map m_mMonitorIDMap;
++
++ void initServer(std::string socketName, int socketFd);
++ void startCompositor();
++ void stopCompositor();
++ void cleanup();
++ void createLockFile();
++ void removeLockFile();
++ void bumpNofile();
++ void restoreNofile();
++
++ WP m_pLastFocus;
++ PHLWINDOWREF m_pLastWindow;
++ WP m_pLastMonitor;
++
++ std::vector m_vWindowFocusHistory; // first element is the most recently focused.
++
++ bool m_bReadyToProcess = false;
++ bool m_bSessionActive = true;
++ bool m_bDPMSStateON = true;
++ bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
++ bool m_bNextIsUnsafe = false;
++ CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
++ bool m_bIsShuttingDown = false;
++ bool m_bDesktopEnvSet = false;
+
+ // ------------------------------------------------- //
+
+- CMonitor* getMonitorFromID(const int&);
++ CMonitor* getMonitorFromID(const MONITORID&);
+ CMonitor* getMonitorFromName(const std::string&);
+ CMonitor* getMonitorFromDesc(const std::string&);
+ CMonitor* getMonitorFromCursor();
+@@ -114,38 +115,38 @@ class CCompositor {
+ PHLWINDOW getWindowFromHandle(uint32_t);
+ bool isWorkspaceVisible(PHLWORKSPACE);
+ bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
+- PHLWORKSPACE getWorkspaceByID(const int&);
++ PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&);
+ PHLWORKSPACE getWorkspaceByName(const std::string&);
+ PHLWORKSPACE getWorkspaceByString(const std::string&);
+ void sanityCheckWorkspaces();
+- void updateWorkspaceWindowDecos(const int&);
+- void updateWorkspaceWindowData(const int&);
+- int getWindowsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {});
+- int getGroupsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {});
++ void updateWorkspaceWindowDecos(const WORKSPACEID&);
++ void updateWorkspaceWindowData(const WORKSPACEID&);
++ int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {});
++ int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {});
+ PHLWINDOW getUrgentWindow();
+- bool hasUrgentWindowOnWorkspace(const int&);
+- PHLWINDOW getFirstWindowOnWorkspace(const int&);
+- PHLWINDOW getTopLeftWindowOnWorkspace(const int&);
+- PHLWINDOW getFullscreenWindowOnWorkspace(const int&);
++ bool hasUrgentWindowOnWorkspace(const WORKSPACEID&);
++ PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&);
++ PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&);
++ PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&);
+ bool isWindowActive(PHLWINDOW);
+ void changeWindowZOrder(PHLWINDOW, bool);
+- void cleanupFadingOut(const int& monid);
++ void cleanupFadingOut(const MONITORID& monid);
+ PHLWINDOW getWindowInDirection(PHLWINDOW, char);
+ PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {});
+ PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {});
+- int getNextAvailableNamedWorkspace();
++ WORKSPACEID getNextAvailableNamedWorkspace();
+ bool isPointOnAnyMonitor(const Vector2D&);
+ bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
+ CMonitor* getMonitorInDirection(const char&);
+ CMonitor* getMonitorInDirection(CMonitor*, const char&);
+ void updateAllWindowsAnimatedDecorationValues();
+- void updateWorkspaceWindows(const int64_t& id);
++ void updateWorkspaceWindows(const WORKSPACEID& id);
+ void updateWindowAnimatedDecorationValues(PHLWINDOW);
+- int getNextAvailableMonitorID(std::string const& name);
++ MONITORID getNextAvailableMonitorID(std::string const& name);
+ void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
+ void swapActiveWorkspaces(CMonitor*, CMonitor*);
+ CMonitor* getMonitorFromString(const std::string&);
+- bool workspaceIDOutOfBounds(const int64_t&);
++ bool workspaceIDOutOfBounds(const WORKSPACEID&);
+ void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
+ void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
+ void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state);
+@@ -162,12 +163,13 @@ class CCompositor {
+ PHLLS getLayerSurfaceFromSurface(SP);
+ void closeWindow(PHLWINDOW);
+ Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
+- void forceReportSizesToWindowsOnWorkspace(const int&);
+- PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused!
+- void renameWorkspace(const int&, const std::string& name = "");
++ void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&);
++ PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
++ bool isEmtpy = true); // will be deleted next frame if left empty and unfocused!
++ void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
+ void setActiveMonitor(CMonitor*);
+- bool isWorkspaceSpecial(const int&);
+- int getNewSpecialID();
++ bool isWorkspaceSpecial(const WORKSPACEID&);
++ WORKSPACEID getNewSpecialID();
+ void performUserChecks();
+ void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
+ PHLWINDOW getForceFocus();
+diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp
+index 2a1546c6..9bee7150 100644
+--- a/src/SharedDefs.hpp
++++ b/src/SharedDefs.hpp
+@@ -52,4 +52,8 @@ struct SHyprCtlCommand {
+ std::function fn;
+ };
+
++typedef int64_t WINDOWID;
++typedef int64_t MONITORID;
++typedef int64_t WORKSPACEID;
++
+ typedef std::function HOOK_CALLBACK_FN;
+diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp
+new file mode 100644
+index 00000000..3c830132
+--- /dev/null
++++ b/src/config/ConfigDescriptions.hpp
+@@ -0,0 +1,1344 @@
++#pragma once
++
++#include "ConfigManager.hpp"
++
++inline static const std::vector CONFIG_OPTIONS = {
++
++ /*
++ * general:
++ */
++
++ SConfigOptionDescription{
++ .value = "general:border_size",
++ .description = "size of the border around windows",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 20},
++ },
++ SConfigOptionDescription{
++ .value = "general:no_border_on_floating",
++ .description = "disable borders for floating windows",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "general:gaps_in",
++ .description = "gaps between windows\n\nsupports css style gaps (top, right, bottom, left -> 5 10 15 20)",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{"5"},
++ },
++ SConfigOptionDescription{
++ .value = "general:gaps_out",
++ .description = "gaps between windows and monitor edges\n\nsupports css style gaps (top, right, bottom, left -> 5 10 15 20)",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{"20"},
++ },
++ SConfigOptionDescription{
++ .value = "general:gaps_workspaces",
++ .description = "gaps between workspaces. Stacks with gaps_out.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 100},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.inactive_border",
++ .description = "border color for inactive windows",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0xff444444"},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.active_border",
++ .description = "border color for the active window",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0xffffffff"},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.nogroup_border",
++ .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0xffffaaff"},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.nogroup_border_active",
++ .description = "active border color for window that cannot be added to a group",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0xffff00ff"},
++ },
++ SConfigOptionDescription{
++ .value = "general:layout",
++ .description = "which layout to use. [dwindle/master]",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{"dwindle"},
++ },
++ SConfigOptionDescription{
++ .value = "general:no_focus_fallback",
++ .description = "if true, will not fall back to the next available window when moving focus in a direction where no window was found",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "general:resize_on_border",
++ .description = "enables resizing windows by clicking and dragging on borders and gaps",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "general:extend_border_grab_area",
++ .description = "extends the area around the border where you can click and drag on, only used when general:resize_on_border is on.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{15, 0, 100},
++ },
++ SConfigOptionDescription{
++ .value = "general:hover_icon_on_border",
++ .description = "show a cursor icon when hovering over borders, only used when general:resize_on_border is on.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "general:allow_tearing",
++ .description = "master switch for allowing tearing to occur. See the Tearing page.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "general:resize_corner",
++ .description = "force floating windows to use a specific corner when being resized (1-4 going clockwise from top left, 0 to disable)",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 4},
++ },
++
++ /*
++ * decoration:
++ */
++
++ SConfigOptionDescription{
++ .value = "decoration:rounding",
++ .description = "rounded corners' radius (in layout px)",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 20},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:active_opacity",
++ .description = "opacity of active windows. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{1, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:inactive_opacity",
++ .description = "opacity of inactive windows. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{1, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:fullscreen_opacity",
++ .description = "opacity of fullscreen windows. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{1, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:drop_shadow",
++ .description = "enable drop shadows on windows",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:shadow_range",
++ .description = "Shadow range (size) in layout px",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{4, 0, 100},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:shadow_render_power",
++ .description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{3, 1, 4},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:shadow_ignore_window",
++ .description = "if true, the shadow will not be rendered behind the window itself, only around it.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:col.shadow",
++ .description = "shadow's color. Alpha dictates shadow's opacity.",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0xee1a1a1a},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:col.shadow_inactive",
++ .description = "inactive shadow color. (if not set, will fall back to col.shadow)",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "decoration:shadow_offset",
++ .description = "shadow's rendering offset.",
++ .type = CONFIG_OPTION_VECTOR,
++ .data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:shadow_scale",
++ .description = "shadow's scale. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{1, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:dim_inactive",
++ .description = "enables dimming of inactive windows",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:dim_strength",
++ .description = "how much inactive windows should be dimmed [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.5, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:dim_special",
++ .description = "how much to dim the rest of the screen by when a special workspace is open. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:dim_around",
++ .description = "how much the dimaround window rule should dim by. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.4, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "decoration:screen_shader",
++ .description = "screen_shader a path to a custom shader to be applied at the end of rendering. See examples/screenShader.frag for an example.",
++ .type = CONFIG_OPTION_STRING_LONG,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++
++ /*
++ * blur:
++ */
++
++ SConfigOptionDescription{
++ .value = "blur:enabled",
++ .description = "enable kawase window background blur",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "blur:size",
++ .description = "blur size (distance)",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{8, 0, 100},
++ },
++ SConfigOptionDescription{
++ .value = "blur:passes",
++ .description = "the amount of passes to perform",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 10},
++ },
++ SConfigOptionDescription{
++ .value = "blur:ignore_opacity",
++ .description = "make the blur layer ignore the opacity of the window",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "blur:new_optimizations",
++ .description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "blur:xray",
++ .description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating "
++ "blur significantly.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "blur:noise",
++ .description = "how much noise to apply. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.0117, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "blur:contrast",
++ .description = "contrast modulation for blur. [0.0 - 2.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.8916, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "blur:brightness",
++ .description = "brightness modulation for blur. [0.0 - 2.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.8172, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "blur:vibrancy",
++ .description = "Increase saturation of blurred colors. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.1696, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "blur:vibrancy_darkness",
++ .description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "blur:special",
++ .description = "whether to blur behind the special workspace (note: expensive)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "blur:popups",
++ .description = "whether to blur popups (e.g. right-click menus)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "blur:popups_ignorealpha",
++ .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
++ },
++
++ /*
++ * animations:
++ */
++
++ SConfigOptionDescription{
++ .value = "animations:enabled",
++ .description = "enable animations",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "animations:first_launch_animation",
++ .description = "enable first launch animation",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++
++ /*
++ * input:
++ */
++
++ SConfigOptionDescription{
++ .value = "input:kb_model",
++ .description = "Appropriate XKB keymap parameter. See the note below.",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY},
++ },
++ SConfigOptionDescription{
++ .value = "input:kb_layout",
++ .description = "Appropriate XKB keymap parameter",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{"us"},
++ },
++ SConfigOptionDescription{
++ .value = "input:kb_variant",
++ .description = "Appropriate XKB keymap parameter",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""},
++ },
++ SConfigOptionDescription{
++ .value = "input:kb_options",
++ .description = "Appropriate XKB keymap parameter",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""},
++ },
++ SConfigOptionDescription{
++ .value = "input:kb_rules",
++ .description = "Appropriate XKB keymap parameter",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""},
++ },
++ SConfigOptionDescription{
++ .value = "input:kb_file",
++ .description = "Appropriate XKB keymap parameter",
++ .type = CONFIG_OPTION_STRING_LONG,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "input:numlock_by_default",
++ .description = "Engage numlock by default.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:resolve_binds_by_sym",
++ .description = "Determines how keybinds act when multiple layouts are used. If false, keybinds will always act as if the first specified layout is active. If true, "
++ "keybinds specified by symbols are activated when you type the respective symbol with the current layout.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:repeat_rate",
++ .description = "The repeat rate for held-down keys, in repeats per second.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{25, 0, 200},
++ },
++ SConfigOptionDescription{
++ .value = "input:repeat_delay",
++ .description = "Delay before a held-down key is repeated, in milliseconds.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{600, 0, 2000},
++ },
++ SConfigOptionDescription{
++ .value = "input:sensitivity",
++ .description = "Sets the mouse input sensitivity. Value is clamped to the range -1.0 to 1.0.",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0, -1, 1},
++ },
++ SConfigOptionDescription{
++ .value = "input:accel_profile",
++ .description = "Sets the cursor acceleration profile. Can be one of adaptive, flat. Can also be custom, see below. Leave empty to use libinput's default mode for your "
++ "input device. [adaptive/flat/custom]",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "input:force_no_accel",
++ .description = "Force no cursor acceleration. This bypasses most of your pointer settings to get as raw of a signal as possible. Enabling this is not recommended due to "
++ "potential cursor desynchronization.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:left_handed",
++ .description = "Switches RMB and LMB",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:scroll_points",
++ .description = "Sets the scroll acceleration profile, when accel_profile is set to custom. Has to be in the form . Leave empty to have a flat scroll curve.",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "input:scroll_method",
++ .description = "Sets the scroll method. Can be one of 2fg (2 fingers), edge, on_button_down, no_scroll. [2fg/edge/on_button_down/no_scroll]",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "input:scroll_button",
++ .description = "Sets the scroll button. Has to be an int, cannot be a string. Check wev if you have any doubts regarding the ID. 0 means default.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 300},
++ },
++ SConfigOptionDescription{
++ .value = "input:scroll_button_lock",
++ .description = "If the scroll button lock is enabled, the button does not need to be held down. Pressing and releasing the button toggles the button lock, which logically "
++ "holds the button down or releases it. While the button is logically held down, motion events are converted to scroll events.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:scroll_factor",
++ .description = "Multiplier added to scroll movement for external mice. Note that there is a separate setting for touchpad scroll_factor.",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{1, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "input:natural_scroll",
++ .description = "Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:follow_mouse",
++ .description = "Specify if and how cursor movement should affect window focus. See the note below. [0/1/2/3]",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 3},
++ },
++ SConfigOptionDescription{
++ .value = "input:mouse_refocus",
++ .description = "if disabled, mouse focus won't switch to the hovered window unless the mouse crosses a window boundary when follow_mouse=1.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "input:float_switch_override_focus",
++ .description = "If enabled (1 or 2), focus will change to the window under the cursor when changing from tiled-to-floating and vice versa. If 2, focus will also follow "
++ "mouse on float-to-float switches.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "input:special_fallthrough",
++ .description = "if enabled, having only floating windows in the special workspace will not block focusing windows in the regular workspace.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:off_window_axis_events",
++ .description = "Handles axis events around (gaps/border for tiled, dragarea/border for floated) a focused window. 0 ignores axis events 1 sends out-of-bound coordinates 2 "
++ "fakes pointer coordinates to the closest point inside the window 3 warps the cursor to the closest point inside the window",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 3},
++ },
++ SConfigOptionDescription{
++ .value = "input:emulate_discrete_scroll",
++ .description = "Emulates discrete scrolling from high resolution scrolling events. 0 disables it, 1 enables handling of non-standard events only, and 2 force enables all "
++ "scroll wheel events to be handled",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 2},
++ },
++
++ /*
++ * input:touchpad:
++ */
++
++ SConfigOptionDescription{
++ .value = "input:touchpad:disable_while_typing",
++ .description = "Disable the touchpad while typing.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:natural_scroll",
++ .description = "Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:scroll_factor",
++ .description = "Multiplier applied to the amount of scroll movement.",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{1, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:middle_button_emulation",
++ .description =
++ "Sending LMB and RMB simultaneously will be interpreted as a middle click. This disables any touchpad area that would normally send a middle click based on location.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:tap_button_map",
++ .description = "Sets the tap button mapping for touchpad button emulation. Can be one of lrm (default) or lmr (Left, Middle, Right Buttons). [lrm/lmr]",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:clickfinger_behavior",
++ .description =
++ "Button presses with 1, 2, or 3 fingers will be mapped to LMB, RMB, and MMB respectively. This disables interpretation of clicks based on location on the touchpad.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:tap-to-click",
++ .description = "Tapping on the touchpad with 1, 2, or 3 fingers will send LMB, RMB, and MMB respectively.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:drag_lock",
++ .description = "When enabled, lifting the finger off for a short time while dragging will not drop the dragged item.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:touchpad:tap-and-drag",
++ .description = "Sets the tap and drag mode for the touchpad",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++
++ /*
++ * input:touchdevice:
++ */
++
++ SConfigOptionDescription{
++ .value = "input:touchdevice:transform",
++ .description = "Transform the input from touchdevices. The possible transformations are the same as those of the monitors",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 6}, // ##TODO RANGE?
++ },
++ SConfigOptionDescription{
++ .value = "input:touchdevice:output",
++ .description = "The monitor to bind touch devices. The default is auto-detection. To stop auto-detection, use an empty string or the [[Empty]] value.",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "input:touchdevice:enabled",
++ .description = "Whether input is enabled for touch devices.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++
++ /*
++ * input:tablet:
++ */
++
++ SConfigOptionDescription{
++ .value = "input:tablet:transform",
++ .description = "transform the input from tablets. The possible transformations are the same as those of the monitors",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 6}, // ##TODO RANGE?
++ },
++ SConfigOptionDescription{
++ .value = "input:tablet:output",
++ .description = "the monitor to bind tablets. Empty means unbound..",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "input:tablet:region_position",
++ .description = "position of the mapped region in monitor layout.",
++ .type = CONFIG_OPTION_VECTOR,
++ .data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}},
++ },
++ SConfigOptionDescription{
++ .value = "input:tablet:region_size",
++ .description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.",
++ .type = CONFIG_OPTION_VECTOR,
++ .data = SConfigOptionDescription::SVectorData{{}, {-100, -100}, {4000, 4000}},
++ },
++ SConfigOptionDescription{
++ .value = "input:tablet:relative_input",
++ .description = "whether the input should be relative",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:tablet:left_handed",
++ .description = "if enabled, the tablet will be rotated 180 degrees",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "input:tablet:active_area_size",
++ .description = "size of tablet's active area in mm",
++ .type = CONFIG_OPTION_VECTOR,
++ .data = SConfigOptionDescription::SVectorData{{}, {}, {500, 500}},
++ },
++ SConfigOptionDescription{
++ .value = "input:tablet:active_area_position",
++ .description = "position of the active area in mm",
++ .type = CONFIG_OPTION_VECTOR,
++ .data = SConfigOptionDescription::SVectorData{{}, {}, {500, 500}},
++ },
++
++ /* ##TODO
++ *
++ * PER DEVICE SETTINGS?
++ *
++ * */
++
++ /*
++ * gestures:
++ */
++
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe",
++ .description = "enable workspace swipe gesture on touchpad",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_fingers",
++ .description = "how many fingers for the touchpad gesture",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{3, 0, 5}, //##TODO RANGE?
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_min_fingers",
++ .description = "if enabled, workspace_swipe_fingers is considered the minimum number of fingers to swipe",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_distance",
++ .description = "in px, the distance of the touchpad gesture",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{300, 0, 2000}, //##TODO RANGE?
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_touch",
++ .description = "enable workspace swiping from the edge of a touchscreen",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_invert",
++ .description = "invert the direction (touchpad only)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_touch_invert",
++ .description = "invert the direction (touchscreen only)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_min_speed_to_force",
++ .description = "minimum speed in px per timepoint to force the change ignoring cancel_ratio. Setting to 0 will disable this mechanic.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{30, 0, 200}, //##TODO RANGE?
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_cancel_ratio",
++ .description = "how much the swipe has to proceed in order to commence it. (0.7 -> if > 0.7 * distance, switch, if less, revert) [0.0 - 1.0]",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{0.5, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_create_new",
++ .description = "whether a swipe right on the last workspace should create a new one.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_direction_lock",
++ .description = "if enabled, switching direction will be locked when you swipe past the direction_lock_threshold (touchpad only).",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_direction_lock_threshold",
++ .description = "in px, the distance to swipe before direction lock activates (touchpad only).",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{10, 0, 200}, //##TODO RANGE?
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_forever",
++ .description = "if enabled, swiping will not clamp at the neighboring workspaces but continue to the further ones.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "gestures:workspace_swipe_use_r",
++ .description = "if enabled, swiping will use the r prefix instead of the m prefix for finding workspaces.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++
++ /*
++ * group:
++ */
++
++ SConfigOptionDescription{
++ .value = "group:insert_after_current",
++ .description = "whether new windows in a group spawn after current or at group tail",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "group:focus_removed_window",
++ .description = "whether Hyprland should focus on the window that has just been moved out of the group",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.border_active",
++ .description = "border color for inactive windows",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0x66ffff00"},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.border_inactive",
++ .description = "border color for the active window",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0x66777700"},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.border_locked_active",
++ .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0x66ff5500"},
++ },
++ SConfigOptionDescription{
++ .value = "general:col.border_locked_inactive",
++ .description = "active border color for window that cannot be added to a group",
++ .type = CONFIG_OPTION_GRADIENT,
++ .data = SConfigOptionDescription::SGradientData{"0x66775500"},
++ },
++
++ /*
++ * group:groupbar:
++ */
++
++ SConfigOptionDescription{
++ .value = "group:groupbar:enabled",
++ .description = "enables groupbars",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:font_family",
++ .description = "font used to display groupbar titles, use misc:font_family if not specified",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:font_size",
++ .description = "font size of groupbar title",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{8, 2, 64},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:gradients",
++ .description = "enables gradients",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:height",
++ .description = "height of the groupbar",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{14, 1, 64},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:stacked",
++ .description = "render the groupbar as a vertical stack",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:priority",
++ .description = "sets the decoration priority for groupbars",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{3, 0, 6}, //##TODO RANGE?
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:render_titles",
++ .description = "whether to render titles in the group bar decoration",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:scrolling",
++ .description = "whether scrolling in the groupbar changes group active window",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:text_color",
++ .description = "controls the group bar text color",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0xffffffff},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:col.active",
++ .description = "active group border color",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0x66ffff00},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:col.inactive",
++ .description = "inactive (out of focus) group border color",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0x66777700},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:col.locked_active",
++ .description = "active locked group border color",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0x66ff5500},
++ },
++ SConfigOptionDescription{
++ .value = "group:groupbar:col.locked_inactive",
++ .description = "controls the group bar text color",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0x66775500},
++ },
++
++ /*
++ * misc:
++ */
++
++ SConfigOptionDescription{
++ .value = "misc:disable_hyprland_logo",
++ .description = "disables the random Hyprland logo / anime girl background. :(",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:disable_splash_rendering",
++ .description = "disables the Hyprland splash rendering. (requires a monitor reload to take effect)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:col.splash",
++ .description = "Changes the color of the splash text (requires a monitor reload to take effect).",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0xffffffff},
++ },
++ SConfigOptionDescription{
++ .value = "misc:font_family",
++ .description = "Set the global default font to render the text including debug fps/notification, config error messages and etc., selected from system fonts.",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{"Sans"},
++ },
++ SConfigOptionDescription{
++ .value = "misc:splash_font_family",
++ .description = "Changes the font used to render the splash text, selected from system fonts (requires a monitor reload to take effect).",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "misc:force_default_wallpaper",
++ .description = "Enforce any of the 3 default wallpapers. Setting this to 0 or 1 disables the anime background. -1 means “random”. [-1/0/1/2]",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{-1, -1, 2},
++ },
++ SConfigOptionDescription{
++ .value = "misc:vfr",
++ .description = "controls the VFR status of Hyprland. Heavily recommended to leave enabled to conserve resources.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "misc:vrr",
++ .description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "misc:mouse_move_enables_dpms",
++ .description = "If DPMS is set to off, wake up the monitors if the mouse move",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:key_press_enables_dpms",
++ .description = "If DPMS is set to off, wake up the monitors if a key is pressed.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:always_follow_on_dnd",
++ .description = "Will make mouse focus follow the mouse when drag and dropping. Recommended to leave it enabled, especially for people using focus follows mouse at 0.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "misc:layers_hog_keyboard_focus",
++ .description = "If true, will make keyboard-interactive layers keep their focus on mouse move (e.g. wofi, bemenu)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "misc:animate_manual_resizes",
++ .description = "If true, will animate manual window resizes/moves",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:animate_mouse_windowdragging",
++ .description = "If true, will animate windows being dragged by mouse, note that this can cause weird behavior on some curves",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:disable_autoreload",
++ .description = "If true, the config will not reload automatically on save, and instead needs to be reloaded with hyprctl reload. Might save on battery.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:enable_swallow",
++ .description = "Enable window swallowing",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:swallow_regex",
++ .description =
++ "The class regex to be used for windows that should be swallowed (usually, a terminal). To know more about the list of regex which can be used use this cheatsheet.",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "misc:swallow_exception_regex",
++ .description = "The title regex to be used for windows that should not be swallowed by the windows specified in swallow_regex (e.g. wev). The regex is matched against the "
++ "parent (e.g. Kitty) window’s title on the assumption that it changes to whatever process it’s running.",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "misc:focus_on_activate",
++ .description = "Whether Hyprland should focus an app that requests to be focused (an activate request)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:mouse_move_focuses_monitor",
++ .description = "Whether mouse moving into a different monitor should focus it",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "misc:render_ahead_of_time",
++ .description = "[Warning: buggy] starts rendering before your monitor displays a frame in order to lower latency",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:render_ahead_safezone",
++ .description = "how many ms of safezone to add to rendering ahead of time. Recommended 1-2.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 1, 10},
++ },
++ SConfigOptionDescription{
++ .value = "misc:allow_session_lock_restore",
++ .description = "if true, will allow you to restart a lockscreen app in case it crashes (red screen of death)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:background_color",
++ .description = "change the background color. (requires enabled disable_hyprland_logo)",
++ .type = CONFIG_OPTION_COLOR,
++ .data = SConfigOptionDescription::SColorData{0x111111},
++ },
++ SConfigOptionDescription{
++ .value = "misc:close_special_on_empty",
++ .description = "close the special workspace if the last window is removed",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "misc:new_window_takes_over_fullscreen",
++ .description = "if there is a fullscreen or maximized window, decide whether a new tiled window opened should replace it, stay behind or disable the fullscreen/maximized "
++ "state. 0 - behind, 1 - takes over, 2 - unfullscreen/unmaxize [0/1/2]",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "misc:exit_window_retains_fullscreen",
++ .description = "if true, closing a fullscreen window makes the next focused window fullscreen",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "misc:initial_workspace_tracking",
++ .description = "if enabled, windows will open on the workspace they were invoked on. 0 - disabled, 1 - single-shot, 2 - persistent (all children too)",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "misc:middle_click_paste",
++ .description = "whether to enable middle-click-paste (aka primary selection)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++
++ /*
++ * binds:
++ */
++
++ SConfigOptionDescription{
++ .value = "binds:pass_mouse_when_bound",
++ .description = "if disabled, will not pass the mouse events to apps / dragging windows around if a keybind has been triggered.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "binds:scroll_event_delay",
++ .description = "in ms, how many ms to wait after a scroll event to allow passing another one for the binds.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{300, 0, 2000},
++ },
++ SConfigOptionDescription{
++ .value = "binds:workspace_back_and_forth",
++ .description = "If enabled, an attempt to switch to the currently focused workspace will instead switch to the previous workspace. Akin to i3’s auto_back_and_forth.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "binds:allow_workspace_cycles",
++ .description = "If enabled, workspaces don’t forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly "
++ "going to the previous workspace.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "binds:workspace_center_on",
++ .description = "Whether switching workspaces should center the cursor on the workspace (0) or on the last active window for that workspace (1)",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "binds:focus_preferred_method",
++ .description = "sets the preferred focus finding method when using focuswindow/movewindow/etc with a direction. 0 - history (recent have priority), 1 - length (longer "
++ "shared edges have priority)",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "binds:ignore_group_lock",
++ .description = "If enabled, dispatchers like moveintogroup, moveoutofgroup and movewindoworgroup will ignore lock per group.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "binds:movefocus_cycles_fullscreen",
++ .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "binds:disable_keybind_grabbing",
++ .description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "binds:window_direction_monitor_fallback",
++ .description = "If enabled, moving a window or focus over the edge of a monitor with a direction will move it to the next monitor in that direction.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++
++ /*
++ * xwayland:
++ */
++
++ SConfigOptionDescription{
++ .value = "xwayland:use_nearest_neighbor",
++ .description = "uses the nearest neighbor filtering for xwayland apps, making them pixelated rather than blurry",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "xwayland:force_zero_scaling",
++ .description = "forces a scale of 1 on xwayland windows on scaled displays.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++
++ /*
++ * opengl:
++ */
++
++ SConfigOptionDescription{
++ .value = "opengl:nvidia_anti_flicker",
++ .description = "reduces flickering on nvidia at the cost of possible frame drops on lower-end GPUs. On non-nvidia, this is ignored.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "opengl:force_introspection",
++ .description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - "
++ "nothing, 1 - force always on, 2 - force always on if nvidia",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{2, 0, 2},
++ },
++
++ /*
++ * render:
++ */
++
++ SConfigOptionDescription{
++ .value = "render:explicit_sync",
++ .description = "Whether to enable explicit sync support. Requires a hyprland restart. 0 - no, 1 - yes, 2 - auto based on the gpu driver",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{2, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "render:explicit_sync_kms",
++ .description = "Whether to enable explicit sync support for the KMS layer. Requires explicit_sync to be enabled. 0 - no, 1 - yes, 2 - auto based on the gpu driver",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{2, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "render:direct_scanout",
++ .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also "
++ "recommended to set this to false if the fullscreen application shows graphical glitches.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++
++ /*
++ * cursor:
++ */
++
++ SConfigOptionDescription{
++ .value = "cursor:use_nearest_neighbor",
++ .description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor "
++ "theme and size.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:no_hardware_cursors",
++ .description = "disables hardware cursors",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:no_break_fs_vrr",
++ .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:min_refresh_rate",
++ .description = "minimum refresh rate for cursor movement when no_break_fs_vrr is active. Set to minimum supported refresh rate or higher",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{24, 10, 500},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:hotspot_padding",
++ .description = "the padding, in logical px, between screen edges and the cursor",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{1, 0, 20},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:inactive_timeout",
++ .description = "in seconds, after how many seconds of cursor’s inactivity to hide it. Set to 0 for never.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 20},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:no_warps",
++ .description = "if true, will not warp the cursor in many cases (focusing, keybinds, etc)",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:persistent_warps",
++ .description = "When a window is refocused, the cursor returns to its last position relative to that window, rather than to the centre.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:warp_on_change_workspace",
++ .description = "If true, move the cursor to the last focused window after changing the workspace.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:default_monitor",
++ .description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)",
++ .type = CONFIG_OPTION_STRING_SHORT,
++ .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
++ },
++ SConfigOptionDescription{
++ .value = "cursor:zoom_factor",
++ .description = "the factor to zoom by around the cursor. Like a magnifying glass. Minimum 1.0 (meaning no zoom)",
++ .type = CONFIG_OPTION_FLOAT,
++ .data = SConfigOptionDescription::SFloatData{1, 1, 10},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:zoom_rigid",
++ .description = "whether the zoom should follow the cursor rigidly (cursor is always centered if it can be) or loosely",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:enable_hyprcursor",
++ .description = "whether to enable hyprcursor support",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:hide_on_key_press",
++ .description = "Hides the cursor when you press any key until the mouse is moved.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:hide_on_touch",
++ .description = "Hides the cursor when the last input was a touch input until a mouse input is done.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "cursor:allow_dumb_copy",
++ .description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++
++ /*
++ * debug:
++ */
++
++ SConfigOptionDescription{
++ .value = "debug:overlay",
++ .description = "print the debug performance overlay. Disable VFR for accurate results.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "debug:damage_blink",
++ .description = "disable logging to a file",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "debug:disable_logs",
++ .description = "disable logging to a file",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "debug:disable_time",
++ .description = "disables time logging",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++ SConfigOptionDescription{
++ .value = "debug:damage_tracking",
++ .description = "redraw only the needed bits of the display. Do not change. (default: full - 2) monitor - 1, none - 0",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{2, 0, 2},
++ },
++ SConfigOptionDescription{
++ .value = "debug:enable_stdout_logs",
++ .description = "enables logging to stdout",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "debug:manual_crash",
++ .description = "set to 1 and then back to 0 to crash Hyprland.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "debug:suppress_errors",
++ .description = "if true, do not display config file parsing errors.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "debug:watchdog_timeout",
++ .description = "sets the timeout in seconds for watchdog to abort processing of a signal of the main thread. Set to 0 to disable.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{5, 0, 20},
++ },
++ SConfigOptionDescription{
++ .value = "debug:disable_scale_checks",
++ .description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{false},
++ },
++ SConfigOptionDescription{
++ .value = "debug:error_limit",
++ .description = "limits the number of displayed config file parsing errors.",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{5, 0, 20},
++ },
++ SConfigOptionDescription{
++ .value = "debug:error_position",
++ .description = "sets the position of the error bar. top - 0, bottom - 1",
++ .type = CONFIG_OPTION_INT,
++ .data = SConfigOptionDescription::SRangeData{0, 0, 1},
++ },
++ SConfigOptionDescription{
++ .value = "debug:colored_stdout_logs",
++ .description = "enables colors in the stdout logs.",
++ .type = CONFIG_OPTION_BOOL,
++ .data = SConfigOptionDescription::SBoolData{true},
++ },
++};
+\ No newline at end of file
+diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
+index be6433fa..1856bd49 100644
+--- a/src/config/ConfigManager.cpp
++++ b/src/config/ConfigManager.cpp
+@@ -28,7 +28,9 @@
+ #include
+ using namespace Hyprutils::String;
+
+-extern "C" char** environ;
++extern "C" char** environ;
++
++#include "ConfigDescriptions.hpp"
+
+ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** data) {
+ std::string V = VALUE;
+@@ -312,8 +314,6 @@ CConfigManager::CConfigManager() {
+ configPaths.emplace_back(getMainConfigPath());
+ m_pConfig = std::make_unique(configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true});
+
+- m_pConfig->addConfigValue("general:sensitivity", {1.0f});
+- m_pConfig->addConfigValue("general:apply_sens_to_raw", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("general:border_size", Hyprlang::INT{1});
+ m_pConfig->addConfigValue("general:no_border_on_floating", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("general:border_part_of_window", Hyprlang::INT{1});
+@@ -531,7 +531,7 @@ CConfigManager::CConfigManager() {
+ m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24});
+ m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0});
+- m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0});
++ m_pConfig->addConfigValue("cursor:inactive_timeout", {0.f});
+ m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0});
+@@ -539,6 +539,7 @@ CConfigManager::CConfigManager() {
+ m_pConfig->addConfigValue("cursor:zoom_factor", {1.f});
+ m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1});
++ m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1});
+ m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1});
+ m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0});
+@@ -821,9 +822,6 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
+ if (!isFirstLaunch)
+ g_pHyprOpenGL->m_bReloadScreenShader = true;
+
+- if (!isFirstLaunch && *PENABLEEXPLICIT != prevEnabledExplicit)
+- g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
+-
+ // parseError will be displayed next frame
+
+ if (result.error)
+@@ -836,6 +834,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
+ else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1)
+ g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland",
+ CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
++ else if (*PENABLEEXPLICIT != prevEnabledExplicit)
++ g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
+ else
+ g_pHyprError->destroy();
+
+@@ -924,7 +924,10 @@ void CConfigManager::init() {
+ }
+
+ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE) {
+- const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str());
++ static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync");
++ static int prevEnabledExplicit = *PENABLEEXPLICIT;
++
++ const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str());
+
+ // invalidate layouts if they changed
+ if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) {
+@@ -932,6 +935,13 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
+ g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
+ }
+
++ if (COMMAND.contains("explicit")) {
++ if (*PENABLEEXPLICIT != prevEnabledExplicit)
++ g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
++ else
++ g_pHyprError->destroy();
++ }
++
+ // Update window border colors
+ g_pCompositor->updateAllWindowsAnimatedDecorationValues();
+
+@@ -2425,7 +2435,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin
+ // }
+
+ const static std::string ruleOnCreatedEmpty = "on-created-empty:";
+- const static int ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length();
++ const static auto ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length();
+
+ auto assignRule = [&](std::string rule) -> std::optional {
+ size_t delim = std::string::npos;
+@@ -2597,3 +2607,60 @@ std::optional CConfigManager::handlePlugin(const std::string& comma
+
+ return {};
+ }
++
++const std::vector& CConfigManager::getAllDescriptions() {
++ return CONFIG_OPTIONS;
++}
++
++std::string SConfigOptionDescription::jsonify() const {
++ auto parseData = [this]() -> std::string {
++ return std::visit(
++ [](auto&& val) {
++ using T = std::decay_t;
++ if constexpr (std::is_same_v) {
++ return std::format(R"#( "value": "{}")#", val.value);
++ } else if constexpr (std::is_same_v) {
++ return std::format(R"#( "value": {},
++ "min": {},
++ "max": {})#",
++ val.value, val.min, val.max);
++ } else if constexpr (std::is_same_v) {
++ return std::format(R"#( "value": {},
++ "min": {},
++ "max": {})#",
++ val.value, val.min, val.max);
++ } else if constexpr (std::is_same_v) {
++ return std::format(R"#( "value": {})#", val.color.getAsHex());
++ } else if constexpr (std::is_same_v) {
++ return std::format(R"#( "value": {})#", val.value);
++ } else if constexpr (std::is_same_v) {
++ return std::format(R"#( "value": {})#", val.choices);
++ } else if constexpr (std::is_same_v) {
++ return std::format(R"#( "x": {},
++ "y": {},
++ "min_x": {},
++ "min_y": {},
++ "max_x": {},
++ "max_y": {})#",
++ val.vec.x, val.vec.y, val.min.x, val.min.y, val.max.x, val.max.y);
++ } else if constexpr (std::is_same_v) {
++ return std::format(R"#( "value": "{}")#", val.gradient);
++ }
++ return std::string{""};
++ },
++ data);
++ };
++
++ std::string json = std::format(R"#({{
++ "value": "{}",
++ "description": "{}",
++ "type": {},
++ "flags": {},
++ "data": {{
++ {}
++ }}
++}})#",
++ value, description, (uint16_t)type, (uint32_t)flags, parseData());
++
++ return json;
++}
+diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
+index 75dea9ef..4241031b 100644
+--- a/src/config/ConfigManager.hpp
++++ b/src/config/ConfigManager.hpp
+@@ -33,7 +33,7 @@ struct SWorkspaceRule {
+ std::string monitor = "";
+ std::string workspaceString = "";
+ std::string workspaceName = "";
+- int workspaceId = -1;
++ WORKSPACEID workspaceId = -1;
+ bool isDefault = false;
+ bool isPersistent = false;
+ std::optional gapsIn;
+@@ -83,6 +83,70 @@ struct SExecRequestedRule {
+ uint64_t iPid = 0;
+ };
+
++enum eConfigOptionType : uint16_t {
++ CONFIG_OPTION_BOOL = 0,
++ CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/
++ CONFIG_OPTION_FLOAT = 2,
++ CONFIG_OPTION_STRING_SHORT = 3, /* e.g. "auto" */
++ CONFIG_OPTION_STRING_LONG = 4, /* e.g. a command */
++ CONFIG_OPTION_COLOR = 5,
++ CONFIG_OPTION_CHOICE = 6, /* e.g. "one", "two", "three" */
++ CONFIG_OPTION_GRADIENT = 7,
++ CONFIG_OPTION_VECTOR = 8,
++};
++
++enum eConfigOptionFlags : uint32_t {
++ CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0),
++};
++
++struct SConfigOptionDescription {
++
++ struct SBoolData {
++ bool value = false;
++ };
++
++ struct SRangeData {
++ int value = 0, min = 0, max = 2;
++ };
++
++ struct SFloatData {
++ float value = 0, min = 0, max = 100;
++ };
++
++ struct SStringData {
++ std::string value;
++ };
++
++ struct SColorData {
++ CColor color;
++ };
++
++ struct SChoiceData {
++ int firstIndex = 0;
++ std::string choices; // comma-separated
++ };
++
++ struct SGradientData {
++ std::string gradient;
++ };
++
++ struct SVectorData {
++ Vector2D vec, min, max;
++ };
++
++ std::string value; // e.g. general:gaps_in
++ std::string description;
++ std::string specialCategory; // if value is special (e.g. device:abc) value will be abc and special device
++ bool specialKey = false;
++ eConfigOptionType type = CONFIG_OPTION_BOOL;
++ uint32_t flags = 0; // eConfigOptionFlags
++
++ std::string jsonify() const;
++
++ //
++ std::variant data;
++};
++
+ class CConfigManager {
+ public:
+ CConfigManager();
+@@ -115,6 +179,8 @@ class CConfigManager {
+ std::vector getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
+ std::vector getMatchingRules(PHLLS);
+
++ const std::vector& getAllDescriptions();
++
+ std::unordered_map m_mAdditionalReservedAreas;
+
+ std::unordered_map getAnimationConfig();
+diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
+index d91a1cec..78c8504a 100644
+--- a/src/debug/HyprCtl.cpp
++++ b/src/debug/HyprCtl.cpp
+@@ -71,7 +71,7 @@ static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFor
+
+ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer m, eHyprCtlOutputFormat format) {
+ std::string result;
+- if (!m->output || m->ID == -1ull)
++ if (!m->output || m->ID == -1)
+ return "";
+
+ if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
+@@ -155,19 +155,19 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
+ result += "]";
+ } else {
+ for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
+- if (!m->output || m->ID == -1ull)
++ if (!m->output || m->ID == -1)
+ continue;
+
+- result +=
+- std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
+- "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
+- "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
+- m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
+- m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
+- m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
+- (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
+- (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false),
+- m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
++ result += std::format(
++ "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
++ "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
++ "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n",
++ m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
++ m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
++ m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
++ (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"),
++ (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled,
++ formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
+ }
+ }
+
+@@ -1561,6 +1561,21 @@ std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) {
+ return lockedStr;
+ }
+
++std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
++ std::string json = "{";
++ const auto& DESCS = g_pConfigManager->getAllDescriptions();
++
++ for (const auto& d : DESCS) {
++ json += d.jsonify() + ",\n";
++ }
++
++ json.pop_back();
++ json.pop_back();
++
++ json += "}\n";
++ return json;
++}
++
+ CHyprCtl::CHyprCtl() {
+ registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
+ registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
+@@ -1581,6 +1596,7 @@ CHyprCtl::CHyprCtl() {
+ registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest});
+ registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest});
+ registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
++ registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
+
+ registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
+ registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
+diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp
+index 889be8ea..fbd8cd71 100644
+--- a/src/debug/HyprDebugOverlay.cpp
++++ b/src/debug/HyprDebugOverlay.cpp
+@@ -7,8 +7,8 @@ CHyprDebugOverlay::CHyprDebugOverlay() {
+ m_pTexture = makeShared();
+ }
+
+-void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
+- m_dLastRenderTimes.push_back(µs / 1000.f);
++void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
++ m_dLastRenderTimes.push_back(durationUs / 1000.f);
+
+ if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
+ m_dLastRenderTimes.pop_front();
+@@ -17,8 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
+ m_pMonitor = pMonitor;
+ }
+
+-void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) {
+- m_dLastRenderTimesNoOverlay.push_back(µs / 1000.f);
++void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
++ m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
+
+ if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
+ m_dLastRenderTimesNoOverlay.pop_front();
+@@ -188,12 +188,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
+ return posY - offset;
+ }
+
+-void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
+- m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs);
++void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
++ m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
+ }
+
+-void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) {
+- m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, µs);
++void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
++ m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
+ }
+
+ void CHyprDebugOverlay::frameData(CMonitor* pMonitor) {
+diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp
+index a6063ee9..e7742b35 100644
+--- a/src/debug/HyprDebugOverlay.hpp
++++ b/src/debug/HyprDebugOverlay.hpp
+@@ -13,8 +13,8 @@ class CHyprMonitorDebugOverlay {
+ public:
+ int draw(int offset);
+
+- void renderData(CMonitor* pMonitor, float µs);
+- void renderDataNoOverlay(CMonitor* pMonitor, float µs);
++ void renderData(CMonitor* pMonitor, float durationUs);
++ void renderDataNoOverlay(CMonitor* pMonitor, float durationUs);
+ void frameData(CMonitor* pMonitor);
+
+ private:
+@@ -33,8 +33,8 @@ class CHyprDebugOverlay {
+ public:
+ CHyprDebugOverlay();
+ void draw();
+- void renderData(CMonitor*, float µs);
+- void renderDataNoOverlay(CMonitor*, float µs);
++ void renderData(CMonitor*, float durationUs);
++ void renderDataNoOverlay(CMonitor*, float durationUs);
+ void frameData(CMonitor*);
+
+ private:
+diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp
+index 8fd448ef..c352fa74 100644
+--- a/src/desktop/LayerSurface.cpp
++++ b/src/desktop/LayerSurface.cpp
+@@ -432,8 +432,8 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
+ PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
+ };
+
+- float closest = std::numeric_limits::max();
+- int leader = force;
++ float closest = std::numeric_limits::max();
++ size_t leader = force;
+ if (leader == -1) {
+ for (size_t i = 0; i < 4; ++i) {
+ float dist = MIDDLE.distance(edgePoints[i]);
+diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp
+index 056f66a8..84935b34 100644
+--- a/src/desktop/LayerSurface.hpp
++++ b/src/desktop/LayerSurface.hpp
+@@ -42,7 +42,7 @@ class CLayerSurface {
+ bool mapped = false;
+ uint32_t layer = 0;
+
+- int monitorID = -1;
++ MONITORID monitorID = -1;
+
+ bool fadingOut = false;
+ bool readyToDelete = false;
+@@ -51,7 +51,7 @@ class CLayerSurface {
+
+ bool forceBlur = false;
+ bool forceBlurPopups = false;
+- int xray = -1;
++ int64_t xray = -1;
+ bool ignoreAlpha = false;
+ float ignoreAlphaValue = 0.f;
+ bool dimAround = false;
+diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp
+index 93c208cf..dcdcb573 100644
+--- a/src/desktop/Window.cpp
++++ b/src/desktop/Window.cpp
+@@ -1243,7 +1243,7 @@ bool CWindow::isEffectiveInternalFSMode(const eFullscreenMode MODE) {
+ return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE;
+ }
+
+-int CWindow::workspaceID() {
++WORKSPACEID CWindow::workspaceID() {
+ return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
+ }
+
+diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp
+index 11bf662a..2e5b54b1 100644
+--- a/src/desktop/Window.hpp
++++ b/src/desktop/Window.hpp
+@@ -270,7 +270,7 @@ class CWindow {
+ bool m_bDraggingTiled = false; // for dragging around tiled windows
+ bool m_bWasMaximized = false;
+ sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
+- uint64_t m_iMonitorID = -1;
++ MONITORID m_iMonitorID = -1;
+ std::string m_szTitle = "";
+ std::string m_szClass = "";
+ std::string m_szInitialTitle = "";
+@@ -358,8 +358,8 @@ class CWindow {
+ bool m_bStayFocused = false;
+
+ // for toplevel monitor events
+- uint64_t m_iLastToplevelMonitorID = -1;
+- uint64_t m_iLastSurfaceMonitorID = -1;
++ MONITORID m_iLastToplevelMonitorID = -1;
++ MONITORID m_iLastSurfaceMonitorID = -1;
+
+ // for idle inhibiting windows
+ eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
+@@ -421,7 +421,7 @@ class CWindow {
+ bool canBeTorn();
+ void setSuspended(bool suspend);
+ bool visibleOnMonitor(CMonitor* pMonitor);
+- int workspaceID();
++ WORKSPACEID workspaceID();
+ bool onSpecialWorkspace();
+ void activate(bool force = false);
+ int surfacesCount();
+@@ -490,9 +490,9 @@ class CWindow {
+
+ private:
+ // For hidden windows and stuff
+- bool m_bHidden = false;
+- bool m_bSuspended = false;
+- int m_iLastWorkspace = WORKSPACE_INVALID;
++ bool m_bHidden = false;
++ bool m_bSuspended = false;
++ WORKSPACEID m_iLastWorkspace = WORKSPACE_INVALID;
+ };
+
+ inline bool valid(PHLWINDOW w) {
+diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp
+index a08f1804..d9ac7927 100644
+--- a/src/desktop/Workspace.cpp
++++ b/src/desktop/Workspace.cpp
+@@ -5,13 +5,13 @@
+ #include
+ using namespace Hyprutils::String;
+
+-PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) {
++PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) {
+ PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy);
+ workspace->init(workspace);
+ return workspace;
+ }
+
+-CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special, bool isEmtpy) {
++CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) {
+ m_iMonitorID = monitorID;
+ m_iID = id;
+ m_szName = name;
+@@ -190,7 +190,7 @@ void CWorkspace::setActive(bool on) {
+ ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
+ }
+
+-void CWorkspace::moveToMonitor(const int& id) {
++void CWorkspace::moveToMonitor(const MONITORID& id) {
+ ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
+ }
+
+@@ -275,7 +275,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
+ i = std::min(NEXTSPACE, std::string::npos - 1);
+
+ if (cur == 'r') {
+- int from = 0, to = 0;
++ WORKSPACEID from = 0, to = 0;
+ if (!prop.starts_with("r[") || !prop.ends_with("]")) {
+ Debug::log(LOG, "Invalid selector {}", selector);
+ return false;
+@@ -365,7 +365,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
+ }
+
+ if (cur == 'w') {
+- int from = 0, to = 0;
++ WORKSPACEID from = 0, to = 0;
+ if (!prop.starts_with("w[") || !prop.ends_with("]")) {
+ Debug::log(LOG, "Invalid selector {}", selector);
+ return false;
+@@ -446,7 +446,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
+ return false;
+ }
+
+- int count;
++ WORKSPACEID count;
+ if (wantsCountGroup)
+ count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled),
+ wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt);
+@@ -506,7 +506,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
+ void CWorkspace::markInert() {
+ m_bInert = true;
+ m_iID = WORKSPACE_INVALID;
+- m_iMonitorID = -1;
++ m_iMonitorID = MONITOR_INVALID;
+ m_bVisible = false;
+ }
+
+diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp
+index 3e9ac8a8..9cacb0cc 100644
+--- a/src/desktop/Workspace.hpp
++++ b/src/desktop/Workspace.hpp
+@@ -17,16 +17,16 @@ class CWindow;
+
+ class CWorkspace {
+ public:
+- static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false, bool isEmtpy = true);
++ static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmtpy = true);
+ // use create() don't use this
+- CWorkspace(int id, int monitorID, std::string name, bool special = false, bool isEmpty = true);
++ CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
+ ~CWorkspace();
+
+ // Workspaces ID-based have IDs > 0
+ // and workspaces name-based have IDs starting with -1337
+- int m_iID = -1;
++ WORKSPACEID m_iID = WORKSPACE_INVALID;
+ std::string m_szName = "";
+- uint64_t m_iMonitorID = -1;
++ MONITORID m_iMonitorID = MONITOR_INVALID;
+ // Previous workspace ID and name is stored during a workspace change, allowing travel
+ // to the previous workspace.
+ SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
+@@ -67,7 +67,7 @@ class CWorkspace {
+ void startAnim(bool in, bool left, bool instant = false);
+ void setActive(bool on);
+
+- void moveToMonitor(const int&);
++ void moveToMonitor(const MONITORID&);
+
+ PHLWINDOW getLastFocusedWindow();
+ void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
+diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
+index 5d29a3b7..2eb7038f 100644
+--- a/src/events/Windows.cpp
++++ b/src/events/Windows.cpp
+@@ -148,7 +148,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
+ PWINDOW->m_iMonitorID = PMONITOR->ID;
+ } else {
+ if (isNumber(MONITORSTR)) {
+- const long int MONITOR = std::stoi(MONITORSTR);
++ const MONITORID MONITOR = std::stoi(MONITORSTR);
+ if (!g_pCompositor->getMonitorFromID(MONITOR))
+ PWINDOW->m_iMonitorID = 0;
+ else
+diff --git a/src/helpers/Color.cpp b/src/helpers/Color.cpp
+index 67526dc7..f9a207bb 100644
+--- a/src/helpers/Color.cpp
++++ b/src/helpers/Color.cpp
+@@ -21,6 +21,6 @@ CColor::CColor(uint64_t hex) {
+ this->a = ALPHA(hex);
+ }
+
+-uint32_t CColor::getAsHex() {
++uint32_t CColor::getAsHex() const {
+ return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1;
+ }
+\ No newline at end of file
+diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp
+index 7ec55b0d..8abfe748 100644
+--- a/src/helpers/Color.hpp
++++ b/src/helpers/Color.hpp
+@@ -10,7 +10,7 @@ class CColor {
+
+ float r = 0, g = 0, b = 0, a = 1.f;
+
+- uint32_t getAsHex();
++ uint32_t getAsHex() const;
+
+ CColor operator-(const CColor& c2) const {
+ return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a);
+diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp
+index 53c0dc13..86f24e3a 100644
+--- a/src/helpers/MiscFunctions.cpp
++++ b/src/helpers/MiscFunctions.cpp
+@@ -249,7 +249,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ return {WORKSPACE_INVALID};
+ }
+
+- std::set invalidWSes;
++ std::set invalidWSes;
+ if (same_mon) {
+ for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) {
+ const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor);
+@@ -258,8 +258,8 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ }
+ }
+
+- int id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0;
+- while (++id < INT_MAX) {
++ WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0;
++ while (++id < LONG_MAX) {
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
+ if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) {
+ result.id = id;
+@@ -296,9 +296,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+
+ result.id = (int)PLUSMINUSRESULT.value();
+
+- int remains = (int)result.id;
++ WORKSPACEID remains = result.id;
+
+- std::set invalidWSes;
++ std::set invalidWSes;
+
+ // Collect all the workspaces we can't jump to.
+ for (auto& ws : g_pCompositor->m_vWorkspaces) {
+@@ -318,7 +318,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ }
+
+ // Prepare all named workspaces in case when we need them
+- std::vector namedWSes;
++ std::vector namedWSes;
+ for (auto& ws : g_pCompositor->m_vWorkspaces) {
+ if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0)
+ continue;
+@@ -347,18 +347,18 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ } else {
+
+ // Just take a blind guess at where we'll probably end up
+- int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
+- int predictedWSID = activeWSID + remains;
+- int remainingWSes = 0;
+- char walkDir = in[1];
++ WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
++ WORKSPACEID predictedWSID = activeWSID + remains;
++ int remainingWSes = 0;
++ char walkDir = in[1];
+
+ // sanitize. 0 means invalid oob in -
+- predictedWSID = std::max(predictedWSID, 0);
++ predictedWSID = std::max(predictedWSID, 0L);
+
+ // Count how many invalidWSes are in between (how bad the prediction was)
+- int beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID;
+- int endID = in[1] == '+' ? predictedWSID : activeWSID;
+- auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
++ WORKSPACEID beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID;
++ WORKSPACEID endID = in[1] == '+' ? predictedWSID : activeWSID;
++ auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
+ for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
+ remainingWSes++;
+ }
+@@ -367,7 +367,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ if (activeWSID < 0) {
+ // Behaviour similar to 'm'
+ // Find current
+- int currentItem = -1;
++ size_t currentItem = -1;
+ for (size_t i = 0; i < namedWSes.size(); i++) {
+ if (namedWSes[i] == activeWSID) {
+ currentItem = i;
+@@ -376,14 +376,14 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ }
+
+ currentItem += remains;
+- currentItem = std::max(currentItem, 0);
+- if (currentItem >= (int)namedWSes.size()) {
++ currentItem = std::max(currentItem, 0UL);
++ if (currentItem >= namedWSes.size()) {
+ // At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0
+- int diff = currentItem - (namedWSes.size() - 1);
+- predictedWSID = diff;
+- int beginID = 1;
+- int endID = predictedWSID;
+- auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
++ size_t diff = currentItem - (namedWSes.size() - 1);
++ predictedWSID = diff;
++ WORKSPACEID beginID = 1;
++ WORKSPACEID endID = predictedWSID;
++ auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
+ for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
+ remainingWSes++;
+ }
+@@ -397,10 +397,10 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+
+ // Go in the search direction for remainingWSes
+ // The performance impact is directly proportional to the number of open and bound workspaces
+- int finalWSID = predictedWSID;
++ WORKSPACEID finalWSID = predictedWSID;
+ if (walkDir == '-') {
+- int beginID = finalWSID;
+- int curID = finalWSID;
++ WORKSPACEID beginID = finalWSID;
++ WORKSPACEID curID = finalWSID;
+ while (--curID > 0 && remainingWSes > 0) {
+ if (!invalidWSes.contains(curID)) {
+ remainingWSes--;
+@@ -411,9 +411,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ if (namedWSes.size()) {
+ // Go to the named workspaces
+ // Need remainingWSes more
+- int namedWSIdx = namedWSes.size() - remainingWSes;
++ auto namedWSIdx = namedWSes.size() - remainingWSes;
+ // Sanitze
+- namedWSIdx = std::clamp(namedWSIdx, 0, (int)namedWSes.size() - 1);
++ namedWSIdx = std::clamp(namedWSIdx, 0UL, namedWSes.size() - 1);
+ finalWSID = namedWSes[namedWSIdx];
+ } else {
+ // Couldn't find valid workspace in negative direction, search last first one back up positive direction
+@@ -425,7 +425,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ }
+ }
+ if (walkDir == '+') {
+- int curID = finalWSID;
++ WORKSPACEID curID = finalWSID;
+ while (++curID < INT32_MAX && remainingWSes > 0) {
+ if (!invalidWSes.contains(curID)) {
+ remainingWSes--;
+@@ -460,9 +460,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ result.id = (int)PLUSMINUSRESULT.value();
+
+ // result now has +/- what we should move on mon
+- int remains = (int)result.id;
++ int remains = (int)result.id;
+
+- std::vector validWSes;
++ std::vector validWSes;
+ for (auto& ws : g_pCompositor->m_vWorkspaces) {
+ if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors))
+ continue;
+@@ -472,7 +472,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+
+ std::sort(validWSes.begin(), validWSes.end());
+
+- int currentItem = -1;
++ ssize_t currentItem = -1;
+
+ if (absolute) {
+ // 1-index
+@@ -481,7 +481,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ // clamp
+ if (currentItem < 0) {
+ currentItem = 0;
+- } else if (currentItem >= (int)validWSes.size()) {
++ } else if (currentItem >= (ssize_t)validWSes.size()) {
+ currentItem = validWSes.size() - 1;
+ }
+ } else {
+@@ -489,8 +489,8 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size();
+
+ // get the current item
+- int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
+- for (size_t i = 0; i < validWSes.size(); i++) {
++ WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
++ for (ssize_t i = 0; i < (ssize_t)validWSes.size(); i++) {
+ if (validWSes[i] == activeWSID) {
+ currentItem = i;
+ break;
+@@ -501,7 +501,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
+ currentItem += remains;
+
+ // sanitize
+- if (currentItem >= (int)validWSes.size()) {
++ if (currentItem >= (ssize_t)validWSes.size()) {
+ currentItem = currentItem % validWSes.size();
+ } else if (currentItem < 0) {
+ currentItem = validWSes.size() + currentItem;
+@@ -547,9 +547,9 @@ std::optional cleanCmdForWorkspace(const std::string& inWorkspaceNa
+ const std::string workspaceRule = "workspace " + inWorkspaceName;
+
+ if (cmd[0] == '[') {
+- const int closingBracketIdx = cmd.find_last_of(']');
+- auto tmpRules = cmd.substr(1, closingBracketIdx - 1);
+- cmd = cmd.substr(closingBracketIdx + 1);
++ const auto closingBracketIdx = cmd.find_last_of(']');
++ auto tmpRules = cmd.substr(1, closingBracketIdx - 1);
++ cmd = cmd.substr(closingBracketIdx + 1);
+
+ auto rulesList = CVarList(tmpRules, 0, ';');
+
+@@ -785,13 +785,13 @@ std::vector getBacktrace() {
+
+ #ifdef HAS_EXECINFO
+ void* bt[1024];
+- size_t btSize;
++ int btSize;
+ char** btSymbols;
+
+ btSize = backtrace(bt, 1024);
+ btSymbols = backtrace_symbols(bt, btSize);
+
+- for (size_t i = 0; i < btSize; ++i) {
++ for (auto i = 0; i < btSize; ++i) {
+ callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}});
+ }
+ #else
+diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp
+index 49e3bced..8b2ea0d1 100644
+--- a/src/helpers/MiscFunctions.hpp
++++ b/src/helpers/MiscFunctions.hpp
+@@ -6,6 +6,8 @@
+ #include "math/Math.hpp"
+ #include
+ #include
++#include "../SharedDefs.hpp"
++#include "../macros.hpp"
+
+ struct SCallstackFrameInfo {
+ void* adr = nullptr;
+@@ -13,7 +15,7 @@ struct SCallstackFrameInfo {
+ };
+
+ struct SWorkspaceIDName {
+- int id = -1;
++ WORKSPACEID id = WORKSPACE_INVALID;
+ std::string name;
+ };
+
+diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
+index 8f23c462..9542d2c4 100644
+--- a/src/helpers/Monitor.cpp
++++ b/src/helpers/Monitor.cpp
+@@ -389,8 +389,8 @@ bool CMonitor::matchesStaticSelector(const std::string& selector) const {
+ }
+ }
+
+-int CMonitor::findAvailableDefaultWS() {
+- for (size_t i = 1; i < INT32_MAX; ++i) {
++WORKSPACEID CMonitor::findAvailableDefaultWS() {
++ for (WORKSPACEID i = 1; i < LONG_MAX; ++i) {
+ if (g_pCompositor->getWorkspaceByID(i))
+ continue;
+
+@@ -400,7 +400,7 @@ int CMonitor::findAvailableDefaultWS() {
+ return i;
+ }
+
+- return INT32_MAX; // shouldn't be reachable
++ return LONG_MAX; // shouldn't be reachable
+ }
+
+ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
+@@ -638,7 +638,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
+ g_pCompositor->updateFullscreenFadeOnWorkspace(activeSpecialWorkspace);
+ }
+
+-void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) {
++void CMonitor::changeWorkspace(const WORKSPACEID& id, bool internal, bool noMouseMove, bool noFocus) {
+ changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus);
+ }
+
+@@ -745,7 +745,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
+ g_pCompositor->updateSuspendedStates();
+ }
+
+-void CMonitor::setSpecialWorkspace(const int& id) {
++void CMonitor::setSpecialWorkspace(const WORKSPACEID& id) {
+ setSpecialWorkspace(g_pCompositor->getWorkspaceByID(id));
+ }
+
+@@ -766,11 +766,11 @@ void CMonitor::updateMatrix() {
+ }
+ }
+
+-int64_t CMonitor::activeWorkspaceID() {
++WORKSPACEID CMonitor::activeWorkspaceID() {
+ return activeWorkspace ? activeWorkspace->m_iID : 0;
+ }
+
+-int64_t CMonitor::activeSpecialWorkspaceID() {
++WORKSPACEID CMonitor::activeSpecialWorkspaceID() {
+ return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0;
+ }
+
+@@ -946,7 +946,7 @@ bool CMonitorState::updateSwapchain() {
+ Debug::log(WARN, "updateSwapchain: No mode?");
+ return true;
+ }
+- options.format = STATE.drmFormat;
++ options.format = m_pOwner->drmFormat;
+ options.scanout = true;
+ options.length = 2;
+ options.size = MODE->pixelSize;
+diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
+index fbe26f67..dcfcb63b 100644
+--- a/src/helpers/Monitor.hpp
++++ b/src/helpers/Monitor.hpp
+@@ -70,7 +70,7 @@ class CMonitor {
+
+ bool primary = false;
+
+- uint64_t ID = -1;
++ MONITORID ID = MONITOR_INVALID;
+ PHLWORKSPACE activeWorkspace = nullptr;
+ PHLWORKSPACE activeSpecialWorkspace = nullptr;
+ float setScale = 1; // scale set by cfg
+@@ -100,6 +100,7 @@ class CMonitor {
+ std::optional forceSize;
+ SP currentMode;
+ SP cursorSwapchain;
++ uint32_t drmFormat = DRM_FORMAT_INVALID;
+
+ bool dpmsStatus = true;
+ bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
+@@ -155,31 +156,31 @@ class CMonitor {
+ std::array, 4> m_aLayerSurfaceLayers;
+
+ // methods
+- void onConnect(bool noRule);
+- void onDisconnect(bool destroy = false);
+- void addDamage(const pixman_region32_t* rg);
+- void addDamage(const CRegion* rg);
+- void addDamage(const CBox* box);
+- bool shouldSkipScheduleFrameOnMouseEvent();
+- void setMirror(const std::string&);
+- bool isMirror();
+- bool matchesStaticSelector(const std::string& selector) const;
+- float getDefaultScale();
+- void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
+- void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
+- void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace);
+- void setSpecialWorkspace(const int& id);
+- void moveTo(const Vector2D& pos);
+- Vector2D middle();
+- void updateMatrix();
+- int64_t activeWorkspaceID();
+- int64_t activeSpecialWorkspaceID();
+- CBox logicalBox();
+- void scheduleDone();
+- bool attemptDirectScanout();
+-
+- bool m_bEnabled = false;
+- bool m_bRenderingInitPassed = false;
++ void onConnect(bool noRule);
++ void onDisconnect(bool destroy = false);
++ void addDamage(const pixman_region32_t* rg);
++ void addDamage(const CRegion* rg);
++ void addDamage(const CBox* box);
++ bool shouldSkipScheduleFrameOnMouseEvent();
++ void setMirror(const std::string&);
++ bool isMirror();
++ bool matchesStaticSelector(const std::string& selector) const;
++ float getDefaultScale();
++ void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
++ void changeWorkspace(const WORKSPACEID& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
++ void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace);
++ void setSpecialWorkspace(const WORKSPACEID& id);
++ void moveTo(const Vector2D& pos);
++ Vector2D middle();
++ void updateMatrix();
++ WORKSPACEID activeWorkspaceID();
++ WORKSPACEID activeSpecialWorkspaceID();
++ CBox logicalBox();
++ void scheduleDone();
++ bool attemptDirectScanout();
++
++ bool m_bEnabled = false;
++ bool m_bRenderingInitPassed = false;
+
+ // For the list lookup
+
+@@ -189,7 +190,7 @@ class CMonitor {
+
+ private:
+ void setupDefaultWS(const SMonitorRule&);
+- int findAvailableDefaultWS();
++ WORKSPACEID findAvailableDefaultWS();
+
+ wl_event_source* doneSource = nullptr;
+
+diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp
+index 25e0ca3b..48c23e6b 100644
+--- a/src/helpers/SdDaemon.cpp
++++ b/src/helpers/SdDaemon.cpp
+@@ -8,6 +8,7 @@
+ #include
+ #include
+ #include
++#include
+
+ namespace Systemd {
+ int SdBooted(void) {
+diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp
+index ec530df4..7b1726df 100644
+--- a/src/helpers/Timer.cpp
++++ b/src/helpers/Timer.cpp
+@@ -8,7 +8,7 @@ std::chrono::steady_clock::duration CTimer::getDuration() {
+ return std::chrono::steady_clock::now() - m_tpLastReset;
+ }
+
+-int CTimer::getMillis() {
++long CTimer::getMillis() {
+ return std::chrono::duration_cast(getDuration()).count();
+ }
+
+diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp
+index a6d1aeed..827e7625 100644
+--- a/src/helpers/Timer.hpp
++++ b/src/helpers/Timer.hpp
+@@ -6,7 +6,7 @@ class CTimer {
+ public:
+ void reset();
+ float getSeconds();
+- int getMillis();
++ long getMillis();
+ const std::chrono::steady_clock::time_point& chrono() const;
+
+ private:
+diff --git a/src/helpers/Watchdog.cpp b/src/helpers/Watchdog.cpp
+index b9f654da..c7ff648b 100644
+--- a/src/helpers/Watchdog.cpp
++++ b/src/helpers/Watchdog.cpp
+@@ -18,15 +18,14 @@ CWatchdog::CWatchdog() {
+ m_pWatchdog = std::make_unique([this] {
+ static auto PTIMEOUT = CConfigValue("debug:watchdog_timeout");
+
+- while (1337) {
+- std::unique_lock lk(m_mWatchdogMutex);
++ m_bWatchdogInitialized = true;
++ while (!m_bExitThread) {
++ std::unique_lock lk(m_mWatchdogMutex);
+
+ if (!m_bWillWatch)
+- m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; });
+- else {
+- if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false)
+- pthread_kill(m_iMainThreadPID, SIGUSR1);
+- }
++ m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified || m_bExitThread; });
++ else if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified || m_bExitThread; }) == false)
++ pthread_kill(m_iMainThreadPID, SIGUSR1);
+
+ if (m_bExitThread)
+ break;
+diff --git a/src/helpers/Watchdog.hpp b/src/helpers/Watchdog.hpp
+index 7bb499d6..b16cb518 100644
+--- a/src/helpers/Watchdog.hpp
++++ b/src/helpers/Watchdog.hpp
+@@ -11,21 +11,23 @@ class CWatchdog {
+ CWatchdog();
+ ~CWatchdog();
+
+- void startWatching();
+- void endWatching();
++ void startWatching();
++ void endWatching();
++
++ std::atomic m_bWatchdogInitialized{false};
+
+ private:
+ std::chrono::high_resolution_clock::time_point m_tTriggered;
+
+ pthread_t m_iMainThreadPID = 0;
+
+- bool m_bWatching = false;
+- bool m_bWillWatch = false;
++ std::atomic m_bWatching = false;
++ std::atomic m_bWillWatch = false;
+
+ std::unique_ptr m_pWatchdog;
+ std::mutex m_mWatchdogMutex;
+- bool m_bNotified = false;
+- bool m_bExitThread = false;
++ std::atomic m_bNotified = false;
++ std::atomic m_bExitThread = false;
+ std::condition_variable m_cvWatchdogCondition;
+ };
+
+diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp
+index f287056f..20085ff7 100644
+--- a/src/layout/DwindleLayout.cpp
++++ b/src/layout/DwindleLayout.cpp
+@@ -47,7 +47,7 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque* pD
+ }
+ }
+
+-int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) {
++int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) {
+ int no = 0;
+ for (auto& n : m_lDwindleNodesData) {
+ if (n.workspaceID == id && n.valid)
+@@ -56,7 +56,7 @@ int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) {
+ return no;
+ }
+
+-SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) {
++SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const WORKSPACEID& id) {
+ for (auto& n : m_lDwindleNodesData) {
+ if (n.workspaceID == id && validMapped(n.pWindow))
+ return &n;
+@@ -64,7 +64,7 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) {
+ return nullptr;
+ }
+
+-SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) {
++SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const WORKSPACEID& id, const Vector2D& point) {
+ SDwindleNodeData* res = nullptr;
+ double distClosest = -1;
+ for (auto& n : m_lDwindleNodesData) {
+@@ -88,7 +88,7 @@ SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(PHLWINDOW pWindow) {
+ return nullptr;
+ }
+
+-SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const int& id) {
++SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const WORKSPACEID& id) {
+ for (auto& n : m_lDwindleNodesData) {
+ if (!n.pParent && n.workspaceID == id)
+ return &n;
+@@ -246,6 +246,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
+
+ g_pHyprRenderer->damageWindow(PWINDOW);
+ }
++
++ PWINDOW->updateWindowDecos();
+ }
+
+ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection direction) {
+@@ -535,7 +537,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
+ m_lDwindleNodesData.remove(*PNODE);
+ }
+
+-void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
++void CHyprDwindleLayout::recalculateMonitor(const MONITORID& monid) {
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
+
+ if (!PMONITOR || !PMONITOR->activeWorkspace)
+@@ -872,7 +874,7 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir,
+ return;
+
+ const auto PNODE = getNodeFromWindow(pWindow);
+- const int originalWorkspaceID = pWindow->workspaceID();
++ const auto originalWorkspaceID = pWindow->workspaceID();
+ const Vector2D originalPos = pWindow->middle();
+
+ if (!PNODE)
+diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp
+index f638f6a2..bbd511c2 100644
+--- a/src/layout/DwindleLayout.hpp
++++ b/src/layout/DwindleLayout.hpp
+@@ -24,7 +24,7 @@ struct SDwindleNodeData {
+
+ CBox box = {0};
+
+- int workspaceID = -1;
++ WORKSPACEID workspaceID = WORKSPACE_INVALID;
+
+ float splitRatio = 1.f;
+
+@@ -48,7 +48,7 @@ class CHyprDwindleLayout : public IHyprLayout {
+ virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT);
+ virtual void onWindowRemovedTiling(PHLWINDOW);
+ virtual bool isWindowTiled(PHLWINDOW);
+- virtual void recalculateMonitor(const int&);
++ virtual void recalculateMonitor(const MONITORID&);
+ virtual void recalculateWindow(PHLWINDOW);
+ virtual void onBeginDragWindow();
+ virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr);
+@@ -77,13 +77,13 @@ class CHyprDwindleLayout : public IHyprLayout {
+
+ std::optional m_vOverrideFocalPoint; // for onWindowCreatedTiling.
+
+- int getNodesOnWorkspace(const int&);
++ int getNodesOnWorkspace(const WORKSPACEID&);
+ void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
+ void calculateWorkspace(const PHLWORKSPACE& pWorkspace);
+ SDwindleNodeData* getNodeFromWindow(PHLWINDOW);
+- SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
+- SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&);
+- SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
++ SDwindleNodeData* getFirstNodeOnWorkspace(const WORKSPACEID&);
++ SDwindleNodeData* getClosestNodeOnWorkspace(const WORKSPACEID&, const Vector2D&);
++ SDwindleNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&);
+
+ void toggleSplit(PHLWINDOW);
+ void swapSplit(PHLWINDOW);
+diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp
+index 4b1b59e3..7e0d5704 100644
+--- a/src/layout/IHyprLayout.hpp
++++ b/src/layout/IHyprLayout.hpp
+@@ -63,7 +63,7 @@ class IHyprLayout {
+ Called when the monitor requires a layout recalculation
+ this usually means reserved area changes
+ */
+- virtual void recalculateMonitor(const int&) = 0;
++ virtual void recalculateMonitor(const MONITORID&) = 0;
+
+ /*
+ Called when the compositor requests a window
+diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp
+index be00168f..e0b48e98 100644
+--- a/src/layout/MasterLayout.cpp
++++ b/src/layout/MasterLayout.cpp
+@@ -14,7 +14,7 @@ SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(PHLWINDOW pWindow) {
+ return nullptr;
+ }
+
+-int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
++int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) {
+ int no = 0;
+ for (auto& n : m_lMasterNodesData) {
+ if (n.workspaceID == ws)
+@@ -24,7 +24,7 @@ int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
+ return no;
+ }
+
+-int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) {
++int CHyprMasterLayout::getMastersOnWorkspace(const WORKSPACEID& ws) {
+ int no = 0;
+ for (auto& n : m_lMasterNodesData) {
+ if (n.workspaceID == ws && n.isMaster)
+@@ -34,7 +34,7 @@ int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) {
+ return no;
+ }
+
+-SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
++SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const WORKSPACEID& ws) {
+ for (auto& n : m_lMasterWorkspacesData) {
+ if (n.workspaceID == ws)
+ return &n;
+@@ -63,7 +63,7 @@ std::string CHyprMasterLayout::getLayoutName() {
+ return "Master";
+ }
+
+-SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) {
++SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const WORKSPACEID& ws) {
+ for (auto& n : m_lMasterNodesData) {
+ if (n.isMaster && n.workspaceID == ws)
+ return &n;
+@@ -304,7 +304,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
+ recalculateMonitor(pWindow->m_iMonitorID);
+ }
+
+-void CHyprMasterLayout::recalculateMonitor(const int& monid) {
++void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) {
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
+
+ if (!PMONITOR || !PMONITOR->activeWorkspace)
+@@ -732,6 +732,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
+
+ g_pHyprRenderer->damageWindow(PWINDOW);
+ }
++
++ PWINDOW->updateWindowDecos();
+ }
+
+ bool CHyprMasterLayout::isWindowTiled(PHLWINDOW pWindow) {
+diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp
+index fdb916e5..b72be74f 100644
+--- a/src/layout/MasterLayout.hpp
++++ b/src/layout/MasterLayout.hpp
+@@ -30,7 +30,7 @@ struct SMasterNodeData {
+
+ float percSize = 1.f; // size multiplier for resizing children
+
+- int workspaceID = -1;
++ WORKSPACEID workspaceID = WORKSPACE_INVALID;
+
+ bool ignoreFullscreenChecks = false;
+
+@@ -41,7 +41,7 @@ struct SMasterNodeData {
+ };
+
+ struct SMasterWorkspaceData {
+- int workspaceID = -1;
++ WORKSPACEID workspaceID = WORKSPACE_INVALID;
+ eOrientation orientation = ORIENTATION_LEFT;
+
+ //
+@@ -55,7 +55,7 @@ class CHyprMasterLayout : public IHyprLayout {
+ virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT);
+ virtual void onWindowRemovedTiling(PHLWINDOW);
+ virtual bool isWindowTiled(PHLWINDOW);
+- virtual void recalculateMonitor(const int&);
++ virtual void recalculateMonitor(const MONITORID&);
+ virtual void recalculateWindow(PHLWINDOW);
+ virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr);
+ virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE);
+@@ -81,14 +81,14 @@ class CHyprMasterLayout : public IHyprLayout {
+ void buildOrientationCycleVectorFromEOperation(std::vector& cycle);
+ void runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int next);
+ eOrientation getDynamicOrientation(PHLWORKSPACE);
+- int getNodesOnWorkspace(const int&);
++ int getNodesOnWorkspace(const WORKSPACEID&);
+ void applyNodeDataToWindow(SMasterNodeData*);
+ SMasterNodeData* getNodeFromWindow(PHLWINDOW);
+- SMasterNodeData* getMasterNodeOnWorkspace(const int&);
+- SMasterWorkspaceData* getMasterWorkspaceData(const int&);
++ SMasterNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&);
++ SMasterWorkspaceData* getMasterWorkspaceData(const WORKSPACEID&);
+ void calculateWorkspace(PHLWORKSPACE);
+ PHLWINDOW getNextWindow(PHLWINDOW, bool);
+- int getMastersOnWorkspace(const int&);
++ int getMastersOnWorkspace(const WORKSPACEID&);
+
+ friend struct SMasterNodeData;
+ friend struct SMasterWorkspaceData;
+diff --git a/src/macros.hpp b/src/macros.hpp
+index b2adb036..44014085 100644
+--- a/src/macros.hpp
++++ b/src/macros.hpp
+@@ -27,6 +27,8 @@
+ #define WORKSPACE_INVALID -1L
+ #define WORKSPACE_NOT_CHANGED -101
+
++#define MONITOR_INVALID -1L
++
+ #define LISTENER(name) \
+ void listener_##name(wl_listener*, void*); \
+ inline wl_listener listen_##name = {.notify = listener_##name}
+diff --git a/src/main.cpp b/src/main.cpp
+index e85b0a22..820a248c 100644
+--- a/src/main.cpp
++++ b/src/main.cpp
+@@ -36,7 +36,6 @@ int main(int argc, char** argv) {
+ setenv("XDG_BACKEND", "wayland", 1);
+ setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
+ setenv("MOZ_ENABLE_WAYLAND", "1", 1);
+- setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1);
+
+ // parse some args
+ std::string configPath;
+diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp
+index 3f3a25f6..1c047f85 100644
+--- a/src/managers/CursorManager.cpp
++++ b/src/managers/CursorManager.cpp
+@@ -102,7 +102,7 @@ CCursorManager::CCursorManager() {
+
+ // since we fallback to xcursor always load it on startup. otherwise we end up with a empty theme if hyprcursor is enabled in the config
+ // and then later is disabled.
+- m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale));
++ m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize, m_fCursorScale);
+
+ m_pAnimationTimer = makeShared(std::nullopt, cursorAnimTimer, this);
+ g_pEventLoopManager->addTimer(m_pAnimationTimer);
+@@ -163,7 +163,7 @@ void CCursorManager::setCursorFromName(const std::string& name) {
+ auto setXCursor = [this](auto const& name) {
+ float scale = std::ceil(m_fCursorScale);
+
+- auto xcursor = m_pXcursor->getShape(name, m_iSize * scale);
++ auto xcursor = m_pXcursor->getShape(name, m_iSize, m_fCursorScale);
+ auto& icon = xcursor->images.front();
+ auto buf = makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot);
+ setCursorBuffer(buf, icon.hotspot / scale, scale);
+@@ -277,7 +277,7 @@ void CCursorManager::setXWaylandCursor() {
+ g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size},
+ {CURSOR.hotspotX, CURSOR.hotspotY});
+ else {
+- auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale));
++ auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize, 1);
+ auto& icon = xcursor->images.front();
+
+ g_pXWayland->setCursor((uint8_t*)icon.pixels.data(), icon.size.x * 4, icon.size, icon.hotspot);
+@@ -329,12 +329,16 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) {
+ m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options);
+ if (!m_pHyprcursor->valid()) {
+ Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", m_szTheme);
+- m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize);
++ m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize, m_fCursorScale);
+ }
+ } else
+- m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize);
++ m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize, m_fCursorScale);
+
+ updateTheme();
+
+ return true;
+-}
+\ No newline at end of file
++}
++
++void CCursorManager::syncGsettings() {
++ m_pXcursor->syncGsettings();
++}
+diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp
+index ceb4816b..796ab10e 100644
+--- a/src/managers/CursorManager.hpp
++++ b/src/managers/CursorManager.hpp
+@@ -53,6 +53,7 @@ class CCursorManager {
+ void updateTheme();
+ SCursorImageData dataFor(const std::string& name); // for xwayland
+ void setXWaylandCursor();
++ void syncGsettings();
+
+ void tickAnimatedCursor();
+
+@@ -75,4 +76,4 @@ class CCursorManager {
+ Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData;
+ };
+
+-inline std::unique_ptr g_pCursorManager;
+\ No newline at end of file
++inline std::unique_ptr g_pCursorManager;
+diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp
+index 75c98e2a..079a6b68 100644
+--- a/src/managers/EventManager.cpp
++++ b/src/managers/EventManager.cpp
+@@ -8,6 +8,7 @@
+ #include
+ #include
+ #include
++#include
+
+ CEventManager::CEventManager() {
+ m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
+index c7b93730..38593497 100644
+--- a/src/managers/KeybindManager.cpp
++++ b/src/managers/KeybindManager.cpp
+@@ -180,6 +180,9 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
+ }
+
+ uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) {
++ if (keycode == 0)
++ return 0;
++
+ switch (keycode - 8) {
+ case KEY_LEFTMETA: return HL_MODIFIER_META;
+ case KEY_RIGHTMETA: return HL_MODIFIER_META;
+@@ -1163,6 +1166,8 @@ void CKeybindManager::fullscreenStateActive(std::string args) {
+ if (!PWINDOW)
+ return;
+
++ PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP);
++
+ int internalMode, clientMode;
+ try {
+ internalMode = std::stoi(ARGS[0]);
+@@ -1174,26 +1179,16 @@ void CKeybindManager::fullscreenStateActive(std::string args) {
+ const sFullscreenState STATE = sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal),
+ .client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)};
+
+- if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) {
++ if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client)
+ g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE});
+- PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP);
+- return;
+- }
+-
+- if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) {
+- g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.client, .client = PWINDOW->m_sFullscreenState.client});
+- PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP);
+- return;
+- }
+-
+- if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) {
+- g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = PWINDOW->m_sFullscreenState.internal});
+- PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP);
+- return;
+- }
++ else if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal)
++ g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client});
++ else if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client)
++ g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE});
++ else
++ g_pCompositor->setWindowFullscreenState(PWINDOW, STATE);
+
+- PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP);
+- g_pCompositor->setWindowFullscreenState(PWINDOW, STATE);
++ PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(PWINDOW->m_sFullscreenState.internal == PWINDOW->m_sFullscreenState.client, PRIORITY_SET_PROP);
+ }
+
+ void CKeybindManager::moveActiveToWorkspace(std::string args) {
+@@ -1738,7 +1733,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
+ return;
+ }
+
+- const int WORKSPACEID = getWorkspaceIDNameFromString(workspace).id;
++ const auto WORKSPACEID = getWorkspaceIDNameFromString(workspace).id;
+
+ if (WORKSPACEID == WORKSPACE_INVALID) {
+ Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!");
+@@ -1756,7 +1751,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
+ }
+
+ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
+- int workspaceID = getWorkspaceIDNameFromString(args).id;
++ auto workspaceID = getWorkspaceIDNameFromString(args).id;
+ if (workspaceID == WORKSPACE_INVALID) {
+ Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
+ return;
+@@ -1816,7 +1811,7 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) {
+
+ bool requestedWorkspaceIsAlreadyOpen = false;
+ const auto PMONITOR = g_pCompositor->m_pLastMonitor;
+- int specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID();
++ auto specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID();
+
+ for (auto& m : g_pCompositor->m_vMonitors) {
+ if (m->activeSpecialWorkspaceID() == workspaceID) {
+diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp
+index 3ba34c11..72ff5ae7 100644
+--- a/src/managers/PointerManager.cpp
++++ b/src/managers/PointerManager.cpp
+@@ -11,13 +11,21 @@
+ #include
+
+ CPointerManager::CPointerManager() {
+- hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) {
+- auto PMONITOR = std::any_cast>(data);
++ hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) {
++ auto PMONITOR = std::any_cast(data)->self.lock();
+
+ onMonitorLayoutChange();
+
+- PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
+- PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
++ PMONITOR->events.modeChanged.registerStaticListener(
++ [this, PMONITOR](void* owner, std::any data) {
++ g_pEventLoopManager->doLater([this, PMONITOR]() {
++ onMonitorLayoutChange();
++ checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name);
++ });
++ },
++ nullptr);
++ PMONITOR->events.disconnect.registerStaticListener(
++ [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
+ PMONITOR->events.destroy.registerStaticListener(
+ [this](void* owner, std::any data) {
+ if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown)
+@@ -35,6 +43,38 @@ CPointerManager::CPointerManager() {
+ });
+ }
+
++void CPointerManager::checkDefaultCursorWarp(SP monitor, std::string monitorName) {
++ static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor");
++ static bool cursorDefaultDone = false;
++ static bool firstLaunch = true;
++
++ const auto POS = monitor->middle();
++
++ // by default, cursor should be set to first monitor detected
++ // this is needed as a default if the monitor given in config above doesn't exist
++ if (firstLaunch) {
++ firstLaunch = false;
++ g_pCompositor->warpCursorTo(POS, true);
++ g_pInputManager->refocus();
++ return;
++ }
++
++ if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) {
++ if (*PCURSORMONITOR == monitorName) {
++ cursorDefaultDone = true;
++ g_pCompositor->warpCursorTo(POS, true);
++ g_pInputManager->refocus();
++ return;
++ }
++ }
++
++ // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed.
++ if (g_pCompositor->getMonitorFromCursor() == monitor.get()) {
++ g_pCompositor->warpCursorTo(POS, true);
++ g_pInputManager->refocus();
++ }
++}
++
+ void CPointerManager::lockSoftwareAll() {
+ for (auto& state : monitorStates)
+ state->softwareLocks++;
+diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp
+index 4a4c4f61..082855b5 100644
+--- a/src/managers/PointerManager.hpp
++++ b/src/managers/PointerManager.hpp
+@@ -26,6 +26,7 @@ class CPointerManager {
+ public:
+ CPointerManager();
+
++ void checkDefaultCursorWarp(SP monitor, std::string monitorName);
+ void attachPointer(SP pointer);
+ void attachTouch(SP touch);
+ void attachTablet(SP tablet);
+diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp
+index f2a7ab53..6f000f9f 100644
+--- a/src/managers/XCursorManager.cpp
++++ b/src/managers/XCursorManager.cpp
+@@ -1,7 +1,11 @@
+ #include
+ #include
+ #include
++#include
++#include
++#include "config/ConfigValue.hpp"
+ #include "helpers/CursorShapes.hpp"
++#include "../managers/CursorManager.hpp"
+ #include "debug/Log.hpp"
+ #include "XCursorManager.hpp"
+
+@@ -96,12 +100,13 @@ CXCursorManager::CXCursorManager() {
+ defaultCursor = hyprCursor;
+ }
+
+-void CXCursorManager::loadTheme(std::string const& name, int size) {
+- if (lastLoadSize == size && themeName == name)
++void CXCursorManager::loadTheme(std::string const& name, int size, float scale) {
++ if (lastLoadSize == (size * std::ceil(scale)) && themeName == name && lastLoadScale == scale)
+ return;
+
+- lastLoadSize = size;
+- themeName = name.empty() ? "default" : name;
++ lastLoadSize = size * std::ceil(scale);
++ lastLoadScale = scale;
++ themeName = name.empty() ? "default" : name;
+ defaultCursor.reset();
+ cursors.clear();
+
+@@ -146,12 +151,16 @@ void CXCursorManager::loadTheme(std::string const& name, int size) {
+
+ cursors.emplace_back(cursor);
+ }
++
++ static auto SYNCGSETTINGS = CConfigValue("cursor:sync_gsettings_theme");
++ if (*SYNCGSETTINGS)
++ syncGsettings();
+ }
+
+-SP CXCursorManager::getShape(std::string const& shape, int size) {
++SP CXCursorManager::getShape(std::string const& shape, int size, float scale) {
+ // monitor scaling changed etc, so reload theme with new size.
+- if (size != lastLoadSize)
+- loadTheme(themeName, size);
++ if ((size * std::ceil(scale)) != lastLoadSize || scale != lastLoadScale)
++ loadTheme(themeName, size, scale);
+
+ // try to get an icon we know if we have one
+ for (auto const& c : cursors) {
+@@ -503,8 +512,11 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa
+
+ if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) {
+ for (const auto& entry : std::filesystem::directory_iterator(path)) {
+- if (!entry.is_regular_file() && !entry.is_symlink())
++ std::error_code e1, e2;
++ if ((!entry.is_regular_file(e1) && !entry.is_symlink(e2)) || e1 || e2) {
++ Debug::log(WARN, "XCursor failed to load shape {}: {}", entry.path().stem().string(), e1 ? e1.message() : e2.message());
+ continue;
++ }
+
+ auto const& full = entry.path().string();
+ using PcloseType = int (*)(FILE*);
+@@ -542,3 +554,56 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa
+
+ return newCursors;
+ }
++
++void CXCursorManager::syncGsettings() {
++ auto checkParamExists = [](std::string const& paramName, std::string const& category) {
++ auto* gSettingsSchemaSource = g_settings_schema_source_get_default();
++
++ if (!gSettingsSchemaSource) {
++ Debug::log(WARN, "GSettings default schema source does not exist, can't sync GSettings");
++ return false;
++ }
++
++ auto* gSettingsSchema = g_settings_schema_source_lookup(gSettingsSchemaSource, category.c_str(), true);
++ bool hasParam = false;
++
++ if (gSettingsSchema != NULL) {
++ hasParam = gSettingsSchema && g_settings_schema_has_key(gSettingsSchema, paramName.c_str());
++ g_settings_schema_unref(gSettingsSchema);
++ }
++
++ return hasParam;
++ };
++
++ using SettingValue = std::variant;
++ auto setValue = [&checkParamExists](std::string const& paramName, const SettingValue& paramValue, std::string const& category) {
++ if (!checkParamExists(paramName, category)) {
++ Debug::log(WARN, "GSettings parameter doesnt exist {} in {}", paramName, category);
++ return;
++ }
++
++ auto* gsettings = g_settings_new(category.c_str());
++
++ if (!gsettings) {
++ Debug::log(WARN, "GSettings failed to allocate new settings with category {}", category);
++ return;
++ }
++
++ std::visit(
++ [&](auto&& value) {
++ using T = std::decay_t;
++ if constexpr (std::is_same_v)
++ g_settings_set_string(gsettings, paramName.c_str(), value.c_str());
++ else if constexpr (std::is_same_v)
++ g_settings_set_int(gsettings, paramName.c_str(), value);
++ },
++ paramValue);
++
++ g_settings_sync();
++ g_object_unref(gsettings);
++ };
++
++ int unscaledSize = lastLoadSize / std::ceil(lastLoadScale);
++ setValue("cursor-theme", themeName, "org.gnome.desktop.interface");
++ setValue("cursor-size", unscaledSize, "org.gnome.desktop.interface");
++}
+diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp
+index 20637055..1f3c24db 100644
+--- a/src/managers/XCursorManager.hpp
++++ b/src/managers/XCursorManager.hpp
+@@ -29,8 +29,9 @@ class CXCursorManager {
+ CXCursorManager();
+ ~CXCursorManager() = default;
+
+- void loadTheme(const std::string& name, int size);
+- SP getShape(std::string const& shape, int size);
++ void loadTheme(const std::string& name, int size, float scale);
++ SP getShape(std::string const& shape, int size, float scale);
++ void syncGsettings();
+
+ private:
+ SP createCursor(std::string const& shape, XcursorImages* xImages);
+@@ -39,9 +40,10 @@ class CXCursorManager {
+ std::vector> loadStandardCursors(std::string const& name, int size);
+ std::vector> loadAllFromDir(std::string const& path, int size);
+
+- int lastLoadSize = 0;
+- std::string themeName = "";
++ int lastLoadSize = 0;
++ float lastLoadScale = 0;
++ std::string themeName = "";
+ SP defaultCursor;
+ SP hyprCursor;
+ std::vector> cursors;
+-};
+\ No newline at end of file
++};
+diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp
+index c2c088f8..d1b85cf2 100644
+--- a/src/managers/eventLoop/EventLoopManager.cpp
++++ b/src/managers/eventLoop/EventLoopManager.cpp
+@@ -48,7 +48,6 @@ void CEventLoopManager::enterLoop() {
+ aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs();
+ for (auto& fd : aqPollFDs) {
+ m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get()));
+- fd->onSignal(); // dispatch outstanding
+ }
+
+ wl_display_run(m_sWayland.display);
+@@ -76,8 +75,8 @@ void CEventLoopManager::removeTimer(SP timer) {
+ }
+
+ static void timespecAddNs(timespec* pTimespec, int64_t delta) {
+- int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
+- int delta_s_high = delta / TIMESPEC_NSEC_PER_SEC;
++ auto delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
++ auto delta_s_high = delta / TIMESPEC_NSEC_PER_SEC;
+
+ pTimespec->tv_sec += delta_s_high;
+
+diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
+index c502cb0d..e5f921a2 100644
+--- a/src/managers/input/InputManager.cpp
++++ b/src/managers/input/InputManager.cpp
+@@ -82,18 +82,13 @@ CInputManager::~CInputManager() {
+ }
+
+ void CInputManager::onMouseMoved(IPointer::SMotionEvent e) {
+- static auto PSENS = CConfigValue("general:sensitivity");
+- static auto PNOACCEL = CConfigValue("input:force_no_accel");
+- static auto PSENSTORAW = CConfigValue("general:apply_sens_to_raw");
++ static auto PNOACCEL = CConfigValue("input:force_no_accel");
+
+ const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta;
+
+- if (*PSENSTORAW == 1)
+- PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA * *PSENS, e.unaccel * *PSENS);
+- else
+- PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel);
++ PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel);
+
+- g_pPointerManager->move(DELTA * *PSENS);
++ g_pPointerManager->move(DELTA);
+
+ mouseMoveUnified(e.timeMs);
+
+@@ -1112,8 +1107,9 @@ void CInputManager::setPointerConfigs() {
+ libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED);
+
+ if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop)
+- if (g_pConfigManager->getDeviceInt(devname, "tap-to-click", "input:touchpad:tap-to-click") == 1)
+- libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED);
++ libinput_device_config_tap_set_enabled(LIBINPUTDEV,
++ g_pConfigManager->getDeviceInt(devname, "tap-to-click", "input:touchpad:tap-to-click") == 1 ? LIBINPUT_CONFIG_TAP_ENABLED :
++ LIBINPUT_CONFIG_TAP_DISABLED);
+
+ if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) {
+
+diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp
+index f6e5c8be..f8e4b962 100644
+--- a/src/managers/input/InputMethodPopup.hpp
++++ b/src/managers/input/InputMethodPopup.hpp
+@@ -33,7 +33,7 @@ class CInputPopup {
+ WP popup;
+ SP surface;
+ CBox lastBoxLocal;
+- uint64_t lastMonitor = -1;
++ MONITORID lastMonitor = MONITOR_INVALID;
+
+ struct {
+ CHyprSignalListener map;
+diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp
+index c0e6c4f0..6ee690cd 100644
+--- a/src/managers/input/Swipe.cpp
++++ b/src/managers/input/Swipe.cpp
+@@ -77,7 +77,7 @@ void CInputManager::endWorkspaceSwipe() {
+ // left of where we started. Instead, it's one more than the greatest
+ // workspace ID that currently exists.
+ if (workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID && *PSWIPENEW) {
+- int maxWorkspace = 0;
++ WORKSPACEID maxWorkspace = 0;
+ for (const auto& ws : g_pCompositor->m_vWorkspaces) {
+ maxWorkspace = std::max(maxWorkspace, ws->m_iID);
+ }
+diff --git a/src/meson.build b/src/meson.build
+index 098d8298..475ecc24 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -28,6 +28,7 @@ executable('Hyprland', src,
+ xcb_xfixes_dep,
+ backtrace_dep,
+ epoll_dep,
++ gio_dep,
+ udis86,
+
+ dependency('pixman-1'),
+diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp
+index 38b8c800..13597fa9 100644
+--- a/src/protocols/AlphaModifier.cpp
++++ b/src/protocols/AlphaModifier.cpp
+@@ -4,8 +4,6 @@
+ #include "../render/Renderer.hpp"
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::alphaModifier->protoLog
+-
+ CAlphaModifier::CAlphaModifier(SP resource_, SP surface_) : resource(resource_), pSurface(surface_) {
+ if (!resource->resource())
+ return;
+diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp
+index 812afe53..233a5df9 100644
+--- a/src/protocols/CursorShape.cpp
++++ b/src/protocols/CursorShape.cpp
+@@ -2,8 +2,6 @@
+ #include
+ #include "../helpers/CursorShapes.hpp"
+
+-#define LOGM PROTO::cursorShape->protoLog
+-
+ CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
+ ;
+ }
+diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp
+index 9f5b6312..bc0945f1 100644
+--- a/src/protocols/DRMLease.cpp
++++ b/src/protocols/DRMLease.cpp
+@@ -1,10 +1,9 @@
+ #include "DRMLease.hpp"
+ #include "../Compositor.hpp"
++#include "managers/eventLoop/EventLoopManager.hpp"
+ #include
+ #include
+
+-#define LOGM PROTO::lease->protoLog
+-
+ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) {
+ if (!good())
+ return;
+@@ -247,10 +246,8 @@ CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver,
+ break;
+ }
+
+- if (!primaryDevice || primaryDevice->success) {
+- PROTO::lease.reset();
+- return;
+- }
++ if (!primaryDevice || !primaryDevice->success)
++ g_pEventLoopManager->doLater([]() { PROTO::lease.reset(); });
+ }
+
+ void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
+diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp
+index 9a48b99a..4993f1a4 100644
+--- a/src/protocols/DRMSyncobj.cpp
++++ b/src/protocols/DRMSyncobj.cpp
+@@ -7,8 +7,6 @@
+
+ #include
+
+-#define LOGM PROTO::sync->protoLog
+-
+ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp
+index c039d3b4..ad6ee89a 100644
+--- a/src/protocols/DataDeviceWlr.cpp
++++ b/src/protocols/DataDeviceWlr.cpp
+@@ -3,8 +3,6 @@
+ #include "../managers/SeatManager.hpp"
+ #include "core/Seat.hpp"
+
+-#define LOGM PROTO::dataWlr->protoLog
+-
+ CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp
+index 40f9af44..2d6b2ee2 100644
+--- a/src/protocols/FocusGrab.cpp
++++ b/src/protocols/FocusGrab.cpp
+@@ -8,8 +8,6 @@
+ #include
+ #include
+
+-#define LOGM PROTO::focusGrab->protoLog
+-
+ CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP surface) {
+ listeners.destroy = surface->events.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); });
+ }
+diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp
+index f7b3886f..59888ce2 100644
+--- a/src/protocols/ForeignToplevel.cpp
++++ b/src/protocols/ForeignToplevel.cpp
+@@ -1,8 +1,6 @@
+ #include "ForeignToplevel.hpp"
+ #include "../Compositor.hpp"
+
+-#define LOGM PROTO::foreignToplevel->protoLog
+-
+ CForeignToplevelHandle::CForeignToplevelHandle(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) {
+ if (!resource_->resource())
+ return;
+diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp
+index 295834ea..bd597a91 100644
+--- a/src/protocols/ForeignToplevelWlr.cpp
++++ b/src/protocols/ForeignToplevelWlr.cpp
+@@ -4,8 +4,6 @@
+ #include "protocols/core/Output.hpp"
+ #include "render/Renderer.hpp"
+
+-#define LOGM PROTO::foreignToplevelWlr->protoLog
+-
+ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) {
+ if (!resource_->resource())
+ return;
+@@ -119,7 +117,7 @@ wl_resource* CForeignToplevelHandleWlr::res() {
+ }
+
+ void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) {
+- if (lastMonitorID == (int64_t)pMonitor->ID)
++ if (lastMonitorID == pMonitor->ID)
+ return;
+
+ const auto CLIENT = resource->client();
+diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp
+index e3b6f3f3..99f63b47 100644
+--- a/src/protocols/ForeignToplevelWlr.hpp
++++ b/src/protocols/ForeignToplevelWlr.hpp
+@@ -20,7 +20,7 @@ class CForeignToplevelHandleWlr {
+ SP resource;
+ PHLWINDOWREF pWindow;
+ bool closed = false;
+- int64_t lastMonitorID = -1;
++ MONITORID lastMonitorID = MONITOR_INVALID;
+
+ void sendMonitor(CMonitor* pMonitor);
+ void sendState();
+diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp
+index 5bf56c5a..d39fa67c 100644
+--- a/src/protocols/FractionalScale.cpp
++++ b/src/protocols/FractionalScale.cpp
+@@ -2,8 +2,6 @@
+ #include
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::fractional->protoLog
+-
+ CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
+ ;
+ }
+diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp
+index 494d9862..c902d00e 100644
+--- a/src/protocols/GammaControl.cpp
++++ b/src/protocols/GammaControl.cpp
+@@ -5,8 +5,6 @@
+ #include "../Compositor.hpp"
+ #include "../protocols/core/Output.hpp"
+
+-#define LOGM PROTO::gamma->protoLog
+-
+ CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) {
+ if (!resource_->resource())
+ return;
+@@ -109,7 +107,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out
+ }
+
+ CGammaControl::~CGammaControl() {
+- if (!gammaTableSet || !pMonitor)
++ if (!gammaTableSet || !pMonitor || !pMonitor->output)
+ return;
+
+ // reset the LUT if the client dies for whatever reason and doesn't unset the gamma
+diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp
+index 860004c9..92bfbae4 100644
+--- a/src/protocols/GlobalShortcuts.cpp
++++ b/src/protocols/GlobalShortcuts.cpp
+@@ -1,8 +1,6 @@
+ #include "GlobalShortcuts.hpp"
+ #include "../Compositor.hpp"
+
+-#define LOGM PROTO::globalShortcuts->protoLog
+-
+ CShortcutClient::CShortcutClient(SP resource_) : resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp
+index 2ec7d2a1..8d915ac6 100644
+--- a/src/protocols/IdleNotify.cpp
++++ b/src/protocols/IdleNotify.cpp
+@@ -1,8 +1,6 @@
+ #include "IdleNotify.hpp"
+ #include "../managers/eventLoop/EventLoopManager.hpp"
+
+-#define LOGM PROTO::idle->protoLog
+-
+ static int onTimer(SP self, void* data) {
+
+ const auto NOTIF = (CExtIdleNotification*)data;
+diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp
+index fd306f09..a0820e0b 100644
+--- a/src/protocols/InputMethodV2.cpp
++++ b/src/protocols/InputMethodV2.cpp
+@@ -6,8 +6,6 @@
+ #include "core/Compositor.hpp"
+ #include
+
+-#define LOGM PROTO::ime->protoLog
+-
+ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SP resource_, SP owner_) : resource(resource_), owner(owner_) {
+ if (!resource->resource())
+ return;
+diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp
+index 17d3b22a..c02d23f3 100644
+--- a/src/protocols/LayerShell.cpp
++++ b/src/protocols/LayerShell.cpp
+@@ -4,8 +4,6 @@
+ #include "core/Compositor.hpp"
+ #include "core/Output.hpp"
+
+-#define LOGM PROTO::layerShell->protoLog
+-
+ void CLayerShellResource::SState::reset() {
+ anchor = 0;
+ exclusive = 0;
+diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp
+index 0fbf832e..32625792 100644
+--- a/src/protocols/LinuxDMABUF.cpp
++++ b/src/protocols/LinuxDMABUF.cpp
+@@ -14,8 +14,6 @@
+ #include "../render/OpenGL.hpp"
+ #include "../Compositor.hpp"
+
+-#define LOGM PROTO::linuxDma->protoLog
+-
+ static std::optional devIDFromFD(int fd) {
+ struct stat stat;
+ if (fstat(fd, &stat) != 0)
+@@ -425,7 +423,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const
+ auto dev = devIDFromFD(rendererFD);
+
+ if (!dev.has_value()) {
+- protoLog(ERR, "failed to get drm dev, disabling linux dmabuf");
++ LOGM(ERR, "failed to get drm dev, disabling linux dmabuf");
+ removeGlobal();
+ return;
+ }
+@@ -477,7 +475,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const
+
+ drmDevice* device = nullptr;
+ if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) {
+- protoLog(ERR, "failed to get drm dev, disabling linux dmabuf");
++ LOGM(ERR, "failed to get drm dev, disabling linux dmabuf");
+ removeGlobal();
+ return;
+ }
+@@ -487,14 +485,13 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const
+ mainDeviceFD = open(name, O_RDWR | O_CLOEXEC);
+ drmFreeDevice(&device);
+ if (mainDeviceFD < 0) {
+- protoLog(ERR, "failed to open drm dev, disabling linux dmabuf");
++ LOGM(ERR, "failed to open drm dev, disabling linux dmabuf");
+ removeGlobal();
+ return;
+ }
+ } else {
+- protoLog(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null");
++ LOGM(ERR, "DRM device {} has no render node, disabling linux dmabuf checks", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null");
+ drmFreeDevice(&device);
+- removeGlobal();
+ }
+ });
+ }
+diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp
+index ed412555..9fcd5f9b 100644
+--- a/src/protocols/MesaDRM.cpp
++++ b/src/protocols/MesaDRM.cpp
+@@ -4,8 +4,6 @@
+ #include "../Compositor.hpp"
+ #include "types/WLBuffer.hpp"
+
+-#define LOGM PROTO::mesaDRM->protoLog
+-
+ CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) {
+ LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes);
+ for (int i = 0; i < attrs_.planes; ++i) {
+@@ -115,7 +113,7 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co
+ drmDevice* dev = nullptr;
+ int drmFD = g_pCompositor->m_iDRMFD;
+ if (drmGetDevice2(drmFD, 0, &dev) != 0) {
+- protoLog(ERR, "Failed to get device, disabling MesaDRM");
++ LOGM(ERR, "Failed to get device, disabling MesaDRM");
+ removeGlobal();
+ return;
+ }
+@@ -126,13 +124,13 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co
+ ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY));
+
+ if (!dev->nodes[DRM_NODE_PRIMARY]) {
+- protoLog(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM");
++ LOGM(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM");
+ drmFreeDevice(&dev);
+ removeGlobal();
+ return;
+ }
+
+- protoLog(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]);
++ LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]);
+ nodeName = dev->nodes[DRM_NODE_PRIMARY];
+ }
+ drmFreeDevice(&dev);
+diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp
+index 66f4c5f0..cfe388fa 100644
+--- a/src/protocols/OutputManagement.cpp
++++ b/src/protocols/OutputManagement.cpp
+@@ -4,8 +4,6 @@
+
+ using namespace Aquamarine;
+
+-#define LOGM PROTO::outputManagement->protoLog
+-
+ COutputManager::COutputManager(SP resource_) : resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp
+index 597b9871..0c324bf0 100644
+--- a/src/protocols/OutputPower.cpp
++++ b/src/protocols/OutputPower.cpp
+@@ -2,8 +2,6 @@
+ #include "../Compositor.hpp"
+ #include "core/Output.hpp"
+
+-#define LOGM PROTO::outputPower->protoLog
+-
+ COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_) : resource(resource_), pMonitor(pMonitor_) {
+ if (!resource->resource())
+ return;
+diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp
+index fd15242d..0f2dd991 100644
+--- a/src/protocols/PointerConstraints.cpp
++++ b/src/protocols/PointerConstraints.cpp
+@@ -5,8 +5,6 @@
+ #include "../managers/SeatManager.hpp"
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::constraints->protoLog
+-
+ CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) :
+ resourceL(resource_), locked(true), lifetime(lifetime_) {
+ if (!resource_->resource())
+diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp
+index 86510779..c83e3887 100644
+--- a/src/protocols/PointerGestures.cpp
++++ b/src/protocols/PointerGestures.cpp
+@@ -4,8 +4,6 @@
+ #include "core/Seat.hpp"
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::pointerGestures->protoLog
+-
+ CPointerGestureSwipe::CPointerGestureSwipe(SP resource_) : resource(resource_) {
+ if (!resource->resource())
+ return;
+diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp
+index a2fc270c..335cf557 100644
+--- a/src/protocols/PresentationTime.cpp
++++ b/src/protocols/PresentationTime.cpp
+@@ -6,8 +6,6 @@
+ #include "core/Output.hpp"
+ #include
+
+-#define LOGM PROTO::presentation->protoLog
+-
+ CQueuedPresentationData::CQueuedPresentationData(SP surf) : surface(surf) {
+ ;
+ }
+diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp
+index 78eb8d63..4fede706 100644
+--- a/src/protocols/PrimarySelection.cpp
++++ b/src/protocols/PrimarySelection.cpp
+@@ -4,8 +4,6 @@
+ #include "core/Seat.hpp"
+ #include "../config/ConfigValue.hpp"
+
+-#define LOGM PROTO::primarySelection->protoLog
+-
+ CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp
+index a8afba84..f246f6dd 100644
+--- a/src/protocols/Screencopy.cpp
++++ b/src/protocols/Screencopy.cpp
+@@ -9,8 +9,6 @@
+
+ #include
+
+-#define LOGM PROTO::screencopy->protoLog
+-
+ CScreencopyFrame::~CScreencopyFrame() {
+ if (buffer && buffer->locked())
+ buffer->unlock();
+diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp
+index 42da52a9..c7b98a9c 100644
+--- a/src/protocols/ServerDecorationKDE.cpp
++++ b/src/protocols/ServerDecorationKDE.cpp
+@@ -1,8 +1,6 @@
+ #include "ServerDecorationKDE.hpp"
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::serverDecorationKDE->protoLog
+-
+ CServerDecorationKDE::CServerDecorationKDE(SP resource_, SP surf) : resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp
+index df97413c..7b0d8b3b 100644
+--- a/src/protocols/SessionLock.cpp
++++ b/src/protocols/SessionLock.cpp
+@@ -5,8 +5,6 @@
+ #include "core/Compositor.hpp"
+ #include "core/Output.hpp"
+
+-#define LOGM PROTO::sessionLock->protoLog
+-
+ CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, CMonitor* pMonitor_, WP owner_) :
+ resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) {
+ if (!resource->resource())
+diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp
+index 1a0433e6..e4424ed7 100644
+--- a/src/protocols/ShortcutsInhibit.cpp
++++ b/src/protocols/ShortcutsInhibit.cpp
+@@ -3,8 +3,6 @@
+ #include "../Compositor.hpp"
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::shortcutsInhibit->protoLog
+-
+ CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP resource_, SP surf) : resource(resource_), pSurface(surf) {
+ if (!resource->resource())
+ return;
+diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp
+index 72c7cfde..b974152e 100644
+--- a/src/protocols/Tablet.cpp
++++ b/src/protocols/Tablet.cpp
+@@ -7,8 +7,6 @@
+ #include
+ #include
+
+-#define LOGM PROTO::tablet->protoLog
+-
+ CTabletPadStripV2Resource::CTabletPadStripV2Resource(SP resource_, uint32_t id_) : id(id_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp
+index 78e910cb..f25f5aca 100644
+--- a/src/protocols/TextInputV1.cpp
++++ b/src/protocols/TextInputV1.cpp
+@@ -3,8 +3,6 @@
+ #include "../Compositor.hpp"
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::textInputV1->protoLog
+-
+ CTextInputV1::~CTextInputV1() {
+ events.destroy.emit();
+ }
+diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp
+index 1302a57f..99d799f3 100644
+--- a/src/protocols/TextInputV3.cpp
++++ b/src/protocols/TextInputV3.cpp
+@@ -2,8 +2,6 @@
+ #include
+ #include "core/Compositor.hpp"
+
+-#define LOGM PROTO::textInputV3->protoLog
+-
+ void CTextInputV3::SState::reset() {
+ cause = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD;
+ surrounding.updated = false;
+diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp
+index fb3fde2b..05e991d6 100644
+--- a/src/protocols/ToplevelExport.cpp
++++ b/src/protocols/ToplevelExport.cpp
+@@ -8,8 +8,6 @@
+
+ #include
+
+-#define LOGM PROTO::toplevelExport->protoLog
+-
+ CToplevelExportClient::CToplevelExportClient(SP resource_) : resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp
+index 78f3039f..58cb851d 100644
+--- a/src/protocols/Viewporter.cpp
++++ b/src/protocols/Viewporter.cpp
+@@ -2,8 +2,6 @@
+ #include "core/Compositor.hpp"
+ #include
+
+-#define LOGM PROTO::viewport->protoLog
+-
+ CViewportResource::CViewportResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp
+index 2642ec11..27a4f248 100644
+--- a/src/protocols/VirtualKeyboard.cpp
++++ b/src/protocols/VirtualKeyboard.cpp
+@@ -2,8 +2,6 @@
+ #include
+ #include "../devices/IKeyboard.hpp"
+
+-#define LOGM PROTO::virtualKeyboard->protoLog
+-
+ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp
+index 8626241a..eb92a640 100644
+--- a/src/protocols/VirtualPointer.cpp
++++ b/src/protocols/VirtualPointer.cpp
+@@ -1,8 +1,6 @@
+ #include "VirtualPointer.hpp"
+ #include "core/Output.hpp"
+
+-#define LOGM PROTO::virtualPointer->protoLog
+-
+ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_, WP boundOutput_) : boundOutput(boundOutput_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp
+index 954f160d..0782d323 100644
+--- a/src/protocols/WaylandProtocol.cpp
++++ b/src/protocols/WaylandProtocol.cpp
+@@ -21,7 +21,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co
+ m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, iface, ver, this, &bindManagerInternal);
+
+ if (!m_pGlobal) {
+- protoLog(ERR, "could not create a global");
++ LOGM(ERR, "could not create a global [{}]", m_szName);
+ return;
+ }
+
+@@ -30,7 +30,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co
+ m_liDisplayDestroy.parent = this;
+ wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener);
+
+- protoLog(LOG, "Registered global");
++ LOGM(LOG, "Registered global [{}]", m_szName);
+ }
+
+ IWaylandProtocol::~IWaylandProtocol() {
+diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp
+index 4d4e7925..0fa8daab 100644
+--- a/src/protocols/WaylandProtocol.hpp
++++ b/src/protocols/WaylandProtocol.hpp
+@@ -11,6 +11,35 @@
+
+ #define PROTO NProtocols
+
++#define EXTRACT_CLASS_NAME() \
++ []() constexpr -> std::string_view { \
++ constexpr std::string_view prettyFunction = __PRETTY_FUNCTION__; \
++ constexpr size_t colons = prettyFunction.find("::"); \
++ if (colons != std::string_view::npos) { \
++ constexpr size_t begin = prettyFunction.substr(0, colons).rfind(' ') + 1; \
++ constexpr size_t end = colons - begin; \
++ return prettyFunction.substr(begin, end); \
++ } else { \
++ return "Global"; \
++ } \
++ }()
++
++#define LOGM(level, ...) \
++ do { \
++ std::ostringstream oss; \
++ if (level == WARN || level == ERR || level == CRIT) { \
++ oss << "[" << __FILE__ << ":" << __LINE__ << "] "; \
++ } else if (level == LOG || level == INFO || level == TRACE) { \
++ oss << "[" << EXTRACT_CLASS_NAME() << "] "; \
++ } \
++ if constexpr (std::is_same_v) { \
++ oss << __VA_ARGS__; \
++ Debug::log(level, oss.str()); \
++ } else { \
++ Debug::log(level, std::format("{}{}", oss.str(), std::format(__VA_ARGS__))); \
++ } \
++ } while (0)
++
+ class IWaylandProtocol;
+ struct IWaylandProtocolDestroyWrapper {
+ wl_listener listener;
+@@ -22,15 +51,10 @@ class IWaylandProtocol {
+ IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name);
+ virtual ~IWaylandProtocol();
+
+- virtual void onDisplayDestroy();
+- virtual void removeGlobal();
+-
+- virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0;
++ virtual void onDisplayDestroy();
++ virtual void removeGlobal();
+
+- template
+- void protoLog(LogLevel level, std::format_string fmt, Args&&... args) {
+- Debug::log(level, std::format("[{}] ", m_szName) + std::vformat(fmt.get(), std::make_format_args(args...)));
+- };
++ virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0;
+
+ IWaylandProtocolDestroyWrapper m_liDisplayDestroy;
+
+diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp
+index 40f33f02..4a6c7bfe 100644
+--- a/src/protocols/XDGActivation.cpp
++++ b/src/protocols/XDGActivation.cpp
+@@ -4,8 +4,6 @@
+ #include "core/Compositor.hpp"
+ #include
+
+-#define LOGM PROTO::activation->protoLog
+-
+ CXDGActivationToken::CXDGActivationToken(SP resource_) : resource(resource_) {
+ if (!resource_->resource())
+ return;
+diff --git a/src/protocols/XDGDecoration.cpp b/src/protocols/XDGDecoration.cpp
+index 021a1141..07b1694c 100644
+--- a/src/protocols/XDGDecoration.cpp
++++ b/src/protocols/XDGDecoration.cpp
+@@ -1,8 +1,6 @@
+ #include "XDGDecoration.hpp"
+ #include
+
+-#define LOGM PROTO::xdgDecoration->protoLog
+-
+ CXDGDecoration::CXDGDecoration(SP resource_, wl_resource* toplevel) : resource(resource_), pToplevelResource(toplevel) {
+ if (!resource->resource())
+ return;
+diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp
+index 073aa502..9c2c353c 100644
+--- a/src/protocols/XDGOutput.cpp
++++ b/src/protocols/XDGOutput.cpp
+@@ -12,8 +12,6 @@
+
+ //
+
+-#define LOGM PROTO::xdgOutput->protoLog
+-
+ void CXDGOutputProtocol::onManagerResourceDestroy(wl_resource* res) {
+ std::erase_if(m_vManagerResources, [&](const auto& other) { return other->resource() == res; });
+ }
+diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp
+index aea23329..eaf5c333 100644
+--- a/src/protocols/XDGShell.cpp
++++ b/src/protocols/XDGShell.cpp
+@@ -6,8 +6,6 @@
+ #include "core/Compositor.hpp"
+ #include
+
+-#define LOGM PROTO::xdgShell->protoLog
+-
+ void SXDGPositionerState::setAnchor(xdgPositionerAnchor edges) {
+ anchor.setTop(edges == XDG_POSITIONER_ANCHOR_TOP || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT);
+ anchor.setLeft(edges == XDG_POSITIONER_ANCHOR_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT);
+diff --git a/src/protocols/XWaylandShell.cpp b/src/protocols/XWaylandShell.cpp
+index 6cc5256f..d6c3b1a8 100644
+--- a/src/protocols/XWaylandShell.cpp
++++ b/src/protocols/XWaylandShell.cpp
+@@ -2,8 +2,6 @@
+ #include "core/Compositor.hpp"
+ #include
+
+-#define LOGM PROTO::xwaylandShell->protoLog
+-
+ CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
+index a767dd52..8b6f46b1 100644
+--- a/src/protocols/core/Compositor.cpp
++++ b/src/protocols/core/Compositor.cpp
+@@ -13,8 +13,6 @@
+ #include "../../render/Renderer.hpp"
+ #include
+
+-#define LOGM PROTO::compositor->protoLog
+-
+ class CDefaultSurfaceRole : public ISurfaceRole {
+ public:
+ virtual eSurfaceRole role() {
+diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp
+index fe3905d0..4ed28f24 100644
+--- a/src/protocols/core/DataDevice.cpp
++++ b/src/protocols/core/DataDevice.cpp
+@@ -6,8 +6,6 @@
+ #include "Seat.hpp"
+ #include "Compositor.hpp"
+
+-#define LOGM PROTO::data->protoLog
+-
+ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp
+index bb6a9d4d..a111c12c 100644
+--- a/src/protocols/core/Seat.cpp
++++ b/src/protocols/core/Seat.cpp
+@@ -9,8 +9,6 @@
+
+ #include
+
+-#define LOGM PROTO::seat->protoLog
+-
+ CWLTouchResource::CWLTouchResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) {
+ if (!good())
+ return;
+diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp
+index 75c2134a..9996a607 100644
+--- a/src/protocols/core/Shm.cpp
++++ b/src/protocols/core/Shm.cpp
+@@ -7,8 +7,6 @@
+ #include "../../Compositor.hpp"
+ #include "../../helpers/Format.hpp"
+
+-#define LOGM PROTO::shm->protoLog
+-
+ CWLSHMBuffer::CWLSHMBuffer(SP