mirror of
https://github.com/elwrcl/copnix.git
synced 2026-10-31 14:28:02 +03:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d7106353b | ||
|
|
db0889bcd0 | ||
|
|
d909653b4c | ||
|
|
776b7c3f87 |
No files matched your search
Generated
+71
-83
@@ -2,22 +2,16 @@
|
||||
"nodes": {
|
||||
"agenix": {
|
||||
"inputs": {
|
||||
"darwin": [
|
||||
"nix-darwin"
|
||||
],
|
||||
"home-manager": [
|
||||
"home-manager"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790530381,
|
||||
"narHash": "sha256-/FjF9A8HVLVftjdmz1MPA2G0wSYWRaC628NTAsCqeyI=",
|
||||
"lastModified": 1790734419,
|
||||
"narHash": "sha256-n7wew722m1OTBT9DOIMxNX/NF4zfsSUABAO5eW3wikE=",
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"rev": "9353cb29366a8535ac9483065284785fd48012a2",
|
||||
"rev": "3daa710894355fa2fad8243380af373a2b4046ef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -35,11 +29,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790507313,
|
||||
"narHash": "sha256-KNfYoS4N3LeQ+8zSBn/QuiR7nfsVqd8fqJL30shP9pI=",
|
||||
"lastModified": 1792224768,
|
||||
"narHash": "sha256-Jj1lkSuYdHE42h5n5O9eY6HrQR7JOEo8MMWyQCPdHBE=",
|
||||
"owner": "chaotic-cx",
|
||||
"repo": "nyx",
|
||||
"rev": "a6a3dcf6a7b1d3cc454f919ed75d60d21179e67e",
|
||||
"rev": "d47fbd3559774e48b768e60b6295f2f16c5e6d75",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -71,11 +65,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1788450739,
|
||||
"narHash": "sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU=",
|
||||
"lastModified": 1790898470,
|
||||
"narHash": "sha256-zTwuwezD0w3hpga6a6P8emidzAZFyWqlNeRBlpWOOl8=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "31729ca8cbdb4fa927b34e5f4353e6a83f39e993",
|
||||
"rev": "024633cd702b10285db5cb19b40ad48d2399ba60",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -142,11 +136,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790333762,
|
||||
"narHash": "sha256-KHGGibq49aAfnESf/xdS+uWgZlk3zNlOkASmxJbgxx4=",
|
||||
"lastModified": 1792231076,
|
||||
"narHash": "sha256-B0jTpyaR+YEAg1dcmeYjoUwOQBRAgLNvzTg66S/cxKo=",
|
||||
"owner": "elwrcl",
|
||||
"repo": "heliux",
|
||||
"rev": "177ae55b79c30adf18203793beae2c47334b5960",
|
||||
"rev": "0b28ec7dde52d74f70bafeae5e68c457ce61c0ed",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -163,11 +157,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790365885,
|
||||
"narHash": "sha256-iQ0ebhiVo64NktTnwft9hNxlFu4j5cvljVxyJaEVIP4=",
|
||||
"lastModified": 1792098797,
|
||||
"narHash": "sha256-u4DIIZgznEGzByxXrxWCXK19VcMtTBmi/M9gZ7Jk9bM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "7b4c5ec4bedaf1e062bbc1bcaeddbc6bd242aa1b",
|
||||
"rev": "640725978b99076e18e069f6e7d2959124584f8f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -183,11 +177,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790365885,
|
||||
"narHash": "sha256-iQ0ebhiVo64NktTnwft9hNxlFu4j5cvljVxyJaEVIP4=",
|
||||
"lastModified": 1792098797,
|
||||
"narHash": "sha256-u4DIIZgznEGzByxXrxWCXK19VcMtTBmi/M9gZ7Jk9bM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "7b4c5ec4bedaf1e062bbc1bcaeddbc6bd242aa1b",
|
||||
"rev": "640725978b99076e18e069f6e7d2959124584f8f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -204,11 +198,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790215976,
|
||||
"narHash": "sha256-VkR1rMGyjU9jtw8ISFx5uqR9e+LEaOlhHwrseFkiIVk=",
|
||||
"lastModified": 1790996401,
|
||||
"narHash": "sha256-f+kOxEmOUnQazVAmGg0i8hzwgd1kX/geY+k/Dpheye8=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "a6631107a83ceab5872f298a2ea710859c80c4cb",
|
||||
"rev": "db7d5e2332710f5abb088f6b5de927d7f9511b35",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -226,11 +220,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1789430117,
|
||||
"narHash": "sha256-t+U1mijItLJ64xZOifpfQ17kpAL73nU7pDI48ScacVc=",
|
||||
"lastModified": 1792098797,
|
||||
"narHash": "sha256-u4DIIZgznEGzByxXrxWCXK19VcMtTBmi/M9gZ7Jk9bM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "cda90fd8838825c689fde9d3f3b4e937937790df",
|
||||
"rev": "640725978b99076e18e069f6e7d2959124584f8f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -319,11 +313,11 @@
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1789478421,
|
||||
"narHash": "sha256-38OKZCaTtcvj3LIicEy/1lbxEKS0ZL7wCkJxzxClQw0=",
|
||||
"lastModified": 1792056812,
|
||||
"narHash": "sha256-3FHVsncGsfcxozcQgHULGkQ6TqXOlguxX6YlBQhQrT8=",
|
||||
"owner": "thiagokokada",
|
||||
"repo": "nix-alien",
|
||||
"rev": "0cca578c63e9055d2514e456d78d6f42bdd1eca2",
|
||||
"rev": "07c41bfdc3b986b7e65e19380b28916e10112c0f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -383,11 +377,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1789286446,
|
||||
"narHash": "sha256-xVstyCdg0DpzjyrEacm72VJAIP9DMhfWJdPDzhWxHuo=",
|
||||
"lastModified": 1791711434,
|
||||
"narHash": "sha256-LpIhxnuO0tYeZ4k7BbNMxsPs2zJpB4hWXO1jdhUuE7Q=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-index-database",
|
||||
"rev": "a74e173407559083a412ea89a1cc58ea389c3b65",
|
||||
"rev": "9a2dd40780eeab8543aa97c59c26f11267025616",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -404,15 +398,15 @@
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-ci": "nixpkgs-ci",
|
||||
"nixpkgs-nixcord": "nixpkgs-nixcord",
|
||||
"nixpkgs-packages": "nixpkgs-packages",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790530226,
|
||||
"narHash": "sha256-V9q2ADcBLo16KW/HK90Qfu2KoEEAZJ1IFSjUd+jWJ9I=",
|
||||
"lastModified": 1792277718,
|
||||
"narHash": "sha256-Nv32eZ+x7qr/yKofkemv1O2ImnXkUpFQgq71u6c6Wi8=",
|
||||
"owner": "FlameFlag",
|
||||
"repo": "nixcord",
|
||||
"rev": "163de914ce8542c1061ad392bccbb750a7b0077f",
|
||||
"rev": "f4f803048d4bb6bc296fc4bdbd8620ff63fe100f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -423,11 +417,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1789286504,
|
||||
"narHash": "sha256-eiEK7cKZORNEvX0GeF3RtNEF/JXhgf2RqSp3230q13E=",
|
||||
"lastModified": 1791956154,
|
||||
"narHash": "sha256-jBYGPi4udQ9uo4KQp9m2J0546nJVQitG15gvZSaVVAs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ef34387ddd751e1ab8857adf4676492d32eb24ec",
|
||||
"rev": "55bfb4d7437bd4e09ab7cba58a43bd68eb310044",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -439,18 +433,15 @@
|
||||
},
|
||||
"nixpkgs-ci": {
|
||||
"locked": {
|
||||
"lastModified": 1790390834,
|
||||
"narHash": "sha256-StRyS/lFHtIw/UgJk+xo+HA66mtoWeDUbkJdvf2Byn4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d54020a6ac3211e9f4201631bdf67678818c0cdf",
|
||||
"type": "github"
|
||||
"lastModified": 1791130267,
|
||||
"narHash": "sha256-NCFqY2YC3/5pwakzk7tXNUj3sG+VImjU4EkZMacxF1w=",
|
||||
"rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
|
||||
"type": "tarball",
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1085518.9013764fcc0e/nixexprs.tar.zst"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
"type": "tarball",
|
||||
"url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.zst"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
@@ -468,20 +459,17 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-nixcord": {
|
||||
"nixpkgs-packages": {
|
||||
"locked": {
|
||||
"lastModified": 1790340521,
|
||||
"narHash": "sha256-cRrWlIjVRJ6BHDr9caUdXsZ3owzWIKYHpNmGPHBInIU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f5c082a40f7571c266e74e80ae2e68aadd8a9fc7",
|
||||
"type": "github"
|
||||
"lastModified": 1791130267,
|
||||
"narHash": "sha256-NCFqY2YC3/5pwakzk7tXNUj3sG+VImjU4EkZMacxF1w=",
|
||||
"rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
|
||||
"type": "tarball",
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1085518.9013764fcc0e/nixexprs.tar.zst"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-26.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
"type": "tarball",
|
||||
"url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.zst"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
@@ -502,11 +490,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1790463110,
|
||||
"narHash": "sha256-hKlVl12B1dF0Q5vd9dY3lIJM5mFGWYSlXwSLAqHZ1+s=",
|
||||
"lastModified": 1792094642,
|
||||
"narHash": "sha256-zp8ToDMnqZcu4o4IH9pdwXFXGp7yLm/M0dEnNWnyd7I=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e158d9ed9b51c98974c5e66e1ba1c9e0255fecaa",
|
||||
"rev": "fe13242281a67641c0102cdb1087f0ebe586c7df",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -518,11 +506,11 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1790323409,
|
||||
"narHash": "sha256-m4DGo58Fza5ImOegtWOeE18nhpSO1IGzsVA6Lpsb4zw=",
|
||||
"rev": "e94cb152ed51bd6e24eb4a41f1460252beb52cd2",
|
||||
"lastModified": 1791594108,
|
||||
"narHash": "sha256-V0WmebqwEeAVZMqxfv7Dq7hpKkPPM19W50xQf3D1Kf4=",
|
||||
"rev": "6510408d147d8c5e6d76043e899e9251756f6a75",
|
||||
"type": "tarball",
|
||||
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1079315.e94cb152ed51/nixexprs.tar.zst"
|
||||
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1089111.6510408d147d/nixexprs.tar.zst"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
@@ -566,11 +554,11 @@
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790523212,
|
||||
"narHash": "sha256-Z8SuI0YgAZaF0sumKPBF85PxPtTjpo8jvtphbgoITv8=",
|
||||
"lastModified": 1792243036,
|
||||
"narHash": "sha256-DUNMQn8Wc1U4SMs+I+WymAdccBu89qoeUeU5M+2JtNE=",
|
||||
"owner": "noctalia-dev",
|
||||
"repo": "noctalia-shell",
|
||||
"rev": "08c30392b1350b4f3d3fb77e23732560559f1638",
|
||||
"rev": "3982122906f2409aeaff17399552153c4c323f20",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -714,11 +702,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1786901030,
|
||||
"narHash": "sha256-WSFCsDSE5ffgD2MqzkM2CYjeFiKhRF/dJUN8uedb6YE=",
|
||||
"lastModified": 1791198660,
|
||||
"narHash": "sha256-f8Pye933T60vreB9u9pqfAXDyBqO13U7H0LvPsOxCIA=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "27b3b12a8e6375f28ebe122f07d230ca5459bbfa",
|
||||
"rev": "8b367b728be38d1bb7206f037c9df9989df3353a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -737,11 +725,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1791550319,
|
||||
"narHash": "sha256-GDO12cDMXhyQycIoyuznQFFO0wzarnxRlzJryA120jU=",
|
||||
"lastModified": 1791550730,
|
||||
"narHash": "sha256-1qLR/JvDZw4QDNHbkvA59tvoN039fgkNWYyPbGNI/LY=",
|
||||
"owner": "elwrcl",
|
||||
"repo": "valw",
|
||||
"rev": "e320f7a1b6d2e2f3dafd096af8668c99ac488be2",
|
||||
"rev": "2edc8c18ccc53d308dc80889126564775f154268",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -791,11 +779,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1790402100,
|
||||
"narHash": "sha256-f/tmhFat/UHra627JbVg6calQ3/ZkEydQZJR71BBX0M=",
|
||||
"lastModified": 1792271801,
|
||||
"narHash": "sha256-LYN8miMEew9CxgRrF/RCnAyOe6476dQM/JzELnFQef0=",
|
||||
"owner": "0xc000022070",
|
||||
"repo": "zen-browser-flake",
|
||||
"rev": "b851b56b787a61b900751aca2f17e4a5ca6c394a",
|
||||
"rev": "e1b9b3578ebb388b56012cd9ddd80e19681d2d39",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -89,6 +89,10 @@ in
|
||||
config.flake.homeModules.home-file-manager
|
||||
config.flake.homeModules.home-file-manager-actions
|
||||
config.flake.homeModules.home-gdrive-rclone
|
||||
config.flake.homeModules.home-keepassxc
|
||||
config.flake.homeModules.home-keepassxc-helium
|
||||
config.flake.homeModules.home-keepassxc-autostart
|
||||
config.flake.homeModules.home-keepassxc-mutable-config
|
||||
config.flake.homeModules.home-easyeffects
|
||||
config.flake.homeModules.home-nyi
|
||||
config.flake.homeModules.home-valw
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{ ... }:
|
||||
{
|
||||
flake.homeModules.home-keepassxc-autostart =
|
||||
{ config, ... }:
|
||||
{
|
||||
programs.keepassxc.settings.GUI = {
|
||||
ShowTrayIcon = true;
|
||||
MinimizeToTray = true;
|
||||
MinimizeOnClose = true;
|
||||
};
|
||||
|
||||
systemd.user.services.keepassxc = {
|
||||
Unit = {
|
||||
Description = "KeePassXC";
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
After = [
|
||||
"graphical-session.target"
|
||||
"rclone-gdrive.service"
|
||||
];
|
||||
Wants = [ "rclone-gdrive.service" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = "${config.programs.keepassxc.package}/bin/keepassxc --minimized";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
Install.WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{ ... }:
|
||||
{
|
||||
flake.homeModules.home-keepassxc-helium =
|
||||
{ config, ... }:
|
||||
{
|
||||
xdg.configFile."net.imput.helium/NativeMessagingHosts/org.keepassxc.keepassxc_browser.json".source =
|
||||
"${config.programs.keepassxc.package}/etc/chromium/native-messaging-hosts/org.keepassxc.keepassxc_browser.json";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{ ... }:
|
||||
{
|
||||
flake.homeModules.home-keepassxc-mutable-config =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.programs.keepassxc;
|
||||
ini = "${config.xdg.configHome}/keepassxc/keepassxc.ini";
|
||||
declared = (pkgs.formats.ini { }).generate "keepassxc-declared.ini" cfg.settings;
|
||||
in
|
||||
{
|
||||
xdg.configFile."keepassxc/keepassxc.ini".enable = lib.mkForce false;
|
||||
|
||||
home.activation.keepassxcConfig = lib.hm.dag.entryAfter [ "linkGeneration" ] ''
|
||||
if [ -L ${ini} ]; then
|
||||
run rm ${ini}
|
||||
fi
|
||||
run mkdir -p ${config.xdg.configHome}/keepassxc
|
||||
run touch ${ini}
|
||||
run ${pkgs.crudini}/bin/crudini --merge ${ini} < ${declared}
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{ ... }:
|
||||
{
|
||||
flake.homeModules.home-keepassxc =
|
||||
{ ... }:
|
||||
{
|
||||
programs.keepassxc = {
|
||||
enable = true;
|
||||
settings = {
|
||||
Browser = {
|
||||
Enabled = true;
|
||||
UpdateBinaryPath = false;
|
||||
};
|
||||
Security = {
|
||||
LockDatabaseIdle = true;
|
||||
LockDatabaseIdleSeconds = 900;
|
||||
ClearClipboardTimeout = 20;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -4,16 +4,6 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
programs.niri.enable = true;
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
xwayland-satellite = prev.xwayland-satellite.overrideAttrs (old: {
|
||||
patches =
|
||||
(old.patches or [ ])
|
||||
++ prev.lib.optional (prev.lib.versionOlder old.version "0.8.3") ./xwayland-satellite-no-focus-override-redirect.patch
|
||||
++ prev.lib.optional (prev.lib.versionOlder old.version "0.8.4") ./xwayland-satellite-resizable-dialog-toplevel.patch;
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
xwayland-satellite
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
diff --git a/src/lib.rs b/src/lib.rs
|
||||
index 5c861ea0..d3bf003a 100644
|
||||
--- a/src/lib.rs
|
||||
+++ b/src/lib.rs
|
||||
@@ -20,6 +20,7 @@ pub trait XConnection: Sized + 'static {
|
||||
fn set_window_dims(&mut self, window: x::Window, dims: PendingSurfaceState) -> bool;
|
||||
fn set_fullscreen(&mut self, window: x::Window, fullscreen: bool);
|
||||
fn focus_window(&mut self, window: x::Window, output_name: Option<String>);
|
||||
+ fn send_take_focus(&mut self, window: x::Window);
|
||||
fn close_window(&mut self, window: x::Window);
|
||||
fn unmap_window(&mut self, window: x::Window);
|
||||
fn raise_to_top(&mut self, window: x::Window);
|
||||
diff --git a/src/server/event.rs b/src/server/event.rs
|
||||
index c75b9f19..4fcf9230 100644
|
||||
--- a/src/server/event.rs
|
||||
+++ b/src/server/event.rs
|
||||
@@ -438,6 +438,7 @@ impl SurfaceEvents {
|
||||
window,
|
||||
output_name: None,
|
||||
is_popup: true,
|
||||
+ has_take_focus: window_data.attrs.has_take_focus,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -864,10 +865,13 @@ impl Event for client::wl_keyboard::Event {
|
||||
serial,
|
||||
));
|
||||
let output_name = get_output_name(output, &state.world);
|
||||
+ let window_data = data.get::<&WindowData>();
|
||||
+ let has_take_focus = window_data.as_ref().is_some_and(|d| d.attrs.has_take_focus);
|
||||
state.to_focus = Some(FocusData {
|
||||
window: *window,
|
||||
output_name,
|
||||
is_popup: false,
|
||||
+ has_take_focus,
|
||||
});
|
||||
keyboard.enter(serial, surface, keys);
|
||||
}
|
||||
diff --git a/src/server/mod.rs b/src/server/mod.rs
|
||||
index 379df771..a436331b 100644
|
||||
--- a/src/server/mod.rs
|
||||
+++ b/src/server/mod.rs
|
||||
@@ -101,9 +101,10 @@ where
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct WindowAttributes {
|
||||
- acquire_input_via_wm: bool,
|
||||
+ accepts_input: bool,
|
||||
has_take_focus: bool,
|
||||
role: WindowRole,
|
||||
+ override_redirect: bool,
|
||||
dims: WindowDims,
|
||||
size_hints: Option<WmNormalHints>,
|
||||
title: Option<WmName>,
|
||||
@@ -114,9 +115,8 @@ struct WindowAttributes {
|
||||
}
|
||||
|
||||
impl WindowAttributes {
|
||||
- /// AKA "Passive" input model
|
||||
fn require_wm_focus(&self) -> bool {
|
||||
- self.acquire_input_via_wm && !self.has_take_focus
|
||||
+ !self.override_redirect && (self.has_take_focus || self.accepts_input)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,7 @@ impl WindowData {
|
||||
mapped: false,
|
||||
attrs: WindowAttributes {
|
||||
role: WindowRole::new_basic(override_redirect),
|
||||
+ override_redirect,
|
||||
dims,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -398,6 +399,7 @@ struct FocusData {
|
||||
window: x::Window,
|
||||
output_name: Option<String>,
|
||||
is_popup: bool,
|
||||
+ has_take_focus: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
@@ -422,6 +424,9 @@ impl<S: X11Selection> XConnection for NoConnection<S> {
|
||||
fn focus_window(&mut self, _: x::Window, _: Option<String>) {
|
||||
debug!("could not focus window without XWayland initialized");
|
||||
}
|
||||
+ fn send_take_focus(&mut self, _: x::Window) {
|
||||
+ debug!("could not send take focus without XWayland initialized");
|
||||
+ }
|
||||
fn close_window(&mut self, _: x::Window) {
|
||||
debug!("could not close window without XWayland initialized");
|
||||
}
|
||||
@@ -742,15 +747,20 @@ impl<C: XConnection> ServerState<C> {
|
||||
window,
|
||||
output_name,
|
||||
is_popup,
|
||||
+ has_take_focus,
|
||||
}) = self.to_focus.take()
|
||||
{
|
||||
debug!(
|
||||
- "focusing {} {window:?}",
|
||||
+ "focusing (take_focus={has_take_focus:?}) {} {window:?}",
|
||||
if is_popup { "popup" } else { "window" }
|
||||
);
|
||||
- self.connection.focus_window(window, output_name);
|
||||
- if !is_popup {
|
||||
- self.last_focused_toplevel = Some(window);
|
||||
+ if has_take_focus {
|
||||
+ self.connection.send_take_focus(window);
|
||||
+ } else {
|
||||
+ self.connection.focus_window(window, output_name);
|
||||
+ if !is_popup {
|
||||
+ self.last_focused_toplevel = Some(window);
|
||||
+ }
|
||||
}
|
||||
} else if self.unfocus {
|
||||
self.connection.focus_window(x::WINDOW_NONE, None);
|
||||
@@ -888,9 +898,24 @@ impl<S: X11Selection + 'static> InnerServerState<S> {
|
||||
self.windows.insert(window, id);
|
||||
}
|
||||
|
||||
+ pub fn set_override_redirect(&mut self, window: x::Window, override_redirect: bool) {
|
||||
+ let Some(id) = self.windows.get(&window).copied() else {
|
||||
+ debug!(
|
||||
+ "not setting override_redirect {override_redirect} for unknown window {window:?}"
|
||||
+ );
|
||||
+ return;
|
||||
+ };
|
||||
+
|
||||
+ self.world
|
||||
+ .get::<&mut WindowData>(id)
|
||||
+ .unwrap()
|
||||
+ .attrs
|
||||
+ .override_redirect = override_redirect;
|
||||
+ }
|
||||
+
|
||||
pub fn set_window_role(&mut self, window: x::Window, role: WindowRole) {
|
||||
let Some(id) = self.windows.get(&window).copied() else {
|
||||
- debug!("not setting popup for unknown window {window:?}");
|
||||
+ debug!("not setting role {role:?} for unknown window {window:?}");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -969,7 +994,7 @@ impl<S: X11Selection + 'static> InnerServerState<S> {
|
||||
|
||||
let attrs = &mut self.world.get::<&mut WindowData>(id).unwrap().attrs;
|
||||
attrs.group = hints.window_group;
|
||||
- attrs.acquire_input_via_wm = hints.acquire_input_via_wm;
|
||||
+ attrs.accepts_input = hints.accepts_input;
|
||||
}
|
||||
|
||||
pub fn set_take_focus(&mut self, window: x::Window, has_take_focus: bool) {
|
||||
diff --git a/src/server/tests.rs b/src/server/tests.rs
|
||||
index 0651bb2a..4e1735ee 100644
|
||||
--- a/src/server/tests.rs
|
||||
+++ b/src/server/tests.rs
|
||||
@@ -160,6 +160,7 @@ struct WindowData {
|
||||
#[derive(Default)]
|
||||
struct FakeXConnection {
|
||||
focused_window: Option<Window>,
|
||||
+ send_take_focus_window: Option<Window>,
|
||||
windows: HashMap<Window, WindowData>,
|
||||
set_window_dims_counter: usize,
|
||||
}
|
||||
@@ -234,6 +235,15 @@ impl super::XConnection for FakeXConnection {
|
||||
self.focused_window = window.into();
|
||||
}
|
||||
|
||||
+ #[track_caller]
|
||||
+ fn send_take_focus(&mut self, window: x::Window) {
|
||||
+ assert!(
|
||||
+ self.windows.contains_key(&window),
|
||||
+ "Unknown window: {window:?}"
|
||||
+ );
|
||||
+ self.send_take_focus_window = window.into();
|
||||
+ }
|
||||
+
|
||||
fn raise_to_top(&mut self, window: Window) {
|
||||
assert!(
|
||||
self.windows.contains_key(&window),
|
||||
@@ -858,6 +868,55 @@ impl TestFixture<FakeXConnection> {
|
||||
(surface, popup_id)
|
||||
}
|
||||
|
||||
+ #[track_caller]
|
||||
+ fn setup_popup_focus_case(
|
||||
+ &mut self,
|
||||
+ comp: &Compositor,
|
||||
+ override_redirect: bool,
|
||||
+ accepts_input: bool,
|
||||
+ take_focus: bool,
|
||||
+ ) -> (Window, Window) {
|
||||
+ let win_toplevel = Window::new(1);
|
||||
+ self.create_toplevel(comp, win_toplevel);
|
||||
+
|
||||
+ let win_popup = Window::new(2);
|
||||
+ let (buffer, surface) = comp.create_surface();
|
||||
+ let data = WindowData {
|
||||
+ mapped: true,
|
||||
+ dims: WindowDims {
|
||||
+ x: 10,
|
||||
+ y: 20,
|
||||
+ width: 100,
|
||||
+ height: 50,
|
||||
+ },
|
||||
+ fullscreen: false,
|
||||
+ };
|
||||
+ self.new_window(win_popup, override_redirect, data);
|
||||
+ if !override_redirect {
|
||||
+ self.satellite
|
||||
+ .set_window_role(win_popup, crate::xstate::WindowRole::Popup);
|
||||
+ }
|
||||
+
|
||||
+ self.satellite.set_win_hints(
|
||||
+ win_popup,
|
||||
+ super::WmHints {
|
||||
+ window_group: None,
|
||||
+ accepts_input,
|
||||
+ },
|
||||
+ );
|
||||
+ if take_focus {
|
||||
+ self.satellite.set_take_focus(win_popup, true);
|
||||
+ }
|
||||
+ self.map_window(comp, win_popup, &surface.obj, &buffer);
|
||||
+ self.run();
|
||||
+
|
||||
+ let popup_id = self.check_new_surface();
|
||||
+ self.testwl.configure_popup(popup_id);
|
||||
+ self.run();
|
||||
+
|
||||
+ (win_toplevel, win_popup)
|
||||
+ }
|
||||
+
|
||||
#[track_caller]
|
||||
fn assert_window_dimensions(
|
||||
&self,
|
||||
@@ -1342,7 +1401,7 @@ fn window_group_properties() {
|
||||
win,
|
||||
super::WmHints {
|
||||
window_group: Some(prop_win),
|
||||
- acquire_input_via_wm: false,
|
||||
+ accepts_input: false,
|
||||
},
|
||||
);
|
||||
f.satellite.map_window(win);
|
||||
@@ -1647,103 +1706,51 @@ fn override_redirect_choose_hover_window() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
-fn popup_no_focus_without_input_hint() {
|
||||
- let (mut f, comp) = TestFixture::new_with_compositor();
|
||||
+fn popup_override_redirect_never_focused_nor_offered() {
|
||||
+ for accepts_input in [true, false] {
|
||||
+ for take_focus in [false, true] {
|
||||
+ let (mut f, comp) = TestFixture::new_with_compositor();
|
||||
+
|
||||
+ let (win_toplevel, _) =
|
||||
+ f.setup_popup_focus_case(&comp, true, accepts_input, take_focus);
|
||||
+ assert_eq!(
|
||||
+ f.connection().focused_window,
|
||||
+ Some(win_toplevel),
|
||||
+ "accepts_input={accepts_input:?} take_focus={take_focus}"
|
||||
+ );
|
||||
+ assert_eq!(
|
||||
+ f.connection().send_take_focus_window,
|
||||
+ None,
|
||||
+ "accepts_input={accepts_input:?} take_focus={take_focus}"
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
|
||||
- let win_toplevel = Window::new(1);
|
||||
- let (_, toplevel_id) = f.create_toplevel(&comp, win_toplevel);
|
||||
+#[test]
|
||||
+fn popup_send_take_focus_when_advertised() {
|
||||
+ for accepts_input in [true, false] {
|
||||
+ let (mut f, comp) = TestFixture::new_with_compositor();
|
||||
|
||||
- // A popup without acquire_input_via_wm should not receive focus.
|
||||
- let win_popup = Window::new(2);
|
||||
- f.create_popup(
|
||||
- &comp,
|
||||
- PopupBuilder::new(win_popup, win_toplevel, toplevel_id),
|
||||
- );
|
||||
- assert_eq!(f.connection().focused_window, Some(win_toplevel));
|
||||
+ let (win_toplevel, win_popup) = f.setup_popup_focus_case(&comp, false, accepts_input, true);
|
||||
+ assert_eq!(f.connection().focused_window, Some(win_toplevel));
|
||||
+ assert_eq!(f.connection().send_take_focus_window, Some(win_popup));
|
||||
+ }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn popup_focus_on_map_with_input_hint() {
|
||||
let (mut f, comp) = TestFixture::new_with_compositor();
|
||||
|
||||
- let win_toplevel = Window::new(1);
|
||||
- let (_, toplevel_id) = f.create_toplevel(&comp, win_toplevel);
|
||||
-
|
||||
- // A popup with acquire_input_via_wm should receive X11 keyboard focus
|
||||
- // at map time, matching what a real X11 WM does for windows with
|
||||
- // WM_HINTS input=True.
|
||||
- let win_popup = Window::new(2);
|
||||
- let (buffer, surface) = comp.create_surface();
|
||||
- let dims = WindowDims {
|
||||
- x: 10,
|
||||
- y: 20,
|
||||
- width: 100,
|
||||
- height: 50,
|
||||
- };
|
||||
- let data = WindowData {
|
||||
- mapped: true,
|
||||
- dims,
|
||||
- fullscreen: false,
|
||||
- };
|
||||
- f.new_window(win_popup, true, data);
|
||||
- f.satellite.set_win_hints(
|
||||
- win_popup,
|
||||
- super::WmHints {
|
||||
- window_group: None,
|
||||
- acquire_input_via_wm: true,
|
||||
- },
|
||||
- );
|
||||
- f.map_window(&comp, win_popup, &surface.obj, &buffer);
|
||||
- f.run();
|
||||
-
|
||||
- let popup_id = f.check_new_surface();
|
||||
- assert_ne!(popup_id, toplevel_id);
|
||||
-
|
||||
- f.testwl.configure_popup(popup_id);
|
||||
- f.run();
|
||||
-
|
||||
- // Focus should have been given directly to the popup at map time.
|
||||
+ let (_, win_popup) = f.setup_popup_focus_case(&comp, false, true, false);
|
||||
assert_eq!(f.connection().focused_window, Some(win_popup));
|
||||
}
|
||||
|
||||
#[test]
|
||||
-fn popup_no_focus_input_hint_wm_take_focus() {
|
||||
+fn popup_no_focus_without_input_hint() {
|
||||
let (mut f, comp) = TestFixture::new_with_compositor();
|
||||
|
||||
- let win_toplevel = Window::new(1);
|
||||
- let (_, toplevel_id) = f.create_toplevel(&comp, win_toplevel);
|
||||
-
|
||||
- let win_popup = Window::new(2);
|
||||
- let (buffer, surface) = comp.create_surface();
|
||||
- let dims = WindowDims {
|
||||
- x: 10,
|
||||
- y: 20,
|
||||
- width: 100,
|
||||
- height: 50,
|
||||
- };
|
||||
- let data = WindowData {
|
||||
- mapped: true,
|
||||
- dims,
|
||||
- fullscreen: false,
|
||||
- };
|
||||
- f.new_window(win_popup, true, data);
|
||||
- f.satellite.set_win_hints(
|
||||
- win_popup,
|
||||
- super::WmHints {
|
||||
- window_group: None,
|
||||
- acquire_input_via_wm: true,
|
||||
- },
|
||||
- );
|
||||
- f.satellite.set_take_focus(win_popup, true);
|
||||
- f.map_window(&comp, win_popup, &surface.obj, &buffer);
|
||||
- f.run();
|
||||
-
|
||||
- let popup_id = f.check_new_surface();
|
||||
- assert_ne!(popup_id, toplevel_id);
|
||||
-
|
||||
- f.testwl.configure_popup(popup_id);
|
||||
- f.run();
|
||||
-
|
||||
+ let (win_toplevel, _) = f.setup_popup_focus_case(&comp, false, false, false);
|
||||
assert_eq!(f.connection().focused_window, Some(win_toplevel));
|
||||
}
|
||||
|
||||
diff --git a/src/xstate/mod.rs b/src/xstate/mod.rs
|
||||
index efcb13de..7a7e02d2 100644
|
||||
--- a/src/xstate/mod.rs
|
||||
+++ b/src/xstate/mod.rs
|
||||
@@ -653,6 +653,7 @@ impl XState {
|
||||
|
||||
let transient_for = self.get_transient_for(window)?;
|
||||
let override_redirect = self.get_override_redirect(window)?;
|
||||
+ server_state.set_override_redirect(window, override_redirect);
|
||||
|
||||
let window_types = self
|
||||
.get_net_wm_window_types(window)?
|
||||
@@ -1010,7 +1011,7 @@ impl From<&[u32]> for WmNormalHints {
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
|
||||
pub struct WmHints {
|
||||
pub window_group: Option<x::Window>,
|
||||
- pub acquire_input_via_wm: bool,
|
||||
+ pub accepts_input: bool,
|
||||
}
|
||||
|
||||
impl From<&[u32]> for WmHints {
|
||||
@@ -1022,8 +1023,11 @@ impl From<&[u32]> for WmHints {
|
||||
let window = x::Window::new(value[8]);
|
||||
ret.window_group = Some(window);
|
||||
}
|
||||
- if flags.contains(WmHintsFlags::Input) {
|
||||
- ret.acquire_input_via_wm = value[1] == 1;
|
||||
+
|
||||
+ // if input hint isn't present, set it to true anyways in case the client is misbehaving
|
||||
+ ret.accepts_input = true;
|
||||
+ if flags.contains(WmHintsFlags::Input) && value[1] == 0 {
|
||||
+ ret.accepts_input = false;
|
||||
}
|
||||
|
||||
ret
|
||||
@@ -1429,6 +1433,22 @@ impl XConnection for RealConnection {
|
||||
}
|
||||
}
|
||||
|
||||
+ fn send_take_focus(&mut self, window: x::Window) {
|
||||
+ let resource_id = self.atoms.wm_take_focus.resource_id();
|
||||
+ let data = [resource_id, x::CURRENT_TIME, 0, 0, 0];
|
||||
+ let event = &x::ClientMessageEvent::new(
|
||||
+ window,
|
||||
+ self.atoms.wm_protocols,
|
||||
+ x::ClientMessageData::Data32(data),
|
||||
+ );
|
||||
+ unwrap_or_skip_bad_window_ret!(self.connection.send_and_check_request(&x::SendEvent {
|
||||
+ destination: x::SendEventDest::Window(window),
|
||||
+ propagate: false,
|
||||
+ event_mask: x::EventMask::empty(),
|
||||
+ event,
|
||||
+ }));
|
||||
+ }
|
||||
+
|
||||
fn close_window(&mut self, window: x::Window) {
|
||||
let cookie = self.connection.send_request(&x::GetProperty {
|
||||
window,
|
||||
@@ -1,49 +0,0 @@
|
||||
--- a/src/xstate/mod.rs 2026-10-10 02:55:59.663368893 +0300
|
||||
+++ b/src/xstate/mod.rs 2026-10-10 02:55:59.699369500 +0300
|
||||
@@ -1189,7 +1189,9 @@
|
||||
match ty {
|
||||
x if x == window_atoms.normal => return WindowRole::Toplevel,
|
||||
x if x == window_atoms.dialog => {
|
||||
- return WindowRole::new_basic(self.has_transient_for && motif_no_decor);
|
||||
+ return WindowRole::new_basic(
|
||||
+ self.has_transient_for && motif_no_decor && forced_size,
|
||||
+ );
|
||||
}
|
||||
x if x == window_atoms.utility => {
|
||||
return WindowRole::new_basic(motif_no_decor && forced_size);
|
||||
--- a/src/xstate/tests.rs 2026-10-10 02:55:59.665368927 +0300
|
||||
+++ b/src/xstate/tests.rs 2026-10-10 02:56:08.382515889 +0300
|
||||
@@ -473,6 +473,33 @@
|
||||
assert_eq!(win.guess_window_role(&win_types), WindowRole::Popup);
|
||||
}
|
||||
|
||||
+ // https://github.com/Supreeeme/xwayland-satellite/issues/470
|
||||
+ // A DIALOG with TRANSIENT_FOR and no Motif decorations which is resizable
|
||||
+ // (min_size != max_size) should be a top-level, mirroring the UTILITY fix in #383.
|
||||
+ // Otherwise the popup parent resolves to a hidden WM_CLIENT_LEADER and the
|
||||
+ // window never appears (e.g. DaVinci Resolve's Project Manager).
|
||||
+ // Window attributes are taken from the full xprop posted in #470 (DIALOG +
|
||||
+ // NORMAL window types, _MOTIF_WM_HINTS decorations=0, resizable normal hints).
|
||||
+ #[test]
|
||||
+ fn davinci_resolve_project_manager() {
|
||||
+ let win_types = WindowTypes::new();
|
||||
+ let wm_normal_hints = WmNormalHints::new()
|
||||
+ .user_pos(978, 270)
|
||||
+ .user_size(1884, 1620)
|
||||
+ .min_size(910, 640)
|
||||
+ .max_size(2880, 1620)
|
||||
+ .win_gravity(Gravity::Static);
|
||||
+ let win = WindowRoleHeuristics {
|
||||
+ has_transient_for: true,
|
||||
+ motif_wm_hints: Some(motif::Hints::from([0x2_u32, 0x1, 0, 0, 0].as_slice())),
|
||||
+ window_types: vec![win_types.dialog, win_types.normal],
|
||||
+ wm_normal_hints: Some(wm_normal_hints.into()),
|
||||
+ wm_class: Some("resolve".into()),
|
||||
+ ..Default::default()
|
||||
+ };
|
||||
+ assert_eq!(win.guess_window_role(&win_types), WindowRole::Toplevel);
|
||||
+ }
|
||||
+
|
||||
// https://github.com/Supreeeme/xwayland-satellite/pull/390
|
||||
// With Motif decorations, even a dialog with TRANSIENT_FOR is better treated as a top-level
|
||||
#[test]
|
||||
Reference in new issue
Block a user