From d9a10c76b0296b11aa556794e0fe1a60a54d5c2d Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 9 Apr 2023 13:14:10 -0400 Subject: [PATCH 01/11] Start building a rendering for a cyberpunk-style splash screen --- cyberpunk-splash/Cargo.lock | 729 +++++++++++++++++++++++++++++++++++ cyberpunk-splash/Cargo.toml | 12 + cyberpunk-splash/src/main.rs | 198 ++++++++++ 3 files changed, 939 insertions(+) create mode 100644 cyberpunk-splash/Cargo.lock create mode 100644 cyberpunk-splash/Cargo.toml create mode 100644 cyberpunk-splash/src/main.rs diff --git a/cyberpunk-splash/Cargo.lock b/cyberpunk-splash/Cargo.lock new file mode 100644 index 0000000..abd6991 --- /dev/null +++ b/cyberpunk-splash/Cargo.lock @@ -0,0 +1,729 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cairo-rs" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8af54f5d48af1226928adc1f57edd22f5df1349e7da1fc96ae15cf43db0e871" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55382a01d30e5e53f185eee269124f5e21ab526595b872751278dfbb463594e" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "cfg-expr" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35b255461940a32985c627ce82900867c61db1659764d3675ea81963f72a4c6" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cyberpunk-splash" +version = "0.1.0" +dependencies = [ + "cairo-rs", + "gio", + "glib", + "gtk4", +] + +[[package]] +name = "field-offset" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b023fbe0c6b407bd3d9805d107d9800da3829dc5a676653210f1d5f16d7f59bf" +dependencies = [ + "bitflags", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b41bd2b44ed49d99277d3925652a163038bd5ed943ec9809338ffb2f4391e3b" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk4" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3abf96408a26e3eddf881a7f893a1e111767137136e347745e8ea6ed12731ff" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk-pixbuf", + "gdk4-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk4-sys" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc92aa1608c089c49393d014c38ac0390d01e4841e1fedaa75dbcef77aaed64" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gio" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261a3b4e922ec676d1c27ac466218c38cf5dcb49a759129e54bb5046e442125" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1d43b0d7968b48455244ecafe41192871257f5740aa6b095eb19db78e362a5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb53061756195d76969292c2d2e329e01259276524a9bae6c9b73af62854773" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4cf346122086f196260783aa58987190dbd5f43bfab01946d2bf9786e8d9ef" +dependencies = [ + "anyhow", + "heck", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "glib-sys" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f00ad0a1bf548e61adfff15d83430941d9e1bb620e334f779edd1c745680a5" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e75b0000a64632b2d8ca3cf856af9308e3a970844f6e9659bd197f026793d0" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "graphene-rs" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cf11565bb0e4dfc2f99d4775b6c329f0d40a2cff9c0066214d31a0e1b46256" +dependencies = [ + "glib", + "graphene-sys", + "libc", +] + +[[package]] +name = "graphene-sys" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf80a4849a8d9565410a8fec6fc3678e9c617f4ac7be182ca55ab75016e07af9" +dependencies = [ + "glib-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gsk4" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f01ef44fa7cac15e2da9978529383e6bee03e570ba5bf7036b4c10a15cc3a3c" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk4", + "glib", + "graphene-rs", + "gsk4-sys", + "libc", + "pango", +] + +[[package]] +name = "gsk4-sys" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07a84fb4dcf1323d29435aa85e2f5f58bef564342bef06775ec7bd0da1f01b0" +dependencies = [ + "cairo-sys-rs", + "gdk4-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk4" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e30e124b5a605f6f5513db13958bfcd51d746607b20bc7bb718b33e303274ed" +dependencies = [ + "bitflags", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk-pixbuf", + "gdk4", + "gio", + "glib", + "graphene-rs", + "gsk4", + "gtk4-macros", + "gtk4-sys", + "libc", + "once_cell", + "pango", +] + +[[package]] +name = "gtk4-macros" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f041a797fb098bfb06e432c61738133604bfa3af57f13f1da3b9d46271422ef0" +dependencies = [ + "anyhow", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "gtk4-sys" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f8283f707b07e019e76c7f2934bdd4180c277e08aa93f4c0d8dd07b7a34e22f" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk4-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "gsk4-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "libc" +version = "0.2.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "pango" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c280b82a881e4208afb3359a8e7fde27a1b272280981f1f34610bed5770d37" +dependencies = [ + "bitflags", + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4293d0f0b5525eb5c24734d30b0ed02cd02aa734f216883f376b54de49625de8" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555fc8147af6256f3931a36bb83ad0023240ce9cf2b319dec8236fd1f220b05f" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] diff --git a/cyberpunk-splash/Cargo.toml b/cyberpunk-splash/Cargo.toml new file mode 100644 index 0000000..04909e5 --- /dev/null +++ b/cyberpunk-splash/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "cyberpunk-splash" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cairo-rs = { version = "0.17" } +gio = { version = "0.17" } +glib = { version = "0.17" } +gtk = { version = "0.6", package = "gtk4" } diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs new file mode 100644 index 0000000..eedd4e9 --- /dev/null +++ b/cyberpunk-splash/src/main.rs @@ -0,0 +1,198 @@ +use cairo::{Context, FontFace, Format, ImageSurface, LineCap, Pattern}; +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; +use std::{cell::RefCell, rc::Rc}; + +const WIDTH: i32 = 800; +const HEIGHT: i32 = 800; + +pub struct SplashPrivate { + text: Rc>, + time: Rc>, + background: Rc>, +} + +impl SplashPrivate { + fn set_text(&self, text: String) { + *self.text.borrow_mut() = text; + } + + fn set_time(&self, time: String) { + *self.time.borrow_mut() = time; + } + + fn redraw_background(&self) { + let background = ImageSurface::create(Format::Rgb24, WIDTH, HEIGHT).unwrap(); + let context = Context::new(background).unwrap(); + context.push_group(); + context.set_source_rgb(0., 0., 0.); + let _ = context.paint(); + + context.set_font_size(64.); + + let title_extents = context.text_extents(&self.text.borrow()).unwrap(); + + context.set_source_rgb(0.7, 0., 1.); + context.set_line_width(5.); + context.set_line_cap(LineCap::Round); + AsymLineReturn { + orientation: gtk::Orientation::Horizontal, + start_x: 20., + start_y: 20., + start_length: 200., + center_length: title_extents.y_advance(), + end_length: 100., + width: title_extents.height(), + } + .draw(&context); + let _ = context.stroke(); + + let background = context.pop_group().unwrap(); + + *self.background.borrow_mut() = background; + } +} + +#[glib::object_subclass] +impl ObjectSubclass for SplashPrivate { + const NAME: &'static str = "Splash"; + type Type = Splash; + type ParentType = gtk::DrawingArea; + + fn new() -> SplashPrivate { + // Set up a default plain black background + let background = ImageSurface::create(Format::Rgb24, WIDTH, HEIGHT).unwrap(); + let context = Context::new(background).unwrap(); + context.push_group(); + context.set_source_rgb(0., 0., 0.); + let _ = context.paint(); + let background = context.pop_group().unwrap(); + + SplashPrivate { + text: Rc::new(RefCell::new(String::from(""))), + time: Rc::new(RefCell::new(String::from(""))), + background: Rc::new(RefCell::new(background)), + } + } +} +impl ObjectImpl for SplashPrivate {} +impl WidgetImpl for SplashPrivate {} +impl DrawingAreaImpl for SplashPrivate {} + +glib::wrapper! { + pub struct Splash(ObjectSubclass) @extends gtk::DrawingArea, gtk::Widget; +} + +impl Splash { + pub fn new(text: String, time: String) -> Self { + let s: Self = Object::builder().build(); + s.set_width_request(WIDTH); + s.set_height_request(HEIGHT); + + s.imp().set_text(text); + s.imp().set_time(time); + s.imp().redraw_background(); + + s.set_draw_func({ + let s = s.clone(); + move |_, context, _width, _height| { + let background = s.imp().background.borrow(); + let _ = context.set_source(&*background); + let _ = context.paint(); + } + }); + + s + } +} + +struct AsymLineReturn { + orientation: gtk::Orientation, + start_x: f64, + start_y: f64, + start_length: f64, + center_length: f64, + end_length: f64, + width: f64, +} + +impl AsymLineReturn { + fn draw(&self, context: &Context) { + match self.orientation { + gtk::Orientation::Horizontal => { + context.move_to(self.start_x, self.start_y); + context.line_to(self.start_x + self.start_length, self.start_y); + context.line_to( + self.start_x + self.start_length + self.width.abs(), + self.start_y + self.width, + ); + context.line_to( + self.start_x + self.start_length + self.width.abs() + self.center_length, + self.start_y + self.width, + ); + context.line_to( + self.start_x + + self.start_length + + self.width.abs() + + self.center_length + + (self.width.abs() / 2.), + self.start_y + self.width / 2., + ); + context.line_to( + self.start_x + + self.start_length + + self.width.abs() + + self.center_length + + (self.width.abs() / 2.) + + self.end_length, + self.start_y + self.width / 2., + ); + } + gtk::Orientation::Vertical => { + context.move_to(self.start_x, self.start_y); + context.line_to(self.start_x, self.start_y + self.start_length); + context.line_to( + self.start_x + self.width, + self.start_y + self.start_length + self.width.abs(), + ); + context.line_to( + self.start_x + self.width, + self.start_y + self.start_length + self.width.abs() + self.center_length, + ); + context.line_to( + self.start_x + self.width / 2., + self.start_y + + self.start_length + + self.width.abs() + + self.center_length + + (self.width.abs() / 2.), + ); + context.line_to( + self.start_x + self.width / 2., + self.start_y + + self.start_length + + self.width.abs() + + self.center_length + + (self.width.abs() / 2.) + + self.end_length, + ); + } + _ => panic!("unknown orientation"), + } + } +} + +fn main() { + let app = gtk::Application::builder() + .application_id("com.luminescent-dreams.cyberpunk-splash") + .build(); + + app.connect_activate(move |app| { + let window = gtk::ApplicationWindow::new(app); + window.present(); + + window.set_child(Some(&Splash::new("Kifu".to_owned(), "4:23".to_owned()))); + }); + + app.run(); +} -- 2.44.1 From 5e57767921199cbb8c13ea885513fd8f4d22317e Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 9 Apr 2023 18:20:29 -0400 Subject: [PATCH 02/11] Clean up the asymetric cutout line --- cyberpunk-splash/src/main.rs | 138 +++++++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 16 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index eedd4e9..5a413e3 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -1,4 +1,6 @@ -use cairo::{Context, FontFace, Format, ImageSurface, LineCap, Pattern}; +use cairo::{ + Context, FontSlant, FontWeight, Format, ImageSurface, LineCap, LinearGradient, Pattern, +}; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; use std::{cell::RefCell, rc::Rc}; @@ -28,24 +30,53 @@ impl SplashPrivate { context.set_source_rgb(0., 0., 0.); let _ = context.paint(); + context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold); context.set_font_size(64.); - let title_extents = context.text_extents(&self.text.borrow()).unwrap(); + let center_x = WIDTH as f64 / 2.; + let center_y = HEIGHT as f64 / 2.; - context.set_source_rgb(0.7, 0., 1.); - context.set_line_width(5.); - context.set_line_cap(LineCap::Round); - AsymLineReturn { - orientation: gtk::Orientation::Horizontal, - start_x: 20., - start_y: 20., - start_length: 200., - center_length: title_extents.y_advance(), - end_length: 100., - width: title_extents.height(), + let (title_width, title_height) = { + let title_extents = context.text_extents(&self.text.borrow()).unwrap(); + + let title_baseline_x = center_x - title_extents.width() / 2.; + let title_baseline_y = center_y - 20.; + + let gradient = LinearGradient::new( + title_baseline_x, + title_baseline_y - title_extents.height(), + title_baseline_x, + title_baseline_y, + ); + gradient.add_color_stop_rgb(0.2, 0.7, 0.0, 1.0); + gradient.add_color_stop_rgb(0.8, 0.2, 0.0, 1.0); + context.move_to(title_baseline_x, title_baseline_y); + let _ = context.set_source(gradient); + let _ = context.show_text(&self.text.borrow()); + + (title_extents.width(), title_extents.height()) + }; + + { + context.set_source_rgb(0.7, 0., 1.); + context.set_line_width(5.); + context.set_line_cap(LineCap::Round); + + let start_length = center_x - title_width / 2. - title_height - 20.; + + AsymLineCutout { + orientation: gtk::Orientation::Horizontal, + start_x: 20., + start_y: center_y - 20. - title_height / 2., + start_length, + total_length: WIDTH as f64 - 120., + cutout_length: title_width, + height: title_height, + invert: false, + } + .draw(&context); + let _ = context.stroke(); } - .draw(&context); - let _ = context.stroke(); let background = context.pop_group().unwrap(); @@ -106,6 +137,81 @@ impl Splash { } } +struct AsymLineCutout { + orientation: gtk::Orientation, + start_x: f64, + start_y: f64, + start_length: f64, + total_length: f64, + cutout_length: f64, + height: f64, + invert: bool, +} + +impl AsymLineCutout { + fn draw(&self, context: &Context) { + let dodge = if self.invert { + self.height + } else { + -self.height + }; + match self.orientation { + gtk::Orientation::Horizontal => { + context.move_to(self.start_x, self.start_y); + context.line_to(self.start_x + self.start_length, self.start_y); + context.line_to( + self.start_x + self.start_length + self.height, + self.start_y + dodge, + ); + context.line_to( + self.start_x + self.start_length + self.height + self.cutout_length, + self.start_y + dodge, + ); + context.line_to( + self.start_x + + self.start_length + + self.height + + self.cutout_length + + (self.height / 2.), + self.start_y + dodge / 2., + ); + context.line_to(self.total_length, self.start_y + dodge / 2.); + } + gtk::Orientation::Vertical => { + /* + context.move_to(self.start_x, self.start_y); + context.line_to(self.start_x, self.start_y + self.start_length); + context.line_to( + self.start_x + self.height, + self.start_y + self.start_length + self.height, + ); + context.line_to( + self.start_x + self.height, + self.start_y + self.start_length + self.height + self.center_length, + ); + context.line_to( + self.start_x + self.height / 2., + self.start_y + + self.start_length + + self.height + + self.center_length + + (self.height / 2.), + ); + context.line_to( + self.start_x + self.height / 2., + self.start_y + + self.start_length + + self.height + + self.center_length + + (self.height / 2.) + + self.end_length, + ); + */ + } + _ => panic!("unknown orientation"), + } + } +} struct AsymLineReturn { orientation: gtk::Orientation, start_x: f64, @@ -191,7 +297,7 @@ fn main() { let window = gtk::ApplicationWindow::new(app); window.present(); - window.set_child(Some(&Splash::new("Kifu".to_owned(), "4:23".to_owned()))); + window.set_child(Some(&Splash::new("GTK Kifu".to_owned(), "4:23".to_owned()))); }); app.run(); -- 2.44.1 From 40e2fbf658a9a5821e0652ae42bb51a4941a9b3a Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 9 Apr 2023 20:07:12 -0400 Subject: [PATCH 03/11] Add the clock and some extra lines --- cyberpunk-splash/src/main.rs | 199 +++++++++++++++++------------------ 1 file changed, 98 insertions(+), 101 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index 5a413e3..019df6a 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -5,8 +5,8 @@ use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; use std::{cell::RefCell, rc::Rc}; -const WIDTH: i32 = 800; -const HEIGHT: i32 = 800; +const WIDTH: i32 = 1920; +const HEIGHT: i32 = 1280; pub struct SplashPrivate { text: Rc>, @@ -31,40 +31,19 @@ impl SplashPrivate { let _ = context.paint(); context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold); - context.set_font_size(64.); + context.set_font_size(128.); let center_x = WIDTH as f64 / 2.; let center_y = HEIGHT as f64 / 2.; - let (title_width, title_height) = { - let title_extents = context.text_extents(&self.text.borrow()).unwrap(); - - let title_baseline_x = center_x - title_extents.width() / 2.; - let title_baseline_y = center_y - 20.; - - let gradient = LinearGradient::new( - title_baseline_x, - title_baseline_y - title_extents.height(), - title_baseline_x, - title_baseline_y, - ); - gradient.add_color_stop_rgb(0.2, 0.7, 0.0, 1.0); - gradient.add_color_stop_rgb(0.8, 0.2, 0.0, 1.0); - context.move_to(title_baseline_x, title_baseline_y); - let _ = context.set_source(gradient); - let _ = context.show_text(&self.text.borrow()); - - (title_extents.width(), title_extents.height()) - }; + let title_extents = context.text_extents(&self.text.borrow()).unwrap(); + let title_width = title_extents.width(); + let title_height = title_extents.height(); { - context.set_source_rgb(0.7, 0., 1.); - context.set_line_width(5.); - context.set_line_cap(LineCap::Round); - let start_length = center_x - title_width / 2. - title_height - 20.; - AsymLineCutout { + let title_cutout = AsymLineCutout { orientation: gtk::Orientation::Horizontal, start_x: 20., start_y: center_y - 20. - title_height / 2., @@ -73,11 +52,81 @@ impl SplashPrivate { cutout_length: title_width, height: title_height, invert: false, + }; + + context.set_line_cap(LineCap::Round); + context.set_source_rgb(0.7, 0., 1.); + context.set_line_width(2.); + title_cutout.draw(&context); + let _ = context.stroke(); + } + + { + let title_baseline_x = center_x - title_width / 2.; + let title_baseline_y = center_y - 20.; + + let gradient = LinearGradient::new( + title_baseline_x, + title_baseline_y - title_height, + title_baseline_x, + title_baseline_y, + ); + gradient.add_color_stop_rgb(0.2, 0.7, 0.0, 1.0); + gradient.add_color_stop_rgb(0.8, 0.2, 0.0, 1.0); + context.move_to(title_baseline_x, title_baseline_y); + let _ = context.set_source(gradient); + let _ = context.show_text(&self.text.borrow()); + } + + { + context.set_source_rgb(0.7, 0., 1.); + AsymLine { + orientation: gtk::Orientation::Horizontal, + start_x: 100., + start_y: HEIGHT as f64 / 2. + 100., + start_length: 400., + height: 50., + total_length: 650., + invert: true, } .draw(&context); let _ = context.stroke(); } + { + context.set_source_rgb(0.7, 0., 1.); + AsymLine { + orientation: gtk::Orientation::Horizontal, + start_x: WIDTH as f64 / 2. + 100., + start_y: HEIGHT as f64 / 2. + 200., + start_length: 600., + height: 50., + total_length: 650., + invert: false, + } + .draw(&context); + let _ = context.stroke(); + } + + { + context.set_font_size(128.); + let time_extents = context.text_extents(&self.time.borrow()).unwrap(); + let time_baseline_x = center_x - time_extents.width() / 2.; + let time_baseline_y = center_y + 100.; + + let gradient = LinearGradient::new( + time_baseline_x, + time_baseline_y - time_extents.height(), + time_baseline_x, + time_baseline_y, + ); + gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); + gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0); + context.move_to(time_baseline_x, time_baseline_y); + let _ = context.set_source(gradient); + let _ = context.show_text(&self.time.borrow()); + } + let background = context.pop_group().unwrap(); *self.background.borrow_mut() = background; @@ -178,111 +227,59 @@ impl AsymLineCutout { context.line_to(self.total_length, self.start_y + dodge / 2.); } gtk::Orientation::Vertical => { - /* context.move_to(self.start_x, self.start_y); context.line_to(self.start_x, self.start_y + self.start_length); context.line_to( - self.start_x + self.height, + self.start_x + dodge, self.start_y + self.start_length + self.height, ); context.line_to( - self.start_x + self.height, - self.start_y + self.start_length + self.height + self.center_length, + self.start_x + dodge, + self.start_y + self.start_length + self.height + self.cutout_length, ); context.line_to( - self.start_x + self.height / 2., + self.start_x + dodge / 2., self.start_y + self.start_length + self.height - + self.center_length + + self.cutout_length + (self.height / 2.), ); - context.line_to( - self.start_x + self.height / 2., - self.start_y - + self.start_length - + self.height - + self.center_length - + (self.height / 2.) - + self.end_length, - ); - */ + context.line_to(self.start_x + dodge / 2., self.total_length); } _ => panic!("unknown orientation"), } } } -struct AsymLineReturn { + +struct AsymLine { orientation: gtk::Orientation, start_x: f64, start_y: f64, start_length: f64, - center_length: f64, - end_length: f64, - width: f64, + height: f64, + total_length: f64, + invert: bool, } -impl AsymLineReturn { +impl AsymLine { fn draw(&self, context: &Context) { + let dodge = if self.invert { + self.height + } else { + -self.height + }; match self.orientation { gtk::Orientation::Horizontal => { context.move_to(self.start_x, self.start_y); context.line_to(self.start_x + self.start_length, self.start_y); context.line_to( - self.start_x + self.start_length + self.width.abs(), - self.start_y + self.width, - ); - context.line_to( - self.start_x + self.start_length + self.width.abs() + self.center_length, - self.start_y + self.width, - ); - context.line_to( - self.start_x - + self.start_length - + self.width.abs() - + self.center_length - + (self.width.abs() / 2.), - self.start_y + self.width / 2., - ); - context.line_to( - self.start_x - + self.start_length - + self.width.abs() - + self.center_length - + (self.width.abs() / 2.) - + self.end_length, - self.start_y + self.width / 2., - ); - } - gtk::Orientation::Vertical => { - context.move_to(self.start_x, self.start_y); - context.line_to(self.start_x, self.start_y + self.start_length); - context.line_to( - self.start_x + self.width, - self.start_y + self.start_length + self.width.abs(), - ); - context.line_to( - self.start_x + self.width, - self.start_y + self.start_length + self.width.abs() + self.center_length, - ); - context.line_to( - self.start_x + self.width / 2., - self.start_y - + self.start_length - + self.width.abs() - + self.center_length - + (self.width.abs() / 2.), - ); - context.line_to( - self.start_x + self.width / 2., - self.start_y - + self.start_length - + self.width.abs() - + self.center_length - + (self.width.abs() / 2.) - + self.end_length, + self.start_x + self.start_length + self.height, + self.start_y + dodge, ); + context.line_to(self.start_x + self.total_length, self.start_y + dodge); } + gtk::Orientation::Vertical => {} _ => panic!("unknown orientation"), } } -- 2.44.1 From e7bf84a744e7801dda3375153e86c9de340f4f66 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 9 Apr 2023 20:31:52 -0400 Subject: [PATCH 04/11] Count down the clock --- cyberpunk-splash/src/main.rs | 96 ++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index 019df6a..fe95cd3 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -3,14 +3,18 @@ use cairo::{ }; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; -use std::{cell::RefCell, rc::Rc}; +use std::{ + cell::RefCell, + rc::Rc, + time::{Duration, Instant}, +}; const WIDTH: i32 = 1920; const HEIGHT: i32 = 1280; pub struct SplashPrivate { text: Rc>, - time: Rc>, + time: Rc>, background: Rc>, } @@ -19,7 +23,7 @@ impl SplashPrivate { *self.text.borrow_mut() = text; } - fn set_time(&self, time: String) { + fn set_time(&self, time: Duration) { *self.time.borrow_mut() = time; } @@ -108,25 +112,6 @@ impl SplashPrivate { let _ = context.stroke(); } - { - context.set_font_size(128.); - let time_extents = context.text_extents(&self.time.borrow()).unwrap(); - let time_baseline_x = center_x - time_extents.width() / 2.; - let time_baseline_y = center_y + 100.; - - let gradient = LinearGradient::new( - time_baseline_x, - time_baseline_y - time_extents.height(), - time_baseline_x, - time_baseline_y, - ); - gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); - gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0); - context.move_to(time_baseline_x, time_baseline_y); - let _ = context.set_source(gradient); - let _ = context.show_text(&self.time.borrow()); - } - let background = context.pop_group().unwrap(); *self.background.borrow_mut() = background; @@ -150,7 +135,7 @@ impl ObjectSubclass for SplashPrivate { SplashPrivate { text: Rc::new(RefCell::new(String::from(""))), - time: Rc::new(RefCell::new(String::from(""))), + time: Rc::new(RefCell::new(Duration::ZERO)), background: Rc::new(RefCell::new(background)), } } @@ -164,7 +149,7 @@ glib::wrapper! { } impl Splash { - pub fn new(text: String, time: String) -> Self { + pub fn new(text: String, time: Duration) -> Self { let s: Self = Object::builder().build(); s.set_width_request(WIDTH); s.set_height_request(HEIGHT); @@ -175,15 +160,53 @@ impl Splash { s.set_draw_func({ let s = s.clone(); - move |_, context, _width, _height| { + move |_, context, width, height| { let background = s.imp().background.borrow(); let _ = context.set_source(&*background); let _ = context.paint(); + + { + let center_x = width as f64 / 2.; + let center_y = height as f64 / 2.; + + context.select_font_face( + "Alegreya Sans SC", + FontSlant::Normal, + FontWeight::Bold, + ); + context.set_font_size(128.); + + let time = s.imp().time.borrow().clone(); + let minutes = time.as_secs() / 60; + let seconds = time.as_secs() % 60; + let time = format!("{:02}' {:02}\"", minutes, seconds); + + let time_extents = context.text_extents(&time).unwrap(); + let time_baseline_x = center_x - time_extents.width() / 2.; + let time_baseline_y = center_y + 100.; + + let gradient = LinearGradient::new( + time_baseline_x, + time_baseline_y - time_extents.height(), + time_baseline_x, + time_baseline_y, + ); + gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); + gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0); + context.move_to(time_baseline_x, time_baseline_y); + let _ = context.set_source(gradient); + let _ = context.show_text(&time); + } } }); s } + + pub fn set_time(&self, time: Duration) { + self.imp().set_time(time); + self.queue_draw(); + } } struct AsymLineCutout { @@ -291,10 +314,31 @@ fn main() { .build(); app.connect_activate(move |app| { + let (gtk_tx, gtk_rx) = + gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT); let window = gtk::ApplicationWindow::new(app); window.present(); - window.set_child(Some(&Splash::new("GTK Kifu".to_owned(), "4:23".to_owned()))); + let mut countdown = Duration::from_secs(5 * 60); + let mut next_tick = Instant::now() + Duration::from_secs(1); + + let splash = Splash::new("GTK Kifu".to_owned(), countdown.clone()); + + window.set_child(Some(&splash)); + + gtk_rx.attach(None, move |time| { + splash.set_time(time); + Continue(true) + }); + + std::thread::spawn(move || loop { + std::thread::sleep(Duration::from_secs(1)); + if Instant::now() >= next_tick { + countdown = countdown - Duration::from_secs(1); + let _ = gtk_tx.send(countdown); + next_tick = next_tick + Duration::from_secs(1); + } + }); }); app.run(); -- 2.44.1 From bed75dc669f870a7efb2e4744bd76e23a3eeacaf Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 9 Apr 2023 21:07:12 -0400 Subject: [PATCH 05/11] Add a slash meter --- cyberpunk-splash/src/main.rs | 79 +++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index fe95cd3..70776ca 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -1,5 +1,6 @@ use cairo::{ Context, FontSlant, FontWeight, Format, ImageSurface, LineCap, LinearGradient, Pattern, + TextExtents, }; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; @@ -16,6 +17,7 @@ pub struct SplashPrivate { text: Rc>, time: Rc>, background: Rc>, + time_extents: Rc>>, } impl SplashPrivate { @@ -137,6 +139,7 @@ impl ObjectSubclass for SplashPrivate { text: Rc::new(RefCell::new(String::from(""))), time: Rc::new(RefCell::new(Duration::ZERO)), background: Rc::new(RefCell::new(background)), + time_extents: Rc::new(RefCell::new(None)), } } } @@ -165,10 +168,14 @@ impl Splash { let _ = context.set_source(&*background); let _ = context.paint(); - { - let center_x = width as f64 / 2.; - let center_y = height as f64 / 2.; + let time = s.imp().time.borrow().clone(); + let minutes = time.as_secs() / 60; + let seconds = time.as_secs() % 60; + let center_x = width as f64 / 2.; + let center_y = height as f64 / 2.; + + { context.select_font_face( "Alegreya Sans SC", FontSlant::Normal, @@ -176,12 +183,15 @@ impl Splash { ); context.set_font_size(128.); - let time = s.imp().time.borrow().clone(); - let minutes = time.as_secs() / 60; - let seconds = time.as_secs() % 60; let time = format!("{:02}' {:02}\"", minutes, seconds); let time_extents = context.text_extents(&time).unwrap(); + + let mut saved_extents = s.imp().time_extents.borrow_mut(); + if saved_extents.is_none() { + *saved_extents = Some(time_extents.clone()); + } + let time_baseline_x = center_x - time_extents.width() / 2.; let time_baseline_y = center_y + 100.; @@ -196,6 +206,23 @@ impl Splash { context.move_to(time_baseline_x, time_baseline_y); let _ = context.set_source(gradient); let _ = context.show_text(&time); + }; + + match *s.imp().time_extents.borrow() { + Some(extents) => { + context.set_source_rgb(0.7, 0.0, 1.0); + let time_meter = SlashMeter { + orientation: gtk::Orientation::Horizontal, + start_x: center_x + extents.width() / 2. + 50., + start_y: center_y + 100., + count: 5, + fill_count: minutes as u8, + height: 60., + length: 100., + }; + time_meter.draw(&context); + } + None => {} } } }); @@ -308,6 +335,46 @@ impl AsymLine { } } +struct SlashMeter { + orientation: gtk::Orientation, + start_x: f64, + start_y: f64, + count: u8, + fill_count: u8, + height: f64, + length: f64, +} + +impl SlashMeter { + fn draw(&self, context: &Context) { + match self.orientation { + gtk::Orientation::Horizontal => { + let angle: f64 = 0.8; + let run = self.height / angle.tan(); + let width = self.length as f64 / (self.count as f64 * 2.); + + for c in 0..self.count { + context.set_line_width(1.); + + let start_x = self.start_x + c as f64 * width * 2.; + context.move_to(start_x, self.start_y); + context.line_to(start_x + run, self.start_y - self.height); + context.line_to(start_x + run + width, self.start_y - self.height); + context.line_to(start_x + width, self.start_y); + context.line_to(start_x, self.start_y); + if c < self.fill_count { + let _ = context.fill(); + } else { + let _ = context.stroke(); + } + } + } + gtk::Orientation::Vertical => {} + _ => panic!("unknown orientation"), + } + } +} + fn main() { let app = gtk::Application::builder() .application_id("com.luminescent-dreams.cyberpunk-splash") -- 2.44.1 From 4da592ad45db0e5847eb1b45bb8dc365c03078c1 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 9 Apr 2023 23:55:15 -0400 Subject: [PATCH 06/11] Add screen resize support and animation timeout --- cyberpunk-splash/src/main.rs | 169 +++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 19 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index 70776ca..b070c3a 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -10,14 +10,49 @@ use std::{ time::{Duration, Instant}, }; -const WIDTH: i32 = 1920; -const HEIGHT: i32 = 1280; +const WIDTH: i32 = 1600; +const HEIGHT: i32 = 600; + +#[derive(Clone, Copy, Debug)] +enum Event { + Frames(u8), + Time(Duration), +} + +struct TimeoutAnimation { + intensity: f64, + duration: f64, + ascending: bool, +} + +impl TimeoutAnimation { + fn tick(&mut self, frames_elapsed: u8) { + let step_size = 1. / (self.duration * 60.); + if self.ascending { + self.intensity = self.intensity + step_size * frames_elapsed as f64; + if self.intensity > 1. { + self.intensity = 1.0; + self.ascending = false; + } + } else { + self.intensity = self.intensity - step_size * frames_elapsed as f64; + if self.intensity < 0. { + self.intensity = 0.0; + self.ascending = true; + } + } + } +} pub struct SplashPrivate { text: Rc>, time: Rc>, background: Rc>, time_extents: Rc>>, + width: Rc>, + height: Rc>, + + timeout_animation: Rc>>, } impl SplashPrivate { @@ -30,7 +65,9 @@ impl SplashPrivate { } fn redraw_background(&self) { - let background = ImageSurface::create(Format::Rgb24, WIDTH, HEIGHT).unwrap(); + let background = + ImageSurface::create(Format::Rgb24, *self.width.borrow(), *self.height.borrow()) + .unwrap(); let context = Context::new(background).unwrap(); context.push_group(); context.set_source_rgb(0., 0., 0.); @@ -39,8 +76,8 @@ impl SplashPrivate { context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold); context.set_font_size(128.); - let center_x = WIDTH as f64 / 2.; - let center_y = HEIGHT as f64 / 2.; + let center_x = *self.width.borrow() as f64 / 2.; + let center_y = *self.height.borrow() as f64 / 2.; let title_extents = context.text_extents(&self.text.borrow()).unwrap(); let title_width = title_extents.width(); @@ -54,7 +91,7 @@ impl SplashPrivate { start_x: 20., start_y: center_y - 20. - title_height / 2., start_length, - total_length: WIDTH as f64 - 120., + total_length: *self.width.borrow() as f64 - 120., cutout_length: title_width, height: title_height, invert: false, @@ -89,7 +126,7 @@ impl SplashPrivate { AsymLine { orientation: gtk::Orientation::Horizontal, start_x: 100., - start_y: HEIGHT as f64 / 2. + 100., + start_y: *self.height.borrow() as f64 / 2. + 100., start_length: 400., height: 50., total_length: 650., @@ -103,8 +140,8 @@ impl SplashPrivate { context.set_source_rgb(0.7, 0., 1.); AsymLine { orientation: gtk::Orientation::Horizontal, - start_x: WIDTH as f64 / 2. + 100., - start_y: HEIGHT as f64 / 2. + 200., + start_x: *self.width.borrow() as f64 / 2. + 100., + start_y: *self.height.borrow() as f64 / 2. + 200., start_length: 600., height: 50., total_length: 650., @@ -140,6 +177,9 @@ impl ObjectSubclass for SplashPrivate { time: Rc::new(RefCell::new(Duration::ZERO)), background: Rc::new(RefCell::new(background)), time_extents: Rc::new(RefCell::new(None)), + width: Rc::new(RefCell::new(WIDTH)), + height: Rc::new(RefCell::new(HEIGHT)), + timeout_animation: Rc::new(RefCell::new(None)), } } } @@ -175,6 +215,8 @@ impl Splash { let center_x = width as f64 / 2.; let center_y = height as f64 / 2.; + {} + { context.select_font_face( "Alegreya Sans SC", @@ -195,16 +237,42 @@ impl Splash { let time_baseline_x = center_x - time_extents.width() / 2.; let time_baseline_y = center_y + 100.; + /* + match *s.imp().timeout_animation.borrow() { + Some(ref animation) => { + context.set_source_rgb(animation.intensity / 2., 0., 0.); + RoundedRectangle { + x: time_baseline_x - 5., + y: time_baseline_y + 10., + width: time_extents.width() + 15., + height: time_extents.height() + 15., + } + .draw(&context); + // let _ = context.fill(); + } + None => {} + } + */ + let gradient = LinearGradient::new( time_baseline_x, time_baseline_y - time_extents.height(), time_baseline_x, time_baseline_y, ); - gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); - gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0); + match *s.imp().timeout_animation.borrow() { + Some(ref animation) => { + gradient.add_color_stop_rgba(0.2, 0.2, 0.0, 1.0, animation.intensity); + gradient.add_color_stop_rgba(0.8, 0.7, 0.0, 1.0, animation.intensity); + let _ = context.set_source(gradient); + } + None => { + gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); + gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0); + let _ = context.set_source(gradient); + } + } context.move_to(time_baseline_x, time_baseline_y); - let _ = context.set_source(gradient); let _ = context.show_text(&time); }; @@ -227,13 +295,37 @@ impl Splash { } }); + s.connect_resize(|s, width, height| { + *s.imp().width.borrow_mut() = width; + *s.imp().height.borrow_mut() = height; + s.imp().redraw_background(); + }); + s } pub fn set_time(&self, time: Duration) { self.imp().set_time(time); + if time == Duration::ZERO { + *self.imp().timeout_animation.borrow_mut() = Some(TimeoutAnimation { + intensity: 1., + duration: 1., + ascending: false, + }); + } self.queue_draw(); } + + pub fn tick(&self, frames_elapsed: u8) { + let mut animation = self.imp().timeout_animation.borrow_mut(); + match *animation { + Some(ref mut animation) => { + animation.tick(frames_elapsed); + self.queue_draw(); + } + None => {} + } + } } struct AsymLineCutout { @@ -335,6 +427,36 @@ impl AsymLine { } } +struct RoundedRectangle { + x: f64, + y: f64, + width: f64, + height: f64, +} + +impl RoundedRectangle { + fn draw(&self, context: &Context) { + context.arc( + self.x, + self.y - self.height / 2., + self.height / 2., + 0.5 * std::f64::consts::PI, + 1.5 * std::f64::consts::PI, + ); + let _ = context.fill(); + context.arc( + self.x + self.width, + self.y - self.height / 2., + self.height / 2., + 1.5 * std::f64::consts::PI, + 0.5 * std::f64::consts::PI, + ); + let _ = context.fill(); + context.rectangle(self.x, self.y, self.width, -self.height); + let _ = context.fill(); + } +} + struct SlashMeter { orientation: gtk::Orientation, start_x: f64, @@ -382,27 +504,36 @@ fn main() { app.connect_activate(move |app| { let (gtk_tx, gtk_rx) = - gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT); + gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT); let window = gtk::ApplicationWindow::new(app); window.present(); - let mut countdown = Duration::from_secs(5 * 60); + let mut countdown = Duration::from_secs(5); let mut next_tick = Instant::now() + Duration::from_secs(1); let splash = Splash::new("GTK Kifu".to_owned(), countdown.clone()); window.set_child(Some(&splash)); + // window.fullscreen(); - gtk_rx.attach(None, move |time| { - splash.set_time(time); + window.connect_maximized_notify(|window| { + window.fullscreen(); + }); + + gtk_rx.attach(None, move |event| { + match event { + Event::Frames(frames) => splash.tick(frames), + Event::Time(time) => splash.set_time(time), + }; Continue(true) }); std::thread::spawn(move || loop { - std::thread::sleep(Duration::from_secs(1)); - if Instant::now() >= next_tick { + std::thread::sleep(Duration::from_millis(1000 / 60)); + let _ = gtk_tx.send(Event::Frames(1)); + if Instant::now() >= next_tick && countdown > Duration::from_secs(0) { countdown = countdown - Duration::from_secs(1); - let _ = gtk_tx.send(countdown); + let _ = gtk_tx.send(Event::Time(countdown)); next_tick = next_tick + Duration::from_secs(1); } }); -- 2.44.1 From 8d7574da165fcf3880e6338c7ce7c1f4f737c9d8 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Mon, 10 Apr 2023 00:20:39 -0400 Subject: [PATCH 07/11] Set up keyboard handling --- cyberpunk-splash/src/main.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index b070c3a..e740699 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -2,8 +2,8 @@ use cairo::{ Context, FontSlant, FontWeight, Format, ImageSurface, LineCap, LinearGradient, Pattern, TextExtents, }; -use glib::Object; -use gtk::{prelude::*, subclass::prelude::*}; +use glib::{GString, Object}; +use gtk::{gdk::Key, prelude::*, subclass::prelude::*, EventControllerKey}; use std::{ cell::RefCell, rc::Rc, @@ -514,12 +514,28 @@ fn main() { let splash = Splash::new("GTK Kifu".to_owned(), countdown.clone()); window.set_child(Some(&splash)); - // window.fullscreen(); window.connect_maximized_notify(|window| { window.fullscreen(); }); + let keyboard_events = EventControllerKey::new(); + keyboard_events.connect_key_released({ + let window = window.clone(); + move |_, key, _, _| { + let name = key + .name() + .map(|s| s.as_str().to_owned()) + .unwrap_or("".to_owned()); + match name.as_ref() { + "Escape" => window.unfullscreen(), + "space" => println!("space pressed"), + _ => {} + } + } + }); + window.add_controller(keyboard_events); + gtk_rx.attach(None, move |event| { match event { Event::Frames(frames) => splash.tick(frames), -- 2.44.1 From 8f4a8b77bcf013faa3eefc90077a6e9fa1a73bf6 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Mon, 10 Apr 2023 01:18:26 -0400 Subject: [PATCH 08/11] Extract state management and add play and pause --- cyberpunk-splash/src/main.rs | 190 +++++++++++++++++++++++------------ 1 file changed, 123 insertions(+), 67 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index e740699..211655c 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -7,6 +7,7 @@ use gtk::{gdk::Key, prelude::*, subclass::prelude::*, EventControllerKey}; use std::{ cell::RefCell, rc::Rc, + sync::{Arc, RwLock}, time::{Duration, Instant}, }; @@ -19,7 +20,85 @@ enum Event { Time(Duration), } -struct TimeoutAnimation { +#[derive(Clone, Copy, Debug)] +pub enum State { + Running { + last_update: Instant, + deadline: Instant, + timeout: Option, + }, + Paused { + time_remaining: Duration, + timeout: Option, + }, +} + +impl State { + fn new(countdown: Duration) -> Self { + Self::Paused { + time_remaining: countdown, + timeout: None, + } + } + + fn start(&mut self) { + if let Self::Paused { + time_remaining, + timeout, + } = self + { + *self = Self::Running { + last_update: Instant::now(), + deadline: Instant::now() + *time_remaining, + timeout: timeout.clone(), + }; + } + } + + fn pause(&mut self) { + if let Self::Running { + deadline, timeout, .. + } = self + { + *self = Self::Paused { + time_remaining: *deadline - Instant::now(), + timeout: timeout.clone(), + } + } + } + + fn start_pause(&mut self) { + match self { + Self::Running { .. } => self.pause(), + Self::Paused { .. } => self.start(), + } + } + + fn run(&mut self, now: Instant) { + if let Self::Running { + last_update, + deadline, + timeout, + } = self + { + *last_update = now; + if let Some(ref mut timeout) = timeout { + // TODO: figure out the actual number of frames + timeout.tick(1); + } + if *last_update > *deadline && timeout.is_none() { + *timeout = Some(TimeoutAnimation { + intensity: 1., + duration: 1., + ascending: false, + }); + } + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct TimeoutAnimation { intensity: f64, duration: f64, ascending: bool, @@ -46,13 +125,12 @@ impl TimeoutAnimation { pub struct SplashPrivate { text: Rc>, - time: Rc>, background: Rc>, time_extents: Rc>>, width: Rc>, height: Rc>, - timeout_animation: Rc>>, + state: Rc>, } impl SplashPrivate { @@ -60,8 +138,8 @@ impl SplashPrivate { *self.text.borrow_mut() = text; } - fn set_time(&self, time: Duration) { - *self.time.borrow_mut() = time; + fn set_state(&self, state: State) { + *self.state.borrow_mut() = state; } fn redraw_background(&self) { @@ -174,12 +252,12 @@ impl ObjectSubclass for SplashPrivate { SplashPrivate { text: Rc::new(RefCell::new(String::from(""))), - time: Rc::new(RefCell::new(Duration::ZERO)), background: Rc::new(RefCell::new(background)), time_extents: Rc::new(RefCell::new(None)), width: Rc::new(RefCell::new(WIDTH)), height: Rc::new(RefCell::new(HEIGHT)), - timeout_animation: Rc::new(RefCell::new(None)), + + state: Rc::new(RefCell::new(State::new(Duration::ZERO))), } } } @@ -192,13 +270,13 @@ glib::wrapper! { } impl Splash { - pub fn new(text: String, time: Duration) -> Self { + pub fn new(text: String, state: State) -> Self { let s: Self = Object::builder().build(); s.set_width_request(WIDTH); s.set_height_request(HEIGHT); s.imp().set_text(text); - s.imp().set_time(time); + s.imp().set_state(state); s.imp().redraw_background(); s.set_draw_func({ @@ -208,15 +286,18 @@ impl Splash { let _ = context.set_source(&*background); let _ = context.paint(); - let time = s.imp().time.borrow().clone(); + let state = s.imp().state.borrow().clone(); + + let time = match state { + State::Running { deadline, .. } => deadline - Instant::now(), + State::Paused { time_remaining, .. } => time_remaining, + }; let minutes = time.as_secs() / 60; let seconds = time.as_secs() % 60; let center_x = width as f64 / 2.; let center_y = height as f64 / 2.; - {} - { context.select_font_face( "Alegreya Sans SC", @@ -237,39 +318,30 @@ impl Splash { let time_baseline_x = center_x - time_extents.width() / 2.; let time_baseline_y = center_y + 100.; - /* - match *s.imp().timeout_animation.borrow() { - Some(ref animation) => { - context.set_source_rgb(animation.intensity / 2., 0., 0.); - RoundedRectangle { - x: time_baseline_x - 5., - y: time_baseline_y + 10., - width: time_extents.width() + 15., - height: time_extents.height() + 15., - } - .draw(&context); - // let _ = context.fill(); - } - None => {} - } - */ - let gradient = LinearGradient::new( time_baseline_x, time_baseline_y - time_extents.height(), time_baseline_x, time_baseline_y, ); - match *s.imp().timeout_animation.borrow() { + let (running, timeout_animation) = match state { + State::Running { timeout, .. } => (true, timeout.clone()), + State::Paused { timeout, .. } => (false, timeout.clone()), + }; + match timeout_animation { Some(ref animation) => { gradient.add_color_stop_rgba(0.2, 0.2, 0.0, 1.0, animation.intensity); gradient.add_color_stop_rgba(0.8, 0.7, 0.0, 1.0, animation.intensity); let _ = context.set_source(gradient); } None => { - gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); - gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0); - let _ = context.set_source(gradient); + if running { + gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); + gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0); + let _ = context.set_source(gradient); + } else { + context.set_source_rgb(0.3, 0.3, 0.3); + } } } context.move_to(time_baseline_x, time_baseline_y); @@ -304,28 +376,10 @@ impl Splash { s } - pub fn set_time(&self, time: Duration) { - self.imp().set_time(time); - if time == Duration::ZERO { - *self.imp().timeout_animation.borrow_mut() = Some(TimeoutAnimation { - intensity: 1., - duration: 1., - ascending: false, - }); - } + pub fn set_state(&self, state: State) { + self.imp().set_state(state); self.queue_draw(); } - - pub fn tick(&self, frames_elapsed: u8) { - let mut animation = self.imp().timeout_animation.borrow_mut(); - match *animation { - Some(ref mut animation) => { - animation.tick(frames_elapsed); - self.queue_draw(); - } - None => {} - } - } } struct AsymLineCutout { @@ -504,14 +558,13 @@ fn main() { app.connect_activate(move |app| { let (gtk_tx, gtk_rx) = - gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT); + gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT); let window = gtk::ApplicationWindow::new(app); window.present(); - let mut countdown = Duration::from_secs(5); - let mut next_tick = Instant::now() + Duration::from_secs(1); - - let splash = Splash::new("GTK Kifu".to_owned(), countdown.clone()); + let state = State::new(Duration::from_secs(5 * 60)); + let splash = Splash::new("GTK Kifu".to_owned(), state.clone()); + let state = Arc::new(RwLock::new(state)); window.set_child(Some(&splash)); @@ -522,6 +575,7 @@ fn main() { let keyboard_events = EventControllerKey::new(); keyboard_events.connect_key_released({ let window = window.clone(); + let state = state.clone(); move |_, key, _, _| { let name = key .name() @@ -529,28 +583,30 @@ fn main() { .unwrap_or("".to_owned()); match name.as_ref() { "Escape" => window.unfullscreen(), - "space" => println!("space pressed"), + "space" => state.write().unwrap().start_pause(), _ => {} } } }); window.add_controller(keyboard_events); - gtk_rx.attach(None, move |event| { + gtk_rx.attach(None, move |state| { + /* match event { Event::Frames(frames) => splash.tick(frames), Event::Time(time) => splash.set_time(time), }; + */ + splash.set_state(state); Continue(true) }); - std::thread::spawn(move || loop { - std::thread::sleep(Duration::from_millis(1000 / 60)); - let _ = gtk_tx.send(Event::Frames(1)); - if Instant::now() >= next_tick && countdown > Duration::from_secs(0) { - countdown = countdown - Duration::from_secs(1); - let _ = gtk_tx.send(Event::Time(countdown)); - next_tick = next_tick + Duration::from_secs(1); + std::thread::spawn(move || { + state.write().unwrap().start(); + loop { + std::thread::sleep(Duration::from_millis(1000 / 60)); + state.write().unwrap().run(Instant::now()); + let _ = gtk_tx.send(state.read().unwrap().clone()); } }); }); -- 2.44.1 From 52ac235f49ec71e5781b26db368cb3319ed29f47 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Mon, 10 Apr 2023 10:46:35 -0400 Subject: [PATCH 09/11] Start handling command line parameters --- cyberpunk-splash/src/main.rs | 68 ++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index 211655c..3cc9883 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -554,17 +554,58 @@ impl SlashMeter { fn main() { let app = gtk::Application::builder() .application_id("com.luminescent-dreams.cyberpunk-splash") + .flags(gio::ApplicationFlags::HANDLES_OPEN) .build(); + app.add_main_option( + "title", + glib::char::Char::from(b't'), + glib::OptionFlags::IN_MAIN, + glib::OptionArg::String, + "", + None, + ); + app.add_main_option( + "countdown", + glib::char::Char::from(b'c'), + glib::OptionFlags::IN_MAIN, + glib::OptionArg::String, + "", + None, + ); + + let state = Arc::new(RwLock::new(State::new(Duration::from_secs(5 * 60)))); + let title = Arc::new(RwLock::new("".to_owned())); + + app.connect_command_line(|_, args| { + println!("connect_command_line"); + 1 + }); + app.connect_handle_local_options({ + let title = title.clone(); + move |_, options| { + println!("connect_handle_local_options"); + *title.write().unwrap() = options.lookup::("title").unwrap().unwrap(); + -1 + } + }); + + app.connect_open(move |app, files, args| { + println!("called open"); + println!("files: {}", files.len()); + println!("args: {}", args); + + app.activate(); + }); + app.connect_activate(move |app| { let (gtk_tx, gtk_rx) = gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT); + let window = gtk::ApplicationWindow::new(app); window.present(); - let state = State::new(Duration::from_secs(5 * 60)); - let splash = Splash::new("GTK Kifu".to_owned(), state.clone()); - let state = Arc::new(RwLock::new(state)); + let splash = Splash::new(title.read().unwrap().clone(), state.read().unwrap().clone()); window.set_child(Some(&splash)); @@ -591,22 +632,19 @@ fn main() { window.add_controller(keyboard_events); gtk_rx.attach(None, move |state| { - /* - match event { - Event::Frames(frames) => splash.tick(frames), - Event::Time(time) => splash.set_time(time), - }; - */ splash.set_state(state); Continue(true) }); - std::thread::spawn(move || { - state.write().unwrap().start(); - loop { - std::thread::sleep(Duration::from_millis(1000 / 60)); - state.write().unwrap().run(Instant::now()); - let _ = gtk_tx.send(state.read().unwrap().clone()); + std::thread::spawn({ + let state = state.clone(); + move || { + state.write().unwrap().start(); + loop { + std::thread::sleep(Duration::from_millis(1000 / 60)); + state.write().unwrap().run(Instant::now()); + let _ = gtk_tx.send(state.read().unwrap().clone()); + } } }); }); -- 2.44.1 From 11391aad68ecd136512e8b9f3ddbffc2e52e5dac Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 13 Apr 2023 18:56:42 -0400 Subject: [PATCH 10/11] Parse the countdown parameter --- cyberpunk-splash/src/main.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index 3cc9883..3d84c9d 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -577,15 +577,44 @@ fn main() { let state = Arc::new(RwLock::new(State::new(Duration::from_secs(5 * 60)))); let title = Arc::new(RwLock::new("".to_owned())); - app.connect_command_line(|_, args| { + app.connect_command_line(|_, _args| { println!("connect_command_line"); 1 }); app.connect_handle_local_options({ let title = title.clone(); + let state = state.clone(); move |_, options| { println!("connect_handle_local_options"); *title.write().unwrap() = options.lookup::("title").unwrap().unwrap(); + let countdown = match options.lookup::("countdown") { + Ok(Some(countdown_str)) => { + let parts = countdown_str.split(':').collect::>(); + let duration = match parts.len() { + 2 => { + let minutes = parts[0].parse::().unwrap(); + let seconds = parts[1].parse::().unwrap(); + Duration::from_secs(minutes * 60 + seconds) + } + 1 => { + let seconds = parts[1].parse::().unwrap(); + Duration::from_secs(seconds) + } + _ => Duration::from_secs(300), + }; + duration + } + _ => Duration::from_secs(300), + }; + match *state.write().unwrap() { + State::Running { + ref mut deadline, .. + } => *deadline = Instant::now() + countdown, + State::Paused { + ref mut time_remaining, + .. + } => *time_remaining = countdown, + } -1 } }); -- 2.44.1 From b92df7b443bd5c81ad04bdf838afaa4015319fae Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 13 Apr 2023 19:13:02 -0400 Subject: [PATCH 11/11] Add the nix flake for the cyberpunk splash screen --- cyberpunk-splash/Cargo.nix | 2836 ++++++++++++++++++++++++++++++++++++ flake.nix | 5 + 2 files changed, 2841 insertions(+) create mode 100644 cyberpunk-splash/Cargo.nix diff --git a/cyberpunk-splash/Cargo.nix b/cyberpunk-splash/Cargo.nix new file mode 100644 index 0000000..4e8e832 --- /dev/null +++ b/cyberpunk-splash/Cargo.nix @@ -0,0 +1,2836 @@ + +# This file was @generated by crate2nix 0.10.0 with the command: +# "generate" +# See https://github.com/kolloch/crate2nix for more info. + +{ nixpkgs ? +, pkgs ? import nixpkgs { config = {}; } +, lib ? pkgs.lib +, stdenv ? pkgs.stdenv +, buildRustCrateForPkgs ? if buildRustCrate != null + then lib.warn "crate2nix: Passing `buildRustCrate` as argument to Cargo.nix is deprecated. If you don't customize `buildRustCrate`, replace `callPackage ./Cargo.nix {}` by `import ./Cargo.nix { inherit pkgs; }`, and if you need to customize `buildRustCrate`, use `buildRustCrateForPkgs` instead." (_: buildRustCrate) + else pkgs: pkgs.buildRustCrate + # Deprecated +, buildRustCrate ? null + # This is used as the `crateOverrides` argument for `buildRustCrate`. +, defaultCrateOverrides ? pkgs.defaultCrateOverrides + # The features to enable for the root_crate or the workspace_members. +, rootFeatures ? [ "default" ] + # If true, throw errors instead of issueing deprecation warnings. +, strictDeprecation ? false + # Used for conditional compilation based on CPU feature detection. +, targetFeatures ? [] + # Whether to perform release builds: longer compile times, faster binaries. +, release ? true + # Additional crate2nix configuration if it exists. +, crateConfig + ? if builtins.pathExists ./crate-config.nix + then pkgs.callPackage ./crate-config.nix {} + else {} +}: + +rec { + # + # "public" attributes that we attempt to keep stable with new versions of crate2nix. + # + + rootCrate = rec { + packageId = "cyberpunk-splash"; + + # Use this attribute to refer to the derivation building your root crate package. + # You can override the features with rootCrate.build.override { features = [ "default" "feature1" ... ]; }. + build = internal.buildRustCrateWithFeatures { + inherit packageId; + }; + + # Debug support which might change between releases. + # File a bug if you depend on any for non-debug work! + debug = internal.debugCrate { inherit packageId; }; + }; + # Refer your crate build derivation by name here. + # You can override the features with + # workspaceMembers."${crateName}".build.override { features = [ "default" "feature1" ... ]; }. + workspaceMembers = { + "cyberpunk-splash" = rec { + packageId = "cyberpunk-splash"; + build = internal.buildRustCrateWithFeatures { + packageId = "cyberpunk-splash"; + }; + + # Debug support which might change between releases. + # File a bug if you depend on any for non-debug work! + debug = internal.debugCrate { inherit packageId; }; + }; + }; + + # A derivation that joins the outputs of all workspace members together. + allWorkspaceMembers = pkgs.symlinkJoin { + name = "all-workspace-members"; + paths = + let members = builtins.attrValues workspaceMembers; + in builtins.map (m: m.build) members; + }; + + # + # "internal" ("private") attributes that may change in every new version of crate2nix. + # + + internal = rec { + # Build and dependency information for crates. + # Many of the fields are passed one-to-one to buildRustCrate. + # + # Noteworthy: + # * `dependencies`/`buildDependencies`: similar to the corresponding fields for buildRustCrate. + # but with additional information which is used during dependency/feature resolution. + # * `resolvedDependencies`: the selected default features reported by cargo - only included for debugging. + # * `devDependencies` as of now not used by `buildRustCrate` but used to + # inject test dependencies into the build + + crates = { + "anyhow" = rec { + crateName = "anyhow"; + version = "1.0.70"; + edition = "2018"; + sha256 = "1r1py8nk0xj6h21jgww8f0zazdvjimbnl1hiacj8i3cz1xgcxs3x"; + authors = [ + "David Tolnay " + ]; + features = { + "backtrace" = [ "dep:backtrace" ]; + "default" = [ "std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "autocfg" = rec { + crateName = "autocfg"; + version = "1.1.0"; + edition = "2015"; + sha256 = "1ylp3cb47ylzabimazvbz9ms6ap784zhb6syaz6c1jqpmcmq0s6l"; + authors = [ + "Josh Stone " + ]; + + }; + "bitflags" = rec { + crateName = "bitflags"; + version = "1.3.2"; + edition = "2018"; + sha256 = "12ki6w8gn1ldq7yz9y680llwk5gmrhrzszaa17g1sbrw2r2qvwxy"; + authors = [ + "The Rust Project Developers" + ]; + features = { + "compiler_builtins" = [ "dep:compiler_builtins" ]; + "core" = [ "dep:core" ]; + "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; + }; + resolvedDefaultFeatures = [ "default" ]; + }; + "cairo-rs" = rec { + crateName = "cairo-rs"; + version = "0.17.0"; + edition = "2021"; + sha256 = "0wg8n0yz8p71db4iznp7949xzx92vmzgbhdd51lj5wcasksm9bx8"; + libName = "cairo"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "cairo-sys-rs"; + packageId = "cairo-sys-rs"; + rename = "ffi"; + } + { + name = "glib"; + packageId = "glib"; + optional = true; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "once_cell"; + packageId = "once_cell"; + } + { + name = "thiserror"; + packageId = "thiserror"; + } + ]; + features = { + "default" = [ "use_glib" ]; + "dox" = [ "ffi/dox" "glib/dox" "freetype" ]; + "freetype" = [ "ffi/freetype" "freetype-rs" ]; + "freetype-rs" = [ "dep:freetype-rs" ]; + "glib" = [ "dep:glib" ]; + "pdf" = [ "ffi/pdf" ]; + "png" = [ "ffi/png" ]; + "ps" = [ "ffi/ps" ]; + "script" = [ "ffi/script" ]; + "svg" = [ "ffi/svg" ]; + "use_glib" = [ "glib" "ffi/use_glib" ]; + "v1_16" = [ "ffi/v1_16" ]; + "v1_18" = [ "v1_16" "ffi/v1_18" ]; + "win32-surface" = [ "ffi/win32-surface" ]; + "xcb" = [ "ffi/xcb" ]; + "xlib" = [ "ffi/xlib" ]; + }; + resolvedDefaultFeatures = [ "default" "glib" "use_glib" ]; + }; + "cairo-sys-rs" = rec { + crateName = "cairo-sys-rs"; + version = "0.17.0"; + edition = "2021"; + sha256 = "0kjrcfsgp397a4kqfnsr4ssimqpm4j8jdvjy30zybr9h3nh84lzm"; + libName = "cairo_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + optional = true; + } + { + name = "libc"; + packageId = "libc"; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "x11/dox" "glib/dox" ]; + "glib" = [ "dep:glib" ]; + "use_glib" = [ "glib" ]; + "v1_18" = [ "v1_16" ]; + "win32-surface" = [ "winapi" ]; + "winapi" = [ "dep:winapi" ]; + "x11" = [ "dep:x11" ]; + "xlib" = [ "x11" ]; + }; + resolvedDefaultFeatures = [ "glib" "use_glib" ]; + }; + "cfg-expr" = rec { + crateName = "cfg-expr"; + version = "0.14.0"; + edition = "2021"; + sha256 = "1im4f8zrd0gaflv4sxjr2vdn2z4600lyhz32bjc342llc5a2anx3"; + authors = [ + "Embark " + "Jake Shadle " + ]; + dependencies = [ + { + name = "smallvec"; + packageId = "smallvec"; + } + ]; + features = { + "target-lexicon" = [ "dep:target-lexicon" ]; + "targets" = [ "target-lexicon" ]; + }; + resolvedDefaultFeatures = [ "default" ]; + }; + "cyberpunk-splash" = rec { + crateName = "cyberpunk-splash"; + version = "0.1.0"; + edition = "2021"; + crateBin = [ + { name = "cyberpunk-splash"; path = "src/main.rs"; } + ]; + src = lib.cleanSourceWith { filter = sourceFilter; src = ./.; }; + dependencies = [ + { + name = "cairo-rs"; + packageId = "cairo-rs"; + } + { + name = "gio"; + packageId = "gio"; + } + { + name = "glib"; + packageId = "glib"; + } + { + name = "gtk4"; + packageId = "gtk4"; + rename = "gtk"; + } + ]; + + }; + "field-offset" = rec { + crateName = "field-offset"; + version = "0.3.5"; + edition = "2015"; + sha256 = "0dc58qzbfis0i031d741aavvi7crzlb4nvfacg461s7n1y03mkx3"; + authors = [ + "Diggory Blake " + ]; + dependencies = [ + { + name = "memoffset"; + packageId = "memoffset"; + } + ]; + buildDependencies = [ + { + name = "rustc_version"; + packageId = "rustc_version"; + } + ]; + + }; + "futures-channel" = rec { + crateName = "futures-channel"; + version = "0.3.28"; + edition = "2018"; + sha256 = "1wmm9wm5zjigxz61qkscmxp7c30zp08dy63spjz5pch9gva1hmcm"; + dependencies = [ + { + name = "futures-core"; + packageId = "futures-core"; + usesDefaultFeatures = false; + } + ]; + features = { + "alloc" = [ "futures-core/alloc" ]; + "default" = [ "std" ]; + "futures-sink" = [ "dep:futures-sink" ]; + "sink" = [ "futures-sink" ]; + "std" = [ "alloc" "futures-core/std" ]; + }; + resolvedDefaultFeatures = [ "alloc" "default" "std" ]; + }; + "futures-core" = rec { + crateName = "futures-core"; + version = "0.3.28"; + edition = "2018"; + sha256 = "137fdxy5amg9zkpa1kqnj7bnha6b94fmddz59w973x96gqxmijjb"; + features = { + "default" = [ "std" ]; + "portable-atomic" = [ "dep:portable-atomic" ]; + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" "std" ]; + }; + "futures-executor" = rec { + crateName = "futures-executor"; + version = "0.3.28"; + edition = "2018"; + sha256 = "1q468di96knnla72xdvswic1ir2qkrf5czsdigc5n4l86a1fxv6c"; + dependencies = [ + { + name = "futures-core"; + packageId = "futures-core"; + usesDefaultFeatures = false; + } + { + name = "futures-task"; + packageId = "futures-task"; + usesDefaultFeatures = false; + } + { + name = "futures-util"; + packageId = "futures-util"; + usesDefaultFeatures = false; + } + ]; + features = { + "default" = [ "std" ]; + "num_cpus" = [ "dep:num_cpus" ]; + "std" = [ "futures-core/std" "futures-task/std" "futures-util/std" ]; + "thread-pool" = [ "std" "num_cpus" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "futures-io" = rec { + crateName = "futures-io"; + version = "0.3.28"; + edition = "2018"; + sha256 = "0r4rhkdhq1my4fahlhz59barqa511bylq813w3w4gvbidq4p9zsg"; + features = { + "default" = [ "std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "futures-macro" = rec { + crateName = "futures-macro"; + version = "0.3.28"; + edition = "2018"; + sha256 = "0wpfsqxwqk5k569xl0jzz4zxy85x695mndf7y9jn66q6jid59jl9"; + procMacro = true; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 2.0.13"; + features = [ "full" ]; + } + ]; + + }; + "futures-task" = rec { + crateName = "futures-task"; + version = "0.3.28"; + edition = "2018"; + sha256 = "0ravgihyarbplj32zp60asirfnaalw2wfsa0afhnl3kcpqrd3lvn"; + features = { + "default" = [ "std" ]; + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" "std" ]; + }; + "futures-util" = rec { + crateName = "futures-util"; + version = "0.3.28"; + edition = "2018"; + sha256 = "0cwmls9369w6q6hwlbm10q0plr6hmg8w28fpqvv4rmbjnx01xc16"; + dependencies = [ + { + name = "futures-core"; + packageId = "futures-core"; + usesDefaultFeatures = false; + } + { + name = "futures-macro"; + packageId = "futures-macro"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "futures-task"; + packageId = "futures-task"; + usesDefaultFeatures = false; + } + { + name = "pin-project-lite"; + packageId = "pin-project-lite"; + } + { + name = "pin-utils"; + packageId = "pin-utils"; + } + { + name = "slab"; + packageId = "slab"; + optional = true; + } + ]; + features = { + "alloc" = [ "futures-core/alloc" "futures-task/alloc" ]; + "async-await-macro" = [ "async-await" "futures-macro" ]; + "channel" = [ "std" "futures-channel" ]; + "compat" = [ "std" "futures_01" ]; + "default" = [ "std" "async-await" "async-await-macro" ]; + "futures-channel" = [ "dep:futures-channel" ]; + "futures-io" = [ "dep:futures-io" ]; + "futures-macro" = [ "dep:futures-macro" ]; + "futures-sink" = [ "dep:futures-sink" ]; + "futures_01" = [ "dep:futures_01" ]; + "io" = [ "std" "futures-io" "memchr" ]; + "io-compat" = [ "io" "compat" "tokio-io" ]; + "memchr" = [ "dep:memchr" ]; + "portable-atomic" = [ "futures-core/portable-atomic" ]; + "sink" = [ "futures-sink" ]; + "slab" = [ "dep:slab" ]; + "std" = [ "alloc" "futures-core/std" "futures-task/std" "slab" ]; + "tokio-io" = [ "dep:tokio-io" ]; + "unstable" = [ "futures-core/unstable" "futures-task/unstable" ]; + "write-all-vectored" = [ "io" ]; + }; + resolvedDefaultFeatures = [ "alloc" "async-await" "async-await-macro" "default" "futures-macro" "slab" "std" ]; + }; + "gdk-pixbuf" = rec { + crateName = "gdk-pixbuf"; + version = "0.17.0"; + edition = "2021"; + sha256 = "1gsrgxnz3mgi20r6axm6qnfq58qdh3chgl85k0yvs1xlqvhgn8xh"; + libName = "gdk_pixbuf"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "gdk-pixbuf-sys"; + packageId = "gdk-pixbuf-sys"; + rename = "ffi"; + } + { + name = "gio"; + packageId = "gio"; + } + { + name = "glib"; + packageId = "glib"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "once_cell"; + packageId = "once_cell"; + } + ]; + features = { + "dox" = [ "glib/dox" "gio/dox" "ffi/dox" ]; + "v2_40" = [ "ffi/v2_40" ]; + "v2_42" = [ "v2_40" "ffi/v2_42" ]; + }; + }; + "gdk-pixbuf-sys" = rec { + crateName = "gdk-pixbuf-sys"; + version = "0.17.0"; + edition = "2021"; + sha256 = "0fqy77sb5zrqjf0cjgllxpaqn0v3l595d4nkfy9djjgd8hmvshbv"; + libName = "gdk_pixbuf_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "gio-sys"; + packageId = "gio-sys"; + rename = "gio"; + } + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "gobject-sys"; + packageId = "gobject-sys"; + rename = "gobject"; + } + { + name = "libc"; + packageId = "libc"; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" "gobject/dox" "gio/dox" ]; + "v2_42" = [ "v2_40" ]; + }; + }; + "gdk4" = rec { + crateName = "gdk4"; + version = "0.6.3"; + edition = "2021"; + sha256 = "1zri4z8nxsp88mvk8vhk6xqpc4g1l69zi9w1z3fkwvm211jgkay3"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "cairo-rs"; + packageId = "cairo-rs"; + } + { + name = "gdk-pixbuf"; + packageId = "gdk-pixbuf"; + } + { + name = "gdk4-sys"; + packageId = "gdk4-sys"; + rename = "ffi"; + } + { + name = "gio"; + packageId = "gio"; + features = [ "v2_66" ]; + } + { + name = "glib"; + packageId = "glib"; + features = [ "v2_66" ]; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "pango"; + packageId = "pango"; + features = [ "v1_46" ]; + } + ]; + features = { + "dox" = [ "ffi/dox" "glib/dox" "gio/dox" "gdk-pixbuf/dox" "cairo-rs/dox" "pango/dox" ]; + "v4_10" = [ "ffi/v4_10" "v4_8" ]; + "v4_2" = [ "ffi/v4_2" ]; + "v4_4" = [ "ffi/v4_4" "v4_2" ]; + "v4_6" = [ "ffi/v4_6" "v4_4" ]; + "v4_8" = [ "ffi/v4_8" "v4_6" ]; + }; + }; + "gdk4-sys" = rec { + crateName = "gdk4-sys"; + version = "0.6.3"; + edition = "2021"; + sha256 = "0r7dm9vyzg2xlzdgxqa190gd1403mhw4q09x754rq24cc2hjmj8v"; + libName = "gdk4_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "cairo-sys-rs"; + packageId = "cairo-sys-rs"; + rename = "cairo"; + } + { + name = "gdk-pixbuf-sys"; + packageId = "gdk-pixbuf-sys"; + rename = "gdk_pixbuf"; + } + { + name = "gio-sys"; + packageId = "gio-sys"; + rename = "gio"; + } + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "gobject-sys"; + packageId = "gobject-sys"; + rename = "gobject"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "pango-sys"; + packageId = "pango-sys"; + rename = "pango"; + } + ]; + buildDependencies = [ + { + name = "pkg-config"; + packageId = "pkg-config"; + } + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" "gobject/dox" "gio/dox" "gdk_pixbuf/dox" "pango/dox" "cairo/dox" ]; + "v4_10" = [ "v4_8" ]; + "v4_4" = [ "v4_2" ]; + "v4_6" = [ "v4_4" ]; + "v4_8" = [ "v4_6" ]; + }; + }; + "gio" = rec { + crateName = "gio"; + version = "0.17.4"; + edition = "2021"; + sha256 = "09918ip09dabwllr2xcsnkfgb36331i4db173inngv12x6sa6q92"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "futures-channel"; + packageId = "futures-channel"; + } + { + name = "futures-core"; + packageId = "futures-core"; + usesDefaultFeatures = false; + } + { + name = "futures-io"; + packageId = "futures-io"; + } + { + name = "futures-util"; + packageId = "futures-util"; + usesDefaultFeatures = false; + } + { + name = "gio-sys"; + packageId = "gio-sys"; + rename = "ffi"; + } + { + name = "glib"; + packageId = "glib"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "once_cell"; + packageId = "once_cell"; + } + { + name = "pin-project-lite"; + packageId = "pin-project-lite"; + } + { + name = "smallvec"; + packageId = "smallvec"; + } + { + name = "thiserror"; + packageId = "thiserror"; + } + ]; + devDependencies = [ + { + name = "futures-util"; + packageId = "futures-util"; + features = [ "io" ]; + } + ]; + features = { + "dox" = [ "ffi/dox" "glib/dox" ]; + "v2_58" = [ "ffi/v2_58" "glib/v2_58" ]; + "v2_60" = [ "v2_58" "ffi/v2_60" "glib/v2_60" ]; + "v2_62" = [ "v2_60" "ffi/v2_62" "glib/v2_62" ]; + "v2_64" = [ "v2_62" "ffi/v2_64" "glib/v2_64" ]; + "v2_66" = [ "v2_64" "ffi/v2_66" "glib/v2_66" ]; + "v2_68" = [ "v2_66" "ffi/v2_68" "glib/v2_68" ]; + "v2_70" = [ "v2_68" "ffi/v2_70" "glib/v2_70" ]; + "v2_72" = [ "v2_70" "ffi/v2_72" "glib/v2_72" ]; + "v2_74" = [ "v2_72" "ffi/v2_74" "glib/v2_74" ]; + "v2_76" = [ "v2_74" "ffi/v2_76" "glib/v2_76" ]; + }; + resolvedDefaultFeatures = [ "v2_58" "v2_60" "v2_62" "v2_64" "v2_66" ]; + }; + "gio-sys" = rec { + crateName = "gio-sys"; + version = "0.17.4"; + edition = "2021"; + sha256 = "19b2wdwdn6gbjnqac2klymbi51wj27jazv24a92li2wnsyq467bb"; + libName = "gio_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "gobject-sys"; + packageId = "gobject-sys"; + rename = "gobject"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "winapi"; + packageId = "winapi"; + target = { target, features }: (target."windows" or false); + features = [ "ws2def" "winsock2" ]; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" "gobject/dox" ]; + "v2_60" = [ "v2_58" ]; + "v2_62" = [ "v2_60" ]; + "v2_64" = [ "v2_62" ]; + "v2_66" = [ "v2_64" ]; + "v2_68" = [ "v2_66" ]; + "v2_70" = [ "v2_68" ]; + "v2_72" = [ "v2_70" ]; + "v2_74" = [ "v2_72" ]; + "v2_76" = [ "v2_74" ]; + }; + resolvedDefaultFeatures = [ "v2_58" "v2_60" "v2_62" "v2_64" "v2_66" ]; + }; + "glib" = rec { + crateName = "glib"; + version = "0.17.5"; + edition = "2021"; + sha256 = "0ws7hmiaywwvdjp9njjjfs92a0cy68p2sb19d5lxg5b1fmhk1dfg"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "futures-channel"; + packageId = "futures-channel"; + } + { + name = "futures-core"; + packageId = "futures-core"; + usesDefaultFeatures = false; + } + { + name = "futures-executor"; + packageId = "futures-executor"; + } + { + name = "futures-task"; + packageId = "futures-task"; + usesDefaultFeatures = false; + } + { + name = "futures-util"; + packageId = "futures-util"; + } + { + name = "gio-sys"; + packageId = "gio-sys"; + rename = "gio_ffi"; + optional = true; + } + { + name = "glib-macros"; + packageId = "glib-macros"; + } + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "ffi"; + } + { + name = "gobject-sys"; + packageId = "gobject-sys"; + rename = "gobject_ffi"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "memchr"; + packageId = "memchr"; + } + { + name = "once_cell"; + packageId = "once_cell"; + } + { + name = "smallvec"; + packageId = "smallvec"; + } + { + name = "thiserror"; + packageId = "thiserror"; + } + ]; + features = { + "default" = [ "gio" ]; + "dox" = [ "ffi/dox" "gobject_ffi/dox" "log_macros" ]; + "gio" = [ "gio_ffi" ]; + "gio_ffi" = [ "dep:gio_ffi" ]; + "log" = [ "rs-log" ]; + "log_macros" = [ "log" ]; + "rs-log" = [ "dep:rs-log" ]; + "v2_58" = [ "ffi/v2_58" "gobject_ffi/v2_58" ]; + "v2_60" = [ "v2_58" "ffi/v2_60" ]; + "v2_62" = [ "v2_60" "ffi/v2_62" "gobject_ffi/v2_62" ]; + "v2_64" = [ "v2_62" "ffi/v2_64" ]; + "v2_66" = [ "v2_64" "ffi/v2_66" "gobject_ffi/v2_66" ]; + "v2_68" = [ "v2_66" "ffi/v2_68" "gobject_ffi/v2_68" ]; + "v2_70" = [ "v2_68" "ffi/v2_70" "gobject_ffi/v2_70" ]; + "v2_72" = [ "v2_70" "ffi/v2_72" "gobject_ffi/v2_72" ]; + "v2_74" = [ "v2_72" "ffi/v2_74" "gobject_ffi/v2_74" ]; + "v2_76" = [ "v2_74" "ffi/v2_76" "gobject_ffi/v2_76" ]; + }; + resolvedDefaultFeatures = [ "default" "gio" "gio_ffi" "v2_58" "v2_60" "v2_62" "v2_64" "v2_66" ]; + }; + "glib-macros" = rec { + crateName = "glib-macros"; + version = "0.17.7"; + edition = "2021"; + sha256 = "1vyrx239ggyj8qcv1yivykaxp43ik1cam0q74sbg31i0293g6k5w"; + procMacro = true; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "anyhow"; + packageId = "anyhow"; + } + { + name = "heck"; + packageId = "heck"; + } + { + name = "proc-macro-crate"; + packageId = "proc-macro-crate"; + } + { + name = "proc-macro-error"; + packageId = "proc-macro-error"; + } + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 1.0.109"; + features = [ "full" ]; + } + ]; + + }; + "glib-sys" = rec { + crateName = "glib-sys"; + version = "0.17.4"; + edition = "2021"; + sha256 = "19c0ars1rpcyfx7k63k2pghxjh898f1mvwgzmmhqwm5zl780mw29"; + libName = "glib_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "libc"; + packageId = "libc"; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "v2_60" = [ "v2_58" ]; + "v2_62" = [ "v2_60" ]; + "v2_64" = [ "v2_62" ]; + "v2_66" = [ "v2_64" ]; + "v2_68" = [ "v2_66" ]; + "v2_70" = [ "v2_68" ]; + "v2_72" = [ "v2_70" ]; + "v2_74" = [ "v2_72" ]; + "v2_76" = [ "v2_74" ]; + }; + resolvedDefaultFeatures = [ "v2_58" "v2_60" "v2_62" "v2_64" "v2_66" ]; + }; + "gobject-sys" = rec { + crateName = "gobject-sys"; + version = "0.17.4"; + edition = "2021"; + sha256 = "1l4kcw17y6dxb6b6wkw4f2ly624kmxbghg6av2r34im60005prqm"; + libName = "gobject_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "libc"; + packageId = "libc"; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" ]; + "v2_62" = [ "v2_58" ]; + "v2_66" = [ "v2_62" ]; + "v2_68" = [ "v2_66" ]; + "v2_70" = [ "v2_68" ]; + "v2_72" = [ "v2_70" ]; + "v2_74" = [ "v2_72" ]; + "v2_76" = [ "v2_74" ]; + }; + resolvedDefaultFeatures = [ "v2_58" "v2_62" "v2_66" ]; + }; + "graphene-rs" = rec { + crateName = "graphene-rs"; + version = "0.17.1"; + edition = "2021"; + sha256 = "0mk2nkhs0cad45k0177z5h5d9w19qfv7aiwxz71dzr5hbdb13kr1"; + libName = "graphene"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "glib"; + packageId = "glib"; + } + { + name = "graphene-sys"; + packageId = "graphene-sys"; + rename = "ffi"; + } + { + name = "libc"; + packageId = "libc"; + } + ]; + features = { + "dox" = [ "ffi/dox" "glib/dox" ]; + }; + }; + "graphene-sys" = rec { + crateName = "graphene-sys"; + version = "0.17.0"; + edition = "2021"; + sha256 = "1ybsw0b51dsslln1ign799zn374fcz1nzv4g190nb5cdka2a906g"; + libName = "graphene_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "libc"; + packageId = "libc"; + } + ]; + buildDependencies = [ + { + name = "pkg-config"; + packageId = "pkg-config"; + } + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" ]; + }; + }; + "gsk4" = rec { + crateName = "gsk4"; + version = "0.6.3"; + edition = "2021"; + sha256 = "0g1srhahmhdl6rqbz98bawzf1gp6hf9m4y4rvbi1bb3wz92fy0bg"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "cairo-rs"; + packageId = "cairo-rs"; + } + { + name = "gdk4"; + packageId = "gdk4"; + rename = "gdk"; + } + { + name = "glib"; + packageId = "glib"; + features = [ "v2_66" ]; + } + { + name = "graphene-rs"; + packageId = "graphene-rs"; + rename = "graphene"; + } + { + name = "gsk4-sys"; + packageId = "gsk4-sys"; + rename = "ffi"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "pango"; + packageId = "pango"; + features = [ "v1_46" ]; + } + ]; + features = { + "dox" = [ "ffi/dox" "gdk/dox" "graphene/dox" "glib/dox" "cairo-rs/dox" "pango/dox" ]; + "v4_10" = [ "ffi/v4_10" "gdk/v4_10" "v4_6" ]; + "v4_2" = [ "ffi/v4_2" "gdk/v4_2" ]; + "v4_4" = [ "ffi/v4_4" "gdk/v4_4" "v4_2" ]; + "v4_6" = [ "ffi/v4_6" "gdk/v4_6" "v4_4" ]; + }; + }; + "gsk4-sys" = rec { + crateName = "gsk4-sys"; + version = "0.6.3"; + edition = "2021"; + sha256 = "1c013zdd0yzcfmkz1gj28dbfz2zmypi8baimjk9264yg9pxq8yn0"; + libName = "gsk4_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "cairo-sys-rs"; + packageId = "cairo-sys-rs"; + rename = "cairo"; + } + { + name = "gdk4-sys"; + packageId = "gdk4-sys"; + rename = "gdk"; + } + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "gobject-sys"; + packageId = "gobject-sys"; + rename = "gobject"; + } + { + name = "graphene-sys"; + packageId = "graphene-sys"; + rename = "graphene"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "pango-sys"; + packageId = "pango-sys"; + rename = "pango"; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" "gobject/dox" "pango/dox" "cairo/dox" "graphene/dox" "gdk/dox" ]; + "v4_10" = [ "v4_6" ]; + "v4_4" = [ "v4_2" ]; + "v4_6" = [ "v4_4" ]; + }; + }; + "gtk4" = rec { + crateName = "gtk4"; + version = "0.6.4"; + edition = "2021"; + sha256 = "1vbl68q3xcqqnxxvq83vc13dflfdpxc3kc9xa7szc1d6nljf2c0y"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "cairo-rs"; + packageId = "cairo-rs"; + } + { + name = "field-offset"; + packageId = "field-offset"; + } + { + name = "futures-channel"; + packageId = "futures-channel"; + } + { + name = "gdk-pixbuf"; + packageId = "gdk-pixbuf"; + } + { + name = "gdk4"; + packageId = "gdk4"; + rename = "gdk"; + } + { + name = "gio"; + packageId = "gio"; + features = [ "v2_66" ]; + } + { + name = "glib"; + packageId = "glib"; + features = [ "v2_66" ]; + } + { + name = "graphene-rs"; + packageId = "graphene-rs"; + rename = "graphene"; + } + { + name = "gsk4"; + packageId = "gsk4"; + rename = "gsk"; + } + { + name = "gtk4-macros"; + packageId = "gtk4-macros"; + } + { + name = "gtk4-sys"; + packageId = "gtk4-sys"; + rename = "ffi"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "once_cell"; + packageId = "once_cell"; + } + { + name = "pango"; + packageId = "pango"; + features = [ "v1_46" ]; + } + ]; + features = { + "blueprint" = [ "gtk4-macros/blueprint" ]; + "dox" = [ "gdk/dox" "gsk/dox" "ffi/dox" "cairo-rs/dox" "gdk-pixbuf/dox" "gio/dox" "glib/dox" "graphene/dox" "pango/dox" ]; + "gnome_42" = [ "v4_6" "cairo-rs/v1_16" "gdk-pixbuf/v2_42" "gio/v2_72" ]; + "gnome_43" = [ "v4_8" "cairo-rs/v1_16" "gdk-pixbuf/v2_42" "gio/v2_74" ]; + "gnome_44" = [ "v4_10" "cairo-rs/v1_16" "gdk-pixbuf/v2_42" "gio/v2_76" ]; + "v4_10" = [ "ffi/v4_10" "v4_8" "gdk/v4_10" "gsk/v4_10" ]; + "v4_2" = [ "ffi/v4_2" "gdk/v4_2" "gsk/v4_2" ]; + "v4_4" = [ "ffi/v4_4" "v4_2" "gdk/v4_4" "gsk/v4_4" ]; + "v4_6" = [ "ffi/v4_6" "v4_4" "gdk/v4_6" "gsk/v4_6" "pango/v1_50" ]; + "v4_8" = [ "ffi/v4_8" "v4_6" "gdk/v4_8" ]; + "xml_validation" = [ "gtk4-macros/xml_validation" ]; + }; + }; + "gtk4-macros" = rec { + crateName = "gtk4-macros"; + version = "0.6.5"; + edition = "2021"; + sha256 = "1w1f89qn5m5rlcfkzwapmyivy11n2cw1giijwh3gp2q9zfbsfhgh"; + procMacro = true; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "anyhow"; + packageId = "anyhow"; + } + { + name = "proc-macro-crate"; + packageId = "proc-macro-crate"; + } + { + name = "proc-macro-error"; + packageId = "proc-macro-error"; + } + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 1.0.109"; + features = [ "full" ]; + } + ]; + features = { + "quick-xml" = [ "dep:quick-xml" ]; + "xml_validation" = [ "quick-xml" ]; + }; + resolvedDefaultFeatures = [ "default" ]; + }; + "gtk4-sys" = rec { + crateName = "gtk4-sys"; + version = "0.6.3"; + edition = "2021"; + sha256 = "0bz26ix7pl4d1m63zacaw1vw5021vm5r7wn7fsg02zmh0zvq70jz"; + libName = "gtk4_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "cairo-sys-rs"; + packageId = "cairo-sys-rs"; + rename = "cairo"; + } + { + name = "gdk-pixbuf-sys"; + packageId = "gdk-pixbuf-sys"; + rename = "gdk_pixbuf"; + } + { + name = "gdk4-sys"; + packageId = "gdk4-sys"; + rename = "gdk"; + } + { + name = "gio-sys"; + packageId = "gio-sys"; + rename = "gio"; + } + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "gobject-sys"; + packageId = "gobject-sys"; + rename = "gobject"; + } + { + name = "graphene-sys"; + packageId = "graphene-sys"; + rename = "graphene"; + } + { + name = "gsk4-sys"; + packageId = "gsk4-sys"; + rename = "gsk"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "pango-sys"; + packageId = "pango-sys"; + rename = "pango"; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" "gobject/dox" "gio/dox" "gdk_pixbuf/dox" "pango/dox" "cairo/dox" "graphene/dox" "gdk/dox" "gsk/dox" ]; + "v4_10" = [ "v4_8" ]; + "v4_12" = [ "v4_10" ]; + "v4_4" = [ "v4_2" ]; + "v4_6" = [ "v4_4" ]; + "v4_8" = [ "v4_6" ]; + }; + }; + "hashbrown" = rec { + crateName = "hashbrown"; + version = "0.12.3"; + edition = "2021"; + sha256 = "1268ka4750pyg2pbgsr43f0289l5zah4arir2k4igx5a8c6fg7la"; + authors = [ + "Amanieu d'Antras " + ]; + features = { + "ahash" = [ "dep:ahash" ]; + "ahash-compile-time-rng" = [ "ahash/compile-time-rng" ]; + "alloc" = [ "dep:alloc" ]; + "bumpalo" = [ "dep:bumpalo" ]; + "compiler_builtins" = [ "dep:compiler_builtins" ]; + "core" = [ "dep:core" ]; + "default" = [ "ahash" "inline-more" ]; + "rayon" = [ "dep:rayon" ]; + "rustc-dep-of-std" = [ "nightly" "core" "compiler_builtins" "alloc" "rustc-internal-api" ]; + "serde" = [ "dep:serde" ]; + }; + resolvedDefaultFeatures = [ "raw" ]; + }; + "heck" = rec { + crateName = "heck"; + version = "0.4.1"; + edition = "2018"; + sha256 = "1a7mqsnycv5z4z5vnv1k34548jzmc0ajic7c1j8jsaspnhw5ql4m"; + authors = [ + "Without Boats " + ]; + features = { + "unicode" = [ "unicode-segmentation" ]; + "unicode-segmentation" = [ "dep:unicode-segmentation" ]; + }; + resolvedDefaultFeatures = [ "default" ]; + }; + "indexmap" = rec { + crateName = "indexmap"; + version = "1.9.3"; + edition = "2021"; + sha256 = "16dxmy7yvk51wvnih3a3im6fp5lmx0wx76i03n06wyak6cwhw1xx"; + dependencies = [ + { + name = "hashbrown"; + packageId = "hashbrown"; + usesDefaultFeatures = false; + features = [ "raw" ]; + } + ]; + buildDependencies = [ + { + name = "autocfg"; + packageId = "autocfg"; + } + ]; + features = { + "arbitrary" = [ "dep:arbitrary" ]; + "quickcheck" = [ "dep:quickcheck" ]; + "rayon" = [ "dep:rayon" ]; + "rustc-rayon" = [ "dep:rustc-rayon" ]; + "serde" = [ "dep:serde" ]; + "serde-1" = [ "serde" ]; + }; + resolvedDefaultFeatures = [ "std" ]; + }; + "libc" = rec { + crateName = "libc"; + version = "0.2.141"; + edition = "2015"; + sha256 = "1dgl8sxpj94v2hwrcr5k2lcp8wk9s8a7l6vlk6z69fcv356sc11k"; + authors = [ + "The Rust Project Developers" + ]; + features = { + "default" = [ "std" ]; + "rustc-dep-of-std" = [ "align" "rustc-std-workspace-core" ]; + "rustc-std-workspace-core" = [ "dep:rustc-std-workspace-core" ]; + "use_std" = [ "std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "memchr" = rec { + crateName = "memchr"; + version = "2.5.0"; + edition = "2018"; + sha256 = "0vanfk5mzs1g1syqnj03q8n0syggnhn55dq535h2wxr7rwpfbzrd"; + authors = [ + "Andrew Gallant " + "bluss" + ]; + features = { + "compiler_builtins" = [ "dep:compiler_builtins" ]; + "core" = [ "dep:core" ]; + "default" = [ "std" ]; + "libc" = [ "dep:libc" ]; + "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; + "use_std" = [ "std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "memoffset" = rec { + crateName = "memoffset"; + version = "0.8.0"; + edition = "2015"; + sha256 = "1qcdic88dhgw76pafgndpz04pig8il4advq978mxdxdwrydp276n"; + authors = [ + "Gilad Naaman " + ]; + buildDependencies = [ + { + name = "autocfg"; + packageId = "autocfg"; + } + ]; + features = { + }; + resolvedDefaultFeatures = [ "default" ]; + }; + "once_cell" = rec { + crateName = "once_cell"; + version = "1.17.1"; + edition = "2021"; + sha256 = "1lrsy9c5ikf2iwxr4iwgd3rlq9mg8alh0np1g8abnvp1k4151rdp"; + authors = [ + "Aleksey Kladov " + ]; + features = { + "alloc" = [ "race" ]; + "atomic-polyfill" = [ "critical-section" ]; + "atomic_polyfill" = [ "dep:atomic_polyfill" ]; + "critical-section" = [ "critical_section" "atomic_polyfill" ]; + "critical_section" = [ "dep:critical_section" ]; + "default" = [ "std" ]; + "parking_lot" = [ "parking_lot_core" ]; + "parking_lot_core" = [ "dep:parking_lot_core" ]; + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" "default" "race" "std" ]; + }; + "pango" = rec { + crateName = "pango"; + version = "0.17.4"; + edition = "2021"; + sha256 = "0dqdfzavw426ygqq2298fara29yygy79lddkmw4447l85aw81hjj"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "gio"; + packageId = "gio"; + } + { + name = "glib"; + packageId = "glib"; + } + { + name = "libc"; + packageId = "libc"; + } + { + name = "once_cell"; + packageId = "once_cell"; + } + { + name = "pango-sys"; + packageId = "pango-sys"; + rename = "ffi"; + } + ]; + features = { + "dox" = [ "ffi/dox" "glib/dox" "gio/dox" ]; + "v1_42" = [ "ffi/v1_42" ]; + "v1_44" = [ "v1_42" "ffi/v1_44" ]; + "v1_46" = [ "v1_44" "ffi/v1_46" ]; + "v1_48" = [ "v1_46" "ffi/v1_48" ]; + "v1_50" = [ "v1_48" "ffi/v1_50" ]; + "v1_52" = [ "v1_50" "ffi/v1_52" ]; + }; + resolvedDefaultFeatures = [ "v1_42" "v1_44" "v1_46" ]; + }; + "pango-sys" = rec { + crateName = "pango-sys"; + version = "0.17.0"; + edition = "2021"; + sha256 = "1s2xc94xwm3b6wzqh5pj6jkjml1cs070plrl8z1bapjjnpqd14s2"; + libName = "pango_sys"; + authors = [ + "The gtk-rs Project Developers" + ]; + dependencies = [ + { + name = "glib-sys"; + packageId = "glib-sys"; + rename = "glib"; + } + { + name = "gobject-sys"; + packageId = "gobject-sys"; + rename = "gobject"; + } + { + name = "libc"; + packageId = "libc"; + } + ]; + buildDependencies = [ + { + name = "system-deps"; + packageId = "system-deps"; + } + ]; + features = { + "dox" = [ "glib/dox" "gobject/dox" ]; + "v1_44" = [ "v1_42" ]; + "v1_46" = [ "v1_44" ]; + "v1_48" = [ "v1_46" ]; + "v1_50" = [ "v1_48" ]; + "v1_52" = [ "v1_50" ]; + }; + resolvedDefaultFeatures = [ "v1_42" "v1_44" "v1_46" ]; + }; + "pin-project-lite" = rec { + crateName = "pin-project-lite"; + version = "0.2.9"; + edition = "2018"; + sha256 = "05n1z851l356hpgqadw4ar64mjanaxq1qlwqsf2k05ziq8xax9z0"; + + }; + "pin-utils" = rec { + crateName = "pin-utils"; + version = "0.1.0"; + edition = "2018"; + sha256 = "117ir7vslsl2z1a7qzhws4pd01cg2d3338c47swjyvqv2n60v1wb"; + authors = [ + "Josef Brandl " + ]; + + }; + "pkg-config" = rec { + crateName = "pkg-config"; + version = "0.3.26"; + edition = "2015"; + sha256 = "0q2i61dhqvawc51zfzl3jich57w0cjgfa894hn6ings7ffgsbjba"; + authors = [ + "Alex Crichton " + ]; + + }; + "proc-macro-crate" = rec { + crateName = "proc-macro-crate"; + version = "1.3.1"; + edition = "2021"; + sha256 = "069r1k56bvgk0f58dm5swlssfcp79im230affwk6d9ck20g04k3z"; + authors = [ + "Bastian Köcher " + ]; + dependencies = [ + { + name = "once_cell"; + packageId = "once_cell"; + } + { + name = "toml_edit"; + packageId = "toml_edit"; + } + ]; + + }; + "proc-macro-error" = rec { + crateName = "proc-macro-error"; + version = "1.0.4"; + edition = "2018"; + sha256 = "1373bhxaf0pagd8zkyd03kkx6bchzf6g0dkwrwzsnal9z47lj9fs"; + authors = [ + "CreepySkeleton " + ]; + dependencies = [ + { + name = "proc-macro-error-attr"; + packageId = "proc-macro-error-attr"; + } + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 1.0.109"; + optional = true; + usesDefaultFeatures = false; + } + ]; + buildDependencies = [ + { + name = "version_check"; + packageId = "version_check"; + } + ]; + features = { + "default" = [ "syn-error" ]; + "syn" = [ "dep:syn" ]; + "syn-error" = [ "syn" ]; + }; + resolvedDefaultFeatures = [ "default" "syn" "syn-error" ]; + }; + "proc-macro-error-attr" = rec { + crateName = "proc-macro-error-attr"; + version = "1.0.4"; + edition = "2018"; + sha256 = "0sgq6m5jfmasmwwy8x4mjygx5l7kp8s4j60bv25ckv2j1qc41gm1"; + procMacro = true; + authors = [ + "CreepySkeleton " + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + ]; + buildDependencies = [ + { + name = "version_check"; + packageId = "version_check"; + } + ]; + + }; + "proc-macro2" = rec { + crateName = "proc-macro2"; + version = "1.0.56"; + edition = "2018"; + sha256 = "0ddlk2c7s9c0fhmf8cd0wikayicv9xrm9ck9vzgg9w86rnqbsqrb"; + authors = [ + "David Tolnay " + "Alex Crichton " + ]; + dependencies = [ + { + name = "unicode-ident"; + packageId = "unicode-ident"; + } + ]; + features = { + "default" = [ "proc-macro" ]; + }; + resolvedDefaultFeatures = [ "default" "proc-macro" ]; + }; + "quote" = rec { + crateName = "quote"; + version = "1.0.26"; + edition = "2018"; + sha256 = "1z521piwggwzs0rj4wjx4ma6af1g6f1h5dkp382y5akqyx5sy924"; + authors = [ + "David Tolnay " + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + usesDefaultFeatures = false; + } + ]; + features = { + "default" = [ "proc-macro" ]; + "proc-macro" = [ "proc-macro2/proc-macro" ]; + }; + resolvedDefaultFeatures = [ "default" "proc-macro" ]; + }; + "rustc_version" = rec { + crateName = "rustc_version"; + version = "0.4.0"; + edition = "2018"; + sha256 = "0rpk9rcdk405xhbmgclsh4pai0svn49x35aggl4nhbkd4a2zb85z"; + authors = [ + "Dirkjan Ochtman " + "Marvin Löbel " + ]; + dependencies = [ + { + name = "semver"; + packageId = "semver"; + } + ]; + + }; + "semver" = rec { + crateName = "semver"; + version = "1.0.17"; + edition = "2018"; + sha256 = "1vf03d99sikkradjj33q1l9h4fqgd1h7darjypic6pnh4qrkdgdy"; + authors = [ + "David Tolnay " + ]; + features = { + "default" = [ "std" ]; + "serde" = [ "dep:serde" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "serde" = rec { + crateName = "serde"; + version = "1.0.159"; + edition = "2015"; + sha256 = "0r9hd539dzp9b7h13w9akwh33pv8f3bvk449ym0yrbix7hsfh11w"; + authors = [ + "Erick Tryzelaar " + "David Tolnay " + ]; + features = { + "default" = [ "std" ]; + "derive" = [ "serde_derive" ]; + "serde_derive" = [ "dep:serde_derive" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "serde_spanned" = rec { + crateName = "serde_spanned"; + version = "0.6.1"; + edition = "2021"; + sha256 = "1x7wqhqay4bgkaq8dmvb9z01mk2z0j0g9jl5nb9ynv3aanpqrz8f"; + dependencies = [ + { + name = "serde"; + packageId = "serde"; + optional = true; + } + ]; + features = { + "serde" = [ "dep:serde" ]; + }; + resolvedDefaultFeatures = [ "serde" ]; + }; + "slab" = rec { + crateName = "slab"; + version = "0.4.8"; + edition = "2018"; + sha256 = "0bgwxig8gkqp6gz8rvrpdj6qwa10karnsxwx7wsj5ay8kcf3aa35"; + authors = [ + "Carl Lerche " + ]; + buildDependencies = [ + { + name = "autocfg"; + packageId = "autocfg"; + } + ]; + features = { + "default" = [ "std" ]; + "serde" = [ "dep:serde" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; + "smallvec" = rec { + crateName = "smallvec"; + version = "1.10.0"; + edition = "2018"; + sha256 = "1q2k15fzxgwjpcdv3f323w24rbbfyv711ayz85ila12lg7zbw1x5"; + authors = [ + "The Servo Project Developers" + ]; + features = { + "arbitrary" = [ "dep:arbitrary" ]; + "const_new" = [ "const_generics" ]; + "serde" = [ "dep:serde" ]; + }; + }; + "syn 1.0.109" = rec { + crateName = "syn"; + version = "1.0.109"; + edition = "2018"; + sha256 = "0ds2if4600bd59wsv7jjgfkayfzy3hnazs394kz6zdkmna8l3dkj"; + authors = [ + "David Tolnay " + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + usesDefaultFeatures = false; + } + { + name = "quote"; + packageId = "quote"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "unicode-ident"; + packageId = "unicode-ident"; + } + ]; + features = { + "default" = [ "derive" "parsing" "printing" "clone-impls" "proc-macro" ]; + "printing" = [ "quote" ]; + "proc-macro" = [ "proc-macro2/proc-macro" "quote/proc-macro" ]; + "quote" = [ "dep:quote" ]; + "test" = [ "syn-test-suite/all-features" ]; + }; + resolvedDefaultFeatures = [ "clone-impls" "default" "derive" "full" "parsing" "printing" "proc-macro" "quote" ]; + }; + "syn 2.0.13" = rec { + crateName = "syn"; + version = "2.0.13"; + edition = "2021"; + sha256 = "1v68ggs5q0addc3z49kqzqfac5xcdnppdl7b6vww2ni8qmbs97ac"; + authors = [ + "David Tolnay " + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + usesDefaultFeatures = false; + } + { + name = "quote"; + packageId = "quote"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "unicode-ident"; + packageId = "unicode-ident"; + } + ]; + features = { + "default" = [ "derive" "parsing" "printing" "clone-impls" "proc-macro" ]; + "printing" = [ "quote" ]; + "proc-macro" = [ "proc-macro2/proc-macro" "quote/proc-macro" ]; + "quote" = [ "dep:quote" ]; + "test" = [ "syn-test-suite/all-features" ]; + }; + resolvedDefaultFeatures = [ "clone-impls" "default" "derive" "full" "parsing" "printing" "proc-macro" "quote" ]; + }; + "system-deps" = rec { + crateName = "system-deps"; + version = "6.0.4"; + edition = "2018"; + sha256 = "0pxh43rd2vr3r3g1kczjkk740ch2s0xbhsx364wny9gng8achpsm"; + authors = [ + "Guillaume Desmottes " + "Josh Triplett " + ]; + dependencies = [ + { + name = "cfg-expr"; + packageId = "cfg-expr"; + } + { + name = "heck"; + packageId = "heck"; + } + { + name = "pkg-config"; + packageId = "pkg-config"; + } + { + name = "toml"; + packageId = "toml"; + usesDefaultFeatures = false; + features = [ "parse" ]; + } + { + name = "version-compare"; + packageId = "version-compare"; + } + ]; + + }; + "thiserror" = rec { + crateName = "thiserror"; + version = "1.0.40"; + edition = "2018"; + sha256 = "1b7bdhriasdsr99y39d50jz995xaz9sw3hsbb6z9kp6q9cqrm34p"; + authors = [ + "David Tolnay " + ]; + dependencies = [ + { + name = "thiserror-impl"; + packageId = "thiserror-impl"; + } + ]; + + }; + "thiserror-impl" = rec { + crateName = "thiserror-impl"; + version = "1.0.40"; + edition = "2018"; + sha256 = "17sn41kyimc6s983aypkk6a45pcyrkbkvrw6rp407n5hqm16ligr"; + procMacro = true; + authors = [ + "David Tolnay " + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 2.0.13"; + } + ]; + + }; + "toml" = rec { + crateName = "toml"; + version = "0.5.11"; + edition = "2018"; + sha256 = "0d2266nx8b3n22c7k24x4428z6di8n83a9n466jm7a2hipfz1xzl"; + authors = [ + "Alex Crichton " + ]; + dependencies = [ + { + name = "serde"; + packageId = "serde"; + } + ]; + features = { + "indexmap" = [ "dep:indexmap" ]; + "preserve_order" = [ "indexmap" ]; + }; + }; + "toml_datetime" = rec { + crateName = "toml_datetime"; + version = "0.6.1"; + edition = "2021"; + sha256 = "08lndxs1bval859mlas0k4f032s26c9k6pzd589m02z1vqpfvf1s"; + authors = [ + "Alex Crichton " + ]; + dependencies = [ + { + name = "serde"; + packageId = "serde"; + optional = true; + } + ]; + features = { + "serde" = [ "dep:serde" ]; + }; + resolvedDefaultFeatures = [ "serde" ]; + }; + "toml_edit" = rec { + crateName = "toml_edit"; + version = "0.19.8"; + edition = "2021"; + sha256 = "04ywrxn4c7q4ph1vir310nsgvcd3cdqp1ri7d52jb0cyc3411513"; + authors = [ + "Andronik Ordian " + "Ed Page " + ]; + dependencies = [ + { + name = "indexmap"; + packageId = "indexmap"; + features = [ "std" ]; + } + { + name = "serde"; + packageId = "serde"; + optional = true; + } + { + name = "serde_spanned"; + packageId = "serde_spanned"; + optional = true; + features = [ "serde" ]; + } + { + name = "toml_datetime"; + packageId = "toml_datetime"; + } + { + name = "winnow"; + packageId = "winnow"; + } + ]; + features = { + "perf" = [ "dep:kstring" ]; + "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ]; + }; + resolvedDefaultFeatures = [ "default" "serde" ]; + }; + "unicode-ident" = rec { + crateName = "unicode-ident"; + version = "1.0.8"; + edition = "2018"; + sha256 = "1x4v4v95fv9gn5zbpm23sa9awjvmclap1wh1lmikmw9rna3llip5"; + authors = [ + "David Tolnay " + ]; + + }; + "version-compare" = rec { + crateName = "version-compare"; + version = "0.1.1"; + edition = "2018"; + sha256 = "0acg4pmjdbmclg0m7yhijn979mdy66z3k8qrcnvn634f1gy456jp"; + authors = [ + "Tim Visee <3a4fb3964f@sinenomine.email>" + ]; + + }; + "version_check" = rec { + crateName = "version_check"; + version = "0.9.4"; + edition = "2015"; + sha256 = "0gs8grwdlgh0xq660d7wr80x14vxbizmd8dbp29p2pdncx8lp1s9"; + authors = [ + "Sergio Benitez " + ]; + + }; + "winapi" = rec { + crateName = "winapi"; + version = "0.3.9"; + edition = "2015"; + sha256 = "06gl025x418lchw1wxj64ycr7gha83m44cjr5sarhynd9xkrm0sw"; + authors = [ + "Peter Atashian " + ]; + dependencies = [ + { + name = "winapi-i686-pc-windows-gnu"; + packageId = "winapi-i686-pc-windows-gnu"; + target = { target, features }: (stdenv.hostPlatform.config == "i686-pc-windows-gnu"); + } + { + name = "winapi-x86_64-pc-windows-gnu"; + packageId = "winapi-x86_64-pc-windows-gnu"; + target = { target, features }: (stdenv.hostPlatform.config == "x86_64-pc-windows-gnu"); + } + ]; + features = { + "debug" = [ "impl-debug" ]; + }; + resolvedDefaultFeatures = [ "winsock2" "ws2def" ]; + }; + "winapi-i686-pc-windows-gnu" = rec { + crateName = "winapi-i686-pc-windows-gnu"; + version = "0.4.0"; + edition = "2015"; + sha256 = "1dmpa6mvcvzz16zg6d5vrfy4bxgg541wxrcip7cnshi06v38ffxc"; + authors = [ + "Peter Atashian " + ]; + + }; + "winapi-x86_64-pc-windows-gnu" = rec { + crateName = "winapi-x86_64-pc-windows-gnu"; + version = "0.4.0"; + edition = "2015"; + sha256 = "0gqq64czqb64kskjryj8isp62m2sgvx25yyj3kpc2myh85w24bki"; + authors = [ + "Peter Atashian " + ]; + + }; + "winnow" = rec { + crateName = "winnow"; + version = "0.4.1"; + edition = "2021"; + sha256 = "0a2b9f0n6fpn2a88jfbp1kdjj6xrhvf8arnny67qsjb6djrp12df"; + dependencies = [ + { + name = "memchr"; + packageId = "memchr"; + optional = true; + usesDefaultFeatures = false; + } + ]; + features = { + "debug" = [ "dep:anstyle" "dep:is-terminal" "dep:terminal_size" "dep:concolor" ]; + "default" = [ "std" ]; + "simd" = [ "dep:memchr" ]; + "std" = [ "alloc" "memchr?/std" ]; + "unstable-doc" = [ "alloc" "std" "simd" ]; + }; + resolvedDefaultFeatures = [ "alloc" "default" "std" ]; + }; + }; + + # +# crate2nix/default.nix (excerpt start) +# + + /* Target (platform) data for conditional dependencies. + This corresponds roughly to what buildRustCrate is setting. + */ + defaultTarget = { + unix = true; + windows = false; + fuchsia = true; + test = false; + + # This doesn't appear to be officially documented anywhere yet. + # See https://github.com/rust-lang-nursery/rust-forge/issues/101. + os = + if stdenv.hostPlatform.isDarwin + then "macos" + else stdenv.hostPlatform.parsed.kernel.name; + arch = stdenv.hostPlatform.parsed.cpu.name; + family = "unix"; + env = "gnu"; + endian = + if stdenv.hostPlatform.parsed.cpu.significantByte.name == "littleEndian" + then "little" else "big"; + pointer_width = toString stdenv.hostPlatform.parsed.cpu.bits; + vendor = stdenv.hostPlatform.parsed.vendor.name; + debug_assertions = false; + }; + + /* Filters common temp files and build files. */ + # TODO(pkolloch): Substitute with gitignore filter + sourceFilter = name: type: + let + baseName = builtins.baseNameOf (builtins.toString name); + in + ! ( + # Filter out git + baseName == ".gitignore" + || (type == "directory" && baseName == ".git") + + # Filter out build results + || ( + type == "directory" && ( + baseName == "target" + || baseName == "_site" + || baseName == ".sass-cache" + || baseName == ".jekyll-metadata" + || baseName == "build-artifacts" + ) + ) + + # Filter out nix-build result symlinks + || ( + type == "symlink" && lib.hasPrefix "result" baseName + ) + + # Filter out IDE config + || ( + type == "directory" && ( + baseName == ".idea" || baseName == ".vscode" + ) + ) || lib.hasSuffix ".iml" baseName + + # Filter out nix build files + || baseName == "Cargo.nix" + + # Filter out editor backup / swap files. + || lib.hasSuffix "~" baseName + || builtins.match "^\\.sw[a-z]$$" baseName != null + || builtins.match "^\\..*\\.sw[a-z]$$" baseName != null + || lib.hasSuffix ".tmp" baseName + || lib.hasSuffix ".bak" baseName + || baseName == "tests.nix" + ); + + /* Returns a crate which depends on successful test execution + of crate given as the second argument. + + testCrateFlags: list of flags to pass to the test exectuable + testInputs: list of packages that should be available during test execution + */ + crateWithTest = { crate, testCrate, testCrateFlags, testInputs, testPreRun, testPostRun }: + assert builtins.typeOf testCrateFlags == "list"; + assert builtins.typeOf testInputs == "list"; + assert builtins.typeOf testPreRun == "string"; + assert builtins.typeOf testPostRun == "string"; + let + # override the `crate` so that it will build and execute tests instead of + # building the actual lib and bin targets We just have to pass `--test` + # to rustc and it will do the right thing. We execute the tests and copy + # their log and the test executables to $out for later inspection. + test = + let + drv = testCrate.override + ( + _: { + buildTests = true; + } + ); + # If the user hasn't set any pre/post commands, we don't want to + # insert empty lines. This means that any existing users of crate2nix + # don't get a spurious rebuild unless they set these explicitly. + testCommand = pkgs.lib.concatStringsSep "\n" + (pkgs.lib.filter (s: s != "") [ + testPreRun + "$f $testCrateFlags 2>&1 | tee -a $out" + testPostRun + ]); + in + pkgs.runCommand "run-tests-${testCrate.name}" + { + inherit testCrateFlags; + buildInputs = testInputs; + } '' + set -ex + + export RUST_BACKTRACE=1 + + # recreate a file hierarchy as when running tests with cargo + + # the source for test data + ${pkgs.xorg.lndir}/bin/lndir ${crate.src} + + # build outputs + testRoot=target/debug + mkdir -p $testRoot + + # executables of the crate + # we copy to prevent std::env::current_exe() to resolve to a store location + for i in ${crate}/bin/*; do + cp "$i" "$testRoot" + done + chmod +w -R . + + # test harness executables are suffixed with a hash, like cargo does + # this allows to prevent name collision with the main + # executables of the crate + hash=$(basename $out) + for file in ${drv}/tests/*; do + f=$testRoot/$(basename $file)-$hash + cp $file $f + ${testCommand} + done + ''; + in + pkgs.runCommand "${crate.name}-linked" + { + inherit (crate) outputs crateName; + passthru = (crate.passthru or { }) // { + inherit test; + }; + } '' + echo tested by ${test} + ${lib.concatMapStringsSep "\n" (output: "ln -s ${crate.${output}} ${"$"}${output}") crate.outputs} + ''; + + /* A restricted overridable version of builtRustCratesWithFeatures. */ + buildRustCrateWithFeatures = + { packageId + , features ? rootFeatures + , crateOverrides ? defaultCrateOverrides + , buildRustCrateForPkgsFunc ? null + , runTests ? false + , testCrateFlags ? [ ] + , testInputs ? [ ] + # Any command to run immediatelly before a test is executed. + , testPreRun ? "" + # Any command run immediatelly after a test is executed. + , testPostRun ? "" + }: + lib.makeOverridable + ( + { features + , crateOverrides + , runTests + , testCrateFlags + , testInputs + , testPreRun + , testPostRun + }: + let + buildRustCrateForPkgsFuncOverriden = + if buildRustCrateForPkgsFunc != null + then buildRustCrateForPkgsFunc + else + ( + if crateOverrides == pkgs.defaultCrateOverrides + then buildRustCrateForPkgs + else + pkgs: (buildRustCrateForPkgs pkgs).override { + defaultCrateOverrides = crateOverrides; + } + ); + builtRustCrates = builtRustCratesWithFeatures { + inherit packageId features; + buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; + runTests = false; + }; + builtTestRustCrates = builtRustCratesWithFeatures { + inherit packageId features; + buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; + runTests = true; + }; + drv = builtRustCrates.crates.${packageId}; + testDrv = builtTestRustCrates.crates.${packageId}; + derivation = + if runTests then + crateWithTest + { + crate = drv; + testCrate = testDrv; + inherit testCrateFlags testInputs testPreRun testPostRun; + } + else drv; + in + derivation + ) + { inherit features crateOverrides runTests testCrateFlags testInputs testPreRun testPostRun; }; + + /* Returns an attr set with packageId mapped to the result of buildRustCrateForPkgsFunc + for the corresponding crate. + */ + builtRustCratesWithFeatures = + { packageId + , features + , crateConfigs ? crates + , buildRustCrateForPkgsFunc + , runTests + , target ? defaultTarget + } @ args: + assert (builtins.isAttrs crateConfigs); + assert (builtins.isString packageId); + assert (builtins.isList features); + assert (builtins.isAttrs target); + assert (builtins.isBool runTests); + let + rootPackageId = packageId; + mergedFeatures = mergePackageFeatures + ( + args // { + inherit rootPackageId; + target = target // { test = runTests; }; + } + ); + # Memoize built packages so that reappearing packages are only built once. + builtByPackageIdByPkgs = mkBuiltByPackageIdByPkgs pkgs; + mkBuiltByPackageIdByPkgs = pkgs: + let + self = { + crates = lib.mapAttrs (packageId: value: buildByPackageIdForPkgsImpl self pkgs packageId) crateConfigs; + build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; + }; + in + self; + buildByPackageIdForPkgsImpl = self: pkgs: packageId: + let + features = mergedFeatures."${packageId}" or [ ]; + crateConfig' = crateConfigs."${packageId}"; + crateConfig = + builtins.removeAttrs crateConfig' [ "resolvedDefaultFeatures" "devDependencies" ]; + devDependencies = + lib.optionals + (runTests && packageId == rootPackageId) + (crateConfig'.devDependencies or [ ]); + dependencies = + dependencyDerivations { + inherit features target; + buildByPackageId = depPackageId: + # proc_macro crates must be compiled for the build architecture + if crateConfigs.${depPackageId}.procMacro or false + then self.build.crates.${depPackageId} + else self.crates.${depPackageId}; + dependencies = + (crateConfig.dependencies or [ ]) + ++ devDependencies; + }; + buildDependencies = + dependencyDerivations { + inherit features target; + buildByPackageId = depPackageId: + self.build.crates.${depPackageId}; + dependencies = crateConfig.buildDependencies or [ ]; + }; + filterEnabledDependenciesForThis = dependencies: filterEnabledDependencies { + inherit dependencies features target; + }; + dependenciesWithRenames = + lib.filter (d: d ? "rename") + ( + filterEnabledDependenciesForThis + ( + (crateConfig.buildDependencies or [ ]) + ++ (crateConfig.dependencies or [ ]) + ++ devDependencies + ) + ); + # Crate renames have the form: + # + # { + # crate_name = [ + # { version = "1.2.3"; rename = "crate_name01"; } + # ]; + # # ... + # } + crateRenames = + let + grouped = + lib.groupBy + (dependency: dependency.name) + dependenciesWithRenames; + versionAndRename = dep: + let + package = crateConfigs."${dep.packageId}"; + in + { inherit (dep) rename; version = package.version; }; + in + lib.mapAttrs (name: choices: builtins.map versionAndRename choices) grouped; + in + buildRustCrateForPkgsFunc pkgs + ( + crateConfig // { + src = crateConfig.src or ( + pkgs.fetchurl rec { + name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; + # https://www.pietroalbini.org/blog/downloading-crates-io/ + # Not rate-limited, CDN URL. + url = "https://static.crates.io/crates/${crateConfig.crateName}/${crateConfig.crateName}-${crateConfig.version}.crate"; + sha256 = + assert (lib.assertMsg (crateConfig ? sha256) "Missing sha256 for ${name}"); + crateConfig.sha256; + } + ); + extraRustcOpts = lib.lists.optional (targetFeatures != [ ]) "-C target-feature=${lib.concatMapStringsSep "," (x: "+${x}") targetFeatures}"; + inherit features dependencies buildDependencies crateRenames release; + } + ); + in + builtByPackageIdByPkgs; + + /* Returns the actual derivations for the given dependencies. */ + dependencyDerivations = + { buildByPackageId + , features + , dependencies + , target + }: + assert (builtins.isList features); + assert (builtins.isList dependencies); + assert (builtins.isAttrs target); + let + enabledDependencies = filterEnabledDependencies { + inherit dependencies features target; + }; + depDerivation = dependency: buildByPackageId dependency.packageId; + in + map depDerivation enabledDependencies; + + /* Returns a sanitized version of val with all values substituted that cannot + be serialized as JSON. + */ + sanitizeForJson = val: + if builtins.isAttrs val + then lib.mapAttrs (n: v: sanitizeForJson v) val + else if builtins.isList val + then builtins.map sanitizeForJson val + else if builtins.isFunction val + then "function" + else val; + + /* Returns various tools to debug a crate. */ + debugCrate = { packageId, target ? defaultTarget }: + assert (builtins.isString packageId); + let + debug = rec { + # The built tree as passed to buildRustCrate. + buildTree = buildRustCrateWithFeatures { + buildRustCrateForPkgsFunc = _: lib.id; + inherit packageId; + }; + sanitizedBuildTree = sanitizeForJson buildTree; + dependencyTree = sanitizeForJson + ( + buildRustCrateWithFeatures { + buildRustCrateForPkgsFunc = _: crate: { + "01_crateName" = crate.crateName or false; + "02_features" = crate.features or [ ]; + "03_dependencies" = crate.dependencies or [ ]; + }; + inherit packageId; + } + ); + mergedPackageFeatures = mergePackageFeatures { + features = rootFeatures; + inherit packageId target; + }; + diffedDefaultPackageFeatures = diffDefaultPackageFeatures { + inherit packageId target; + }; + }; + in + { internal = debug; }; + + /* Returns differences between cargo default features and crate2nix default + features. + + This is useful for verifying the feature resolution in crate2nix. + */ + diffDefaultPackageFeatures = + { crateConfigs ? crates + , packageId + , target + }: + assert (builtins.isAttrs crateConfigs); + let + prefixValues = prefix: lib.mapAttrs (n: v: { "${prefix}" = v; }); + mergedFeatures = + prefixValues + "crate2nix" + (mergePackageFeatures { inherit crateConfigs packageId target; features = [ "default" ]; }); + configs = prefixValues "cargo" crateConfigs; + combined = lib.foldAttrs (a: b: a // b) { } [ mergedFeatures configs ]; + onlyInCargo = + builtins.attrNames + (lib.filterAttrs (n: v: !(v ? "crate2nix") && (v ? "cargo")) combined); + onlyInCrate2Nix = + builtins.attrNames + (lib.filterAttrs (n: v: (v ? "crate2nix") && !(v ? "cargo")) combined); + differentFeatures = lib.filterAttrs + ( + n: v: + (v ? "crate2nix") + && (v ? "cargo") + && (v.crate2nix.features or [ ]) != (v."cargo".resolved_default_features or [ ]) + ) + combined; + in + builtins.toJSON { + inherit onlyInCargo onlyInCrate2Nix differentFeatures; + }; + + /* Returns an attrset mapping packageId to the list of enabled features. + + If multiple paths to a dependency enable different features, the + corresponding feature sets are merged. Features in rust are additive. + */ + mergePackageFeatures = + { crateConfigs ? crates + , packageId + , rootPackageId ? packageId + , features ? rootFeatures + , dependencyPath ? [ crates.${packageId}.crateName ] + , featuresByPackageId ? { } + , target + # Adds devDependencies to the crate with rootPackageId. + , runTests ? false + , ... + } @ args: + assert (builtins.isAttrs crateConfigs); + assert (builtins.isString packageId); + assert (builtins.isString rootPackageId); + assert (builtins.isList features); + assert (builtins.isList dependencyPath); + assert (builtins.isAttrs featuresByPackageId); + assert (builtins.isAttrs target); + assert (builtins.isBool runTests); + let + crateConfig = crateConfigs."${packageId}" or (builtins.throw "Package not found: ${packageId}"); + expandedFeatures = expandFeatures (crateConfig.features or { }) features; + enabledFeatures = enableFeatures (crateConfig.dependencies or [ ]) expandedFeatures; + depWithResolvedFeatures = dependency: + let + packageId = dependency.packageId; + features = dependencyFeatures enabledFeatures dependency; + in + { inherit packageId features; }; + resolveDependencies = cache: path: dependencies: + assert (builtins.isAttrs cache); + assert (builtins.isList dependencies); + let + enabledDependencies = filterEnabledDependencies { + inherit dependencies target; + features = enabledFeatures; + }; + directDependencies = map depWithResolvedFeatures enabledDependencies; + foldOverCache = op: lib.foldl op cache directDependencies; + in + foldOverCache + ( + cache: { packageId, features }: + let + cacheFeatures = cache.${packageId} or [ ]; + combinedFeatures = sortedUnique (cacheFeatures ++ features); + in + if cache ? ${packageId} && cache.${packageId} == combinedFeatures + then cache + else + mergePackageFeatures { + features = combinedFeatures; + featuresByPackageId = cache; + inherit crateConfigs packageId target runTests rootPackageId; + } + ); + cacheWithSelf = + let + cacheFeatures = featuresByPackageId.${packageId} or [ ]; + combinedFeatures = sortedUnique (cacheFeatures ++ enabledFeatures); + in + featuresByPackageId // { + "${packageId}" = combinedFeatures; + }; + cacheWithDependencies = + resolveDependencies cacheWithSelf "dep" + ( + crateConfig.dependencies or [ ] + ++ lib.optionals + (runTests && packageId == rootPackageId) + (crateConfig.devDependencies or [ ]) + ); + cacheWithAll = + resolveDependencies + cacheWithDependencies "build" + (crateConfig.buildDependencies or [ ]); + in + cacheWithAll; + + /* Returns the enabled dependencies given the enabled features. */ + filterEnabledDependencies = { dependencies, features, target }: + assert (builtins.isList dependencies); + assert (builtins.isList features); + assert (builtins.isAttrs target); + + lib.filter + ( + dep: + let + targetFunc = dep.target or (features: true); + in + targetFunc { inherit features target; } + && ( + !(dep.optional or false) + || builtins.any (doesFeatureEnableDependency dep) features + ) + ) + dependencies; + + /* Returns whether the given feature should enable the given dependency. */ + doesFeatureEnableDependency = { name, rename ? null, ... }: feature: + let + prefix = "${name}/"; + len = builtins.stringLength prefix; + startsWithPrefix = builtins.substring 0 len feature == prefix; + in + (rename == null && feature == name) + || (rename != null && rename == feature) + || startsWithPrefix; + + /* Returns the expanded features for the given inputFeatures by applying the + rules in featureMap. + + featureMap is an attribute set which maps feature names to lists of further + feature names to enable in case this feature is selected. + */ + expandFeatures = featureMap: inputFeatures: + assert (builtins.isAttrs featureMap); + assert (builtins.isList inputFeatures); + let + expandFeature = feature: + assert (builtins.isString feature); + [ feature ] ++ (expandFeatures featureMap (featureMap."${feature}" or [ ])); + outFeatures = lib.concatMap expandFeature inputFeatures; + in + sortedUnique outFeatures; + + /* This function adds optional dependencies as features if they are enabled + indirectly by dependency features. This function mimics Cargo's behavior + described in a note at: + https://doc.rust-lang.org/nightly/cargo/reference/features.html#dependency-features + */ + enableFeatures = dependencies: features: + assert (builtins.isList features); + assert (builtins.isList dependencies); + let + additionalFeatures = lib.concatMap + ( + dependency: + assert (builtins.isAttrs dependency); + let + enabled = builtins.any (doesFeatureEnableDependency dependency) features; + in + if (dependency.optional or false) && enabled then [ dependency.name ] else [ ] + ) + dependencies; + in + sortedUnique (features ++ additionalFeatures); + + /* + Returns the actual features for the given dependency. + + features: The features of the crate that refers this dependency. + */ + dependencyFeatures = features: dependency: + assert (builtins.isList features); + assert (builtins.isAttrs dependency); + let + defaultOrNil = + if dependency.usesDefaultFeatures or true + then [ "default" ] + else [ ]; + explicitFeatures = dependency.features or [ ]; + additionalDependencyFeatures = + let + dependencyPrefix = (dependency.rename or dependency.name) + "/"; + dependencyFeatures = + builtins.filter (f: lib.hasPrefix dependencyPrefix f) features; + in + builtins.map (lib.removePrefix dependencyPrefix) dependencyFeatures; + in + defaultOrNil ++ explicitFeatures ++ additionalDependencyFeatures; + + /* Sorts and removes duplicates from a list of strings. */ + sortedUnique = features: + assert (builtins.isList features); + assert (builtins.all builtins.isString features); + let + outFeaturesSet = lib.foldl (set: feature: set // { "${feature}" = 1; }) { } features; + outFeaturesUnique = builtins.attrNames outFeaturesSet; + in + builtins.sort (a: b: a < b) outFeaturesUnique; + + deprecationWarning = message: value: + if strictDeprecation + then builtins.throw "strictDeprecation enabled, aborting: ${message}" + else builtins.trace message value; + + # + # crate2nix/default.nix (excerpt end) + # + }; +} + diff --git a/flake.nix b/flake.nix index 138422f..516888d 100644 --- a/flake.nix +++ b/flake.nix @@ -78,6 +78,11 @@ rootFeatures = [ "screenplay" ]; release = false; }).rootCrate.build; + cyberpunk-splash = (import ./cyberpunk-splash/Cargo.nix { + inherit pkgs; + buildRustCrateForPkgs = customBuildInfo; + release = true; + }).rootCrate.build; }; }; } -- 2.44.1