diff --git a/Cargo.lock b/Cargo.lock index 4afcbe2..74ea0eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e08104bebc65a46f8bc7aa733d39ea6874bfa7156f41a46b805785e3af1587d" +checksum = "1c3a1cbc201cc13ed06cf875efb781f2249b3677f5c74571b67d817877f9d697" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -48,12 +48,12 @@ dependencies = [ [[package]] name = "android-activity" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.5.0", + "bitflags 2.6.0", "cc", "cesu8", "jni", @@ -81,9 +81,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "arrayref" @@ -140,9 +140,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" @@ -152,9 +152,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -165,49 +165,39 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -[[package]] -name = "block-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" -dependencies = [ - "objc-sys", -] - [[package]] name = "block2" -version = "0.3.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "block-sys", "objc2", ] [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -228,7 +218,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cairo-sys-rs", "glib", "libc", @@ -253,7 +243,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "log", "polling", "rustix", @@ -281,12 +271,13 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -297,9 +288,9 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-expr" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", "target-lexicon", @@ -313,15 +304,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - -[[package]] -name = "cfg_aliases" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "ciborium" @@ -352,18 +337,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" dependencies = [ "anstyle", "clap_lex", @@ -371,9 +356,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "cocoa" @@ -407,9 +392,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -417,9 +402,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -466,9 +451,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -511,9 +496,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -539,9 +524,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -550,14 +535,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] -name = "ctor" -version = "0.2.7" +name = "ctor-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" -dependencies = [ - "quote", - "syn 2.0.58", -] +checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b" [[package]] name = "cursor-icon" @@ -595,6 +576,15 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -640,14 +630,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.3", + "libloading 0.8.4", ] [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" @@ -657,11 +647,11 @@ checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" [[package]] name = "drm" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" +checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bytemuck", "drm-ffi", "drm-fourcc", @@ -670,9 +660,9 @@ dependencies = [ [[package]] name = "drm-ffi" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" +checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53" dependencies = [ "drm-sys", "rustix", @@ -686,9 +676,9 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" [[package]] name = "drm-sys" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176" +checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986" dependencies = [ "libc", "linux-raw-sys 0.6.4", @@ -696,9 +686,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" @@ -708,9 +698,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -718,9 +708,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fdeflate" @@ -743,9 +733,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -769,7 +759,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -818,7 +808,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -911,9 +901,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -958,7 +948,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "futures-channel", "futures-core", "futures-executor", @@ -986,7 +976,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -1059,14 +1049,14 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] name = "half" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -1074,9 +1064,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -1096,6 +1086,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "home" version = "0.5.9" @@ -1115,17 +1111,6 @@ dependencies = [ "png", ] -[[package]] -name = "icrate" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" -dependencies = [ - "block2", - "dispatch", - "objc2", -] - [[package]] name = "indexmap" version = "2.2.6" @@ -1142,7 +1127,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.52.0", ] @@ -1195,9 +1180,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -1217,16 +1202,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "serde", "unicode-segmentation", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libappindicator" @@ -1254,9 +1239,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" @@ -1270,12 +1255,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1284,7 +1269,7 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", "redox_syscall 0.4.1", ] @@ -1295,15 +1280,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "linux-raw-sys" @@ -1313,9 +1298,9 @@ checksum = "f0b5399f6804fbab912acbd8878ed3532d506b7c951b8f9f164ef90fef39e3f4" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "macos-accessibility-client" @@ -1338,9 +1323,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -1368,9 +1353,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", "simd-adler32", @@ -1378,9 +1363,9 @@ dependencies = [ [[package]] name = "muda" -version = "0.13.1" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f428b4e9db3d17e2f809dfb1ff9ddfbbf16c71790d1656d10aee320877e1392f" +checksum = "86b959f97c97044e4c96e32e1db292a7d594449546a3c6b77ae613dc3a5b5145" dependencies = [ "cocoa", "crossbeam-channel", @@ -1419,16 +1404,16 @@ dependencies = [ [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "jni-sys", "log", "ndk-sys", "num_enum", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.2", "thiserror", ] @@ -1440,9 +1425,9 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.5.0+25.2.9519653" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys", ] @@ -1459,9 +1444,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -1484,7 +1469,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -1509,25 +1494,206 @@ dependencies = [ [[package]] name = "objc-sys" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ "objc-sys", "objc2-encode", ] +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + [[package]] name = "objc2-encode" -version = "3.0.0" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] [[package]] name = "objc_id" @@ -1567,9 +1733,9 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7" +checksum = "6b41438d2fc63c46c74a2203bf5ccd82c41ba04347b2fcf5754f230b167067d5" dependencies = [ "ttf-parser", ] @@ -1605,6 +1771,26 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1625,9 +1811,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" dependencies = [ "num-traits", "plotters-backend", @@ -1638,15 +1824,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" dependencies = [ "plotters-backend", ] @@ -1666,13 +1852,13 @@ dependencies = [ [[package]] name = "polling" -version = "3.6.0" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", "rustix", "tracing", @@ -1733,9 +1919,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1751,9 +1937,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1766,9 +1952,9 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "raw-window-handle" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" @@ -1804,20 +1990,20 @@ checksum = "be105c72a1e6a5a1198acee3d5b506a15676b74a02ecd78060042a447f408d94" [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] @@ -1833,9 +2019,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -1845,9 +2031,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1856,9 +2042,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustc_version" @@ -1871,22 +2057,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1905,9 +2091,9 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "sctk-adwaita" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +checksum = "7de61fa7334ee8ee1f5c3c58dcc414fb9361e7e8f5bff9d45f4d69eeb89a7169" dependencies = [ "ab_glyph", "log", @@ -1918,35 +2104,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -1955,9 +2141,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -1983,7 +2169,7 @@ dependencies = [ "png", "serde", "softbuffer", - "toml 0.8.12", + "toml 0.8.14", "tray-icon", "winapi", "winit", @@ -2011,7 +2197,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -2032,23 +2218,22 @@ dependencies = [ [[package]] name = "smol_str" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" dependencies = [ "serde", ] [[package]] name = "softbuffer" -version = "0.4.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071916a85d1db274b4ed57af3a14afb66bd836ae7f82ebb6f1fd3455107830d9" +checksum = "d623bff5d06f60d738990980d782c8c866997d9194cfe79ecad00aa2f76826dd" dependencies = [ "as-raw-xcb-connection", "bytemuck", - "cfg_aliases 0.2.0", - "cocoa", + "cfg_aliases", "core-graphics", "drm", "fastrand", @@ -2056,9 +2241,12 @@ dependencies = [ "js-sys", "log", "memmap2", - "objc", - "raw-window-handle 0.6.0", - "redox_syscall 0.4.1", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle 0.6.2", + "redox_syscall 0.5.2", "rustix", "tiny-xlib", "wasm-bindgen", @@ -2088,9 +2276,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -2106,7 +2294,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.12", + "toml 0.8.14", "version-compare", ] @@ -2118,22 +2306,22 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -2163,13 +2351,14 @@ dependencies = [ [[package]] name = "tiny-xlib" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4098d49269baa034a8d1eae9bd63e9fa532148d772121dace3bcd6a6c98eb6d" +checksum = "1d52f22673960ad13af14ff4025997312def1223bfa7c8e4949d099e6b3d5d1c" dependencies = [ "as-raw-xcb-connection", - "ctor", - "libloading 0.8.3", + "ctor-lite", + "libloading 0.8.4", + "pkg-config", "tracing", ] @@ -2194,21 +2383,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.9", + "toml_edit 0.22.14", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] @@ -2248,15 +2437,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.9" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.5", + "winnow 0.6.13", ] [[package]] @@ -2277,14 +2466,14 @@ checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] name = "tray-icon" -version = "0.13.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da36482ee1dbcedfddb038b3a0f6d27f04d9470dc99dabfa90b8d7cdc8b5f3d6" +checksum = "3ad8319cca93189ea9ab1b290de0595960529750b6b8b501a399ed1ec3775d60" dependencies = [ "cocoa", "core-graphics", "crossbeam-channel", - "dirs-next", + "dirs", "libappindicator", "muda", "objc", @@ -2296,9 +2485,9 @@ dependencies = [ [[package]] name = "ttf-parser" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" [[package]] name = "unicode-ident" @@ -2371,7 +2560,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", "wasm-bindgen-shared", ] @@ -2405,7 +2594,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2418,9 +2607,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-backend" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" +checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07" dependencies = [ "cc", "downcast-rs", @@ -2432,11 +2621,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.2" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" +checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "rustix", "wayland-backend", "wayland-scanner", @@ -2448,16 +2637,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.1" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" +checksum = "a206e8b2b53b1d3fcb9428fec72bc278ce539e2fa81fe2bfc1ab27703d5187b9" dependencies = [ "rustix", "wayland-client", @@ -2470,7 +2659,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -2482,7 +2671,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2495,7 +2684,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2504,9 +2693,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" +checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565" dependencies = [ "proc-macro2", "quick-xml", @@ -2515,9 +2704,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" +checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12" dependencies = [ "dlib", "log", @@ -2537,9 +2726,9 @@ dependencies = [ [[package]] name = "web-time" -version = "0.2.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2585,11 +2774,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -2631,7 +2820,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -2666,17 +2855,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2693,9 +2883,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2711,9 +2901,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2729,9 +2919,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2747,9 +2943,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2765,9 +2961,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2783,9 +2979,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2801,43 +2997,47 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" -version = "0.29.15" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +checksum = "49f45a7b7e2de6af35448d7718dab6d95acec466eb3bb7a56f4d31d1af754004" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.5.0", + "bitflags 2.6.0", + "block2", "bytemuck", "calloop", - "cfg_aliases 0.1.1", + "cfg_aliases", + "concurrent-queue", "core-foundation", "core-graphics", "cursor-icon", - "icrate", + "dpi", "js-sys", "libc", - "log", "memmap2", "ndk", - "ndk-sys", "objc2", - "once_cell", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", "orbclient", "percent-encoding", - "raw-window-handle 0.6.0", - "redox_syscall 0.3.5", + "pin-project", + "raw-window-handle 0.6.2", + "redox_syscall 0.4.1", "rustix", "sctk-adwaita", "smithay-client-toolkit", "smol_str", + "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", @@ -2847,7 +3047,7 @@ dependencies = [ "wayland-protocols-plasma", "web-sys", "web-time", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", "x11rb", "xkbcommon-dl", @@ -2864,9 +3064,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.5" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] @@ -2903,14 +3103,14 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading 0.8.3", + "libloading 0.8.4", "once_cell", "rustix", "x11rb-protocol", @@ -2918,9 +3118,9 @@ dependencies = [ [[package]] name = "x11rb-protocol" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" @@ -2934,7 +3134,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "dlib", "log", "once_cell", @@ -2943,26 +3143,26 @@ dependencies = [ [[package]] name = "xkeysym" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] diff --git a/Cargo.toml b/Cargo.toml index afcfb35..718f491 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,8 +29,8 @@ debug = true # required for `cargo flamegraph`, and makes `cargo-bloat` output s benchmark = [] # used to compile reference functions only needed for benchmarking against [dependencies] -tray-icon = { version = "0.13", default-features = false } -winit = "0.29" +tray-icon = { version = "0.14", default-features = false } +winit = "0.30" softbuffer = "0.4" serde = { version = "1", features = ["derive"] } toml = "0.8.12" @@ -47,7 +47,7 @@ winapi = { version = "0.3", features = ["winuser", "windef", "minwindef"] } [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18" # must use this version of gtk because it's what tray-icon 0.10 needs -[target.'cfg(target_os = "windows")'.build-dependencies] +[build-dependencies] winres = "0.1" ico = "0.3" diff --git a/MAINTENANCE.md b/MAINTENANCE.md index f90a964..8506628 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -11,6 +11,12 @@ This document contains some common commands that I need to remember for package `cargo deny check` +## Check & Lint + +To check all supported targets for compilation/lint errors, run: + +`cargo clippy --target x86_64-pc-windows-msvc --target x86_64-apple-darwin --target aarch64-apple-darwin --all-features` + ## Tests `cargo test` diff --git a/README.md b/README.md index 099325f..f0733f7 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,6 @@ For suggestions, questions, or even just to say hey, feel free to start a [discu ## License -Copyright 2023 [Michael Ripley](https://github.com/zkxs). +Copyright 2023-2024 [Michael Ripley](https://github.com/zkxs). Simple Crosshair Overlay is provided under the [GPL-3.0 license](LICENSE). diff --git a/build.rs b/build.rs index f842e0c..d41b1f0 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,6 @@ // This file is part of simple-crosshair-overlay and is licenced under the GNU GPL v3.0. // See LICENSE file for full text. -// Copyright © 2023 Michael Ripley +// Copyright © 2023-2024 Michael Ripley use std::{env, fs, io}; use std::io::{BufWriter, Write}; @@ -17,11 +17,11 @@ use std::process::Command; const TRAY_ICON_DIMENSION: u32 = 32; /// The sexy Windows .ico with the multiple size defined below adds ~26k to the binary. -#[cfg(target_os = "windows")] const APP_ICON_DIMENSIONS: [u32; 5] = [16, 24, 32, 48, 64]; +const APP_ICON_DIMENSIONS: [u32; 5] = [16, 24, 32, 48, 64]; static CONSTANTS_SOURCE_NAME: &str = "constants.rs"; static TRAY_ICON_NAME: &str = "trayicon.argb"; -#[cfg(target_os = "windows")] static APP_ICON_NAME: &str = "app.ico"; +static APP_ICON_NAME: &str = "app.ico"; static APP_NAME: &str = "Simple Crosshair Overlay"; // Put in some indication that a build was in debug profile so there's a chance someone with the wrong build might one day notice @@ -56,8 +56,7 @@ fn main() -> io::Result<()> { } // only generate Windows resource info on Windows. - #[cfg(target_os = "windows")] - { + if env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { let icon_path = out_dir.join(APP_ICON_NAME); generate_file_if_not_cached(icon_path.as_path(), create_windows_app_icon_file)?; @@ -138,7 +137,6 @@ fn create_tray_icon_file(path: &Path) -> io::Result<()> { } /// build a .ico file for windows -#[cfg(target_os = "windows")] fn create_windows_app_icon_file(path: &Path) -> io::Result<()> { let mut icon_dir = ico::IconDir::new(ico::ResourceType::Icon); diff --git a/src/linux.rs b/src/linux.rs deleted file mode 100644 index 43c9e65..0000000 --- a/src/linux.rs +++ /dev/null @@ -1,108 +0,0 @@ -use tray_icon::menu::MenuId; - -use crate::MenuItems; - -pub trait MenuItemWithId { - fn id(&self) -> &MenuId; -} - -#[derive(Clone)] -pub struct LinuxMenuItem { - id: MenuId, -} - -impl LinuxCheckMenuItem { - pub fn new(id: &MenuId) -> LinuxMenuItem { - LinuxMenuItem { - id: id.to_owned(), - } - } -} - -impl MenuItemWithId for LinuxMenuItem { - fn id(&self) -> &MenuId { - &self.id - } -} - -pub trait MenuItemWithCheckbox { - fn is_checked(&self) -> bool; - fn set_checked(&mut self, checked: bool); - fn set_enabled(&mut self, enabled: bool); - fn is_dirty(&self) -> bool; - fn reset_dirty(&mut self); -} - -#[derive(Clone)] -pub struct LinuxCheckMenuItem { - id: MenuId, - enabled: bool, - checked: bool, - dirty: bool, -} - -impl LinuxCheckMenuItem { - pub fn new(id: &MenuId, checked: bool) -> LinuxCheckMenuItem { - LinuxCheckMenuItem { - id: id.to_owned(), - enabled: true, - checked, - dirty: false, - } - } -} - -impl MenuItemWithId for LinuxCheckMenuItem { - fn id(&self) -> &MenuId { - &self.id - } -} - -impl MenuItemWithCheckbox for LinuxCheckMenuItem { - fn is_checked(&self) -> bool { - self.checked - } - - fn set_checked(&mut self, checked: bool) { - self.checked = checked; - self.dirty = true; - } - - fn set_enabled(&mut self, enabled: bool) { - self.enabled = enabled; - self.dirty = true; - } - - fn is_dirty(&self) -> bool { - self.dirty - } - - fn reset_dirty(&mut self) { - self.dirty = false; - } -} - -#[derive(Clone)] -struct LinuxMenuItems { - visible_button: LinuxCheckMenuItem, - adjust_button: LinuxCheckMenuItem, - color_pick_button: LinuxCheckMenuItem, - image_pick_button: LinuxMenuItem, - reset_button: LinuxMenuItem, - about_button: LinuxMenuItem, - exit_button: LinuxMenuItem, -} - -impl LinuxMenuItems { - fn new(menu_items: &MenuItems) -> Self { - LinuxMenuItems { - visible_button: LinuxCheckMenuItem::new(menu_items.visible_button.id(), menu_items.visible_button.is_checked()), - adjust_button: LinuxCheckMenuItem::new(menu_items.adjust_button.id(), menu_items.adjust_button.is_checked()), - color_pick_button: LinuxCheckMenuItem::new(menu_items.adjust_button.id(), menu_items.adjust_button.is_checked()), - image_pick_button: LinuxMenuItem::new(menu_items.image_pick_button.id()), - reset_button: LinuxMenuItem::new(menu_items.reset_button.id()), - about_button: LinuxMenuItem::new(menu_items.about_button.id()), - exit_button: LinuxMenuItem::new(menu_items.exit_button.id()), - } - } -} diff --git a/src/main.rs b/src/main.rs index d9247c1..1b5dc43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,22 @@ // This file is part of simple-crosshair-overlay and is licenced under the GNU GPL v3.0. // See LICENSE file for full text. -// Copyright © 2023 Michael Ripley +// Copyright © 2023-2024 Michael Ripley #![windows_subsystem = "windows"] // necessary to remove the console window on Windows use std::io; -use std::num::NonZeroU32; -use std::rc::Rc; use debug_print::debug_println; -use softbuffer::{Context, Surface}; -use tray_icon::{Icon as TrayIcon, menu::Menu, TrayIconBuilder}; -use tray_icon::menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, Result as MenuResult, Submenu}; -use winit::dpi::{PhysicalPosition, PhysicalSize}; -use winit::event::{ElementState, Event, MouseButton, WindowEvent}; use winit::event_loop::{DeviceEvents, EventLoop}; -use winit::window::{CursorGrabMode, CursorIcon, Window, WindowBuilder, WindowLevel}; +use winit::window::{CursorGrabMode, Window}; use simple_crosshair_overlay::platform; -use simple_crosshair_overlay::platform::HotkeyManager; -use simple_crosshair_overlay::settings::{RenderMode, Settings}; use simple_crosshair_overlay::settings::CONFIG_PATH; +use simple_crosshair_overlay::settings::Settings; use simple_crosshair_overlay::util::dialog; -use simple_crosshair_overlay::util::image; -#[cfg(target_os = "linux")] -mod linux; +mod window; +mod tray; static ICON_TOOLTIP: &str = "Simple Crosshair Overlay"; @@ -36,10 +27,13 @@ mod build_constants { fn main() { // Initialize Eventloop before everything - let event_loop = EventLoop::new().unwrap(); + let event_loop: EventLoop = EventLoop::new().unwrap(); + // in theory Wait is now the default ControlFlow, so the following isn't needed: + // event_loop.set_control_flow(ControlFlow::Wait); + // settings has a decent quantity of data in it, but it never really gets moved so we can just leave it on the stack // the image buffer is internally boxed so don't worry about that - let mut settings = match Settings::load() { + let settings = match Settings::load() { Ok(settings) => settings, Err(e) if e.kind() == io::ErrorKind::NotFound => Settings::default(), // generate new settings file when it doesn't exist Err(e) => { @@ -48,105 +42,20 @@ fn main() { } }; - // HotkeyManager has a decent quantity of data in it, but again it never really gets moved so we can just leave it on the stack - let mut hotkey_manager = HotkeyManager::new(&settings.persisted.key_bindings).unwrap_or_else(|e| { - dialog::show_warning(format!("{e}\n\nUsing default hotkeys.")); - HotkeyManager::default() - }); - - // on linux we have to do this in a completely different way - #[cfg(not(target_os = "linux"))] let tray_menu = Menu::new(); - - let menu_items = MenuItems::default(); - - // windows: do not use a submenu - #[cfg(target_os = "windows")] { - menu_items.add_to_menu(&tray_menu); - } - - // mac: there are special submenu requirements - #[cfg(target_os = "macos")] { - // on mac all menu items must be in a submenu, so just make one with no name. Hope that doesn't cause problems... - let submenu = tray_icon::menu::Submenu::new("", true); - tray_menu.append(&submenu).unwrap(); - menu_items.add_to_menu(&submenu); - } - - // keep the tray icon in an Option so we can take() it later to drop - // on Linux this MUST be called on the GTK thread, so we have to do some weird hijinks to pass things around - #[cfg(not(target_os = "linux"))] let mut tray_icon = { - let tray_icon_builder = TrayIconBuilder::new() - .with_menu(Box::new(tray_menu)) - .with_tooltip(ICON_TOOLTIP) - .with_icon(get_icon()); - Some(tray_icon_builder.build().unwrap()) - }; - - #[cfg(target_os = "linux")] { - use std::sync::{Arc, Condvar, Mutex}; - use std::time::Duration; - - let condvar_pair = Arc::new((Mutex::new(false), Condvar::new())); - - // start GTK background thread - let condvar_pair_clone = condvar_pair.clone(); - std::thread::Builder::new() - .name("gtk-main".to_string()) - .spawn(move || { - debug_println!("starting GTK background thread"); - gtk::init().unwrap(); - debug_println!("GTK init complete"); - - // initialize the tray icon - let tray_menu = Menu::new(); - menu_items.add_to_menu(&tray_menu); - - let tray_icon_builder = TrayIconBuilder::new() - .with_menu(Box::new(tray_menu)) - .with_tooltip(ICON_TOOLTIP) - .with_icon(get_icon()); - let mut tray_icon = Some(tray_icon_builder.build().unwrap()); + // only functional on Linux targets + event_loop.listen_device_events(DeviceEvents::Never); - // signal that GTK init is complete - { - let (lock, condvar) = &*condvar_pair_clone; - let mut gtk_started = lock.lock().unwrap(); - *gtk_started = true; - condvar.notify_one(); - } // this block is actually necessary so that the lock gets released! + // start sending tick events + start_tick_sender(&settings, &event_loop); - debug_println!("GTK init signal sent. Starting GTK main loop."); - loop { - gtk::main_iteration_do(false); - //TODO: channel MenuItem state around? - std::thread::yield_now(); - } - debug_println!("GTK main loop returned!? Weird."); - }).unwrap(); - debug_println!("spawned GTK background thread"); + // create the winit application + let mut window_state = window::State::new(settings, &event_loop); - // wait for GTK to init - let (lock, condvar) = &*condvar_pair; - let gtk_started = lock.lock().unwrap(); - debug_println!("acquired GTK lock"); - if !*gtk_started { - debug_println!("waiting for GTK init signal"); - let (gtk_started, timeout_result) = condvar.wait_timeout(gtk_started, Duration::from_secs(5)).unwrap(); - if !*gtk_started { - panic!("GTK startup timed out = {}", timeout_result.timed_out()); - } - } - - debug_println!("GTK startup complete"); - } - - // native dialogs block a thread, so we'll spin up a single thread to loop through queued dialogs. - // If we ever need to show multiple dialogs, they just get queued. - let mut dialog_worker = dialog::spawn_worker(); - - let menu_channel = MenuEvent::receiver(); - event_loop.listen_device_events(DeviceEvents::Always); + // pass control to the event loop + event_loop.run_app(&mut window_state).unwrap(); +} +fn start_tick_sender(settings: &Settings, event_loop: &EventLoop) { let user_event_sender = event_loop.create_proxy(); let key_process_interval = settings.tick_interval; std::thread::Builder::new() @@ -156,204 +65,7 @@ fn main() { let _ = user_event_sender.send_event(()); std::thread::sleep(key_process_interval); } - }).unwrap(); - - // unsafe note: these three structs MUST live and die together. - // It is highly illegal to use the context or surface after the window is dropped. - // The context only gets used right here, so that's fine. - // As of this writing, none of these get moved. Therefore they all get dropped one after the other at the end of main(), which is safe. - let window = Rc::new(init_window(&event_loop, &mut settings)); - let context = Context::new(window.clone()).unwrap(); - let mut surface = Surface::new(&context, window.clone()).unwrap(); - - // remember some application state that's NOT part of our saved config - let mut window_visible = true; - let mut force_redraw = false; // if set to true, the next redraw will be forced even for known buffer contents - let mut last_mouse_position = PhysicalPosition::default(); - - let mut last_focused_window: Option = None; - - // pass control to the event loop - event_loop.run(move |event, window_target| { - // in theory Wait is now the default ControlFlow, so the following isn't needed: - // window_target.set_control_flow(ControlFlow::Wait); - - let mut window_position_dirty = false; - let mut window_scale_dirty = false; - - match event { - Event::WindowEvent { event: WindowEvent::RedrawRequested, .. } => { - // failsafe to resize the window before a redraw if necessary - // ...and of course it's fucking necessary - settings.validate_window_size(&window, window.inner_size()); - draw_window(&mut surface, &settings, force_redraw); - force_redraw = false; - } - Event::UserEvent(_) => { - hotkey_manager.poll_keys(); - hotkey_manager.process_keys(); - - let adjust_mode = menu_items.adjust_button.is_checked(); - if adjust_mode { - if hotkey_manager.move_up() != 0 { - settings.persisted.window_dy -= hotkey_manager.move_up() as i32; - window_position_dirty = true; - } - - if hotkey_manager.move_down() != 0 { - settings.persisted.window_dy += hotkey_manager.move_down() as i32; - window_position_dirty = true; - } - - if hotkey_manager.move_left() != 0 { - settings.persisted.window_dx -= hotkey_manager.move_left() as i32; - window_position_dirty = true; - } - - if hotkey_manager.move_right() != 0 { - settings.persisted.window_dx += hotkey_manager.move_right() as i32; - window_position_dirty = true; - } - - if hotkey_manager.cycle_monitor() { - settings.monitor_index = (settings.monitor_index + 1) % window.available_monitors().count(); - window_scale_dirty = true; - } - - if settings.is_scalable() && hotkey_manager.scale_increase() != 0 { - settings.persisted.window_height += hotkey_manager.scale_increase(); - settings.persisted.window_width = settings.persisted.window_height; - window_scale_dirty = true; - } - - if settings.is_scalable() && hotkey_manager.scale_decrease() != 0 { - settings.persisted.window_height = settings.persisted.window_height.checked_sub(hotkey_manager.scale_decrease()).unwrap_or(1).max(1); - settings.persisted.window_width = settings.persisted.window_height; - window_scale_dirty = true; - } - - // adjust button is already checked - if hotkey_manager.toggle_adjust() { - menu_items.adjust_button.set_checked(false) - } - } else if hotkey_manager.toggle_adjust() { - // adjust button is NOT checked - menu_items.adjust_button.set_checked(true) - } - - if hotkey_manager.toggle_hidden() { - window_visible = !window_visible; - window.set_visible(window_visible); - if !window_visible { - menu_items.adjust_button.set_checked(false) - } - } - - // only enable this hotkey if the color picker is already visible OR if adjust mode is on - if hotkey_manager.toggle_color_picker() && (adjust_mode || settings.get_pick_color()) { - let color_pick = settings.toggle_pick_color(); - menu_items.color_pick_button.set_checked(color_pick); - handle_color_pick(color_pick, &window, &mut last_focused_window, true); - window_scale_dirty = true; - } - } - Event::WindowEvent { event: WindowEvent::Moved(position), .. } => { - // incredibly, if the taskbar is at the top or left of the screen Windows will - // (un)helpfully shift the window over by the taskbar's size. I have no idea why - // this happens and it's terrible, but luckily Windows tells me it's done this so - // that I can immediately detect and undo it. - debug_println!("window position changed to {:?}", position); - settings.validate_window_position(&window, position); - } - Event::WindowEvent { event: WindowEvent::Resized(size), .. } => { - // See above nightmare scenario with the window position. I figure I might as well - // do the same thing for size just in case Windows also has some arcane, evil - // involuntary resizing behavior. - debug_println!("window size changed to {:?}", size); - settings.validate_window_size(&window, size); - } - Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, .. } => { - last_mouse_position = position; - } - Event::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. }, .. } => { - let PhysicalPosition { x, y } = last_mouse_position; - let x = x as usize; - let y = y as usize; - - let PhysicalSize { width, height } = settings.size(); - let width = width as usize; - let height = height as usize; - - settings.set_color(image::hue_alpha_color_from_coordinates(x, y, width, height)); - menu_items.color_pick_button.set_checked(false); - handle_color_pick(false, &window, &mut last_focused_window, false); - window_scale_dirty = true; - } - _ => () - } - - if let Ok(path) = dialog_worker.try_recv_file_path() { - menu_items.image_pick_button.set_enabled(true); - - if let Some(path) = path { - match settings.load_png(path) { - Ok(()) => { - force_redraw = true; - window_scale_dirty = true; - } - Err(e) => dialog::show_warning(format!("Error loading PNG.\n\n{}", e)) - } - } - } - - while let Ok(event) = menu_channel.try_recv() { - match event.id { - id if id == menu_items.exit_button.id() => { - // drop the tray icon, solving the funny Windows issue where it lingers after application close - #[cfg(not(target_os = "linux"))] tray_icon.take(); - window.set_visible(false); - if let Err(e) = settings.save() { - dialog::show_warning(format!("Error saving settings to \"{}\".\n\n{}", CONFIG_PATH.display(), e)); - } - - // kill the dialog worker and wait for it to finish - // this makes the application remain open until the user has clicked through any queued dialogs - dialog_worker.shutdown().expect("failed to shut down dialog worker"); - - window_target.exit(); - break; - } - id if id == menu_items.visible_button.id() => { - window.set_visible(menu_items.visible_button.is_checked()); - } - id if id == menu_items.reset_button.id() => { - settings.reset(); - force_redraw = true; - window_scale_dirty = true; - } - id if id == menu_items.color_pick_button.id() => { - let pick_color = menu_items.color_pick_button.is_checked(); - settings.set_pick_color(pick_color); - handle_color_pick(pick_color, &window, &mut last_focused_window, false); - window_scale_dirty = true; - } - id if id == menu_items.image_pick_button.id() => { - menu_items.image_pick_button.set_enabled(false); - dialog::request_png(); - } - id if id == menu_items.about_button.id() => { - dialog::show_info(format!("{}\nversion {} {}", build_constants::APPLICATION_NAME, env!("CARGO_PKG_VERSION"), env!("GIT_COMMIT_HASH"))); - } - _ => (), - } - } - - if window_scale_dirty { - on_window_size_or_position_change(&window, &mut settings); - } else if window_position_dirty { - on_window_position_change(&window, &mut settings); - } - }).unwrap(); + }).unwrap(); // if we fail to spawn a thread something is super wrong and we ought to panic } /// Updates the window state after entering or exiting color picker mode @@ -368,7 +80,7 @@ fn handle_color_pick(color_pick: bool, window: &Window, last_focused_window: &mu // make sure we don't have some weird old window handle saved if we shouldn't be saving focus None }; - window.set_cursor_hittest(true).unwrap(); + window.set_cursor_hittest(true).unwrap(); // fails on non Windows/Mac/Linux platforms window.focus_window(); window.set_cursor_grab(CursorGrabMode::Confined).unwrap(); // if we do this after the window is focused, it'll move the cursor to the window for us. } else { @@ -380,205 +92,3 @@ fn handle_color_pick(color_pick: bool, window: &Window, last_focused_window: &mu } } } - -/// Handles both window size and position change side effects. -fn on_window_size_or_position_change(window: &Window, settings: &mut Settings) { - settings.set_window_size(window); - settings.set_window_position(window); - window.request_redraw(); // needed in case the window size didn't change but the image was replaced - - /* - TODO: scaling jitter problem - When the application is scaled really quickly via key-repeat spam it struggles to scale, move, and redraw the window in perfect sync. - To fix this I'd have to completely rearchitect how scaling works. Ideas: - 1. Temporarily size the window to full screen, thereby eliminating all but the redraws - 2. Stop relying on key repeat and instead remember key state and use ticks for your update intervals - */ -} - -/// Slightly cheaper special case that can only handle window position changes. Do not use this if the window size may have changed. -fn on_window_position_change(window: &Window, settings: &mut Settings) { - settings.set_window_position(window); -} - -/// Draws a crosshair image, or a simple red crosshair if no image is set. Normally this only -/// redraws the buffer if it's uninitialized, but redraw can be forced by setting the `force` -/// parameter to `true`. -fn draw_window(surface: &mut Surface, Rc>, settings: &Settings, force: bool) { - let PhysicalSize { width: window_width, height: window_height } = settings.size(); - surface.resize( - NonZeroU32::new(window_width).unwrap(), - NonZeroU32::new(window_height).unwrap(), - ).unwrap(); - - let width = window_width as usize; - let height = window_height as usize; - - let mut buffer = surface.buffer_mut().unwrap(); - - if force || buffer.age() == 0 { // only redraw if the buffer is uninitialized OR redraw is being forced - match settings.render_mode { - RenderMode::Image => { - // draw our image - buffer.copy_from_slice(settings.image().unwrap().data.as_slice()); - } - RenderMode::Crosshair => { - // draw a generated crosshair - - const FULL_ALPHA: u32 = 0x00000000; - - if width <= 2 || height <= 2 { - // edge case where there simply aren't enough pixels to draw a crosshair, so we just fall back to a dot - buffer.fill(settings.color); - } else { - // draw a simple crosshair. Think a `+` shape. - buffer.fill(FULL_ALPHA); - - // horizontal line - let start = width * (height / 2); - for x in start..start + width { - buffer[x] = settings.color; - } - - // second horizontal line (if size is even we need this for centering) - if height % 2 == 0 { - let start = start - width; - for x in start..start + width { - buffer[x] = settings.color; - } - } - - // vertical line - for y in 0..height { - buffer[width * y + width / 2] = settings.color; - } - - // second vertical line (if size is even we need this for centering) - if width % 2 == 0 { - for y in 0..height { - buffer[width * y + width / 2 - 1] = settings.color; - } - } - } - } - RenderMode::ColorPicker => { - image::draw_color_picker(&mut buffer); - } - } - } - - buffer.present().unwrap(); -} - -/// Load a tray icon graphic. -fn get_icon() -> TrayIcon { - // simply grab the static byte array that's embedded in the application, which was generated in build.rs - TrayIcon::from_rgba(include_bytes!(env!("TRAY_ICON_PATH")).to_vec(), build_constants::TRAY_ICON_DIMENSION, build_constants::TRAY_ICON_DIMENSION).unwrap() -} - -/// Initialize the window. This gives a transparent, borderless window that's always on top and can be clicked through. -fn init_window(event_loop: &EventLoop<()>, settings: &mut Settings) -> Window { - let window_builder = WindowBuilder::new() - .with_visible(false) // things get very buggy on Windows if you default the window to invisible... - .with_transparent(true) - .with_decorations(false) - .with_resizable(false) - .with_title("Simple Crosshair Overlay") - .with_position(PhysicalPosition::new(0, 0)) // can't determine monitor size until the window is created, so just use some dummy values - .with_inner_size(PhysicalSize::new(1, 1)) // this might flicker so make it very tiny - .with_active(false); - - #[cfg(target_os = "windows")] let window_builder = { - use winit::platform::windows::WindowBuilderExtWindows; - window_builder - .with_drag_and_drop(false) - .with_skip_taskbar(true) - }; - - let window = window_builder.build(event_loop) - .unwrap(); - - // contrary to all my expectations this call appears to work reliably - settings.set_window_position(&window); - - // this call is very fragile (read: shit) and sometimes simply doesn't do anything. - // There's a fallback call up in the event loop that saves us when this fails. - settings.set_window_size(&window); - - // once the window is ready, show it - window.set_visible(true); - - // set these weirder settings AFTER the window is visible to avoid even more buggy Windows behavior - // Windows particularly hates if you unset cursor_hittest while the window is hidden - window.set_cursor_hittest(false).unwrap(); - window.set_window_level(WindowLevel::AlwaysOnTop); - window.set_cursor_icon(CursorIcon::Crosshair); // Yo Dawg, I herd you like crosshairs so I put a crosshair in your crosshair so you can aim while you aim. - - window -} - -/// Contains the menu items in our tray menu -#[derive(Clone)] -struct MenuItems { - visible_button: CheckMenuItem, - adjust_button: CheckMenuItem, - color_pick_button: CheckMenuItem, - image_pick_button: MenuItem, - reset_button: MenuItem, - about_button: MenuItem, - exit_button: MenuItem, -} - -impl Default for MenuItems { - fn default() -> Self { - let visible_button = CheckMenuItem::new("Visible", true, true, None); - let adjust_button = CheckMenuItem::new("Adjust", true, false, None); - let color_pick_button = CheckMenuItem::new("Pick Color", true, false, None); - let image_pick_button = MenuItem::new("Load Image", true, None); - let reset_button = MenuItem::new("Reset Overlay", true, None); - let about_button = MenuItem::new("About", true, None); - let exit_button = MenuItem::new("Exit", true, None); - - MenuItems { - visible_button, - adjust_button, - color_pick_button, - image_pick_button, - reset_button, - about_button, - exit_button, - } - } -} - -impl MenuItems { - /// Append all the menu items into the provided `menu`. - fn add_to_menu(&self, menu: &T) where T: AppendableMenu { - menu.append(&self.visible_button).unwrap(); - menu.append(&self.adjust_button).unwrap(); - menu.append(&self.color_pick_button).unwrap(); - menu.append(&self.image_pick_button).unwrap(); - menu.append(&self.reset_button).unwrap(); - menu.append(&self.about_button).unwrap(); - menu.append(&self.exit_button).unwrap(); - } -} - -/// Surprisingly tray-icon doesn't provide a trait for the Menu.append() behavior several structs -/// have, so I have to build it myself for the structs I'm actually using. -trait AppendableMenu { - /// Add a menu item to the end of this menu. - fn append(&self, item: &dyn IsMenuItem) -> MenuResult<()>; -} - -impl AppendableMenu for Menu { - fn append(&self, item: &dyn IsMenuItem) -> MenuResult<()> { - self.append(item) - } -} - -impl AppendableMenu for Submenu { - fn append(&self, item: &dyn IsMenuItem) -> MenuResult<()> { - self.append(item) - } -} diff --git a/src/tray.rs b/src/tray.rs new file mode 100644 index 0000000..52b4110 --- /dev/null +++ b/src/tray.rs @@ -0,0 +1,174 @@ +// This file is part of simple-crosshair-overlay and is licenced under the GNU GPL v3.0. +// See LICENSE file for full text. +// Copyright © 2023-2024 Michael Ripley + +#[cfg(target_os = "linux")] +use debug_print::debug_println; +use tray_icon::{menu::Menu, TrayIcon, TrayIconBuilder}; +use tray_icon::menu::{CheckMenuItem, IsMenuItem, MenuItem, Result as MenuResult, Submenu}; + +use crate::{build_constants, ICON_TOOLTIP}; + +pub fn build_tray_icon() -> (MenuItems, TrayIcon) { + // on linux we have to do this in a completely different way + #[cfg(not(target_os = "linux"))] let tray_menu = Menu::new(); + + let menu_items = MenuItems::default(); + + // windows: do not use a submenu + #[cfg(target_os = "windows")] { + menu_items.add_to_menu(&tray_menu); + } + + // mac: there are special submenu requirements + #[cfg(target_os = "macos")] { + // on mac all menu items must be in a submenu, so just make one with no name. Hope that doesn't cause problems... + let submenu = tray_icon::menu::Submenu::new("", true); + tray_menu.append(&submenu).unwrap(); + menu_items.add_to_menu(&submenu); + } + + // on Linux this MUST be called on the GTK thread, so we have to do some weird hijinks to pass things around + #[cfg(not(target_os = "linux"))] let tray_icon: TrayIcon = { + let tray_icon_builder = TrayIconBuilder::new() + .with_menu(Box::new(tray_menu)) + .with_tooltip(ICON_TOOLTIP) + .with_icon(get_icon()); + tray_icon_builder.build().unwrap() + }; + + #[cfg(target_os = "linux")] { + use std::sync::{Arc, Condvar, Mutex}; + use std::time::Duration; + + let condvar_pair = Arc::new((Mutex::new(false), Condvar::new())); + + // start GTK background thread + let condvar_pair_clone = condvar_pair.clone(); + std::thread::Builder::new() + .name("gtk-main".to_string()) + .spawn(move || { + debug_println!("starting GTK background thread"); + gtk::init().unwrap(); + debug_println!("GTK init complete"); + + // initialize the tray icon + let tray_menu = Menu::new(); + menu_items.add_to_menu(&tray_menu); + + let tray_icon_builder = TrayIconBuilder::new() + .with_menu(Box::new(tray_menu)) + .with_tooltip(ICON_TOOLTIP) + .with_icon(get_icon()); + let mut tray_icon = Some(tray_icon_builder.build().unwrap()); + + // signal that GTK init is complete + { + let (lock, condvar) = &*condvar_pair_clone; + let mut gtk_started = lock.lock().unwrap(); + *gtk_started = true; + condvar.notify_one(); + } // this block is actually necessary so that the lock gets released! + + debug_println!("GTK init signal sent. Starting GTK main loop."); + loop { + gtk::main_iteration_do(false); + //TODO: channel MenuItem state around? + std::thread::yield_now(); + } + debug_println!("GTK main loop returned!? Weird."); + }).unwrap(); + debug_println!("spawned GTK background thread"); + + // wait for GTK to init + let (lock, condvar) = &*condvar_pair; + let gtk_started = lock.lock().unwrap(); + debug_println!("acquired GTK lock"); + if !*gtk_started { + debug_println!("waiting for GTK init signal"); + let (gtk_started, timeout_result) = condvar.wait_timeout(gtk_started, Duration::from_secs(5)).unwrap(); + if !*gtk_started { + panic!("GTK startup timed out = {}", timeout_result.timed_out()); + } + } + + debug_println!("GTK startup complete"); + } + + (menu_items, tray_icon) +} + +/// Load a tray icon graphic. +fn get_icon() -> tray_icon::Icon { + // simply grab the static byte array that's embedded in the application, which was generated in build.rs + tray_icon::Icon::from_rgba(include_bytes!(env!("TRAY_ICON_PATH")).to_vec(), build_constants::TRAY_ICON_DIMENSION, build_constants::TRAY_ICON_DIMENSION).unwrap() +} + +/// Contains the menu items in our tray menu +#[derive(Clone)] +pub struct MenuItems { + pub visible_button: CheckMenuItem, + pub adjust_button: CheckMenuItem, + pub color_pick_button: CheckMenuItem, + pub image_pick_button: MenuItem, + pub reset_button: MenuItem, + pub about_button: MenuItem, + pub exit_button: MenuItem, +} + +impl Default for MenuItems { + fn default() -> Self { + let visible_button = CheckMenuItem::new("Visible", true, true, None); + let adjust_button = CheckMenuItem::new("Adjust", true, false, None); + let color_pick_button = CheckMenuItem::new("Pick Color", true, false, None); + let image_pick_button = MenuItem::new("Load Image", true, None); + let reset_button = MenuItem::new("Reset Overlay", true, None); + let about_button = MenuItem::new("About", true, None); + let exit_button = MenuItem::new("Exit", true, None); + + MenuItems { + visible_button, + adjust_button, + color_pick_button, + image_pick_button, + reset_button, + about_button, + exit_button, + } + } +} + +impl MenuItems { + /// Append all the menu items into the provided `menu`. + fn add_to_menu(&self, menu: &T) + where + T: AppendableMenu, + { + menu.append(&self.visible_button).unwrap(); + menu.append(&self.adjust_button).unwrap(); + menu.append(&self.color_pick_button).unwrap(); + menu.append(&self.image_pick_button).unwrap(); + menu.append(&self.reset_button).unwrap(); + menu.append(&self.about_button).unwrap(); + menu.append(&self.exit_button).unwrap(); + } +} + +/// Surprisingly tray-icon doesn't provide a trait for the Menu.append() behavior several structs +/// have, so I have to build it myself for the structs I'm actually using. +trait AppendableMenu { + /// Add a menu item to the end of this menu. + fn append(&self, item: &dyn IsMenuItem) -> MenuResult<()>; +} + +impl AppendableMenu for Menu { + fn append(&self, item: &dyn IsMenuItem) -> MenuResult<()> { + self.append(item) + } +} + +impl AppendableMenu for Submenu { + fn append(&self, item: &dyn IsMenuItem) -> MenuResult<()> { + self.append(item) + } +} diff --git a/src/window.rs b/src/window.rs new file mode 100644 index 0000000..23b1967 --- /dev/null +++ b/src/window.rs @@ -0,0 +1,443 @@ +// This file is part of simple-crosshair-overlay and is licenced under the GNU GPL v3.0. +// See LICENSE file for full text. +// Copyright © 2023-2024 Michael Ripley + +use std::num::NonZeroU32; +use std::rc::Rc; + +use debug_print::debug_println; +use tray_icon::dpi::{PhysicalPosition, PhysicalSize}; +use tray_icon::menu::{MenuEvent, MenuEventReceiver}; +use tray_icon::TrayIcon; +use winit::application::ApplicationHandler; +use winit::event::{DeviceEvent, DeviceId, ElementState, MouseButton, StartCause, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, EventLoop}; +use winit::window::{CursorIcon, Window, WindowId, WindowLevel}; + +use simple_crosshair_overlay::platform; +use simple_crosshair_overlay::platform::HotkeyManager; +use simple_crosshair_overlay::settings::{CONFIG_PATH, RenderMode, Settings}; +use simple_crosshair_overlay::util::{dialog, image}; +use simple_crosshair_overlay::util::dialog::DialogWorker; + +use crate::{build_constants, handle_color_pick, tray}; +use crate::tray::MenuItems; + +pub type UserEvent = (); +type Surface = softbuffer::Surface, Rc>; + +pub struct State<'a> { + context: Option, + settings: Settings, + hotkey_manager: HotkeyManager, + /// native dialogs block a thread, so we'll spin up a single thread to loop through queued dialogs. + /// If we ever need to show multiple dialogs, they just get queued. + dialog_worker: DialogWorker, + /// we keep the tray icon in an Option so that we can take() it later to drop + tray_icon: Option, + menu_items: MenuItems, + last_focused_window: Option, + last_mouse_position: PhysicalPosition, + menu_channel: &'a MenuEventReceiver, + /// if set to true, the next redraw will be forced even for known buffer contents + force_redraw: bool, + window_position_dirty: bool, + window_scale_dirty: bool, + window_visible: bool, +} + +/// Window context +struct Context { + window: Rc, + surface: Surface, +} + +impl Context { + fn new(active_event_loop: &ActiveEventLoop, settings: &mut Settings) -> Self { + // unsafe note: these three structs MUST live and die together. + // It is highly illegal to use the context or surface after the window is dropped. + // The context only gets used right here, so that's fine. + // As of this writing, none of these get moved out of this struct. Therefore, they all get dropped at the same time, which is safe. + let window = Rc::new(init_window(active_event_loop, settings)); + let context = softbuffer::Context::new(window.clone()).unwrap(); + let surface: Surface = Surface::new(&context, window.clone()).unwrap(); + Context { + window, + surface, + } + } +} + +impl<'a> State<'a> { + pub fn new(settings: Settings, _event_loop: &EventLoop) -> Self { + // HotkeyManager has a decent quantity of data in it, but again it never really gets moved so we can just leave it on the stack + let hotkey_manager: HotkeyManager = HotkeyManager::new(&settings.persisted.key_bindings).unwrap_or_else(|e| { + dialog::show_warning(format!("{e}\n\nUsing default hotkeys.")); + HotkeyManager::default() + }); + + let (menu_items, tray_icon) = tray::build_tray_icon(); + State { + context: None, + settings, + hotkey_manager, + dialog_worker: dialog::spawn_worker(), + tray_icon: Some(tray_icon), + menu_items, + last_focused_window: None, + last_mouse_position: Default::default(), + menu_channel: MenuEvent::receiver(), + force_redraw: false, + window_position_dirty: false, + window_scale_dirty: false, + window_visible: true, + } + } + + fn post_event_work(&mut self, active_event_loop: &ActiveEventLoop) { + let window: &Window = &self.context.as_ref().unwrap().window; + + if let Ok(path) = self.dialog_worker.try_recv_file_path() { + self.menu_items.image_pick_button.set_enabled(true); + + if let Some(path) = path { + match self.settings.load_png(path) { + Ok(()) => { + self.force_redraw = true; + self.window_scale_dirty = true; + } + Err(e) => dialog::show_warning(format!("Error loading PNG.\n\n{}", e)) + } + } + } + + while let Ok(event) = self.menu_channel.try_recv() { + match event.id { + id if id == self.menu_items.exit_button.id() => { + // drop the tray icon, solving the funny Windows issue where it lingers after application close + #[cfg(not(target_os = "linux"))] self.tray_icon.take(); + window.set_visible(false); + if let Err(e) = self.settings.save() { + dialog::show_warning(format!("Error saving settings to \"{}\".\n\n{}", CONFIG_PATH.display(), e)); + } + + // kill the dialog worker and wait for it to finish + // this makes the application remain open until the user has clicked through any queued dialogs + self.dialog_worker.shutdown().expect("failed to shut down dialog worker"); + + active_event_loop.exit(); + break; + } + id if id == self.menu_items.visible_button.id() => { + window.set_visible(self.menu_items.visible_button.is_checked()); + } + id if id == self.menu_items.reset_button.id() => { + self.settings.reset(); + self.force_redraw = true; + self.window_scale_dirty = true; + } + id if id == self.menu_items.color_pick_button.id() => { + let pick_color = self.menu_items.color_pick_button.is_checked(); + self.settings.set_pick_color(pick_color); + handle_color_pick(pick_color, window, &mut self.last_focused_window, false); + self.window_scale_dirty = true; + } + id if id == self.menu_items.image_pick_button.id() => { + self.menu_items.image_pick_button.set_enabled(false); + dialog::request_png(); + } + id if id == self.menu_items.about_button.id() => { + dialog::show_info(format!("{}\nversion {} {}", build_constants::APPLICATION_NAME, env!("CARGO_PKG_VERSION"), env!("GIT_COMMIT_HASH"))); + } + _ => (), + } + } + + if self.window_scale_dirty { + on_window_size_or_position_change(window, &mut self.settings); + self.window_scale_dirty = false; + self.window_position_dirty = false; + } else if self.window_position_dirty { + on_window_position_change(window, &mut self.settings); + self.window_position_dirty = false; + } + } +} + +impl<'a> ApplicationHandler for State<'a> { + fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) { + if matches!(cause, StartCause::Init) { + self.context = Some(Context::new(event_loop, &mut self.settings)) + } + } + + fn resumed(&mut self, _event_loop: &ActiveEventLoop) { + // only used on iOS/Android/Web + } + + fn user_event(&mut self, event_loop: &ActiveEventLoop, _event: UserEvent) { + let window: &Window = &self.context.as_ref().unwrap().window; + + self.hotkey_manager.poll_keys(); + self.hotkey_manager.process_keys(); + + let adjust_mode = self.menu_items.adjust_button.is_checked(); + if adjust_mode { + if self.hotkey_manager.move_up() != 0 { + self.settings.persisted.window_dy -= self.hotkey_manager.move_up() as i32; + self.window_position_dirty = true; + } + + if self.hotkey_manager.move_down() != 0 { + self.settings.persisted.window_dy += self.hotkey_manager.move_down() as i32; + self.window_position_dirty = true; + } + + if self.hotkey_manager.move_left() != 0 { + self.settings.persisted.window_dx -= self.hotkey_manager.move_left() as i32; + self.window_position_dirty = true; + } + + if self.hotkey_manager.move_right() != 0 { + self.settings.persisted.window_dx += self.hotkey_manager.move_right() as i32; + self.window_position_dirty = true; + } + + if self.hotkey_manager.cycle_monitor() { + self.settings.monitor_index = (self.settings.monitor_index + 1) % window.available_monitors().count(); + self.window_scale_dirty = true; + } + + if self.settings.is_scalable() && self.hotkey_manager.scale_increase() != 0 { + self.settings.persisted.window_height += self.hotkey_manager.scale_increase(); + self.settings.persisted.window_width = self.settings.persisted.window_height; + self.window_scale_dirty = true; + } + + if self.settings.is_scalable() && self.hotkey_manager.scale_decrease() != 0 { + self.settings.persisted.window_height = self.settings.persisted.window_height.checked_sub(self.hotkey_manager.scale_decrease()).unwrap_or(1).max(1); + self.settings.persisted.window_width = self.settings.persisted.window_height; + self.window_scale_dirty = true; + } + + // adjust button is already checked + if self.hotkey_manager.toggle_adjust() { + self.menu_items.adjust_button.set_checked(false) + } + } else if self.hotkey_manager.toggle_adjust() { + // adjust button is NOT checked + self.menu_items.adjust_button.set_checked(true) + } + + if self.hotkey_manager.toggle_hidden() { + self.window_visible = !self.window_visible; + window.set_visible(self.window_visible); + if !self.window_visible { + self.menu_items.adjust_button.set_checked(false) + } + } + + // only enable this hotkey if the color picker is already visible OR if adjust mode is on + if self.hotkey_manager.toggle_color_picker() && (adjust_mode || self.settings.get_pick_color()) { + let color_pick = self.settings.toggle_pick_color(); + self.menu_items.color_pick_button.set_checked(color_pick); + handle_color_pick(color_pick, window, &mut self.last_focused_window, true); + self.window_scale_dirty = true; + } + + self.post_event_work(event_loop); + } + + fn window_event(&mut self, event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) { + let context: &mut Context = self.context.as_mut().unwrap(); + + match event { + WindowEvent::RedrawRequested => { + // failsafe to resize the window before a redraw if necessary + // ...and of course it's fucking necessary + self.settings.validate_window_size(&context.window, context.window.inner_size()); + draw_window(&mut context.surface, &self.settings, self.force_redraw); + self.force_redraw = false; + } + WindowEvent::Moved(position) => { + // incredibly, if the taskbar is at the top or left of the screen Windows will + // (un)helpfully shift the window over by the taskbar's size. I have no idea why + // this happens and it's terrible, but luckily Windows tells me it's done this so + // that I can immediately detect and undo it. + debug_println!("window position changed to {:?}", position); + self.settings.validate_window_position(&context.window, position); + } + WindowEvent::Resized(size) => { + // See above nightmare scenario with the window position. I figure I might as well + // do the same thing for size just in case Windows also has some arcane, evil + // involuntary resizing behavior. + debug_println!("window size changed to {:?}", size); + self.settings.validate_window_size(&context.window, size); + } + WindowEvent::CursorMoved { position, .. } => { + self.last_mouse_position = position; + } + WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => { + let PhysicalPosition { x, y } = self.last_mouse_position; + let x = x as usize; + let y = y as usize; + + let PhysicalSize { width, height } = self.settings.size(); + let width = width as usize; + let height = height as usize; + + self.settings.set_color(image::hue_alpha_color_from_coordinates(x, y, width, height)); + self.menu_items.color_pick_button.set_checked(false); + handle_color_pick(false, &context.window, &mut self.last_focused_window, false); + self.window_scale_dirty = true; + } + _ => {} + } + + self.post_event_work(event_loop); + } + + fn device_event(&mut self, _event_loop: &ActiveEventLoop, _device_id: DeviceId, _event: DeviceEvent) {} + + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {} + + fn suspended(&mut self, _event_loop: &ActiveEventLoop) { + // only used on iOS/Android/Web + } + + fn exiting(&mut self, _event_loop: &ActiveEventLoop) {} + + fn memory_warning(&mut self, _event_loop: &ActiveEventLoop) { + // only used on iOS/Android + } +} + +/// Handles both window size and position change side effects. +fn on_window_size_or_position_change(window: &Window, settings: &mut Settings) { + settings.set_window_size(window); + settings.set_window_position(window); + window.request_redraw(); // needed in case the window size didn't change but the image was replaced + + /* + TODO: scaling jitter problem + When the application is scaled really quickly via key-repeat spam it struggles to scale, move, and redraw the window in perfect sync. + To fix this I'd have to completely rearchitect how scaling works. Ideas: + 1. Temporarily size the window to full screen, thereby eliminating all but the redraws + 2. Stop relying on key repeat and instead remember key state and use ticks for your update intervals + */ +} + +/// Slightly cheaper special case that can only handle window position changes. Do not use this if the window size may have changed. +fn on_window_position_change(window: &Window, settings: &mut Settings) { + settings.set_window_position(window); +} + +/// Draws a crosshair image, or a simple red crosshair if no image is set. Normally this only +/// redraws the buffer if it's uninitialized, but redraw can be forced by setting the `force` +/// parameter to `true`. +fn draw_window(surface: &mut Surface, settings: &Settings, force: bool) { + let PhysicalSize { width: window_width, height: window_height } = settings.size(); + surface.resize( + NonZeroU32::new(window_width).unwrap(), + NonZeroU32::new(window_height).unwrap(), + ).unwrap(); + + let width = window_width as usize; + let height = window_height as usize; + + let mut buffer = surface.buffer_mut().unwrap(); + + if force || buffer.age() == 0 { // only redraw if the buffer is uninitialized OR redraw is being forced + match settings.render_mode { + RenderMode::Image => { + // draw our image + buffer.copy_from_slice(settings.image().unwrap().data.as_slice()); + } + RenderMode::Crosshair => { + // draw a generated crosshair + + const FULL_ALPHA: u32 = 0x00000000; + + if width <= 2 || height <= 2 { + // edge case where there simply aren't enough pixels to draw a crosshair, so we just fall back to a dot + buffer.fill(settings.color); + } else { + // draw a simple crosshair. Think a `+` shape. + buffer.fill(FULL_ALPHA); + + // horizontal line + let start = width * (height / 2); + for x in start..start + width { + buffer[x] = settings.color; + } + + // second horizontal line (if size is even we need this for centering) + if height % 2 == 0 { + let start = start - width; + for x in start..start + width { + buffer[x] = settings.color; + } + } + + // vertical line + for y in 0..height { + buffer[width * y + width / 2] = settings.color; + } + + // second vertical line (if size is even we need this for centering) + if width % 2 == 0 { + for y in 0..height { + buffer[width * y + width / 2 - 1] = settings.color; + } + } + } + } + RenderMode::ColorPicker => { + image::draw_color_picker(&mut buffer); + } + } + } + + buffer.present().unwrap(); +} + +/// Initialize the window. This gives a transparent, borderless window that's always on top and can be clicked through. +fn init_window(active_event_loop: &ActiveEventLoop, settings: &mut Settings) -> Window { + let window_attributes = Window::default_attributes() + .with_visible(false) // things get very buggy on Windows if you default the window to invisible... + .with_transparent(true) + .with_decorations(false) + .with_resizable(false) + .with_title("Simple Crosshair Overlay") + .with_position(PhysicalPosition::new(0, 0)) // can't determine monitor size until the window is created, so just use some dummy values + .with_inner_size(PhysicalSize::new(1, 1)) // this might flicker so make it very tiny + .with_active(false); + + #[cfg(target_os = "windows")] let window_attributes = { + use winit::platform::windows::WindowAttributesExtWindows; + window_attributes + .with_drag_and_drop(false) + .with_skip_taskbar(true) + }; + + let window = active_event_loop.create_window(window_attributes) + .unwrap(); + + // contrary to all my expectations this call appears to work reliably + settings.set_window_position(&window); + + // this call is very fragile (read: shit) and sometimes simply doesn't do anything. + // There's a fallback call up in the event loop that saves us when this fails. + settings.set_window_size(&window); + + // once the window is ready, show it + window.set_visible(true); + + // set these weirder settings AFTER the window is visible to avoid even more buggy Windows behavior + // Windows particularly hates if you unset cursor_hittest while the window is hidden + window.set_cursor_hittest(false).unwrap(); + window.set_window_level(WindowLevel::AlwaysOnTop); + window.set_cursor(CursorIcon::Crosshair); // Yo Dawg, I herd you like crosshairs so I put a crosshair in your crosshair so you can aim while you aim. + + window +}