diff --git a/Cargo.lock b/Cargo.lock index 8a334b9..5260cb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,9 +77,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -131,6 +131,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.0" @@ -140,8 +146,10 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "bit_field" version = "0.10.2" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" @@ -158,8 +166,10 @@ checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytemuck" version = "1.13.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -170,6 +180,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" version = "1.4.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" @@ -214,8 +225,10 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" [[package]] name = "cc" version = "1.0.79" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -225,9 +238,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "js-sys", @@ -235,6 +248,8 @@ dependencies = [ "num-traits", "serde", "time 0.1.45", + "serde", + "time 0.1.45", "wasm-bindgen", "winapi", ] @@ -245,13 +260,22 @@ version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdc5d93c358224b4d6867ef1356d740de2303e9892edc06c5340daeccd96bab" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", ] [[package]] @@ -261,10 +285,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -352,10 +375,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "colorchoice" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "crc32fast" @@ -379,8 +408,10 @@ dependencies = [ [[package]] name = "crossbeam-deque" version = "0.8.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -390,21 +421,26 @@ dependencies = [ [[package]] name = "crossbeam-epoch" version = "0.9.14" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset 0.8.0", + "memoffset 0.8.0", "scopeguard", ] [[package]] name = "crossbeam-utils" version = "0.8.15" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -439,7 +475,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 2.0.15", ] [[package]] @@ -456,6 +492,76 @@ checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" dependencies = [ "proc-macro2", "quote", + "syn 2.0.15", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", "syn", ] @@ -502,29 +608,30 @@ checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" [[package]] name = "directories" -version = "4.0.1" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ "dirs-sys", ] [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", "winapi", ] @@ -541,8 +648,10 @@ dependencies = [ [[package]] name = "either" version = "1.8.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "enum_dispatch" @@ -553,18 +662,18 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -580,17 +689,21 @@ dependencies = [ [[package]] name = "exr" version = "1.6.3" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdd2162b720141a91a054640662d3edce3d50a944a50ffca5313cd951abb35b4" +checksum = "bdd2162b720141a91a054640662d3edce3d50a944a50ffca5313cd951abb35b4" dependencies = [ "bit_field", "flume", "half 2.2.1", + "half 2.2.1", "lebe", "miniz_oxide", "rayon-core", "smallvec", "zune-inflate", + "zune-inflate", ] [[package]] @@ -629,6 +742,9 @@ checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499" dependencies = [ "serde", ] +dependencies = [ + "serde", +] [[package]] name = "flatbuffers" @@ -642,9 +758,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", "miniz_oxide", @@ -688,13 +804,22 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "fontconfig-parser" version = "0.5.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ab2e12762761366dcb876ab8b6e0cfa4797ddcd890575919f008b5ba655672a" +checksum = "4ab2e12762761366dcb876ab8b6e0cfa4797ddcd890575919f008b5ba655672a" dependencies = [ "roxmltree", + "roxmltree", ] [[package]] @@ -719,6 +844,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "freedesktop_entry_parser" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9c27b72f19a99a895f8ca89e2d26e4ef31013376e56fdafef697627306c3e4" +dependencies = [ + "nom", + "thiserror", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -750,9 +885,41 @@ dependencies = [ ] [[package]] -name = "futures-core" +name = "futures" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] @@ -764,6 +931,7 @@ checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-sink" version = "0.3.28" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" @@ -773,6 +941,26 @@ 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-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[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" @@ -788,9 +976,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "js-sys", @@ -799,16 +987,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gif" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" -dependencies = [ - "color_quant", - "weezl", -] - [[package]] name = "gif" version = "0.12.0" @@ -822,12 +1000,14 @@ dependencies = [ [[package]] name = "gimli" version = "0.27.2" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "glam" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774" dependencies = [ @@ -852,8 +1032,10 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "half" version = "2.2.1" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" dependencies = [ "crunchy", ] @@ -861,15 +1043,23 @@ dependencies = [ [[package]] name = "hashbrown" version = "0.9.1" +name = "hashbrown" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" dependencies = [ "ahash 0.4.7", ] +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] [[package]] name = "hashbrown" version = "0.12.3" +name = "hashbrown" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" @@ -879,6 +1069,19 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "heck" version = "0.4.1" @@ -906,6 +1109,18 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -917,7 +1132,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows", ] [[package]] @@ -936,6 +1151,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "image" version = "0.24.5" @@ -946,12 +1167,12 @@ dependencies = [ "byteorder", "color_quant", "exr", - "gif 0.11.4", + "gif", "jpeg-decoder", "num-rational", "num-traits", "png", - "scoped_threadpool", + "qoi", "tiff", ] @@ -993,8 +1214,9 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" dependencies = [ + "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1003,10 +1225,11 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ + "hermit-abi 0.3.1", "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1015,6 +1238,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + [[package]] name = "jpeg-decoder" version = "0.3.0" @@ -1027,8 +1256,10 @@ dependencies = [ [[package]] name = "js-sys" version = "0.3.61" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1095,17 +1326,19 @@ dependencies = [ [[package]] name = "link-cplusplus" version = "1.0.8" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" [[package]] name = "lock_api" @@ -1128,9 +1361,9 @@ dependencies = [ [[package]] name = "manifest-dir-macros" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f08150cf2bab1fc47c2196f4f41173a27fcd0f684165e5458c0046b53a472e2f" +checksum = "450e5ef583bc05177c4975b9ea907047091a9f62e74e81fcafb99dbffac51e7e" dependencies = [ "once_cell", "proc-macro2", @@ -1165,8 +1398,10 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" version = "0.5.10" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -1180,6 +1415,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.7.1" @@ -1192,10 +1436,14 @@ dependencies = [ [[package]] name = "memoffset" version = "0.8.0" +name = "memoffset" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", + "autocfg", ] [[package]] @@ -1204,6 +1452,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.6.2" @@ -1213,6 +1467,16 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + [[package]] name = "mint" version = "0.5.9" @@ -1225,13 +1489,15 @@ dependencies = [ [[package]] name = "mio" version = "0.8.6" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1255,9 +1521,12 @@ dependencies = [ [[package]] name = "nix" version = "0.25.1" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ + "autocfg", "autocfg", "bitflags", "cfg-if", @@ -1266,6 +1535,20 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset 0.7.1", + "memoffset 0.6.5", + "pin-utils", +] + [[package]] name = "nix" version = "0.26.2" @@ -1290,6 +1573,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1333,9 +1626,12 @@ dependencies = [ [[package]] name = "num_cpus" version = "1.15.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ + "hermit-abi 0.2.6", "hermit-abi 0.2.6", "libc", ] @@ -1343,8 +1639,10 @@ dependencies = [ [[package]] name = "num_enum" version = "0.5.11" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ "num_enum_derive", ] @@ -1352,20 +1650,24 @@ dependencies = [ [[package]] name = "num_enum_derive" version = "0.5.11" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "object" version = "0.30.3" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -1373,8 +1675,10 @@ dependencies = [ [[package]] name = "once_cell" version = "1.17.1" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "ordered-multimap" @@ -1395,8 +1699,10 @@ checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "ouroboros" version = "0.15.6" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" dependencies = [ "aliasable", "ouroboros_macro", @@ -1405,14 +1711,16 @@ dependencies = [ [[package]] name = "ouroboros_macro" version = "0.15.6" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" dependencies = [ "Inflector", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1446,6 +1754,7 @@ checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core 0.9.7", + "parking_lot_core 0.9.7", ] [[package]] @@ -1465,14 +1774,16 @@ dependencies = [ [[package]] name = "parking_lot_core" version = "0.9.7" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1498,7 +1809,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1521,6 +1832,7 @@ checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" dependencies = [ "bitflags", "crc32fast", + "fdeflate", "flate2", "miniz_oxide", ] @@ -1534,11 +1846,14 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" version = "1.3.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", "toml_edit", + "toml_edit", ] [[package]] @@ -1550,7 +1865,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -1578,25 +1893,32 @@ dependencies = [ name = "protostar" version = "0.4.0" dependencies = [ + "cached", "cached", "clap", "color-eyre", "directories", "dirs", "ez-pixmap", - "glam 0.22.0", + "glam", "image", "lazy_static", "linicon", + "linicon", "manifest-dir-macros", "mint", "nix 0.26.2", "regex", + "nix 0.26.2", + "regex", "resvg", "rustc-hash", "serde", "serde_json", "serde_with", + "serde", + "serde_json", + "serde_with", "stardust-xr-fusion", "stardust-xr-molecules", "tempdir", @@ -1677,8 +1999,10 @@ dependencies = [ [[package]] name = "rayon" version = "1.7.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -1687,8 +2011,10 @@ dependencies = [ [[package]] name = "rayon-core" version = "1.11.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -1733,9 +2059,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ "aho-corasick", "memchr", @@ -1748,14 +2074,20 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "remove_dir_all" @@ -1772,7 +2104,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76888219c0881e22b0ceab06fddcfe83163cd81642bd60c7842387f9c968a72e" dependencies = [ - "gif 0.12.0", + "gif", "jpeg-decoder", "log", "pico-args", @@ -1788,8 +2120,10 @@ dependencies = [ [[package]] name = "rgb" version = "0.8.36" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" +checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" dependencies = [ "bytemuck", ] @@ -1802,6 +2136,7 @@ checksum = "bdc23d1ace03d6b8153c7d16f0708cd80b61ee8e80304954803354e67e40d150" dependencies = [ "log", "roxmltree", + "roxmltree", "simplecss", "siphasher", "svgtypes 0.9.0", @@ -1810,8 +2145,10 @@ dependencies = [ [[package]] name = "roxmltree" version = "0.18.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8f595a457b6b8c6cda66a48503e92ee8d19342f905948f29c383200ec9eb1d8" +checksum = "d8f595a457b6b8c6cda66a48503e92ee8d19342f905948f29c383200ec9eb1d8" dependencies = [ "xmlparser", ] @@ -1819,11 +2156,16 @@ dependencies = [ [[package]] name = "rust-ini" version = "0.17.0" +name = "rust-ini" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" +checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" dependencies = [ "cfg-if", "ordered-multimap", + "cfg-if", + "ordered-multimap", ] [[package]] @@ -1858,7 +2200,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1883,6 +2225,12 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + [[package]] name = "same-file" version = "1.0.6" @@ -1892,12 +2240,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scoped_threadpool" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" - [[package]] name = "scopeguard" version = "1.1.0" @@ -1907,14 +2249,16 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" version = "1.0.5" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" @@ -1998,8 +2342,10 @@ dependencies = [ [[package]] name = "signal-hook-registry" version = "1.4.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -2034,8 +2380,10 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" version = "0.4.9" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -2052,9 +2400,7 @@ dependencies = [ [[package]] name = "stardust-xr" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798fb96a582da0fe0c791cfc10005a5eff3fbe3024e73b139456e63eda1380f4" +version = "0.11.4" dependencies = [ "chrono", "cluFlock", @@ -2076,6 +2422,7 @@ version = "0.40.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10dc289847fa08d3a67bd2be88abbc04584c6cab0081cc43bf4d56fe3cf43b5a" dependencies = [ + "color-eyre", "color-eyre", "color-rs", "enum_dispatch", @@ -2095,13 +2442,16 @@ dependencies = [ [[package]] name = "stardust-xr-molecules" version = "0.24.3" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "724a92e67765300651d165950b70ec4800d4ad6450f473882f6024d5a559ea9d" +checksum = "724a92e67765300651d165950b70ec4800d4ad6450f473882f6024d5a559ea9d" dependencies = [ "color-rs", "glam 0.24.0", "lazy_static", "map-range", + "map-range", "mint", "rustc-hash", "serde", @@ -2113,16 +2463,16 @@ dependencies = [ [[package]] name = "stardust-xr-schemas" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bebfbddbcba7db7ce8180bb373c9ad5a7d58ff60ee213ca07562820d7e8aab0" +version = "1.5.0" dependencies = [ "flatbuffers", "flexbuffers", - "glam 0.22.0", + "glam", + "manifest-dir-macros", "mint", "ouroboros", "serde", + "serde_repr", "thiserror", ] @@ -2180,6 +2530,7 @@ dependencies = [ [[package]] name = "syn" version = "1.0.109" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ @@ -2201,8 +2552,10 @@ dependencies = [ [[package]] name = "termcolor" version = "1.2.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -2224,15 +2577,18 @@ checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] name = "thread_local" version = "1.1.7" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "cfg-if", "once_cell", ] @@ -2286,6 +2642,33 @@ dependencies = [ "time-core", ] +[[package]] +name = "time" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", +] + [[package]] name = "tiny-skia" version = "0.8.3" @@ -2302,9 +2685,9 @@ dependencies = [ [[package]] name = "tiny-skia-path" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b5edac058fc98f51c935daea4d805b695b38e2f151241cad125ade2a2ac20d" +checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c" dependencies = [ "arrayref", "bytemuck", @@ -2320,7 +2703,6 @@ dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot 0.12.1", @@ -2328,23 +2710,25 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] name = "toml_datetime" version = "0.6.1" +name = "toml_datetime" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" @@ -2357,6 +2741,9 @@ dependencies = [ "indexmap", "toml_datetime", "winnow", + "indexmap", + "toml_datetime", + "winnow", ] [[package]] @@ -2373,13 +2760,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -2415,9 +2802,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -2440,8 +2827,10 @@ checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" [[package]] name = "tween" version = "2.0.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90aba0c5c9d07e12084c38dcbf0f4b16f74801b588650ad633f9d7e9a0143952" +checksum = "90aba0c5c9d07e12084c38dcbf0f4b16f74801b588650ad633f9d7e9a0143952" [[package]] name = "unicode-bidi" @@ -2470,8 +2859,10 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" version = "1.0.8" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-script" @@ -2497,6 +2888,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "371436099f2980de56dc385b615696d3eabbdac9649a72b85f9d75f68474fa9c" dependencies = [ + "ahash 0.7.6", "ahash 0.7.6", "byteorder", "lazy_static", @@ -2509,6 +2901,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b6bb4e62619d9f68aa2d8a823fea2bff302340a1f2d45c264d5b0be170832e" dependencies = [ + "base64 0.21.0", "base64 0.21.0", "data-url", "flate2", @@ -2536,6 +2929,12 @@ dependencies = [ "usvg", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" @@ -2550,12 +2949,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -2574,8 +2972,10 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.84" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2584,23 +2984,27 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" version = "0.2.84" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.84" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2609,12 +3013,14 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" version = "0.2.84" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2622,8 +3028,10 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" version = "0.2.84" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "weezl" @@ -2665,8 +3073,10 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.45.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ "windows-targets", ] diff --git a/Cargo.toml b/Cargo.toml index cb9f9b2..7971dfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,12 +5,13 @@ edition = "2021" [dependencies] cached = "0.42.0" +cached = "0.43.0" clap = { version = "4.1.3", features = ["derive"] } color-eyre = "0.6.2" -directories = "4.0.1" -dirs = "4.0.0" +directories = "5.0.0" +dirs = "5.0.0" ez-pixmap = "0.2.2" -glam = { version = "0.22.0", features = ["mint"] } +glam = { version = "0.24.0", features = ["mint"] } image = "0.24.5" lazy_static = "1.4.0" linicon = "2.3.0" @@ -25,11 +26,13 @@ serde_json = "1.0.94" serde_with = "2.3.1" stardust-xr-fusion = "0.40.0" stardust-xr-molecules = "0.24.3" +serde = "1.0.155" +serde_json = "1.0.94" +serde_with = "2.3.1" +stardust-xr-fusion = "0.40.2" +stardust-xr-molecules = "0.24.3" tokio = { version = "1.24.1", features = ["full"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } tween = "2.0.0" ustr = "0.9.0" walkdir = "2.3.2" - -[dev-dependencies] -tempdir = "0.3.7" diff --git a/assets/hexagon.blend b/assets/hexagon.blend index 17e162a..20cd188 100644 Binary files a/assets/hexagon.blend and b/assets/hexagon.blend differ diff --git a/examples/hexagon_launcher.rs b/examples/hexagon_launcher.rs index 38c6ced..1e28775 100644 --- a/examples/hexagon_launcher.rs +++ b/examples/hexagon_launcher.rs @@ -231,3 +231,446 @@ impl RootHandler for Button { self.grabbable.update(&info).unwrap(); } } +use color_eyre::eyre::Result; +use glam::Quat; +use manifest_dir_macros::directory_relative_path; +use mint::Vector3; +use protostar::{ + application::Application, + xdg::{get_desktop_files, parse_desktop_file, DesktopFile, Icon, IconType}, +}; +use stardust_xr_fusion::{ + client::{Client, FrameInfo, RootHandler}, + core::values::Transform, + drawable::{Alignment, Bounds, MaterialParameter, Model, ResourceID, Text, TextFit, TextStyle}, + fields::BoxField, + node::NodeError, + node::NodeType, + spatial::Spatial, +}; +use stardust_xr_molecules::{touch_plane::TouchPlane, GrabData, Grabbable}; +use std::f32::consts::PI; +use tween::TweenTime; +use tween::{QuartInOut, Tweener}; + +const APP_SIZE: f32 = 0.06; +const PADDING: f32 = 0.005; +const ACTIVATION_DISTANCE: f32 = 0.5; + +#[derive(Clone)] +struct Hex { + q: isize, + r: isize, + s: isize, +} + +const HEX_CENTER: Hex = Hex { q: 0, r: 0, s: 0 }; +const HEX_DIRECTION_VECTORS: [Hex; 6] = [ + Hex { q: 1, r: 0, s: -1 }, + Hex { q: 1, r: -1, s: 0 }, + Hex { q: 0, r: -1, s: 1 }, + Hex { q: -1, r: 0, s: 1 }, + Hex { q: -1, r: 1, s: 0 }, + Hex { q: 0, r: 1, s: -1 }, +]; + +impl Hex { + fn new(q: isize, r: isize, s: isize) -> Self { + Hex { q, r, s } + } + + fn get_coords(&self) -> [f32; 3] { + let x = 3.0 / 2.0 * (APP_SIZE + PADDING) / 2.0 * (-self.q - self.s).to_f32(); + let y = 3.0_f32.sqrt() * (APP_SIZE + PADDING) / 2.0 + * ((-self.q - self.s).to_f32() / 2.0 + self.s.to_f32()); + [x, y, 0.0] + } + + fn add(self, vec: &Hex) -> Self { + Hex::new(self.q + vec.q, self.r + vec.r, self.s + vec.s) + } + + fn neighbor(self, direction: usize) -> Self { + self.add(&HEX_DIRECTION_VECTORS[direction]) + } + + fn scale(self, factor: isize) -> Self { + Hex::new(self.q * factor, self.r * factor, self.s * factor) + } +} + +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<()> { + color_eyre::install().unwrap(); + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .pretty() + .init(); + let (client, event_loop) = Client::connect_with_async_loop().await?; + client.set_base_prefixes(&[directory_relative_path!("res")]); + + let _root = client.wrap_root(AppHexGrid::new(&client))?; + + tokio::select! { + _ = tokio::signal::ctrl_c() => (), + e = event_loop => e??, + }; + Ok(()) +} + +struct AppHexGrid { + apps: Vec, + button: Button, +} +impl AppHexGrid { + fn new(client: &Client) -> Self { + let button = Button::new(client).unwrap(); + let mut desktop_files: Vec = get_desktop_files() + .into_iter() + .filter_map(|d| parse_desktop_file(d).ok()) + .filter(|d| !d.no_display) + .collect(); + + desktop_files.sort_by_key(|d| d.clone().name.unwrap_or_default()); + + let mut apps = Vec::new(); + let mut radius = 1; + while !desktop_files.is_empty() { + let mut hex = HEX_CENTER.add(&HEX_DIRECTION_VECTORS[4].clone().scale(radius)); + for i in 0..6 { + if desktop_files.is_empty() { + break; + }; + for _ in 0..radius { + if desktop_files.is_empty() { + break; + }; + apps.push( + App::create_from_desktop_file( + button.grabbable.content_parent(), + hex.get_coords(), + desktop_files.pop().unwrap(), + ) + .unwrap(), + ); + hex = hex.neighbor(i); + } + } + radius += 1; + } + AppHexGrid { apps, button } + } +} +impl RootHandler for AppHexGrid { + fn frame(&mut self, info: FrameInfo) { + self.button.frame(info); + if self.button.touch_plane.touch_started() { + let color = [0.0, 1.0, 0.0, 1.0]; + self.button + .model + .model_part("Hex") + .unwrap() + .set_material_parameter("color", MaterialParameter::Color(color)) + .unwrap(); + for app in &mut self.apps { + app.toggle(); + } + } else if self.button.touch_plane.touch_stopped() { + let color = [0.0, 0.0, 1.0, 1.0]; + self.button + .model + .model_part("Hex") + .unwrap() + .set_material_parameter("color", MaterialParameter::Color(color)) + .unwrap(); + } + for app in &mut self.apps { + app.frame(info); + } + } +} + +struct Button { + touch_plane: TouchPlane, + grabbable: Grabbable, + model: Model, +} +impl Button { + fn new(client: &Client) -> Result { + let field = BoxField::create(client.get_root(), Transform::default(), [APP_SIZE; 3])?; + let grabbable = Grabbable::create( + client.get_root(), + Transform::default(), + &field, + GrabData { + max_distance: 0.01, + ..Default::default() + }, + )?; + field.set_spatial_parent(grabbable.content_parent())?; + let touch_plane = TouchPlane::create( + grabbable.content_parent(), + Transform::default(), + [(APP_SIZE + PADDING) / 2.0; 2], + (APP_SIZE + PADDING) / 2.0, + 0.0..1.0, + 0.0..1.0, + )?; + + let model = Model::create( + grabbable.content_parent(), + Transform::from_rotation_scale( + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + [0.03, 0.03, 0.03], + ), + &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), + )?; + model + .model_part("Hex")? + .set_material_parameter("color", MaterialParameter::Color([0.0, 0.0, 1.0, 1.0]))?; + Ok(Button { + touch_plane, + grabbable, + model, + }) + } +} +impl RootHandler for Button { + fn frame(&mut self, info: FrameInfo) { + let _ = self.grabbable.update(&info); + if self.grabbable.grab_action().actor_started() { + let _ = self.touch_plane.set_enabled(false); + } + if self.grabbable.grab_action().actor_stopped() { + let _ = self.touch_plane.set_enabled(true); + } + self.touch_plane.update(); + } +} + +fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { + return match &icon.icon_type { + IconType::Png => { + let t = Transform::from_rotation_scale( + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + [APP_SIZE * 0.5; 3], + ); + + let model = Model::create( + parent, + t, + &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), + )?; + model + .model_part("Hex")? + .set_material_parameter("color", MaterialParameter::Color([0.0, 1.0, 1.0, 1.0]))?; + model.model_part("Icon")?.set_material_parameter( + "diffuse", + MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), + )?; + Ok(model) + } + IconType::Gltf => Ok(Model::create( + parent, + Transform::from_scale([0.05; 3]), + &ResourceID::new_direct(icon.path.clone())?, + )?), + _ => panic!("Invalid Icon Type"), + }; +} + +pub struct App { + application: Application, + parent: Spatial, + position: Vector3, + grabbable: Grabbable, + _field: BoxField, + icon: Model, + label: Option, + grabbable_shrink: Option>, + grabbable_grow: Option>, + grabbable_move: Option>, + currently_shown: bool, +} +impl App { + pub fn create_from_desktop_file( + parent: &Spatial, + position: impl Into>, + desktop_file: DesktopFile, + ) -> Result { + let position = position.into(); + let field = BoxField::create(parent, Transform::default(), [APP_SIZE; 3])?; + let application = Application::create(&parent.client()?, desktop_file)?; + let icon = application.icon(128, false); + let grabbable = Grabbable::create( + parent, + Transform::from_position(position), + &field, + GrabData { + max_distance: 0.01, + frame_cancel_threshold: 50, + ..Default::default() + }, + )?; + grabbable.content_parent().set_spatial_parent(parent)?; + field.set_spatial_parent(grabbable.content_parent())?; + let icon = icon + .map(|i| model_from_icon(grabbable.content_parent(), &i)) + .unwrap_or_else(|| { + Ok(Model::create( + grabbable.content_parent(), + Transform::from_rotation_scale( + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + [APP_SIZE * 0.5; 3], + ), + &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), + )?) + })?; + + let label_style = TextStyle { + character_height: APP_SIZE * 2.0, + bounds: Some(Bounds { + bounds: [1.0; 2].into(), + fit: TextFit::Wrap, + bounds_align: Alignment::XCenter | Alignment::YCenter, + }), + text_align: Alignment::Center.into(), + ..Default::default() + }; + let label = application.name().and_then(|name| { + Text::create( + &icon, + Transform::from_position_rotation( + [0.0, 0.1, -(APP_SIZE * 4.0)], + Quat::from_rotation_x(PI * 0.5), + ), + name, + label_style, + ) + .ok() + }); + Ok(App { + parent: parent.alias(), + position, + grabbable, + _field: field, + label, + application, + icon, + grabbable_shrink: None, + grabbable_grow: None, + grabbable_move: None, + currently_shown: true, + }) + } + pub fn content_parent(&self) -> &Spatial { + self.grabbable.content_parent() + } + pub fn toggle(&mut self) { + self.grabbable.set_enabled(!self.currently_shown).unwrap(); + if self.currently_shown { + self.grabbable_move = Some(Tweener::quart_in_out(1.0, 0.0001, 0.25)); //TODO make the scale a parameter + } else { + self.icon.set_enabled(true).unwrap(); + self.label.as_ref().map(|l| l.set_enabled(true).unwrap()); + self.grabbable_move = Some(Tweener::quart_in_out(0.0001, 1.0, 0.25)); + } + self.currently_shown = !self.currently_shown; + } +} +impl RootHandler for App { + fn frame(&mut self, info: FrameInfo) { + let _ = self.grabbable.update(&info); + + if let Some(grabbable_move) = &mut self.grabbable_move { + if !grabbable_move.is_finished() { + let scale = grabbable_move.move_by(info.delta); + self.grabbable + .content_parent() + .set_position( + Some(&self.parent), + [ + self.position.x * scale, + self.position.y * scale, + self.position.z * scale, + ], + ) + .unwrap(); + } else { + if grabbable_move.final_value() == 0.0001 { + self.icon.set_enabled(false).unwrap(); + self.label.as_ref().map(|l| l.set_enabled(false).unwrap()); + } + self.grabbable_move = None; + } + } + if let Some(grabbable_shrink) = &mut self.grabbable_shrink { + if !grabbable_shrink.is_finished() { + let scale = grabbable_shrink.move_by(info.delta); + self.grabbable + .content_parent() + .set_scale(Some(&self.parent), Vector3::from([scale; 3])) + .unwrap(); + } else { + self.grabbable + .content_parent() + .set_spatial_parent(&self.parent) + .unwrap(); + if self.currently_shown { + self.grabbable_grow = Some(Tweener::quart_in_out(0.0001, 1.0, 0.25)); + self.grabbable.cancel_angular_velocity(); + self.grabbable.cancel_linear_velocity(); + } + self.grabbable_shrink = None; + self.grabbable + .content_parent() + .set_position(Some(&self.parent), self.position) + .unwrap(); + self.grabbable + .content_parent() + .set_rotation(Some(&self.parent), Quat::default()) + .unwrap(); + self.icon + .set_rotation( + None, + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + ) + .unwrap(); + } + } else if let Some(grabbable_grow) = &mut self.grabbable_grow { + if !grabbable_grow.is_finished() { + let scale = grabbable_grow.move_by(info.delta); + self.grabbable + .content_parent() + .set_scale(Some(&self.parent), Vector3::from([scale; 3])) + .unwrap(); + } else { + self.grabbable + .content_parent() + .set_spatial_parent(&self.parent) + .unwrap(); + self.grabbable_grow = None; + } + } else if self.grabbable.valid() && self.grabbable.grab_action().actor_stopped() { + self.grabbable_shrink = Some(Tweener::quart_in_out(APP_SIZE * 0.5, 0.0001, 0.25)); + let Ok(distance_future) = self.grabbable + .content_parent() + .get_position_rotation_scale(&self.parent) + else {return}; + + let application = self.application.clone(); + let space = self.content_parent().alias(); + + //TODO: split the executable string for the args + tokio::task::spawn(async move { + let distance_vector = distance_future.await.ok().unwrap().0; + let distance = ((distance_vector.x.powi(2) + distance_vector.y.powi(2)).sqrt() + + distance_vector.z.powi(2)) + .sqrt(); + if dbg!(distance) > ACTIVATION_DISTANCE { + let _ = application.launch(&space); + } + }); + } + } +} diff --git a/res/protostar/hexagon/hexagon.bin b/res/protostar/hexagon/hexagon.bin index e900474..f56fec4 100644 Binary files a/res/protostar/hexagon/hexagon.bin and b/res/protostar/hexagon/hexagon.bin differ diff --git a/res/protostar/hexagon/hexagon.gltf b/res/protostar/hexagon/hexagon.gltf index 2199495..f0480e3 100644 --- a/res/protostar/hexagon/hexagon.gltf +++ b/res/protostar/hexagon/hexagon.gltf @@ -1,276 +1,286 @@ { - "asset" : { - "generator" : "Khronos glTF Blender I/O v3.4.50", - "version" : "2.0" - }, - "extensionsUsed" : [ - "KHR_materials_unlit" - ], - "scene" : 0, - "scenes" : [ - { - "name" : "Scene", - "nodes" : [ - 0 - ] - } - ], - "nodes" : [ - { - "mesh" : 0, - "name" : "Hex" - } - ], - "materials" : [ - { - "alphaCutoff" : 0.5, - "alphaMode" : "MASK", - "extensions" : { - "KHR_materials_unlit" : {} - }, - "name" : "Icon", - "pbrMetallicRoughness" : { - "baseColorTexture" : { - "index" : 0, - "texCoord" : 0 - }, - "metallicFactor" : 0, - "roughnessFactor" : 0.9 - } - }, - { - "alphaMode" : "BLEND", - "extensions" : { - "KHR_materials_unlit" : {} - }, - "name" : "Hex", - "pbrMetallicRoughness" : { - "baseColorFactor" : [ - 1, - 0, - 0, - 1 - ], - "baseColorTexture" : { - "index" : 1, - "texCoord" : 0 - }, - "metallicFactor" : 0, - "roughnessFactor" : 0.9 - } - } - ], - "meshes" : [ - { - "name" : "Circle", - "primitives" : [ - { - "attributes" : { - "COLOR_0" : 0, - "POSITION" : 1, - "TEXCOORD_0" : 2, - "NORMAL" : 3 - }, - "indices" : 4, - "material" : 0 - }, - { - "attributes" : { - "COLOR_0" : 5, - "POSITION" : 6, - "TEXCOORD_0" : 7, - "NORMAL" : 8 - }, - "indices" : 9, - "material" : 1 - } - ] - } - ], - "textures" : [ - { - "sampler" : 0, - "source" : 0 - }, - { - "sampler" : 1, - "source" : 1 - } - ], - "images" : [ - { - "mimeType" : "image/png", - "name" : "icon_test", - "uri" : "icon_test.png" - }, - { - "mimeType" : "image/png", - "name" : "hex_atlas", - "uri" : "hex_atlas.png" - } - ], - "accessors" : [ - { - "bufferView" : 0, - "componentType" : 5123, - "count" : 4, - "normalized" : true, - "type" : "VEC4" - }, - { - "bufferView" : 1, - "componentType" : 5126, - "count" : 4, - "max" : [ - 0.5853440165519714, - 0.05000000074505806, - 0.5853440165519714 - ], - "min" : [ - -0.5853440165519714, - 0.05000000074505806, - -0.5853440165519714 - ], - "type" : "VEC3" - }, - { - "bufferView" : 2, - "componentType" : 5126, - "count" : 4, - "type" : "VEC2" - }, - { - "bufferView" : 3, - "componentType" : 5126, - "count" : 4, - "type" : "VEC3" - }, - { - "bufferView" : 4, - "componentType" : 5123, - "count" : 6, - "type" : "SCALAR" - }, - { - "bufferView" : 5, - "componentType" : 5123, - "count" : 54, - "normalized" : true, - "type" : "VEC4" - }, - { - "bufferView" : 6, - "componentType" : 5126, - "count" : 54, - "max" : [ - 1.0441828966140747, - 0.05000000074505806, - 0.9042890667915344 - ], - "min" : [ - -1.0441828966140747, - 0, - -0.9042890667915344 - ], - "type" : "VEC3" - }, - { - "bufferView" : 7, - "componentType" : 5126, - "count" : 54, - "type" : "VEC2" - }, - { - "bufferView" : 8, - "componentType" : 5126, - "count" : 54, - "type" : "VEC3" - }, - { - "bufferView" : 9, - "componentType" : 5123, - "count" : 84, - "type" : "SCALAR" - } - ], - "bufferViews" : [ - { - "buffer" : 0, - "byteLength" : 32, - "byteOffset" : 0, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 48, - "byteOffset" : 32, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 32, - "byteOffset" : 80, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 48, - "byteOffset" : 112, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 12, - "byteOffset" : 160, - "target" : 34963 - }, - { - "buffer" : 0, - "byteLength" : 432, - "byteOffset" : 172, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 648, - "byteOffset" : 604, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 432, - "byteOffset" : 1252, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 648, - "byteOffset" : 1684, - "target" : 34962 - }, - { - "buffer" : 0, - "byteLength" : 168, - "byteOffset" : 2332, - "target" : 34963 - } - ], - "samplers" : [ - { - "magFilter" : 9729, - "minFilter" : 9987, - "wrapS" : 33071, - "wrapT" : 33071 - }, - { - "magFilter" : 9729, - "minFilter" : 9987 - } - ], - "buffers" : [ - { - "byteLength" : 2500, - "uri" : "hexagon.bin" - } - ] + "asset":{ + "generator":"Khronos glTF Blender I/O v3.5.30", + "version":"2.0" + }, + "extensionsUsed":[ + "KHR_materials_unlit" + ], + "scene":0, + "scenes":[ + { + "name":"Scene", + "nodes":[ + 0, + 1 + ] + } + ], + "nodes":[ + { + "mesh":0, + "name":"Icon" + }, + { + "mesh":1, + "name":"Hex" + } + ], + "materials":[ + { + "alphaCutoff":0.5, + "alphaMode":"MASK", + "extensions":{ + "KHR_materials_unlit":{} + }, + "name":"Icon", + "pbrMetallicRoughness":{ + "baseColorTexture":{ + "index":0, + "texCoord":0 + }, + "metallicFactor":0, + "roughnessFactor":0.9 + } + }, + { + "alphaMode":"BLEND", + "extensions":{ + "KHR_materials_unlit":{} + }, + "name":"Hex", + "pbrMetallicRoughness":{ + "baseColorFactor":[ + 1, + 0, + 0, + 1 + ], + "baseColorTexture":{ + "index":1, + "texCoord":0 + }, + "metallicFactor":0, + "roughnessFactor":0.9 + } + } + ], + "meshes":[ + { + "name":"Circle", + "primitives":[ + { + "attributes":{ + "COLOR_0":0, + "POSITION":1, + "TEXCOORD_0":2, + "NORMAL":3 + }, + "indices":4, + "material":0 + } + ] + }, + { + "name":"Circle.001", + "primitives":[ + { + "attributes":{ + "COLOR_0":5, + "POSITION":6, + "TEXCOORD_0":7, + "NORMAL":8 + }, + "indices":9, + "material":1 + } + ] + } + ], + "textures":[ + { + "sampler":0, + "source":0 + }, + { + "sampler":1, + "source":1 + } + ], + "images":[ + { + "mimeType":"image/png", + "name":"icon_test", + "uri":"icon_test.png" + }, + { + "mimeType":"image/png", + "name":"hex_atlas", + "uri":"hex_atlas.png" + } + ], + "accessors":[ + { + "bufferView":0, + "componentType":5123, + "count":4, + "normalized":true, + "type":"VEC4" + }, + { + "bufferView":1, + "componentType":5126, + "count":4, + "max":[ + 0.5853440165519714, + 0.05000000074505806, + 0.5853440165519714 + ], + "min":[ + -0.5853440165519714, + 0.05000000074505806, + -0.5853440165519714 + ], + "type":"VEC3" + }, + { + "bufferView":2, + "componentType":5126, + "count":4, + "type":"VEC2" + }, + { + "bufferView":3, + "componentType":5126, + "count":4, + "type":"VEC3" + }, + { + "bufferView":4, + "componentType":5123, + "count":6, + "type":"SCALAR" + }, + { + "bufferView":5, + "componentType":5123, + "count":54, + "normalized":true, + "type":"VEC4" + }, + { + "bufferView":6, + "componentType":5126, + "count":54, + "max":[ + 1.0441828966140747, + 0.05000000074505806, + 0.9042890667915344 + ], + "min":[ + -1.0441828966140747, + 0, + -0.9042890667915344 + ], + "type":"VEC3" + }, + { + "bufferView":7, + "componentType":5126, + "count":54, + "type":"VEC2" + }, + { + "bufferView":8, + "componentType":5126, + "count":54, + "type":"VEC3" + }, + { + "bufferView":9, + "componentType":5123, + "count":84, + "type":"SCALAR" + } + ], + "bufferViews":[ + { + "buffer":0, + "byteLength":32, + "byteOffset":0, + "target":34962 + }, + { + "buffer":0, + "byteLength":48, + "byteOffset":32, + "target":34962 + }, + { + "buffer":0, + "byteLength":32, + "byteOffset":80, + "target":34962 + }, + { + "buffer":0, + "byteLength":48, + "byteOffset":112, + "target":34962 + }, + { + "buffer":0, + "byteLength":12, + "byteOffset":160, + "target":34963 + }, + { + "buffer":0, + "byteLength":432, + "byteOffset":172, + "target":34962 + }, + { + "buffer":0, + "byteLength":648, + "byteOffset":604, + "target":34962 + }, + { + "buffer":0, + "byteLength":432, + "byteOffset":1252, + "target":34962 + }, + { + "buffer":0, + "byteLength":648, + "byteOffset":1684, + "target":34962 + }, + { + "buffer":0, + "byteLength":168, + "byteOffset":2332, + "target":34963 + } + ], + "samplers":[ + { + "magFilter":9729, + "minFilter":9987, + "wrapS":33071, + "wrapT":33071 + }, + { + "magFilter":9729, + "minFilter":9987 + } + ], + "buffers":[ + { + "byteLength":2500, + "uri":"hexagon.bin" + } + ] } diff --git a/src/application.rs b/src/application.rs new file mode 100644 index 0000000..466bddc --- /dev/null +++ b/src/application.rs @@ -0,0 +1,100 @@ +use crate::xdg::{DesktopFile, Icon, IconType}; +use nix::unistd::setsid; +use regex::Regex; +use stardust_xr_fusion::{ + client::Client, + node::{NodeError, NodeType}, + spatial::Spatial, + startup_settings::StartupSettings, +}; +use std::{ + os::unix::process::CommandExt, + process::{Command, Stdio}, + sync::Arc, +}; + +#[derive(Debug, Clone)] +pub struct Application { + desktop_file: DesktopFile, + startup_settings: Arc, +} +impl Application { + pub fn create(client: &Arc, desktop_file: DesktopFile) -> Result { + if desktop_file.no_display { + return Err(NodeError::DoesNotExist); + } + + let startup_settings = Arc::new(StartupSettings::create(client)?); + Ok(Application { + desktop_file, + startup_settings, + }) + } + + pub fn name(&self) -> Option<&str> { + self.desktop_file.name.as_deref() + } + pub fn categories(&self) -> &[String] { + self.desktop_file.categories.as_slice() + } + + pub fn icon(&self, preferred_px_size: u16, prefer_3d: bool) -> Option { + let raw_icons = self.desktop_file.get_raw_icons(preferred_px_size); + let mut icon = raw_icons.iter().max_by_key(|i| i.size).cloned(); + if prefer_3d { + icon = raw_icons + .into_iter() + .find(|i| match i.icon_type { + IconType::Gltf => true, + _ => false, + }) + .or(icon); + } + + icon.and_then(|i| i.cached_process(preferred_px_size).ok()) + } + + pub fn launch(&self, launch_space: &Spatial) -> Result<(), NodeError> { + self.startup_settings.set_root(launch_space)?; + let future_startup_token = self.startup_settings.generate_startup_token()?; + let future_connection_env = self + .startup_settings + .node() + .client()? + .get_connection_environment()?; + + let executable = self + .desktop_file + .command + .clone() + .ok_or(NodeError::DoesNotExist)?; + tokio::task::spawn(async move { + let Ok(startup_token) = future_startup_token.await else {return}; + let Ok(connection_env) = future_connection_env.await else {return}; + + for (k, v) in connection_env.into_iter() { + std::env::set_var(k, v); + } + + std::env::set_var("STARDUST_STARTUP_TOKEN", startup_token); + let re = Regex::new(r"%[fFuUdDnNickvm]").unwrap(); + let exec = re.replace_all(&executable, ""); + unsafe { + Command::new("sh") + .arg("-c") + .arg(exec.to_string()) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .pre_exec(|| { + _ = setsid(); + Ok(()) + }) + .spawn() + .expect("Failed to start child process"); + } + }); + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index bda7f63..c9c8dfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ +pub mod application; pub mod protostar; pub mod xdg; diff --git a/src/main.rs b/src/main.rs index a41c780..fcfe8bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,5 @@ use clap::Parser; -use color_eyre::{ - eyre::{bail, Result}, - Report, -}; +use color_eyre::{eyre::Result, Report}; use manifest_dir_macros::directory_relative_path; use protostar::{protostar::ProtoStar, xdg::parse_desktop_file}; use stardust_xr_fusion::client::Client; @@ -11,21 +8,8 @@ use std::path::PathBuf; #[derive(Debug, Parser)] #[clap(author, version, about, long_about = None)] struct Args { - #[clap(short, long, default_value_t = 0.1)] - size: f32, - #[clap( - short, - long, - conflicts_with = "command", - required_unless_present = "command", - conflicts_with = "icon", - required_unless_present = "icon" - )] - desktop_file: Option, - #[clap(short, long, conflicts_with = "desktop_file", requires = "command")] - icon: Option, - #[clap(short, long, conflicts_with = "desktop_file", requires = "icon")] - command: Option, + // #[clap(short, long)] + desktop_file: PathBuf, } #[tokio::main(flavor = "current_thread")] diff --git a/src/protostar.rs b/src/protostar.rs index 0913cc7..9ae86ab 100644 --- a/src/protostar.rs +++ b/src/protostar.rs @@ -1,5 +1,10 @@ use crate::xdg::{DesktopFile, Icon, IconType}; use color_eyre::eyre::{eyre, Result}; +use crate::{ + application::Application, + xdg::{DesktopFile, Icon, IconType}, +}; +use color_eyre::eyre::Result; use glam::Quat; use mint::Vector3; use nix::unistd::setsid; @@ -11,17 +16,20 @@ use stardust_xr_fusion::{ fields::BoxField, node::NodeType, spatial::Spatial, - startup_settings::StartupSettings, }; use stardust_xr_molecules::{GrabData, Grabbable}; use std::f32::consts::PI; use std::os::unix::process::CommandExt; use std::process::{Command, Stdio}; +use std::f32::consts::PI; use tween::{QuartInOut, Tweener}; const MODEL_SCALE: f32 = 0.03; const ACTIVATION_DISTANCE: f32 = 1.0; +const MODEL_SCALE: f32 = 0.03; +const ACTIVATION_DISTANCE: f32 = 0.5; + fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { return match &icon.icon_type { IconType::Png => { @@ -39,6 +47,10 @@ fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { model_part .set_material_parameter("color", MaterialParameter::Color([0.0, 1.0, 1.0, 1.0]))?; model_part.set_material_parameter( + model + .model_part("Hex")? + .set_material_parameter("color", MaterialParameter::Color([0.0, 1.0, 1.0, 1.0]))?; + model.model_part("Icon")?.set_material_parameter( "diffuse", MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), )?; @@ -54,10 +66,13 @@ fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { } pub struct ProtoStar { + parent: Spatial, + position: Vector3, + application: Application, parent: Spatial, position: Vector3, grabbable: Grabbable, - field: BoxField, + _field: BoxField, icon: Model, label: Option, grabbable_shrink: Option>, @@ -65,6 +80,11 @@ pub struct ProtoStar { grabbable_move: Option>, execute_command: String, currently_shown: bool, + label: Option, + grabbable_shrink: Option>, + grabbable_grow: Option>, + grabbable_move: Option>, + currently_shown: bool, } impl ProtoStar { pub fn create_from_desktop_file( @@ -94,6 +114,16 @@ impl ProtoStar { } Self::new_raw( + pub fn create_from_desktop_file( + parent: &Spatial, + position: impl Into>, + desktop_file: DesktopFile, + ) -> Result { + let position = position.into(); + let field = BoxField::create(parent, Transform::default(), [MODEL_SCALE * 2.0; 3])?; + let application = Application::create(&parent.client()?, desktop_file)?; + let icon = application.icon(128, false); + let grabbable = Grabbable::create( parent, position, desktop_file.name.as_deref(), @@ -113,6 +143,7 @@ impl ProtoStar { let grabbable = Grabbable::create( parent, Transform::from_position(position), + Transform::from_position(position), &field, GrabData { max_distance: 0.01, @@ -156,18 +187,48 @@ impl ProtoStar { ) .ok() }); + + let label_style = TextStyle { + character_height: MODEL_SCALE * 4.0, + bounds: Some(Bounds { + bounds: [1.0; 2].into(), + fit: TextFit::Wrap, + bounds_align: Alignment::XCenter | Alignment::YCenter, + }), + text_align: Alignment::Center.into(), + ..Default::default() + }; + let label = application.name().and_then(|name| { + Text::create( + &icon, + Transform::from_position_rotation( + [0.0, 0.1, -(MODEL_SCALE * 8.0)], + Quat::from_rotation_x(PI * 0.5), + ), + name, + label_style, + ) + .ok() + }); Ok(ProtoStar { parent: parent.alias(), position, grabbable, field, label, + _field: field, + label, + application, icon, grabbable_shrink: None, grabbable_grow: None, execute_command, currently_shown: true, grabbable_move: None, + grabbable_shrink: None, + grabbable_grow: None, + grabbable_move: None, + currently_shown: true, }) } pub fn content_parent(&self) -> &Spatial { @@ -188,6 +249,7 @@ impl ProtoStar { impl RootHandler for ProtoStar { fn frame(&mut self, info: FrameInfo) { self.grabbable.update(&info).unwrap(); + let _ = self.grabbable.update(&info); if let Some(grabbable_move) = &mut self.grabbable_move { if !grabbable_move.is_finished() { @@ -250,6 +312,19 @@ impl RootHandler for ProtoStar { self.grabbable .content_parent() .set_scale(Some(&self.parent), Vector3::from([scale; 3])) + if let Some(grabbable_move) = &mut self.grabbable_move { + if !grabbable_move.is_finished() { + let scale = grabbable_move.move_by(info.delta); + self.grabbable + .content_parent() + .set_position( + Some(&self.parent), + [ + self.position.x * scale, + self.position.y * scale, + self.position.z * scale, + ], + ) .unwrap(); } else { self.grabbable @@ -257,6 +332,11 @@ impl RootHandler for ProtoStar { .set_spatial_parent(&self.parent) .unwrap(); self.grabbable_grow = None; + if grabbable_move.final_value() == 0.0001 { + self.icon.set_enabled(false).unwrap(); + self.label.as_ref().map(|l| l.set_enabled(false).unwrap()); + } + self.grabbable_move = None; } } else if self.grabbable.grab_action().actor_stopped() { let startup_settings = StartupSettings::create(&self.field.client().unwrap()).unwrap(); @@ -272,6 +352,65 @@ impl RootHandler for ProtoStar { let executable = self.execute_command.clone(); + //TODO: split the executable string for the args + } + if let Some(grabbable_shrink) = &mut self.grabbable_shrink { + if !grabbable_shrink.is_finished() { + let scale = grabbable_shrink.move_by(info.delta); + self.grabbable + .content_parent() + .set_scale(Some(&self.parent), Vector3::from([scale; 3])) + .unwrap(); + } else { + self.grabbable + .content_parent() + .set_spatial_parent(&self.parent) + .unwrap(); + if self.currently_shown { + self.grabbable_grow = Some(Tweener::quart_in_out(0.0001, 1.0, 0.25)); + self.grabbable.cancel_angular_velocity(); + self.grabbable.cancel_linear_velocity(); + } + self.grabbable_shrink = None; + self.grabbable + .content_parent() + .set_position(Some(&self.parent), self.position) + .unwrap(); + self.grabbable + .content_parent() + .set_rotation(Some(&self.parent), Quat::default()) + .unwrap(); + self.icon + .set_rotation( + None, + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + ) + .unwrap(); + } + } else if let Some(grabbable_grow) = &mut self.grabbable_grow { + if !grabbable_grow.is_finished() { + let scale = grabbable_grow.move_by(info.delta); + self.grabbable + .content_parent() + .set_scale(Some(&self.parent), Vector3::from([scale; 3])) + .unwrap(); + } else { + self.grabbable + .content_parent() + .set_spatial_parent(&self.parent) + .unwrap(); + self.grabbable_grow = None; + } + } else if self.grabbable.valid() && self.grabbable.grab_action().actor_stopped() { + self.grabbable_shrink = Some(Tweener::quart_in_out(MODEL_SCALE, 0.0001, 0.25)); + let Ok(distance_future) = self.grabbable + .content_parent() + .get_position_rotation_scale(&self.parent) + else {return}; + + let application = self.application.clone(); + let space = self.content_parent().alias(); + //TODO: split the executable string for the args tokio::task::spawn(async move { let distance_vector = distance_future.await.ok().unwrap().0; @@ -298,6 +437,12 @@ impl RootHandler for ProtoStar { .spawn() .expect("Failed to start child process"); } + let distance_vector = distance_future.await.ok().unwrap().0; + let distance = ((distance_vector.x.powi(2) + distance_vector.y.powi(2)).sqrt() + + distance_vector.z.powi(2)) + .sqrt(); + if dbg!(distance) > ACTIVATION_DISTANCE { + let _ = application.launch(&space); } }); } diff --git a/src/xdg.rs b/src/xdg.rs index 0ff4bf1..f41596e 100644 --- a/src/xdg.rs +++ b/src/xdg.rs @@ -2,6 +2,9 @@ use color_eyre::eyre::Result; use lazy_static::lazy_static; use linicon; use regex::Regex; +use lazy_static::lazy_static; +use linicon; +use regex::Regex; use resvg::render; use resvg::tiny_skia::{Pixmap, Transform}; use resvg::usvg::{FitTo, Tree}; @@ -9,14 +12,21 @@ use serde::{Deserialize, Serialize}; use serde_json; use serde_with::serde_as; use std::collections::HashMap; +use serde::{Deserialize, Serialize}; +use serde_json; +use serde_with::serde_as; +use std::collections::HashMap; use std::ffi::OsString; use std::fs::create_dir_all; use std::fs::File; +use std::fs::File; use std::io::{BufRead, BufReader, ErrorKind}; use std::io::{Read, Write}; +use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Mutex; +use std::sync::Mutex; use std::{env, fs}; use walkdir::WalkDir; @@ -62,14 +72,64 @@ lazy_static! { get_image_cache_dir().join("imagechache.map") )); } +#[serde_as] +#[derive(Deserialize, Serialize)] +struct ImageCache { + path: PathBuf, + #[serde_as(as = "Vec<(_, _)>")] + pub map: HashMap, +} +impl ImageCache { + fn new(path: PathBuf) -> Self { + if let Ok(mut file) = File::open(&path) { + let mut buf = vec![]; + if file.read_to_end(&mut buf).is_ok() { + if let Ok(cache) = serde_json::from_slice(&buf[..]) { + return cache; + } + } + } + + //There was no file, or the file failed to load, create a new World. + ImageCache { + path, + map: HashMap::new(), + } + } + + fn insert(&mut self, k: String, v: PathBuf) { + self.map.insert(k, v); + } + + fn save(&self) { + let mut f = File::create(&self.path).unwrap(); + let buf = serde_json::to_vec(&self).unwrap(); + f.write_all(&buf[..]).unwrap(); + } +} + +lazy_static! { + static ref IMAGE_CACHE: Mutex = Mutex::new(ImageCache::new( + get_image_cache_dir().join("imagechache.map") + )); +} + +fn get_data_dirs() -> Vec { + let xdg_data_dirs_str = std::env::var("XDG_DATA_DIRS").unwrap_or_default(); fn get_data_dirs() -> Vec { let xdg_data_dirs_str = std::env::var("XDG_DATA_DIRS").unwrap_or_default(); + let xdg_data_dirs = xdg_data_dirs_str let xdg_data_dirs = xdg_data_dirs_str .split(":") .filter_map(|dir| PathBuf::from_str(dir).ok()); + .filter_map(|dir| PathBuf::from_str(dir).ok()); + let data_home = dirs::home_dir() + .unwrap_or(PathBuf::from_str("/usr/share/").expect( + "No XDG_DATA_DIR set, no HOME directory found and no /usr/share direcotry found", + )) let data_home = dirs::home_dir() .unwrap_or(PathBuf::from_str("/usr/share/").expect( "No XDG_DATA_DIR set, no HOME directory found and no /usr/share direcotry found", @@ -90,12 +150,30 @@ fn get_app_dirs() -> Vec { .filter(|dir| dir.exists() && dir.is_dir()) .collect() } + .join("share"); + xdg_data_dirs + .chain([data_home].into_iter()) + .filter(|dir| dir.exists() && dir.is_dir()) + .collect() +} + +fn get_app_dirs() -> Vec { + get_data_dirs() + .into_iter() + .map(|dir| dir.join("applications")) + .filter(|dir| dir.exists() && dir.is_dir()) + .collect() +} + +pub fn get_desktop_files() -> Vec { pub fn get_desktop_files() -> Vec { let desktop_extension = OsString::from_str("desktop").unwrap(); // Get the list of directories to search let app_dirs = get_app_dirs(); + let app_dirs = get_app_dirs(); app_dirs + .into_iter() .into_iter() .flat_map(|dir| { // Follow symlinks and recursively search directories @@ -140,6 +218,10 @@ pub fn parse_desktop_file(path: PathBuf) -> Result { let mut no_display = false; let mut desktop_entry_found = false; + let re = Regex::new(r"^\[([^\]]*)\]$").unwrap(); + let mut no_display = false; + let mut desktop_entry_found = false; + let re = Regex::new(r"^\[([^\]]*)\]$").unwrap(); // Loop through each line of the file @@ -159,6 +241,14 @@ pub fn parse_desktop_file(path: PathBuf) -> Result { desktop_entry_found = entry.as_str().contains("Desktop Entry"); } + if !desktop_entry_found { + continue; + } + if let Some(captures) = re.captures(&line) { + let entry = captures.get(1).unwrap(); + desktop_entry_found = entry.as_str().contains("Desktop Entry"); + } + if !desktop_entry_found { continue; } @@ -187,6 +277,12 @@ pub fn parse_desktop_file(path: PathBuf) -> Result { _ => false, } } + "NoDisplay" => { + no_display = match value { + "true" => true, + _ => false, + } + } _ => (), // Ignore unknown keys } } @@ -199,6 +295,7 @@ pub fn parse_desktop_file(path: PathBuf) -> Result { categories, icon, no_display, + no_display, }) } @@ -231,6 +328,7 @@ pub struct DesktopFile { pub categories: Vec, pub icon: Option, pub no_display: bool, + pub no_display: bool, } impl DesktopFile { pub fn get_raw_icons(&self) -> Vec { @@ -243,6 +341,13 @@ impl DesktopFile { } } + if let Some(cache_icon_path) = IMAGE_CACHE.lock().unwrap().map.get(icon_name) { + if cache_icon_path.exists() { + if let Some(icon) = Icon::from_path(cache_icon_path.to_owned(), 128) { + return vec![icon]; + } + } + } if let Some(cache_icon_path) = IMAGE_CACHE.lock().unwrap().map.get(icon_name) { if cache_icon_path.exists() { if let Some(icon) = Icon::from_path(cache_icon_path.to_owned(), 128) { @@ -251,6 +356,9 @@ impl DesktopFile { } } + let mut icons_iter = linicon::lookup_icon(icon_name) + .use_fallback_themes(false) + .peekable(); let mut icons_iter = linicon::lookup_icon(icon_name) .use_fallback_themes(false) .peekable(); @@ -259,6 +367,10 @@ impl DesktopFile { //dbg!("No icons found in current theme"); icons_iter = linicon::lookup_icon(icon_name).peekable(); } + if icons_iter.peek().is_none() { + //dbg!("No icons found in current theme"); + icons_iter = linicon::lookup_icon(icon_name).peekable(); + } let sized_png: Vec = icons_iter .filter_map(|i| i.ok()) @@ -266,9 +378,20 @@ impl DesktopFile { .map(|i| Icon::from_path(i.path, i.max_size - 2).unwrap()) .collect(); sized_png + let sized_png: Vec = icons_iter + .filter_map(|i| i.ok()) + .filter(|i| i.icon_type != linicon::IconType::XMP) //TODO: support XMP + .map(|i| Icon::from_path(i.path, i.max_size - 2).unwrap()) + .collect(); + sized_png } } +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Icon { + pub icon_type: IconType, + pub path: PathBuf, + pub size: u16, #[derive(Debug, PartialEq, Eq, Clone)] pub struct Icon { pub icon_type: IconType, @@ -276,6 +399,26 @@ pub struct Icon { pub size: u16, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum IconType { + Png, + Svg, + Gltf, +} +impl Icon { + pub fn from_path(path: PathBuf, size: u16) -> Option { + let icon_type = match path.extension().and_then(|ext| ext.to_str()) { + Some("png") => IconType::Png, + Some("svg") => IconType::Svg, + Some("glb") | Some("gltf") => IconType::Gltf, + _ => return None, + }; + return Some(Icon { + icon_type, + path, + size, + }); + #[derive(Debug, PartialEq, Eq, Clone)] pub enum IconType { Png, @@ -297,6 +440,33 @@ impl Icon { }); } + pub fn cached_process(self, size: u16) -> Result { + if !IMAGE_CACHE.lock().unwrap().map.contains_key( + &self + .path + .with_extension("") + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_owned(), + ) { + dbg!("Saving value in the DB"); + IMAGE_CACHE.lock().unwrap().insert( + self.path + .with_extension("") + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_owned(), + self.path.clone(), + ); + IMAGE_CACHE.lock().unwrap().save(); + } + match self.icon_type { + IconType::Svg => Ok(Icon::from_path(get_png_from_svg(self.path, size)?, size).unwrap()), + _ => Ok(self), pub fn cached_process(self, size: u16) -> Result { if !IMAGE_CACHE.lock().unwrap().map.contains_key( &self @@ -338,10 +508,11 @@ fn test_get_icon_path() { categories: vec![], icon: Some("krita".into()), no_display: false, + no_display: false, }; // Call the get_icon_path() function with a size argument and store the result - let icon_paths = desktop_file.get_raw_icons(); + let icon_paths = desktop_file.get_raw_icons(128); dbg!(&icon_paths); // Assert that the get_icon_path() function returns the expected result @@ -352,8 +523,26 @@ fn test_get_icon_path() { ) .unwrap() )); + assert!(icon_paths.contains( + &Icon::from_path( + PathBuf::from("/usr/share/icons/hicolor/32x32/apps/krita.png"), + 32 + ) + .unwrap() + )); } +pub fn get_image_cache_dir() -> PathBuf { + let cache_dir; + if let Ok(xdg_cache_home) = std::env::var("XDG_CACHE_HOME") { + cache_dir = + PathBuf::from_str(&xdg_cache_home).unwrap_or(dirs::home_dir().unwrap().join(".cache")) + } else { + cache_dir = dirs::home_dir().unwrap().join(".cache"); + } + let image_cache_dir = cache_dir.join("protostar_icon_cache"); + create_dir_all(&image_cache_dir).expect("Could not create image cache directory"); + return image_cache_dir; pub fn get_image_cache_dir() -> PathBuf { let cache_dir; if let Ok(xdg_cache_home) = std::env::var("XDG_CACHE_HOME") { @@ -367,6 +556,7 @@ pub fn get_image_cache_dir() -> PathBuf { return image_cache_dir; } +pub fn get_png_from_svg(svg_path: impl AsRef, size: u16) -> Result { pub fn get_png_from_svg(svg_path: impl AsRef, size: u16) -> Result { let svg_path = fs::canonicalize(svg_path)?; let svg_data = fs::read(svg_path.as_path())?; @@ -383,10 +573,26 @@ pub fn get_png_from_svg(svg_path: impl AsRef, size: u16) -> Result