mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ffe25f5cc4 | |||
| 43e2cf14d2 | |||
| 2c59131f7f | |||
| 64c41fa2c8 | |||
| 4e0aa39113 | |||
| dcb80efc88 | |||
| 3d5de921cd | |||
| 8703feedee | |||
| a27d22571d | |||
| d10af92aea | |||
| 0bc83eda71 | |||
| 6fce5662e7 | |||
| 1c7c5b3f28 | |||
| b9d7812f1f | |||
| 655b9808b9 | |||
| 5cd31e5730 | |||
| de3fc2def0 | |||
| fd1d4b07fd | |||
| 8b5acd5e6e | |||
| 31bb9096e2 | |||
| dae93ee159 | |||
| 57a7347620 | |||
| 628891db2c | |||
| be6e25f5fb | |||
| e005a795e7 | |||
| 655fe413fb | |||
| ac6ff7ff41 | |||
| 84befb4e91 | |||
| d39f7bebf3 | |||
| 0dd9a42087 | |||
| 658941f2c3 | |||
| 6ccc4147ae | |||
| 46d5f5ec4d | |||
| c64e96d0d8 | |||
| 44d3a5b9a2 | |||
| 5d95de97a0 | |||
| 56174b2c34 | |||
| 310aa2b464 | |||
| d6c553091f | |||
| 097c415036 | |||
| 2d16c04869 | |||
| 249f2b7a21 | |||
| f3e5e13c45 | |||
| b13892ca63 | |||
| 777ad4ee5c | |||
| c21805bf70 | |||
| bfc2418267 | |||
| 77b4715e0b | |||
| c048abc8b5 | |||
| 4dd7578fe7 | |||
| ea72e4dae8 | |||
| 0c671ee493 | |||
| 324c1efd04 | |||
| 99e75b95b7 | |||
| 489a225fae | |||
| 85cb4b42f6 | |||
| be2e551a89 | |||
| ed3080d908 | |||
| 461ce5f363 | |||
| 624c799ebf |
Generated
+164
-178
@@ -10,9 +10,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
@@ -38,9 +38,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android-activity"
|
name = "android-activity"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "052ad56e336bcc615a214bffbeca6c181ee9550acec193f0327e0b103b033a4d"
|
checksum = "39b801912a977c3fd52d80511fe1c0c8480c6f957f21ae2ce1b92ffe970cf4b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-properties",
|
"android-properties",
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
@@ -113,9 +113,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.75"
|
version = "1.0.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "appendlist"
|
name = "appendlist"
|
||||||
@@ -161,7 +161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
|
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"event-listener 4.0.1",
|
"event-listener 4.0.3",
|
||||||
"event-listener-strategy",
|
"event-listener-strategy",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -177,7 +177,7 @@ dependencies = [
|
|||||||
"async-task",
|
"async-task",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"futures-lite 2.1.0",
|
"futures-lite 2.2.0",
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 2.1.0",
|
"futures-lite 2.2.0",
|
||||||
"parking",
|
"parking",
|
||||||
"polling 3.3.1",
|
"polling 3.3.1",
|
||||||
"rustix 0.38.28",
|
"rustix 0.38.28",
|
||||||
@@ -247,7 +247,7 @@ version = "3.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c"
|
checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener 4.0.1",
|
"event-listener 4.0.3",
|
||||||
"event-listener-strategy",
|
"event-listener-strategy",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
@@ -277,7 +277,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -300,19 +300,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-task"
|
name = "async-task"
|
||||||
version = "4.6.0"
|
version = "4.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1d90cd0b264dfdd8eb5bad0a2c217c1f88fa96a8573f40e7b12de23fb468f46"
|
checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.74"
|
version = "0.1.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
|
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -350,7 +350,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"shlex",
|
"shlex",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -397,9 +397,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-sys"
|
name = "block-sys"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dd7cf50912cddc06dc5ea7c08c5e81c1b2c842a70d19def1848d54c586fed92"
|
checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc-sys",
|
"objc-sys",
|
||||||
]
|
]
|
||||||
@@ -425,7 +425,7 @@ dependencies = [
|
|||||||
"async-task",
|
"async-task",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 2.1.0",
|
"futures-lite 2.2.0",
|
||||||
"piper",
|
"piper",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -453,7 +453,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -521,9 +521,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-expr"
|
name = "cfg-expr"
|
||||||
version = "0.15.5"
|
version = "0.15.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3"
|
checksum = "6100bc57b6209840798d95cb2775684849d332f7bd788db2a8c8caf7ef82a41a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
@@ -562,20 +562,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.6.1"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
|
checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.7.4",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.4.11"
|
version = "4.4.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
|
checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -583,9 +583,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.4.11"
|
version = "4.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
|
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -602,7 +602,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -693,9 +693,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.11"
|
version = "0.2.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -711,9 +711,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.17"
|
version = "0.8.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
|
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
@@ -736,9 +736,9 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.10"
|
version = "0.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc"
|
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
@@ -818,7 +818,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.8.1",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -829,9 +829,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "drm"
|
name = "drm"
|
||||||
version = "0.11.0"
|
version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e58eefd79f5173683872c0c82d0f05c2dc3c583d631259f60bb7a323756b7ff2"
|
checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@@ -842,9 +842,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "drm-ffi"
|
name = "drm-ffi"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "220dd8c12ebf2b0cbaffa19e00de02f5f090d363fb900f16ea012c077eea1174"
|
checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"drm-sys",
|
"drm-sys",
|
||||||
"rustix 0.38.28",
|
"rustix 0.38.28",
|
||||||
@@ -858,9 +858,9 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "drm-sys"
|
name = "drm-sys"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5115283ec60c99da8a9e5dc3c55f27680211e974c948cb6f3b51f0373190503b"
|
checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.6.3",
|
"linux-raw-sys 0.6.3",
|
||||||
@@ -890,7 +890,7 @@ checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -928,9 +928,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "4.0.1"
|
version = "4.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84f2cdcf274580f2d63697192d744727b3198894b1bf02923643bf59e2c26712"
|
checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"parking",
|
"parking",
|
||||||
@@ -943,7 +943,7 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
|
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener 4.0.1",
|
"event-listener 4.0.3",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -964,9 +964,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.1"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868"
|
checksum = "209098dd6dfc4445aa6111f0e98653ac323eaa4dfd212c9ca3931bf9955c31bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
@@ -1005,7 +1005,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1025,15 +1025,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.29"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.29"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
@@ -1052,9 +1052,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
version = "2.1.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143"
|
checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -1065,21 +1065,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.29"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.29"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.29"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
@@ -1140,12 +1140,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "0.3.0"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177"
|
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1176,7 +1176,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1406,16 +1406,6 @@ version = "0.2.151"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
@@ -1548,9 +1538,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loom"
|
name = "loom"
|
||||||
version = "0.5.6"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
|
checksum = "7e045d70ddfbc984eacfa964ded019534e8f6cbf36f6410aee0ed5cefa5a9175"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"generator",
|
"generator",
|
||||||
@@ -1592,9 +1582,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.6.4"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memmap2"
|
name = "memmap2"
|
||||||
@@ -1652,7 +1642,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1703,7 +1693,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "niri"
|
name = "niri"
|
||||||
version = "0.1.0-alpha.2"
|
version = "0.1.0-alpha.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
@@ -1714,11 +1704,10 @@ dependencies = [
|
|||||||
"directories",
|
"directories",
|
||||||
"git-version",
|
"git-version",
|
||||||
"keyframe",
|
"keyframe",
|
||||||
"knuffel",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"logind-zbus",
|
"logind-zbus",
|
||||||
"miette",
|
"niri-config",
|
||||||
"notify-rust",
|
"notify-rust",
|
||||||
"pipewire",
|
"pipewire",
|
||||||
"png",
|
"png",
|
||||||
@@ -1738,6 +1727,18 @@ dependencies = [
|
|||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "niri-config"
|
||||||
|
version = "0.1.0-alpha.3"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"directories",
|
||||||
|
"knuffel",
|
||||||
|
"miette",
|
||||||
|
"smithay",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.26.4"
|
version = "0.26.4"
|
||||||
@@ -1796,23 +1797,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum"
|
name = "num_enum"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0"
|
checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num_enum_derive",
|
"num_enum_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum_derive"
|
name = "num_enum_derive"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e"
|
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 2.0.1",
|
"proc-macro-crate 3.0.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1974,9 +1975,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.27"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
@@ -2051,12 +2052,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "2.0.1"
|
version = "3.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a"
|
checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"toml_datetime",
|
"toml_edit 0.21.0",
|
||||||
"toml_edit 0.20.2",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2085,18 +2085,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.70"
|
version = "1.0.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "profiling"
|
name = "profiling"
|
||||||
version = "1.0.12"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1de09527cd2ea2c2d59fb6c2f8c1ab8c71709ed9d1b6d60b0e1c9fbb6fdcb33c"
|
checksum = "d135ede8821cf6376eb7a64148901e1690b788c11ae94dc297ae917dbc91dc0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"profiling-procmacros",
|
"profiling-procmacros",
|
||||||
"tracy-client",
|
"tracy-client",
|
||||||
@@ -2104,12 +2104,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "profiling-procmacros"
|
name = "profiling-procmacros"
|
||||||
version = "1.0.12"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d8f36e3c621a72254893ed5cc57d1a069162adb3f98bfef610788661db6ad8d"
|
checksum = "4b322d7d65c1ab449be3c890fcbd0db6e1092d0dd05d79dba2dd28032cebeb05"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2160,9 +2160,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.33"
|
version = "1.0.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -2365,40 +2365,40 @@ checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.193"
|
version = "1.0.195"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.193"
|
version = "1.0.195"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_repr"
|
name = "serde_repr"
|
||||||
version = "0.1.17"
|
version = "0.1.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
|
checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.4"
|
version = "0.6.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
|
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -2462,7 +2462,7 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay"
|
name = "smithay"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/Smithay/smithay.git#b15d29e596b629ec25474b67cc9ecb2f1729d6a2"
|
source = "git+https://github.com/Smithay/smithay.git#77686d70991d6aa86de2ed787a335ef1643132d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"appendlist",
|
"appendlist",
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
@@ -2481,7 +2481,7 @@ dependencies = [
|
|||||||
"input",
|
"input",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.1",
|
"libloading",
|
||||||
"libseat",
|
"libseat",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
@@ -2533,7 +2533,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-drm-extras"
|
name = "smithay-drm-extras"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/Smithay/smithay.git#b15d29e596b629ec25474b67cc9ecb2f1729d6a2"
|
source = "git+https://github.com/Smithay/smithay.git#77686d70991d6aa86de2ed787a335ef1643132d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"drm",
|
"drm",
|
||||||
"edid-rs",
|
"edid-rs",
|
||||||
@@ -2566,9 +2566,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "ccbca6f34534eb78dbee83f6b2c9442fea7113f43d9e80ea320f0972ae5dc08d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
@@ -2583,9 +2583,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.41"
|
version = "2.0.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2607,9 +2607,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.12.12"
|
version = "0.12.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
|
checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-winrt-notification"
|
name = "tauri-winrt-notification"
|
||||||
@@ -2623,35 +2623,35 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.8.1"
|
version = "3.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
|
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall 0.4.1",
|
||||||
"rustix 0.38.28",
|
"rustix 0.38.28",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.51"
|
version = "1.0.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
|
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.51"
|
version = "1.0.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
|
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2699,21 +2699,21 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.2"
|
version = "0.8.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
|
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"toml_edit 0.20.2",
|
"toml_edit 0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.3"
|
version = "0.6.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
|
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -2731,9 +2731,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.20.2"
|
version = "0.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -2761,7 +2761,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2805,9 +2805,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracy-client"
|
name = "tracy-client"
|
||||||
version = "0.16.4"
|
version = "0.16.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82da0d50d9df1106619b1e5b118f39de779f7d8b9c3504485b291cb16fabd20f"
|
checksum = "307e6b7030112fe9640fdd87988a40795549ba75c355f59485d14e6b444d2987"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"loom",
|
"loom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -2816,9 +2816,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracy-client-sys"
|
name = "tracy-client-sys"
|
||||||
version = "0.22.0"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3db0b1cc1bb12a70457300d9affc07acb587390d971a796dac2f4d9bca8df776"
|
checksum = "078c7ed72141b0e4369671a7f7af0eecffe18d753bf0296adca9c7add7276c9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
@@ -2989,7 +2989,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3023,7 +3023,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@@ -3196,9 +3196,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-time"
|
name = "web-time"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57099a701fb3a8043f993e8228dc24229c7b942e2b009a1b962e54489ba1d3bf"
|
checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -3229,15 +3229,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-wsapoll"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -3472,9 +3463,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.29.4"
|
version = "0.29.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d25d662bb83b511acd839534bb2d88521b0bbc81440969cb077d23c4db9e62c7"
|
checksum = "c2376dab13e09c01ad8b679f0dbc7038af4ec43d9a91344338e37bd686481550"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"android-activity",
|
"android-activity",
|
||||||
@@ -3519,9 +3510,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.5.30"
|
version = "0.5.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5"
|
checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -3539,29 +3530,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11rb"
|
name = "x11rb"
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a"
|
checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.7.4",
|
"libloading",
|
||||||
"nix",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"winapi",
|
"rustix 0.38.28",
|
||||||
"winapi-wsapoll",
|
|
||||||
"x11rb-protocol",
|
"x11rb-protocol",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11rb-protocol"
|
name = "x11rb-protocol"
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc"
|
checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34"
|
||||||
dependencies = [
|
|
||||||
"nix",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xcursor"
|
name = "xcursor"
|
||||||
@@ -3683,22 +3669,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.31"
|
version = "0.7.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d"
|
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.7.31"
|
version = "0.7.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
|
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
+40
-20
@@ -1,48 +1,68 @@
|
|||||||
[package]
|
[workspace.package]
|
||||||
name = "niri"
|
version = "0.1.0-alpha.3"
|
||||||
version = "0.1.0-alpha.2"
|
|
||||||
description = "A scrollable-tiling Wayland compositor"
|
description = "A scrollable-tiling Wayland compositor"
|
||||||
authors = ["Ivan Molodetskikh <yalterz@gmail.com>"]
|
authors = ["Ivan Molodetskikh <yalterz@gmail.com>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
repository = "https://github.com/YaLTeR/niri"
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
bitflags = "2.4.1"
|
||||||
|
directories = "5.0.1"
|
||||||
|
tracing = { version = "0.1.40", features = ["max_level_trace", "release_max_level_debug"] }
|
||||||
|
|
||||||
|
[workspace.dependencies.smithay]
|
||||||
|
git = "https://github.com/Smithay/smithay.git"
|
||||||
|
# path = "../smithay"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[workspace.dependencies.smithay-drm-extras]
|
||||||
|
git = "https://github.com/Smithay/smithay.git"
|
||||||
|
# path = "../smithay/smithay-drm-extras"
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "niri"
|
||||||
|
version.workspace = true
|
||||||
|
description.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/YaLTeR/niri"
|
|
||||||
keywords = ["wayland", "compositor", "tiling", "smithay", "wm"]
|
keywords = ["wayland", "compositor", "tiling", "smithay", "wm"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { version = "1.0.75" }
|
anyhow = { version = "1.0.79" }
|
||||||
arrayvec = "0.7.4"
|
arrayvec = "0.7.4"
|
||||||
async-channel = { version = "2.1.1", optional = true }
|
async-channel = { version = "2.1.1", optional = true }
|
||||||
async-io = { version = "1.13.0", optional = true }
|
async-io = { version = "1.13.0", optional = true }
|
||||||
bitflags = "2.4.1"
|
bitflags = "2.4.1"
|
||||||
clap = { version = "4.4.11", features = ["derive"] }
|
clap = { version = "4.4.13", features = ["derive"] }
|
||||||
directories = "5.0.1"
|
directories = "5.0.1"
|
||||||
git-version = "0.3.9"
|
git-version = "0.3.9"
|
||||||
keyframe = { version = "1.1.1", default-features = false }
|
keyframe = { version = "1.1.1", default-features = false }
|
||||||
knuffel = "3.2.0"
|
|
||||||
libc = "0.2.151"
|
libc = "0.2.151"
|
||||||
logind-zbus = { version = "3.1.2", optional = true }
|
logind-zbus = { version = "3.1.2", optional = true }
|
||||||
log = { version = "0.4.20", features = ["max_level_trace", "release_max_level_debug"] }
|
log = { version = "0.4.20", features = ["max_level_trace", "release_max_level_debug"] }
|
||||||
miette = "5.10.0"
|
niri-config = { version = "0.1.0-alpha.3", path = "niri-config" }
|
||||||
notify-rust = { version = "4.10.0", optional = true }
|
notify-rust = { version = "4.10.0", optional = true }
|
||||||
pipewire = { version = "0.7.2", optional = true }
|
pipewire = { version = "0.7.2", optional = true }
|
||||||
png = "0.17.10"
|
png = "0.17.10"
|
||||||
portable-atomic = { version = "1.6.0", default-features = false, features = ["float"] }
|
portable-atomic = { version = "1.6.0", default-features = false, features = ["float"] }
|
||||||
profiling = "1.0.12"
|
profiling = "1.0.13"
|
||||||
sd-notify = "0.4.1"
|
sd-notify = "0.4.1"
|
||||||
serde = { version = "1.0.193", features = ["derive"] }
|
smithay-drm-extras.workspace = true
|
||||||
|
serde = { version = "1.0.195", features = ["derive"] }
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
tracing = { version = "0.1.40", features = ["max_level_trace", "release_max_level_debug"] }
|
tracing.workspace = true
|
||||||
tracy-client = { version = "0.16.4", default-features = false }
|
tracy-client = { version = "0.16.5", default-features = false }
|
||||||
url = { version = "2.5.0", optional = true }
|
url = { version = "2.5.0", optional = true }
|
||||||
xcursor = "0.3.5"
|
xcursor = "0.3.5"
|
||||||
zbus = { version = "3.14.1", optional = true }
|
zbus = { version = "3.14.1", optional = true }
|
||||||
|
|
||||||
[dependencies.smithay]
|
[dependencies.smithay]
|
||||||
git = "https://github.com/Smithay/smithay.git"
|
workspace = true
|
||||||
# path = "../smithay"
|
|
||||||
default-features = false
|
|
||||||
features = [
|
features = [
|
||||||
"backend_drm",
|
"backend_drm",
|
||||||
"backend_egl",
|
"backend_egl",
|
||||||
@@ -58,10 +78,6 @@ features = [
|
|||||||
"wayland_frontend",
|
"wayland_frontend",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies.smithay-drm-extras]
|
|
||||||
git = "https://github.com/Smithay/smithay.git"
|
|
||||||
# path = "../smithay/smithay-drm-extras"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
proptest = "1.4.0"
|
proptest = "1.4.0"
|
||||||
proptest-derive = "0.4.0"
|
proptest-derive = "0.4.0"
|
||||||
@@ -80,8 +96,12 @@ debug = "line-tables-only"
|
|||||||
overflow-checks = true
|
overflow-checks = true
|
||||||
lto = "thin"
|
lto = "thin"
|
||||||
|
|
||||||
|
[profile.release.package.niri-config]
|
||||||
|
# knuffel with chomsky generates a metric ton of debuginfo.
|
||||||
|
debug = false
|
||||||
|
|
||||||
[package.metadata.generate-rpm]
|
[package.metadata.generate-rpm]
|
||||||
version = "0.1.0~alpha.2"
|
version = "0.1.0~alpha.3"
|
||||||
assets = [
|
assets = [
|
||||||
{ source = "target/release/niri", dest = "/usr/bin/", mode = "755" },
|
{ source = "target/release/niri", dest = "/usr/bin/", mode = "755" },
|
||||||
{ source = "resources/niri-session", dest = "/usr/bin/", mode = "755" },
|
{ source = "resources/niri-session", dest = "/usr/bin/", mode = "755" },
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ When a monitor disconnects, its workspaces will move to another monitor, but upo
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
For Fedora users, there's a COPR with built and packaged niri: https://copr.fedorainfracloud.org/coprs/yalter/niri/
|
> [!TIP]
|
||||||
|
> For Fedora users, there's a COPR with built and packaged niri: https://copr.fedorainfracloud.org/coprs/yalter/niri/
|
||||||
|
>
|
||||||
|
> NixOS users, check out https://github.com/sodiboo/niri-flake
|
||||||
|
|
||||||
First, install the dependencies for your distribution.
|
First, install the dependencies for your distribution.
|
||||||
|
|
||||||
@@ -91,6 +94,10 @@ A step-by-step process for this is explained [on the wiki](https://github.com/Ya
|
|||||||
Niri also works with some parts of xdg-desktop-portal-gnome.
|
Niri also works with some parts of xdg-desktop-portal-gnome.
|
||||||
In particular, it supports file choosers and monitor screencasting (e.g. to [OBS]).
|
In particular, it supports file choosers and monitor screencasting (e.g. to [OBS]).
|
||||||
|
|
||||||
|
### Xwayland
|
||||||
|
|
||||||
|
See [the wiki page](https://github.com/YaLTeR/niri/wiki/Xwayland) to learn how to use Xwayland with niri.
|
||||||
|
|
||||||
## Default Hotkeys
|
## Default Hotkeys
|
||||||
|
|
||||||
When running on a TTY, the Mod key is <kbd>Super</kbd>.
|
When running on a TTY, the Mod key is <kbd>Super</kbd>.
|
||||||
@@ -112,6 +119,8 @@ The general system is: if a hotkey switches somewhere, then adding <kbd>Ctrl</kb
|
|||||||
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>L</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>→</kbd> | Move the focused column to the right |
|
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>L</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>→</kbd> | Move the focused column to the right |
|
||||||
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>J</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>↓</kbd> | Move the focused window below in a column |
|
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>J</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>↓</kbd> | Move the focused window below in a column |
|
||||||
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>K</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>↑</kbd> | Move the focused window above in a column |
|
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>K</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>↑</kbd> | Move the focused window above in a column |
|
||||||
|
| <kbd>Mod</kbd><kbd>Home</kbd> and <kbd>Mod</kbd><kbd>End</kbd> | Focus the first or the last column |
|
||||||
|
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>Home</kbd> and <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>End</kbd> | Move the focused column to the very start or to the very end |
|
||||||
| <kbd>Mod</kbd><kbd>Shift</kbd><kbd>H</kbd><kbd>J</kbd><kbd>K</kbd><kbd>L</kbd> or <kbd>Mod</kbd><kbd>Shift</kbd><kbd>←</kbd><kbd>↓</kbd><kbd>↑</kbd><kbd>→</kbd> | Focus the monitor to the side |
|
| <kbd>Mod</kbd><kbd>Shift</kbd><kbd>H</kbd><kbd>J</kbd><kbd>K</kbd><kbd>L</kbd> or <kbd>Mod</kbd><kbd>Shift</kbd><kbd>←</kbd><kbd>↓</kbd><kbd>↑</kbd><kbd>→</kbd> | Focus the monitor to the side |
|
||||||
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>Shift</kbd><kbd>H</kbd><kbd>J</kbd><kbd>K</kbd><kbd>L</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>Shift</kbd><kbd>←</kbd><kbd>↓</kbd><kbd>↑</kbd><kbd>→</kbd> | Move the focused window to the monitor to the side |
|
| <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>Shift</kbd><kbd>H</kbd><kbd>J</kbd><kbd>K</kbd><kbd>L</kbd> or <kbd>Mod</kbd><kbd>Ctrl</kbd><kbd>Shift</kbd><kbd>←</kbd><kbd>↓</kbd><kbd>↑</kbd><kbd>→</kbd> | Move the focused window to the monitor to the side |
|
||||||
| <kbd>Mod</kbd><kbd>U</kbd> or <kbd>Mod</kbd><kbd>PageDown</kbd> | Switch to the workspace below |
|
| <kbd>Mod</kbd><kbd>U</kbd> or <kbd>Mod</kbd><kbd>PageDown</kbd> | Switch to the workspace below |
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "niri-config"
|
||||||
|
version.workspace = true
|
||||||
|
description.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags.workspace = true
|
||||||
|
directories.workspace = true
|
||||||
|
knuffel = "3.2.0"
|
||||||
|
miette = "5.10.0"
|
||||||
|
smithay.workspace = true
|
||||||
|
tracing.workspace = true
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate tracing;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use miette::{miette, Context, IntoDiagnostic};
|
use miette::{miette, Context, IntoDiagnostic, NarratableReportHandler};
|
||||||
use smithay::input::keyboard::keysyms::KEY_NoSymbol;
|
use smithay::input::keyboard::keysyms::KEY_NoSymbol;
|
||||||
use smithay::input::keyboard::xkb::{keysym_from_name, KEYSYM_CASE_INSENSITIVE};
|
use smithay::input::keyboard::xkb::{keysym_from_name, KEYSYM_CASE_INSENSITIVE};
|
||||||
use smithay::input::keyboard::{Keysym, XkbConfig};
|
use smithay::input::keyboard::{Keysym, XkbConfig};
|
||||||
@@ -17,19 +20,11 @@ pub struct Config {
|
|||||||
#[knuffel(children(name = "spawn-at-startup"))]
|
#[knuffel(children(name = "spawn-at-startup"))]
|
||||||
pub spawn_at_startup: Vec<SpawnAtStartup>,
|
pub spawn_at_startup: Vec<SpawnAtStartup>,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
pub focus_ring: FocusRing,
|
pub layout: Layout,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
pub prefer_no_csd: bool,
|
pub prefer_no_csd: bool,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
pub cursor: Cursor,
|
pub cursor: Cursor,
|
||||||
#[knuffel(child, unwrap(children), default)]
|
|
||||||
pub preset_column_widths: Vec<PresetWidth>,
|
|
||||||
#[knuffel(child)]
|
|
||||||
pub default_column_width: Option<DefaultColumnWidth>,
|
|
||||||
#[knuffel(child, unwrap(argument), default = 16)]
|
|
||||||
pub gaps: u16,
|
|
||||||
#[knuffel(child, default)]
|
|
||||||
pub struts: Struts,
|
|
||||||
#[knuffel(
|
#[knuffel(
|
||||||
child,
|
child,
|
||||||
unwrap(argument),
|
unwrap(argument),
|
||||||
@@ -53,6 +48,8 @@ pub struct Input {
|
|||||||
pub touchpad: Touchpad,
|
pub touchpad: Touchpad,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
pub tablet: Tablet,
|
pub tablet: Tablet,
|
||||||
|
#[knuffel(child)]
|
||||||
|
pub disable_power_key_handling: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)]
|
#[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)]
|
||||||
@@ -161,6 +158,22 @@ pub struct Mode {
|
|||||||
pub refresh: Option<f64>,
|
pub refresh: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(knuffel::Decode, Debug, Default, Clone, PartialEq)]
|
||||||
|
pub struct Layout {
|
||||||
|
#[knuffel(child, default)]
|
||||||
|
pub focus_ring: FocusRing,
|
||||||
|
#[knuffel(child, default = default_border())]
|
||||||
|
pub border: FocusRing,
|
||||||
|
#[knuffel(child, unwrap(children), default)]
|
||||||
|
pub preset_column_widths: Vec<PresetWidth>,
|
||||||
|
#[knuffel(child)]
|
||||||
|
pub default_column_width: Option<DefaultColumnWidth>,
|
||||||
|
#[knuffel(child, unwrap(argument), default = 16)]
|
||||||
|
pub gaps: u16,
|
||||||
|
#[knuffel(child, default)]
|
||||||
|
pub struts: Struts,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)]
|
#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct SpawnAtStartup {
|
pub struct SpawnAtStartup {
|
||||||
#[knuffel(arguments)]
|
#[knuffel(arguments)]
|
||||||
@@ -190,6 +203,15 @@ impl Default for FocusRing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn default_border() -> FocusRing {
|
||||||
|
FocusRing {
|
||||||
|
off: true,
|
||||||
|
width: 4,
|
||||||
|
active_color: Color::new(255, 200, 127, 255),
|
||||||
|
inactive_color: Color::new(80, 80, 80, 255),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq, Eq)]
|
#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
#[knuffel(argument)]
|
#[knuffel(argument)]
|
||||||
@@ -203,7 +225,7 @@ pub struct Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||||
Self { r, g, b, a }
|
Self { r, g, b, a }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,12 +322,16 @@ pub enum Action {
|
|||||||
FullscreenWindow,
|
FullscreenWindow,
|
||||||
FocusColumnLeft,
|
FocusColumnLeft,
|
||||||
FocusColumnRight,
|
FocusColumnRight,
|
||||||
|
FocusColumnFirst,
|
||||||
|
FocusColumnLast,
|
||||||
FocusWindowDown,
|
FocusWindowDown,
|
||||||
FocusWindowUp,
|
FocusWindowUp,
|
||||||
FocusWindowOrWorkspaceDown,
|
FocusWindowOrWorkspaceDown,
|
||||||
FocusWindowOrWorkspaceUp,
|
FocusWindowOrWorkspaceUp,
|
||||||
MoveColumnLeft,
|
MoveColumnLeft,
|
||||||
MoveColumnRight,
|
MoveColumnRight,
|
||||||
|
MoveColumnToFirst,
|
||||||
|
MoveColumnToLast,
|
||||||
MoveWindowDown,
|
MoveWindowDown,
|
||||||
MoveWindowUp,
|
MoveWindowUp,
|
||||||
MoveWindowDownOrToWorkspaceDown,
|
MoveWindowDownOrToWorkspaceDown,
|
||||||
@@ -362,6 +388,10 @@ pub struct DebugConfig {
|
|||||||
pub enable_color_transformations_capability: bool,
|
pub enable_color_transformations_capability: bool,
|
||||||
#[knuffel(child)]
|
#[knuffel(child)]
|
||||||
pub enable_overlay_planes: bool,
|
pub enable_overlay_planes: bool,
|
||||||
|
#[knuffel(child)]
|
||||||
|
pub disable_cursor_plane: bool,
|
||||||
|
#[knuffel(child, unwrap(argument))]
|
||||||
|
pub render_drm_device: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DebugConfig {
|
impl Default for DebugConfig {
|
||||||
@@ -372,12 +402,18 @@ impl Default for DebugConfig {
|
|||||||
wait_for_frame_completion_before_queueing: false,
|
wait_for_frame_completion_before_queueing: false,
|
||||||
enable_color_transformations_capability: false,
|
enable_color_transformations_capability: false,
|
||||||
enable_overlay_planes: false,
|
enable_overlay_planes: false,
|
||||||
|
disable_cursor_plane: false,
|
||||||
|
render_drm_device: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load(path: Option<PathBuf>) -> miette::Result<(Self, PathBuf)> {
|
pub fn load(path: Option<PathBuf>) -> miette::Result<(Self, PathBuf)> {
|
||||||
|
Self::load_internal(path).context("error loading config")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_internal(path: Option<PathBuf>) -> miette::Result<(Self, PathBuf)> {
|
||||||
let path = if let Some(path) = path {
|
let path = if let Some(path) = path {
|
||||||
path
|
path
|
||||||
} else {
|
} else {
|
||||||
@@ -407,7 +443,7 @@ impl Default for Config {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Config::parse(
|
Config::parse(
|
||||||
"default-config.kdl",
|
"default-config.kdl",
|
||||||
include_str!("../resources/default-config.kdl"),
|
include_str!("../../resources/default-config.kdl"),
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
@@ -535,6 +571,10 @@ impl FromStr for SizeChange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_miette_hook() -> Result<(), miette::InstallError> {
|
||||||
|
miette::set_hook(Box::new(|_| Box::new(NarratableReportHandler::new())))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use miette::NarratableReportHandler;
|
use miette::NarratableReportHandler;
|
||||||
@@ -574,6 +614,8 @@ mod tests {
|
|||||||
tablet {
|
tablet {
|
||||||
map-to-output "eDP-1"
|
map-to-output "eDP-1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disable-power-key-handling
|
||||||
}
|
}
|
||||||
|
|
||||||
output "eDP-1" {
|
output "eDP-1" {
|
||||||
@@ -582,14 +624,39 @@ mod tests {
|
|||||||
mode "1920x1080@144"
|
mode "1920x1080@144"
|
||||||
}
|
}
|
||||||
|
|
||||||
spawn-at-startup "alacritty" "-e" "fish"
|
layout {
|
||||||
|
focus-ring {
|
||||||
|
width 5
|
||||||
|
active-color 0 100 200 255
|
||||||
|
inactive-color 255 200 100 0
|
||||||
|
}
|
||||||
|
|
||||||
focus-ring {
|
border {
|
||||||
width 5
|
width 3
|
||||||
active-color 0 100 200 255
|
active-color 0 100 200 255
|
||||||
inactive-color 255 200 100 0
|
inactive-color 255 200 100 0
|
||||||
|
}
|
||||||
|
|
||||||
|
preset-column-widths {
|
||||||
|
proportion 0.25
|
||||||
|
proportion 0.5
|
||||||
|
fixed 960
|
||||||
|
fixed 1280
|
||||||
|
}
|
||||||
|
|
||||||
|
default-column-width { proportion 0.25; }
|
||||||
|
|
||||||
|
gaps 8
|
||||||
|
|
||||||
|
struts {
|
||||||
|
left 1
|
||||||
|
right 2
|
||||||
|
top 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spawn-at-startup "alacritty" "-e" "fish"
|
||||||
|
|
||||||
prefer-no-csd
|
prefer-no-csd
|
||||||
|
|
||||||
cursor {
|
cursor {
|
||||||
@@ -597,23 +664,6 @@ mod tests {
|
|||||||
xcursor-size 16
|
xcursor-size 16
|
||||||
}
|
}
|
||||||
|
|
||||||
preset-column-widths {
|
|
||||||
proportion 0.25
|
|
||||||
proportion 0.5
|
|
||||||
fixed 960
|
|
||||||
fixed 1280
|
|
||||||
}
|
|
||||||
|
|
||||||
default-column-width { proportion 0.25; }
|
|
||||||
|
|
||||||
gaps 8
|
|
||||||
|
|
||||||
struts {
|
|
||||||
left 1
|
|
||||||
right 2
|
|
||||||
top 3
|
|
||||||
}
|
|
||||||
|
|
||||||
screenshot-path "~/Screenshots/screenshot.png"
|
screenshot-path "~/Screenshots/screenshot.png"
|
||||||
|
|
||||||
binds {
|
binds {
|
||||||
@@ -627,6 +677,7 @@ mod tests {
|
|||||||
|
|
||||||
debug {
|
debug {
|
||||||
animation-slowdown 2.0
|
animation-slowdown 2.0
|
||||||
|
render-drm-device "/dev/dri/renderD129"
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
Config {
|
Config {
|
||||||
@@ -649,6 +700,7 @@ mod tests {
|
|||||||
tablet: Tablet {
|
tablet: Tablet {
|
||||||
map_to_output: Some("eDP-1".to_owned()),
|
map_to_output: Some("eDP-1".to_owned()),
|
||||||
},
|
},
|
||||||
|
disable_power_key_handling: true,
|
||||||
},
|
},
|
||||||
outputs: vec![Output {
|
outputs: vec![Output {
|
||||||
off: false,
|
off: false,
|
||||||
@@ -661,44 +713,64 @@ mod tests {
|
|||||||
refresh: Some(144.),
|
refresh: Some(144.),
|
||||||
}),
|
}),
|
||||||
}],
|
}],
|
||||||
|
layout: Layout {
|
||||||
|
focus_ring: FocusRing {
|
||||||
|
off: false,
|
||||||
|
width: 5,
|
||||||
|
active_color: Color {
|
||||||
|
r: 0,
|
||||||
|
g: 100,
|
||||||
|
b: 200,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
|
inactive_color: Color {
|
||||||
|
r: 255,
|
||||||
|
g: 200,
|
||||||
|
b: 100,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
border: FocusRing {
|
||||||
|
off: false,
|
||||||
|
width: 3,
|
||||||
|
active_color: Color {
|
||||||
|
r: 0,
|
||||||
|
g: 100,
|
||||||
|
b: 200,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
|
inactive_color: Color {
|
||||||
|
r: 255,
|
||||||
|
g: 200,
|
||||||
|
b: 100,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preset_column_widths: vec![
|
||||||
|
PresetWidth::Proportion(0.25),
|
||||||
|
PresetWidth::Proportion(0.5),
|
||||||
|
PresetWidth::Fixed(960),
|
||||||
|
PresetWidth::Fixed(1280),
|
||||||
|
],
|
||||||
|
default_column_width: Some(DefaultColumnWidth(vec![PresetWidth::Proportion(
|
||||||
|
0.25,
|
||||||
|
)])),
|
||||||
|
gaps: 8,
|
||||||
|
struts: Struts {
|
||||||
|
left: 1,
|
||||||
|
right: 2,
|
||||||
|
top: 3,
|
||||||
|
bottom: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
spawn_at_startup: vec![SpawnAtStartup {
|
spawn_at_startup: vec![SpawnAtStartup {
|
||||||
command: vec!["alacritty".to_owned(), "-e".to_owned(), "fish".to_owned()],
|
command: vec!["alacritty".to_owned(), "-e".to_owned(), "fish".to_owned()],
|
||||||
}],
|
}],
|
||||||
focus_ring: FocusRing {
|
|
||||||
off: false,
|
|
||||||
width: 5,
|
|
||||||
active_color: Color {
|
|
||||||
r: 0,
|
|
||||||
g: 100,
|
|
||||||
b: 200,
|
|
||||||
a: 255,
|
|
||||||
},
|
|
||||||
inactive_color: Color {
|
|
||||||
r: 255,
|
|
||||||
g: 200,
|
|
||||||
b: 100,
|
|
||||||
a: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
prefer_no_csd: true,
|
prefer_no_csd: true,
|
||||||
cursor: Cursor {
|
cursor: Cursor {
|
||||||
xcursor_theme: String::from("breeze_cursors"),
|
xcursor_theme: String::from("breeze_cursors"),
|
||||||
xcursor_size: 16,
|
xcursor_size: 16,
|
||||||
},
|
},
|
||||||
preset_column_widths: vec![
|
|
||||||
PresetWidth::Proportion(0.25),
|
|
||||||
PresetWidth::Proportion(0.5),
|
|
||||||
PresetWidth::Fixed(960),
|
|
||||||
PresetWidth::Fixed(1280),
|
|
||||||
],
|
|
||||||
default_column_width: Some(DefaultColumnWidth(vec![PresetWidth::Proportion(0.25)])),
|
|
||||||
gaps: 8,
|
|
||||||
struts: Struts {
|
|
||||||
left: 1,
|
|
||||||
right: 2,
|
|
||||||
top: 3,
|
|
||||||
bottom: 0,
|
|
||||||
},
|
|
||||||
screenshot_path: Some(String::from("~/Screenshots/screenshot.png")),
|
screenshot_path: Some(String::from("~/Screenshots/screenshot.png")),
|
||||||
binds: Binds(vec![
|
binds: Binds(vec![
|
||||||
Bind {
|
Bind {
|
||||||
@@ -746,6 +818,7 @@ mod tests {
|
|||||||
]),
|
]),
|
||||||
debug: DebugConfig {
|
debug: DebugConfig {
|
||||||
animation_slowdown: 2.,
|
animation_slowdown: 2.,
|
||||||
|
render_drm_device: Some(PathBuf::from("/dev/dri/renderD129")),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -37,6 +37,12 @@ input {
|
|||||||
// existing outputs.
|
// existing outputs.
|
||||||
map-to-output "eDP-1"
|
map-to-output "eDP-1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By default, niri will take over the power button to make it sleep
|
||||||
|
// instead of power off.
|
||||||
|
// Uncomment this if you would like to configure the power button elsewhere
|
||||||
|
// (i.e. logind.conf).
|
||||||
|
// disable-power-key-handling
|
||||||
}
|
}
|
||||||
|
|
||||||
// You can configure outputs by their name, which you can find with wayland-info(1).
|
// You can configure outputs by their name, which you can find with wayland-info(1).
|
||||||
@@ -69,26 +75,72 @@ input {
|
|||||||
position x=1280 y=0
|
position x=1280 y=0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
// You can change how the focus ring looks.
|
||||||
|
focus-ring {
|
||||||
|
// Uncomment this line to disable the focus ring.
|
||||||
|
// off
|
||||||
|
|
||||||
|
// How many logical pixels the ring extends out from the windows.
|
||||||
|
width 4
|
||||||
|
|
||||||
|
// Color of the ring on the active monitor: red, green, blue, alpha.
|
||||||
|
active-color 127 200 255 255
|
||||||
|
|
||||||
|
// Color of the ring on inactive monitors: red, green, blue, alpha.
|
||||||
|
inactive-color 80 80 80 255
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can also add a border. It's similar to the focus ring, but always visible.
|
||||||
|
border {
|
||||||
|
// The settings are the same as for the focus ring.
|
||||||
|
// If you enable the border, you probably want to disable the focus ring.
|
||||||
|
off
|
||||||
|
|
||||||
|
width 4
|
||||||
|
active-color 255 200 127 255
|
||||||
|
inactive-color 80 80 80 255
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between.
|
||||||
|
preset-column-widths {
|
||||||
|
// Proportion sets the width as a fraction of the output width, taking gaps into account.
|
||||||
|
// For example, you can perfectly fit four windows sized "proportion 0.25" on an output.
|
||||||
|
// The default preset widths are 1/3, 1/2 and 2/3 of the output.
|
||||||
|
proportion 0.333
|
||||||
|
proportion 0.5
|
||||||
|
proportion 0.667
|
||||||
|
|
||||||
|
// Fixed sets the width in logical pixels exactly.
|
||||||
|
// fixed 1920
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can change the default width of the new windows.
|
||||||
|
default-column-width { proportion 0.5; }
|
||||||
|
// If you leave the brackets empty, the windows themselves will decide their initial width.
|
||||||
|
// default-column-width {}
|
||||||
|
|
||||||
|
// Set gaps around windows in logical pixels.
|
||||||
|
gaps 16
|
||||||
|
|
||||||
|
// Struts shrink the area occupied by windows, similarly to layer-shell panels.
|
||||||
|
// You can think of them as a kind of outer gaps. They are set in logical pixels.
|
||||||
|
// Left and right struts will cause the next window to the side to always be visible.
|
||||||
|
// Top and bottom struts will simply add outer gaps in addition to the area occupied by
|
||||||
|
// layer-shell panels and regular gaps.
|
||||||
|
struts {
|
||||||
|
// left 64
|
||||||
|
// right 64
|
||||||
|
// top 64
|
||||||
|
// bottom 64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add lines like this to spawn processes at startup.
|
// Add lines like this to spawn processes at startup.
|
||||||
// Note that running niri as a session supports xdg-desktop-autostart,
|
// Note that running niri as a session supports xdg-desktop-autostart,
|
||||||
// which may be more convenient to use.
|
// which may be more convenient to use.
|
||||||
// spawn-at-startup "alacritty" "-e" "fish"
|
// spawn-at-startup "alacritty" "-e" "fish"
|
||||||
|
|
||||||
// You can change how the focus ring looks.
|
|
||||||
focus-ring {
|
|
||||||
// Uncomment this line to disable the focus ring.
|
|
||||||
// off
|
|
||||||
|
|
||||||
// How many logical pixels the ring extends out from the windows.
|
|
||||||
width 4
|
|
||||||
|
|
||||||
// Color of the ring on the active monitor: red, green, blue, alpha.
|
|
||||||
active-color 127 200 255 255
|
|
||||||
|
|
||||||
// Color of the ring on inactive monitors: red, green, blue, alpha.
|
|
||||||
inactive-color 80 80 80 255
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor {
|
cursor {
|
||||||
// Change the theme and size of the cursor as well as set the
|
// Change the theme and size of the cursor as well as set the
|
||||||
// `XCURSOR_THEME` and `XCURSOR_SIZE` env variables.
|
// `XCURSOR_THEME` and `XCURSOR_SIZE` env variables.
|
||||||
@@ -101,39 +153,6 @@ cursor {
|
|||||||
// Additionally, clients will be informed that they are tiled, removing some rounded corners.
|
// Additionally, clients will be informed that they are tiled, removing some rounded corners.
|
||||||
// prefer-no-csd
|
// prefer-no-csd
|
||||||
|
|
||||||
// You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between.
|
|
||||||
preset-column-widths {
|
|
||||||
// Proportion sets the width as a fraction of the output width, taking gaps into account.
|
|
||||||
// For example, you can perfectly fit four windows sized "proportion 0.25" on an output.
|
|
||||||
// The default preset widths are 1/3, 1/2 and 2/3 of the output.
|
|
||||||
proportion 0.333
|
|
||||||
proportion 0.5
|
|
||||||
proportion 0.667
|
|
||||||
|
|
||||||
// Fixed sets the width in logical pixels exactly.
|
|
||||||
// fixed 1920
|
|
||||||
}
|
|
||||||
|
|
||||||
// You can change the default width of the new windows.
|
|
||||||
default-column-width { proportion 0.5; }
|
|
||||||
// If you leave the brackets empty, the windows themselves will decide their initial width.
|
|
||||||
// default-column-width {}
|
|
||||||
|
|
||||||
// Set gaps around windows in logical pixels.
|
|
||||||
gaps 16
|
|
||||||
|
|
||||||
// Struts shrink the area occupied by windows, similarly to layer-shell panels.
|
|
||||||
// You can think of them as a kind of outer gaps. They are set in logical pixels.
|
|
||||||
// Left and right struts will cause the next window to the side to always be visible.
|
|
||||||
// Top and bottom struts will simply add outer gaps in addition to the area occupied by
|
|
||||||
// layer-shell panels and regular gaps.
|
|
||||||
struts {
|
|
||||||
// left 64
|
|
||||||
// right 64
|
|
||||||
// top 64
|
|
||||||
// bottom 64
|
|
||||||
}
|
|
||||||
|
|
||||||
// You can change the path where screenshots are saved.
|
// You can change the path where screenshots are saved.
|
||||||
// A ~ at the front will be expanded to the home directory.
|
// A ~ at the front will be expanded to the home directory.
|
||||||
// The path is formatted with strftime(3) to give you the screenshot date and time.
|
// The path is formatted with strftime(3) to give you the screenshot date and time.
|
||||||
@@ -186,6 +205,11 @@ binds {
|
|||||||
// Mod+Ctrl+J { move-window-down-or-to-workspace-down; }
|
// Mod+Ctrl+J { move-window-down-or-to-workspace-down; }
|
||||||
// Mod+Ctrl+K { move-window-up-or-to-workspace-up; }
|
// Mod+Ctrl+K { move-window-up-or-to-workspace-up; }
|
||||||
|
|
||||||
|
Mod+Home { focus-column-first; }
|
||||||
|
Mod+End { focus-column-last; }
|
||||||
|
Mod+Ctrl+Home { move-column-to-first; }
|
||||||
|
Mod+Ctrl+End { move-column-to-last; }
|
||||||
|
|
||||||
Mod+Shift+H { focus-monitor-left; }
|
Mod+Shift+H { focus-monitor-left; }
|
||||||
Mod+Shift+J { focus-monitor-down; }
|
Mod+Shift+J { focus-monitor-down; }
|
||||||
Mod+Shift+K { focus-monitor-up; }
|
Mod+Shift+K { focus-monitor-up; }
|
||||||
|
|||||||
+27
-17
@@ -2,11 +2,12 @@ use std::collections::HashMap;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||||
use smithay::backend::renderer::gles::GlesRenderer;
|
use smithay::backend::renderer::gles::GlesRenderer;
|
||||||
use smithay::output::Output;
|
use smithay::output::Output;
|
||||||
|
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
|
||||||
use crate::input::CompositorMod;
|
use crate::input::CompositorMod;
|
||||||
use crate::niri::OutputRenderElements;
|
|
||||||
use crate::Niri;
|
use crate::Niri;
|
||||||
|
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
@@ -26,8 +27,8 @@ pub enum RenderResult {
|
|||||||
Submitted,
|
Submitted,
|
||||||
/// Rendering succeeded, but there was no damage.
|
/// Rendering succeeded, but there was no damage.
|
||||||
NoDamage,
|
NoDamage,
|
||||||
/// An error has occurred, the frame was not submitted.
|
/// The frame was not rendered and submitted, due to an error or otherwise.
|
||||||
Error,
|
Skipped,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
@@ -45,10 +46,13 @@ impl Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn renderer(&mut self) -> Option<&mut GlesRenderer> {
|
pub fn with_primary_renderer<T>(
|
||||||
|
&mut self,
|
||||||
|
f: impl FnOnce(&mut GlesRenderer) -> T,
|
||||||
|
) -> Option<T> {
|
||||||
match self {
|
match self {
|
||||||
Backend::Tty(tty) => tty.renderer(),
|
Backend::Tty(tty) => tty.with_primary_renderer(f),
|
||||||
Backend::Winit(winit) => Some(winit.renderer()),
|
Backend::Winit(winit) => winit.with_primary_renderer(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,12 +60,11 @@ impl Backend {
|
|||||||
&mut self,
|
&mut self,
|
||||||
niri: &mut Niri,
|
niri: &mut Niri,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
elements: &[OutputRenderElements<GlesRenderer>],
|
|
||||||
target_presentation_time: Duration,
|
target_presentation_time: Duration,
|
||||||
) -> RenderResult {
|
) -> RenderResult {
|
||||||
match self {
|
match self {
|
||||||
Backend::Tty(tty) => tty.render(niri, output, elements, target_presentation_time),
|
Backend::Tty(tty) => tty.render(niri, output, target_presentation_time),
|
||||||
Backend::Winit(winit) => winit.render(niri, output, elements),
|
Backend::Winit(winit) => winit.render(niri, output),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +96,20 @@ impl Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn import_dmabuf(&mut self, dmabuf: &Dmabuf) -> Result<(), ()> {
|
||||||
|
match self {
|
||||||
|
Backend::Tty(tty) => tty.import_dmabuf(dmabuf),
|
||||||
|
Backend::Winit(winit) => winit.import_dmabuf(dmabuf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn early_import(&mut self, surface: &WlSurface) {
|
||||||
|
match self {
|
||||||
|
Backend::Tty(tty) => tty.early_import(surface),
|
||||||
|
Backend::Winit(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "dbus"), allow(unused))]
|
#[cfg_attr(not(feature = "dbus"), allow(unused))]
|
||||||
pub fn connectors(&self) -> Arc<Mutex<HashMap<String, Output>>> {
|
pub fn connectors(&self) -> Arc<Mutex<HashMap<String, Output>>> {
|
||||||
match self {
|
match self {
|
||||||
@@ -107,18 +124,11 @@ impl Backend {
|
|||||||
) -> Option<smithay::backend::allocator::gbm::GbmDevice<smithay::backend::drm::DrmDeviceFd>>
|
) -> Option<smithay::backend::allocator::gbm::GbmDevice<smithay::backend::drm::DrmDeviceFd>>
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Backend::Tty(tty) => tty.gbm_device(),
|
Backend::Tty(tty) => tty.primary_gbm_device(),
|
||||||
Backend::Winit(_) => None,
|
Backend::Winit(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_active(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Backend::Tty(tty) => tty.is_active(),
|
|
||||||
Backend::Winit(_) => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_monitors_active(&self, active: bool) {
|
pub fn set_monitors_active(&self, active: bool) {
|
||||||
match self {
|
match self {
|
||||||
Backend::Tty(tty) => tty.set_monitors_active(active),
|
Backend::Tty(tty) => tty.set_monitors_active(active),
|
||||||
|
|||||||
+526
-204
File diff suppressed because it is too large
Load Diff
+33
-23
@@ -5,9 +5,11 @@ use std::rc::Rc;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use niri_config::Config;
|
||||||
|
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||||
use smithay::backend::renderer::damage::OutputDamageTracker;
|
use smithay::backend::renderer::damage::OutputDamageTracker;
|
||||||
use smithay::backend::renderer::gles::GlesRenderer;
|
use smithay::backend::renderer::gles::GlesRenderer;
|
||||||
use smithay::backend::renderer::{DebugFlags, Renderer};
|
use smithay::backend::renderer::{DebugFlags, ImportDma, ImportEgl, Renderer};
|
||||||
use smithay::backend::winit::{self, WinitEvent, WinitGraphicsBackend};
|
use smithay::backend::winit::{self, WinitEvent, WinitGraphicsBackend};
|
||||||
use smithay::output::{Mode, Output, PhysicalProperties, Scale, Subpixel};
|
use smithay::output::{Mode, Output, PhysicalProperties, Scale, Subpixel};
|
||||||
use smithay::reexports::calloop::LoopHandle;
|
use smithay::reexports::calloop::LoopHandle;
|
||||||
@@ -17,8 +19,7 @@ use smithay::reexports::winit::window::WindowBuilder;
|
|||||||
use smithay::utils::Transform;
|
use smithay::utils::Transform;
|
||||||
|
|
||||||
use super::RenderResult;
|
use super::RenderResult;
|
||||||
use crate::config::Config;
|
use crate::niri::{RedrawState, State};
|
||||||
use crate::niri::{OutputRenderElements, RedrawState, State};
|
|
||||||
use crate::utils::get_monotonic_time;
|
use crate::utils::get_monotonic_time;
|
||||||
use crate::Niri;
|
use crate::Niri;
|
||||||
|
|
||||||
@@ -113,17 +114,14 @@ impl Winit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&mut self, niri: &mut Niri) {
|
pub fn init(&mut self, niri: &mut Niri) {
|
||||||
// For some reason, binding the display here causes damage tracker artifacts.
|
if let Err(err) = self
|
||||||
//
|
.backend
|
||||||
// use smithay::backend::renderer::ImportEgl;
|
.renderer()
|
||||||
//
|
.bind_wl_display(&niri.display_handle)
|
||||||
// if let Err(err) = self
|
{
|
||||||
// .backend
|
warn!("error binding renderer wl_display: {err}");
|
||||||
// .renderer()
|
}
|
||||||
// .bind_wl_display(&niri.display_handle)
|
|
||||||
// {
|
|
||||||
// warn!("error binding renderer wl_display: {err}");
|
|
||||||
// }
|
|
||||||
niri.add_output(self.output.clone(), None);
|
niri.add_output(self.output.clone(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,23 +129,25 @@ impl Winit {
|
|||||||
"winit".to_owned()
|
"winit".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn renderer(&mut self) -> &mut GlesRenderer {
|
pub fn with_primary_renderer<T>(
|
||||||
self.backend.renderer()
|
&mut self,
|
||||||
|
f: impl FnOnce(&mut GlesRenderer) -> T,
|
||||||
|
) -> Option<T> {
|
||||||
|
Some(f(self.backend.renderer()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(
|
pub fn render(&mut self, niri: &mut Niri, output: &Output) -> RenderResult {
|
||||||
&mut self,
|
|
||||||
niri: &mut Niri,
|
|
||||||
output: &Output,
|
|
||||||
elements: &[OutputRenderElements<GlesRenderer>],
|
|
||||||
) -> RenderResult {
|
|
||||||
let _span = tracy_client::span!("Winit::render");
|
let _span = tracy_client::span!("Winit::render");
|
||||||
|
|
||||||
|
// Render the elements.
|
||||||
|
let elements = niri.render::<GlesRenderer>(self.backend.renderer(), output, true);
|
||||||
|
|
||||||
|
// Hand them over to winit.
|
||||||
self.backend.bind().unwrap();
|
self.backend.bind().unwrap();
|
||||||
let age = self.backend.buffer_age().unwrap();
|
let age = self.backend.buffer_age().unwrap();
|
||||||
let res = self
|
let res = self
|
||||||
.damage_tracker
|
.damage_tracker
|
||||||
.render_output(self.backend.renderer(), age, elements, [0.; 4])
|
.render_output(self.backend.renderer(), age, &elements, [0.; 4])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
niri.update_primary_scanout_output(output, &res.states);
|
niri.update_primary_scanout_output(output, &res.states);
|
||||||
@@ -202,6 +202,16 @@ impl Winit {
|
|||||||
renderer.set_debug_flags(renderer.debug_flags() ^ DebugFlags::TINT);
|
renderer.set_debug_flags(renderer.debug_flags() ^ DebugFlags::TINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn import_dmabuf(&mut self, dmabuf: &Dmabuf) -> Result<(), ()> {
|
||||||
|
match self.backend.renderer().import_dmabuf(dmabuf, None) {
|
||||||
|
Ok(_texture) => Ok(()),
|
||||||
|
Err(err) => {
|
||||||
|
debug!("error importing dmabuf: {err:?}");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connectors(&self) -> Arc<Mutex<HashMap<String, Output>>> {
|
pub fn connectors(&self) -> Arc<Mutex<HashMap<String, Output>>> {
|
||||||
self.connectors.clone()
|
self.connectors.clone()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use smithay::{delegate_compositor, delegate_shm};
|
|||||||
|
|
||||||
use super::xdg_shell;
|
use super::xdg_shell;
|
||||||
use crate::niri::{ClientState, State};
|
use crate::niri::{ClientState, State};
|
||||||
|
use crate::utils::clone2;
|
||||||
|
|
||||||
impl CompositorHandler for State {
|
impl CompositorHandler for State {
|
||||||
fn compositor_state(&mut self) -> &mut CompositorState {
|
fn compositor_state(&mut self) -> &mut CompositorState {
|
||||||
@@ -81,6 +82,7 @@ impl CompositorHandler for State {
|
|||||||
let _span = tracy_client::span!("CompositorHandler::commit");
|
let _span = tracy_client::span!("CompositorHandler::commit");
|
||||||
|
|
||||||
on_commit_buffer_handler::<Self>(surface);
|
on_commit_buffer_handler::<Self>(surface);
|
||||||
|
self.backend.early_import(surface);
|
||||||
|
|
||||||
if is_sync_subsurface(surface) {
|
if is_sync_subsurface(surface) {
|
||||||
return;
|
return;
|
||||||
@@ -116,8 +118,9 @@ impl CompositorHandler for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a commit of a previously-mapped root or a non-toplevel root.
|
// This is a commit of a previously-mapped root or a non-toplevel root.
|
||||||
if let Some((window, output)) = self.niri.layout.find_window_and_output(surface) {
|
if let Some(win_out) = self.niri.layout.find_window_and_output(surface) {
|
||||||
// This is a commit of a previously-mapped toplevel.
|
let (window, output) = clone2(win_out);
|
||||||
|
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
|
|
||||||
// This is a commit of a previously-mapped toplevel.
|
// This is a commit of a previously-mapped toplevel.
|
||||||
@@ -147,7 +150,7 @@ impl CompositorHandler for State {
|
|||||||
|
|
||||||
// This is a commit of a non-root or a non-toplevel root.
|
// This is a commit of a non-root or a non-toplevel root.
|
||||||
let root_window_output = self.niri.layout.find_window_and_output(&root_surface);
|
let root_window_output = self.niri.layout.find_window_and_output(&root_surface);
|
||||||
if let Some((window, output)) = root_window_output {
|
if let Some((window, output)) = root_window_output.map(clone2) {
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
self.niri.layout.update_window(&window);
|
self.niri.layout.update_window(&window);
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output);
|
||||||
@@ -158,7 +161,7 @@ impl CompositorHandler for State {
|
|||||||
self.popups_handle_commit(surface);
|
self.popups_handle_commit(surface);
|
||||||
if let Some(popup) = self.niri.popups.find_popup(surface) {
|
if let Some(popup) = self.niri.popups.find_popup(surface) {
|
||||||
if let Some(output) = self.output_for_popup(&popup) {
|
if let Some(output) = self.output_for_popup(&popup) {
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-10
@@ -9,7 +9,6 @@ use std::sync::Arc;
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use smithay::backend::allocator::dmabuf::Dmabuf;
|
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||||
use smithay::backend::renderer::ImportDma;
|
|
||||||
use smithay::desktop::{PopupKind, PopupManager};
|
use smithay::desktop::{PopupKind, PopupManager};
|
||||||
use smithay::input::pointer::{CursorIcon, CursorImageStatus, PointerHandle};
|
use smithay::input::pointer::{CursorIcon, CursorImageStatus, PointerHandle};
|
||||||
use smithay::input::{Seat, SeatHandler, SeatState};
|
use smithay::input::{Seat, SeatHandler, SeatState};
|
||||||
@@ -43,8 +42,8 @@ use smithay::{
|
|||||||
delegate_text_input_manager, delegate_virtual_keyboard_manager,
|
delegate_text_input_manager, delegate_virtual_keyboard_manager,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::layout::output_size;
|
|
||||||
use crate::niri::State;
|
use crate::niri::State;
|
||||||
|
use crate::utils::output_size;
|
||||||
|
|
||||||
impl SeatHandler for State {
|
impl SeatHandler for State {
|
||||||
type KeyboardFocus = WlSurface;
|
type KeyboardFocus = WlSurface;
|
||||||
@@ -193,7 +192,7 @@ delegate_presentation!(State);
|
|||||||
|
|
||||||
impl DmabufHandler for State {
|
impl DmabufHandler for State {
|
||||||
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
||||||
self.backend.tty().dmabuf_state()
|
&mut self.niri.dmabuf_state
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dmabuf_imported(
|
fn dmabuf_imported(
|
||||||
@@ -202,15 +201,11 @@ impl DmabufHandler for State {
|
|||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
notifier: ImportNotifier,
|
notifier: ImportNotifier,
|
||||||
) {
|
) {
|
||||||
let renderer = self.backend.renderer().expect(
|
match self.backend.import_dmabuf(&dmabuf) {
|
||||||
"the dmabuf global must be created and destroyed together with the output device",
|
Ok(_) => {
|
||||||
);
|
|
||||||
match renderer.import_dmabuf(&dmabuf, None) {
|
|
||||||
Ok(_texture) => {
|
|
||||||
let _ = notifier.successful::<State>();
|
let _ = notifier.successful::<State>();
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(_) => {
|
||||||
debug!("error importing dmabuf: {err:?}");
|
|
||||||
notifier.failed();
|
notifier.failed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-12
@@ -20,6 +20,7 @@ use smithay::wayland::shell::xdg::{
|
|||||||
use smithay::{delegate_kde_decoration, delegate_xdg_decoration, delegate_xdg_shell};
|
use smithay::{delegate_kde_decoration, delegate_xdg_decoration, delegate_xdg_shell};
|
||||||
|
|
||||||
use crate::niri::State;
|
use crate::niri::State;
|
||||||
|
use crate::utils::clone2;
|
||||||
|
|
||||||
impl XdgShellHandler for State {
|
impl XdgShellHandler for State {
|
||||||
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
|
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
|
||||||
@@ -123,8 +124,10 @@ impl XdgShellHandler for State {
|
|||||||
.layout
|
.layout
|
||||||
.find_window_and_output(surface.wl_surface())
|
.find_window_and_output(surface.wl_surface())
|
||||||
{
|
{
|
||||||
|
let window = window.clone();
|
||||||
|
|
||||||
if let Some(requested_output) = wl_output.as_ref().and_then(Output::from_resource) {
|
if let Some(requested_output) = wl_output.as_ref().and_then(Output::from_resource) {
|
||||||
if requested_output != current_output {
|
if &requested_output != current_output {
|
||||||
self.niri
|
self.niri
|
||||||
.layout
|
.layout
|
||||||
.move_window_to_output(window.clone(), &requested_output);
|
.move_window_to_output(window.clone(), &requested_output);
|
||||||
@@ -146,6 +149,7 @@ impl XdgShellHandler for State {
|
|||||||
.layout
|
.layout
|
||||||
.find_window_and_output(surface.wl_surface())
|
.find_window_and_output(surface.wl_surface())
|
||||||
{
|
{
|
||||||
|
let window = window.clone();
|
||||||
self.niri.layout.set_fullscreen(&window, false);
|
self.niri.layout.set_fullscreen(&window, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,7 +170,7 @@ impl XdgShellHandler for State {
|
|||||||
.layout
|
.layout
|
||||||
.find_window_and_output(surface.wl_surface());
|
.find_window_and_output(surface.wl_surface());
|
||||||
|
|
||||||
let Some((window, output)) = win_out else {
|
let Some((window, output)) = win_out.map(clone2) else {
|
||||||
// I have no idea how this can happen, but I saw it happen once, in a weird interaction
|
// I have no idea how this can happen, but I saw it happen once, in a weird interaction
|
||||||
// involving laptop going to sleep and resuming.
|
// involving laptop going to sleep and resuming.
|
||||||
error!("toplevel missing from both unmapped_windows and layout");
|
error!("toplevel missing from both unmapped_windows and layout");
|
||||||
@@ -179,7 +183,7 @@ impl XdgShellHandler for State {
|
|||||||
|
|
||||||
fn popup_destroyed(&mut self, surface: PopupSurface) {
|
fn popup_destroyed(&mut self, surface: PopupSurface) {
|
||||||
if let Some(output) = self.output_for_popup(&PopupKind::Xdg(surface)) {
|
if let Some(output) = self.output_for_popup(&PopupKind::Xdg(surface)) {
|
||||||
self.niri.queue_redraw(output);
|
self.niri.queue_redraw(output.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,16 +193,25 @@ delegate_xdg_shell!(State);
|
|||||||
impl XdgDecorationHandler for State {
|
impl XdgDecorationHandler for State {
|
||||||
fn new_decoration(&mut self, toplevel: ToplevelSurface) {
|
fn new_decoration(&mut self, toplevel: ToplevelSurface) {
|
||||||
let mode = if self.niri.config.borrow().prefer_no_csd {
|
let mode = if self.niri.config.borrow().prefer_no_csd {
|
||||||
Some(zxdg_toplevel_decoration_v1::Mode::ServerSide)
|
zxdg_toplevel_decoration_v1::Mode::ServerSide
|
||||||
} else {
|
} else {
|
||||||
None
|
zxdg_toplevel_decoration_v1::Mode::ClientSide
|
||||||
};
|
};
|
||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.decoration_mode = mode;
|
state.decoration_mode = Some(mode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_mode(&mut self, toplevel: ToplevelSurface, mode: zxdg_toplevel_decoration_v1::Mode) {
|
fn request_mode(
|
||||||
|
&mut self,
|
||||||
|
toplevel: ToplevelSurface,
|
||||||
|
mut mode: zxdg_toplevel_decoration_v1::Mode,
|
||||||
|
) {
|
||||||
|
// If prefer-no-csd is unset, then insist on CSD.
|
||||||
|
if !self.niri.config.borrow().prefer_no_csd {
|
||||||
|
mode = zxdg_toplevel_decoration_v1::Mode::ClientSide;
|
||||||
|
}
|
||||||
|
|
||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.decoration_mode = Some(mode);
|
state.decoration_mode = Some(mode);
|
||||||
});
|
});
|
||||||
@@ -211,12 +224,12 @@ impl XdgDecorationHandler for State {
|
|||||||
|
|
||||||
fn unset_mode(&mut self, toplevel: ToplevelSurface) {
|
fn unset_mode(&mut self, toplevel: ToplevelSurface) {
|
||||||
let mode = if self.niri.config.borrow().prefer_no_csd {
|
let mode = if self.niri.config.borrow().prefer_no_csd {
|
||||||
Some(zxdg_toplevel_decoration_v1::Mode::ServerSide)
|
zxdg_toplevel_decoration_v1::Mode::ServerSide
|
||||||
} else {
|
} else {
|
||||||
None
|
zxdg_toplevel_decoration_v1::Mode::ClientSide
|
||||||
};
|
};
|
||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.decoration_mode = mode;
|
state.decoration_mode = Some(mode);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Only send configure if it's non-initial.
|
// Only send configure if it's non-initial.
|
||||||
@@ -288,7 +301,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn output_for_popup(&self, popup: &PopupKind) -> Option<Output> {
|
pub fn output_for_popup(&self, popup: &PopupKind) -> Option<&Output> {
|
||||||
let root = find_popup_root_surface(popup).ok()?;
|
let root = find_popup_root_surface(popup).ok()?;
|
||||||
self.niri.output_for_root(&root)
|
self.niri.output_for_root(&root)
|
||||||
}
|
}
|
||||||
@@ -304,7 +317,7 @@ impl State {
|
|||||||
|
|
||||||
// Figure out if the root is a window or a layer surface.
|
// Figure out if the root is a window or a layer surface.
|
||||||
if let Some((window, output)) = self.niri.layout.find_window_and_output(&root) {
|
if let Some((window, output)) = self.niri.layout.find_window_and_output(&root) {
|
||||||
self.unconstrain_window_popup(popup, &window, &output);
|
self.unconstrain_window_popup(popup, window, output);
|
||||||
} else if let Some((layer_surface, output)) = self.niri.layout.outputs().find_map(|o| {
|
} else if let Some((layer_surface, output)) = self.niri.layout.outputs().find_map(|o| {
|
||||||
let map = layer_map_for_output(o);
|
let map = layer_map_for_output(o);
|
||||||
let layer_surface = map.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)?;
|
let layer_surface = map.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)?;
|
||||||
|
|||||||
+48
-13
@@ -1,6 +1,7 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use niri_config::{Action, Binds, LayoutAction, Modifiers};
|
||||||
use smithay::backend::input::{
|
use smithay::backend::input::{
|
||||||
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event,
|
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event,
|
||||||
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _,
|
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _,
|
||||||
@@ -20,7 +21,6 @@ use smithay::utils::{Logical, Point, SERIAL_COUNTER};
|
|||||||
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint};
|
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint};
|
||||||
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
|
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
|
||||||
|
|
||||||
use crate::config::{Action, Binds, LayoutAction, Modifiers};
|
|
||||||
use crate::niri::State;
|
use crate::niri::State;
|
||||||
use crate::screenshot_ui::ScreenshotUi;
|
use crate::screenshot_ui::ScreenshotUi;
|
||||||
use crate::utils::{center, get_monotonic_time, spawn};
|
use crate::utils::{center, get_monotonic_time, spawn};
|
||||||
@@ -209,6 +209,7 @@ impl State {
|
|||||||
pressed,
|
pressed,
|
||||||
*mods,
|
*mods,
|
||||||
&this.niri.screenshot_ui,
|
&this.niri.screenshot_ui,
|
||||||
|
this.niri.config.borrow().input.disable_power_key_handling,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) else {
|
) else {
|
||||||
@@ -244,6 +245,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
Action::ToggleDebugTint => {
|
Action::ToggleDebugTint => {
|
||||||
self.backend.toggle_debug_tint();
|
self.backend.toggle_debug_tint();
|
||||||
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::Spawn(command) => {
|
Action::Spawn(command) => {
|
||||||
spawn(command);
|
spawn(command);
|
||||||
@@ -251,15 +253,15 @@ impl State {
|
|||||||
Action::ScreenshotScreen => {
|
Action::ScreenshotScreen => {
|
||||||
let active = self.niri.layout.active_output().cloned();
|
let active = self.niri.layout.active_output().cloned();
|
||||||
if let Some(active) = active {
|
if let Some(active) = active {
|
||||||
if let Some(renderer) = self.backend.renderer() {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
if let Err(err) = self.niri.screenshot(renderer, &active) {
|
if let Err(err) = self.niri.screenshot(renderer, &active) {
|
||||||
warn!("error taking screenshot: {err:?}");
|
warn!("error taking screenshot: {err:?}");
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::ConfirmScreenshot => {
|
Action::ConfirmScreenshot => {
|
||||||
if let Some(renderer) = self.backend.renderer() {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
match self.niri.screenshot_ui.capture(renderer) {
|
match self.niri.screenshot_ui.capture(renderer) {
|
||||||
Ok((size, pixels)) => {
|
Ok((size, pixels)) => {
|
||||||
if let Err(err) = self.niri.save_screenshot(size, pixels) {
|
if let Err(err) = self.niri.save_screenshot(size, pixels) {
|
||||||
@@ -270,7 +272,7 @@ impl State {
|
|||||||
warn!("error capturing screenshot: {err:?}");
|
warn!("error capturing screenshot: {err:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
self.niri.screenshot_ui.close();
|
self.niri.screenshot_ui.close();
|
||||||
self.niri
|
self.niri
|
||||||
@@ -286,18 +288,18 @@ impl State {
|
|||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
Action::Screenshot => {
|
Action::Screenshot => {
|
||||||
if let Some(renderer) = self.backend.renderer() {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
self.niri.open_screenshot_ui(renderer);
|
self.niri.open_screenshot_ui(renderer);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
Action::ScreenshotWindow => {
|
Action::ScreenshotWindow => {
|
||||||
let active = self.niri.layout.active_window();
|
let active = self.niri.layout.active_window();
|
||||||
if let Some((window, output)) = active {
|
if let Some((window, output)) = active {
|
||||||
if let Some(renderer) = self.backend.renderer() {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
if let Err(err) = self.niri.screenshot_window(renderer, &output, &window) {
|
if let Err(err) = self.niri.screenshot_window(renderer, output, window) {
|
||||||
warn!("error taking screenshot: {err:?}");
|
warn!("error taking screenshot: {err:?}");
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::CloseWindow => {
|
Action::CloseWindow => {
|
||||||
@@ -330,6 +332,16 @@ impl State {
|
|||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
self.niri.queue_redraw_all();
|
self.niri.queue_redraw_all();
|
||||||
}
|
}
|
||||||
|
Action::MoveColumnToFirst => {
|
||||||
|
self.niri.layout.move_column_to_first();
|
||||||
|
// FIXME: granular
|
||||||
|
self.niri.queue_redraw_all();
|
||||||
|
}
|
||||||
|
Action::MoveColumnToLast => {
|
||||||
|
self.niri.layout.move_column_to_last();
|
||||||
|
// FIXME: granular
|
||||||
|
self.niri.queue_redraw_all();
|
||||||
|
}
|
||||||
Action::MoveWindowDown => {
|
Action::MoveWindowDown => {
|
||||||
self.niri.layout.move_down();
|
self.niri.layout.move_down();
|
||||||
// FIXME: granular
|
// FIXME: granular
|
||||||
@@ -356,6 +368,12 @@ impl State {
|
|||||||
Action::FocusColumnRight => {
|
Action::FocusColumnRight => {
|
||||||
self.niri.layout.focus_right();
|
self.niri.layout.focus_right();
|
||||||
}
|
}
|
||||||
|
Action::FocusColumnFirst => {
|
||||||
|
self.niri.layout.focus_column_first();
|
||||||
|
}
|
||||||
|
Action::FocusColumnLast => {
|
||||||
|
self.niri.layout.focus_column_last();
|
||||||
|
}
|
||||||
Action::FocusWindowDown => {
|
Action::FocusWindowDown => {
|
||||||
self.niri.layout.focus_down();
|
self.niri.layout.focus_down();
|
||||||
}
|
}
|
||||||
@@ -800,12 +818,16 @@ impl State {
|
|||||||
|
|
||||||
let mut frame = AxisFrame::new(event.time_msec()).source(source);
|
let mut frame = AxisFrame::new(event.time_msec()).source(source);
|
||||||
if horizontal_amount != 0.0 {
|
if horizontal_amount != 0.0 {
|
||||||
|
frame = frame
|
||||||
|
.relative_direction(Axis::Horizontal, event.relative_direction(Axis::Horizontal));
|
||||||
frame = frame.value(Axis::Horizontal, horizontal_amount);
|
frame = frame.value(Axis::Horizontal, horizontal_amount);
|
||||||
if let Some(discrete) = horizontal_amount_discrete {
|
if let Some(discrete) = horizontal_amount_discrete {
|
||||||
frame = frame.v120(Axis::Horizontal, discrete as i32);
|
frame = frame.v120(Axis::Horizontal, discrete as i32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if vertical_amount != 0.0 {
|
if vertical_amount != 0.0 {
|
||||||
|
frame =
|
||||||
|
frame.relative_direction(Axis::Vertical, event.relative_direction(Axis::Vertical));
|
||||||
frame = frame.value(Axis::Vertical, vertical_amount);
|
frame = frame.value(Axis::Vertical, vertical_amount);
|
||||||
if let Some(discrete) = vertical_amount_discrete {
|
if let Some(discrete) = vertical_amount_discrete {
|
||||||
frame = frame.v120(Axis::Vertical, discrete as i32);
|
frame = frame.v120(Axis::Vertical, discrete as i32);
|
||||||
@@ -1165,6 +1187,7 @@ fn should_intercept_key(
|
|||||||
pressed: bool,
|
pressed: bool,
|
||||||
mods: ModifiersState,
|
mods: ModifiersState,
|
||||||
screenshot_ui: &ScreenshotUi,
|
screenshot_ui: &ScreenshotUi,
|
||||||
|
disable_power_key_handling: bool,
|
||||||
) -> FilterResult<Option<Action>> {
|
) -> FilterResult<Option<Action>> {
|
||||||
// Actions are only triggered on presses, release of the key
|
// Actions are only triggered on presses, release of the key
|
||||||
// shouldn't try to intercept anything unless we have marked
|
// shouldn't try to intercept anything unless we have marked
|
||||||
@@ -1173,7 +1196,14 @@ fn should_intercept_key(
|
|||||||
return FilterResult::Forward;
|
return FilterResult::Forward;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut final_action = action(bindings, comp_mod, modified, raw, mods);
|
let mut final_action = action(
|
||||||
|
bindings,
|
||||||
|
comp_mod,
|
||||||
|
modified,
|
||||||
|
raw,
|
||||||
|
mods,
|
||||||
|
disable_power_key_handling,
|
||||||
|
);
|
||||||
|
|
||||||
// Allow only a subset of compositor actions while the screenshot UI is open, since the user
|
// Allow only a subset of compositor actions while the screenshot UI is open, since the user
|
||||||
// cannot see the screen.
|
// cannot see the screen.
|
||||||
@@ -1210,6 +1240,7 @@ fn action(
|
|||||||
modified: Keysym,
|
modified: Keysym,
|
||||||
raw: Option<Keysym>,
|
raw: Option<Keysym>,
|
||||||
mods: ModifiersState,
|
mods: ModifiersState,
|
||||||
|
disable_power_key_handling: bool,
|
||||||
) -> Option<Action> {
|
) -> Option<Action> {
|
||||||
use keysyms::*;
|
use keysyms::*;
|
||||||
|
|
||||||
@@ -1220,7 +1251,7 @@ fn action(
|
|||||||
let vt = (modified - KEY_XF86Switch_VT_1 + 1) as i32;
|
let vt = (modified - KEY_XF86Switch_VT_1 + 1) as i32;
|
||||||
return Some(Action::ChangeVt(vt));
|
return Some(Action::ChangeVt(vt));
|
||||||
}
|
}
|
||||||
KEY_XF86PowerOff => return Some(Action::Suspend),
|
KEY_XF86PowerOff if !disable_power_key_handling => return Some(Action::Suspend),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,8 +1338,9 @@ fn allowed_during_screenshot(action: &Action) -> bool {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use niri_config::{Action, Bind, Binds, Key, Modifiers};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::config::{Action, Bind, Binds, Key, Modifiers};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bindings_suppress_keys() {
|
fn bindings_suppress_keys() {
|
||||||
@@ -1325,6 +1357,7 @@ mod tests {
|
|||||||
let mut suppressed_keys = HashSet::new();
|
let mut suppressed_keys = HashSet::new();
|
||||||
|
|
||||||
let screenshot_ui = ScreenshotUi::new();
|
let screenshot_ui = ScreenshotUi::new();
|
||||||
|
let disable_power_key_handling = false;
|
||||||
|
|
||||||
// The key_code we pick is arbitrary, the only thing
|
// The key_code we pick is arbitrary, the only thing
|
||||||
// that matters is that they are different between cases.
|
// that matters is that they are different between cases.
|
||||||
@@ -1341,6 +1374,7 @@ mod tests {
|
|||||||
pressed,
|
pressed,
|
||||||
mods,
|
mods,
|
||||||
&screenshot_ui,
|
&screenshot_ui,
|
||||||
|
disable_power_key_handling,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1356,6 +1390,7 @@ mod tests {
|
|||||||
pressed,
|
pressed,
|
||||||
mods,
|
mods,
|
||||||
&screenshot_ui,
|
&screenshot_ui,
|
||||||
|
disable_power_key_handling,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
-4025
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,115 @@
|
|||||||
|
use std::iter::zip;
|
||||||
|
|
||||||
|
use arrayvec::ArrayVec;
|
||||||
|
use niri_config::{self, Color};
|
||||||
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
|
use smithay::backend::renderer::element::Kind;
|
||||||
|
use smithay::utils::{Logical, Point, Scale, Size};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FocusRing {
|
||||||
|
buffers: [SolidColorBuffer; 4],
|
||||||
|
locations: [Point<i32, Logical>; 4],
|
||||||
|
is_off: bool,
|
||||||
|
is_border: bool,
|
||||||
|
width: i32,
|
||||||
|
active_color: Color,
|
||||||
|
inactive_color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type FocusRingRenderElement = SolidColorRenderElement;
|
||||||
|
|
||||||
|
impl FocusRing {
|
||||||
|
pub fn new(config: niri_config::FocusRing) -> Self {
|
||||||
|
Self {
|
||||||
|
buffers: Default::default(),
|
||||||
|
locations: Default::default(),
|
||||||
|
is_off: config.off,
|
||||||
|
is_border: false,
|
||||||
|
width: config.width.into(),
|
||||||
|
active_color: config.active_color,
|
||||||
|
inactive_color: config.inactive_color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_config(&mut self, config: niri_config::FocusRing) {
|
||||||
|
self.is_off = config.off;
|
||||||
|
self.width = config.width.into();
|
||||||
|
self.active_color = config.active_color;
|
||||||
|
self.inactive_color = config.inactive_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
win_pos: Point<i32, Logical>,
|
||||||
|
win_size: Size<i32, Logical>,
|
||||||
|
is_border: bool,
|
||||||
|
) {
|
||||||
|
if is_border {
|
||||||
|
self.buffers[0].resize((win_size.w + self.width * 2, self.width));
|
||||||
|
self.buffers[1].resize((win_size.w + self.width * 2, self.width));
|
||||||
|
self.buffers[2].resize((self.width, win_size.h));
|
||||||
|
self.buffers[3].resize((self.width, win_size.h));
|
||||||
|
|
||||||
|
self.locations[0] = win_pos + Point::from((-self.width, -self.width));
|
||||||
|
self.locations[1] = win_pos + Point::from((-self.width, win_size.h));
|
||||||
|
self.locations[2] = win_pos + Point::from((-self.width, 0));
|
||||||
|
self.locations[3] = win_pos + Point::from((win_size.w, 0));
|
||||||
|
} else {
|
||||||
|
let size = win_size + Size::from((self.width * 2, self.width * 2));
|
||||||
|
self.buffers[0].resize(size);
|
||||||
|
self.locations[0] = win_pos - Point::from((self.width, self.width));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.is_border = is_border;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_active(&mut self, is_active: bool) {
|
||||||
|
let color = if is_active {
|
||||||
|
self.active_color.into()
|
||||||
|
} else {
|
||||||
|
self.inactive_color.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
for buf in &mut self.buffers {
|
||||||
|
buf.set_color(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, scale: Scale<f64>) -> impl Iterator<Item = FocusRingRenderElement> {
|
||||||
|
let mut rv = ArrayVec::<_, 4>::new();
|
||||||
|
|
||||||
|
if self.is_off {
|
||||||
|
return rv.into_iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut push = |buffer, location: Point<i32, Logical>| {
|
||||||
|
let elem = SolidColorRenderElement::from_buffer(
|
||||||
|
buffer,
|
||||||
|
location.to_physical_precise_round(scale),
|
||||||
|
scale,
|
||||||
|
1.,
|
||||||
|
Kind::Unspecified,
|
||||||
|
);
|
||||||
|
rv.push(elem);
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.is_border {
|
||||||
|
for (buf, loc) in zip(&self.buffers, self.locations) {
|
||||||
|
push(buf, loc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push(&self.buffers[0], self.locations[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(&self) -> i32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_off(&self) -> bool {
|
||||||
|
self.is_off
|
||||||
|
}
|
||||||
|
}
|
||||||
+2217
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,584 @@
|
|||||||
|
use std::cmp::min;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use niri_config::SizeChange;
|
||||||
|
use smithay::backend::renderer::element::utils::{
|
||||||
|
CropRenderElement, Relocate, RelocateRenderElement,
|
||||||
|
};
|
||||||
|
use smithay::backend::renderer::{ImportAll, Renderer};
|
||||||
|
use smithay::desktop::Window;
|
||||||
|
use smithay::output::Output;
|
||||||
|
use smithay::utils::{Logical, Point, Rectangle, Scale};
|
||||||
|
|
||||||
|
use super::workspace::{
|
||||||
|
compute_working_area, ColumnWidth, OutputId, Workspace, WorkspaceRenderElement,
|
||||||
|
};
|
||||||
|
use super::{LayoutElement, Options};
|
||||||
|
use crate::animation::Animation;
|
||||||
|
use crate::utils::output_size;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Monitor<W: LayoutElement> {
|
||||||
|
/// Output for this monitor.
|
||||||
|
pub output: Output,
|
||||||
|
// Must always contain at least one.
|
||||||
|
pub workspaces: Vec<Workspace<W>>,
|
||||||
|
/// Index of the currently active workspace.
|
||||||
|
pub active_workspace_idx: usize,
|
||||||
|
/// In-progress switch between workspaces.
|
||||||
|
pub workspace_switch: Option<WorkspaceSwitch>,
|
||||||
|
/// Configurable properties of the layout.
|
||||||
|
pub options: Rc<Options>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WorkspaceSwitch {
|
||||||
|
Animation(Animation),
|
||||||
|
Gesture(WorkspaceSwitchGesture),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WorkspaceSwitchGesture {
|
||||||
|
/// Index of the workspace where the gesture was started.
|
||||||
|
pub center_idx: usize,
|
||||||
|
/// Current, fractional workspace index.
|
||||||
|
pub current_idx: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type MonitorRenderElement<R> =
|
||||||
|
RelocateRenderElement<CropRenderElement<WorkspaceRenderElement<R>>>;
|
||||||
|
|
||||||
|
impl WorkspaceSwitch {
|
||||||
|
pub fn current_idx(&self) -> f64 {
|
||||||
|
match self {
|
||||||
|
WorkspaceSwitch::Animation(anim) => anim.value(),
|
||||||
|
WorkspaceSwitch::Gesture(gesture) => gesture.current_idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the workspace switch is [`Animation`].
|
||||||
|
///
|
||||||
|
/// [`Animation`]: WorkspaceSwitch::Animation
|
||||||
|
#[must_use]
|
||||||
|
fn is_animation(&self) -> bool {
|
||||||
|
matches!(self, Self::Animation(..))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: LayoutElement> Monitor<W> {
|
||||||
|
pub fn new(output: Output, workspaces: Vec<Workspace<W>>, options: Rc<Options>) -> Self {
|
||||||
|
Self {
|
||||||
|
output,
|
||||||
|
workspaces,
|
||||||
|
active_workspace_idx: 0,
|
||||||
|
workspace_switch: None,
|
||||||
|
options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn active_workspace(&mut self) -> &mut Workspace<W> {
|
||||||
|
&mut self.workspaces[self.active_workspace_idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate_workspace(&mut self, idx: usize) {
|
||||||
|
if self.active_workspace_idx == idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_idx = self
|
||||||
|
.workspace_switch
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.current_idx())
|
||||||
|
.unwrap_or(self.active_workspace_idx as f64);
|
||||||
|
|
||||||
|
self.active_workspace_idx = idx;
|
||||||
|
|
||||||
|
self.workspace_switch = Some(WorkspaceSwitch::Animation(Animation::new(
|
||||||
|
current_idx,
|
||||||
|
idx as f64,
|
||||||
|
Duration::from_millis(250),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_window(
|
||||||
|
&mut self,
|
||||||
|
workspace_idx: usize,
|
||||||
|
window: W,
|
||||||
|
activate: bool,
|
||||||
|
width: ColumnWidth,
|
||||||
|
is_full_width: bool,
|
||||||
|
) {
|
||||||
|
let workspace = &mut self.workspaces[workspace_idx];
|
||||||
|
|
||||||
|
workspace.add_window(window, activate, width, is_full_width);
|
||||||
|
|
||||||
|
// After adding a new window, workspace becomes this output's own.
|
||||||
|
workspace.original_output = OutputId::new(&self.output);
|
||||||
|
|
||||||
|
if workspace_idx == self.workspaces.len() - 1 {
|
||||||
|
// Insert a new empty workspace.
|
||||||
|
let ws = Workspace::new(self.output.clone(), self.options.clone());
|
||||||
|
self.workspaces.push(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
if activate {
|
||||||
|
self.activate_workspace(workspace_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clean_up_workspaces(&mut self) {
|
||||||
|
assert!(self.workspace_switch.is_none());
|
||||||
|
|
||||||
|
for idx in (0..self.workspaces.len() - 1).rev() {
|
||||||
|
if self.active_workspace_idx == idx {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.workspaces[idx].has_windows() {
|
||||||
|
self.workspaces.remove(idx);
|
||||||
|
if self.active_workspace_idx > idx {
|
||||||
|
self.active_workspace_idx -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_left(&mut self) {
|
||||||
|
self.active_workspace().move_left();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_right(&mut self) {
|
||||||
|
self.active_workspace().move_right();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_column_to_first(&mut self) {
|
||||||
|
self.active_workspace().move_column_to_first();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_column_to_last(&mut self) {
|
||||||
|
self.active_workspace().move_column_to_last();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_down(&mut self) {
|
||||||
|
self.active_workspace().move_down();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_up(&mut self) {
|
||||||
|
self.active_workspace().move_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_down_or_to_workspace_down(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let column = &mut workspace.columns[workspace.active_column_idx];
|
||||||
|
let curr_idx = column.active_tile_idx;
|
||||||
|
let new_idx = min(column.active_tile_idx + 1, column.tiles.len() - 1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.move_to_workspace_down();
|
||||||
|
} else {
|
||||||
|
workspace.move_down();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_up_or_to_workspace_up(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let curr_idx = workspace.columns[workspace.active_column_idx].active_tile_idx;
|
||||||
|
let new_idx = curr_idx.saturating_sub(1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.move_to_workspace_up();
|
||||||
|
} else {
|
||||||
|
workspace.move_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_left(&mut self) {
|
||||||
|
self.active_workspace().focus_left();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_right(&mut self) {
|
||||||
|
self.active_workspace().focus_right();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_column_first(&mut self) {
|
||||||
|
self.active_workspace().focus_column_first();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_column_last(&mut self) {
|
||||||
|
self.active_workspace().focus_column_last();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_down(&mut self) {
|
||||||
|
self.active_workspace().focus_down();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_up(&mut self) {
|
||||||
|
self.active_workspace().focus_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_window_or_workspace_down(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
self.switch_workspace_down();
|
||||||
|
} else {
|
||||||
|
let column = &workspace.columns[workspace.active_column_idx];
|
||||||
|
let curr_idx = column.active_tile_idx;
|
||||||
|
let new_idx = min(column.active_tile_idx + 1, column.tiles.len() - 1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.switch_workspace_down();
|
||||||
|
} else {
|
||||||
|
workspace.focus_down();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_window_or_workspace_up(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
self.switch_workspace_up();
|
||||||
|
} else {
|
||||||
|
let curr_idx = workspace.columns[workspace.active_column_idx].active_tile_idx;
|
||||||
|
let new_idx = curr_idx.saturating_sub(1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.switch_workspace_up();
|
||||||
|
} else {
|
||||||
|
workspace.focus_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_to_workspace_up(&mut self) {
|
||||||
|
let source_workspace_idx = self.active_workspace_idx;
|
||||||
|
|
||||||
|
let new_idx = source_workspace_idx.saturating_sub(1);
|
||||||
|
if new_idx == source_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &workspace.columns[workspace.active_column_idx];
|
||||||
|
let width = column.width;
|
||||||
|
let is_full_width = column.is_full_width;
|
||||||
|
let window =
|
||||||
|
workspace.remove_window_by_idx(workspace.active_column_idx, column.active_tile_idx);
|
||||||
|
|
||||||
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_to_workspace_down(&mut self) {
|
||||||
|
let source_workspace_idx = self.active_workspace_idx;
|
||||||
|
|
||||||
|
let new_idx = min(source_workspace_idx + 1, self.workspaces.len() - 1);
|
||||||
|
if new_idx == source_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &workspace.columns[workspace.active_column_idx];
|
||||||
|
let width = column.width;
|
||||||
|
let is_full_width = column.is_full_width;
|
||||||
|
let window =
|
||||||
|
workspace.remove_window_by_idx(workspace.active_column_idx, column.active_tile_idx);
|
||||||
|
|
||||||
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_to_workspace(&mut self, idx: usize) {
|
||||||
|
let source_workspace_idx = self.active_workspace_idx;
|
||||||
|
|
||||||
|
let new_idx = min(idx, self.workspaces.len() - 1);
|
||||||
|
if new_idx == source_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &workspace.columns[workspace.active_column_idx];
|
||||||
|
let width = column.width;
|
||||||
|
let is_full_width = column.is_full_width;
|
||||||
|
let window =
|
||||||
|
workspace.remove_window_by_idx(workspace.active_column_idx, column.active_tile_idx);
|
||||||
|
|
||||||
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
|
|
||||||
|
// Don't animate this action.
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_workspace_up(&mut self) {
|
||||||
|
self.activate_workspace(self.active_workspace_idx.saturating_sub(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_workspace_down(&mut self) {
|
||||||
|
self.activate_workspace(min(
|
||||||
|
self.active_workspace_idx + 1,
|
||||||
|
self.workspaces.len() - 1,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_workspace(&mut self, idx: usize) {
|
||||||
|
self.activate_workspace(min(idx, self.workspaces.len() - 1));
|
||||||
|
// Don't animate this action.
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume_into_column(&mut self) {
|
||||||
|
self.active_workspace().consume_into_column();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expel_from_column(&mut self) {
|
||||||
|
self.active_workspace().expel_from_column();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center_column(&mut self) {
|
||||||
|
self.active_workspace().center_column();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus(&self) -> Option<&W> {
|
||||||
|
let workspace = &self.workspaces[self.active_workspace_idx];
|
||||||
|
if !workspace.has_windows() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &workspace.columns[workspace.active_column_idx];
|
||||||
|
Some(column.tiles[column.active_tile_idx].window())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
|
||||||
|
if let Some(WorkspaceSwitch::Animation(anim)) = &mut self.workspace_switch {
|
||||||
|
anim.set_current_time(current_time);
|
||||||
|
if anim.is_done() {
|
||||||
|
self.workspace_switch = None;
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ws in &mut self.workspaces {
|
||||||
|
ws.advance_animations(current_time, is_active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn are_animations_ongoing(&self) -> bool {
|
||||||
|
self.workspace_switch
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|s| s.is_animation())
|
||||||
|
|| self.workspaces.iter().any(|ws| ws.are_animations_ongoing())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn are_transitions_ongoing(&self) -> bool {
|
||||||
|
self.workspace_switch.is_some()
|
||||||
|
|| self.workspaces.iter().any(|ws| ws.are_animations_ongoing())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_config(&mut self, options: Rc<Options>) {
|
||||||
|
for ws in &mut self.workspaces {
|
||||||
|
ws.update_config(options.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.options.struts != options.struts {
|
||||||
|
let view_size = output_size(&self.output);
|
||||||
|
let working_area = compute_working_area(&self.output, options.struts);
|
||||||
|
|
||||||
|
for ws in &mut self.workspaces {
|
||||||
|
ws.set_view_size(view_size, working_area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_width(&mut self) {
|
||||||
|
self.active_workspace().toggle_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_full_width(&mut self) {
|
||||||
|
self.active_workspace().toggle_full_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_column_width(&mut self, change: SizeChange) {
|
||||||
|
self.active_workspace().set_column_width(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_window_height(&mut self, change: SizeChange) {
|
||||||
|
self.active_workspace().set_window_height(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_workspace_down(&mut self) {
|
||||||
|
let new_idx = min(self.active_workspace_idx + 1, self.workspaces.len() - 1);
|
||||||
|
if new_idx == self.active_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.workspaces.swap(self.active_workspace_idx, new_idx);
|
||||||
|
|
||||||
|
if new_idx == self.workspaces.len() - 1 {
|
||||||
|
// Insert a new empty workspace.
|
||||||
|
let ws = Workspace::new(self.output.clone(), self.options.clone());
|
||||||
|
self.workspaces.push(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.activate_workspace(new_idx);
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_workspace_up(&mut self) {
|
||||||
|
let new_idx = self.active_workspace_idx.saturating_sub(1);
|
||||||
|
if new_idx == self.active_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.workspaces.swap(self.active_workspace_idx, new_idx);
|
||||||
|
|
||||||
|
if self.active_workspace_idx == self.workspaces.len() - 1 {
|
||||||
|
// Insert a new empty workspace.
|
||||||
|
let ws = Workspace::new(self.output.clone(), self.options.clone());
|
||||||
|
self.workspaces.push(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.activate_workspace(new_idx);
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_under(
|
||||||
|
&self,
|
||||||
|
pos_within_output: Point<f64, Logical>,
|
||||||
|
) -> Option<(&W, Option<Point<i32, Logical>>)> {
|
||||||
|
match &self.workspace_switch {
|
||||||
|
Some(switch) => {
|
||||||
|
let size = output_size(&self.output);
|
||||||
|
|
||||||
|
let render_idx = switch.current_idx();
|
||||||
|
let before_idx = render_idx.floor() as usize;
|
||||||
|
let after_idx = render_idx.ceil() as usize;
|
||||||
|
|
||||||
|
let offset = ((render_idx - before_idx as f64) * size.h as f64).round() as i32;
|
||||||
|
|
||||||
|
let (idx, ws_offset) = if pos_within_output.y < (size.h - offset) as f64 {
|
||||||
|
(before_idx, Point::from((0, offset)))
|
||||||
|
} else {
|
||||||
|
(after_idx, Point::from((0, -size.h + offset)))
|
||||||
|
};
|
||||||
|
|
||||||
|
let ws = &self.workspaces[idx];
|
||||||
|
let (win, win_pos) = ws.window_under(pos_within_output + ws_offset.to_f64())?;
|
||||||
|
Some((win, win_pos.map(|p| p - ws_offset)))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let ws = &self.workspaces[self.active_workspace_idx];
|
||||||
|
ws.window_under(pos_within_output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_above_top_layer(&self) -> bool {
|
||||||
|
// Render above the top layer only if the view is stationary.
|
||||||
|
if self.workspace_switch.is_some() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ws = &self.workspaces[self.active_workspace_idx];
|
||||||
|
ws.render_above_top_layer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monitor<Window> {
|
||||||
|
pub fn render_elements<R: Renderer + ImportAll>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
) -> Vec<MonitorRenderElement<R>>
|
||||||
|
where
|
||||||
|
<R as Renderer>::TextureId: 'static,
|
||||||
|
{
|
||||||
|
let _span = tracy_client::span!("Monitor::render_elements");
|
||||||
|
|
||||||
|
let output_scale = Scale::from(self.output.current_scale().fractional_scale());
|
||||||
|
let output_transform = self.output.current_transform();
|
||||||
|
let output_mode = self.output.current_mode().unwrap();
|
||||||
|
let size = output_transform.transform_size(output_mode.size);
|
||||||
|
|
||||||
|
match &self.workspace_switch {
|
||||||
|
Some(switch) => {
|
||||||
|
let render_idx = switch.current_idx();
|
||||||
|
let before_idx = render_idx.floor() as usize;
|
||||||
|
let after_idx = render_idx.ceil() as usize;
|
||||||
|
|
||||||
|
let offset = ((render_idx - before_idx as f64) * size.h as f64).round() as i32;
|
||||||
|
|
||||||
|
let before = self.workspaces[before_idx].render_elements(renderer);
|
||||||
|
let after = self.workspaces[after_idx].render_elements(renderer);
|
||||||
|
|
||||||
|
let before = before.into_iter().filter_map(|elem| {
|
||||||
|
Some(RelocateRenderElement::from_element(
|
||||||
|
CropRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
output_scale,
|
||||||
|
Rectangle::from_extemities((0, offset), (size.w, size.h)),
|
||||||
|
)?,
|
||||||
|
(0, -offset),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
let after = after.into_iter().filter_map(|elem| {
|
||||||
|
Some(RelocateRenderElement::from_element(
|
||||||
|
CropRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
output_scale,
|
||||||
|
Rectangle::from_extemities((0, 0), (size.w, offset)),
|
||||||
|
)?,
|
||||||
|
(0, -offset + size.h),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
before.chain(after).collect()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let elements = self.workspaces[self.active_workspace_idx].render_elements(renderer);
|
||||||
|
elements
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|elem| {
|
||||||
|
Some(RelocateRenderElement::from_element(
|
||||||
|
CropRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
output_scale,
|
||||||
|
// HACK: set infinite crop bounds due to a damage tracking bug
|
||||||
|
// which causes glitched rendering for maximized GTK windows.
|
||||||
|
// FIXME: use proper bounds after fixing the Crop element.
|
||||||
|
Rectangle::from_loc_and_size(
|
||||||
|
(-i32::MAX / 2, -i32::MAX / 2),
|
||||||
|
(i32::MAX, i32::MAX),
|
||||||
|
),
|
||||||
|
// Rectangle::from_loc_and_size((0, 0), size),
|
||||||
|
)?,
|
||||||
|
(0, 0),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
use std::cmp::max;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
|
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
|
||||||
|
use smithay::backend::renderer::element::Kind;
|
||||||
|
use smithay::backend::renderer::{ImportAll, Renderer};
|
||||||
|
use smithay::utils::{Logical, Point, Rectangle, Scale, Size};
|
||||||
|
|
||||||
|
use super::focus_ring::FocusRing;
|
||||||
|
use super::workspace::WorkspaceRenderElement;
|
||||||
|
use super::{LayoutElement, Options};
|
||||||
|
|
||||||
|
/// Toplevel window with decorations.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Tile<W: LayoutElement> {
|
||||||
|
/// The toplevel window itself.
|
||||||
|
window: W,
|
||||||
|
|
||||||
|
/// The border around the window.
|
||||||
|
border: FocusRing,
|
||||||
|
|
||||||
|
/// Whether this tile is fullscreen.
|
||||||
|
///
|
||||||
|
/// This will update only when the `window` actually goes fullscreen, rather than right away,
|
||||||
|
/// to avoid black backdrop flicker before the window has had a chance to resize.
|
||||||
|
is_fullscreen: bool,
|
||||||
|
|
||||||
|
/// The black backdrop for fullscreen windows.
|
||||||
|
fullscreen_backdrop: SolidColorBuffer,
|
||||||
|
|
||||||
|
/// The size we were requested to fullscreen into.
|
||||||
|
fullscreen_size: Size<i32, Logical>,
|
||||||
|
|
||||||
|
/// Configurable properties of the layout.
|
||||||
|
options: Rc<Options>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: LayoutElement> Tile<W> {
|
||||||
|
pub fn new(window: W, options: Rc<Options>) -> Self {
|
||||||
|
Self {
|
||||||
|
window,
|
||||||
|
border: FocusRing::new(options.border),
|
||||||
|
is_fullscreen: false, // FIXME: up-to-date fullscreen right away, but we need size.
|
||||||
|
fullscreen_backdrop: SolidColorBuffer::new((0, 0), [0., 0., 0., 1.]),
|
||||||
|
fullscreen_size: Default::default(),
|
||||||
|
options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_config(&mut self, options: Rc<Options>) {
|
||||||
|
self.border.update_config(options.border);
|
||||||
|
self.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_window(&mut self) {
|
||||||
|
// FIXME: remove when we can get a fullscreen size right away.
|
||||||
|
if self.fullscreen_size != Size::from((0, 0)) {
|
||||||
|
self.is_fullscreen = self.window.is_fullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn advance_animations(&mut self, _current_time: Duration, is_active: bool) {
|
||||||
|
let width = self.border.width();
|
||||||
|
self.border.update(
|
||||||
|
(width, width).into(),
|
||||||
|
self.window.size(),
|
||||||
|
self.window.has_ssd(),
|
||||||
|
);
|
||||||
|
self.border.set_active(is_active);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window(&self) -> &W {
|
||||||
|
&self.window
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_window(self) -> W {
|
||||||
|
self.window
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `None` if the border is hidden and `Some(width)` if it should be shown.
|
||||||
|
fn effective_border_width(&self) -> Option<i32> {
|
||||||
|
if self.is_fullscreen {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.border.is_off() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self.border.width())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the location of the window's visual geometry within this Tile.
|
||||||
|
pub fn window_loc(&self) -> Point<i32, Logical> {
|
||||||
|
let mut loc = Point::from((0, 0));
|
||||||
|
|
||||||
|
// In fullscreen, center the window in the given size.
|
||||||
|
if self.is_fullscreen {
|
||||||
|
let window_size = self.window.size();
|
||||||
|
let target_size = self.fullscreen_size;
|
||||||
|
|
||||||
|
// Windows aren't supposed to be larger than the fullscreen size, but in case we get
|
||||||
|
// one, leave it at the top-left as usual.
|
||||||
|
if window_size.w < target_size.w {
|
||||||
|
loc.x += (target_size.w - window_size.w) / 2;
|
||||||
|
}
|
||||||
|
if window_size.h < target_size.h {
|
||||||
|
loc.y += (target_size.h - window_size.h) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(width) = self.effective_border_width() {
|
||||||
|
loc += (width, width).into();
|
||||||
|
}
|
||||||
|
|
||||||
|
loc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_size(&self) -> Size<i32, Logical> {
|
||||||
|
let mut size = self.window.size();
|
||||||
|
|
||||||
|
if self.is_fullscreen {
|
||||||
|
// Normally we'd just return the fullscreen size here, but this makes things a bit
|
||||||
|
// nicer if a fullscreen window is bigger than the fullscreen size for some reason.
|
||||||
|
size.w = max(size.w, self.fullscreen_size.w);
|
||||||
|
size.h = max(size.h, self.fullscreen_size.h);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(width) = self.effective_border_width() {
|
||||||
|
size.w = size.w.saturating_add(width * 2);
|
||||||
|
size.h = size.h.saturating_add(width * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_size(&self) -> Size<i32, Logical> {
|
||||||
|
self.window.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn buf_loc(&self) -> Point<i32, Logical> {
|
||||||
|
let mut loc = Point::from((0, 0));
|
||||||
|
loc += self.window_loc();
|
||||||
|
loc += self.window.buf_loc();
|
||||||
|
loc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_input_region(&self, mut point: Point<f64, Logical>) -> bool {
|
||||||
|
point -= self.window_loc().to_f64();
|
||||||
|
self.window.is_in_input_region(point)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_activation_region(&self, point: Point<f64, Logical>) -> bool {
|
||||||
|
let activation_region = Rectangle::from_loc_and_size((0, 0), self.tile_size());
|
||||||
|
activation_region.to_f64().contains(point)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_tile_size(&mut self, mut size: Size<i32, Logical>) {
|
||||||
|
// Can't go through effective_border_width() because we might be fullscreen.
|
||||||
|
if !self.border.is_off() {
|
||||||
|
let width = self.border.width();
|
||||||
|
size.w = max(1, size.w - width * 2);
|
||||||
|
size.h = max(1, size.h - width * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.window.request_size(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_width_for_window_width(&self, size: i32) -> i32 {
|
||||||
|
if self.border.is_off() {
|
||||||
|
size
|
||||||
|
} else {
|
||||||
|
size.saturating_add(self.border.width() * 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_height_for_window_height(&self, size: i32) -> i32 {
|
||||||
|
if self.border.is_off() {
|
||||||
|
size
|
||||||
|
} else {
|
||||||
|
size.saturating_add(self.border.width() * 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_height_for_tile_height(&self, size: i32) -> i32 {
|
||||||
|
if self.border.is_off() {
|
||||||
|
size
|
||||||
|
} else {
|
||||||
|
size.saturating_sub(self.border.width() * 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_fullscreen(&mut self, size: Size<i32, Logical>) {
|
||||||
|
self.fullscreen_backdrop.resize(size);
|
||||||
|
self.fullscreen_size = size;
|
||||||
|
self.window.request_fullscreen(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min_size(&self) -> Size<i32, Logical> {
|
||||||
|
let mut size = self.window.min_size();
|
||||||
|
|
||||||
|
if let Some(width) = self.effective_border_width() {
|
||||||
|
size.w = max(1, size.w);
|
||||||
|
size.h = max(1, size.h);
|
||||||
|
|
||||||
|
size.w = size.w.saturating_add(width * 2);
|
||||||
|
size.h = size.h.saturating_add(width * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_size(&self) -> Size<i32, Logical> {
|
||||||
|
let mut size = self.window.max_size();
|
||||||
|
|
||||||
|
if let Some(width) = self.effective_border_width() {
|
||||||
|
if size.w > 0 {
|
||||||
|
size.w = size.w.saturating_add(width * 2);
|
||||||
|
}
|
||||||
|
if size.h > 0 {
|
||||||
|
size.h = size.h.saturating_add(width * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_ssd(&self) -> bool {
|
||||||
|
self.effective_border_width().is_some() || self.window.has_ssd()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<R: Renderer + ImportAll>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
location: Point<i32, Logical>,
|
||||||
|
scale: Scale<f64>,
|
||||||
|
) -> Vec<WorkspaceRenderElement<R>>
|
||||||
|
where
|
||||||
|
<R as Renderer>::TextureId: 'static,
|
||||||
|
{
|
||||||
|
let mut rv = Vec::new();
|
||||||
|
|
||||||
|
let window_pos = location + self.window_loc();
|
||||||
|
rv.extend(self.window.render(renderer, window_pos, scale));
|
||||||
|
|
||||||
|
if self.effective_border_width().is_some() {
|
||||||
|
rv.extend(
|
||||||
|
self.border
|
||||||
|
.render(scale)
|
||||||
|
.map(|elem| {
|
||||||
|
RelocateRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
location.to_physical_precise_round(scale),
|
||||||
|
Relocate::Relative,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(Into::into),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_fullscreen {
|
||||||
|
let elem = SolidColorRenderElement::from_buffer(
|
||||||
|
&self.fullscreen_backdrop,
|
||||||
|
location.to_physical_precise_round(scale),
|
||||||
|
scale,
|
||||||
|
1.,
|
||||||
|
Kind::Unspecified,
|
||||||
|
);
|
||||||
|
rv.push(elem.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
rv
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
+9
-8
@@ -3,7 +3,6 @@ extern crate tracing;
|
|||||||
|
|
||||||
mod animation;
|
mod animation;
|
||||||
mod backend;
|
mod backend;
|
||||||
mod config;
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
#[cfg(feature = "dbus")]
|
#[cfg(feature = "dbus")]
|
||||||
mod dbus;
|
mod dbus;
|
||||||
@@ -12,6 +11,7 @@ mod handlers;
|
|||||||
mod input;
|
mod input;
|
||||||
mod layout;
|
mod layout;
|
||||||
mod niri;
|
mod niri;
|
||||||
|
mod render_helpers;
|
||||||
mod screenshot_ui;
|
mod screenshot_ui;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod watcher;
|
mod watcher;
|
||||||
@@ -27,12 +27,11 @@ use std::process::Command;
|
|||||||
use std::{env, mem};
|
use std::{env, mem};
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use config::Config;
|
|
||||||
#[cfg(not(feature = "xdp-gnome-screencast"))]
|
#[cfg(not(feature = "xdp-gnome-screencast"))]
|
||||||
use dummy_pw_utils as pw_utils;
|
use dummy_pw_utils as pw_utils;
|
||||||
use git_version::git_version;
|
use git_version::git_version;
|
||||||
use miette::{Context, NarratableReportHandler};
|
|
||||||
use niri::{Niri, State};
|
use niri::{Niri, State};
|
||||||
|
use niri_config::Config;
|
||||||
use portable_atomic::Ordering;
|
use portable_atomic::Ordering;
|
||||||
use sd_notify::NotifyState;
|
use sd_notify::NotifyState;
|
||||||
use smithay::reexports::calloop::{self, EventLoop};
|
use smithay::reexports::calloop::{self, EventLoop};
|
||||||
@@ -109,13 +108,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let _client = tracy_client::Client::start();
|
let _client = tracy_client::Client::start();
|
||||||
|
|
||||||
// Set a better error printer for config loading.
|
// Set a better error printer for config loading.
|
||||||
miette::set_hook(Box::new(|_| Box::new(NarratableReportHandler::new()))).unwrap();
|
niri_config::set_miette_hook().unwrap();
|
||||||
|
|
||||||
// Handle subcommands.
|
// Handle subcommands.
|
||||||
if let Some(subcommand) = cli.subcommand {
|
if let Some(subcommand) = cli.subcommand {
|
||||||
match subcommand {
|
match subcommand {
|
||||||
Sub::Validate { config } => {
|
Sub::Validate { config } => {
|
||||||
Config::load(config).context("error loading config")?;
|
Config::load(config)?;
|
||||||
info!("config is valid");
|
info!("config is valid");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -129,7 +128,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Load the config.
|
// Load the config.
|
||||||
let (mut config, path) = match Config::load(cli.config).context("error loading config") {
|
let (mut config, path) = match Config::load(cli.config) {
|
||||||
Ok((config, path)) => (config, Some(path)),
|
Ok((config, path)) => (config, Some(path)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("{err:?}");
|
warn!("{err:?}");
|
||||||
@@ -163,8 +162,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
// Inhibit power key handling so we can suspend on it.
|
// Inhibit power key handling so we can suspend on it.
|
||||||
#[cfg(feature = "dbus")]
|
#[cfg(feature = "dbus")]
|
||||||
if let Err(err) = state.niri.inhibit_power_key() {
|
if !state.niri.config.borrow().input.disable_power_key_handling {
|
||||||
warn!("error inhibiting power key: {err:?}");
|
if let Err(err) = state.niri.inhibit_power_key() {
|
||||||
|
warn!("error inhibiting power key: {err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+379
-130
@@ -10,19 +10,24 @@ use std::{env, mem, thread};
|
|||||||
|
|
||||||
use _server_decoration::server::org_kde_kwin_server_decoration_manager::Mode as KdeDecorationsMode;
|
use _server_decoration::server::org_kde_kwin_server_decoration_manager::Mode as KdeDecorationsMode;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use niri_config::{Config, TrackLayout};
|
||||||
use smithay::backend::allocator::Fourcc;
|
use smithay::backend::allocator::Fourcc;
|
||||||
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use smithay::backend::renderer::element::surface::{
|
use smithay::backend::renderer::element::surface::{
|
||||||
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
|
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
|
||||||
};
|
};
|
||||||
use smithay::backend::renderer::element::texture::TextureRenderElement;
|
use smithay::backend::renderer::element::texture::TextureRenderElement;
|
||||||
|
use smithay::backend::renderer::element::utils::select_dmabuf_feedback;
|
||||||
use smithay::backend::renderer::element::{
|
use smithay::backend::renderer::element::{
|
||||||
default_primary_scanout_output_compare, render_elements, AsRenderElements, Kind, RenderElement,
|
default_primary_scanout_output_compare, AsRenderElements, Element, Id, Kind, RenderElement,
|
||||||
RenderElementStates,
|
RenderElementStates, UnderlyingStorage,
|
||||||
|
};
|
||||||
|
use smithay::backend::renderer::gles::{
|
||||||
|
GlesError, GlesFrame, GlesMapping, GlesRenderer, GlesTexture,
|
||||||
};
|
};
|
||||||
use smithay::backend::renderer::gles::{GlesMapping, GlesRenderer, GlesTexture};
|
|
||||||
use smithay::backend::renderer::sync::SyncPoint;
|
use smithay::backend::renderer::sync::SyncPoint;
|
||||||
use smithay::backend::renderer::{Bind, ExportMem, Frame, ImportAll, Offscreen, Renderer};
|
use smithay::backend::renderer::utils::CommitCounter;
|
||||||
|
use smithay::backend::renderer::{Bind, ExportMem, Frame, Offscreen, Renderer};
|
||||||
use smithay::desktop::utils::{
|
use smithay::desktop::utils::{
|
||||||
bbox_from_surface_tree, output_update, send_dmabuf_feedback_surface_tree,
|
bbox_from_surface_tree, output_update, send_dmabuf_feedback_surface_tree,
|
||||||
send_frames_surface_tree, surface_presentation_feedback_flags_from_states,
|
send_frames_surface_tree, surface_presentation_feedback_flags_from_states,
|
||||||
@@ -50,7 +55,7 @@ use smithay::reexports::wayland_server::backend::{
|
|||||||
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||||
use smithay::reexports::wayland_server::{Display, DisplayHandle};
|
use smithay::reexports::wayland_server::{Display, DisplayHandle};
|
||||||
use smithay::utils::{
|
use smithay::utils::{
|
||||||
ClockSource, Logical, Monotonic, Physical, Point, Rectangle, Scale, Size, Transform,
|
Buffer, ClockSource, Logical, Monotonic, Physical, Point, Rectangle, Scale, Size, Transform,
|
||||||
SERIAL_COUNTER,
|
SERIAL_COUNTER,
|
||||||
};
|
};
|
||||||
use smithay::wayland::compositor::{
|
use smithay::wayland::compositor::{
|
||||||
@@ -58,7 +63,7 @@ use smithay::wayland::compositor::{
|
|||||||
CompositorState, SurfaceData, TraversalAction,
|
CompositorState, SurfaceData, TraversalAction,
|
||||||
};
|
};
|
||||||
use smithay::wayland::cursor_shape::CursorShapeManagerState;
|
use smithay::wayland::cursor_shape::CursorShapeManagerState;
|
||||||
use smithay::wayland::dmabuf::DmabufFeedback;
|
use smithay::wayland::dmabuf::DmabufState;
|
||||||
use smithay::wayland::input_method::InputMethodManagerState;
|
use smithay::wayland::input_method::InputMethodManagerState;
|
||||||
use smithay::wayland::output::OutputManagerState;
|
use smithay::wayland::output::OutputManagerState;
|
||||||
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraintsState};
|
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraintsState};
|
||||||
@@ -80,8 +85,8 @@ use smithay::wayland::text_input::TextInputManagerState;
|
|||||||
use smithay::wayland::virtual_keyboard::VirtualKeyboardManagerState;
|
use smithay::wayland::virtual_keyboard::VirtualKeyboardManagerState;
|
||||||
|
|
||||||
use crate::animation;
|
use crate::animation;
|
||||||
|
use crate::backend::tty::{SurfaceDmabufFeedback, TtyFrame, TtyRenderer, TtyRendererError};
|
||||||
use crate::backend::{Backend, RenderResult, Tty, Winit};
|
use crate::backend::{Backend, RenderResult, Tty, Winit};
|
||||||
use crate::config::{Config, TrackLayout};
|
|
||||||
use crate::cursor::{CursorManager, CursorTextureCache, RenderCursor, XCursor};
|
use crate::cursor::{CursorManager, CursorTextureCache, RenderCursor, XCursor};
|
||||||
#[cfg(feature = "dbus")]
|
#[cfg(feature = "dbus")]
|
||||||
use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri};
|
use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri};
|
||||||
@@ -90,10 +95,13 @@ use crate::dbus::mutter_screen_cast::{self, ScreenCastToNiri};
|
|||||||
use crate::frame_clock::FrameClock;
|
use crate::frame_clock::FrameClock;
|
||||||
use crate::handlers::configure_lock_surface;
|
use crate::handlers::configure_lock_surface;
|
||||||
use crate::input::TabletData;
|
use crate::input::TabletData;
|
||||||
use crate::layout::{output_size, Layout, MonitorRenderElement};
|
use crate::layout::{Layout, MonitorRenderElement};
|
||||||
use crate::pw_utils::{Cast, PipeWire};
|
use crate::pw_utils::{Cast, PipeWire};
|
||||||
|
use crate::render_helpers::{NiriRenderer, PrimaryGpuTextureRenderElement};
|
||||||
use crate::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement};
|
use crate::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement};
|
||||||
use crate::utils::{center, get_monotonic_time, make_screenshot_path, write_png_rgba8};
|
use crate::utils::{
|
||||||
|
center, get_monotonic_time, make_screenshot_path, output_size, write_png_rgba8,
|
||||||
|
};
|
||||||
|
|
||||||
const CLEAR_COLOR: [f32; 4] = [0.2, 0.2, 0.2, 1.];
|
const CLEAR_COLOR: [f32; 4] = [0.2, 0.2, 0.2, 1.];
|
||||||
const CLEAR_COLOR_LOCKED: [f32; 4] = [0.3, 0.1, 0.1, 1.];
|
const CLEAR_COLOR_LOCKED: [f32; 4] = [0.3, 0.1, 0.1, 1.];
|
||||||
@@ -136,6 +144,7 @@ pub struct Niri {
|
|||||||
pub session_lock_state: SessionLockManagerState,
|
pub session_lock_state: SessionLockManagerState,
|
||||||
pub shm_state: ShmState,
|
pub shm_state: ShmState,
|
||||||
pub output_manager_state: OutputManagerState,
|
pub output_manager_state: OutputManagerState,
|
||||||
|
pub dmabuf_state: DmabufState,
|
||||||
pub seat_state: SeatState<State>,
|
pub seat_state: SeatState<State>,
|
||||||
pub tablet_state: TabletManagerState,
|
pub tablet_state: TabletManagerState,
|
||||||
pub text_input_state: TextInputManagerState,
|
pub text_input_state: TextInputManagerState,
|
||||||
@@ -577,31 +586,32 @@ impl State {
|
|||||||
let ScreenshotToNiri::TakeScreenshot { include_cursor } = msg;
|
let ScreenshotToNiri::TakeScreenshot { include_cursor } = msg;
|
||||||
let _span = tracy_client::span!("TakeScreenshot");
|
let _span = tracy_client::span!("TakeScreenshot");
|
||||||
|
|
||||||
let Some(renderer) = self.backend.renderer() else {
|
let rv = self.backend.with_primary_renderer(|renderer| {
|
||||||
let msg = NiriToScreenshot::ScreenshotResult(None);
|
let on_done = {
|
||||||
if let Err(err) = to_screenshot.send_blocking(msg) {
|
let to_screenshot = to_screenshot.clone();
|
||||||
warn!("error sending None to screenshot: {err:?}");
|
move |path| {
|
||||||
}
|
let msg = NiriToScreenshot::ScreenshotResult(Some(path));
|
||||||
return;
|
if let Err(err) = to_screenshot.send_blocking(msg) {
|
||||||
};
|
warn!("error sending path to screenshot: {err:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let on_done = {
|
let res = self
|
||||||
let to_screenshot = to_screenshot.clone();
|
.niri
|
||||||
move |path| {
|
.screenshot_all_outputs(renderer, include_cursor, on_done);
|
||||||
let msg = NiriToScreenshot::ScreenshotResult(Some(path));
|
|
||||||
|
if let Err(err) = res {
|
||||||
|
warn!("error taking a screenshot: {err:?}");
|
||||||
|
|
||||||
|
let msg = NiriToScreenshot::ScreenshotResult(None);
|
||||||
if let Err(err) = to_screenshot.send_blocking(msg) {
|
if let Err(err) = to_screenshot.send_blocking(msg) {
|
||||||
warn!("error sending path to screenshot: {err:?}");
|
warn!("error sending None to screenshot: {err:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
let res = self
|
|
||||||
.niri
|
|
||||||
.screenshot_all_outputs(renderer, include_cursor, on_done);
|
|
||||||
|
|
||||||
if let Err(err) = res {
|
|
||||||
warn!("error taking a screenshot: {err:?}");
|
|
||||||
|
|
||||||
|
if rv.is_none() {
|
||||||
let msg = NiriToScreenshot::ScreenshotResult(None);
|
let msg = NiriToScreenshot::ScreenshotResult(None);
|
||||||
if let Err(err) = to_screenshot.send_blocking(msg) {
|
if let Err(err) = to_screenshot.send_blocking(msg) {
|
||||||
warn!("error sending None to screenshot: {err:?}");
|
warn!("error sending None to screenshot: {err:?}");
|
||||||
@@ -645,6 +655,7 @@ impl Niri {
|
|||||||
let shm_state = ShmState::new::<State>(&display_handle, vec![]);
|
let shm_state = ShmState::new::<State>(&display_handle, vec![]);
|
||||||
let output_manager_state =
|
let output_manager_state =
|
||||||
OutputManagerState::new_with_xdg_output::<State>(&display_handle);
|
OutputManagerState::new_with_xdg_output::<State>(&display_handle);
|
||||||
|
let dmabuf_state = DmabufState::new();
|
||||||
let mut seat_state = SeatState::new();
|
let mut seat_state = SeatState::new();
|
||||||
let tablet_state = TabletManagerState::new::<State>(&display_handle);
|
let tablet_state = TabletManagerState::new::<State>(&display_handle);
|
||||||
let pointer_gestures_state = PointerGesturesState::new::<State>(&display_handle);
|
let pointer_gestures_state = PointerGesturesState::new::<State>(&display_handle);
|
||||||
@@ -758,6 +769,7 @@ impl Niri {
|
|||||||
virtual_keyboard_state,
|
virtual_keyboard_state,
|
||||||
shm_state,
|
shm_state,
|
||||||
output_manager_state,
|
output_manager_state,
|
||||||
|
dmabuf_state,
|
||||||
seat_state,
|
seat_state,
|
||||||
tablet_state,
|
tablet_state,
|
||||||
pointer_gestures_state,
|
pointer_gestures_state,
|
||||||
@@ -1033,6 +1045,10 @@ impl Niri {
|
|||||||
Some((output, pos_within_output))
|
Some((output, pos_within_output))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the window under the position to be activated.
|
||||||
|
///
|
||||||
|
/// The cursor may be inside the window's activation region, but not within the window's input
|
||||||
|
/// region.
|
||||||
pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<&Window> {
|
pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<&Window> {
|
||||||
if self.is_locked() || self.screenshot_ui.is_open() {
|
if self.is_locked() || self.screenshot_ui.is_open() {
|
||||||
return None;
|
return None;
|
||||||
@@ -1043,6 +1059,10 @@ impl Niri {
|
|||||||
Some(window)
|
Some(window)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the window under the cursor to be activated.
|
||||||
|
///
|
||||||
|
/// The cursor may be inside the window's activation region, but not within the window's input
|
||||||
|
/// region.
|
||||||
pub fn window_under_cursor(&self) -> Option<&Window> {
|
pub fn window_under_cursor(&self) -> Option<&Window> {
|
||||||
let pos = self.seat.get_pointer().unwrap().current_location();
|
let pos = self.seat.get_pointer().unwrap().current_location();
|
||||||
self.window_under(pos)
|
self.window_under(pos)
|
||||||
@@ -1101,6 +1121,7 @@ impl Niri {
|
|||||||
self.layout
|
self.layout
|
||||||
.window_under(output, pos_within_output)
|
.window_under(output, pos_within_output)
|
||||||
.and_then(|(window, win_pos_within_output)| {
|
.and_then(|(window, win_pos_within_output)| {
|
||||||
|
let win_pos_within_output = win_pos_within_output?;
|
||||||
window
|
window
|
||||||
.surface_under(
|
.surface_under(
|
||||||
pos_within_output - win_pos_within_output.to_f64(),
|
pos_within_output - win_pos_within_output.to_f64(),
|
||||||
@@ -1220,7 +1241,7 @@ impl Niri {
|
|||||||
.or_else(|| self.global_space.outputs().next())
|
.or_else(|| self.global_space.outputs().next())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn output_for_root(&self, root: &WlSurface) -> Option<Output> {
|
pub fn output_for_root(&self, root: &WlSurface) -> Option<&Output> {
|
||||||
// Check the main layout.
|
// Check the main layout.
|
||||||
let win_out = self.layout.find_window_and_output(root);
|
let win_out = self.layout.find_window_and_output(root);
|
||||||
let layout_output = win_out.map(|(_, output)| output);
|
let layout_output = win_out.map(|(_, output)| output);
|
||||||
@@ -1231,7 +1252,7 @@ impl Niri {
|
|||||||
.layer_for_surface(root, WindowSurfaceType::TOPLEVEL)
|
.layer_for_surface(root, WindowSurfaceType::TOPLEVEL)
|
||||||
.is_some()
|
.is_some()
|
||||||
};
|
};
|
||||||
let layer_shell_output = || self.layout.outputs().find(has_layer_surface).cloned();
|
let layer_shell_output = || self.layout.outputs().find(has_layer_surface);
|
||||||
|
|
||||||
layout_output.or_else(layer_shell_output)
|
layout_output.or_else(layer_shell_output)
|
||||||
}
|
}
|
||||||
@@ -1288,11 +1309,11 @@ impl Niri {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pointer_element(
|
pub fn pointer_element<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut R,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> Vec<OutputRenderElements<GlesRenderer>> {
|
) -> Vec<OutputRenderElements<R>> {
|
||||||
let _span = tracy_client::span!("Niri::pointer_element");
|
let _span = tracy_client::span!("Niri::pointer_element");
|
||||||
let output_scale = output.current_scale();
|
let output_scale = output.current_scale();
|
||||||
let output_pos = self.global_space.output_geometry(output).unwrap().loc;
|
let output_pos = self.global_space.output_geometry(output).unwrap().loc;
|
||||||
@@ -1336,19 +1357,23 @@ impl Niri {
|
|||||||
let pointer_pos =
|
let pointer_pos =
|
||||||
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
|
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
|
||||||
|
|
||||||
let texture = self
|
let texture = self.cursor_texture_cache.get(
|
||||||
.cursor_texture_cache
|
renderer.as_gles_renderer(),
|
||||||
.get(renderer, icon, scale, &cursor, idx);
|
icon,
|
||||||
|
scale,
|
||||||
|
&cursor,
|
||||||
|
idx,
|
||||||
|
);
|
||||||
|
|
||||||
let pointer_elements = vec![OutputRenderElements::NamedPointer(
|
let pointer_elements = vec![OutputRenderElements::NamedPointer(
|
||||||
TextureRenderElement::from_texture_buffer(
|
PrimaryGpuTextureRenderElement(TextureRenderElement::from_texture_buffer(
|
||||||
pointer_pos.to_f64(),
|
pointer_pos.to_f64(),
|
||||||
&texture,
|
&texture,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Kind::Cursor,
|
Kind::Cursor,
|
||||||
),
|
)),
|
||||||
)];
|
)];
|
||||||
|
|
||||||
(pointer_elements, pointer_pos)
|
(pointer_elements, pointer_pos)
|
||||||
@@ -1481,12 +1506,12 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(
|
pub fn render<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut R,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
include_pointer: bool,
|
include_pointer: bool,
|
||||||
) -> Vec<OutputRenderElements<GlesRenderer>> {
|
) -> Vec<OutputRenderElements<R>> {
|
||||||
let _span = tracy_client::span!("Niri::render");
|
let _span = tracy_client::span!("Niri::render");
|
||||||
|
|
||||||
let output_scale = Scale::from(output.current_scale().fractional_scale());
|
let output_scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
@@ -1558,8 +1583,7 @@ impl Niri {
|
|||||||
|
|
||||||
// Get layer-shell elements.
|
// Get layer-shell elements.
|
||||||
let layer_map = layer_map_for_output(output);
|
let layer_map = layer_map_for_output(output);
|
||||||
let mut extend_from_layer = |elements: &mut Vec<OutputRenderElements<GlesRenderer>>,
|
let mut extend_from_layer = |elements: &mut Vec<OutputRenderElements<R>>, layer| {
|
||||||
layer| {
|
|
||||||
let iter = layer_map
|
let iter = layer_map
|
||||||
.layers_on(layer)
|
.layers_on(layer)
|
||||||
.filter_map(|surface| {
|
.filter_map(|surface| {
|
||||||
@@ -1606,75 +1630,50 @@ impl Niri {
|
|||||||
fn redraw(&mut self, backend: &mut Backend, output: &Output) {
|
fn redraw(&mut self, backend: &mut Backend, output: &Output) {
|
||||||
let _span = tracy_client::span!("Niri::redraw");
|
let _span = tracy_client::span!("Niri::redraw");
|
||||||
|
|
||||||
let monitors_active = self.monitors_active;
|
// Verify our invariant.
|
||||||
|
|
||||||
let state = self.output_state.get_mut(output).unwrap();
|
let state = self.output_state.get_mut(output).unwrap();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
state.redraw_state,
|
state.redraw_state,
|
||||||
RedrawState::Queued(_) | RedrawState::WaitingForEstimatedVBlankAndQueued(_)
|
RedrawState::Queued(_) | RedrawState::WaitingForEstimatedVBlankAndQueued(_)
|
||||||
));
|
));
|
||||||
|
|
||||||
// FIXME: make this not cursed.
|
let target_presentation_time = state.frame_clock.next_presentation_time();
|
||||||
let mut reset = || {
|
|
||||||
let state = self.output_state.get_mut(output).unwrap();
|
let mut res = RenderResult::Skipped;
|
||||||
|
if self.monitors_active {
|
||||||
|
// Update from the config and advance the animations.
|
||||||
|
self.layout.advance_animations(target_presentation_time);
|
||||||
|
state.unfinished_animations_remain = self
|
||||||
|
.layout
|
||||||
|
.monitor_for_output(output)
|
||||||
|
.unwrap()
|
||||||
|
.are_animations_ongoing();
|
||||||
|
|
||||||
|
// Also keep redrawing if the current cursor is animated.
|
||||||
|
state.unfinished_animations_remain |= self
|
||||||
|
.cursor_manager
|
||||||
|
.is_current_cursor_animated(output.current_scale().integer_scale());
|
||||||
|
|
||||||
|
// Render.
|
||||||
|
res = backend.render(self, output, target_presentation_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_locked = self.is_locked();
|
||||||
|
let state = self.output_state.get_mut(output).unwrap();
|
||||||
|
|
||||||
|
if res == RenderResult::Skipped {
|
||||||
|
// Update the redraw state on failed render.
|
||||||
state.redraw_state =
|
state.redraw_state =
|
||||||
if let RedrawState::WaitingForEstimatedVBlankAndQueued((token, _)) =
|
if let RedrawState::WaitingForEstimatedVBlank(token)
|
||||||
|
| RedrawState::WaitingForEstimatedVBlankAndQueued((token, _)) =
|
||||||
state.redraw_state
|
state.redraw_state
|
||||||
{
|
{
|
||||||
RedrawState::WaitingForEstimatedVBlank(token)
|
RedrawState::WaitingForEstimatedVBlank(token)
|
||||||
} else {
|
} else {
|
||||||
RedrawState::Idle
|
RedrawState::Idle
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
if matches!(self.lock_state, LockState::Locking { .. })
|
// Update the lock render state on successful render.
|
||||||
&& state.lock_render_state == LockRenderState::Unlocked
|
|
||||||
{
|
|
||||||
// We needed to redraw this output for locking and failed.
|
|
||||||
self.unlock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !monitors_active {
|
|
||||||
reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !backend.is_active() {
|
|
||||||
reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(renderer) = backend.renderer() else {
|
|
||||||
reset();
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let state = self.output_state.get_mut(output).unwrap();
|
|
||||||
let target_presentation_time = state.frame_clock.next_presentation_time();
|
|
||||||
|
|
||||||
// Update from the config and advance the animations.
|
|
||||||
self.layout.advance_animations(target_presentation_time);
|
|
||||||
state.unfinished_animations_remain = self
|
|
||||||
.layout
|
|
||||||
.monitor_for_output(output)
|
|
||||||
.unwrap()
|
|
||||||
.are_animations_ongoing();
|
|
||||||
|
|
||||||
// Also keep redrawing if the current cursor is animated.
|
|
||||||
state.unfinished_animations_remain |= self
|
|
||||||
.cursor_manager
|
|
||||||
.is_current_cursor_animated(output.current_scale().integer_scale());
|
|
||||||
|
|
||||||
// Render the elements.
|
|
||||||
let elements = self.render(renderer, output, true);
|
|
||||||
|
|
||||||
// Hand it over to the backend.
|
|
||||||
let res = backend.render(self, output, &elements, target_presentation_time);
|
|
||||||
|
|
||||||
// Update the lock render state on successful render.
|
|
||||||
let is_locked = self.is_locked();
|
|
||||||
let state = self.output_state.get_mut(output).unwrap();
|
|
||||||
if res != RenderResult::Error {
|
|
||||||
state.lock_render_state = if is_locked {
|
state.lock_render_state = if is_locked {
|
||||||
LockRenderState::Locked
|
LockRenderState::Locked
|
||||||
} else {
|
} else {
|
||||||
@@ -1685,7 +1684,7 @@ impl Niri {
|
|||||||
// If we're in process of locking the session, check if the requirements were met.
|
// If we're in process of locking the session, check if the requirements were met.
|
||||||
match mem::take(&mut self.lock_state) {
|
match mem::take(&mut self.lock_state) {
|
||||||
LockState::Locking(confirmation) => {
|
LockState::Locking(confirmation) => {
|
||||||
if res == RenderResult::Error {
|
if res == RenderResult::Skipped {
|
||||||
if state.lock_render_state == LockRenderState::Unlocked {
|
if state.lock_render_state == LockRenderState::Unlocked {
|
||||||
// We needed to render a locked frame on this output but failed.
|
// We needed to render a locked frame on this output but failed.
|
||||||
self.unlock();
|
self.unlock();
|
||||||
@@ -1728,10 +1727,9 @@ impl Niri {
|
|||||||
// Render and send to PipeWire screencast streams.
|
// Render and send to PipeWire screencast streams.
|
||||||
#[cfg(feature = "xdp-gnome-screencast")]
|
#[cfg(feature = "xdp-gnome-screencast")]
|
||||||
{
|
{
|
||||||
let renderer = backend
|
backend.with_primary_renderer(|renderer| {
|
||||||
.renderer()
|
self.render_for_screen_cast(renderer, output, target_presentation_time);
|
||||||
.expect("renderer must not have disappeared");
|
});
|
||||||
self.send_for_screen_cast(renderer, output, &elements, target_presentation_time);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1833,18 +1831,45 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_dmabuf_feedbacks(&self, output: &Output, feedback: &DmabufFeedback) {
|
pub fn send_dmabuf_feedbacks(
|
||||||
|
&self,
|
||||||
|
output: &Output,
|
||||||
|
feedback: &SurfaceDmabufFeedback,
|
||||||
|
render_element_states: &RenderElementStates,
|
||||||
|
) {
|
||||||
let _span = tracy_client::span!("Niri::send_dmabuf_feedbacks");
|
let _span = tracy_client::span!("Niri::send_dmabuf_feedbacks");
|
||||||
|
|
||||||
// We can unconditionally send the current output's feedback to regular and layer-shell
|
// We can unconditionally send the current output's feedback to regular and layer-shell
|
||||||
// surfaces, as they can only be displayed on a single output at a time. Even if a surface
|
// surfaces, as they can only be displayed on a single output at a time. Even if a surface
|
||||||
// is currently invisible, this is the DMABUF feedback that it should know about.
|
// is currently invisible, this is the DMABUF feedback that it should know about.
|
||||||
for win in self.layout.windows_for_output(output) {
|
for win in self.layout.windows_for_output(output) {
|
||||||
win.send_dmabuf_feedback(output, |_, _| Some(output.clone()), |_, _| feedback);
|
win.send_dmabuf_feedback(
|
||||||
|
output,
|
||||||
|
|_, _| Some(output.clone()),
|
||||||
|
|surface, _| {
|
||||||
|
select_dmabuf_feedback(
|
||||||
|
surface,
|
||||||
|
render_element_states,
|
||||||
|
&feedback.render,
|
||||||
|
&feedback.scanout,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for surface in layer_map_for_output(output).layers() {
|
for surface in layer_map_for_output(output).layers() {
|
||||||
surface.send_dmabuf_feedback(output, |_, _| Some(output.clone()), |_, _| feedback);
|
surface.send_dmabuf_feedback(
|
||||||
|
output,
|
||||||
|
|_, _| Some(output.clone()),
|
||||||
|
|surface, _| {
|
||||||
|
select_dmabuf_feedback(
|
||||||
|
surface,
|
||||||
|
render_element_states,
|
||||||
|
&feedback.render,
|
||||||
|
&feedback.scanout,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(surface) = &self.output_state[output].lock_surface {
|
if let Some(surface) = &self.output_state[output].lock_surface {
|
||||||
@@ -1852,7 +1877,14 @@ impl Niri {
|
|||||||
surface.wl_surface(),
|
surface.wl_surface(),
|
||||||
output,
|
output,
|
||||||
|_, _| Some(output.clone()),
|
|_, _| Some(output.clone()),
|
||||||
|_, _| feedback,
|
|surface, _| {
|
||||||
|
select_dmabuf_feedback(
|
||||||
|
surface,
|
||||||
|
render_element_states,
|
||||||
|
&feedback.render,
|
||||||
|
&feedback.scanout,
|
||||||
|
)
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1861,7 +1893,14 @@ impl Niri {
|
|||||||
surface,
|
surface,
|
||||||
output,
|
output,
|
||||||
surface_primary_scanout_output,
|
surface_primary_scanout_output,
|
||||||
|_, _| feedback,
|
|surface, _| {
|
||||||
|
select_dmabuf_feedback(
|
||||||
|
surface,
|
||||||
|
render_element_states,
|
||||||
|
&feedback.render,
|
||||||
|
&feedback.scanout,
|
||||||
|
)
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1870,7 +1909,14 @@ impl Niri {
|
|||||||
surface,
|
surface,
|
||||||
output,
|
output,
|
||||||
surface_primary_scanout_output,
|
surface_primary_scanout_output,
|
||||||
|_, _| feedback,
|
|surface, _| {
|
||||||
|
select_dmabuf_feedback(
|
||||||
|
surface,
|
||||||
|
render_element_states,
|
||||||
|
&feedback.render,
|
||||||
|
&feedback.scanout,
|
||||||
|
)
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2010,19 +2056,21 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "xdp-gnome-screencast")]
|
#[cfg(feature = "xdp-gnome-screencast")]
|
||||||
fn send_for_screen_cast(
|
fn render_for_screen_cast(
|
||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
elements: &[OutputRenderElements<GlesRenderer>],
|
|
||||||
target_presentation_time: Duration,
|
target_presentation_time: Duration,
|
||||||
) {
|
) {
|
||||||
let _span = tracy_client::span!("Niri::send_for_screen_cast");
|
let _span = tracy_client::span!("Niri::render_for_screen_cast");
|
||||||
|
|
||||||
let size = output.current_mode().unwrap().size;
|
let size = output.current_mode().unwrap().size;
|
||||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
|
|
||||||
for cast in &mut self.casts {
|
let mut elements = None;
|
||||||
|
|
||||||
|
let mut casts = mem::take(&mut self.casts);
|
||||||
|
for cast in &mut casts {
|
||||||
if !cast.is_active.get() {
|
if !cast.is_active.get() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2068,6 +2116,9 @@ impl Niri {
|
|||||||
let dmabuf = cast.dmabufs.borrow()[&fd].clone();
|
let dmabuf = cast.dmabufs.borrow()[&fd].clone();
|
||||||
|
|
||||||
// FIXME: Hidden / embedded / metadata cursor
|
// FIXME: Hidden / embedded / metadata cursor
|
||||||
|
let elements = elements
|
||||||
|
.get_or_insert_with(|| self.render::<GlesRenderer>(renderer, output, true));
|
||||||
|
|
||||||
if let Err(err) = render_to_dmabuf(renderer, dmabuf, size, scale, elements) {
|
if let Err(err) = render_to_dmabuf(renderer, dmabuf, size, scale, elements) {
|
||||||
error!("error rendering to dmabuf: {err:?}");
|
error!("error rendering to dmabuf: {err:?}");
|
||||||
continue;
|
continue;
|
||||||
@@ -2081,6 +2132,7 @@ impl Niri {
|
|||||||
|
|
||||||
cast.last_frame_time = target_presentation_time;
|
cast.last_frame_time = target_presentation_time;
|
||||||
}
|
}
|
||||||
|
self.casts = casts;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "xdp-gnome-screencast")]
|
#[cfg(feature = "xdp-gnome-screencast")]
|
||||||
@@ -2132,7 +2184,7 @@ impl Niri {
|
|||||||
.filter_map(|output| {
|
.filter_map(|output| {
|
||||||
let size = output.current_mode().unwrap().size;
|
let size = output.current_mode().unwrap().size;
|
||||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
let elements = self.render(renderer, &output, true);
|
let elements = self.render::<GlesRenderer>(renderer, &output, true);
|
||||||
|
|
||||||
let res = render_to_texture(renderer, size, scale, Fourcc::Abgr8888, &elements);
|
let res = render_to_texture(renderer, size, scale, Fourcc::Abgr8888, &elements);
|
||||||
let screenshot = match res {
|
let screenshot = match res {
|
||||||
@@ -2159,7 +2211,7 @@ impl Niri {
|
|||||||
|
|
||||||
let size = output.current_mode().unwrap().size;
|
let size = output.current_mode().unwrap().size;
|
||||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
let elements = self.render(renderer, output, true);
|
let elements = self.render::<GlesRenderer>(renderer, output, true);
|
||||||
let pixels = render_to_vec(renderer, size, scale, Fourcc::Abgr8888, &elements)?;
|
let pixels = render_to_vec(renderer, size, scale, Fourcc::Abgr8888, &elements)?;
|
||||||
|
|
||||||
self.save_screenshot(size, pixels)
|
self.save_screenshot(size, pixels)
|
||||||
@@ -2283,7 +2335,7 @@ impl Niri {
|
|||||||
size.w = max(size.w, geom.loc.x + geom.size.w);
|
size.w = max(size.w, geom.loc.x + geom.size.w);
|
||||||
size.h = max(size.h, geom.loc.y + geom.size.h);
|
size.h = max(size.h, geom.loc.y + geom.size.h);
|
||||||
|
|
||||||
let output_elements = self.render(renderer, &output, include_pointer);
|
let output_elements = self.render::<GlesRenderer>(renderer, &output, include_pointer);
|
||||||
elements.extend(output_elements.into_iter().map(|elem| {
|
elements.extend(output_elements.into_iter().map(|elem| {
|
||||||
RelocateRenderElement::from_element(elem, geom.loc, Relocate::Relative)
|
RelocateRenderElement::from_element(elem, geom.loc, Relocate::Relative)
|
||||||
}));
|
}));
|
||||||
@@ -2388,16 +2440,6 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_elements! {
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub OutputRenderElements<R> where R: ImportAll;
|
|
||||||
Monitor = MonitorRenderElement<R>,
|
|
||||||
Wayland = WaylandSurfaceRenderElement<R>,
|
|
||||||
NamedPointer = TextureRenderElement<<R as Renderer>::TextureId>,
|
|
||||||
SolidColor = SolidColorRenderElement,
|
|
||||||
ScreenshotUi = ScreenshotUiRenderElement<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
pub compositor_state: CompositorClientState,
|
pub compositor_state: CompositorClientState,
|
||||||
@@ -2488,8 +2530,6 @@ fn render_to_dmabuf(
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
elements: &[OutputRenderElements<GlesRenderer>],
|
elements: &[OutputRenderElements<GlesRenderer>],
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
use smithay::backend::renderer::element::Element;
|
|
||||||
|
|
||||||
let _span = tracy_client::span!("render_to_dmabuf");
|
let _span = tracy_client::span!("render_to_dmabuf");
|
||||||
|
|
||||||
let output_rect = Rectangle::from_loc_and_size((0, 0), size);
|
let output_rect = Rectangle::from_loc_and_size((0, 0), size);
|
||||||
@@ -2511,3 +2551,212 @@ fn render_to_dmabuf(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manual RenderElement implementation due to AsGlesFrame requirement.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum OutputRenderElements<R: NiriRenderer> {
|
||||||
|
Monitor(MonitorRenderElement<R>),
|
||||||
|
Wayland(WaylandSurfaceRenderElement<R>),
|
||||||
|
NamedPointer(PrimaryGpuTextureRenderElement),
|
||||||
|
SolidColor(SolidColorRenderElement),
|
||||||
|
ScreenshotUi(ScreenshotUiRenderElement),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: NiriRenderer> Element for OutputRenderElements<R> {
|
||||||
|
fn id(&self) -> &Id {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.id(),
|
||||||
|
Self::Wayland(elem) => elem.id(),
|
||||||
|
Self::NamedPointer(elem) => elem.id(),
|
||||||
|
Self::SolidColor(elem) => elem.id(),
|
||||||
|
Self::ScreenshotUi(elem) => elem.id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_commit(&self) -> CommitCounter {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.current_commit(),
|
||||||
|
Self::Wayland(elem) => elem.current_commit(),
|
||||||
|
Self::NamedPointer(elem) => elem.current_commit(),
|
||||||
|
Self::SolidColor(elem) => elem.current_commit(),
|
||||||
|
Self::ScreenshotUi(elem) => elem.current_commit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.geometry(scale),
|
||||||
|
Self::Wayland(elem) => elem.geometry(scale),
|
||||||
|
Self::NamedPointer(elem) => elem.geometry(scale),
|
||||||
|
Self::SolidColor(elem) => elem.geometry(scale),
|
||||||
|
Self::ScreenshotUi(elem) => elem.geometry(scale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform(&self) -> Transform {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.transform(),
|
||||||
|
Self::Wayland(elem) => elem.transform(),
|
||||||
|
Self::NamedPointer(elem) => elem.transform(),
|
||||||
|
Self::SolidColor(elem) => elem.transform(),
|
||||||
|
Self::ScreenshotUi(elem) => elem.transform(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn src(&self) -> Rectangle<f64, Buffer> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.src(),
|
||||||
|
Self::Wayland(elem) => elem.src(),
|
||||||
|
Self::NamedPointer(elem) => elem.src(),
|
||||||
|
Self::SolidColor(elem) => elem.src(),
|
||||||
|
Self::ScreenshotUi(elem) => elem.src(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn damage_since(
|
||||||
|
&self,
|
||||||
|
scale: Scale<f64>,
|
||||||
|
commit: Option<CommitCounter>,
|
||||||
|
) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.damage_since(scale, commit),
|
||||||
|
Self::Wayland(elem) => elem.damage_since(scale, commit),
|
||||||
|
Self::NamedPointer(elem) => elem.damage_since(scale, commit),
|
||||||
|
Self::SolidColor(elem) => elem.damage_since(scale, commit),
|
||||||
|
Self::ScreenshotUi(elem) => elem.damage_since(scale, commit),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.opaque_regions(scale),
|
||||||
|
Self::Wayland(elem) => elem.opaque_regions(scale),
|
||||||
|
Self::NamedPointer(elem) => elem.opaque_regions(scale),
|
||||||
|
Self::SolidColor(elem) => elem.opaque_regions(scale),
|
||||||
|
Self::ScreenshotUi(elem) => elem.opaque_regions(scale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alpha(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.alpha(),
|
||||||
|
Self::Wayland(elem) => elem.alpha(),
|
||||||
|
Self::NamedPointer(elem) => elem.alpha(),
|
||||||
|
Self::SolidColor(elem) => elem.alpha(),
|
||||||
|
Self::ScreenshotUi(elem) => elem.alpha(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kind(&self) -> Kind {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.kind(),
|
||||||
|
Self::Wayland(elem) => elem.kind(),
|
||||||
|
Self::NamedPointer(elem) => elem.kind(),
|
||||||
|
Self::SolidColor(elem) => elem.kind(),
|
||||||
|
Self::ScreenshotUi(elem) => elem.kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderElement<GlesRenderer> for OutputRenderElements<GlesRenderer> {
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut GlesFrame<'_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[Rectangle<i32, Physical>],
|
||||||
|
) -> Result<(), GlesError> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.draw(frame, src, dst, damage),
|
||||||
|
Self::Wayland(elem) => elem.draw(frame, src, dst, damage),
|
||||||
|
Self::NamedPointer(elem) => {
|
||||||
|
RenderElement::<GlesRenderer>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
Self::SolidColor(elem) => {
|
||||||
|
RenderElement::<GlesRenderer>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
Self::ScreenshotUi(elem) => {
|
||||||
|
RenderElement::<GlesRenderer>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underlying_storage(&self, renderer: &mut GlesRenderer) -> Option<UnderlyingStorage> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::Wayland(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::NamedPointer(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::SolidColor(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::ScreenshotUi(elem) => elem.underlying_storage(renderer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'render, 'alloc> RenderElement<TtyRenderer<'render, 'alloc>>
|
||||||
|
for OutputRenderElements<TtyRenderer<'render, 'alloc>>
|
||||||
|
{
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut TtyFrame<'render, 'alloc, '_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[Rectangle<i32, Physical>],
|
||||||
|
) -> Result<(), TtyRendererError<'render, 'alloc>> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.draw(frame, src, dst, damage),
|
||||||
|
Self::Wayland(elem) => elem.draw(frame, src, dst, damage),
|
||||||
|
Self::NamedPointer(elem) => {
|
||||||
|
RenderElement::<TtyRenderer<'render, 'alloc>>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
Self::SolidColor(elem) => {
|
||||||
|
RenderElement::<TtyRenderer<'render, 'alloc>>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
Self::ScreenshotUi(elem) => {
|
||||||
|
RenderElement::<TtyRenderer<'render, 'alloc>>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underlying_storage(
|
||||||
|
&self,
|
||||||
|
renderer: &mut TtyRenderer<'render, 'alloc>,
|
||||||
|
) -> Option<UnderlyingStorage> {
|
||||||
|
match self {
|
||||||
|
Self::Monitor(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::Wayland(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::NamedPointer(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::SolidColor(elem) => elem.underlying_storage(renderer),
|
||||||
|
Self::ScreenshotUi(elem) => elem.underlying_storage(renderer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: NiriRenderer> From<MonitorRenderElement<R>> for OutputRenderElements<R> {
|
||||||
|
fn from(x: MonitorRenderElement<R>) -> Self {
|
||||||
|
Self::Monitor(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: NiriRenderer> From<WaylandSurfaceRenderElement<R>> for OutputRenderElements<R> {
|
||||||
|
fn from(x: WaylandSurfaceRenderElement<R>) -> Self {
|
||||||
|
Self::Wayland(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: NiriRenderer> From<PrimaryGpuTextureRenderElement> for OutputRenderElements<R> {
|
||||||
|
fn from(x: PrimaryGpuTextureRenderElement) -> Self {
|
||||||
|
Self::NamedPointer(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: NiriRenderer> From<SolidColorRenderElement> for OutputRenderElements<R> {
|
||||||
|
fn from(x: SolidColorRenderElement) -> Self {
|
||||||
|
Self::SolidColor(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: NiriRenderer> From<ScreenshotUiRenderElement> for OutputRenderElements<R> {
|
||||||
|
fn from(x: ScreenshotUiRenderElement) -> Self {
|
||||||
|
Self::ScreenshotUi(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||||
|
use smithay::backend::renderer::element::texture::TextureRenderElement;
|
||||||
|
use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
|
||||||
|
use smithay::backend::renderer::gles::{GlesError, GlesFrame, GlesRenderer, GlesTexture};
|
||||||
|
use smithay::backend::renderer::utils::CommitCounter;
|
||||||
|
use smithay::backend::renderer::{Bind, ExportMem, ImportAll, Offscreen, Renderer, Texture};
|
||||||
|
use smithay::utils::{Buffer, Physical, Rectangle, Scale, Transform};
|
||||||
|
|
||||||
|
use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
|
||||||
|
|
||||||
|
/// Trait with our main renderer requirements to save on the typing.
|
||||||
|
pub trait NiriRenderer:
|
||||||
|
ImportAll
|
||||||
|
+ ExportMem
|
||||||
|
+ Bind<Dmabuf>
|
||||||
|
+ Offscreen<GlesTexture>
|
||||||
|
+ Renderer<TextureId = Self::NiriTextureId, Error = Self::NiriError>
|
||||||
|
+ AsGlesRenderer
|
||||||
|
{
|
||||||
|
// Associated types to work around the instability of associated type bounds.
|
||||||
|
type NiriTextureId: Texture + Clone + 'static;
|
||||||
|
type NiriError: std::error::Error
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ From<<GlesRenderer as Renderer>::Error>
|
||||||
|
+ 'static;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> NiriRenderer for R
|
||||||
|
where
|
||||||
|
R: ImportAll + ExportMem + Bind<Dmabuf> + Offscreen<GlesTexture> + AsGlesRenderer,
|
||||||
|
R::TextureId: Texture + Clone + 'static,
|
||||||
|
R::Error: std::error::Error + Send + Sync + From<<GlesRenderer as Renderer>::Error> + 'static,
|
||||||
|
{
|
||||||
|
type NiriTextureId = R::TextureId;
|
||||||
|
type NiriError = R::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for getting the underlying `GlesRenderer`.
|
||||||
|
pub trait AsGlesRenderer {
|
||||||
|
fn as_gles_renderer(&mut self) -> &mut GlesRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsGlesRenderer for GlesRenderer {
|
||||||
|
fn as_gles_renderer(&mut self) -> &mut GlesRenderer {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'render, 'alloc> AsGlesRenderer for TtyRenderer<'render, 'alloc> {
|
||||||
|
fn as_gles_renderer(&mut self) -> &mut GlesRenderer {
|
||||||
|
self.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for getting the underlying `GlesFrame`.
|
||||||
|
pub trait AsGlesFrame<'frame>
|
||||||
|
where
|
||||||
|
Self: 'frame,
|
||||||
|
{
|
||||||
|
fn as_gles_frame(&mut self) -> &mut GlesFrame<'frame>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'frame> AsGlesFrame<'frame> for GlesFrame<'frame> {
|
||||||
|
fn as_gles_frame(&mut self) -> &mut GlesFrame<'frame> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'render, 'alloc, 'frame> AsGlesFrame<'frame> for TtyFrame<'render, 'alloc, 'frame> {
|
||||||
|
fn as_gles_frame(&mut self) -> &mut GlesFrame<'frame> {
|
||||||
|
self.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for a texture from the primary GPU for rendering with the primary GPU.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrimaryGpuTextureRenderElement(pub TextureRenderElement<GlesTexture>);
|
||||||
|
|
||||||
|
impl Element for PrimaryGpuTextureRenderElement {
|
||||||
|
fn id(&self) -> &Id {
|
||||||
|
self.0.id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_commit(&self) -> CommitCounter {
|
||||||
|
self.0.current_commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
|
||||||
|
self.0.geometry(scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform(&self) -> Transform {
|
||||||
|
self.0.transform()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn src(&self) -> Rectangle<f64, Buffer> {
|
||||||
|
self.0.src()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn damage_since(
|
||||||
|
&self,
|
||||||
|
scale: Scale<f64>,
|
||||||
|
commit: Option<CommitCounter>,
|
||||||
|
) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
self.0.damage_since(scale, commit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
self.0.opaque_regions(scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alpha(&self) -> f32 {
|
||||||
|
self.0.alpha()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kind(&self) -> Kind {
|
||||||
|
self.0.kind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderElement<GlesRenderer> for PrimaryGpuTextureRenderElement {
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut GlesFrame<'_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[Rectangle<i32, Physical>],
|
||||||
|
) -> Result<(), GlesError> {
|
||||||
|
let gles_frame = frame.as_gles_frame();
|
||||||
|
RenderElement::<GlesRenderer>::draw(&self.0, gles_frame, src, dst, damage)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underlying_storage(&self, _renderer: &mut GlesRenderer) -> Option<UnderlyingStorage> {
|
||||||
|
// If scanout for things other than Wayland buffers is implemented, this will need to take
|
||||||
|
// the target GPU into account.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'render, 'alloc> RenderElement<TtyRenderer<'render, 'alloc>>
|
||||||
|
for PrimaryGpuTextureRenderElement
|
||||||
|
{
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut TtyFrame<'_, '_, '_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[Rectangle<i32, Physical>],
|
||||||
|
) -> Result<(), TtyRendererError<'render, 'alloc>> {
|
||||||
|
let gles_frame = frame.as_gles_frame();
|
||||||
|
RenderElement::<GlesRenderer>::draw(&self.0, gles_frame, src, dst, damage)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underlying_storage(
|
||||||
|
&self,
|
||||||
|
_renderer: &mut TtyRenderer<'render, 'alloc>,
|
||||||
|
) -> Option<UnderlyingStorage> {
|
||||||
|
// If scanout for things other than Wayland buffers is implemented, this will need to take
|
||||||
|
// the target GPU into account.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
+149
-16
@@ -5,19 +5,21 @@ use std::mem;
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
|
use niri_config::Action;
|
||||||
use smithay::backend::allocator::Fourcc;
|
use smithay::backend::allocator::Fourcc;
|
||||||
use smithay::backend::input::{ButtonState, MouseButton};
|
use smithay::backend::input::{ButtonState, MouseButton};
|
||||||
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement};
|
use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement};
|
||||||
use smithay::backend::renderer::element::Kind;
|
use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
|
||||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
use smithay::backend::renderer::gles::{GlesError, GlesFrame, GlesRenderer, GlesTexture};
|
||||||
|
use smithay::backend::renderer::utils::CommitCounter;
|
||||||
use smithay::backend::renderer::ExportMem;
|
use smithay::backend::renderer::ExportMem;
|
||||||
use smithay::input::keyboard::{Keysym, ModifiersState};
|
use smithay::input::keyboard::{Keysym, ModifiersState};
|
||||||
use smithay::output::{Output, WeakOutput};
|
use smithay::output::{Output, WeakOutput};
|
||||||
use smithay::render_elements;
|
use smithay::utils::{Buffer, Physical, Point, Rectangle, Scale, Size, Transform};
|
||||||
use smithay::utils::{Physical, Point, Rectangle, Size, Transform};
|
|
||||||
|
|
||||||
use crate::config::Action;
|
use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
|
||||||
|
use crate::render_helpers::PrimaryGpuTextureRenderElement;
|
||||||
|
|
||||||
const BORDER: i32 = 2;
|
const BORDER: i32 = 2;
|
||||||
|
|
||||||
@@ -45,11 +47,10 @@ pub struct OutputData {
|
|||||||
locations: [Point<i32, Physical>; 8],
|
locations: [Point<i32, Physical>; 8],
|
||||||
}
|
}
|
||||||
|
|
||||||
render_elements! {
|
#[derive(Debug)]
|
||||||
#[derive(Debug)]
|
pub enum ScreenshotUiRenderElement {
|
||||||
pub ScreenshotUiRenderElement<R>;
|
Screenshot(PrimaryGpuTextureRenderElement),
|
||||||
Screenshot = TextureRenderElement<R::TextureId>,
|
SolidColor(SolidColorRenderElement),
|
||||||
SolidColor = SolidColorRenderElement,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenshotUi {
|
impl ScreenshotUi {
|
||||||
@@ -236,10 +237,7 @@ impl ScreenshotUi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_output(
|
pub fn render_output(&self, output: &Output) -> ArrayVec<ScreenshotUiRenderElement, 9> {
|
||||||
&self,
|
|
||||||
output: &Output,
|
|
||||||
) -> ArrayVec<ScreenshotUiRenderElement<GlesRenderer>, 9> {
|
|
||||||
let _span = tracy_client::span!("ScreenshotUi::render_output");
|
let _span = tracy_client::span!("ScreenshotUi::render_output");
|
||||||
|
|
||||||
let Self::Open { output_data, .. } = self else {
|
let Self::Open { output_data, .. } = self else {
|
||||||
@@ -266,14 +264,14 @@ impl ScreenshotUi {
|
|||||||
|
|
||||||
// The screenshot itself goes last.
|
// The screenshot itself goes last.
|
||||||
elements.push(
|
elements.push(
|
||||||
TextureRenderElement::from_texture_buffer(
|
PrimaryGpuTextureRenderElement(TextureRenderElement::from_texture_buffer(
|
||||||
(0., 0.),
|
(0., 0.),
|
||||||
&output_data.texture_buffer,
|
&output_data.texture_buffer,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
)
|
))
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -446,3 +444,138 @@ pub fn rect_from_corner_points(
|
|||||||
let y2 = max(a.y, b.y);
|
let y2 = max(a.y, b.y);
|
||||||
Rectangle::from_extemities((x1, y1), (x2 + scale, y2 + scale))
|
Rectangle::from_extemities((x1, y1), (x2 + scale, y2 + scale))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manual RenderElement implementation due to AsGlesFrame requirement.
|
||||||
|
impl Element for ScreenshotUiRenderElement {
|
||||||
|
fn id(&self) -> &Id {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.id(),
|
||||||
|
Self::SolidColor(elem) => elem.id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_commit(&self) -> CommitCounter {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.current_commit(),
|
||||||
|
Self::SolidColor(elem) => elem.current_commit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.geometry(scale),
|
||||||
|
Self::SolidColor(elem) => elem.geometry(scale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform(&self) -> Transform {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.transform(),
|
||||||
|
Self::SolidColor(elem) => elem.transform(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn src(&self) -> Rectangle<f64, Buffer> {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.src(),
|
||||||
|
Self::SolidColor(elem) => elem.src(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn damage_since(
|
||||||
|
&self,
|
||||||
|
scale: Scale<f64>,
|
||||||
|
commit: Option<CommitCounter>,
|
||||||
|
) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.damage_since(scale, commit),
|
||||||
|
Self::SolidColor(elem) => elem.damage_since(scale, commit),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.opaque_regions(scale),
|
||||||
|
Self::SolidColor(elem) => elem.opaque_regions(scale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alpha(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.alpha(),
|
||||||
|
Self::SolidColor(elem) => elem.alpha(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kind(&self) -> Kind {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => elem.kind(),
|
||||||
|
Self::SolidColor(elem) => elem.kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderElement<GlesRenderer> for ScreenshotUiRenderElement {
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut GlesFrame<'_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[Rectangle<i32, Physical>],
|
||||||
|
) -> Result<(), GlesError> {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => {
|
||||||
|
RenderElement::<GlesRenderer>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
Self::SolidColor(elem) => {
|
||||||
|
RenderElement::<GlesRenderer>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underlying_storage(&self, _renderer: &mut GlesRenderer) -> Option<UnderlyingStorage> {
|
||||||
|
// If scanout for things other than Wayland buffers is implemented, this will need to take
|
||||||
|
// the target GPU into account.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'render, 'alloc> RenderElement<TtyRenderer<'render, 'alloc>> for ScreenshotUiRenderElement {
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut TtyFrame<'render, 'alloc, '_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[Rectangle<i32, Physical>],
|
||||||
|
) -> Result<(), TtyRendererError<'render, 'alloc>> {
|
||||||
|
match self {
|
||||||
|
Self::Screenshot(elem) => {
|
||||||
|
RenderElement::<TtyRenderer<'render, 'alloc>>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
Self::SolidColor(elem) => {
|
||||||
|
RenderElement::<TtyRenderer<'render, 'alloc>>::draw(&elem, frame, src, dst, damage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underlying_storage(
|
||||||
|
&self,
|
||||||
|
_renderer: &mut TtyRenderer<'render, 'alloc>,
|
||||||
|
) -> Option<UnderlyingStorage> {
|
||||||
|
// If scanout for things other than Wayland buffers is implemented, this will need to take
|
||||||
|
// the target GPU into account.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SolidColorRenderElement> for ScreenshotUiRenderElement {
|
||||||
|
fn from(x: SolidColorRenderElement) -> Self {
|
||||||
|
Self::SolidColor(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PrimaryGpuTextureRenderElement> for ScreenshotUiRenderElement {
|
||||||
|
fn from(x: PrimaryGpuTextureRenderElement) -> Self {
|
||||||
|
Self::Screenshot(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+16
-2
@@ -11,10 +11,14 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use anyhow::{ensure, Context};
|
use anyhow::{ensure, Context};
|
||||||
use directories::UserDirs;
|
use directories::UserDirs;
|
||||||
|
use niri_config::Config;
|
||||||
|
use smithay::output::Output;
|
||||||
use smithay::reexports::rustix::time::{clock_gettime, ClockId};
|
use smithay::reexports::rustix::time::{clock_gettime, ClockId};
|
||||||
use smithay::utils::{Logical, Point, Rectangle};
|
use smithay::utils::{Logical, Point, Rectangle, Size};
|
||||||
|
|
||||||
use crate::config::Config;
|
pub fn clone2<T: Clone, U: Clone>(t: (&T, &U)) -> (T, U) {
|
||||||
|
(t.0.clone(), t.1.clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_monotonic_time() -> Duration {
|
pub fn get_monotonic_time() -> Duration {
|
||||||
let ts = clock_gettime(ClockId::Monotonic);
|
let ts = clock_gettime(ClockId::Monotonic);
|
||||||
@@ -25,6 +29,16 @@ pub fn center(rect: Rectangle<i32, Logical>) -> Point<i32, Logical> {
|
|||||||
rect.loc + rect.size.downscale(2).to_point()
|
rect.loc + rect.size.downscale(2).to_point()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn output_size(output: &Output) -> Size<i32, Logical> {
|
||||||
|
let output_scale = output.current_scale().integer_scale();
|
||||||
|
let output_transform = output.current_transform();
|
||||||
|
let output_mode = output.current_mode().unwrap();
|
||||||
|
|
||||||
|
output_transform
|
||||||
|
.transform_size(output_mode.size)
|
||||||
|
.to_logical(output_scale)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn make_screenshot_path(config: &Config) -> anyhow::Result<Option<PathBuf>> {
|
pub fn make_screenshot_path(config: &Config) -> anyhow::Result<Option<PathBuf>> {
|
||||||
let Some(path) = &config.screenshot_path else {
|
let Some(path) = &config.screenshot_path else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
|||||||
Reference in New Issue
Block a user