diff --git a/Cargo.lock b/Cargo.lock index aada7dc6..fad67bc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,7 +77,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.9.3", + "bitflags 2.9.4", "cc", "cesu8", "jni", @@ -91,6 +91,15 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "android-build" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cac4c64175d504608cf239756339c07f6384a476f97f20a7043f92920b0b8fd" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "android-properties" version = "0.2.2" @@ -190,47 +199,18 @@ dependencies = [ "libloading", ] -[[package]] -name = "ashpd" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3d60bee1a1d38c2077030f4788e1b4e31058d2e79a8cfc8f2b440bd44db290" -dependencies = [ - "async-fs", - "async-net", - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.8.5", - "serde", - "serde_repr", - "url", - "zbus", -] - [[package]] name = "async-broadcast" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "futures-core", "pin-project-lite", ] -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - [[package]] name = "async-channel" version = "2.5.0" @@ -268,21 +248,6 @@ dependencies = [ "futures-lite", ] -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.5.0", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - [[package]] name = "async-io" version = "2.5.0" @@ -307,7 +272,7 @@ version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] @@ -329,14 +294,14 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-io", "async-lock", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener 5.4.1", + "event-listener", "futures-lite", "rustix 1.0.8", ] @@ -370,32 +335,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "async-std" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - [[package]] name = "async-task" version = "4.7.1" @@ -569,9 +508,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.3" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ "serde", ] @@ -606,13 +545,22 @@ dependencies = [ "objc2 0.5.2", ] +[[package]] +name = "block2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" +dependencies = [ + "objc2 0.6.2", +] + [[package]] name = "blocking" version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-task", "futures-io", "futures-lite", @@ -703,7 +651,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "log", "polling", "rustix 0.38.44", @@ -742,10 +690,11 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.34" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -811,7 +760,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -843,18 +792,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" dependencies = [ "anstyle", "clap_lex", @@ -882,7 +831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f" dependencies = [ "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", ] @@ -1030,7 +979,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "core-foundation 0.10.1", "core-graphics-types 0.2.0", "foreign-types 0.5.0", @@ -1054,7 +1003,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "core-foundation 0.10.1", "libc", ] @@ -1065,7 +1014,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da46a9d5a8905cc538a4a5bceb6a4510de7a51049c5588c0114efce102bcbbe8" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "fontdb 0.16.2", "log", "rangemap", @@ -1234,20 +1183,6 @@ dependencies = [ "iced", ] -[[package]] -name = "dark-light" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e1a09f280e29a8b00bc7e81eca5ac87dca0575639c9422a5fa25a07bb884b8" -dependencies = [ - "ashpd", - "async-std", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "web-sys", - "winreg", -] - [[package]] name = "data-encoding" version = "2.9.0" @@ -1262,9 +1197,9 @@ checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", ] @@ -1297,7 +1232,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -1306,6 +1241,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1360,7 +1305,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytemuck", "drm-ffi", "drm-fourcc", @@ -1505,12 +1450,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "event-listener" version = "5.4.1" @@ -1528,7 +1467,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener", "pin-project-lite", ] @@ -1573,6 +1512,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -1589,6 +1548,12 @@ dependencies = [ "iced", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "flate2" version = "1.1.2" @@ -1936,7 +1901,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasi 0.14.4+wasi-0.2.4", ] [[package]] @@ -1998,18 +1963,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "glow" version = "0.16.0" @@ -2048,7 +2001,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "gpu-alloc-types", ] @@ -2058,7 +2011,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", ] [[package]] @@ -2079,7 +2032,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "gpu-descriptor-types", "hashbrown", ] @@ -2090,7 +2043,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", ] [[package]] @@ -2474,9 +2427,8 @@ dependencies = [ name = "iced_core" version = "0.14.0-dev" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytes", - "dark-light", "glam", "lilt", "log", @@ -2527,7 +2479,7 @@ dependencies = [ name = "iced_graphics" version = "0.14.0-dev" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytemuck", "cosmic-text", "half", @@ -2589,7 +2541,7 @@ version = "0.14.0-dev" dependencies = [ "iced_renderer", "iced_runtime", - "png", + "png 0.18.0", "sha2", "thiserror 1.0.69", ] @@ -2614,7 +2566,7 @@ dependencies = [ name = "iced_wgpu" version = "0.14.0-dev" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytemuck", "cryoglyph", "futures", @@ -2655,6 +2607,7 @@ dependencies = [ "iced_debug", "iced_program", "log", + "mundy", "rustc-hash 2.1.1", "sysinfo", "thiserror 1.0.69", @@ -2774,9 +2727,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.6" +version = "0.25.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" dependencies = [ "bytemuck", "byteorder-lite", @@ -2784,8 +2737,9 @@ dependencies = [ "exr", "gif", "image-webp", + "moxcms", "num-traits", - "png", + "png 0.18.0", "qoi", "ravif", "rayon", @@ -2859,7 +2813,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "libc", ] @@ -2974,9 +2928,9 @@ checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -3029,15 +2983,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "layout" version = "0.1.0" @@ -3060,9 +3005,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lebe" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" @@ -3102,7 +3047,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "libc", "redox_syscall 0.5.17", ] @@ -3172,12 +3117,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -dependencies = [ - "value-bag", -] +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "loop9" @@ -3300,11 +3242,11 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memfd" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "rustix 0.38.44", + "rustix 1.0.8", ] [[package]] @@ -3331,7 +3273,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "block", "core-graphics-types 0.2.0", "foreign-types 0.5.0", @@ -3390,6 +3332,16 @@ dependencies = [ "iced", ] +[[package]] +name = "moxcms" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "multer" version = "2.1.0" @@ -3424,6 +3376,31 @@ dependencies = [ "voronator", ] +[[package]] +name = "mundy" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f507e52285e981a349f7224e0ac7eaf014e1a9cce399471547c8dfbc018b79" +dependencies = [ + "android-build", + "async-io", + "cfg-if", + "dispatch", + "futures-channel", + "futures-lite", + "jni", + "ndk-context", + "objc2 0.6.2", + "objc2-app-kit 0.3.1", + "objc2-foundation 0.3.1", + "pin-project-lite", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.61.3", + "zbus", +] + [[package]] name = "mutate_once" version = "0.1.2" @@ -3438,7 +3415,7 @@ checksum = "916cbc7cb27db60be930a4e2da243cf4bc39569195f22fd8ee419cd31d5b662c" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -3479,7 +3456,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "jni-sys", "log", "ndk-sys", @@ -3515,7 +3492,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -3696,14 +3673,33 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "libc", "objc2 0.5.2", - "objc2-core-data", - "objc2-core-image", + "objc2-core-data 0.2.2", + "objc2-core-image 0.2.2", "objc2-foundation 0.2.2", - "objc2-quartz-core", + "objc2-quartz-core 0.2.2", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +dependencies = [ + "bitflags 2.9.4", + "block2 0.6.1", + "libc", + "objc2 0.6.2", + "objc2-cloud-kit 0.3.1", + "objc2-core-data 0.3.1", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image 0.3.1", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.1", ] [[package]] @@ -3712,20 +3708,31 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-cloud-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + [[package]] name = "objc2-contacts" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3736,31 +3743,76 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-core-data" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2 0.6.2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2 0.6.2", + "objc2-core-foundation", + "objc2-io-surface", +] + [[package]] name = "objc2-core-image" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", "objc2-metal", ] +[[package]] +name = "objc2-core-image" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" +dependencies = [ + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + [[package]] name = "objc2-core-location" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-contacts", "objc2-foundation 0.2.2", @@ -3778,8 +3830,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "dispatch", "libc", "objc2 0.5.2", @@ -3791,8 +3843,22 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", + "block2 0.6.1", + "libc", "objc2 0.6.2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-core-foundation", ] [[package]] @@ -3801,9 +3867,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", ] @@ -3813,8 +3879,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3825,13 +3891,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", "objc2-metal", ] +[[package]] +name = "objc2-quartz-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + [[package]] name = "objc2-symbols" version = "0.2.2" @@ -3848,16 +3925,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "objc2 0.5.2", - "objc2-cloud-kit", - "objc2-core-data", - "objc2-core-image", + "objc2-cloud-kit 0.2.2", + "objc2-core-data 0.2.2", + "objc2-core-image 0.2.2", "objc2-core-location", "objc2-foundation 0.2.2", "objc2-link-presentation", - "objc2-quartz-core", + "objc2-quartz-core 0.2.2", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -3869,7 +3946,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3880,8 +3957,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", @@ -3917,7 +3994,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "libc", "once_cell", "onig_sys", @@ -3956,7 +4033,7 @@ version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "foreign-types 0.3.2", "libc", @@ -4309,6 +4386,19 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "png" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags 2.9.4", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "pokedex" version = "0.1.0" @@ -4443,7 +4533,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "getopts", "memchr", "pulldown-cmark-escape", @@ -4456,6 +4546,15 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" +[[package]] +name = "pxfm" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55f4fedc84ed39cb7a489322318976425e42a147e2be79d8f878e2884f94e84" +dependencies = [ + "num-traits", +] + [[package]] name = "qoi" version = "0.4.1" @@ -4695,7 +4794,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", ] [[package]] @@ -4879,7 +4978,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.4.15", @@ -4892,7 +4991,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.9.4", @@ -4969,7 +5068,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytemuck", "libm", "smallvec", @@ -5052,7 +5151,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5061,9 +5160,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -5286,7 +5385,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "calloop", "calloop-wayland-source", "cursor-icon", @@ -5322,7 +5421,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-executor", "async-fs", "async-io", @@ -5380,7 +5479,7 @@ dependencies = [ "memmap2", "objc2 0.5.2", "objc2-foundation 0.2.2", - "objc2-quartz-core", + "objc2-quartz-core 0.2.2", "raw-window-handle 0.6.2", "redox_syscall 0.5.17", "rustix 0.38.44", @@ -5415,7 +5514,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", ] [[package]] @@ -5605,7 +5704,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -5736,23 +5835,25 @@ dependencies = [ [[package]] name = "tiff" -version = "0.9.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" dependencies = [ + "fax", "flate2", - "jpeg-decoder", + "half", + "quick-error", "weezl", + "zune-jpeg", ] [[package]] name = "time" -version = "0.3.41" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde", @@ -5762,15 +5863,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -5787,7 +5888,7 @@ dependencies = [ "bytemuck", "cfg-if", "log", - "png", + "png 0.17.16", "tiny-skia-path", ] @@ -6032,7 +6133,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytes", "futures-util", "http 1.3.1", @@ -6314,9 +6415,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.18.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -6342,12 +6443,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "value-bag" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" - [[package]] name = "vcpkg" version = "0.2.15" @@ -6451,30 +6546,31 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.3+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -6486,9 +6582,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -6499,9 +6595,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6509,9 +6605,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -6522,9 +6618,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] @@ -6544,9 +6640,9 @@ dependencies = [ [[package]] name = "wasmtimer" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8d49b5d6c64e8558d9b1b065014426f35c18de636895d24893dbbd329743446" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" dependencies = [ "futures", "js-sys", @@ -6576,7 +6672,7 @@ version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "rustix 1.0.8", "wayland-backend", "wayland-scanner", @@ -6588,7 +6684,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "cursor-icon", "wayland-backend", ] @@ -6610,7 +6706,7 @@ version = "0.32.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "wayland-backend", "wayland-client", "wayland-scanner", @@ -6622,7 +6718,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6635,7 +6731,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6667,9 +6763,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -6742,7 +6838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70b6ff82bbf6e9206828e1a3178e851f8c20f1c9028e74dd3a8090741ccd5798" dependencies = [ "arrayvec", - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "document-features", @@ -6773,7 +6869,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg_aliases", "document-features", "hashbrown", @@ -6842,7 +6938,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.9.3", + "bitflags 2.9.4", "block", "bytemuck", "cfg-if", @@ -6886,7 +6982,7 @@ version = "26.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eca7a8d8af57c18f57d393601a1fb159ace8b2328f1b6b5f80893f7d672c9ae2" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytemuck", "js-sys", "log", @@ -6912,11 +7008,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -6959,6 +7055,28 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + [[package]] name = "windows-core" version = "0.57.0" @@ -6992,11 +7110,22 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement 0.60.0", "windows-interface 0.59.1", - "windows-link", + "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings 0.4.2", ] +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.57.0" @@ -7069,13 +7198,29 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + [[package]] name = "windows-registry" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings 0.4.2", ] @@ -7104,7 +7249,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -7123,7 +7268,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -7171,6 +7316,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -7223,7 +7377,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -7234,6 +7388,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -7422,8 +7585,8 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.9.3", - "block2", + "bitflags 2.9.4", + "block2 0.5.1", "bytemuck", "calloop", "cfg_aliases", @@ -7437,7 +7600,7 @@ dependencies = [ "memmap2", "ndk", "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", @@ -7474,21 +7637,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "writeable" @@ -7540,7 +7693,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "dlib", "log", "once_cell", @@ -7626,7 +7779,7 @@ dependencies = [ "async-trait", "blocking", "enumflags2", - "event-listener 5.4.1", + "event-listener", "futures-core", "futures-lite", "hex", @@ -7678,18 +7831,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -7773,9 +7926,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core", ] @@ -7789,7 +7942,6 @@ dependencies = [ "endi", "enumflags2", "serde", - "url", "winnow", "zvariant_derive", "zvariant_utils", diff --git a/Cargo.toml b/Cargo.toml index a3ae52c6..a92f7778 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ all-features = true maintenance = { status = "actively-developed" } [features] -default = ["wgpu", "tiny-skia", "crisp", "web-colors", "auto-detect-theme", "thread-pool"] +default = ["wgpu", "tiny-skia", "crisp", "web-colors", "thread-pool", "linux-theme-detection"] # Enables the `wgpu` GPU-accelerated renderer backend wgpu = ["iced_renderer/wgpu", "iced_widget/wgpu"] # Enables the `tiny-skia` software renderer backend @@ -54,21 +54,19 @@ tokio = ["iced_futures/tokio"] # Enables `smol` as the `executor::Default` on native platforms smol = ["iced_futures/smol"] # Enables querying system information -system = ["iced_winit/system"] +sysinfo = ["iced_winit/sysinfo"] # Enables broken "sRGB linear" blending to reproduce color management of the Web web-colors = ["iced_renderer/web-colors"] # Enables pixel snapping for crisp edges by default (can cause jitter!) crisp = ["iced_core/crisp", "iced_widget/crisp"] # Enables the WebGL backend webgl = ["iced_renderer/webgl"] -# Enables syntax highligthing +# Enables syntax highlighting highlighter = ["iced_highlighter", "iced_widget/highlighter"] # Enables the advanced module advanced = ["iced_core/advanced", "iced_widget/advanced"] # Embeds Fira Sans into the final application; useful for testing and Wasm builds fira-sans = ["iced_renderer/fira-sans"] -# Auto-detects light/dark mode for the built-in theme -auto-detect-theme = ["iced_core/auto-detect-theme"] # Enables basic text shaping by default basic-shaping = ["iced_core/basic-shaping"] # Enables advanced text shaping by default @@ -79,6 +77,8 @@ strict-assertions = ["iced_renderer/strict-assertions"] unconditional-rendering = ["iced_winit/unconditional-rendering"] # Enables support for the `sipper` library sipper = ["iced_runtime/sipper"] +# Enables Linux system theme detection +linux-theme-detection = ["iced_winit/linux-theme-detection"] [dependencies] iced_debug.workspace = true @@ -175,10 +175,9 @@ bytemuck = { version = "1.0", features = ["derive"] } bytes = "1.6" cargo-hot = { package = "cargo-hot-protocol", git = "https://github.com/hecrj/cargo-hot.git", rev = "b8dc518b8640928178a501257e353b73bc06cf47" } cosmic-text = "0.14" -dark-light = "2.0" +cryoglyph = { git = "https://github.com/iced-rs/cryoglyph.git", rev = "453cedec0d2ec563bd7fa87e84a2319bcebb1ba3" } futures = { version = "0.3", default-features = false } glam = "0.25" -cryoglyph = { git = "https://github.com/iced-rs/cryoglyph.git", rev = "453cedec0d2ec563bd7fa87e84a2319bcebb1ba3" } guillotiere = "0.6" half = "2.2" image = { version = "0.25", default-features = false } @@ -188,16 +187,17 @@ lilt = "0.8" log = "0.4" lyon = "1.0" lyon_path = "1.0" +mundy = { version = "0.2", default-features = false } num-traits = "0.2" ouroboros = "0.18" -png = "0.17" +png = "0.18" pulldown-cmark = "0.12" qrcode = { version = "0.13", default-features = false } raw-window-handle = "0.6" resvg = "0.42" rustc-hash = "2.0" -serde = "1.0" semver = "1.0" +serde = "1.0" sha2 = "0.10" sipper = "0.1" smol = "2" diff --git a/core/Cargo.toml b/core/Cargo.toml index cb7ef3ef..31296446 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,7 +14,6 @@ keywords.workspace = true workspace = true [features] -auto-detect-theme = ["dep:dark-light"] advanced = [] crisp = [] basic-shaping = [] @@ -32,9 +31,6 @@ smol_str.workspace = true thiserror.workspace = true web-time.workspace = true -dark-light.workspace = true -dark-light.optional = true - serde.workspace = true serde.optional = true serde.features = ["derive"] diff --git a/core/src/theme.rs b/core/src/theme.rs index 0adf9ab2..1260bca8 100644 --- a/core/src/theme.rs +++ b/core/src/theme.rs @@ -166,31 +166,6 @@ impl Theme { } } -impl Default for Theme { - fn default() -> Self { - #[cfg(feature = "auto-detect-theme")] - { - use std::sync::LazyLock; - - static DEFAULT: LazyLock = LazyLock::new(|| { - match dark_light::detect() - .unwrap_or(dark_light::Mode::Unspecified) - { - dark_light::Mode::Dark => Theme::Dark, - dark_light::Mode::Light | dark_light::Mode::Unspecified => { - Theme::Light - } - } - }); - - DEFAULT.clone() - } - - #[cfg(not(feature = "auto-detect-theme"))] - Theme::Light - } -} - impl fmt::Display for Theme { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -256,6 +231,18 @@ impl fmt::Display for Custom { } } +/// A theme mode, denoting the tone or brightness of a theme. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum Mode { + /// No specific tone. + #[default] + None, + /// A mode referring to themes with light tones. + Light, + /// A mode referring to themes with dark tones. + Dark, +} + /// The base style of a theme. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Style { @@ -268,7 +255,13 @@ pub struct Style { /// The default blank style of a theme. pub trait Base { - /// Returns the default base [`Style`] of a theme. + /// Returns the default theme for the preferred [`Mode`]. + fn default(preference: Mode) -> Self; + + /// Returns the [`Mode`] of the theme. + fn mode(&self) -> Mode; + + /// Returns the default base [`Style`] of the theme. fn base(&self) -> Style; /// Returns the color [`Palette`] of the theme. @@ -280,6 +273,39 @@ pub trait Base { } impl Base for Theme { + fn default(preference: Mode) -> Self { + use std::env; + use std::sync::OnceLock; + + static SYSTEM: OnceLock> = OnceLock::new(); + + let system = SYSTEM.get_or_init(|| { + let name = env::var("ICED_THEME").ok()?; + + Theme::ALL + .iter() + .find(|theme| theme.to_string() == name) + .cloned() + }); + + if let Some(system) = system { + return system.clone(); + } + + match preference { + Mode::None | Mode::Light => Self::Light, + Mode::Dark => Self::Dark, + } + } + + fn mode(&self) -> Mode { + if self.extended_palette().is_dark { + Mode::Dark + } else { + Mode::Light + } + } + fn base(&self) -> Style { default(self) } diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs index 09a2a67b..d8ef0729 100644 --- a/devtools/src/lib.rs +++ b/devtools/src/lib.rs @@ -12,7 +12,7 @@ mod time_machine; use crate::core::border; use crate::core::keyboard; -use crate::core::theme::{self, Base, Theme}; +use crate::core::theme::{self, Theme}; use crate::core::time::seconds; use crate::core::window; use crate::core::{Alignment::Center, Color, Element, Length::Fill}; @@ -90,7 +90,11 @@ where state.subscription(&self.program) } - fn theme(&self, state: &Self::State, window: window::Id) -> Self::Theme { + fn theme( + &self, + state: &Self::State, + window: window::Id, + ) -> Option { state.theme(&self.program, window) } @@ -307,14 +311,12 @@ where } }; - let theme = program.theme(state, window); - - let derive_theme = move || { + fn derive_theme(theme: &T) -> Theme { theme .palette() .map(|palette| Theme::custom("iced devtools", palette)) - .unwrap_or_default() - }; + .unwrap_or(Theme::Dark) + } let mode = match &self.mode { Mode::None => None, @@ -340,7 +342,7 @@ where } } .map(|mode| { - themer(derive_theme(), Element::from(mode).map(Event::Message)) + themer(derive_theme, Element::from(mode).map(Event::Message)) }); let notification = self @@ -359,7 +361,7 @@ where .push_maybe(mode.map(opaque)) .push_maybe(notification.map(|notification| { themer( - derive_theme(), + derive_theme, bottom_right(opaque( container(notification) .padding(10) @@ -389,7 +391,7 @@ where Subscription::batch([subscription, hotkeys, commands]) } - fn theme(&self, program: &P, window: window::Id) -> P::Theme { + fn theme(&self, program: &P, window: window::Id) -> Option { program.theme(self.state(), window) } diff --git a/examples/arc/src/main.rs b/examples/arc/src/main.rs index ce461ab6..6f801d97 100644 --- a/examples/arc/src/main.rs +++ b/examples/arc/src/main.rs @@ -10,7 +10,7 @@ use iced::{Element, Fill, Point, Rectangle, Renderer, Subscription, Theme}; pub fn main() -> iced::Result { iced::application(Arc::new, Arc::update, Arc::view) .subscription(Arc::subscription) - .theme(|_| Theme::Dark) + .theme(Theme::Dark) .run() } diff --git a/examples/bezier_tool/src/main.rs b/examples/bezier_tool/src/main.rs index 8b040755..9a525210 100644 --- a/examples/bezier_tool/src/main.rs +++ b/examples/bezier_tool/src/main.rs @@ -4,7 +4,7 @@ use iced::{Element, Theme}; pub fn main() -> iced::Result { iced::application(Example::default, Example::update, Example::view) - .theme(|_| Theme::CatppuccinMocha) + .theme(Theme::CatppuccinMocha) .run() } diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs index 57b36f7c..cde7eac2 100644 --- a/examples/events/src/main.rs +++ b/examples/events/src/main.rs @@ -37,7 +37,7 @@ impl Events { } Message::EventOccurred(event) => { if let Event::Window(window::Event::CloseRequested) = event { - window::get_latest().and_then(window::close) + window::latest().and_then(window::close) } else { Task::none() } @@ -47,7 +47,7 @@ impl Events { Task::none() } - Message::Exit => window::get_latest().and_then(window::close), + Message::Exit => window::latest().and_then(window::close), } } diff --git a/examples/exit/src/main.rs b/examples/exit/src/main.rs index 767ff93f..567a0ce6 100644 --- a/examples/exit/src/main.rs +++ b/examples/exit/src/main.rs @@ -20,7 +20,7 @@ enum Message { impl Exit { fn update(&mut self, message: Message) -> Task { match message { - Message::Confirm => window::get_latest().and_then(window::close), + Message::Confirm => window::latest().and_then(window::close), Message::Exit => { self.show_confirm = true; diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs index add266b5..96b61813 100644 --- a/examples/ferris/src/main.rs +++ b/examples/ferris/src/main.rs @@ -11,7 +11,7 @@ use iced::{ pub fn main() -> iced::Result { iced::application(Image::default, Image::update, Image::view) .subscription(Image::subscription) - .theme(|_| Theme::TokyoNight) + .theme(Theme::TokyoNight) .run() } diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index e6cb4dab..d27ee62e 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -16,7 +16,7 @@ pub fn main() -> iced::Result { iced::application(GameOfLife::default, GameOfLife::update, GameOfLife::view) .subscription(GameOfLife::subscription) - .theme(|_| Theme::Dark) + .theme(Theme::Dark) .centered() .run() } diff --git a/examples/layout/src/main.rs b/examples/layout/src/main.rs index f3765d9d..b930bdb0 100644 --- a/examples/layout/src/main.rs +++ b/examples/layout/src/main.rs @@ -19,11 +19,11 @@ pub fn main() -> iced::Result { .run() } -#[derive(Default, Debug)] +#[derive(Debug, Default)] struct Layout { example: Example, explain: bool, - theme: Theme, + theme: Option, } #[derive(Debug, Clone)] @@ -51,7 +51,7 @@ impl Layout { self.explain = explain; } Message::ThemeSelected(theme) => { - self.theme = theme; + self.theme = Some(theme); } } } @@ -74,7 +74,8 @@ impl Layout { horizontal_space(), checkbox("Explain", self.explain) .on_toggle(Message::ExplainToggled), - pick_list(Theme::ALL, Some(&self.theme), Message::ThemeSelected), + pick_list(Theme::ALL, self.theme.as_ref(), Message::ThemeSelected) + .placeholder("Theme"), ] .spacing(20) .align_y(Center); @@ -116,7 +117,7 @@ impl Layout { .into() } - fn theme(&self) -> Theme { + fn theme(&self) -> Option { self.theme.clone() } } diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs index cb5e6f43..42082f21 100644 --- a/examples/multi_window/src/main.rs +++ b/examples/multi_window/src/main.rs @@ -66,7 +66,7 @@ impl Example { return Task::none(); }; - window::get_position(*last_window) + window::position(*last_window) .then(|last_position| { let position = last_position.map_or( window::Position::Default, @@ -138,12 +138,8 @@ impl Example { } } - fn theme(&self, window: window::Id) -> Theme { - if let Some(window) = self.windows.get(&window) { - window.theme.clone() - } else { - Theme::default() - } + fn theme(&self, window: window::Id) -> Option { + Some(self.windows.get(&window)?.theme.clone()) } fn scale_factor(&self, window: window::Id) -> f32 { diff --git a/examples/qr_code/src/main.rs b/examples/qr_code/src/main.rs index 6b6989d0..fecc4abf 100644 --- a/examples/qr_code/src/main.rs +++ b/examples/qr_code/src/main.rs @@ -20,7 +20,7 @@ struct QRGenerator { data: String, qr_code: Option, total_size: Option, - theme: Theme, + theme: Option, } #[derive(Debug, Clone)] @@ -58,7 +58,7 @@ impl QRGenerator { self.total_size = Some(total_size); } Message::ThemeChanged(theme) => { - self.theme = theme; + self.theme = Some(theme); } } } @@ -78,7 +78,8 @@ impl QRGenerator { let choose_theme = row![ text("Theme:"), - pick_list(Theme::ALL, Some(&self.theme), Message::ThemeChanged,) + pick_list(Theme::ALL, self.theme.as_ref(), Message::ThemeChanged) + .placeholder("Theme") ] .spacing(10) .align_y(Center); @@ -107,7 +108,7 @@ impl QRGenerator { center(content).padding(20).into() } - fn theme(&self) -> Theme { + fn theme(&self) -> Option { self.theme.clone() } } diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs index 61285b72..100eca94 100644 --- a/examples/screenshot/src/main.rs +++ b/examples/screenshot/src/main.rs @@ -49,7 +49,7 @@ impl Example { fn update(&mut self, message: Message) -> Task { match message { Message::Screenshot => { - return window::get_latest() + return window::latest() .and_then(window::screenshot) .map(Message::Screenshotted); } diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index f28216f9..e5805532 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -15,7 +15,7 @@ pub fn main() -> iced::Result { #[derive(Default)] struct Styling { - theme: Theme, + theme: Option, input_value: String, slider_value: f32, checkbox_value: bool, @@ -32,13 +32,14 @@ enum Message { TogglerToggled(bool), PreviousTheme, NextTheme, + ClearTheme, } impl Styling { fn update(&mut self, message: Message) { match message { Message::ThemeChanged(theme) => { - self.theme = theme; + self.theme = Some(theme); } Message::InputChanged(value) => self.input_value = value, Message::ButtonPressed => {} @@ -46,21 +47,29 @@ impl Styling { Message::CheckboxToggled(value) => self.checkbox_value = value, Message::TogglerToggled(value) => self.toggler_value = value, Message::PreviousTheme | Message::NextTheme => { - if let Some(current) = Theme::ALL - .iter() - .position(|candidate| &self.theme == candidate) - { - self.theme = if matches!(message, Message::NextTheme) { - Theme::ALL[(current + 1) % Theme::ALL.len()].clone() - } else if current == 0 { + let current = Theme::ALL.iter().position(|candidate| { + self.theme.as_ref() == Some(candidate) + }); + + self.theme = Some(if matches!(message, Message::NextTheme) { + Theme::ALL[current.map(|current| current + 1).unwrap_or(0) + % Theme::ALL.len()] + .clone() + } else { + let current = current.unwrap_or(0); + + if current == 0 { Theme::ALL .last() .expect("Theme::ALL must not be empty") .clone() } else { Theme::ALL[current - 1].clone() - }; - } + } + }); + } + Message::ClearTheme => { + self.theme = None; } } } @@ -68,8 +77,9 @@ impl Styling { fn view(&self) -> Element<'_, Message> { let choose_theme = column![ text("Theme:"), - pick_list(Theme::ALL, Some(&self.theme), Message::ThemeChanged) - .width(Fill), + pick_list(Theme::ALL, self.theme.as_ref(), Message::ThemeChanged) + .width(Fill) + .placeholder("System"), ] .spacing(10); @@ -186,11 +196,14 @@ impl Styling { keyboard::key::Named::ArrowDown | keyboard::key::Named::ArrowRight, ) => Some(Message::NextTheme), + keyboard::Key::Named(keyboard::key::Named::Space) => { + Some(Message::ClearTheme) + } _ => None, }) } - fn theme(&self) -> Theme { + fn theme(&self) -> Option { self.theme.clone() } } @@ -210,9 +223,7 @@ mod tests { .cloned() .map(|theme| { let mut styling = Styling::default(); - styling.update(Message::ThemeChanged(theme)); - - let theme = styling.theme(); + styling.update(Message::ThemeChanged(theme.clone())); let mut ui = simulator(styling.view()); let snapshot = ui.snapshot(&theme)?; diff --git a/examples/system_information/Cargo.toml b/examples/system_information/Cargo.toml index 55e00d59..6c99e006 100644 --- a/examples/system_information/Cargo.toml +++ b/examples/system_information/Cargo.toml @@ -7,6 +7,6 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["system"] +iced.features = ["sysinfo"] bytesize = "1.1" diff --git a/examples/system_information/src/main.rs b/examples/system_information/src/main.rs index 61bca4c8..4de4ab23 100644 --- a/examples/system_information/src/main.rs +++ b/examples/system_information/src/main.rs @@ -1,5 +1,6 @@ +use iced::system; use iced::widget::{button, center, column, text}; -use iced::{Element, Task, system}; +use iced::{Element, Task}; pub fn main() -> iced::Result { iced::application(Example::new, Example::update, Example::view).run() @@ -26,7 +27,7 @@ impl Example { fn new() -> (Self, Task) { ( Self::Loading, - system::fetch_information().map(Message::InformationReceived), + system::information().map(Message::InformationReceived), ) } diff --git a/examples/table/src/main.rs b/examples/table/src/main.rs index 26a8e621..7a1d6be2 100644 --- a/examples/table/src/main.rs +++ b/examples/table/src/main.rs @@ -8,7 +8,7 @@ use iced::{Center, Element, Fill, Font, Right, Theme}; pub fn main() -> iced::Result { iced::application(Table::new, Table::update, Table::view) - .theme(|_| Theme::CatppuccinMocha) + .theme(Theme::CatppuccinMocha) .run() } diff --git a/examples/todos/snapshots/creates_a_new_task-tiny-skia.sha256 b/examples/todos/snapshots/creates_a_new_task-tiny-skia.sha256 index e6746cf8..f56ef744 100644 --- a/examples/todos/snapshots/creates_a_new_task-tiny-skia.sha256 +++ b/examples/todos/snapshots/creates_a_new_task-tiny-skia.sha256 @@ -1 +1 @@ -99f418007af163f172e163565f166da31015521e1bf7de95fa55cda2fb5a7db5 \ No newline at end of file +0acb67235c6a11014a2d2b825e0a70069bca0c67bee0cdb38a0144fc72b25220 \ No newline at end of file diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index ed767e70..31f20ab6 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -5,7 +5,7 @@ use iced::widget::{ }; use iced::window; use iced::{ - Center, Element, Fill, Font, Function, Subscription, Task as Command, + Center, Element, Fill, Font, Function, Subscription, Task as Command, Theme, }; use serde::{Deserialize, Serialize}; @@ -151,7 +151,7 @@ impl Todos { widget::focus_next() } } - Message::ToggleFullscreen(mode) => window::get_latest() + Message::ToggleFullscreen(mode) => window::latest() .and_then(move |window| window::set_mode(window, mode)), Message::Loaded(_) => Command::none(), }; @@ -194,7 +194,7 @@ impl Todos { let title = text("todos") .width(Fill) .size(100) - .color([0.5, 0.5, 0.5]) + .style(subtle) .align_x(Center); let input = text_input("What needs to be done?", input_value) @@ -447,7 +447,7 @@ fn empty_message(message: &str) -> Element<'_, Message> { .width(Fill) .size(25) .align_x(Center) - .color([0.7, 0.7, 0.7]), + .style(subtle), ) .height(200) .into() @@ -471,6 +471,12 @@ fn delete_icon() -> Text<'static> { icon('\u{F1F8}') } +fn subtle(theme: &Theme) -> text::Style { + text::Style { + color: Some(theme.extended_palette().background.strongest.color), + } +} + // Persistence #[derive(Debug, Clone, Serialize, Deserialize)] struct SavedState { diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index 5d009da6..78c329b5 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -1,11 +1,10 @@ -use iced::border; use iced::widget::{Button, Column, Container, Slider}; use iced::widget::{ button, center_x, center_y, checkbox, column, horizontal_space, image, radio, rich_text, row, scrollable, slider, span, text, text_input, toggler, vertical_space, }; -use iced::{Center, Color, Element, Fill, Font, Pixels, Theme}; +use iced::{Center, Color, Element, Fill, Font, Pixels, color}; pub fn main() -> iced::Result { #[cfg(target_arch = "wasm32")] @@ -201,7 +200,7 @@ impl Tour { Self::container("Welcome!") .push( "This is a simple tour meant to showcase a bunch of \ - widgets that can be easily implemented on top of Iced.", + widgets that come bundled in Iced.", ) .push( "Iced is a cross-platform GUI library for Rust focused on \ @@ -216,28 +215,19 @@ impl Tour { built on top of wgpu, a graphics library supporting Vulkan, \ Metal, DX11, and DX12.", ) - .push({ - let theme = Theme::default(); - let palette = theme.extended_palette(); - + .push( rich_text![ "Additionally, this tour can also run on WebAssembly ", "by leveraging ", span("trunk") - .color(palette.primary.base.color) - .background(palette.background.weakest.color) - .border( - border::rounded(2) - .width(1) - .color(palette.background.weak.color) - ) - .padding([0, 2]) + .color(color!(0x7777FF)) + .underline(true) .font(Font::MONOSPACE) .link(Message::OpenTrunk), "." ] - .on_link_click(std::convert::identity) - }) + .on_link_click(std::convert::identity), + ) .push( "You will need to interact with the UI in order to reach \ the end!", diff --git a/examples/vectorial_text/src/main.rs b/examples/vectorial_text/src/main.rs index d0ba91b9..78349696 100644 --- a/examples/vectorial_text/src/main.rs +++ b/examples/vectorial_text/src/main.rs @@ -11,7 +11,7 @@ pub fn main() -> iced::Result { VectorialText::update, VectorialText::view, ) - .theme(|_| Theme::Dark) + .theme(Theme::Dark) .run() } diff --git a/examples/visible_bounds/src/main.rs b/examples/visible_bounds/src/main.rs index 8e5e4a07..fa00a8fc 100644 --- a/examples/visible_bounds/src/main.rs +++ b/examples/visible_bounds/src/main.rs @@ -12,7 +12,7 @@ use iced::{ pub fn main() -> iced::Result { iced::application(Example::default, Example::update, Example::view) .subscription(Example::subscription) - .theme(|_| Theme::Dark) + .theme(Theme::Dark) .run() } diff --git a/futures/src/event.rs b/futures/src/event.rs index bd75d82c..58bc9df2 100644 --- a/futures/src/event.rs +++ b/futures/src/event.rs @@ -37,6 +37,7 @@ where event: Event::Window(window::Event::RedrawRequested(_)), .. } + | subscription::Event::SystemThemeChanged(_) | subscription::Event::PlatformSpecific(_) => None, subscription::Event::Interaction { window, @@ -66,7 +67,8 @@ where event, status, } => f(event, status, window), - subscription::Event::PlatformSpecific(_) => None, + subscription::Event::SystemThemeChanged(_) + | subscription::Event::PlatformSpecific(_) => None, }) } diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index e347e81f..338b2622 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -4,6 +4,7 @@ mod tracker; pub use tracker::Tracker; use crate::core::event; +use crate::core::theme; use crate::core::window; use crate::futures::Stream; use crate::{BoxStream, MaybeSend}; @@ -27,6 +28,9 @@ pub enum Event { status: event::Status, }, + /// The system theme has changed. + SystemThemeChanged(theme::Mode), + /// A platform specific event. PlatformSpecific(PlatformSpecific), } @@ -422,7 +426,8 @@ where } } -pub(crate) fn filter_map(id: I, f: F) -> Subscription +/// Creatges a [`Subscription`] from a hashable id and a filter function. +pub fn filter_map(id: I, f: F) -> Subscription where I: Hash + 'static, F: Fn(Event) -> Option + MaybeSend + 'static, diff --git a/graphics/src/compositor.rs b/graphics/src/compositor.rs index 338d648f..e0c8eb46 100644 --- a/graphics/src/compositor.rs +++ b/graphics/src/compositor.rs @@ -59,7 +59,7 @@ pub trait Compositor: Sized { ); /// Returns [`Information`] used by this [`Compositor`]. - fn fetch_information(&self) -> Information; + fn information(&self) -> Information; /// Loads a font from its bytes. fn load_font(&mut self, font: Cow<'static, [u8]>) { @@ -178,7 +178,7 @@ impl Compositor for () { fn load_font(&mut self, _font: Cow<'static, [u8]>) {} - fn fetch_information(&self) -> Information { + fn information(&self) -> Information { Information { adapter: String::from("Null Renderer"), backend: String::from("Null"), diff --git a/program/src/lib.rs b/program/src/lib.rs index d479d2f8..3b516770 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -25,7 +25,7 @@ pub trait Program: Sized { type Message: Message + 'static; /// The theme of the program. - type Theme: Default + theme::Base; + type Theme: theme::Base; /// The renderer of the program. type Renderer: Renderer; @@ -86,8 +86,12 @@ pub trait Program: Sized { Subscription::none() } - fn theme(&self, _state: &Self::State, _window: window::Id) -> Self::Theme { - ::default() + fn theme( + &self, + _state: &Self::State, + _window: window::Id, + ) -> Option { + None } fn style(&self, _state: &Self::State, theme: &Self::Theme) -> theme::Style { @@ -152,7 +156,7 @@ pub fn with_title( &self, state: &Self::State, window: window::Id, - ) -> Self::Theme { + ) -> Option { self.program.theme(state, window) } @@ -238,7 +242,7 @@ pub fn with_subscription( &self, state: &Self::State, window: window::Id, - ) -> Self::Theme { + ) -> Option { self.program.theme(state, window) } @@ -264,7 +268,7 @@ pub fn with_subscription( /// Decorates a [`Program`] with the given theme function. pub fn with_theme( program: P, - f: impl Fn(&P::State, window::Id) -> P::Theme, + f: impl Fn(&P::State, window::Id) -> Option, ) -> impl Program { struct WithTheme { program: P, @@ -273,7 +277,7 @@ pub fn with_theme( impl Program for WithTheme where - F: Fn(&P::State, window::Id) -> P::Theme, + F: Fn(&P::State, window::Id) -> Option, { type State = P::State; type Message = P::Message; @@ -285,7 +289,7 @@ pub fn with_theme( &self, state: &Self::State, window: window::Id, - ) -> Self::Theme { + ) -> Option { (self.theme)(state, window) } @@ -407,7 +411,7 @@ pub fn with_style( &self, state: &Self::State, window: window::Id, - ) -> Self::Theme { + ) -> Option { self.program.theme(state, window) } @@ -478,7 +482,7 @@ pub fn with_scale_factor( &self, state: &Self::State, window: window::Id, - ) -> Self::Theme { + ) -> Option { self.program.theme(state, window) } @@ -561,7 +565,7 @@ pub fn with_executor( &self, state: &Self::State, window: window::Id, - ) -> Self::Theme { + ) -> Option { self.program.theme(state, window) } @@ -628,7 +632,7 @@ impl Instance

{ } /// Returns the current theme of the [`Instance`]. - pub fn theme(&self, window: window::Id) -> P::Theme { + pub fn theme(&self, window: window::Id) -> Option { self.program.theme(&self.state, window) } diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index d8d04d45..d018a242 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -313,8 +313,8 @@ where delegate!(self, compositor, compositor.load_font(font)); } - fn fetch_information(&self) -> compositor::Information { - delegate!(self, compositor, compositor.fetch_information()) + fn information(&self) -> compositor::Information { + delegate!(self, compositor, compositor.information()) } fn present( diff --git a/runtime/src/system.rs b/runtime/src/system.rs index 8b0ec2d8..09f112f5 100644 --- a/runtime/src/system.rs +++ b/runtime/src/system.rs @@ -1,11 +1,20 @@ //! Access the native system. +use crate::core::theme; use crate::futures::futures::channel::oneshot; +use crate::futures::subscription::{self, Subscription}; +use crate::task::{self, Task}; /// An operation to be performed on the system. #[derive(Debug)] pub enum Action { - /// Query system information and produce `T` with the result. - QueryInformation(oneshot::Sender), + /// Send available system information. + GetInformation(oneshot::Sender), + + /// Send the current system theme mode. + GetTheme(oneshot::Sender), + + /// Notify to the runtime that the system theme has changed. + NotifyTheme(theme::Mode), } /// Contains information about the system (e.g. system name, processor, memory, graphics adapter). @@ -37,3 +46,29 @@ pub struct Information { /// Model information for the active graphics adapter pub graphics_adapter: String, } + +/// Returns available system information. +pub fn information() -> Task { + task::oneshot(|channel| { + crate::Action::System(Action::GetInformation(channel)) + }) +} + +/// Returns the current system theme. +pub fn theme() -> Task { + task::oneshot(|sender| crate::Action::System(Action::GetTheme(sender))) +} + +/// Subscribes to system theme changes. +pub fn theme_changes() -> Subscription { + #[derive(Hash)] + struct ThemeChanges; + + subscription::filter_map(ThemeChanges, |event| { + let subscription::Event::SystemThemeChanged(mode) = event else { + return None; + }; + + Some(mode) + }) +} diff --git a/runtime/src/window.rs b/runtime/src/window.rs index ccd8721b..dde540b8 100644 --- a/runtime/src/window.rs +++ b/runtime/src/window.rs @@ -266,12 +266,12 @@ pub fn close(id: Id) -> Task { } /// Gets the window [`Id`] of the oldest window. -pub fn get_oldest() -> Task> { +pub fn oldest() -> Task> { task::oneshot(|channel| crate::Action::Window(Action::GetOldest(channel))) } /// Gets the window [`Id`] of the latest window. -pub fn get_latest() -> Task> { +pub fn latest() -> Task> { task::oneshot(|channel| crate::Action::Window(Action::GetLatest(channel))) } @@ -315,14 +315,14 @@ pub fn set_resize_increments(id: Id, increments: Option) -> Task { } /// Get the window's size in logical dimensions. -pub fn get_size(id: Id) -> Task { +pub fn size(id: Id) -> Task { task::oneshot(move |channel| { crate::Action::Window(Action::GetSize(id, channel)) }) } /// Gets the maximized state of the window with the given [`Id`]. -pub fn get_maximized(id: Id) -> Task { +pub fn is_maximized(id: Id) -> Task { task::oneshot(move |channel| { crate::Action::Window(Action::GetMaximized(id, channel)) }) @@ -334,7 +334,7 @@ pub fn maximize(id: Id, maximized: bool) -> Task { } /// Gets the minimized state of the window with the given [`Id`]. -pub fn get_minimized(id: Id) -> Task> { +pub fn is_minimized(id: Id) -> Task> { task::oneshot(move |channel| { crate::Action::Window(Action::GetMinimized(id, channel)) }) @@ -346,14 +346,14 @@ pub fn minimize(id: Id, minimized: bool) -> Task { } /// Gets the position in logical coordinates of the window with the given [`Id`]. -pub fn get_position(id: Id) -> Task> { +pub fn position(id: Id) -> Task> { task::oneshot(move |channel| { crate::Action::Window(Action::GetPosition(id, channel)) }) } /// Gets the scale factor of the window with the given [`Id`]. -pub fn get_scale_factor(id: Id) -> Task { +pub fn scale_factor(id: Id) -> Task { task::oneshot(move |channel| { crate::Action::Window(Action::GetScaleFactor(id, channel)) }) @@ -365,7 +365,7 @@ pub fn move_to(id: Id, position: Point) -> Task { } /// Gets the current [`Mode`] of the window. -pub fn get_mode(id: Id) -> Task { +pub fn mode(id: Id) -> Task { task::oneshot(move |channel| { crate::Action::Window(Action::GetMode(id, channel)) }) @@ -426,7 +426,7 @@ pub fn show_system_menu(id: Id) -> Task { /// Gets an identifier unique to the window, provided by the underlying windowing system. This is /// not to be confused with [`Id`]. -pub fn get_raw_id(id: Id) -> Task { +pub fn raw_id(id: Id) -> Task { task::oneshot(|channel| { crate::Action::Window(Action::GetRawId(id, channel)) }) diff --git a/src/application.rs b/src/application.rs index d8f7862b..ef15a34a 100644 --- a/src/application.rs +++ b/src/application.rs @@ -7,7 +7,7 @@ //! //! pub fn main() -> iced::Result { //! iced::application(u64::default, update, view) -//! .theme(|_| Theme::Dark) +//! .theme(Theme::Dark) //! .centered() //! .run() //! } @@ -35,7 +35,7 @@ use crate::shell; use crate::theme; use crate::window; use crate::{ - Element, Executor, Font, Result, Settings, Size, Subscription, Task, + Element, Executor, Font, Result, Settings, Size, Subscription, Task, Theme, }; use iced_debug as debug; @@ -75,14 +75,14 @@ pub use timed::timed; /// } /// ``` pub fn application( - boot: impl Boot, - update: impl Update, - view: impl for<'a> View<'a, State, Message, Theme, Renderer>, + boot: impl BootFn, + update: impl UpdateFn, + view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>, ) -> Application> where State: 'static, Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, { use std::marker::PhantomData; @@ -101,11 +101,11 @@ where for Instance where Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, - Boot: self::Boot, - Update: self::Update, - View: for<'a> self::View<'a, State, Message, Theme, Renderer>, + Boot: self::BootFn, + Update: self::UpdateFn, + View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>, { type State = State; type Message = Message; @@ -320,10 +320,10 @@ impl Application

{ } } - /// Sets the [`Title`] of the [`Application`]. + /// Sets the title of the [`Application`]. pub fn title( self, - title: impl Title, + title: impl TitleFn, ) -> Application< impl Program, > { @@ -355,13 +355,13 @@ impl Application

{ /// Sets the theme logic of the [`Application`]. pub fn theme( self, - f: impl Fn(&P::State) -> P::Theme, + f: impl ThemeFn, ) -> Application< impl Program, > { Application { raw: program::with_theme(self.raw, move |state, _window| { - debug::hot(|| f(state)) + debug::hot(|| f.theme(state)) }), settings: self.settings, window: self.window, @@ -425,12 +425,12 @@ impl Application

{ /// In practice, this means that [`application`] can both take /// simple functions like `State::default` and more advanced ones /// that return a [`Task`]. -pub trait Boot { +pub trait BootFn { /// Initializes the [`Application`] state. fn boot(&self) -> (State, Task); } -impl Boot for T +impl BootFn for T where T: Fn() -> C, C: IntoBoot, @@ -464,18 +464,18 @@ impl IntoBoot for (State, Task) { /// any closure `Fn(&State) -> String`. /// /// This trait allows the [`application`] builder to take any of them. -pub trait Title { +pub trait TitleFn { /// Produces the title of the [`Application`]. fn title(&self, state: &State) -> String; } -impl Title for &'static str { +impl TitleFn for &'static str { fn title(&self, _state: &State) -> String { self.to_string() } } -impl Title for T +impl TitleFn for T where T: Fn(&State) -> String, { @@ -488,18 +488,18 @@ where /// /// This trait allows the [`application`] builder to take any closure that /// returns any `Into>`. -pub trait Update { +pub trait UpdateFn { /// Processes the message and updates the state of the [`Application`]. fn update(&self, state: &mut State, message: Message) -> Task; } -impl Update for () { +impl UpdateFn for () { fn update(&self, _state: &mut State, _message: Message) -> Task { Task::none() } } -impl Update for T +impl UpdateFn for T where T: Fn(&mut State, Message) -> C, C: Into>, @@ -513,13 +513,13 @@ where /// /// This trait allows the [`application`] builder to take any closure that /// returns any `Into>`. -pub trait View<'a, State, Message, Theme, Renderer> { +pub trait ViewFn<'a, State, Message, Theme, Renderer> { /// Produces the widget of the [`Application`]. fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer>; } impl<'a, T, State, Message, Theme, Renderer, Widget> - View<'a, State, Message, Theme, Renderer> for T + ViewFn<'a, State, Message, Theme, Renderer> for T where T: Fn(&'a State) -> Widget, State: 'static, @@ -529,3 +529,35 @@ where self(state).into() } } + +/// The theme logic of some [`Application`]. +/// +/// Any implementors of this trait can be provided as an argument to +/// [`Application::theme`]. +/// +/// `iced` provides two implementors: +/// - the built-in [`Theme`] itself +/// - and any `Fn(&State) -> impl Into>`. +pub trait ThemeFn { + /// Returns the theme of the [`Application`] for the current state. + /// + /// If `None` is returned, `iced` will try to use a theme that + /// matches the system color scheme. + fn theme(&self, state: &State) -> Option; +} + +impl ThemeFn for Theme { + fn theme(&self, _state: &State) -> Option { + Some(self.clone()) + } +} + +impl ThemeFn for F +where + F: Fn(&State) -> T, + T: Into>, +{ + fn theme(&self, state: &State) -> Option { + (self)(state).into() + } +} diff --git a/src/application/timed.rs b/src/application/timed.rs index 3d158874..32b2f100 100644 --- a/src/application/timed.rs +++ b/src/application/timed.rs @@ -1,5 +1,5 @@ //! An [`Application`] that receives an [`Instant`] in update logic. -use crate::application::{Application, Boot, View}; +use crate::application::{Application, BootFn, ViewFn}; use crate::program; use crate::theme; use crate::time::Instant; @@ -20,17 +20,17 @@ use iced_debug as debug; /// /// [`comet`]: https://github.com/iced-rs/comet pub fn timed( - boot: impl Boot, - update: impl Update, + boot: impl BootFn, + update: impl UpdateFn, subscription: impl Fn(&State) -> Subscription, - view: impl for<'a> View<'a, State, Message, Theme, Renderer>, + view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>, ) -> Application< impl Program, > where State: 'static, Message: program::Message + 'static, - Theme: Default + theme::Base + 'static, + Theme: theme::Base + 'static, Renderer: program::Renderer + 'static, { use std::marker::PhantomData; @@ -69,12 +69,12 @@ where > where Message: program::Message + 'static, - Theme: Default + theme::Base + 'static, + Theme: theme::Base + 'static, Renderer: program::Renderer + 'static, - Boot: self::Boot, - Update: self::Update, + Boot: self::BootFn, + Update: self::UpdateFn, Subscription: Fn(&State) -> self::Subscription, - View: for<'a> self::View<'a, State, Message, Theme, Renderer>, + View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>, { type State = State; type Message = (Message, Instant); @@ -148,9 +148,9 @@ where /// The update logic of some timed [`Application`]. /// -/// This is like [`application::Update`](super::Update), +/// This is like [`application::UpdateFn`](super::UpdateFn), /// but it also takes an [`Instant`]. -pub trait Update { +pub trait UpdateFn { /// Processes the message and updates the state of the [`Application`]. fn update( &self, @@ -160,7 +160,7 @@ pub trait Update { ) -> impl Into>; } -impl Update for () { +impl UpdateFn for () { fn update( &self, _state: &mut State, @@ -170,7 +170,7 @@ impl Update for () { } } -impl Update for T +impl UpdateFn for T where T: Fn(&mut State, Message, Instant) -> C, C: Into>, diff --git a/src/daemon.rs b/src/daemon.rs index 05d276c3..08a7d939 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -4,7 +4,9 @@ use crate::program::{self, Program}; use crate::shell; use crate::theme; use crate::window; -use crate::{Element, Executor, Font, Result, Settings, Subscription, Task}; +use crate::{ + Element, Executor, Font, Result, Settings, Subscription, Task, Theme, +}; use iced_debug as debug; @@ -21,14 +23,14 @@ use std::borrow::Cow; /// /// [`exit`]: crate::exit pub fn daemon( - boot: impl application::Boot, - update: impl application::Update, - view: impl for<'a> View<'a, State, Message, Theme, Renderer>, + boot: impl application::BootFn, + update: impl application::UpdateFn, + view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>, ) -> Daemon> where State: 'static, Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, { use std::marker::PhantomData; @@ -47,11 +49,11 @@ where for Instance where Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, - Boot: application::Boot, - Update: application::Update, - View: for<'a> self::View<'a, State, Message, Theme, Renderer>, + Boot: application::BootFn, + Update: application::UpdateFn, + View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>, { type State = State; type Message = Message; @@ -169,10 +171,10 @@ impl Daemon

{ self } - /// Sets the [`Title`] of the [`Daemon`]. + /// Sets the title of the [`Daemon`]. pub fn title( self, - title: impl Title, + title: impl TitleFn, ) -> Daemon< impl Program, > { @@ -202,13 +204,13 @@ impl Daemon

{ /// Sets the theme logic of the [`Daemon`]. pub fn theme( self, - f: impl Fn(&P::State, window::Id) -> P::Theme, + f: impl ThemeFn, ) -> Daemon< impl Program, > { Daemon { raw: program::with_theme(self.raw, move |state, window| { - debug::hot(|| f(state, window)) + debug::hot(|| f.theme(state, window)) }), settings: self.settings, } @@ -266,18 +268,18 @@ impl Daemon

{ /// any closure `Fn(&State, window::Id) -> String`. /// /// This trait allows the [`daemon`] builder to take any of them. -pub trait Title { +pub trait TitleFn { /// Produces the title of the [`Daemon`]. fn title(&self, state: &State, window: window::Id) -> String; } -impl Title for &'static str { +impl TitleFn for &'static str { fn title(&self, _state: &State, _window: window::Id) -> String { self.to_string() } } -impl Title for T +impl TitleFn for T where T: Fn(&State, window::Id) -> String, { @@ -290,7 +292,7 @@ where /// /// This trait allows the [`daemon`] builder to take any closure that /// returns any `Into>`. -pub trait View<'a, State, Message, Theme, Renderer> { +pub trait ViewFn<'a, State, Message, Theme, Renderer> { /// Produces the widget of the [`Daemon`]. fn view( &self, @@ -300,7 +302,7 @@ pub trait View<'a, State, Message, Theme, Renderer> { } impl<'a, T, State, Message, Theme, Renderer, Widget> - View<'a, State, Message, Theme, Renderer> for T + ViewFn<'a, State, Message, Theme, Renderer> for T where T: Fn(&'a State, window::Id) -> Widget, State: 'static, @@ -314,3 +316,35 @@ where self(state, window).into() } } + +/// The theme logic of some [`Daemon`]. +/// +/// Any implementors of this trait can be provided as an argument to +/// [`Daemon::theme`]. +/// +/// `iced` provides two implementors: +/// - the built-in [`Theme`] itself +/// - and any `Fn(&State, window::Id) -> impl Into>`. +pub trait ThemeFn { + /// Returns the theme of the [`Daemon`] for the current state and window. + /// + /// If `None` is returned, `iced` will try to use a theme that + /// matches the system color scheme. + fn theme(&self, state: &State, window: window::Id) -> Option; +} + +impl ThemeFn for Theme { + fn theme(&self, _state: &State, _window: window::Id) -> Option { + Some(self.clone()) + } +} + +impl ThemeFn for F +where + F: Fn(&State, window::Id) -> T, + T: Into>, +{ + fn theme(&self, state: &State, window: window::Id) -> Option { + (self)(state, window).into() + } +} diff --git a/src/lib.rs b/src/lib.rs index a933d21f..8dfad67d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -587,11 +587,12 @@ pub mod mouse { }; } -#[cfg(feature = "system")] pub mod system { //! Retrieve system information. - pub use crate::runtime::system::Information; - pub use crate::shell::system::*; + pub use crate::runtime::system::{theme, theme_changes}; + + #[cfg(feature = "sysinfo")] + pub use crate::runtime::system::{Information, information}; } pub mod overlay { @@ -691,14 +692,14 @@ pub type Result = std::result::Result<(), Error>; /// } /// ``` pub fn run( - update: impl application::Update + 'static, - view: impl for<'a> application::View<'a, State, Message, Theme, Renderer> + update: impl application::UpdateFn + 'static, + view: impl for<'a> application::ViewFn<'a, State, Message, Theme, Renderer> + 'static, ) -> Result where State: Default + 'static, Message: program::Message + 'static, - Theme: Default + theme::Base + 'static, + Theme: theme::Base + 'static, Renderer: program::Renderer + 'static, { application(State::default, update, view).run() diff --git a/test/src/lib.rs b/test/src/lib.rs index 30b08176..72f9441b 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -494,10 +494,13 @@ impl Snapshot { if path.exists() { let file = fs::File::open(&path)?; - let decoder = png::Decoder::new(file); + let decoder = png::Decoder::new(io::BufReader::new(file)); let mut reader = decoder.read_info()?; - let mut bytes = vec![0; reader.output_buffer_size()]; + let n = reader + .output_buffer_size() + .expect("snapshot should fit in memory"); + let mut bytes = vec![0; n]; let info = reader.next_frame(&mut bytes)?; Ok(self.screenshot.bytes == bytes[..info.buffer_size()]) diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 321a003f..02cace72 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -100,7 +100,7 @@ impl crate::graphics::Compositor for Compositor { surface.layer_stack.clear(); } - fn fetch_information(&self) -> Information { + fn information(&self) -> Information { Information { adapter: String::from("CPU"), backend: String::from("tiny-skia"), diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index a8b161a8..c912ef1d 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -332,7 +332,7 @@ impl graphics::Compositor for Compositor { ); } - fn fetch_information(&self) -> compositor::Information { + fn information(&self) -> compositor::Information { let information = self.adapter.get_info(); compositor::Information { diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 3b1d0bbe..9e510685 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -2063,7 +2063,7 @@ where /// A widget that applies any `Theme` to its contents. pub fn themer<'a, Message, OldTheme, NewTheme, Renderer>( - new_theme: NewTheme, + to_theme: impl Fn(&OldTheme) -> NewTheme, content: impl Into>, ) -> Themer< 'a, @@ -2077,7 +2077,7 @@ where Renderer: core::Renderer, NewTheme: Clone, { - Themer::new(move |_| new_theme.clone(), content) + Themer::new(to_theme, content) } /// Creates a [`PaneGrid`] with the given [`pane_grid::State`] and view function. diff --git a/winit/Cargo.toml b/winit/Cargo.toml index f2157978..85f235f7 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -16,13 +16,14 @@ workspace = true [features] default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"] debug = ["iced_debug/enable"] -system = ["sysinfo"] +sysinfo = ["dep:sysinfo"] program = [] x11 = ["winit/x11"] wayland = ["winit/wayland"] wayland-dlopen = ["winit/wayland-dlopen"] wayland-csd-adwaita = ["winit/wayland-csd-adwaita"] unconditional-rendering = [] +linux-theme-detection = ["dep:mundy", "mundy/async-io", "mundy/color-scheme"] [dependencies] iced_debug.workspace = true @@ -42,3 +43,7 @@ sysinfo.optional = true web-sys.workspace = true web-sys.features = ["Document", "Window", "HtmlCanvasElement"] wasm-bindgen-futures.workspace = true + +[target.'cfg(target_os = "linux")'.dependencies] +mundy.workspace = true +mundy.optional = true diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 6f22405d..250918ab 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -5,6 +5,7 @@ use crate::core::input_method; use crate::core::keyboard; use crate::core::mouse; +use crate::core::theme; use crate::core::touch; use crate::core::window; use crate::core::{Event, Point, Size}; @@ -322,7 +323,7 @@ pub fn window_event( } } -/// Converts a [`window::Level`] to a [`winit`] window level. +/// Converts a [`window::Level`] into a [`winit`] window level. /// /// [`winit`]: https://github.com/rust-windowing/winit pub fn window_level(level: window::Level) -> winit::window::WindowLevel { @@ -335,7 +336,7 @@ pub fn window_level(level: window::Level) -> winit::window::WindowLevel { } } -/// Converts a [`window::Position`] to a [`winit`] logical position for a given monitor. +/// Converts a [`window::Position`] into a [`winit`] logical position for a given monitor. /// /// [`winit`]: https://github.com/rust-windowing/winit pub fn position( @@ -407,7 +408,7 @@ pub fn position( } } -/// Converts a [`window::Mode`] to a [`winit`] fullscreen mode. +/// Converts a [`window::Mode`] into a [`winit`] fullscreen mode. /// /// [`winit`]: https://github.com/rust-windowing/winit pub fn fullscreen( @@ -422,7 +423,7 @@ pub fn fullscreen( } } -/// Converts a [`window::Mode`] to a visibility flag. +/// Converts a [`window::Mode`] into a visibility flag. pub fn visible(mode: window::Mode) -> bool { match mode { window::Mode::Windowed | window::Mode::Fullscreen => true, @@ -430,7 +431,7 @@ pub fn visible(mode: window::Mode) -> bool { } } -/// Converts a [`winit`] fullscreen mode to a [`window::Mode`]. +/// Converts a [`winit`] fullscreen mode into a [`window::Mode`]. /// /// [`winit`]: https://github.com/rust-windowing/winit pub fn mode(mode: Option) -> window::Mode { @@ -440,7 +441,28 @@ pub fn mode(mode: Option) -> window::Mode { } } -/// Converts a [`mouse::Interaction`] to a [`winit`] cursor icon. +/// Converts a [`winit`] window theme into a [`theme::Mode`]. +/// +/// [`winit`]: https://github.com/rust-windowing/winit +pub fn theme_mode(theme: winit::window::Theme) -> theme::Mode { + match theme { + winit::window::Theme::Light => theme::Mode::Light, + winit::window::Theme::Dark => theme::Mode::Dark, + } +} + +/// Converts a [`theme::Mode`] into a window theme. +/// +/// [`winit`]: https://github.com/rust-windowing/winit +pub fn window_theme(mode: theme::Mode) -> Option { + match mode { + theme::Mode::None => None, + theme::Mode::Light => Some(winit::window::Theme::Light), + theme::Mode::Dark => Some(winit::window::Theme::Dark), + } +} + +/// Converts a [`mouse::Interaction`] into a [`winit`] cursor icon. /// /// [`winit`]: https://github.com/rust-windowing/winit pub fn mouse_interaction( @@ -511,7 +533,7 @@ pub fn modifiers( result } -/// Converts a physical cursor position to a logical `Point`. +/// Converts a physical cursor position into a logical `Point`. pub fn cursor_position( position: winit::dpi::PhysicalPosition, scale_factor: f32, @@ -1182,7 +1204,7 @@ pub fn icon(icon: window::Icon) -> Option { winit::window::Icon::from_rgba(pixels, size.width, size.height).ok() } -/// Convertions some [`input_method::Purpose`] to its `winit` counterpart. +/// Converts some [`input_method::Purpose`] into its `winit` counterpart. pub fn ime_purpose( purpose: input_method::Purpose, ) -> winit::window::ImePurpose { diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 38d6f3c3..90a4529b 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -29,9 +29,6 @@ pub use winit; pub mod clipboard; pub mod conversion; -#[cfg(feature = "system")] -pub mod system; - mod error; mod proxy; mod window; @@ -53,6 +50,7 @@ use crate::futures::futures::{Future, StreamExt}; use crate::futures::subscription; use crate::futures::{Executor, Runtime}; use crate::graphics::{Compositor, compositor}; +use crate::runtime::system; use crate::runtime::user_interface::{self, UserInterface}; use crate::runtime::{Action, Task}; @@ -111,7 +109,7 @@ where let (_id, open) = runtime::window::open(window_settings); - open.then(move |_| task.take().unwrap_or(Task::none())) + open.then(move |_| task.take().unwrap_or_else(Task::none)) } else { task }; @@ -126,6 +124,7 @@ where let (event_sender, event_receiver) = mpsc::unbounded(); let (control_sender, control_receiver) = mpsc::unbounded(); + let (system_theme_sender, system_theme_receiver) = oneshot::channel(); let instance = Box::pin(run_instance::

( program, @@ -136,6 +135,7 @@ where is_daemon, graphics_settings, settings.fonts, + system_theme_receiver, )); let context = task::Context::from_waker(task::noop_waker_ref()); @@ -147,6 +147,7 @@ where sender: mpsc::UnboundedSender>>, receiver: mpsc::UnboundedReceiver, error: Option, + system_theme: Option>, #[cfg(target_arch = "wasm32")] canvas: Option, @@ -159,6 +160,7 @@ where sender: event_sender, receiver: control_receiver, error: None, + system_theme: Some(system_theme_sender), #[cfg(target_arch = "wasm32")] canvas: None, @@ -172,10 +174,15 @@ where Message: std::fmt::Debug, F: Future, { - fn resumed( - &mut self, - _event_loop: &winit::event_loop::ActiveEventLoop, - ) { + fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { + if let Some(sender) = self.system_theme.take() { + let _ = sender.send( + event_loop + .system_theme() + .map(conversion::theme_mode) + .unwrap_or_default(), + ); + } } fn new_events( @@ -498,6 +505,7 @@ async fn run_instance

( is_daemon: bool, graphics_settings: graphics::Settings, default_fonts: Vec>, + mut _system_theme: oneshot::Receiver, ) where P: Program + 'static, P::Theme: theme::Base, @@ -517,6 +525,38 @@ async fn run_instance

( let mut user_interfaces = ManuallyDrop::new(FxHashMap::default()); let mut clipboard = Clipboard::unconnected(); + #[cfg(all(feature = "linux-theme-detection", target_os = "linux"))] + let mut system_theme = { + let to_mode = |color_scheme| match color_scheme { + mundy::ColorScheme::NoPreference => theme::Mode::None, + mundy::ColorScheme::Light => theme::Mode::Light, + mundy::ColorScheme::Dark => theme::Mode::Dark, + }; + + runtime.run( + mundy::Preferences::stream(mundy::Interest::ColorScheme) + .map(move |preferences| { + Action::System(system::Action::NotifyTheme(to_mode( + preferences.color_scheme, + ))) + }) + .boxed(), + ); + + mundy::Preferences::once_blocking( + mundy::Interest::ColorScheme, + core::time::Duration::from_millis(200), + ) + .map(|preferences| to_mode(preferences.color_scheme)) + .unwrap_or_default() + }; + + #[cfg(not(all(feature = "linux-theme-detection", target_os = "linux")))] + let mut system_theme = + _system_theme.try_recv().ok().flatten().unwrap_or_default(); + + log::info!("System theme: {system_theme:?}"); + loop { // Empty the queue if possible let event = if let Ok(event) = event_receiver.try_next() { @@ -595,14 +635,7 @@ async fn run_instance

( } } - debug::theme_changed(|| { - if window_manager.is_empty() { - theme::Base::palette(&program.theme(id)) - } else { - None - } - }); - + let is_first = window_manager.is_empty(); let window = window_manager.insert( id, window, @@ -611,8 +644,21 @@ async fn run_instance

( .as_mut() .expect("Compositor must be initialized"), exit_on_close_request, + system_theme, ); + window.raw.set_theme(conversion::window_theme( + window.state.theme_mode(), + )); + + debug::theme_changed(|| { + if is_first { + theme::Base::palette(window.state.theme()) + } else { + None + } + }); + let logical_size = window.state.logical_size(); let _ = user_interfaces.insert( @@ -695,6 +741,7 @@ async fn run_instance

( run_action( action, &program, + &mut runtime, &mut compositor, &mut events, &mut messages, @@ -704,6 +751,7 @@ async fn run_instance

( &mut window_manager, &mut ui_caches, &mut is_window_opening, + &mut system_theme, ); actions += 1; } @@ -862,11 +910,24 @@ async fn run_instance

( continue; }; - if matches!( - window_event, - winit::event::WindowEvent::Resized(_) - ) { - window.raw.request_redraw(); + match window_event { + winit::event::WindowEvent::Resized(_) => { + window.raw.request_redraw(); + } + winit::event::WindowEvent::ThemeChanged(theme) => { + let mode = conversion::theme_mode(theme); + + if mode != system_theme { + system_theme = mode; + + runtime.broadcast( + subscription::Event::SystemThemeChanged( + mode, + ), + ); + } + } + _ => {} } if matches!( @@ -879,6 +940,7 @@ async fn run_instance

( id, )), &program, + &mut runtime, &mut compositor, &mut events, &mut messages, @@ -888,9 +950,14 @@ async fn run_instance

( &mut window_manager, &mut ui_caches, &mut is_window_opening, + &mut system_theme, ); } else { - window.state.update(&window.raw, &window_event); + window.state.update( + &program, + &window.raw, + &window_event, + ); if let Some(event) = conversion::window_event( window_event, @@ -1095,6 +1162,7 @@ fn update( fn run_action<'a, P, C>( action: Action, program: &'a program::Instance

, + runtime: &mut Runtime, Action>, compositor: &mut Option, events: &mut Vec<(window::Id, core::Event)>, messages: &mut Vec, @@ -1107,13 +1175,13 @@ fn run_action<'a, P, C>( window_manager: &mut WindowManager, ui_caches: &mut FxHashMap, is_window_opening: &mut bool, + system_theme: &mut theme::Mode, ) where P: Program, C: Compositor + 'static, P::Theme: theme::Base, { use crate::runtime::clipboard; - use crate::runtime::system; use crate::runtime::window; match action { @@ -1421,21 +1489,44 @@ fn run_action<'a, P, C>( } }, Action::System(action) => match action { - system::Action::QueryInformation(_channel) => { - #[cfg(feature = "system")] + system::Action::GetInformation(_channel) => { + #[cfg(feature = "sysinfo")] { if let Some(compositor) = compositor { - let graphics_info = compositor.fetch_information(); + let graphics_info = compositor.information(); let _ = std::thread::spawn(move || { - let information = - crate::system::information(graphics_info); + let information = system_information(graphics_info); let _ = _channel.send(information); }); } } } + system::Action::GetTheme(channel) => { + let _ = channel.send(*system_theme); + } + system::Action::NotifyTheme(mode) => { + if mode != *system_theme { + *system_theme = mode; + + runtime.broadcast(subscription::Event::SystemThemeChanged( + mode, + )); + } + + let Some(theme) = conversion::window_theme(mode) else { + return; + }; + + for (_id, window) in window_manager.iter_mut() { + window.state.update( + program, + &window.raw, + &winit::event::WindowEvent::ThemeChanged(theme), + ); + } + } }, Action::Widget(operation) => { let mut current_operation = Some(operation); @@ -1544,3 +1635,37 @@ pub fn user_force_quit( _ => false, } } + +#[cfg(feature = "sysinfo")] +fn system_information( + graphics: compositor::Information, +) -> system::Information { + use sysinfo::{Process, System}; + + let mut system = System::new_all(); + system.refresh_all(); + + let cpu_brand = system + .cpus() + .first() + .map(|cpu| cpu.brand().to_string()) + .unwrap_or_default(); + + let memory_used = sysinfo::get_current_pid() + .and_then(|pid| system.process(pid).ok_or("Process not found")) + .map(Process::memory) + .ok(); + + system::Information { + system_name: System::name(), + system_kernel: System::kernel_version(), + system_version: System::long_os_version(), + system_short_version: System::os_version(), + cpu_brand, + cpu_cores: system.physical_core_count(), + memory_total: system.total_memory(), + memory_used, + graphics_adapter: graphics.adapter, + graphics_backend: graphics.backend, + } +} diff --git a/winit/src/system.rs b/winit/src/system.rs deleted file mode 100644 index 0b476773..00000000 --- a/winit/src/system.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Access the native system. -use crate::graphics::compositor; -use crate::runtime::system::{Action, Information}; -use crate::runtime::{self, Task}; - -/// Query for available system information. -pub fn fetch_information() -> Task { - runtime::task::oneshot(|channel| { - runtime::Action::System(Action::QueryInformation(channel)) - }) -} - -pub(crate) fn information( - graphics_info: compositor::Information, -) -> Information { - use sysinfo::{Process, System}; - let mut system = System::new_all(); - system.refresh_all(); - - let cpu_brand = system - .cpus() - .first() - .map(|cpu| cpu.brand().to_string()) - .unwrap_or_default(); - - let memory_used = sysinfo::get_current_pid() - .and_then(|pid| system.process(pid).ok_or("Process not found")) - .map(Process::memory) - .ok(); - - Information { - system_name: System::name(), - system_kernel: System::kernel_version(), - system_version: System::long_os_version(), - system_short_version: System::os_version(), - cpu_brand, - cpu_cores: system.physical_core_count(), - memory_total: system.total_memory(), - memory_used, - graphics_adapter: graphics_info.adapter, - graphics_backend: graphics_info.backend, - } -} diff --git a/winit/src/window.rs b/winit/src/window.rs index f2d12677..419c50e1 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -55,8 +55,9 @@ where program: &program::Instance

, compositor: &mut C, exit_on_close_request: bool, + system_theme: theme::Mode, ) -> &mut Window { - let state = State::new(program, id, &window); + let state = State::new(program, id, &window, system_theme); let viewport_version = state.viewport_version(); let physical_size = state.physical_size(); let surface = compositor.create_surface( diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index c345a846..4c3cb403 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -9,7 +9,7 @@ use winit::window::Window; use std::fmt::{Debug, Formatter}; -/// The state of a multi-windowed [`Program`]. +/// The state of the window of a [`Program`]. pub struct State where P::Theme: theme::Base, @@ -20,7 +20,9 @@ where viewport_version: u64, cursor_position: Option>, modifiers: winit::keyboard::ModifiersState, - theme: P::Theme, + theme: Option, + theme_mode: theme::Mode, + default_theme: P::Theme, style: theme::Style, } @@ -29,7 +31,7 @@ where P::Theme: theme::Base, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("multi_window::State") + f.debug_struct("window::State") .field("title", &self.title) .field("scale_factor", &self.scale_factor) .field("viewport", &self.viewport) @@ -49,11 +51,15 @@ where program: &program::Instance

, window_id: window::Id, window: &Window, + system_theme: theme::Mode, ) -> Self { let title = program.title(window_id); let scale_factor = program.scale_factor(window_id); let theme = program.theme(window_id); - let style = program.style(&theme); + let theme_mode = + theme.as_ref().map(theme::Base::mode).unwrap_or_default(); + let default_theme = ::default(system_theme); + let style = program.style(theme.as_ref().unwrap_or(&default_theme)); let viewport = { let physical_size = window.inner_size(); @@ -72,6 +78,8 @@ where cursor_position: None, modifiers: winit::keyboard::ModifiersState::default(), theme, + theme_mode, + default_theme, style, } } @@ -123,7 +131,12 @@ where /// Returns the current theme of the [`State`]. pub fn theme(&self) -> &P::Theme { - &self.theme + self.theme.as_ref().unwrap_or(&self.default_theme) + } + + /// Returns the current [`theme::Mode`] of the [`State`]. + pub fn theme_mode(&self) -> theme::Mode { + self.theme_mode } /// Returns the current background [`Color`] of the [`State`]. @@ -137,7 +150,12 @@ where } /// Processes the provided window event and updates the [`State`] accordingly. - pub fn update(&mut self, window: &Window, event: &WindowEvent) { + pub fn update( + &mut self, + program: &program::Instance

, + window: &Window, + event: &WindowEvent, + ) { match event { WindowEvent::Resized(new_size) => { let size = Size::new(new_size.width, new_size.height); @@ -174,6 +192,16 @@ where WindowEvent::ModifiersChanged(new_modifiers) => { self.modifiers = new_modifiers.state(); } + WindowEvent::ThemeChanged(theme) => { + self.default_theme = ::default( + conversion::theme_mode(*theme), + ); + + if self.theme.is_none() { + self.style = program.style(&self.default_theme); + window.request_redraw(); + } + } _ => {} } } @@ -182,7 +210,7 @@ where /// window. /// /// Normally, a [`Program`] should be synchronized with its [`State`] - /// and window after calling [`State::update`]. + /// and window after calling [`Program::update`]. pub fn synchronize( &mut self, program: &program::Instance

, @@ -217,6 +245,45 @@ where // Update theme and appearance self.theme = program.theme(window_id); - self.style = program.style(&self.theme); + self.style = program.style(self.theme()); + + let new_mode = self + .theme + .as_ref() + .map(theme::Base::mode) + .unwrap_or_default(); + + if self.theme_mode != new_mode { + #[cfg(not(target_os = "linux"))] + { + window.set_theme(conversion::window_theme(new_mode)); + + // Assume the old mode matches the system one + // We will be notified otherwise + if new_mode == theme::Mode::None { + self.default_theme = + ::default(self.theme_mode); + + if self.theme.is_none() { + self.style = program.style(&self.default_theme); + } + } + } + + #[cfg(target_os = "linux")] + { + // mundy always notifies system theme changes, so we + // just restore the default theme mode. + let new_mode = if new_mode == theme::Mode::None { + theme::Base::mode(&self.default_theme) + } else { + new_mode + }; + + window.set_theme(conversion::window_theme(new_mode)); + } + + self.theme_mode = new_mode; + } } }