├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── example ├── README.md ├── config.toml └── swayidle ├── man └── dim.1.scd └── src ├── dim.rs ├── lib.rs ├── main.rs └── opts.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | pull_request: 7 | branches: ["master"] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Dependencies 19 | run: | 20 | sudo apt-get update -y 21 | sudo apt-get install -y libxkbcommon-dev libwayland-dev scdoc 22 | - name: Lint 23 | uses: wearerequired/lint-action@v2 24 | with: 25 | clippy: true 26 | rustfmt: true 27 | - name: Build locked 28 | run: cargo build --locked --verbose 29 | - name: Test locked 30 | run: cargo test --locked --verbose 31 | - name: Test manpages 32 | run: scdoc /dev/null 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anstream" 16 | version = "0.6.18" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 19 | dependencies = [ 20 | "anstyle", 21 | "anstyle-parse", 22 | "anstyle-query", 23 | "anstyle-wincon", 24 | "colorchoice", 25 | "is_terminal_polyfill", 26 | "utf8parse", 27 | ] 28 | 29 | [[package]] 30 | name = "anstyle" 31 | version = "1.0.10" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 34 | 35 | [[package]] 36 | name = "anstyle-parse" 37 | version = "0.2.6" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 40 | dependencies = [ 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-query" 46 | version = "1.1.2" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 49 | dependencies = [ 50 | "windows-sys 0.59.0", 51 | ] 52 | 53 | [[package]] 54 | name = "anstyle-wincon" 55 | version = "3.0.6" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 58 | dependencies = [ 59 | "anstyle", 60 | "windows-sys 0.59.0", 61 | ] 62 | 63 | [[package]] 64 | name = "anyhow" 65 | version = "1.0.93" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 68 | 69 | [[package]] 70 | name = "autocfg" 71 | version = "1.4.0" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 74 | 75 | [[package]] 76 | name = "bitflags" 77 | version = "2.6.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 80 | 81 | [[package]] 82 | name = "bytemuck" 83 | version = "1.19.0" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" 86 | dependencies = [ 87 | "bytemuck_derive", 88 | ] 89 | 90 | [[package]] 91 | name = "bytemuck_derive" 92 | version = "1.8.0" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" 95 | dependencies = [ 96 | "proc-macro2", 97 | "quote", 98 | "syn", 99 | ] 100 | 101 | [[package]] 102 | name = "calloop" 103 | version = "0.13.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" 106 | dependencies = [ 107 | "bitflags", 108 | "log", 109 | "polling", 110 | "rustix", 111 | "slab", 112 | "thiserror", 113 | ] 114 | 115 | [[package]] 116 | name = "calloop-wayland-source" 117 | version = "0.3.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" 120 | dependencies = [ 121 | "calloop", 122 | "rustix", 123 | "wayland-backend", 124 | "wayland-client", 125 | ] 126 | 127 | [[package]] 128 | name = "cc" 129 | version = "1.1.37" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" 132 | dependencies = [ 133 | "shlex", 134 | ] 135 | 136 | [[package]] 137 | name = "cfg-if" 138 | version = "1.0.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 141 | 142 | [[package]] 143 | name = "clap" 144 | version = "4.5.20" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" 147 | dependencies = [ 148 | "clap_builder", 149 | "clap_derive", 150 | ] 151 | 152 | [[package]] 153 | name = "clap_builder" 154 | version = "4.5.20" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" 157 | dependencies = [ 158 | "anstream", 159 | "anstyle", 160 | "clap_lex", 161 | "strsim", 162 | ] 163 | 164 | [[package]] 165 | name = "clap_complete" 166 | version = "4.5.37" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "11611dca53440593f38e6b25ec629de50b14cdfa63adc0fb856115a2c6d97595" 169 | dependencies = [ 170 | "clap", 171 | ] 172 | 173 | [[package]] 174 | name = "clap_derive" 175 | version = "4.5.18" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" 178 | dependencies = [ 179 | "heck", 180 | "proc-macro2", 181 | "quote", 182 | "syn", 183 | ] 184 | 185 | [[package]] 186 | name = "clap_lex" 187 | version = "0.7.2" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" 190 | 191 | [[package]] 192 | name = "colorchoice" 193 | version = "1.0.3" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 196 | 197 | [[package]] 198 | name = "concurrent-queue" 199 | version = "2.5.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 202 | dependencies = [ 203 | "crossbeam-utils", 204 | ] 205 | 206 | [[package]] 207 | name = "crossbeam-utils" 208 | version = "0.8.20" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 211 | 212 | [[package]] 213 | name = "cursor-icon" 214 | version = "1.1.0" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" 217 | 218 | [[package]] 219 | name = "dim-screen" 220 | version = "0.3.0" 221 | dependencies = [ 222 | "anyhow", 223 | "clap", 224 | "clap_complete", 225 | "env_logger", 226 | "log", 227 | "serde", 228 | "smithay-client-toolkit", 229 | "toml", 230 | ] 231 | 232 | [[package]] 233 | name = "dlib" 234 | version = "0.5.2" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" 237 | dependencies = [ 238 | "libloading", 239 | ] 240 | 241 | [[package]] 242 | name = "downcast-rs" 243 | version = "1.2.1" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" 246 | 247 | [[package]] 248 | name = "env_filter" 249 | version = "0.1.2" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" 252 | dependencies = [ 253 | "log", 254 | "regex", 255 | ] 256 | 257 | [[package]] 258 | name = "env_logger" 259 | version = "0.11.5" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" 262 | dependencies = [ 263 | "anstream", 264 | "anstyle", 265 | "env_filter", 266 | "humantime", 267 | "log", 268 | ] 269 | 270 | [[package]] 271 | name = "equivalent" 272 | version = "1.0.1" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 275 | 276 | [[package]] 277 | name = "errno" 278 | version = "0.3.9" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 281 | dependencies = [ 282 | "libc", 283 | "windows-sys 0.52.0", 284 | ] 285 | 286 | [[package]] 287 | name = "hashbrown" 288 | version = "0.15.1" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" 291 | 292 | [[package]] 293 | name = "heck" 294 | version = "0.5.0" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 297 | 298 | [[package]] 299 | name = "hermit-abi" 300 | version = "0.4.0" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" 303 | 304 | [[package]] 305 | name = "humantime" 306 | version = "2.1.0" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 309 | 310 | [[package]] 311 | name = "indexmap" 312 | version = "2.6.0" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 315 | dependencies = [ 316 | "equivalent", 317 | "hashbrown", 318 | ] 319 | 320 | [[package]] 321 | name = "is_terminal_polyfill" 322 | version = "1.70.1" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 325 | 326 | [[package]] 327 | name = "libc" 328 | version = "0.2.162" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" 331 | 332 | [[package]] 333 | name = "libloading" 334 | version = "0.8.5" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" 337 | dependencies = [ 338 | "cfg-if", 339 | "windows-targets", 340 | ] 341 | 342 | [[package]] 343 | name = "linux-raw-sys" 344 | version = "0.4.14" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 347 | 348 | [[package]] 349 | name = "log" 350 | version = "0.4.22" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 353 | 354 | [[package]] 355 | name = "memchr" 356 | version = "2.7.4" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 359 | 360 | [[package]] 361 | name = "memmap2" 362 | version = "0.8.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" 365 | dependencies = [ 366 | "libc", 367 | ] 368 | 369 | [[package]] 370 | name = "memmap2" 371 | version = "0.9.5" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" 374 | dependencies = [ 375 | "libc", 376 | ] 377 | 378 | [[package]] 379 | name = "pin-project-lite" 380 | version = "0.2.15" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 383 | 384 | [[package]] 385 | name = "pkg-config" 386 | version = "0.3.31" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 389 | 390 | [[package]] 391 | name = "polling" 392 | version = "3.7.4" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" 395 | dependencies = [ 396 | "cfg-if", 397 | "concurrent-queue", 398 | "hermit-abi", 399 | "pin-project-lite", 400 | "rustix", 401 | "tracing", 402 | "windows-sys 0.59.0", 403 | ] 404 | 405 | [[package]] 406 | name = "proc-macro2" 407 | version = "1.0.89" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" 410 | dependencies = [ 411 | "unicode-ident", 412 | ] 413 | 414 | [[package]] 415 | name = "quick-xml" 416 | version = "0.36.2" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" 419 | dependencies = [ 420 | "memchr", 421 | ] 422 | 423 | [[package]] 424 | name = "quote" 425 | version = "1.0.37" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 428 | dependencies = [ 429 | "proc-macro2", 430 | ] 431 | 432 | [[package]] 433 | name = "regex" 434 | version = "1.11.1" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 437 | dependencies = [ 438 | "aho-corasick", 439 | "memchr", 440 | "regex-automata", 441 | "regex-syntax", 442 | ] 443 | 444 | [[package]] 445 | name = "regex-automata" 446 | version = "0.4.8" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 449 | dependencies = [ 450 | "aho-corasick", 451 | "memchr", 452 | "regex-syntax", 453 | ] 454 | 455 | [[package]] 456 | name = "regex-syntax" 457 | version = "0.8.5" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 460 | 461 | [[package]] 462 | name = "rustix" 463 | version = "0.38.39" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" 466 | dependencies = [ 467 | "bitflags", 468 | "errno", 469 | "libc", 470 | "linux-raw-sys", 471 | "windows-sys 0.52.0", 472 | ] 473 | 474 | [[package]] 475 | name = "scoped-tls" 476 | version = "1.0.1" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 479 | 480 | [[package]] 481 | name = "serde" 482 | version = "1.0.214" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" 485 | dependencies = [ 486 | "serde_derive", 487 | ] 488 | 489 | [[package]] 490 | name = "serde_derive" 491 | version = "1.0.214" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" 494 | dependencies = [ 495 | "proc-macro2", 496 | "quote", 497 | "syn", 498 | ] 499 | 500 | [[package]] 501 | name = "serde_spanned" 502 | version = "0.6.8" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 505 | dependencies = [ 506 | "serde", 507 | ] 508 | 509 | [[package]] 510 | name = "shlex" 511 | version = "1.3.0" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 514 | 515 | [[package]] 516 | name = "slab" 517 | version = "0.4.9" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 520 | dependencies = [ 521 | "autocfg", 522 | ] 523 | 524 | [[package]] 525 | name = "smallvec" 526 | version = "1.13.2" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 529 | 530 | [[package]] 531 | name = "smithay-client-toolkit" 532 | version = "0.19.2" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" 535 | dependencies = [ 536 | "bitflags", 537 | "bytemuck", 538 | "calloop", 539 | "calloop-wayland-source", 540 | "cursor-icon", 541 | "libc", 542 | "log", 543 | "memmap2 0.9.5", 544 | "pkg-config", 545 | "rustix", 546 | "thiserror", 547 | "wayland-backend", 548 | "wayland-client", 549 | "wayland-csd-frame", 550 | "wayland-cursor", 551 | "wayland-protocols", 552 | "wayland-protocols-wlr", 553 | "wayland-scanner", 554 | "xkbcommon", 555 | "xkeysym", 556 | ] 557 | 558 | [[package]] 559 | name = "strsim" 560 | version = "0.11.1" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 563 | 564 | [[package]] 565 | name = "syn" 566 | version = "2.0.87" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" 569 | dependencies = [ 570 | "proc-macro2", 571 | "quote", 572 | "unicode-ident", 573 | ] 574 | 575 | [[package]] 576 | name = "thiserror" 577 | version = "1.0.68" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" 580 | dependencies = [ 581 | "thiserror-impl", 582 | ] 583 | 584 | [[package]] 585 | name = "thiserror-impl" 586 | version = "1.0.68" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" 589 | dependencies = [ 590 | "proc-macro2", 591 | "quote", 592 | "syn", 593 | ] 594 | 595 | [[package]] 596 | name = "toml" 597 | version = "0.8.19" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 600 | dependencies = [ 601 | "serde", 602 | "serde_spanned", 603 | "toml_datetime", 604 | "toml_edit", 605 | ] 606 | 607 | [[package]] 608 | name = "toml_datetime" 609 | version = "0.6.8" 610 | source = "registry+https://github.com/rust-lang/crates.io-index" 611 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 612 | dependencies = [ 613 | "serde", 614 | ] 615 | 616 | [[package]] 617 | name = "toml_edit" 618 | version = "0.22.22" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 621 | dependencies = [ 622 | "indexmap", 623 | "serde", 624 | "serde_spanned", 625 | "toml_datetime", 626 | "winnow", 627 | ] 628 | 629 | [[package]] 630 | name = "tracing" 631 | version = "0.1.40" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 634 | dependencies = [ 635 | "pin-project-lite", 636 | "tracing-core", 637 | ] 638 | 639 | [[package]] 640 | name = "tracing-core" 641 | version = "0.1.32" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 644 | 645 | [[package]] 646 | name = "unicode-ident" 647 | version = "1.0.13" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 650 | 651 | [[package]] 652 | name = "utf8parse" 653 | version = "0.2.2" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 656 | 657 | [[package]] 658 | name = "wayland-backend" 659 | version = "0.3.7" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" 662 | dependencies = [ 663 | "cc", 664 | "downcast-rs", 665 | "rustix", 666 | "scoped-tls", 667 | "smallvec", 668 | "wayland-sys", 669 | ] 670 | 671 | [[package]] 672 | name = "wayland-client" 673 | version = "0.31.7" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" 676 | dependencies = [ 677 | "bitflags", 678 | "rustix", 679 | "wayland-backend", 680 | "wayland-scanner", 681 | ] 682 | 683 | [[package]] 684 | name = "wayland-csd-frame" 685 | version = "0.3.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" 688 | dependencies = [ 689 | "bitflags", 690 | "cursor-icon", 691 | "wayland-backend", 692 | ] 693 | 694 | [[package]] 695 | name = "wayland-cursor" 696 | version = "0.31.7" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" 699 | dependencies = [ 700 | "rustix", 701 | "wayland-client", 702 | "xcursor", 703 | ] 704 | 705 | [[package]] 706 | name = "wayland-protocols" 707 | version = "0.32.5" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" 710 | dependencies = [ 711 | "bitflags", 712 | "wayland-backend", 713 | "wayland-client", 714 | "wayland-scanner", 715 | ] 716 | 717 | [[package]] 718 | name = "wayland-protocols-wlr" 719 | version = "0.3.5" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" 722 | dependencies = [ 723 | "bitflags", 724 | "wayland-backend", 725 | "wayland-client", 726 | "wayland-protocols", 727 | "wayland-scanner", 728 | ] 729 | 730 | [[package]] 731 | name = "wayland-scanner" 732 | version = "0.31.5" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" 735 | dependencies = [ 736 | "proc-macro2", 737 | "quick-xml", 738 | "quote", 739 | ] 740 | 741 | [[package]] 742 | name = "wayland-sys" 743 | version = "0.31.5" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" 746 | dependencies = [ 747 | "dlib", 748 | "log", 749 | "pkg-config", 750 | ] 751 | 752 | [[package]] 753 | name = "windows-sys" 754 | version = "0.52.0" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 757 | dependencies = [ 758 | "windows-targets", 759 | ] 760 | 761 | [[package]] 762 | name = "windows-sys" 763 | version = "0.59.0" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 766 | dependencies = [ 767 | "windows-targets", 768 | ] 769 | 770 | [[package]] 771 | name = "windows-targets" 772 | version = "0.52.6" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 775 | dependencies = [ 776 | "windows_aarch64_gnullvm", 777 | "windows_aarch64_msvc", 778 | "windows_i686_gnu", 779 | "windows_i686_gnullvm", 780 | "windows_i686_msvc", 781 | "windows_x86_64_gnu", 782 | "windows_x86_64_gnullvm", 783 | "windows_x86_64_msvc", 784 | ] 785 | 786 | [[package]] 787 | name = "windows_aarch64_gnullvm" 788 | version = "0.52.6" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 791 | 792 | [[package]] 793 | name = "windows_aarch64_msvc" 794 | version = "0.52.6" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 797 | 798 | [[package]] 799 | name = "windows_i686_gnu" 800 | version = "0.52.6" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 803 | 804 | [[package]] 805 | name = "windows_i686_gnullvm" 806 | version = "0.52.6" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 809 | 810 | [[package]] 811 | name = "windows_i686_msvc" 812 | version = "0.52.6" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 815 | 816 | [[package]] 817 | name = "windows_x86_64_gnu" 818 | version = "0.52.6" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 821 | 822 | [[package]] 823 | name = "windows_x86_64_gnullvm" 824 | version = "0.52.6" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 827 | 828 | [[package]] 829 | name = "windows_x86_64_msvc" 830 | version = "0.52.6" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 833 | 834 | [[package]] 835 | name = "winnow" 836 | version = "0.6.20" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 839 | dependencies = [ 840 | "memchr", 841 | ] 842 | 843 | [[package]] 844 | name = "xcursor" 845 | version = "0.3.8" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" 848 | 849 | [[package]] 850 | name = "xkbcommon" 851 | version = "0.7.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e" 854 | dependencies = [ 855 | "libc", 856 | "memmap2 0.8.0", 857 | "xkeysym", 858 | ] 859 | 860 | [[package]] 861 | name = "xkeysym" 862 | version = "0.2.1" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" 865 | dependencies = [ 866 | "bytemuck", 867 | ] 868 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dim-screen" 3 | authors = ["Marcelo Hernandez "] 4 | description = "Native Wayland screen dimming tool" 5 | homepage = "https://github.com/marcelohdez/dim" 6 | license = "GPL-3.0-only" 7 | keywords = ["wayland", "smithay"] 8 | 9 | version = "0.3.0" 10 | edition = "2021" 11 | 12 | [[bin]] 13 | name = "dim" 14 | path = "src/main.rs" 15 | 16 | [dependencies] 17 | anyhow = "1.0.0" 18 | clap = { version = "4.4.0", features = ["derive"] } 19 | clap_complete = "4.4.0" 20 | env_logger = "0.11.0" 21 | log = "0.4.20" 22 | serde = { version = "1.0.0", features = ["derive"] } 23 | smithay-client-toolkit = "0.19.0" 24 | toml = "0.8.0" 25 | 26 | [profile.release] 27 | lto = true 28 | panic = "abort" 29 | codegen-units = 1 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dim 2 | 3 | Native Wayland screen dimming tool 4 | 5 | ## Usage 6 | 7 | > [!NOTE] 8 | > A Wayland compositor supporting the [single pixel buffer protocol] is 9 | > required e.g. Sway 1.8+, river, Hyprland. 10 | 11 | After [installing], you may run `dim` before you would run your locker, when 12 | you want the screen to dim for a period, e.g. in your [swayidle] config/command: 13 | 14 | ```bash 15 | timeout 270 'dim && swaylock' 16 | ``` 17 | 18 | Would make it so that at 270 seconds, `dim` is run waiting for user input 19 | for the default of `30` seconds, then if no input is detected the next 20 | command will proceed, in this case [swaylock] will lock your screen. 21 | 22 | `dim` should only finish **successfully** when no input is detected for the 23 | duration. If `dim` finishes successfully before this duration, please [submit 24 | an issue]. 25 | 26 | The alpha and duration of `dim` may be configured with either a config file 27 | located at `~/.config/dim/config.toml`, or through arguments at call-time, for 28 | all options and their defaults please see: 29 | 30 | ```bash 31 | dim --help 32 | ``` 33 | 34 | ## Installing 35 | 36 | dim packages are titled as `dim-screen` to avoid naming conflicts. 37 | 38 | ### Fedora (COPR) 39 | 40 | dim is available in Fedora as a [COPR]: 41 | 42 | ```bash 43 | sudo dnf copr enable marcelohdez/dim 44 | sudo dnf install dim-screen 45 | ``` 46 | 47 | ### Arch (AUR) 48 | 49 | For Arch, dim is available in the [AUR] (Thanks to [ge-garcia] for 50 | maintaining!). You may use your preferred [AUR helper] like so: 51 | 52 | ```bash 53 | paru -Syu dim-screen 54 | ``` 55 | 56 | ### Others 57 | 58 | > [!IMPORTANT] 59 | > 60 | > - Ensure you have [Rust] installed. 61 | > - The system libraries `libxkbcommon` and `libwayland` are required. 62 | 63 | dim is available on crates.io: 64 | 65 | ```bash 66 | cargo install dim-screen 67 | ``` 68 | 69 | ### Building Manually 70 | 71 | Choose a directory for this repo, then clone and `cd` into it: 72 | 73 | ```bash 74 | git clone https://github.com/marcelohdez/dim 75 | cd dim 76 | ``` 77 | 78 | Lastly, `cargo` can build and install `dim` for you, placing the binary in 79 | `$HOME/.cargo/bin/`: 80 | 81 | ```bash 82 | cargo install --path . 83 | ``` 84 | 85 | Or, if you would like to place the binary in your `$PATH` yourself: 86 | 87 | ```bash 88 | cargo build -r 89 | ``` 90 | 91 | And the resulting binary should be in `./target/release/dim`. 92 | 93 | ## License 94 | 95 | `dim` is licensed under the GPLv3 license, a free and open source license. For 96 | more information, please refer to the [LICENSE] file in the repository root. 97 | 98 | [AUR]: https://aur.archlinux.org/packages/dim-screen 99 | [ge-garcia]: https://github.com/ge-garcia/ 100 | [AUR helper]: https://wiki.archlinux.org/title/AUR_helpers 101 | [COPR]: https://copr.fedorainfracloud.org/coprs/marcelohdez/dim 102 | [installing]: #installing 103 | [swayidle]: https://github.com/swaywm/swayidle 104 | [swaylock]: https://github.com/swaywm/swaylock 105 | [submit an issue]: https://github.com/marcelohdez/dim/issues 106 | [Rust]: https://www.rust-lang.org/ 107 | [single pixel buffer protocol]: https://wayland.app/protocols/single-pixel-buffer-v1 108 | [LICENSE]: LICENSE 109 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example configs 2 | 3 | ## [config.toml] 4 | 5 | Example dim config. 6 | 7 | ## [swayidle] 8 | 9 | Adapted from my own dotfiles, it does several things; 10 | 11 | At 45 seconds idle, check if [swaylock] (or your locker) is running, if so, 12 | suspend again (user has been idle for 45 seconds on lock screen): 13 | 14 | ```bash 15 | timeout 45 'pgrep swaylock && systemctl suspend' 16 | ``` 17 | 18 | At 435 seconds (7 minute and 15 seconds) it runs dim, which if no input is 19 | detected after the default of 30 seconds, it will exit successfully and run 20 | the screen locker 15 seconds before the system is suspended at 480 seconds: 21 | 22 | ```bash 23 | timeout 435 'dim && swaylock' 24 | timeout 480 'systemctl suspend' 25 | ``` 26 | 27 | Finally, before the system sleeps (even if user suspends manually) pause all 28 | media players and run screen locker: 29 | 30 | ```bash 31 | before-sleep 'playerctl pause -i kdeconnect; swaylock' 32 | ``` 33 | 34 | [config.toml]: config.toml 35 | [swayidle]: swayidle 36 | [swaylock]: https://github.com/swaywm/swaylock 37 | -------------------------------------------------------------------------------- /example/config.toml: -------------------------------------------------------------------------------- 1 | # any line starting with a hashtag is a comment 2 | # here are some default values: 3 | duration = 30 4 | alpha = 0.5 5 | passthrough = false 6 | -------------------------------------------------------------------------------- /example/swayidle: -------------------------------------------------------------------------------- 1 | timeout 45 'pgrep swaylock && systemctl suspend' 2 | 3 | timeout 435 'dim && swaylock' 4 | timeout 480 'systemctl suspend' 5 | 6 | before-sleep 'playerctl pause -i kdeconnect; swaylock' 7 | -------------------------------------------------------------------------------- /man/dim.1.scd: -------------------------------------------------------------------------------- 1 | DIM(1) 2 | 3 | # NAME 4 | 5 | dim - A Wayland screen dimmer. 6 | 7 | # USAGE 8 | 9 | dim [OPTIONS] 10 | 11 | # DESCRIPTION 12 | 13 | dim requires a Wayland compositor with suport for the single pixel buffer 14 | protocol, e.g. Sway 1.8+, river, Hyprland. 15 | 16 | Upon running, dim will create a black overlay with the given alpha (see 17 | OPTIONS) and wait for the given duration (see OPTIONS). If any mouse, touch or 18 | keyboard input is detected, an error will be thrown. Otherwise, when the 19 | duration is reached without input, dim will quit successfully, allowing you to 20 | chain commands. For example, if using `swayidle` you may set: 21 | 22 | ``` 23 | timeout 270 'dim && swaylock' 24 | ``` 25 | 26 | Making it so at 270 seconds, or 5 minutes, dim is run, and if no input is 27 | detected after its timeout, swaylock will be run, locking the screen. 28 | 29 | # OPTIONS 30 | 31 | \-d, --duration 32 | Set the duration in seconds. 0 Will be considered as infinite. The default is 33 | 30. 34 | 35 | \-a, --alpha 36 | Set the *alpha* value of the overlay, 0.0 being transparent and 1.0 being 37 | solid black. When solid, cursor will be hidden. Default is 0.5. 38 | 39 | \-p, --passthrough 40 | Make dim ignore input, passing it to the surfaces behind it, making dim act as 41 | a way to lower your brightness artificially. You probably want to set the 42 | duration option above to 0 for this to last indefinitely. 43 | 44 | When scripting this, you could summon dim with passthrough enabled and then 45 | kill it with `pkill dim` 46 | 47 | \--gen-completions 48 | Generates completions for all supported shells at the given path. 49 | 50 | \-c, --config 51 | Read config file at given PATH instead of default location (see CONFIGURATION 52 | below.) 53 | 54 | \-h, --help 55 | Print help information 56 | 57 | \-V, --version 58 | Print the binary's version 59 | 60 | # CONFIGURATION 61 | 62 | dim can be configured through a TOML configuration file, which is by default 63 | looked for at `$XDG_CONFIG_HOME/dim/config.toml`, or, if `$XDG_CONFIG_HOME` is 64 | not set, it will instead default to searching at `~/.config/dim/config.toml`. 65 | 66 | The options set here will be overriden by any arguments passed in. Valid 67 | options are alpha, duration and passthrough as seen above, example config: 68 | 69 | ``` 70 | # i am a comment! 71 | duration = 30 72 | alpha = 0.5 73 | passthrough = false 74 | ``` 75 | -------------------------------------------------------------------------------- /src/dim.rs: -------------------------------------------------------------------------------- 1 | use log::{debug, error}; 2 | use smithay_client_toolkit::{ 3 | compositor::{CompositorHandler, CompositorState, Region}, 4 | delegate_compositor, delegate_keyboard, delegate_layer, delegate_output, delegate_pointer, 5 | delegate_registry, delegate_seat, delegate_simple, delegate_touch, 6 | output::{OutputHandler, OutputState}, 7 | reexports::{ 8 | client::{ 9 | globals::GlobalList, 10 | protocol::{ 11 | wl_buffer::{self, WlBuffer}, 12 | wl_keyboard, 13 | wl_output::WlOutput, 14 | wl_pointer, wl_touch, 15 | }, 16 | Connection, Dispatch, QueueHandle, 17 | }, 18 | protocols::wp::{ 19 | single_pixel_buffer::v1::client::wp_single_pixel_buffer_manager_v1::{ 20 | self, WpSinglePixelBufferManagerV1, 21 | }, 22 | viewporter::client::{ 23 | wp_viewport::{self, WpViewport}, 24 | wp_viewporter::{self, WpViewporter}, 25 | }, 26 | }, 27 | }, 28 | registry::{ProvidesRegistryState, RegistryState, SimpleGlobal}, 29 | registry_handlers, 30 | seat::{ 31 | keyboard::KeyboardHandler, 32 | pointer::{PointerEvent, PointerEventKind, PointerHandler}, 33 | touch::TouchHandler, 34 | Capability, SeatHandler, SeatState, 35 | }, 36 | shell::{ 37 | wlr_layer::{KeyboardInteractivity, Layer, LayerShell, LayerShellHandler, LayerSurface}, 38 | WaylandSurface, 39 | }, 40 | }; 41 | 42 | use crate::INIT_SIZE; 43 | 44 | pub struct DimData { 45 | compositor: CompositorState, 46 | registry_state: RegistryState, 47 | seat_state: SeatState, 48 | output_state: OutputState, 49 | layer_shell: LayerShell, 50 | pixel_buffer_mgr: SimpleGlobal, 51 | viewporter: SimpleGlobal, 52 | 53 | alpha: f32, 54 | passthrough: bool, 55 | views: Vec, 56 | 57 | keyboard: Option, 58 | pointer: Option, 59 | touch: Option, 60 | exit: bool, 61 | } 62 | 63 | struct DimView { 64 | first_configure: bool, 65 | width: u32, 66 | height: u32, 67 | buffer: WlBuffer, 68 | viewport: WpViewport, 69 | layer: LayerSurface, 70 | output: WlOutput, 71 | } 72 | 73 | impl DimData { 74 | pub fn new( 75 | compositor: CompositorState, 76 | globals: &GlobalList, 77 | qh: &QueueHandle, 78 | layer_shell: LayerShell, 79 | alpha: f32, 80 | passthrough: bool, 81 | ) -> Self { 82 | Self { 83 | compositor, 84 | registry_state: RegistryState::new(globals), 85 | seat_state: SeatState::new(globals, qh), 86 | output_state: OutputState::new(globals, qh), 87 | layer_shell, 88 | pixel_buffer_mgr: SimpleGlobal::::bind(globals, qh) 89 | .expect("wp_single_pixel_buffer_manager_v1 not available!"), 90 | viewporter: SimpleGlobal::::bind(globals, qh) 91 | .expect("wp_viewporter not available"), 92 | 93 | alpha, 94 | passthrough, 95 | views: Vec::new(), 96 | 97 | exit: false, 98 | keyboard: None, 99 | pointer: None, 100 | touch: None, 101 | } 102 | } 103 | 104 | pub fn should_exit(&self) -> bool { 105 | self.exit 106 | } 107 | 108 | fn create_view(&self, qh: &QueueHandle, output: WlOutput) -> DimView { 109 | let layer = self.layer_shell.create_layer_surface( 110 | qh, 111 | self.compositor.create_surface(qh), 112 | Layer::Overlay, 113 | Some("dim_layer"), 114 | Some(&output), 115 | ); 116 | 117 | let (width, height) = if let Some((width, height)) = self 118 | .output_state 119 | .info(&output) 120 | .and_then(|info| info.logical_size) 121 | { 122 | (width as u32, height as u32) 123 | } else { 124 | (INIT_SIZE, INIT_SIZE) 125 | }; 126 | 127 | if self.passthrough { 128 | let input_region = Region::new(&self.compositor).expect("Failed to get a wl_region"); 129 | layer.set_keyboard_interactivity(KeyboardInteractivity::None); 130 | layer.set_input_region(Some(input_region.wl_region())); 131 | } else { 132 | layer.set_keyboard_interactivity(KeyboardInteractivity::Exclusive); 133 | } 134 | 135 | layer.set_exclusive_zone(-1); 136 | layer.set_size(width, height); 137 | layer.commit(); 138 | 139 | let viewport = self 140 | .viewporter 141 | .get() 142 | .expect("wp_viewporter failed") 143 | .get_viewport(layer.wl_surface(), qh, ()); 144 | 145 | // pre-multiply alpha 146 | let alpha = (u32::MAX as f32 * self.alpha) as u32; 147 | let buffer = self 148 | .pixel_buffer_mgr 149 | .get() 150 | .expect("failed to get buffer") 151 | .create_u32_rgba_buffer(0, 0, 0, alpha, qh, ()); 152 | 153 | DimView::new(qh, buffer, viewport, layer, output) 154 | } 155 | } 156 | 157 | impl DimView { 158 | fn new( 159 | _qh: &QueueHandle, 160 | buffer: WlBuffer, 161 | viewport: WpViewport, 162 | layer: LayerSurface, 163 | output: WlOutput, 164 | ) -> Self { 165 | Self { 166 | first_configure: true, 167 | width: INIT_SIZE, 168 | height: INIT_SIZE, 169 | buffer, 170 | viewport, 171 | layer, 172 | output, 173 | } 174 | } 175 | 176 | fn draw(&mut self, _qh: &QueueHandle) { 177 | debug!("Requesting draw"); 178 | if !self.first_configure { 179 | // we only need to draw once as it is a static color 180 | return; 181 | } 182 | 183 | self.layer.wl_surface().attach(Some(&self.buffer), 0, 0); 184 | self.layer.commit(); 185 | 186 | debug!("Drawn"); 187 | } 188 | } 189 | 190 | impl LayerShellHandler for DimData { 191 | fn closed( 192 | &mut self, 193 | _conn: &smithay_client_toolkit::reexports::client::Connection, 194 | _qh: &QueueHandle, 195 | _layer: &LayerSurface, 196 | ) { 197 | debug!("Closed"); 198 | self.exit = true; 199 | } 200 | 201 | fn configure( 202 | &mut self, 203 | _conn: &smithay_client_toolkit::reexports::client::Connection, 204 | qh: &QueueHandle, 205 | layer: &LayerSurface, 206 | configure: smithay_client_toolkit::shell::wlr_layer::LayerSurfaceConfigure, 207 | _serial: u32, 208 | ) { 209 | let Some(view) = self.views.iter_mut().find(|view| &view.layer == layer) else { 210 | error!("Configuring layer not in self.views?"); 211 | return; 212 | }; 213 | 214 | (view.width, view.height) = configure.new_size; 215 | 216 | view.viewport 217 | .set_destination(view.width as _, view.height as _); 218 | 219 | if view.first_configure { 220 | view.draw(qh); 221 | view.first_configure = false; 222 | } 223 | } 224 | } 225 | 226 | impl CompositorHandler for DimData { 227 | fn scale_factor_changed( 228 | &mut self, 229 | _conn: &smithay_client_toolkit::reexports::client::Connection, 230 | _qh: &QueueHandle, 231 | _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 232 | _new_factor: i32, 233 | ) { 234 | } 235 | 236 | fn transform_changed( 237 | &mut self, 238 | _conn: &smithay_client_toolkit::reexports::client::Connection, 239 | _qh: &QueueHandle, 240 | _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 241 | _new_transform: smithay_client_toolkit::reexports::client::protocol::wl_output::Transform, 242 | ) { 243 | } 244 | 245 | fn frame( 246 | &mut self, 247 | _conn: &smithay_client_toolkit::reexports::client::Connection, 248 | _qh: &QueueHandle, 249 | _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 250 | _time: u32, 251 | ) { 252 | } 253 | 254 | fn surface_enter( 255 | &mut self, 256 | _conn: &Connection, 257 | _qh: &QueueHandle, 258 | _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 259 | _output: &smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput, 260 | ) { 261 | } 262 | 263 | fn surface_leave( 264 | &mut self, 265 | _conn: &Connection, 266 | _qh: &QueueHandle, 267 | _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 268 | _output: &smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput, 269 | ) { 270 | } 271 | } 272 | 273 | impl OutputHandler for DimData { 274 | fn output_state(&mut self) -> &mut OutputState { 275 | &mut self.output_state 276 | } 277 | 278 | fn new_output( 279 | &mut self, 280 | _conn: &smithay_client_toolkit::reexports::client::Connection, 281 | qh: &QueueHandle, 282 | output: smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput, 283 | ) { 284 | self.views.push(self.create_view(qh, output)); 285 | } 286 | 287 | fn update_output( 288 | &mut self, 289 | _conn: &smithay_client_toolkit::reexports::client::Connection, 290 | qh: &QueueHandle, 291 | output: smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput, 292 | ) { 293 | let new_view = self.create_view(qh, output); 294 | 295 | if let Some(view) = self.views.iter_mut().find(|v| v.output == new_view.output) { 296 | *view = new_view; 297 | } else { 298 | error!("Updating output not in views list??"); 299 | } 300 | } 301 | 302 | fn output_destroyed( 303 | &mut self, 304 | _conn: &smithay_client_toolkit::reexports::client::Connection, 305 | _qh: &QueueHandle, 306 | output: smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput, 307 | ) { 308 | self.views.retain(|v| v.output != output); 309 | } 310 | } 311 | 312 | impl SeatHandler for DimData { 313 | fn seat_state(&mut self) -> &mut SeatState { 314 | &mut self.seat_state 315 | } 316 | 317 | fn new_seat( 318 | &mut self, 319 | _conn: &smithay_client_toolkit::reexports::client::Connection, 320 | _qh: &QueueHandle, 321 | _seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat, 322 | ) { 323 | } 324 | 325 | fn new_capability( 326 | &mut self, 327 | _conn: &smithay_client_toolkit::reexports::client::Connection, 328 | qh: &QueueHandle, 329 | seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat, 330 | capability: Capability, 331 | ) { 332 | match capability { 333 | Capability::Keyboard => { 334 | self.keyboard = Some( 335 | self.seat_state 336 | .get_keyboard(qh, &seat, None) 337 | .expect("Failed to get keyboard"), 338 | ) 339 | } 340 | Capability::Pointer => { 341 | self.pointer = Some( 342 | self.seat_state 343 | .get_pointer(qh, &seat) 344 | .expect("Failed to get pointer"), 345 | ) 346 | } 347 | Capability::Touch => { 348 | self.touch = Some( 349 | self.seat_state 350 | .get_touch(qh, &seat) 351 | .expect("Failed to get touch device!"), 352 | ) 353 | } 354 | _ => debug!("Unknown capability found: {capability}"), 355 | } 356 | } 357 | 358 | fn remove_capability( 359 | &mut self, 360 | _conn: &smithay_client_toolkit::reexports::client::Connection, 361 | _qh: &QueueHandle, 362 | _seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat, 363 | capability: Capability, 364 | ) { 365 | match capability { 366 | Capability::Keyboard => self 367 | .keyboard 368 | .take() 369 | .expect("Failed to remove keyboard!") 370 | .release(), 371 | Capability::Pointer => self 372 | .pointer 373 | .take() 374 | .expect("Failed to remove pointer!") 375 | .release(), 376 | Capability::Touch => self 377 | .touch 378 | .take() 379 | .expect("Failed to remove touch device!") 380 | .release(), 381 | _ => debug!("Unknown capability removed: {capability}"), 382 | } 383 | } 384 | 385 | fn remove_seat( 386 | &mut self, 387 | _conn: &smithay_client_toolkit::reexports::client::Connection, 388 | _qh: &QueueHandle, 389 | _seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat, 390 | ) { 391 | } 392 | } 393 | 394 | impl KeyboardHandler for DimData { 395 | fn enter( 396 | &mut self, 397 | _conn: &smithay_client_toolkit::reexports::client::Connection, 398 | _qh: &QueueHandle, 399 | _keyboard: &wl_keyboard::WlKeyboard, 400 | _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 401 | _serial: u32, 402 | _raw: &[u32], 403 | _keysyms: &[smithay_client_toolkit::seat::keyboard::Keysym], 404 | ) { 405 | } 406 | 407 | fn leave( 408 | &mut self, 409 | _conn: &smithay_client_toolkit::reexports::client::Connection, 410 | _qh: &QueueHandle, 411 | _keyboard: &wl_keyboard::WlKeyboard, 412 | _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 413 | _serial: u32, 414 | ) { 415 | } 416 | 417 | fn press_key( 418 | &mut self, 419 | _conn: &smithay_client_toolkit::reexports::client::Connection, 420 | _qh: &QueueHandle, 421 | _keyboard: &wl_keyboard::WlKeyboard, 422 | _serial: u32, 423 | _event: smithay_client_toolkit::seat::keyboard::KeyEvent, 424 | ) { 425 | debug!("Key pressed"); 426 | self.exit = true; 427 | } 428 | 429 | fn release_key( 430 | &mut self, 431 | _conn: &smithay_client_toolkit::reexports::client::Connection, 432 | _qh: &QueueHandle, 433 | _keyboard: &wl_keyboard::WlKeyboard, 434 | _serial: u32, 435 | _event: smithay_client_toolkit::seat::keyboard::KeyEvent, 436 | ) { 437 | debug!("Key released"); 438 | } 439 | 440 | fn update_modifiers( 441 | &mut self, 442 | _conn: &smithay_client_toolkit::reexports::client::Connection, 443 | _qh: &QueueHandle, 444 | _keyboard: &wl_keyboard::WlKeyboard, 445 | _serial: u32, 446 | _modifiers: smithay_client_toolkit::seat::keyboard::Modifiers, 447 | _layout: u32, 448 | ) { 449 | debug!("Modifiers updated"); 450 | } 451 | } 452 | 453 | impl PointerHandler for DimData { 454 | fn pointer_frame( 455 | &mut self, 456 | _conn: &smithay_client_toolkit::reexports::client::Connection, 457 | _qh: &QueueHandle, 458 | pointer: &wl_pointer::WlPointer, 459 | events: &[PointerEvent], 460 | ) { 461 | for e in events { 462 | match e.kind { 463 | PointerEventKind::Enter { serial } => { 464 | if self.alpha == 1.0 { 465 | pointer.set_cursor(serial, None, 0, 0); 466 | } 467 | } 468 | PointerEventKind::Leave { .. } => {} 469 | _ => { 470 | debug!("Mouse event"); 471 | self.exit = true; 472 | } 473 | } 474 | } 475 | } 476 | } 477 | 478 | impl TouchHandler for DimData { 479 | fn down( 480 | &mut self, 481 | _conn: &Connection, 482 | _qh: &QueueHandle, 483 | _touch: &wl_touch::WlTouch, 484 | _serial: u32, 485 | _time: u32, 486 | _surface: smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface, 487 | _id: i32, 488 | _position: (f64, f64), 489 | ) { 490 | self.exit = true; 491 | } 492 | 493 | fn up( 494 | &mut self, 495 | _conn: &Connection, 496 | _qh: &QueueHandle, 497 | _touch: &wl_touch::WlTouch, 498 | _serial: u32, 499 | _time: u32, 500 | _id: i32, 501 | ) { 502 | } 503 | 504 | fn motion( 505 | &mut self, 506 | _conn: &Connection, 507 | _qh: &QueueHandle, 508 | _touch: &wl_touch::WlTouch, 509 | _time: u32, 510 | _id: i32, 511 | _position: (f64, f64), 512 | ) { 513 | } 514 | 515 | fn shape( 516 | &mut self, 517 | _conn: &Connection, 518 | _qh: &QueueHandle, 519 | _touch: &wl_touch::WlTouch, 520 | _id: i32, 521 | _major: f64, 522 | _minor: f64, 523 | ) { 524 | } 525 | 526 | fn orientation( 527 | &mut self, 528 | _conn: &Connection, 529 | _qh: &QueueHandle, 530 | _touch: &wl_touch::WlTouch, 531 | _id: i32, 532 | _orientation: f64, 533 | ) { 534 | } 535 | 536 | fn cancel(&mut self, _conn: &Connection, _qh: &QueueHandle, _touch: &wl_touch::WlTouch) {} 537 | } 538 | 539 | delegate_compositor!(DimData); 540 | delegate_touch!(DimData); 541 | delegate_layer!(DimData); 542 | delegate_registry!(DimData); 543 | delegate_pointer!(DimData); 544 | delegate_keyboard!(DimData); 545 | delegate_output!(DimData); 546 | delegate_seat!(DimData); 547 | delegate_simple!(DimData, WpViewporter, 1); 548 | 549 | impl ProvidesRegistryState for DimData { 550 | fn registry(&mut self) -> &mut RegistryState { 551 | &mut self.registry_state 552 | } 553 | 554 | registry_handlers![OutputState, SeatState]; 555 | } 556 | 557 | impl Dispatch for DimData { 558 | fn event( 559 | _: &mut Self, 560 | _: &WpViewport, 561 | _: wp_viewport::Event, 562 | _: &(), 563 | _: &Connection, 564 | _: &QueueHandle, 565 | ) { 566 | unreachable!("wp_single_pixel_buffer_manager_v1::Event is empty in version 1") 567 | } 568 | } 569 | 570 | impl Dispatch for DimData { 571 | fn event( 572 | _: &mut Self, 573 | _: &WpSinglePixelBufferManagerV1, 574 | _: wp_single_pixel_buffer_manager_v1::Event, 575 | _: &(), 576 | _: &Connection, 577 | _: &QueueHandle, 578 | ) { 579 | unreachable!("wp_single_pixel_buffer_manager_v1::Event is empty in version 1") 580 | } 581 | } 582 | impl Dispatch for DimData { 583 | fn event( 584 | _: &mut Self, 585 | _: &WlBuffer, 586 | event: wl_buffer::Event, 587 | _: &(), 588 | _: &Connection, 589 | _: &QueueHandle, 590 | ) { 591 | match event { 592 | wl_buffer::Event::Release => debug!("WlBuffer released"), 593 | _ => unreachable!("WlBuffer only has Release event"), 594 | } 595 | } 596 | } 597 | 598 | impl Drop for DimView { 599 | fn drop(&mut self) { 600 | self.viewport.destroy(); 601 | self.buffer.destroy(); 602 | } 603 | } 604 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod dim; 2 | pub mod opts; 3 | 4 | pub const DEFAULT_DURATION: u64 = 30; 5 | pub const DEFAULT_ALPHA: f32 = 0.5; 6 | 7 | pub const CONFIG_FILENAME: &str = "config.toml"; 8 | 9 | /// Default window size in width and height, in logical pixels 10 | pub const INIT_SIZE: u32 = 100; 11 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | borrow::Cow, 3 | env, 4 | fs::File, 5 | io::read_to_string, 6 | path::{Path, PathBuf}, 7 | process, thread, 8 | time::Duration, 9 | }; 10 | 11 | use anyhow::{anyhow, Context}; 12 | use clap::Parser; 13 | use dim_screen::{dim::DimData, opts::DimOpts, CONFIG_FILENAME, DEFAULT_ALPHA, DEFAULT_DURATION}; 14 | use log::{debug, info}; 15 | use smithay_client_toolkit::{ 16 | compositor::CompositorState, 17 | reexports::client::{globals::registry_queue_init, Connection, EventQueue}, 18 | shell::wlr_layer::LayerShell, 19 | }; 20 | 21 | fn main() -> anyhow::Result<()> { 22 | env_logger::init(); 23 | let args = DimOpts::parse(); 24 | args.validate()?; 25 | 26 | if let Some(path) = args.gen_completions { 27 | DimOpts::generate_completions(&path)?; 28 | return Ok(()); 29 | } 30 | 31 | let opts = match get_config(args.config.as_deref()).context("Failed to read config!")? { 32 | Some(config) => config.merge_onto_self(args), 33 | None => args, 34 | }; 35 | 36 | debug!("Using options: {opts:?}"); 37 | let alpha = opts.alpha.unwrap_or(DEFAULT_ALPHA); 38 | let duration = opts.duration.unwrap_or(DEFAULT_DURATION); 39 | 40 | // A duration of 0 is considered as infinite, not starting the timer: 41 | if duration > 0 { 42 | thread::spawn(move || { 43 | thread::sleep(Duration::from_secs(duration)); 44 | process::exit(0); 45 | }); 46 | } 47 | 48 | let (mut data, mut event_queue) = create_wl_app(alpha, opts.passthrough)?; 49 | while !data.should_exit() { 50 | event_queue 51 | .blocking_dispatch(&mut data) 52 | .context("Failed to block on events!")?; 53 | } 54 | 55 | Err(anyhow!("Some user input was detected!")) 56 | } 57 | 58 | fn get_config(dir: Option<&Path>) -> anyhow::Result> { 59 | let config = match dir { 60 | Some(user_config) => Cow::Borrowed(user_config), 61 | None => { 62 | // follow XDG base directory spec, checking $XDG_CONFIG_HOME first then defaulting to $HOME/.config 63 | let config_home = env::var("XDG_CONFIG_HOME") 64 | .map(PathBuf::from) 65 | .or(env::var("HOME") 66 | .map(PathBuf::from) 67 | .map(|p| p.join(".config"))); 68 | 69 | if let Ok(path) = config_home { 70 | Cow::Owned(path.join("dim").join(CONFIG_FILENAME)) 71 | } else { 72 | info!("No config path, neither XDG_CONFIG_HOME nor HOME are set."); 73 | return Ok(None); 74 | } 75 | } 76 | }; 77 | 78 | if !config.exists() { 79 | info!("No config found!"); 80 | return Ok(None); 81 | } 82 | 83 | debug!("Config file found at {config:?}"); 84 | let file = File::open(config).context("Failed to open config file")?; 85 | let config: DimOpts = toml::from_str(&read_to_string(file)?)?; 86 | 87 | debug!("Config: {config:?}"); 88 | config.validate()?; 89 | Ok(Some(config)) 90 | } 91 | 92 | fn create_wl_app(alpha: f32, passthrough: bool) -> anyhow::Result<(DimData, EventQueue)> { 93 | let conn = Connection::connect_to_env().context("Failed to connect to environment")?; 94 | 95 | let (globals, event_queue) = 96 | registry_queue_init(&conn).context("Failed to initialize registry")?; 97 | let qh = event_queue.handle(); 98 | 99 | let compositor = CompositorState::bind(&globals, &qh).context("Compositor not available")?; 100 | let layer_shell = LayerShell::bind(&globals, &qh).context("Layer shell failed?")?; 101 | 102 | Ok(( 103 | DimData::new(compositor, &globals, &qh, layer_shell, alpha, passthrough), 104 | event_queue, 105 | )) 106 | } 107 | -------------------------------------------------------------------------------- /src/opts.rs: -------------------------------------------------------------------------------- 1 | use std::path::{Path, PathBuf}; 2 | 3 | use anyhow::{anyhow, Result}; 4 | use clap::{CommandFactory, Parser, ValueEnum}; 5 | use clap_complete::{generate_to, Shell}; 6 | use serde::Deserialize; 7 | 8 | use crate::{DEFAULT_ALPHA, DEFAULT_DURATION}; 9 | 10 | #[derive(Debug, Deserialize, Parser)] 11 | #[command(author, version, about)] 12 | pub struct DimOpts { 13 | #[arg( 14 | short, 15 | long, 16 | help = format!("Duration in seconds, 0 is infinite, [default: {DEFAULT_DURATION}]") 17 | )] 18 | pub duration: Option, 19 | 20 | #[arg( 21 | short, 22 | long, 23 | help = format!("0.0 is transparent, 1.0 is opaque. When opaque, cursor will be hidden. [default: {DEFAULT_ALPHA}]") 24 | )] 25 | pub alpha: Option, 26 | 27 | #[arg( 28 | short, 29 | long, 30 | help = "Make dim ignore input, passing it to lower surfaces. (You probably want to use `-d 0` with this)" 31 | )] 32 | #[serde(default)] 33 | pub passthrough: bool, 34 | 35 | #[serde(skip)] 36 | #[arg(long, value_name = "PATH", help = "Generate completions at given path")] 37 | pub gen_completions: Option, 38 | 39 | #[serde(skip)] 40 | #[arg(short, long, value_name = "PATH", help = "Use config at path")] 41 | pub config: Option, 42 | } 43 | 44 | impl DimOpts { 45 | pub fn generate_completions(dir: &Path) -> anyhow::Result<()> { 46 | let mut cli = Self::command(); 47 | 48 | for &shell in Shell::value_variants() { 49 | let comp_file = generate_to(shell, &mut cli, "dim", dir)?; 50 | println!("Generated completion for {shell} at {comp_file:?}"); 51 | } 52 | 53 | Ok(()) 54 | } 55 | 56 | /// Merge other onto self, with other's values taking precedent 57 | pub fn merge_onto_self(self, other: DimOpts) -> Self { 58 | Self { 59 | duration: other.duration.or(self.duration), 60 | alpha: other.alpha.or(self.alpha), 61 | passthrough: self.passthrough || other.passthrough, 62 | 63 | ..self 64 | } 65 | } 66 | 67 | pub fn validate(&self) -> Result<()> { 68 | if let Some(alpha) = self.alpha { 69 | if !(0.0..=1.0).contains(&alpha) { 70 | return Err(anyhow!("Alpha can only be from 0.0 to 1.0 inclusive.")); 71 | } 72 | } 73 | 74 | Ok(()) 75 | } 76 | } 77 | --------------------------------------------------------------------------------