From 9445f5fcdf4e53eaaec4fe1944432b2b333a5c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 01:24:22 +0200 Subject: [PATCH 01/16] Replace `dark-light` with `mundy` --- Cargo.lock | 737 ++++++++++++++++++++++++++++------------------ Cargo.toml | 6 +- core/Cargo.toml | 6 +- core/src/theme.rs | 19 +- 4 files changed, 466 insertions(+), 302 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aada7dc6..ac9425e7 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" @@ -504,6 +443,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "beul" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c3baedf037b161e69da9200947329f52afa3b6e1cdbe6f344d6aa350fedd2f" + [[package]] name = "bezier_tool" version = "0.1.0" @@ -569,9 +514,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 +551,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 +657,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 +696,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 +766,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -843,18 +798,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 +837,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 +985,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 +1009,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 +1020,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 +1189,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 +1203,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 +1238,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -1306,6 +1247,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 +1311,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 +1456,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 +1473,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 +1518,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 +1554,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 +1907,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 +1969,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 +2007,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 +2017,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 +2038,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 +2049,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,12 +2433,12 @@ dependencies = [ name = "iced_core" version = "0.14.0-dev" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytes", - "dark-light", "glam", "lilt", "log", + "mundy", "num-traits", "rustc-hash 2.1.1", "serde", @@ -2527,7 +2486,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 +2548,7 @@ version = "0.14.0-dev" dependencies = [ "iced_renderer", "iced_runtime", - "png", + "png 0.17.16", "sha2", "thiserror 1.0.69", ] @@ -2614,7 +2573,7 @@ dependencies = [ name = "iced_wgpu" version = "0.14.0-dev" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.9.4", "bytemuck", "cryoglyph", "futures", @@ -2774,9 +2733,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 +2743,9 @@ dependencies = [ "exr", "gif", "image-webp", + "moxcms", "num-traits", - "png", + "png 0.18.0", "qoi", "ravif", "rayon", @@ -2859,7 +2819,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 +2934,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 +2989,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 +3011,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 +3053,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 +3123,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 +3248,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 +3279,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 +3338,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 +3382,32 @@ 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", + "beul", + "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 +3422,7 @@ checksum = "916cbc7cb27db60be930a4e2da243cf4bc39569195f22fd8ee419cd31d5b662c" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -3479,7 +3463,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 +3499,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 +3680,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 +3715,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 +3750,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 +3837,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 +3850,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 +3874,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 +3886,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 +3898,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 +3932,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 +3953,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 +3964,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 +4001,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 +4040,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 +4393,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 +4540,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 +4553,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 +4801,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 +4985,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 +4998,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 +5075,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 +5158,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", @@ -5286,7 +5392,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 +5428,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 +5486,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 +5521,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 +5711,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 +5842,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 +5870,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 +5895,7 @@ dependencies = [ "bytemuck", "cfg-if", "log", - "png", + "png 0.17.16", "tiny-skia-path", ] @@ -6032,7 +6140,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 +6422,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 +6450,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 +6553,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 +6589,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 +6602,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 +6612,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 +6625,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 +6647,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 +6679,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 +6691,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 +6713,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 +6725,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 +6738,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 +6770,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 +6845,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 +6876,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.9.3", + "bitflags 2.9.4", "cfg_aliases", "document-features", "hashbrown", @@ -6842,7 +6945,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.9.3", + "bitflags 2.9.4", "block", "bytemuck", "cfg-if", @@ -6886,7 +6989,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 +7015,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 +7062,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 +7117,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 +7205,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 +7256,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 +7275,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 +7323,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 +7384,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 +7395,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 +7592,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 +7607,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 +7644,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 +7700,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 +7786,7 @@ dependencies = [ "async-trait", "blocking", "enumflags2", - "event-listener 5.4.1", + "event-listener", "futures-core", "futures-lite", "hex", @@ -7678,18 +7838,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 +7933,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 +7949,6 @@ dependencies = [ "endi", "enumflags2", "serde", - "url", "winnow", "zvariant_derive", "zvariant_utils", diff --git a/Cargo.toml b/Cargo.toml index a3ae52c6..c6088e4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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,6 +187,7 @@ lilt = "0.8" log = "0.4" lyon = "1.0" lyon_path = "1.0" +mundy = "0.2" num-traits = "0.2" ouroboros = "0.18" png = "0.17" @@ -196,8 +196,8 @@ 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..a44ca660 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,7 +14,7 @@ keywords.workspace = true workspace = true [features] -auto-detect-theme = ["dep:dark-light"] +auto-detect-theme = ["dep:mundy"] advanced = [] crisp = [] basic-shaping = [] @@ -32,8 +32,8 @@ smol_str.workspace = true thiserror.workspace = true web-time.workspace = true -dark-light.workspace = true -dark-light.optional = true +mundy.workspace = true +mundy.optional = true serde.workspace = true serde.optional = true diff --git a/core/src/theme.rs b/core/src/theme.rs index 0adf9ab2..c47f4e2f 100644 --- a/core/src/theme.rs +++ b/core/src/theme.rs @@ -170,16 +170,21 @@ impl Default for Theme { fn default() -> Self { #[cfg(feature = "auto-detect-theme")] { + use crate::time::Duration; 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 - } + let color_scheme = mundy::Preferences::once_blocking( + mundy::Interest::ColorScheme, + Duration::from_millis(100), + ) + .map(|preferences| preferences.color_scheme) + .unwrap_or_default(); + + match color_scheme { + mundy::ColorScheme::Dark => Theme::Dark, + mundy::ColorScheme::Light + | mundy::ColorScheme::NoPreference => Theme::Light, } }); From 5c7ae8a3d64e297993cd9ed8d1e9c988004bd51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 01:27:01 +0200 Subject: [PATCH 02/16] Enable needed `mundy` features explicitly --- Cargo.lock | 7 ------- Cargo.toml | 4 +++- core/Cargo.toml | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac9425e7..b54ce648 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -443,12 +443,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "beul" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3c3baedf037b161e69da9200947329f52afa3b6e1cdbe6f344d6aa350fedd2f" - [[package]] name = "bezier_tool" version = "0.1.0" @@ -3390,7 +3384,6 @@ checksum = "f5f507e52285e981a349f7224e0ac7eaf014e1a9cce399471547c8dfbc018b79" dependencies = [ "android-build", "async-io", - "beul", "cfg-if", "dispatch", "futures-channel", diff --git a/Cargo.toml b/Cargo.toml index c6088e4f..c587c7d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -187,7 +187,6 @@ lilt = "0.8" log = "0.4" lyon = "1.0" lyon_path = "1.0" -mundy = "0.2" num-traits = "0.2" ouroboros = "0.18" png = "0.17" @@ -219,6 +218,9 @@ wgpu = "26.0" window_clipboard = "0.4.1" winit = { git = "https://github.com/iced-rs/winit.git", rev = "11414b6aa45699f038114e61b4ddf5102b2d3b4b" } +mundy.version = "0.2" +mundy.default-features = false + [workspace.lints.rust] rust_2018_idioms = { level = "deny", priority = -1 } missing_debug_implementations = "deny" diff --git a/core/Cargo.toml b/core/Cargo.toml index a44ca660..2b875545 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -34,6 +34,7 @@ web-time.workspace = true mundy.workspace = true mundy.optional = true +mundy.features = ["async-io", "color-scheme"] serde.workspace = true serde.optional = true From 0111f514a11fdda7db69ca0c99ad751194665d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 05:16:20 +0200 Subject: [PATCH 03/16] Use `winit` to obtain current `theme::Mode` --- Cargo.lock | 477 ++-------------------------- Cargo.toml | 7 +- core/Cargo.toml | 5 - core/src/theme.rs | 52 ++- devtools/src/lib.rs | 22 +- examples/arc/src/main.rs | 2 +- examples/bezier_tool/src/main.rs | 2 +- examples/ferris/src/main.rs | 2 +- examples/game_of_life/src/main.rs | 2 +- examples/layout/src/main.rs | 11 +- examples/multi_window/src/main.rs | 8 +- examples/qr_code/src/main.rs | 9 +- examples/styling/src/main.rs | 43 ++- examples/table/src/main.rs | 2 +- examples/tour/src/main.rs | 24 +- examples/vectorial_text/src/main.rs | 2 +- examples/visible_bounds/src/main.rs | 2 +- program/src/lib.rs | 28 +- src/application.rs | 34 +- src/application/timed.rs | 4 +- src/daemon.rs | 34 +- src/lib.rs | 2 +- widget/src/helpers.rs | 4 +- winit/src/lib.rs | 17 +- winit/src/window/state.rs | 15 +- 25 files changed, 208 insertions(+), 602 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b54ce648..a3be4ad7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,15 +91,6 @@ 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" @@ -199,18 +190,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - [[package]] name = "async-channel" version = "2.5.0" @@ -306,17 +285,6 @@ dependencies = [ "rustix 1.0.8", ] -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-signal" version = "0.2.12" @@ -341,17 +309,6 @@ version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-tungstenite" version = "0.25.1" @@ -545,15 +502,6 @@ 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" @@ -831,7 +779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f" dependencies = [ "objc2 0.5.2", - "objc2-app-kit 0.2.2", + "objc2-app-kit", "objc2-foundation 0.2.2", ] @@ -1241,16 +1189,6 @@ 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" @@ -1362,33 +1300,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - -[[package]] -name = "enumflags2" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "equator" version = "0.4.2" @@ -2182,12 +2093,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "hexf-parse" version = "0.2.1" @@ -2432,7 +2337,6 @@ dependencies = [ "glam", "lilt", "log", - "mundy", "num-traits", "rustc-hash 2.1.1", "serde", @@ -3258,15 +3162,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "metal" version = "0.32.0" @@ -3376,31 +3271,6 @@ 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" @@ -3486,19 +3356,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - [[package]] name = "nom" version = "7.1.3" @@ -3674,32 +3531,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "libc", "objc2 0.5.2", - "objc2-core-data 0.2.2", - "objc2-core-image 0.2.2", + "objc2-core-data", + "objc2-core-image", "objc2-foundation 0.2.2", - "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", + "objc2-quartz-core", ] [[package]] @@ -3709,30 +3547,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "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 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3744,75 +3571,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "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 0.5.1", + "block2", "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 0.5.1", + "block2", "objc2 0.5.2", "objc2-contacts", "objc2-foundation 0.2.2", @@ -3831,7 +3613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "dispatch", "libc", "objc2 0.5.2", @@ -3844,21 +3626,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ "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]] @@ -3867,9 +3635,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "block2 0.5.1", + "block2", "objc2 0.5.2", - "objc2-app-kit 0.2.2", + "objc2-app-kit", "objc2-foundation 0.2.2", ] @@ -3880,7 +3648,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3892,23 +3660,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "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" @@ -3926,15 +3683,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "objc2 0.5.2", - "objc2-cloud-kit 0.2.2", - "objc2-core-data 0.2.2", - "objc2-core-image 0.2.2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", "objc2-core-location", "objc2-foundation 0.2.2", "objc2-link-presentation", - "objc2-quartz-core 0.2.2", + "objc2-quartz-core", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -3946,7 +3703,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3958,7 +3715,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.9.4", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", @@ -4095,16 +3852,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "ouroboros" version = "0.18.5" @@ -5215,17 +4962,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "serde_spanned" version = "0.6.9" @@ -5479,7 +5215,7 @@ dependencies = [ "memmap2", "objc2 0.5.2", "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", + "objc2-quartz-core", "raw-window-handle 0.6.2", "redox_syscall 0.5.17", "rustix 0.38.44", @@ -6266,17 +6002,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" -[[package]] -name = "uds_windows" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" -dependencies = [ - "memoffset", - "tempfile", - "winapi", -] - [[package]] name = "unicase" version = "2.8.1" @@ -7055,28 +6780,6 @@ 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" @@ -7115,17 +6818,6 @@ dependencies = [ "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" @@ -7204,16 +6896,6 @@ 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" @@ -7388,15 +7070,6 @@ 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" @@ -7586,7 +7259,7 @@ dependencies = [ "android-activity", "atomic-waker", "bitflags 2.9.4", - "block2 0.5.1", + "block2", "bytemuck", "calloop", "cfg_aliases", @@ -7600,7 +7273,7 @@ dependencies = [ "memmap2", "ndk", "objc2 0.5.2", - "objc2-app-kit 0.2.2", + "objc2-app-kit", "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", @@ -7763,66 +7436,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zbus" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a073be99ace1adc48af593701c8015cd9817df372e14a1a6b0ee8f8bf043be" -dependencies = [ - "async-broadcast", - "async-executor", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-lite", - "hex", - "nix", - "ordered-stream", - "serde", - "serde_repr", - "tracing", - "uds_windows", - "windows-sys 0.60.2", - "winnow", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e80cd713a45a49859dcb648053f63265f4f2851b6420d47a958e5697c68b131" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zbus_names", - "zvariant", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" -dependencies = [ - "serde", - "static_assertions", - "winnow", - "zvariant", -] - [[package]] name = "zeno" version = "0.3.3" @@ -7932,43 +7545,3 @@ checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core", ] - -[[package]] -name = "zvariant" -version = "5.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" -dependencies = [ - "endi", - "enumflags2", - "serde", - "winnow", - "zvariant_derive", - "zvariant_utils", -] - -[[package]] -name = "zvariant_derive" -version = "5.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "syn", - "winnow", -] diff --git a/Cargo.toml b/Cargo.toml index c587c7d9..f68a5c96 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"] # Enables the `wgpu` GPU-accelerated renderer backend wgpu = ["iced_renderer/wgpu", "iced_widget/wgpu"] # Enables the `tiny-skia` software renderer backend @@ -67,8 +67,6 @@ highlighter = ["iced_highlighter", "iced_widget/highlighter"] 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 @@ -218,9 +216,6 @@ wgpu = "26.0" window_clipboard = "0.4.1" winit = { git = "https://github.com/iced-rs/winit.git", rev = "11414b6aa45699f038114e61b4ddf5102b2d3b4b" } -mundy.version = "0.2" -mundy.default-features = false - [workspace.lints.rust] rust_2018_idioms = { level = "deny", priority = -1 } missing_debug_implementations = "deny" diff --git a/core/Cargo.toml b/core/Cargo.toml index 2b875545..31296446 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,7 +14,6 @@ keywords.workspace = true workspace = true [features] -auto-detect-theme = ["dep:mundy"] advanced = [] crisp = [] basic-shaping = [] @@ -32,10 +31,6 @@ smol_str.workspace = true thiserror.workspace = true web-time.workspace = true -mundy.workspace = true -mundy.optional = true -mundy.features = ["async-io", "color-scheme"] - serde.workspace = true serde.optional = true serde.features = ["derive"] diff --git a/core/src/theme.rs b/core/src/theme.rs index c47f4e2f..3c0f51f9 100644 --- a/core/src/theme.rs +++ b/core/src/theme.rs @@ -166,36 +166,6 @@ impl Theme { } } -impl Default for Theme { - fn default() -> Self { - #[cfg(feature = "auto-detect-theme")] - { - use crate::time::Duration; - use std::sync::LazyLock; - - static DEFAULT: LazyLock = LazyLock::new(|| { - let color_scheme = mundy::Preferences::once_blocking( - mundy::Interest::ColorScheme, - Duration::from_millis(100), - ) - .map(|preferences| preferences.color_scheme) - .unwrap_or_default(); - - match color_scheme { - mundy::ColorScheme::Dark => Theme::Dark, - mundy::ColorScheme::Light - | mundy::ColorScheme::NoPreference => 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 { @@ -261,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 { @@ -273,6 +255,9 @@ pub struct Style { /// The default blank style of a theme. pub trait Base { + /// Returns the default theme for the preferred [`Mode`]. + fn default(preference: Mode) -> Self; + /// Returns the default base [`Style`] of a theme. fn base(&self) -> Style; @@ -285,6 +270,13 @@ pub trait Base { } impl Base for Theme { + fn default(preference: Mode) -> Self { + match preference { + Mode::None | Mode::Light => Self::Light, + Mode::Dark => Self::Dark, + } + } + 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/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..d299648e 100644 --- a/examples/multi_window/src/main.rs +++ b/examples/multi_window/src/main.rs @@ -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/styling/src/main.rs b/examples/styling/src/main.rs index f28216f9..0117d2dc 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, @@ -38,7 +38,7 @@ 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,20 +46,20 @@ 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 { - Theme::ALL - .last() - .expect("Theme::ALL must not be empty") - .clone() - } else { - Theme::ALL[current - 1].clone() - }; + if let Some(current) = Theme::ALL.iter().position(|candidate| { + self.theme.as_ref() == Some(candidate) + }) { + self.theme = + Some(if matches!(message, Message::NextTheme) { + Theme::ALL[(current + 1) % Theme::ALL.len()].clone() + } else if current == 0 { + Theme::ALL + .last() + .expect("Theme::ALL must not be empty") + .clone() + } else { + Theme::ALL[current - 1].clone() + }); } } } @@ -68,8 +68,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); @@ -190,7 +191,7 @@ impl Styling { }) } - fn theme(&self) -> Theme { + fn theme(&self) -> Option { self.theme.clone() } } @@ -210,9 +211,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/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/tour/src/main.rs b/examples/tour/src/main.rs index 5d009da6..56e14f06 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!(0x0000FF)) + .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/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/src/application.rs b/src/application.rs index d8f7862b..ef547cea 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; @@ -82,7 +82,7 @@ pub fn application( where State: 'static, Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, { use std::marker::PhantomData; @@ -101,7 +101,7 @@ where for Instance where Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, Boot: self::Boot, Update: self::Update, @@ -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, @@ -529,3 +529,25 @@ where self(state).into() } } + +/// TODO +pub trait ThemeFn { + /// TODO + 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..2aaf40f3 100644 --- a/src/application/timed.rs +++ b/src/application/timed.rs @@ -30,7 +30,7 @@ pub fn timed( 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,7 +69,7 @@ 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, diff --git a/src/daemon.rs b/src/daemon.rs index 05d276c3..2a4451e0 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; @@ -28,7 +30,7 @@ pub fn daemon( where State: 'static, Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, { use std::marker::PhantomData; @@ -47,7 +49,7 @@ where for Instance where Message: program::Message + 'static, - Theme: Default + theme::Base, + Theme: theme::Base, Renderer: program::Renderer, Boot: application::Boot, Update: application::Update, @@ -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, } @@ -314,3 +316,25 @@ where self(state, window).into() } } + +/// TODO +pub trait ThemeFn { + /// TODO + 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..b0b2bb8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -698,7 +698,7 @@ pub fn run( 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/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/src/lib.rs b/winit/src/lib.rs index 38d6f3c3..6f9cea56 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -595,14 +595,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, @@ -613,6 +606,14 @@ async fn run_instance

( exit_on_close_request, ); + 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( diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index c345a846..6adc2205 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -21,6 +21,7 @@ where cursor_position: Option>, modifiers: winit::keyboard::ModifiersState, theme: P::Theme, + theme_mode: theme::Mode, style: theme::Style, } @@ -52,7 +53,14 @@ where ) -> Self { let title = program.title(window_id); let scale_factor = program.scale_factor(window_id); - let theme = program.theme(window_id); + let theme_mode = match window.theme() { + None => theme::Mode::None, + Some(winit::window::Theme::Light) => theme::Mode::Light, + Some(winit::window::Theme::Dark) => theme::Mode::Dark, + }; + let theme = program + .theme(window_id) + .unwrap_or_else(|| ::default(theme_mode)); let style = program.style(&theme); let viewport = { @@ -72,6 +80,7 @@ where cursor_position: None, modifiers: winit::keyboard::ModifiersState::default(), theme, + theme_mode, style, } } @@ -216,7 +225,9 @@ where } // Update theme and appearance - self.theme = program.theme(window_id); + self.theme = program.theme(window_id).unwrap_or_else(|| { + ::default(self.theme_mode) + }); self.style = program.style(&self.theme); } } From 4d32e733b705a144cc15bec538d6fc809b4c656f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 05:23:50 +0200 Subject: [PATCH 04/16] Fix `styling` example when system theme is selected --- examples/styling/src/main.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index 0117d2dc..1465d501 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -46,21 +46,26 @@ 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| { + let current = Theme::ALL.iter().position(|candidate| { self.theme.as_ref() == Some(candidate) - }) { - self.theme = - Some(if matches!(message, Message::NextTheme) { - Theme::ALL[(current + 1) % Theme::ALL.len()].clone() - } else if current == 0 { - Theme::ALL - .last() - .expect("Theme::ALL must not be empty") - .clone() - } else { - Theme::ALL[current - 1].clone() - }); - } + }); + + 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() + } + }); } } } From cb9b106ff89cd05cde757ad76369b61d90d46c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 05:32:23 +0200 Subject: [PATCH 05/16] Allow system theme override with `ICED_THEME` env variable --- core/src/theme.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/src/theme.rs b/core/src/theme.rs index 3c0f51f9..5f2fb127 100644 --- a/core/src/theme.rs +++ b/core/src/theme.rs @@ -271,6 +271,24 @@ 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, From 354159bdf4930b25d452c182840648dedcd1192f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 05:40:31 +0200 Subject: [PATCH 06/16] Update `png` to `0.18` --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- test/src/lib.rs | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3be4ad7..d8d8bcba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2446,7 +2446,7 @@ version = "0.14.0-dev" dependencies = [ "iced_renderer", "iced_runtime", - "png 0.17.16", + "png 0.18.0", "sha2", "thiserror 1.0.69", ] @@ -4907,9 +4907,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", diff --git a/Cargo.toml b/Cargo.toml index f68a5c96..8e952b41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -187,7 +187,7 @@ lyon = "1.0" lyon_path = "1.0" 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" 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()]) From c1d7819c07e6dd40d405b33484e4c127c1e4db2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 06:01:36 +0200 Subject: [PATCH 07/16] Track window theme in `window::State` --- core/src/window/event.rs | 4 ++++ winit/src/conversion.rs | 14 +++++++++++++ winit/src/window/state.rs | 41 ++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/core/src/window/event.rs b/core/src/window/event.rs index 45d29179..48622b70 100644 --- a/core/src/window/event.rs +++ b/core/src/window/event.rs @@ -1,3 +1,4 @@ +use crate::theme; use crate::time::Instant; use crate::{Point, Size}; @@ -71,4 +72,7 @@ pub enum Event { /// /// - **Wayland:** Not implemented. FilesHoveredLeft, + + /// The theme mode of the window has changed. + ThemeModeChanged(theme::Mode), } diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 6f22405d..8668d6a3 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}; @@ -318,6 +319,9 @@ pub fn window_event( Some(Event::Window(window::Event::Moved(Point::new(x, y)))) } + WindowEvent::ThemeChanged(theme) => Some(Event::Window( + window::Event::ThemeModeChanged(theme_mode(theme)), + )), _ => None, } } @@ -440,6 +444,16 @@ pub fn mode(mode: Option) -> window::Mode { } } +/// Converts a [`winit`] window theme to 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 [`mouse::Interaction`] to a [`winit`] cursor icon. /// /// [`winit`]: https://github.com/rust-windowing/winit diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index 6adc2205..65f08d21 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -20,8 +20,8 @@ where viewport_version: u64, cursor_position: Option>, modifiers: winit::keyboard::ModifiersState, - theme: P::Theme, - theme_mode: theme::Mode, + theme: Option, + system_theme: P::Theme, style: theme::Style, } @@ -30,7 +30,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) @@ -53,15 +53,13 @@ where ) -> Self { let title = program.title(window_id); let scale_factor = program.scale_factor(window_id); - let theme_mode = match window.theme() { - None => theme::Mode::None, - Some(winit::window::Theme::Light) => theme::Mode::Light, - Some(winit::window::Theme::Dark) => theme::Mode::Dark, - }; - let theme = program - .theme(window_id) - .unwrap_or_else(|| ::default(theme_mode)); - let style = program.style(&theme); + let theme_mode = window + .theme() + .map(conversion::theme_mode) + .unwrap_or_default(); + let theme = program.theme(window_id); + let system_theme = ::default(theme_mode); + let style = program.style(theme.as_ref().unwrap_or(&system_theme)); let viewport = { let physical_size = window.inner_size(); @@ -80,7 +78,7 @@ where cursor_position: None, modifiers: winit::keyboard::ModifiersState::default(), theme, - theme_mode, + system_theme, style, } } @@ -132,7 +130,7 @@ where /// Returns the current theme of the [`State`]. pub fn theme(&self) -> &P::Theme { - &self.theme + self.theme.as_ref().unwrap_or(&self.system_theme) } /// Returns the current background [`Color`] of the [`State`]. @@ -183,6 +181,15 @@ where WindowEvent::ModifiersChanged(new_modifiers) => { self.modifiers = new_modifiers.state(); } + WindowEvent::ThemeChanged(theme) => { + self.system_theme = ::default( + conversion::theme_mode(*theme), + ); + + if self.theme.is_none() { + window.request_redraw(); + } + } _ => {} } } @@ -225,9 +232,7 @@ where } // Update theme and appearance - self.theme = program.theme(window_id).unwrap_or_else(|| { - ::default(self.theme_mode) - }); - self.style = program.style(&self.theme); + self.theme = program.theme(window_id); + self.style = program.style(self.theme()); } } From ab7eb88951a7e184c444f735986ff1183e7d9d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 06:07:41 +0200 Subject: [PATCH 08/16] Use lighter color for link in `tour` example --- examples/tour/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index 56e14f06..78c329b5 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -220,7 +220,7 @@ impl Tour { "Additionally, this tour can also run on WebAssembly ", "by leveraging ", span("trunk") - .color(color!(0x0000FF)) + .color(color!(0x7777FF)) .underline(true) .font(Font::MONOSPACE) .link(Message::OpenTrunk), From e92c87061d2c62529141106e346c31f2e4a2008e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 09:49:11 +0200 Subject: [PATCH 09/16] Add `linux-theme-detection` feature through `mundy` --- Cargo.lock | 477 ++++++++++++++++++++++++++++++++++++-- Cargo.toml | 7 +- runtime/src/lib.rs | 8 + winit/Cargo.toml | 5 + winit/src/conversion.rs | 29 ++- winit/src/lib.rs | 57 ++++- winit/src/window.rs | 3 +- winit/src/window/state.rs | 30 ++- 8 files changed, 566 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8d8bcba..fad67bc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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,6 +199,18 @@ dependencies = [ "libloading", ] +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -285,6 +306,17 @@ dependencies = [ "rustix 1.0.8", ] +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-signal" version = "0.2.12" @@ -309,6 +341,17 @@ version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-tungstenite" version = "0.25.1" @@ -502,6 +545,15 @@ 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" @@ -779,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", ] @@ -1189,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" @@ -1300,6 +1362,33 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equator" version = "0.4.2" @@ -2093,6 +2182,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hexf-parse" version = "0.2.1" @@ -2512,6 +2607,7 @@ dependencies = [ "iced_debug", "iced_program", "log", + "mundy", "rustc-hash 2.1.1", "sysinfo", "thiserror 1.0.69", @@ -3162,6 +3258,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "metal" version = "0.32.0" @@ -3271,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" @@ -3356,6 +3486,19 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nom" version = "7.1.3" @@ -3531,13 +3674,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ "bitflags 2.9.4", - "block2", + "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]] @@ -3547,19 +3709,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ "bitflags 2.9.4", - "block2", + "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", ] @@ -3571,30 +3744,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.9.4", - "block2", + "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", @@ -3613,7 +3831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.9.4", - "block2", + "block2 0.5.1", "dispatch", "libc", "objc2 0.5.2", @@ -3626,7 +3844,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ "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]] @@ -3635,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", ] @@ -3648,7 +3880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ "bitflags 2.9.4", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3660,12 +3892,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.9.4", - "block2", + "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" @@ -3683,15 +3926,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.9.4", - "block2", + "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", @@ -3703,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", ] @@ -3715,7 +3958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.9.4", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", @@ -3852,6 +4095,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "ouroboros" version = "0.18.5" @@ -4962,6 +5215,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -5215,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", @@ -6002,6 +6266,17 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + [[package]] name = "unicase" version = "2.8.1" @@ -6780,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" @@ -6818,6 +7115,17 @@ dependencies = [ "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" @@ -6896,6 +7204,16 @@ 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" @@ -7070,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" @@ -7259,7 +7586,7 @@ dependencies = [ "android-activity", "atomic-waker", "bitflags 2.9.4", - "block2", + "block2 0.5.1", "bytemuck", "calloop", "cfg_aliases", @@ -7273,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", @@ -7436,6 +7763,66 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zbus" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a073be99ace1adc48af593701c8015cd9817df372e14a1a6b0ee8f8bf043be" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "nix", + "ordered-stream", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "windows-sys 0.60.2", + "winnow", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e80cd713a45a49859dcb648053f63265f4f2851b6420d47a958e5697c68b131" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow", + "zvariant", +] + [[package]] name = "zeno" version = "0.3.3" @@ -7545,3 +7932,43 @@ checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core", ] + +[[package]] +name = "zvariant" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn", + "winnow", +] diff --git a/Cargo.toml b/Cargo.toml index 8e952b41..157c59bc 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", "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 @@ -61,7 +61,7 @@ web-colors = ["iced_renderer/web-colors"] 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"] @@ -77,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 @@ -185,6 +187,7 @@ 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.18" diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 457f723c..77e80b8d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -25,6 +25,7 @@ pub use iced_futures as futures; pub use task::Task; pub use user_interface::UserInterface; +use crate::core::theme; use crate::core::widget; use crate::futures::futures::channel::oneshot; @@ -56,6 +57,9 @@ pub enum Action { /// Run a system action. System(system::Action), + /// Change the default system theme mode of all windows. + ChangeTheme(theme::Mode), + /// Recreate all user interfaces and redraw all windows. Reload, @@ -82,6 +86,7 @@ impl Action { Action::Clipboard(action) => Err(Action::Clipboard(action)), Action::Window(action) => Err(Action::Window(action)), Action::System(action) => Err(Action::System(action)), + Action::ChangeTheme(mode) => Err(Action::ChangeTheme(mode)), Action::Reload => Err(Action::Reload), Action::Exit => Err(Action::Exit), } @@ -106,6 +111,9 @@ where } Action::Window(_) => write!(f, "Action::Window"), Action::System(action) => write!(f, "Action::System({action:?})"), + Action::ChangeTheme(mode) => { + write!(f, "Action::ChangeTheme({mode:?})") + } Action::Reload => write!(f, "Action::Reload"), Action::Exit => write!(f, "Action::Exit"), } diff --git a/winit/Cargo.toml b/winit/Cargo.toml index f2157978..85390a0d 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -23,6 +23,7 @@ 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 8668d6a3..feef78bd 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -326,7 +326,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 { @@ -339,7 +339,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( @@ -411,7 +411,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( @@ -426,7 +426,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, @@ -434,7 +434,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 { @@ -444,7 +444,7 @@ pub fn mode(mode: Option) -> window::Mode { } } -/// Converts a [`winit`] window theme to a [`theme::Mode`]. +/// 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 { @@ -454,7 +454,18 @@ pub fn theme_mode(theme: winit::window::Theme) -> theme::Mode { } } -/// Converts a [`mouse::Interaction`] to a [`winit`] cursor icon. +/// 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( @@ -525,7 +536,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, @@ -1196,7 +1207,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. +/// Convertions 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 6f9cea56..a2d58820 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -111,7 +111,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 }; @@ -517,6 +517,33 @@ 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 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::ChangeTheme(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 system_theme = theme::Mode::None; + loop { // Empty the queue if possible let event = if let Ok(event) = event_receiver.try_next() { @@ -604,6 +631,7 @@ async fn run_instance

( .as_mut() .expect("Compositor must be initialized"), exit_on_close_request, + system_theme, ); debug::theme_changed(|| { @@ -891,7 +919,11 @@ async fn run_instance

( &mut is_window_opening, ); } 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, @@ -1465,6 +1497,27 @@ fn run_action<'a, P, C>( let _ = channel.send(Ok(())); } } + Action::ChangeTheme(mode) => { + let Some(theme) = conversion::window_theme(mode) else { + return; + }; + + for (id, window) in window_manager.iter_mut() { + window.raw.set_theme(Some(theme)); + window.state.update( + program, + &window.raw, + &winit::event::WindowEvent::ThemeChanged(theme), + ); + + events.push(( + id, + core::Event::Window(core::window::Event::ThemeModeChanged( + mode, + )), + )); + } + } Action::Reload => { for (id, window) in window_manager.iter_mut() { let Some(ui) = interfaces.remove(&id) else { 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 65f08d21..b3f9af3c 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -21,7 +21,7 @@ where cursor_position: Option>, modifiers: winit::keyboard::ModifiersState, theme: Option, - system_theme: P::Theme, + default_theme: P::Theme, style: theme::Style, } @@ -50,16 +50,18 @@ 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_mode = window .theme() .map(conversion::theme_mode) - .unwrap_or_default(); + .unwrap_or(system_theme); + + let title = program.title(window_id); + let scale_factor = program.scale_factor(window_id); let theme = program.theme(window_id); - let system_theme = ::default(theme_mode); - let style = program.style(theme.as_ref().unwrap_or(&system_theme)); + let default_theme = ::default(theme_mode); + let style = program.style(theme.as_ref().unwrap_or(&default_theme)); let viewport = { let physical_size = window.inner_size(); @@ -78,7 +80,7 @@ where cursor_position: None, modifiers: winit::keyboard::ModifiersState::default(), theme, - system_theme, + default_theme, style, } } @@ -130,7 +132,7 @@ where /// Returns the current theme of the [`State`]. pub fn theme(&self) -> &P::Theme { - self.theme.as_ref().unwrap_or(&self.system_theme) + self.theme.as_ref().unwrap_or(&self.default_theme) } /// Returns the current background [`Color`] of the [`State`]. @@ -144,7 +146,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); @@ -182,9 +189,10 @@ where self.modifiers = new_modifiers.state(); } WindowEvent::ThemeChanged(theme) => { - self.system_theme = ::default( + self.default_theme = ::default( conversion::theme_mode(*theme), ); + self.style = program.style(self.theme()); if self.theme.is_none() { window.request_redraw(); @@ -198,7 +206,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

, From 74425d5cb1ddc12637c4f11adbdc258d693b3dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 10:12:04 +0200 Subject: [PATCH 10/16] Set window theme to match color scheme of active theme --- core/src/theme.rs | 13 ++++++++++++- winit/src/conversion.rs | 2 +- winit/src/lib.rs | 4 ++++ winit/src/window/state.rs | 27 +++++++++++++++++++++++---- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/core/src/theme.rs b/core/src/theme.rs index 5f2fb127..1260bca8 100644 --- a/core/src/theme.rs +++ b/core/src/theme.rs @@ -258,7 +258,10 @@ pub trait Base { /// Returns the default theme for the preferred [`Mode`]. fn default(preference: Mode) -> Self; - /// Returns the default base [`Style`] of a theme. + /// 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. @@ -295,6 +298,14 @@ impl Base for Theme { } } + fn mode(&self) -> Mode { + if self.extended_palette().is_dark { + Mode::Dark + } else { + Mode::Light + } + } + fn base(&self) -> Style { default(self) } diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index feef78bd..654cfb54 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -1207,7 +1207,7 @@ pub fn icon(icon: window::Icon) -> Option { winit::window::Icon::from_rgba(pixels, size.width, size.height).ok() } -/// Convertions some [`input_method::Purpose`] into 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 a2d58820..970366c7 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -634,6 +634,10 @@ async fn run_instance

( 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()) diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index b3f9af3c..683b5352 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, @@ -21,6 +21,7 @@ where cursor_position: Option>, modifiers: winit::keyboard::ModifiersState, theme: Option, + theme_mode: theme::Mode, default_theme: P::Theme, style: theme::Style, } @@ -52,7 +53,7 @@ where window: &Window, system_theme: theme::Mode, ) -> Self { - let theme_mode = window + let system_theme = window .theme() .map(conversion::theme_mode) .unwrap_or(system_theme); @@ -60,7 +61,9 @@ where let title = program.title(window_id); let scale_factor = program.scale_factor(window_id); let theme = program.theme(window_id); - let default_theme = ::default(theme_mode); + 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 = { @@ -80,6 +83,7 @@ where cursor_position: None, modifiers: winit::keyboard::ModifiersState::default(), theme, + theme_mode, default_theme, style, } @@ -135,6 +139,11 @@ where 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`]. pub fn background_color(&self) -> Color { self.style.background_color @@ -192,9 +201,9 @@ where self.default_theme = ::default( conversion::theme_mode(*theme), ); - self.style = program.style(self.theme()); if self.theme.is_none() { + self.style = program.style(&self.default_theme); window.request_redraw(); } } @@ -242,5 +251,15 @@ where // Update theme and appearance self.theme = program.theme(window_id); self.style = program.style(self.theme()); + + if let Some(theme) = &self.theme { + let new_mode = theme::Base::mode(theme); + + if self.theme_mode != new_mode { + window.set_theme(conversion::window_theme(new_mode)); + + self.theme_mode = new_mode; + } + } } } From 7fedb0cc9ba9f1262d14402e043617cd5c6899e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 11:03:45 +0200 Subject: [PATCH 11/16] Fix edge cases when restoring system theme --- examples/styling/src/main.rs | 7 +++++++ winit/src/window/state.rs | 37 ++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index 1465d501..e5805532 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -32,6 +32,7 @@ enum Message { TogglerToggled(bool), PreviousTheme, NextTheme, + ClearTheme, } impl Styling { @@ -67,6 +68,9 @@ impl Styling { } }); } + Message::ClearTheme => { + self.theme = None; + } } } @@ -192,6 +196,9 @@ impl Styling { keyboard::key::Named::ArrowDown | keyboard::key::Named::ArrowRight, ) => Some(Message::NextTheme), + keyboard::Key::Named(keyboard::key::Named::Space) => { + Some(Message::ClearTheme) + } _ => None, }) } diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index 683b5352..4bc28cd4 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -252,14 +252,43 @@ where self.theme = program.theme(window_id); self.style = program.style(self.theme()); - if let Some(theme) = &self.theme { - let new_mode = theme::Base::mode(theme); + let new_mode = self + .theme + .as_ref() + .map(theme::Base::mode) + .unwrap_or_default(); - if self.theme_mode != new_mode { + if self.theme_mode != new_mode { + #[cfg(not(target_os = "linux"))] + { window.set_theme(conversion::window_theme(new_mode)); - self.theme_mode = 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; } } } From b5974a23ccff58f13c3bf9db54fd8b60cb9c9f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 11:22:13 +0200 Subject: [PATCH 12/16] Remove hardcoded colors from `todos` example --- .../snapshots/creates_a_new_task-tiny-skia.sha256 | 2 +- examples/todos/src/main.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) 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..9c57487c 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}; @@ -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 { From 323b17d45849a5096b92437a53e92509436b7494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 12:05:39 +0200 Subject: [PATCH 13/16] Write documentation for new `ThemeFn` traits --- src/application.rs | 14 ++++++++++++-- src/daemon.rs | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/application.rs b/src/application.rs index ef547cea..dfcc4c00 100644 --- a/src/application.rs +++ b/src/application.rs @@ -530,9 +530,19 @@ where } } -/// TODO +/// 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 { - /// TODO + /// 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; } diff --git a/src/daemon.rs b/src/daemon.rs index 2a4451e0..1e4143db 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -317,9 +317,19 @@ where } } -/// TODO +/// 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 { - /// TODO + /// 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; } From 9518573fcef7ee0bc4276c87e7d5ad1ca9b4c9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 12:29:10 +0200 Subject: [PATCH 14/16] Add `Fn` suffix to `application` and `daemon` traits --- src/application.rs | 36 ++++++++++++++++++------------------ src/application/timed.rs | 22 +++++++++++----------- src/daemon.rs | 26 +++++++++++++------------- src/lib.rs | 4 ++-- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/application.rs b/src/application.rs index dfcc4c00..ef15a34a 100644 --- a/src/application.rs +++ b/src/application.rs @@ -75,9 +75,9 @@ 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, @@ -103,9 +103,9 @@ where Message: program::Message + 'static, 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, > { @@ -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, diff --git a/src/application/timed.rs b/src/application/timed.rs index 2aaf40f3..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,10 +20,10 @@ 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, > @@ -71,10 +71,10 @@ where Message: program::Message + '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 1e4143db..08a7d939 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -23,9 +23,9 @@ 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, @@ -51,9 +51,9 @@ where Message: program::Message + 'static, 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; @@ -171,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, > { @@ -268,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, { @@ -292,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, @@ -302,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, diff --git a/src/lib.rs b/src/lib.rs index b0b2bb8d..4ced8d30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -691,8 +691,8 @@ 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 From 09c604c92db07f5e9ed2f6657702a2d68f47836e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 14:32:24 +0200 Subject: [PATCH 15/16] Add `theme` and `theme_changes` functions to `system` --- Cargo.toml | 2 +- core/src/window/event.rs | 4 - examples/events/src/main.rs | 4 +- examples/exit/src/main.rs | 2 +- examples/multi_window/src/main.rs | 2 +- examples/screenshot/src/main.rs | 2 +- examples/system_information/Cargo.toml | 2 +- examples/system_information/src/main.rs | 5 +- examples/todos/src/main.rs | 2 +- futures/src/event.rs | 4 +- futures/src/subscription.rs | 7 +- graphics/src/compositor.rs | 4 +- renderer/src/fallback.rs | 4 +- runtime/src/lib.rs | 8 -- runtime/src/system.rs | 39 +++++- runtime/src/window.rs | 18 +-- src/lib.rs | 7 +- tiny_skia/src/window/compositor.rs | 2 +- wgpu/src/window/compositor.rs | 2 +- winit/Cargo.toml | 2 +- winit/src/conversion.rs | 3 - winit/src/lib.rs | 151 +++++++++++++++++------- winit/src/system.rs | 7 -- winit/src/window/state.rs | 5 - 24 files changed, 186 insertions(+), 102 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 157c59bc..a92f7778 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ 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!) diff --git a/core/src/window/event.rs b/core/src/window/event.rs index 48622b70..45d29179 100644 --- a/core/src/window/event.rs +++ b/core/src/window/event.rs @@ -1,4 +1,3 @@ -use crate::theme; use crate::time::Instant; use crate::{Point, Size}; @@ -72,7 +71,4 @@ pub enum Event { /// /// - **Wayland:** Not implemented. FilesHoveredLeft, - - /// The theme mode of the window has changed. - ThemeModeChanged(theme::Mode), } 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/multi_window/src/main.rs b/examples/multi_window/src/main.rs index d299648e..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, 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/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/todos/src/main.rs b/examples/todos/src/main.rs index 9c57487c..31f20ab6 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -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(), }; 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/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/lib.rs b/runtime/src/lib.rs index 77e80b8d..457f723c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -25,7 +25,6 @@ pub use iced_futures as futures; pub use task::Task; pub use user_interface::UserInterface; -use crate::core::theme; use crate::core::widget; use crate::futures::futures::channel::oneshot; @@ -57,9 +56,6 @@ pub enum Action { /// Run a system action. System(system::Action), - /// Change the default system theme mode of all windows. - ChangeTheme(theme::Mode), - /// Recreate all user interfaces and redraw all windows. Reload, @@ -86,7 +82,6 @@ impl Action { Action::Clipboard(action) => Err(Action::Clipboard(action)), Action::Window(action) => Err(Action::Window(action)), Action::System(action) => Err(Action::System(action)), - Action::ChangeTheme(mode) => Err(Action::ChangeTheme(mode)), Action::Reload => Err(Action::Reload), Action::Exit => Err(Action::Exit), } @@ -111,9 +106,6 @@ where } Action::Window(_) => write!(f, "Action::Window"), Action::System(action) => write!(f, "Action::System({action:?})"), - Action::ChangeTheme(mode) => { - write!(f, "Action::ChangeTheme({mode:?})") - } Action::Reload => write!(f, "Action::Reload"), Action::Exit => write!(f, "Action::Exit"), } 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/lib.rs b/src/lib.rs index 4ced8d30..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 { 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/winit/Cargo.toml b/winit/Cargo.toml index 85390a0d..85f235f7 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -16,7 +16,7 @@ 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"] diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 654cfb54..250918ab 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -319,9 +319,6 @@ pub fn window_event( Some(Event::Window(window::Event::Moved(Point::new(x, y)))) } - WindowEvent::ThemeChanged(theme) => Some(Event::Window( - window::Event::ThemeModeChanged(theme_mode(theme)), - )), _ => None, } } diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 970366c7..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}; @@ -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, @@ -518,7 +526,7 @@ async fn run_instance

( let mut clipboard = Clipboard::unconnected(); #[cfg(all(feature = "linux-theme-detection", target_os = "linux"))] - let system_theme = { + let mut system_theme = { let to_mode = |color_scheme| match color_scheme { mundy::ColorScheme::NoPreference => theme::Mode::None, mundy::ColorScheme::Light => theme::Mode::Light, @@ -528,7 +536,9 @@ async fn run_instance

( runtime.run( mundy::Preferences::stream(mundy::Interest::ColorScheme) .map(move |preferences| { - Action::ChangeTheme(to_mode(preferences.color_scheme)) + Action::System(system::Action::NotifyTheme(to_mode( + preferences.color_scheme, + ))) }) .boxed(), ); @@ -542,7 +552,10 @@ async fn run_instance

( }; #[cfg(not(all(feature = "linux-theme-detection", target_os = "linux")))] - let system_theme = theme::Mode::None; + 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 @@ -728,6 +741,7 @@ async fn run_instance

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

( &mut window_manager, &mut ui_caches, &mut is_window_opening, + &mut system_theme, ); actions += 1; } @@ -895,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!( @@ -912,6 +940,7 @@ async fn run_instance

( id, )), &program, + &mut runtime, &mut compositor, &mut events, &mut messages, @@ -921,6 +950,7 @@ async fn run_instance

( &mut window_manager, &mut ui_caches, &mut is_window_opening, + &mut system_theme, ); } else { window.state.update( @@ -1132,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, @@ -1144,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 { @@ -1458,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); @@ -1501,27 +1555,6 @@ fn run_action<'a, P, C>( let _ = channel.send(Ok(())); } } - Action::ChangeTheme(mode) => { - let Some(theme) = conversion::window_theme(mode) else { - return; - }; - - for (id, window) in window_manager.iter_mut() { - window.raw.set_theme(Some(theme)); - window.state.update( - program, - &window.raw, - &winit::event::WindowEvent::ThemeChanged(theme), - ); - - events.push(( - id, - core::Event::Window(core::window::Event::ThemeModeChanged( - mode, - )), - )); - } - } Action::Reload => { for (id, window) in window_manager.iter_mut() { let Some(ui) = interfaces.remove(&id) else { @@ -1602,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 index 0b476773..ec13c0f3 100644 --- a/winit/src/system.rs +++ b/winit/src/system.rs @@ -3,13 +3,6 @@ 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 { diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index 4bc28cd4..4c3cb403 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -53,11 +53,6 @@ where window: &Window, system_theme: theme::Mode, ) -> Self { - let system_theme = window - .theme() - .map(conversion::theme_mode) - .unwrap_or(system_theme); - let title = program.title(window_id); let scale_factor = program.scale_factor(window_id); let theme = program.theme(window_id); From 1df16356ed4d1cfc125e4e0eb972d970a84697c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 8 Sep 2025 14:35:17 +0200 Subject: [PATCH 16/16] Remove `system` module leftover from `iced_winit` --- winit/src/system.rs | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 winit/src/system.rs diff --git a/winit/src/system.rs b/winit/src/system.rs deleted file mode 100644 index ec13c0f3..00000000 --- a/winit/src/system.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Access the native system. -use crate::graphics::compositor; -use crate::runtime::system::{Action, Information}; -use crate::runtime::{self, Task}; - -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, - } -}