diff --git a/Cargo.lock b/Cargo.lock index 9fddcd2e..b5d874b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,24 +158,28 @@ dependencies = [ ] [[package]] -name = "android-activity" -version = "0.6.0" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android-activity" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", "bitflags 2.11.0", "cc", - "cesu8", - "jni 0.21.1", - "jni-sys 0.3.0", + "jni 0.22.4", "libc", "log", "ndk", "ndk-context", "ndk-sys", "num_enum", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -210,9 +214,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anyhow" @@ -307,7 +311,7 @@ dependencies = [ "url", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "zbus", ] @@ -457,9 +461,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" dependencies = [ "async-io", "async-lock", @@ -775,10 +779,11 @@ checksum = "e79769241dcd44edf79a732545e8b5cec84c247ac060f5252cd51885d093a8fc" [[package]] name = "borsh" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ + "bytes", "cfg_aliases", ] @@ -923,9 +928,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.56" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -1036,18 +1041,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.60" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.60" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstyle", "clap_lex", @@ -1055,9 +1060,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "clipboard-win" @@ -1071,7 +1076,6 @@ dependencies = [ [[package]] name = "clipboard_macos" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#3a7af79e54db6854d8aa9d9e2866a9288d0f95d5" dependencies = [ "objc", "objc-foundation", @@ -1081,22 +1085,12 @@ dependencies = [ [[package]] name = "clipboard_wayland" version = "0.2.2" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#3a7af79e54db6854d8aa9d9e2866a9288d0f95d5" dependencies = [ "dnd", "mime 0.1.0", "smithay-clipboard", ] -[[package]] -name = "clipboard_x11" -version = "0.4.2" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#3a7af79e54db6854d8aa9d9e2866a9288d0f95d5" -dependencies = [ - "thiserror 1.0.69", - "x11rb", -] - [[package]] name = "clock" version = "0.1.0" @@ -1289,34 +1283,31 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=160b086#160b086abe03cd34a8a375d7fbe47b24308d1f38" dependencies = [ "bitflags 2.11.0", "cosmic-protocols", "libc", "smithay-client-toolkit 0.20.0", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", ] [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=160b086#160b086abe03cd34a8a375d7fbe47b24308d1f38" dependencies = [ "bitflags 2.11.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", - "wayland-protocols-wlr 0.3.11", + "wayland-protocols 0.32.12", + "wayland-protocols-wlr 0.3.12", "wayland-scanner", "wayland-server", ] [[package]] name = "cosmic-text" -version = "0.18.2" -source = "git+https://github.com/pop-os/cosmic-text.git#9a2ab09f06905e91f41d64ac6eee887726e7fd76" +version = "0.19.0" dependencies = [ "bitflags 2.11.0", "fontdb", @@ -1324,9 +1315,9 @@ dependencies = [ "linebender_resource_handle", "log", "rangemap", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "self_cell", - "skrifa 0.40.0", + "skrifa", "smol_str", "swash", "sys-locale", @@ -1334,6 +1325,7 @@ dependencies = [ "unicode-linebreak", "unicode-script", "unicode-segmentation", + "unicode-width", ] [[package]] @@ -1440,12 +1432,11 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cryoglyph" version = "0.1.0" -source = "git+https://github.com/pop-os/glyphon.git?tag=cosmic-0.14#c49de15bce4d8254ac136d1be9911960cc85ce12" dependencies = [ "cosmic-text", "etagere", "lru", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "wgpu", ] @@ -1617,7 +1608,6 @@ dependencies = [ [[package]] name = "dnd" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#3a7af79e54db6854d8aa9d9e2866a9288d0f95d5" dependencies = [ "bitflags 2.11.0", "mime 0.1.0", @@ -1652,30 +1642,6 @@ dependencies = [ [[package]] name = "dpi" version = "0.1.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" - -[[package]] -name = "drm" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" -dependencies = [ - "bitflags 2.11.0", - "bytemuck", - "drm-ffi", - "drm-fourcc", - "rustix 0.38.44", -] - -[[package]] -name = "drm-ffi" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" -dependencies = [ - "drm-sys", - "rustix 0.38.44", -] [[package]] name = "drm-fourcc" @@ -1683,16 +1649,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" -[[package]] -name = "drm-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176" -dependencies = [ - "libc", - "linux-raw-sys 0.6.5", -] - [[package]] name = "editor" version = "0.1.0" @@ -1811,9 +1767,9 @@ dependencies = [ [[package]] name = "euclid" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" dependencies = [ "num-traits", ] @@ -1893,9 +1849,9 @@ checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fax" @@ -1981,18 +1937,9 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "font-types" -version = "0.10.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "font-types" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4d2d0cf79d38430cc9dc9aadec84774bff2e1ba30ae2bf6c16cfce9385a23" +checksum = "2d9237c6d82152100c691fb77ea18037b402bcc7257d2c876a4ffac81bc22a1c" dependencies = [ "bytemuck", ] @@ -2192,7 +2139,7 @@ version = "0.1.0" dependencies = [ "iced", "itertools 0.12.1", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "tokio", "tracing-subscriber", ] @@ -2284,9 +2231,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" dependencies = [ "color_quant", "weezl", @@ -2413,35 +2360,18 @@ dependencies = [ "system-deps", ] -[[package]] -name = "gpu-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" -dependencies = [ - "bitflags 2.11.0", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags 2.11.0", -] - [[package]] name = "gpu-allocator" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" dependencies = [ + "ash", + "hashbrown 0.16.1", "log", "presser", - "thiserror 1.0.69", - "windows 0.58.0", + "thiserror 2.0.18", + "windows 0.62.2", ] [[package]] @@ -2690,7 +2620,7 @@ dependencies = [ "bitflags 2.11.0", "bytemuck", "core_maths", - "read-fonts 0.37.0", + "read-fonts", "smallvec", ] @@ -2709,9 +2639,17 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ + "allocator-api2", + "equivalent", "foldhash 0.2.0", ] +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + [[package]] name = "headers" version = "0.3.9" @@ -2865,9 +2803,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", "bytes", @@ -2879,7 +2817,6 @@ dependencies = [ "httparse", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -2892,7 +2829,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http 1.4.0", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "rustls 0.23.37", "rustls-pki-types", @@ -2909,7 +2846,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-util", "native-tls", "tokio", @@ -2929,7 +2866,7 @@ dependencies = [ "futures-util", "http 1.4.0", "http-body 1.0.1", - "hyper 1.8.1", + "hyper 1.9.0", "ipnet", "libc", "percent-encoding", @@ -3032,10 +2969,11 @@ dependencies = [ "num-traits", "palette", "raw-window-handle", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "serde", "smol_str", "thiserror 2.0.18", + "unicode-segmentation", "web-time", "window_clipboard", ] @@ -3068,7 +3006,7 @@ dependencies = [ "futures", "iced_core", "log", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "smol", "tokio", "wasm-bindgen-futures", @@ -3090,7 +3028,7 @@ dependencies = [ "log", "lyon_path", "raw-window-handle", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "thiserror 2.0.18", "unicode-segmentation", ] @@ -3182,7 +3120,7 @@ dependencies = [ "kurbo 0.10.4", "log", "resvg", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "softbuffer", "tiny-skia", ] @@ -3205,13 +3143,13 @@ dependencies = [ "lyon", "raw-window-handle", "resvg", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "rustix 0.38.44", "thiserror 2.0.18", "tiny-xlib", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "wayland-sys", "wgpu", "x11rb", @@ -3232,7 +3170,7 @@ dependencies = [ "ouroboros", "pulldown-cmark", "qrcode", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "thiserror 2.0.18", "unicode-segmentation", "window_clipboard", @@ -3254,14 +3192,14 @@ dependencies = [ "log", "mundy", "raw-window-handle", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "rustix 0.38.44", "sysinfo", "thiserror 2.0.18", "wasm-bindgen-futures", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "web-sys", "winapi", "window_clipboard", @@ -3274,12 +3212,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -3287,9 +3226,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -3300,9 +3239,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -3314,15 +3253,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -3334,15 +3273,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -3390,7 +3329,7 @@ dependencies = [ "byteorder-lite", "color_quant", "exr", - "gif 0.14.1", + "gif 0.14.2", "image-webp", "moxcms", "num-traits", @@ -3401,7 +3340,7 @@ dependencies = [ "rgb", "tiff", "zune-core 0.5.1", - "zune-jpeg 0.5.13", + "zune-jpeg 0.5.15", ] [[package]] @@ -3428,12 +3367,12 @@ checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -3457,9 +3396,9 @@ checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" dependencies = [ "memchr", "serde", @@ -3524,9 +3463,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" @@ -3578,7 +3517,7 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys 0.3.0", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", @@ -3587,9 +3526,9 @@ dependencies = [ [[package]] name = "jni" -version = "0.22.3" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295dc9997acda1562fdf8d299f56063c936443b60f078e63a5d8d3c34ef2642b" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" dependencies = [ "cfg-if", "combine", @@ -3604,9 +3543,9 @@ dependencies = [ [[package]] name = "jni-macros" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3d1da60c95c98847b26b9d45f4360fee718b31de746df016d9cd6de916a7ef" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" dependencies = [ "proc-macro2", "quote", @@ -3617,9 +3556,12 @@ dependencies = [ [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] [[package]] name = "jni-sys" @@ -3652,10 +3594,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -3760,9 +3704,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libfuzzer-sys" @@ -3792,14 +3736,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.14" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "bitflags 2.11.0", "libc", "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.9.0", ] [[package]] @@ -3829,12 +3773,6 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" -[[package]] -name = "linux-raw-sys" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -3850,9 +3788,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "litrs" @@ -3951,9 +3889,9 @@ dependencies = [ [[package]] name = "lyon_tessellation" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a35a7dd71b845ff317ce1834c4185506b79790294bde397df8d5c23031e357" +checksum = "8e43b7e44161571868f5c931d12583592c223c5583eef86b08aa02b7048a3552" dependencies = [ "float_next_after", "lyon_path", @@ -4044,9 +3982,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" +checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ "bitflags 2.11.0", "block", @@ -4060,7 +3998,6 @@ dependencies = [ [[package]] name = "mime" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#3a7af79e54db6854d8aa9d9e2866a9288d0f95d5" dependencies = [ "smithay-clipboard", ] @@ -4093,9 +4030,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi", @@ -4192,9 +4129,9 @@ checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" [[package]] name = "naga" -version = "27.0.3" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" +checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", @@ -4240,7 +4177,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.11.0", - "jni-sys 0.3.0", + "jni-sys 0.3.1", "log", "ndk-sys", "num_enum", @@ -4260,7 +4197,7 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys 0.3.0", + "jni-sys 0.3.1", ] [[package]] @@ -4314,9 +4251,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-derive" @@ -4361,9 +4298,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -4371,9 +4308,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4753,9 +4690,9 @@ dependencies = [ [[package]] name = "orbclient" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ad2c6bae700b7aa5d1cc30c59bdd3a1c180b09dbaea51e2ae2b8e1cf211fdd" +checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6" dependencies = [ "libc", "libredox", @@ -4763,9 +4700,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "5.1.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" dependencies = [ "num-traits", ] @@ -5114,18 +5051,18 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" dependencies = [ "portable-atomic", ] [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -5475,16 +5412,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "read-fonts" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" -dependencies = [ - "bytemuck", - "font-types 0.10.1", -] - [[package]] name = "read-fonts" version = "0.37.0" @@ -5493,7 +5420,17 @@ checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ "bytemuck", "core_maths", - "font-types 0.11.0", + "font-types", +] + +[[package]] +name = "redox_event" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5018d583d6d2f5499352aea8d177e9067d1eb03ab17c78169d5ba7a30001b15" +dependencies = [ + "bitflags 2.11.0", + "libredox", ] [[package]] @@ -5507,9 +5444,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" dependencies = [ "bitflags 2.11.0", ] @@ -5586,7 +5523,7 @@ dependencies = [ "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.8.1", + "hyper 1.9.0", "hyper-rustls", "hyper-tls", "hyper-util", @@ -5692,9 +5629,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -5753,7 +5690,7 @@ checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.9", + "rustls-webpki 0.103.11", "subtle", "zeroize", ] @@ -5780,9 +5717,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "20a6af516fea4b20eccceaf166e8aa666ac996208e8a644ce3ef5aa783bc7cd4" dependencies = [ "ring", "rustls-pki-types", @@ -5999,9 +5936,9 @@ checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -6063,9 +6000,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -6139,9 +6076,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "simd_cesu8" @@ -6193,16 +6130,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "skrifa" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" -dependencies = [ - "bytemuck", - "read-fonts 0.35.0", -] - [[package]] name = "skrifa" version = "0.40.0" @@ -6210,7 +6137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", - "read-fonts 0.37.0", + "read-fonts", ] [[package]] @@ -6289,10 +6216,10 @@ dependencies = [ "wayland-client", "wayland-csd-frame", "wayland-cursor", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "wayland-protocols-experimental", "wayland-protocols-misc", - "wayland-protocols-wlr 0.3.11", + "wayland-protocols-wlr 0.3.12", "wayland-scanner", "xkbcommon 0.8.0", "xkeysym", @@ -6301,7 +6228,6 @@ dependencies = [ [[package]] name = "smithay-clipboard" version = "0.8.0" -source = "git+https://github.com/pop-os/smithay-clipboard?tag=sctk-0.20#859b02c88f45c554049a67c6ddeec1692ce0e20b" dependencies = [ "libc", "raw-window-handle", @@ -6359,14 +6285,12 @@ dependencies = [ [[package]] name = "softbuffer" version = "0.4.1" -source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#a3f77e251e7422803f693df6e3fc313c010c4dcb" dependencies = [ "as-raw-xcb-connection", "bytemuck", "cfg_aliases", "cocoa", "core-graphics", - "drm", "fastrand", "foreign-types 0.5.0", "js-sys", @@ -6449,9 +6373,9 @@ dependencies = [ [[package]] name = "subsecond" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8438668e545834d795d04c4335aafc332ce046106521a29f0a5c6501de34187c" +checksum = "5dbb9f2928b6654ccc28d4ddfef5213e97ed66afed4907774d049b376c62a838" dependencies = [ "js-sys", "libc", @@ -6468,9 +6392,9 @@ dependencies = [ [[package]] name = "subsecond-types" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e72f747606fc19fe81d6c59e491af93ed7dcbcb6aad9d1d18b05129914ec298" +checksum = "388bb28e6ddbee717745963b8932d9a6e24a5d3c93350655f733e938de04d81f" dependencies = [ "serde", ] @@ -6506,11 +6430,11 @@ dependencies = [ [[package]] name = "swash" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47846491253e976bdd07d0f9cc24b7daf24720d11309302ccbbc6e6b6e53550a" +checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" dependencies = [ - "skrifa 0.37.0", + "skrifa", "yazi", "zeno", ] @@ -6613,9 +6537,9 @@ dependencies = [ [[package]] name = "system-deps" -version = "7.0.7" +version = "7.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c8f33736f986f16d69b6cb8b03f55ddcad5c41acc4ccc39dd88e84aa805e7f" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" dependencies = [ "cfg-expr", "heck 0.5.0", @@ -6728,7 +6652,7 @@ dependencies = [ "half", "quick-error", "weezl", - "zune-jpeg 0.5.13", + "zune-jpeg 0.5.15", ] [[package]] @@ -6803,9 +6727,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -6823,9 +6747,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -6861,9 +6785,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.50.0" +version = "1.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" dependencies = [ "bytes", "libc", @@ -6877,9 +6801,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -6955,63 +6879,54 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.12+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime", "toml_parser", "toml_writer", - "winnow", + "winnow 1.0.1", ] [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_datetime" -version = "1.0.0+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.4+spec-1.1.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ "indexmap", - "toml_datetime 1.0.0+spec-1.1.0", + "toml_datetime", "toml_parser", - "winnow", + "winnow 1.0.1", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.1", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tooltip" @@ -7122,9 +7037,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -7189,9 +7104,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "uds_windows" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b70b87d15e91f553711b40df3048faf27a7a04e01e0ddc0cf9309f0af7c2ca" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", @@ -7248,9 +7163,9 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-vo" @@ -7342,9 +7257,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -7490,9 +7405,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -7503,23 +7418,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7527,9 +7438,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -7540,9 +7451,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -7610,9 +7521,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa75f400b7f719bcd68b3f47cd939ba654cedeef690f486db71331eec4c6a406" +checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" dependencies = [ "cc", "downcast-rs", @@ -7624,9 +7535,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.13" +version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab51d9f7c071abeee76007e2b742499e535148035bb835f97aaed1338cf516c3" +checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ "bitflags 2.11.0", "rustix 1.1.4", @@ -7647,9 +7558,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.13" +version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b3298683470fbdc6ca40151dfc48c8f2fd4c41a26e13042f801f85002384091" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" dependencies = [ "rustix 1.1.4", "wayland-client", @@ -7670,9 +7581,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.11" +version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23b5df31ceff1328f06ac607591d5ba360cf58f90c8fad4ac8d3a55a3c4aec7" +checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ "bitflags 2.11.0", "wayland-backend", @@ -7690,33 +7601,33 @@ dependencies = [ "bitflags 2.11.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "wayland-scanner", ] [[package]] name = "wayland-protocols-misc" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "429b99200febaf95d4f4e46deff6fe4382bcff3280ee16a41cf887b3c3364984" +checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" dependencies = [ "bitflags 2.11.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "wayland-scanner", ] [[package]] name = "wayland-protocols-plasma" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d392fc283a87774afc9beefcd6f931582bb97fe0e6ced0b306a62cb1d026527c" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ "bitflags 2.11.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "wayland-scanner", ] @@ -7735,23 +7646,23 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78248e4cc0eff8163370ba5c158630dcae1f3497a586b826eca2ef5f348d6235" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ "bitflags 2.11.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "wayland-scanner", "wayland-server", ] [[package]] name = "wayland-scanner" -version = "0.31.9" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86287151a309799b821ca709b7345a048a2956af05957c89cb824ab919fa4e3" +checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" dependencies = [ "proc-macro2", "quick-xml 0.39.2", @@ -7760,9 +7671,9 @@ dependencies = [ [[package]] name = "wayland-server" -version = "0.31.12" +version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63736a4a73e781cf6a736aa32c5d6773c3eb5389197562742a8c611b49b5e359" +checksum = "cc1846eb04c49182e04f4a099e2a830a2b745610bbc1d61246e206f29c7000a0" dependencies = [ "bitflags 2.11.0", "downcast-rs", @@ -7773,9 +7684,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.10" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" dependencies = [ "dlib", "log", @@ -7785,9 +7696,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -7810,7 +7721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe985f41e291eecef5e5c0770a18d28390addb03331c043964d9e916453d6f16" dependencies = [ "core-foundation 0.10.1", - "jni 0.22.3", + "jni 0.22.4", "log", "ndk-context", "objc2 0.6.4", @@ -7855,12 +7766,13 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wgpu" -version = "27.0.1" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" +checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" dependencies = [ "arrayvec", "bitflags 2.11.0", + "bytemuck", "cfg-if", "cfg_aliases", "document-features", @@ -7884,9 +7796,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "27.0.3" +version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" +checksum = "d23f4642f53f666adcfd2d3218ab174d1e6681101aef18696b90cbe64d1c10f9" dependencies = [ "arrayvec", "bit-set", @@ -7917,45 +7829,45 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233" +checksum = "87b7b696b918f337c486bf93142454080a32a37832ba8a31e4f48221890047da" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-emscripten" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5" +checksum = "34b251c331f84feac147de3c4aa3aa45112622a95dd7ee1b74384fa0458dbd79" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-wasm" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1027dcf3b027a877e44819df7ceb0e2e98578830f8cd34cd6c3c7c2a7a50b7" +checksum = "12a2cf578ce8d7d50d0e63ddc2345c7dcb599f6eb90b888813406ea78b9b7010" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3" +checksum = "68ca976e72b2c9964eb243e281f6ce7f14a514e409920920dcda12ae40febaae" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "27.0.4" +version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b21cb61c57ee198bc4aff71aeadff4cbb80b927beb912506af9c780d64313ce" +checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" dependencies = [ "android_system_properties", "arrayvec", @@ -7969,7 +7881,6 @@ dependencies = [ "core-graphics-types 0.2.0", "glow", "glutin_wgl_sys", - "gpu-alloc", "gpu-allocator", "gpu-descriptor", "hashbrown 0.16.1", @@ -7996,21 +7907,20 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "windows 0.58.0", - "windows-core 0.58.0", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] name = "wgpu-types" -version = "27.0.1" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" +checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" dependencies = [ "bitflags 2.11.0", "bytemuck", "js-sys", "log", - "thiserror 2.0.18", "web-sys", ] @@ -8048,12 +7958,10 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" version = "0.4.1" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#3a7af79e54db6854d8aa9d9e2866a9288d0f95d5" dependencies = [ "clipboard-win", "clipboard_macos", "clipboard_wayland", - "clipboard_x11", "dnd", "mime 0.1.0", "raw-window-handle", @@ -8070,16 +7978,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.61.3" @@ -8135,19 +8033,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-core" version = "0.61.2" @@ -8207,17 +8092,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-implement" version = "0.60.2" @@ -8240,17 +8114,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.3" @@ -8314,15 +8177,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -8341,16 +8195,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -8621,7 +8465,6 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "bitflags 2.11.0", "cfg_aliases", @@ -8647,7 +8490,6 @@ dependencies = [ [[package]] name = "winit-android" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "android-activity", "bitflags 2.11.0", @@ -8662,7 +8504,6 @@ dependencies = [ [[package]] name = "winit-appkit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "bitflags 2.11.0", "block2 0.6.2", @@ -8684,7 +8525,6 @@ dependencies = [ [[package]] name = "winit-common" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "memmap2 0.9.10", "objc2 0.6.4", @@ -8699,7 +8539,6 @@ dependencies = [ [[package]] name = "winit-core" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "bitflags 2.11.0", "cursor-icon", @@ -8713,14 +8552,13 @@ dependencies = [ [[package]] name = "winit-orbital" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "bitflags 2.11.0", "dpi", "libredox", "orbclient", "raw-window-handle", - "redox_syscall 0.7.3", + "redox_event", "smol_str", "tracing", "winit-core", @@ -8729,7 +8567,6 @@ dependencies = [ [[package]] name = "winit-uikit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "bitflags 2.11.0", "block2 0.6.2", @@ -8749,7 +8586,6 @@ dependencies = [ [[package]] name = "winit-wayland" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "ahash", "bitflags 2.11.0", @@ -8766,7 +8602,7 @@ dependencies = [ "tracing", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.11", + "wayland-protocols 0.32.12", "wayland-protocols-plasma", "winit-common", "winit-core", @@ -8775,7 +8611,6 @@ dependencies = [ [[package]] name = "winit-web" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "atomic-waker", "bitflags 2.11.0", @@ -8797,7 +8632,6 @@ dependencies = [ [[package]] name = "winit-win32" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "bitflags 2.11.0", "cursor-icon", @@ -8813,7 +8647,6 @@ dependencies = [ [[package]] name = "winit-x11" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#a610ac9c7a72b39ff102ed4d946291618dc725b6" dependencies = [ "bitflags 2.11.0", "bytemuck", @@ -8842,6 +8675,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.51.0" @@ -8932,9 +8774,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "x11-dl" @@ -9060,9 +8902,9 @@ checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -9071,9 +8913,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -9110,7 +8952,7 @@ dependencies = [ "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow", + "winnow 0.7.15", "zbus_macros", "zbus_names", "zvariant", @@ -9162,7 +9004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" dependencies = [ "serde", - "winnow", + "winnow 0.7.15", "zvariant", ] @@ -9186,18 +9028,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.42" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.42" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -9206,18 +9048,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -9233,9 +9075,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -9244,9 +9086,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -9255,9 +9097,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", @@ -9302,9 +9144,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core 0.5.1", ] @@ -9319,7 +9161,7 @@ dependencies = [ "enumflags2", "serde", "url", - "winnow", + "winnow 0.7.15", "zvariant_derive", "zvariant_utils", ] @@ -9347,5 +9189,9 @@ dependencies = [ "quote", "serde", "syn", - "winnow", + "winnow 0.7.15", ] + +[[patch.unused]] +name = "cosmic-freedesktop-icons" +version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 49b4b5d7..c49fcf92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,7 +120,7 @@ winit = [ ] wayland = ["iced_renderer/wayland", "iced_winit/wayland"] cctk = ["iced_winit/cctk", "iced_widget/cctk", "iced_core/cctk", "wayland"] -# Enables the sctk shell. +# Enables the sctk shell. [dependencies] @@ -202,7 +202,7 @@ repository = "https://github.com/iced-rs/iced" homepage = "https://iced.rs" categories = ["gui"] keywords = ["gui", "ui", "graphics", "interface", "widgets"] -rust-version = "1.89" +rust-version = "1.92" [workspace.dependencies] iced = { version = "0.14.0", path = "." } @@ -238,10 +238,9 @@ async-std = "1.0" bitflags = "2.5" bytemuck = { version = "1.0", features = ["derive"] } bytes = "1.6" -cosmic-text = { git = "https://github.com/pop-os/cosmic-text.git" } -# cosmic-text = "0.10" +cosmic-text = { path = "../../cosmic-text" } +cryoglyph = { package = "cryoglyph", path = "../../glyphon" } dark-light = "1.0" -cryoglyph = { package = "cryoglyph", git = "https://github.com/pop-os/glyphon.git", tag = "cosmic-0.14" } resvg = "0.45" web-sys = "0.3.69" guillotiere = "0.6" @@ -275,8 +274,11 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "std", "simd", ] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "160b086" } -softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0" } +cctk = { path = "../../cosmic-protocols/client-toolkit", package = "cosmic-client-toolkit" } +# Yoda: default-features=false drops softbuffer's x11 / x11-dlopen (pulled +# tiny-xlib + as-raw-xcb-connection). The wayland + wayland-dlopen features +# are re-activated via iced_tiny_skia's own `wayland` feature propagation. +softbuffer = { path = "../../softbuffer", default-features = false } syntect = "5.2" tokio = "1.0" tracing = "0.1" @@ -288,7 +290,7 @@ url = "2.5" wasm-bindgen-futures = "0.4" wasmtimer = "0.4.2" web-time = "1.1" -wgpu = { version = "27.0", default-features = false, features = [ +wgpu = { version = "28.0", default-features = false, features = [ "std", "wgsl", ] } @@ -302,13 +304,40 @@ wayland-client = { version = "0.31.5" } winapi = "0.3" # window_clipboard = "0.4.1" -window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } -dnd = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } -mime = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } -winit = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } -winit-core = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } +# Yoda: window_clipboard pinned to our public fork that has x11 gated behind +# an opt-in feature. default-features=false + features=["wayland"] drops +# clipboard_x11 + x11rb from the build. Branch yoda-x11-optional on +# https://forge.aditua.com/leyoda/window_clipboard. +window_clipboard = { path = "../../window_clipboard", default-features = false, features = ["wayland"] } +dnd = { path = "../../window_clipboard/dnd" } +mime = { path = "../../window_clipboard/mime" } +# Yoda: default-features = false drops winit's x11 default, which otherwise +# pulls winit-x11, x11-dl, tiny-xlib, as-raw-xcb-connection. Our Wayland-only +# fork doesn't need any of that — the wayland + wayland-dlopen features are +# re-enabled via iced_winit's own feature propagation from libcosmic-yoda. +winit = { path = "../../winit/winit", default-features = false } +winit-core = { path = "../../winit/winit-core" } cursor-icon = "1.1.0" +[patch.'https://github.com/pop-os/softbuffer'] +softbuffer = { path = "../../softbuffer" } + +[patch.'https://github.com/pop-os/smithay-clipboard'] +smithay-clipboard = { path = "../../smithay-clipboard" } + +[patch.'https://github.com/pop-os/winit.git'] +dpi = { path = "../../winit/dpi" } +winit = { path = "../../winit/winit" } +winit-android = { path = "../../winit/winit-android" } +winit-appkit = { path = "../../winit/winit-appkit" } +winit-common = { path = "../../winit/winit-common" } +winit-core = { path = "../../winit/winit-core" } +winit-orbital = { path = "../../winit/winit-orbital" } +winit-uikit = { path = "../../winit/winit-uikit" } +winit-wayland = { path = "../../winit/winit-wayland" } +winit-web = { path = "../../winit/winit-web" } +winit-win32 = { path = "../../winit/winit-win32" } +winit-x11 = { path = "../../winit/winit-x11" } [workspace.lints.rust] rust_2018_idioms = { level = "deny", priority = -1 } diff --git a/core/Cargo.toml b/core/Cargo.toml index e64a5c37..0a376b7c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -31,6 +31,7 @@ num-traits.workspace = true rustc-hash.workspace = true smol_str.workspace = true thiserror.workspace = true +unicode-segmentation.workspace = true web-time.workspace = true serde.workspace = true diff --git a/core/src/element.rs b/core/src/element.rs index f97ed6bc..dbe449c5 100644 --- a/core/src/element.rs +++ b/core/src/element.rs @@ -1,4 +1,4 @@ -use crate::event::{self, Event}; +use crate::event::Event; use crate::id::Id; use crate::layout; use crate::mouse; diff --git a/core/src/event/wayland/mod.rs b/core/src/event/wayland/mod.rs index 03e74407..5050ce66 100644 --- a/core/src/event/wayland/mod.rs +++ b/core/src/event/wayland/mod.rs @@ -46,4 +46,6 @@ pub enum Event { Subsurface(SubsurfaceEvent), /// Keyboard inhibit shortcuts ShortcutsInhibited(bool), + /// Blur Support Enabled + BlurEnabled, } diff --git a/core/src/overlay/group.rs b/core/src/overlay/group.rs index ec0906e7..1a4ce672 100644 --- a/core/src/overlay/group.rs +++ b/core/src/overlay/group.rs @@ -3,7 +3,7 @@ use crate::mouse; use crate::overlay; use crate::renderer; use crate::widget; -use crate::{Clipboard, Event, Layout, Overlay, Point, Rectangle, Shell, Size}; +use crate::{Clipboard, Event, Layout, Overlay, Shell, Size}; /// An [`Overlay`] container that displays multiple overlay [`overlay::Element`] /// children. diff --git a/core/src/text/editor.rs b/core/src/text/editor.rs index e0b87756..ff89af01 100644 --- a/core/src/text/editor.rs +++ b/core/src/text/editor.rs @@ -78,6 +78,8 @@ pub enum Action { SelectLine, /// Select the entire buffer. SelectAll, + /// Clear the selection + ClearSelection, /// Perform an [`Edit`]. Edit(Edit), /// Click the [`Editor`] at the given [`Point`]. diff --git a/core/src/widget/operation/search_id.rs b/core/src/widget/operation/search_id.rs index 1286abaf..e03fac8a 100644 --- a/core/src/widget/operation/search_id.rs +++ b/core/src/widget/operation/search_id.rs @@ -4,7 +4,7 @@ use super::Operation; use crate::{ Rectangle, id::Id, - widget::operation::{Outcome, focusable::Count}, + widget::operation::Outcome, }; /// Produces an [`Operation`] that searches for the Id diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 1e40bf9e..2ba0ada4 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -22,16 +22,18 @@ //! ``` use crate::alignment; use crate::layout; -use crate::mouse; +use crate::mouse::{self, click}; use crate::renderer; +use crate::text; use crate::text::paragraph::{self, Paragraph}; -use crate::text::{self, Fragment}; use crate::widget::tree::{self, Tree}; use crate::{ - Color, Element, Layout, Length, Pixels, Rectangle, Size, Theme, Widget, + Clipboard, Color, Element, Event, Layout, Length, Pixels, Point, Rectangle, + Shell, Size, Theme, Widget, keyboard, touch, }; -use std::borrow::Cow; +use unicode_segmentation::UnicodeSegmentation; + pub use text::{Alignment, Ellipsize, LineHeight, Shaping, Wrapping}; /// A bunch of text. @@ -65,6 +67,7 @@ where fragment: text::Fragment<'a>, format: Format, class: Theme::Class<'a>, + selectable: bool, } impl<'a, Theme, Renderer> Text<'a, Theme, Renderer> @@ -79,6 +82,7 @@ where fragment: fragment.into_fragment(), format: Format::default(), class: Theme::default(), + selectable: false, } } @@ -189,7 +193,17 @@ where { let color = color.map(Into::into); - self.style(move |_theme| Style { color }) + self.style(move |_theme| Style { + color, + ..Style::default() + }) + } + + /// Makes the [`Text`] selectable. When enabled, the user can click and + /// drag to select text, and copy it with Ctrl+C / Cmd+C. + pub fn selectable(mut self) -> Self { + self.selectable = true; + self } /// Sets the style class of the [`Text`]. @@ -202,7 +216,114 @@ where } /// The internal state of a [`Text`] widget. -pub type State

= paragraph::Plain

; +pub struct State { + /// The cached paragraph layout. + pub paragraph: paragraph::Plain

, + /// Lazily allocated when text is selectable and first interacted with. + selection: Option>, + focused: bool, + keyboard_focused: bool, + context_menu_position: Option, +} + +impl Default for State

{ + fn default() -> Self { + Self { + paragraph: paragraph::Plain::default(), + selection: None, + focused: false, + keyboard_focused: false, + context_menu_position: None, + } + } +} + +impl std::fmt::Debug for State

{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("State") + .field("selection", &self.selection) + .field("focused", &self.focused) + .finish_non_exhaustive() + } +} + +impl State

{ + /// Returns `true` if the widget currently has focus. + pub fn is_focused(&self) -> bool { + self.focused + } + + /// Returns `true` if focus was gained via keyboard navigation (Tab). + pub fn is_keyboard_focused(&self) -> bool { + self.keyboard_focused + } + + /// Clears focus, selection, and all interaction state. + pub fn clear_focus(&mut self) { + self.focused = false; + self.keyboard_focused = false; + self.context_menu_position = None; + if let Some(sel) = &mut self.selection { + sel.clear(); + } + } + + /// Returns the context menu position, if a context menu should be shown. + pub fn context_menu_position(&self) -> Option { + self.context_menu_position + } + + /// Sets or clears the context menu position. + pub fn set_context_menu_position(&mut self, pos: Option) { + self.context_menu_position = pos; + } +} + +impl std::ops::Deref for State

{ + type Target = paragraph::Plain

; + + fn deref(&self) -> ¶graph::Plain

{ + &self.paragraph + } +} + +impl std::ops::DerefMut for State

{ + fn deref_mut(&mut self) -> &mut paragraph::Plain

{ + &mut self.paragraph + } +} + +#[derive(Debug, Clone, Default)] +struct SelectionState { + anchor: usize, + end: usize, + dragging: bool, + modifiers: keyboard::Modifiers, + last_click: Option, +} + +impl SelectionState { + fn clear(&mut self) { + self.anchor = 0; + self.end = 0; + self.dragging = false; + } +} + +impl crate::widget::operation::Focusable for State

{ + fn is_focused(&self) -> bool { + self.focused + } + + fn focus(&mut self) { + self.focused = true; + self.keyboard_focused = true; + } + + fn unfocus(&mut self) { + self.clear_focus(); + } +} impl Widget for Text<'_, Theme, Renderer> @@ -215,7 +336,7 @@ where } fn state(&self) -> tree::State { - tree::State::new(paragraph::Plain::::default()) + tree::State::new(State::::default()) } fn size(&self) -> Size { @@ -231,8 +352,10 @@ where renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { + let state = tree.state.downcast_mut::>(); + layout( - tree.state.downcast_mut::>(), + &mut state.paragraph, renderer, limits, &self.fragment, @@ -252,25 +375,325 @@ where ) { let state = tree.state.downcast_ref::>(); let style = theme.style(&self.class); + let bounds = layout.bounds(); + let paragraph = state.paragraph.raw(); + if let Some(sel) = &state.selection { + let left = sel.anchor.min(sel.end); + let right = sel.anchor.max(sel.end); + let content: &str = self.fragment.as_ref(); - draw( - renderer, - defaults, - layout.bounds(), - state.raw(), - style, - viewport, - ); + if left != right { + let lo_byte = grapheme_to_byte(content, left); + let hi_byte = grapheme_to_byte(content, right); + + let anchor = bounds.anchor( + paragraph.min_bounds(), + paragraph.align_x(), + paragraph.align_y(), + ); + + let rects = paragraph.highlight( + 0, + (lo_byte, text::Affinity::After), + (hi_byte, text::Affinity::Before), + ); + + for r in rects { + renderer.fill_quad( + renderer::Quad { + bounds: Rectangle { + x: anchor.x + r.x, + y: anchor.y + r.y, + width: r.width, + height: r.height, + }, + ..renderer::Quad::default() + }, + style.selected_fill, + ); + } + } + } + + draw(renderer, defaults, bounds, paragraph, style, viewport); + } + + fn update( + &mut self, + tree: &mut Tree, + event: &Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + _renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + _viewport: &Rectangle, + ) { + if !self.selectable { + return; + } + + let state = tree.state.downcast_mut::>(); + let bounds = layout.bounds(); + let content: &str = self.fragment.as_ref(); + let grapheme_count = content.graphemes(true).count(); + let paragraph = state.paragraph.raw(); + + // Any click outside this widget clears selection and focus. + if matches!( + event, + Event::Mouse(mouse::Event::ButtonPressed(_)) + | Event::Touch(touch::Event::FingerPressed { .. }) + ) { + if cursor.position_over(bounds).is_none() { + state.focused = false; + state.keyboard_focused = false; + if let Some(sel) = &mut state.selection { + sel.clear(); + } + } + } + + match event { + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + if state.context_menu_position.take().is_some() { + shell.capture_event(); + return; + } + + if let Some(pos) = cursor.position_over(bounds) { + let sel = state.selection.get_or_insert_with(|| { + Box::new(SelectionState::default()) + }); + + let anchor = bounds.anchor( + paragraph.min_bounds(), + paragraph.align_x(), + paragraph.align_y(), + ); + let relative = + Point::new(pos.x - anchor.x, pos.y - anchor.y); + + let grapheme_pos = + hit_to_grapheme(paragraph, relative, content); + + let new_click = click::Click::new( + pos, + mouse::Button::Left, + sel.last_click.take(), + ); + + match new_click.kind() { + click::Kind::Single => { + if sel.modifiers.shift() { + sel.end = grapheme_pos; + } else { + sel.anchor = grapheme_pos; + sel.end = grapheme_pos; + } + sel.dragging = true; + } + click::Kind::Double => { + sel.anchor = + previous_start_of_word(content, grapheme_pos); + sel.end = next_end_of_word(content, grapheme_pos); + sel.dragging = true; + } + click::Kind::Triple => { + sel.anchor = 0; + sel.end = grapheme_count; + sel.dragging = true; + } + } + + sel.last_click = Some(new_click); + state.focused = true; + state.keyboard_focused = false; + shell.capture_event(); + } + } + + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) => { + if let Some(pos) = cursor.position_over(bounds) { + state.context_menu_position = Some(pos); + state.focused = true; + state.keyboard_focused = false; + shell.capture_event(); + } + } + + Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerLifted { .. }) => { + if let Some(sel) = &mut state.selection { + sel.dragging = false; + } + } + + Event::Mouse(mouse::Event::CursorMoved { position }) + | Event::Touch(touch::Event::FingerMoved { position, .. }) => { + if let Some(sel) = &mut state.selection { + if sel.dragging { + let anchor = bounds.anchor( + paragraph.min_bounds(), + paragraph.align_x(), + paragraph.align_y(), + ); + let relative = Point::new( + position.x - anchor.x, + position.y - anchor.y, + ); + + sel.end = hit_to_grapheme(paragraph, relative, content); + shell.capture_event(); + } + } + } + + Event::Keyboard(keyboard::Event::KeyPressed { + key, + modifiers, + physical_key, + text: _, + .. + }) => { + if !state.focused { + return; + } + let sel = state + .selection + .get_or_insert_with(|| Box::new(SelectionState::default())); + + if modifiers.command() { + match key.to_latin(*physical_key) { + Some('c') => { + let left = sel.anchor.min(sel.end); + let right = sel.anchor.max(sel.end); + if left != right { + let selected: String = content + .graphemes(true) + .skip(left) + .take(right - left) + .collect(); + clipboard.write( + crate::clipboard::Kind::Standard, + selected, + ); + } + shell.capture_event(); + return; + } + Some('a') => { + sel.anchor = 0; + sel.end = grapheme_count; + shell.capture_event(); + return; + } + _ => {} + } + } + + match key { + keyboard::Key::Named(keyboard::key::Named::ArrowLeft) => { + let by_word = is_jump_modifier(*modifiers); + if modifiers.shift() { + sel.end = if by_word { + previous_start_of_word(content, sel.end) + } else { + sel.end.saturating_sub(1) + }; + } else { + let left = sel.anchor.min(sel.end); + let pos = if by_word { + previous_start_of_word(content, left) + } else { + left.saturating_sub(1) + }; + sel.anchor = pos; + sel.end = pos; + } + shell.capture_event(); + } + keyboard::Key::Named(keyboard::key::Named::ArrowRight) => { + let by_word = is_jump_modifier(*modifiers); + if modifiers.shift() { + sel.end = if by_word { + next_end_of_word(content, sel.end) + } else { + (sel.end + 1).min(grapheme_count) + }; + } else { + let right = sel.anchor.max(sel.end); + let pos = if by_word { + next_end_of_word(content, right) + } else { + (right + 1).min(grapheme_count) + }; + sel.anchor = pos; + sel.end = pos; + } + shell.capture_event(); + } + keyboard::Key::Named(keyboard::key::Named::Home) => { + if modifiers.shift() { + sel.end = 0; + } else { + sel.anchor = 0; + sel.end = 0; + } + shell.capture_event(); + } + keyboard::Key::Named(keyboard::key::Named::End) => { + if modifiers.shift() { + sel.end = grapheme_count; + } else { + sel.anchor = grapheme_count; + sel.end = grapheme_count; + } + shell.capture_event(); + } + _ => {} + } + } + + Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { + if let Some(sel) = &mut state.selection { + sel.modifiers = *modifiers; + } + } + + _ => {} + } + } + + fn mouse_interaction( + &self, + _tree: &Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + _viewport: &Rectangle, + _renderer: &Renderer, + ) -> mouse::Interaction { + if self.selectable && cursor.is_over(layout.bounds()) { + mouse::Interaction::Text + } else { + mouse::Interaction::None + } } fn operate( &mut self, - _tree: &mut Tree, + tree: &mut Tree, layout: Layout<'_>, _renderer: &Renderer, operation: &mut dyn super::Operation, ) { operation.text(None, layout.bounds(), &self.fragment); + + if self.selectable { + let state = tree.state.downcast_mut::>(); + operation.focusable(None, layout.bounds(), state); + } } #[cfg(feature = "a11y")] @@ -471,12 +894,23 @@ where } /// The appearance of some text. -#[derive(Debug, Clone, Copy, PartialEq, Default)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Style { /// The [`Color`] of the text. /// /// The default, `None`, means using the inherited color. pub color: Option, + /// The fill [`Color`] of the selection highlight. + pub selected_fill: Color, +} + +impl Default for Style { + fn default() -> Self { + Self { + color: None, + selected_fill: DEFAULT_SELECTION_COLOR, + } + } } /// The theme catalog of a [`Text`]. @@ -510,13 +944,14 @@ impl Catalog for Theme { /// The default text styling; color is inherited. pub fn default(_theme: &Theme) -> Style { - Style { color: None } + Style::default() } /// Text with the default base color. pub fn base(theme: &Theme) -> Style { Style { color: Some(theme.palette().text), + ..Style::default() } } @@ -524,6 +959,7 @@ pub fn base(theme: &Theme) -> Style { pub fn primary(theme: &Theme) -> Style { Style { color: Some(theme.palette().primary), + ..Style::default() } } @@ -531,6 +967,7 @@ pub fn primary(theme: &Theme) -> Style { pub fn secondary(theme: &Theme) -> Style { Style { color: Some(theme.extended_palette().secondary.base.color), + ..Style::default() } } @@ -538,6 +975,7 @@ pub fn secondary(theme: &Theme) -> Style { pub fn success(theme: &Theme) -> Style { Style { color: Some(theme.palette().success), + ..Style::default() } } @@ -545,6 +983,7 @@ pub fn success(theme: &Theme) -> Style { pub fn warning(theme: &Theme) -> Style { Style { color: Some(theme.palette().warning), + ..Style::default() } } @@ -552,5 +991,177 @@ pub fn warning(theme: &Theme) -> Style { pub fn danger(theme: &Theme) -> Style { Style { color: Some(theme.palette().danger), + ..Style::default() + } +} + +use crate::widget::tree::Tree as WidgetTree; + +/// Implement this on a **widget** to enable context menu support for +/// text selection (Copy, Select All, and optionally Cut / Paste) in libcosmic +pub trait HasSelectableText { + /// Returns the currently selected text, if any. + fn selected_text(&self, tree: &WidgetTree) -> Option; + + /// Selects all text. + fn select_all(&self, tree: &mut WidgetTree); + + /// Returns `true` if the widget is editable (enables Cut / Paste). + fn is_editable(&self) -> bool { + false + } + + /// Returns `true` if the widget is currently focused. + fn is_focused(&self, tree: &WidgetTree) -> bool; + + /// Returns the position where the context menu should appear + fn context_menu_position(&self, tree: &WidgetTree) -> Option; + + /// Sets or clears the context menu position. + fn set_context_menu_position( + &self, + tree: &mut WidgetTree, + pos: Option, + ); + + /// Copies the selection to the clipboard. + fn copy_to_clipboard( + &self, + tree: &WidgetTree, + clipboard: &mut dyn Clipboard, + ) { + if let Some(text) = self.selected_text(tree) { + clipboard.write(crate::clipboard::Kind::Standard, text); + } + } + + /// Deletes the selected text and returns the new full content. + /// Only called when [`is_editable`](Self::is_editable) is `true`. + fn delete_selection(&self, _tree: &mut WidgetTree) -> Option { + None + } + + /// Inserts `text` at the cursor (replacing any selection) and returns + /// the new full content. + /// Only called when [`is_editable`](Self::is_editable) is `true`. + fn paste_text( + &self, + _tree: &mut WidgetTree, + _text: &str, + ) -> Option { + None + } +} + +impl HasSelectableText + for Text<'_, Theme, Renderer> +{ + fn selected_text(&self, tree: &WidgetTree) -> Option { + let state = tree.state.downcast_ref::>(); + let sel = state.selection.as_ref()?; + let left = sel.anchor.min(sel.end); + let right = sel.anchor.max(sel.end); + if left == right { + return None; + } + let content = state.paragraph.content(); + let lo = grapheme_to_byte(content, left); + let hi = grapheme_to_byte(content, right); + content.get(lo..hi).map(|s| s.to_owned()) + } + + fn select_all(&self, tree: &mut WidgetTree) { + let state = tree.state.downcast_mut::>(); + let count = state.paragraph.content().graphemes(true).count(); + let sel = state + .selection + .get_or_insert_with(|| Box::new(SelectionState::default())); + sel.anchor = 0; + sel.end = count; + } + + fn is_focused(&self, tree: &WidgetTree) -> bool { + let state = tree.state.downcast_ref::>(); + state.is_focused() + } + + fn context_menu_position(&self, tree: &WidgetTree) -> Option { + let state = tree.state.downcast_ref::>(); + state.context_menu_position() + } + + fn set_context_menu_position( + &self, + tree: &mut WidgetTree, + pos: Option, + ) { + let state = tree.state.downcast_mut::>(); + state.set_context_menu_position(pos); + } +} + +const DEFAULT_SELECTION_COLOR: Color = Color { + r: 0.0, + g: 0.47, + b: 0.84, + a: 0.3, +}; + +fn grapheme_to_byte(content: &str, grapheme_index: usize) -> usize { + content + .graphemes(true) + .take(grapheme_index) + .map(|g| g.len()) + .sum() +} + +fn hit_to_grapheme( + paragraph: &P, + point: Point, + content: &str, +) -> usize { + match paragraph.hit_test(point) { + Some(hit) => { + let byte_offset = hit.cursor().min(content.len()); + content[..byte_offset].graphemes(true).count() + } + None => content.graphemes(true).count(), + } +} + +fn previous_start_of_word(content: &str, grapheme_index: usize) -> usize { + let graphemes: Vec<&str> = content.graphemes(true).collect(); + let clamped = grapheme_index.min(graphemes.len()); + let before: String = graphemes[..clamped].concat(); + + UnicodeSegmentation::split_word_bound_indices(&*before) + .filter(|(_, word)| !word.trim_start().is_empty()) + .next_back() + .map_or(0, |(i, prev_word)| { + clamped + - prev_word.graphemes(true).count() + - before[i + prev_word.len()..].graphemes(true).count() + }) +} + +fn next_end_of_word(content: &str, grapheme_index: usize) -> usize { + let graphemes: Vec<&str> = content.graphemes(true).collect(); + let clamped = grapheme_index.min(graphemes.len()); + let after: String = graphemes[clamped..].concat(); + + UnicodeSegmentation::split_word_bound_indices(&*after) + .find(|(_, word)| !word.trim_start().is_empty()) + .map_or(graphemes.len(), |(i, next_word)| { + clamped + + next_word.graphemes(true).count() + + after[..i].graphemes(true).count() + }) +} + +fn is_jump_modifier(modifiers: keyboard::Modifiers) -> bool { + if cfg!(target_os = "macos") { + modifiers.alt() + } else { + modifiers.control() } } diff --git a/examples/counter/src/main.rs b/examples/counter/src/main.rs index 5027afd7..cfae782a 100644 --- a/examples/counter/src/main.rs +++ b/examples/counter/src/main.rs @@ -1,5 +1,5 @@ +use iced::widget::{button, column, text, Column}; use iced::Center; -use iced::widget::{Column, button, column, text}; pub fn main() -> iced::Result { iced::run(Counter::update, Counter::view) @@ -42,7 +42,7 @@ impl Counter { #[cfg(test)] mod tests { use super::*; - use iced_test::{Error, simulator}; + use iced_test::{simulator, Error}; #[test] fn it_counts() -> Result<(), Error> { diff --git a/examples/custom_shader/src/scene/pipeline.rs b/examples/custom_shader/src/scene/pipeline.rs index 80b0d533..30262a5d 100644 --- a/examples/custom_shader/src/scene/pipeline.rs +++ b/examples/custom_shader/src/scene/pipeline.rs @@ -140,7 +140,7 @@ impl Pipeline { address_mode_w: wgpu::AddressMode::ClampToEdge, mag_filter: wgpu::FilterMode::Linear, min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::MipmapFilterMode::Linear, ..Default::default() }); @@ -223,7 +223,7 @@ impl Pipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("cubes pipeline layout"), bind_group_layouts: &[&uniform_bind_group_layout], - push_constant_ranges: &[], + immediate_size: 0, }); let shader = @@ -280,7 +280,7 @@ impl Pipeline { compilation_options: wgpu::PipelineCompilationOptions::default(), }), - multiview: None, + multiview_mask: None, cache: None, }); @@ -388,6 +388,7 @@ impl Pipeline { ), timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); pass.set_viewport( @@ -478,7 +479,7 @@ impl DepthPipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("cubes.depth_pipeline.layout"), bind_group_layouts: &[&bind_group_layout], - push_constant_ranges: &[], + immediate_size: 0, }); let shader = @@ -520,7 +521,7 @@ impl DepthPipeline { compilation_options: wgpu::PipelineCompilationOptions::default(), }), - multiview: None, + multiview_mask: None, cache: None, }); @@ -586,6 +587,7 @@ impl DepthPipeline { ), timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); pass.set_viewport( diff --git a/examples/integration/src/scene.rs b/examples/integration/src/scene.rs index 4e4757fa..1b248036 100644 --- a/examples/integration/src/scene.rs +++ b/examples/integration/src/scene.rs @@ -43,6 +43,7 @@ impl Scene { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }) } @@ -64,8 +65,8 @@ fn build_pipeline( let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, - push_constant_ranges: &[], bind_group_layouts: &[], + immediate_size: 0, }); device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { @@ -101,7 +102,7 @@ fn build_pipeline( mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }) } diff --git a/examples/sctk_drag/src/dnd_destination.rs b/examples/sctk_drag/src/dnd_destination.rs index 1081d8bb..d1b3374b 100644 --- a/examples/sctk_drag/src/dnd_destination.rs +++ b/examples/sctk_drag/src/dnd_destination.rs @@ -3,20 +3,20 @@ use std::{ sync::atomic::{AtomicU64, Ordering}, }; -use iced::{Element, id::Id}; use iced::{ - Event, Length, Rectangle, clipboard::{ dnd::{self, DndAction, DndDestinationRectangle, DndEvent, OfferEvent}, mime::AllowedMimeTypes, }, event, id::Internal, - mouse, overlay, + mouse, overlay, Event, Length, Rectangle, }; +use iced::{id::Id, Element}; use iced_core::{ - self, Clipboard, Layout, Shell, Widget, layout, - widget::{Tree, tree}, + self, layout, + widget::{tree, Tree}, + Clipboard, Layout, Shell, Widget, }; pub fn dnd_destination<'a, Message: 'static>( diff --git a/examples/sctk_drag/src/dnd_source.rs b/examples/sctk_drag/src/dnd_source.rs index 1d8b85c4..e93b925e 100644 --- a/examples/sctk_drag/src/dnd_source.rs +++ b/examples/sctk_drag/src/dnd_source.rs @@ -1,16 +1,16 @@ use std::any::Any; -use iced::Element; use iced::id::Id; use iced::widget::container; +use iced::Element; use iced::{ - Event, Length, Point, Rectangle, clipboard::dnd::{DndAction, DndEvent, SourceEvent}, - event, mouse, overlay, + event, mouse, overlay, Event, Length, Point, Rectangle, }; use iced_core::{ - Clipboard, Shell, layout, renderer, - widget::{Tree, tree}, + layout, renderer, + widget::{tree, Tree}, + Clipboard, Shell, }; use iced_core::{Layout, Widget}; @@ -37,11 +37,11 @@ pub struct DndSource<'a, Message, AppMessage, D> { } impl< - 'a, - Message: 'static, - AppMessage: 'static, - D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, -> DndSource<'a, Message, AppMessage, D> + 'a, + Message: 'static, + AppMessage: 'static, + D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, + > DndSource<'a, Message, AppMessage, D> { pub fn new(child: impl Into>) -> Self { Self { @@ -119,11 +119,11 @@ impl< } impl< - 'a, - Message: 'static, - AppMessage: 'static, - D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, -> Widget + 'a, + Message: 'static, + AppMessage: 'static, + D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, + > Widget for DndSource<'a, Message, AppMessage, D> { fn children(&self) -> Vec { @@ -357,11 +357,11 @@ impl< } impl< - 'a, - Message: 'static, - AppMessage: 'static, - D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, -> From> for Element<'a, Message> + 'a, + Message: 'static, + AppMessage: 'static, + D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, + > From> for Element<'a, Message> { fn from(e: DndSource<'a, Message, AppMessage, D>) -> Element<'a, Message> { Element::new(e) diff --git a/examples/sctk_subsurface/src/main.rs b/examples/sctk_subsurface/src/main.rs index c00f7225..a204572c 100644 --- a/examples/sctk_subsurface/src/main.rs +++ b/examples/sctk_subsurface/src/main.rs @@ -7,7 +7,6 @@ use cctk::sctk::reexports::{ use iced::platform_specific::shell::commands::subsurface::get_subsurface; use iced::{ - Element, Length, Subscription, Task, event::wayland::Event as WaylandEvent, platform_specific::{ runtime::wayland::subsurface::SctkSubsurfaceSettings, @@ -15,6 +14,7 @@ use iced::{ }, widget::{button, column, text, text_input}, window::{self, Id, Settings}, + Element, Length, Subscription, Task, }; use std::sync::{Arc, Mutex}; diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 2e3722b1..9fe39035 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -477,6 +477,7 @@ fn delete_icon() -> Text<'static> { fn subtle(theme: &Theme) -> text::Style { text::Style { color: Some(theme.extended_palette().background.strongest.color), + ..text::Style::default() } } diff --git a/graphics/src/image.rs b/graphics/src/image.rs index e5fe9281..d9b23216 100644 --- a/graphics/src/image.rs +++ b/graphics/src/image.rs @@ -2,8 +2,6 @@ #[cfg(feature = "image")] use crate::core::Bytes; -use crate::core::Color; -use crate::core::Radians; use crate::core::Rectangle; use crate::core::image; use crate::core::svg; diff --git a/graphics/src/text.rs b/graphics/src/text.rs index 230a362d..910cbbde 100644 --- a/graphics/src/text.rs +++ b/graphics/src/text.rs @@ -161,6 +161,14 @@ impl FontSystem { &mut self.raw } + /// Returns a reference to the underlying [`fontdb::Database`]. + /// + /// Unlike going through [`raw`](Self::raw) and `db_mut`, this does not + /// clear `cosmic-text`'s internal font-match cache. + pub fn db(&self) -> &cosmic_text::fontdb::Database { + self.raw.db() + } + /// Loads a font from its bytes. pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) { if let Cow::Borrowed(bytes) = bytes { diff --git a/graphics/src/text/editor.rs b/graphics/src/text/editor.rs index b284c76b..1586479e 100644 --- a/graphics/src/text/editor.rs +++ b/graphics/src/text/editor.rs @@ -336,6 +336,10 @@ impl editor::Editor for Editor { } } + Action::ClearSelection => { + editor.set_selection(cosmic_text::Selection::None); + } + // Editing events Action::Edit(edit) => { let topmost_line_before_edit = editor diff --git a/runtime/src/dnd.rs b/runtime/src/dnd.rs index e6f2b267..2e526eb6 100644 --- a/runtime/src/dnd.rs +++ b/runtime/src/dnd.rs @@ -1,12 +1,10 @@ //! Access the clipboard. -use std::any::Any; use dnd::{DndDestinationRectangle, DndSurface}; -use iced_core::clipboard::DndSource; -use window_clipboard::mime::{AllowedMimeTypes, AsMimeTypes}; +use window_clipboard::mime::AllowedMimeTypes; -use crate::{oneshot, task, Action, Task}; +use crate::{Action, Task, oneshot, task}; /// An action to be performed on the system. pub enum DndAction { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 22da3d66..68034bfc 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -28,7 +28,6 @@ pub use task::Task; pub use user_interface::UserInterface; pub use window::Window; -use crate::core::Color; use crate::futures::futures::channel::oneshot; use std::borrow::Cow; diff --git a/runtime/src/platform_specific/wayland/activation.rs b/runtime/src/platform_specific/wayland/activation.rs index 64d4dc4d..3f48f01c 100644 --- a/runtime/src/platform_specific/wayland/activation.rs +++ b/runtime/src/platform_specific/wayland/activation.rs @@ -36,7 +36,7 @@ impl fmt::Debug for Action { f, "Action::ActivationAction::Activate {{ window: {:?}, token: {:?} }}", window, token, - ) + ), } } } diff --git a/runtime/src/platform_specific/wayland/layer_surface.rs b/runtime/src/platform_specific/wayland/layer_surface.rs index 4745ef67..6e5f3e9e 100644 --- a/runtime/src/platform_specific/wayland/layer_surface.rs +++ b/runtime/src/platform_specific/wayland/layer_surface.rs @@ -6,8 +6,8 @@ use cctk::sctk::{ }; use iced_core::layout::Limits; -use iced_core::window::Id; use iced_core::Rectangle; +use iced_core::window::Id; /// output for layer surface #[derive(Debug, Clone)] @@ -150,6 +150,13 @@ pub enum Action { /// layer of the layer surface layer: Layer, }, + /// padding of the surface geometry + Padding { + /// id of the layer surface + id: Id, + /// padding of the surface geometry + padding: IcedMargin, + }, } impl fmt::Debug for Action { @@ -162,35 +169,51 @@ impl fmt::Debug for Action { ), Action::Size { id, width, height } => write!( f, - "Action::LayerSurfaceAction::Size {{ id: {:#?}, width: {:?}, height: {:?} }}", id, width, height + "Action::LayerSurfaceAction::Size {{ id: {:#?}, width: {:?}, height: {:?} }}", + id, width, height ), Action::Destroy(id) => write!( f, - "Action::LayerSurfaceAction::Destroy {{ id: {:#?} }}", id + "Action::LayerSurfaceAction::Destroy {{ id: {:#?} }}", + id ), Action::Anchor { id, anchor } => write!( f, - "Action::LayerSurfaceAction::Anchor {{ id: {:#?}, anchor: {:?} }}", id, anchor + "Action::LayerSurfaceAction::Anchor {{ id: {:#?}, anchor: {:?} }}", + id, anchor ), Action::ExclusiveZone { id, exclusive_zone } => write!( f, - "Action::LayerSurfaceAction::ExclusiveZone {{ id: {:#?}, exclusive_zone: {exclusive_zone} }}", id + "Action::LayerSurfaceAction::ExclusiveZone {{ id: {:#?}, exclusive_zone: {exclusive_zone} }}", + id ), Action::Margin { id, margin } => write!( f, - "Action::LayerSurfaceAction::Margin {{ id: {:#?}, margin: {:?} }}", id, margin + "Action::LayerSurfaceAction::Margin {{ id: {:#?}, margin: {:?} }}", + id, margin ), - Action::KeyboardInteractivity { id, keyboard_interactivity } => write!( + Action::KeyboardInteractivity { + id, + keyboard_interactivity, + } => write!( f, - "Action::LayerSurfaceAction::KeyboardInteractivity {{ id: {:#?}, keyboard_interactivity: {:?} }}", id, keyboard_interactivity + "Action::LayerSurfaceAction::KeyboardInteractivity {{ id: {:#?}, keyboard_interactivity: {:?} }}", + id, keyboard_interactivity ), Action::InputZone { id, zone } => write!( f, - "Action::LayerSurfaceAction::InputZone {{ id: {:#?}, zone: {:?} }}", id, zone + "Action::LayerSurfaceAction::InputZone {{ id: {:#?}, zone: {:?} }}", + id, zone ), Action::Layer { id, layer } => write!( f, - "Action::LayerSurfaceAction::Layer {{ id: {:#?}, layer: {:?} }}", id, layer + "Action::LayerSurfaceAction::Layer {{ id: {:#?}, layer: {:?} }}", + id, layer + ), + Action::Padding { id, padding } => write!( + f, + "Action::LayerSurfaceAction::Padding {{ id: {:#?}, padding: {:?} }}", + id, padding ), } } diff --git a/runtime/src/platform_specific/wayland/mod.rs b/runtime/src/platform_specific/wayland/mod.rs index 752ca49a..3c2ac977 100644 --- a/runtime/src/platform_specific/wayland/mod.rs +++ b/runtime/src/platform_specific/wayland/mod.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; -use iced_core::window::Id; +use iced_core::{Rectangle, window::Id}; /// activation Actions pub mod activation; @@ -35,6 +35,8 @@ pub enum Action { InhibitShortcuts(bool), /// Rounded corners in logical space RoundedCorners(iced_core::window::Id, Option), + /// Blur effect for a surface + BlurSurface(Id, Option>), } #[derive(Debug, Clone, Copy, PartialEq, Default)] @@ -70,6 +72,11 @@ impl Debug for Action { Action::RoundedCorners(id, v) => { f.debug_tuple("RoundedCorners").field(id).field(v).finish() } + Action::BlurSurface(id, rectangles) => f + .debug_tuple("BlurSurface") + .field(id) + .field(rectangles) + .finish(), } } } diff --git a/runtime/src/platform_specific/wayland/popup.rs b/runtime/src/platform_specific/wayland/popup.rs index e0475eb8..27279ab6 100644 --- a/runtime/src/platform_specific/wayland/popup.rs +++ b/runtime/src/platform_specific/wayland/popup.rs @@ -124,26 +124,34 @@ pub enum Action { /// height height: u32, }, + /// set the size of the popup + Reposition { + /// id of the popup + id: Id, + /// positioner of the popup + positioner: SctkPositioner, + }, } impl fmt::Debug for Action { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Action::Popup { popup, .. } => write!( - f, - "Action::PopupAction::Popup {{ popup: {:?} }}", - popup - ), - Action::Destroy { id } => write!( - f, - "Action::PopupAction::Destroy {{ id: {:?} }}", - id - ), + Action::Popup { popup, .. } => { + write!(f, "Action::PopupAction::Popup {{ popup: {:?} }}", popup) + } + Action::Destroy { id } => { + write!(f, "Action::PopupAction::Destroy {{ id: {:?} }}", id) + } Action::Size { id, width, height } => write!( f, "Action::PopupAction::Size {{ id: {:?}, width: {:?}, height: {:?} }}", id, width, height ), + Action::Reposition { id, positioner } => write!( + f, + "Action::Reposition {{ id: {:?}, positioner: {:?} }}", + id, positioner + ), } } } diff --git a/src/lib.rs b/src/lib.rs index 8d408969..6e57128b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -683,6 +683,8 @@ pub use event::Event; pub use executor::Executor; pub use font::Font; pub use renderer::Renderer; +#[cfg(feature = "canvas")] +pub use renderer::graphics::geometry; pub use task::Task; pub use window::Window; diff --git a/tester/src/lib.rs b/tester/src/lib.rs index 334f17bc..f41fbb68 100644 --- a/tester/src/lib.rs +++ b/tester/src/lib.rs @@ -775,6 +775,7 @@ impl Tester

{ } _ => None, }, + ..text::Style::default() }) .into() }, @@ -945,6 +946,7 @@ where text(label).size(14).style(|theme: &core::Theme| { text::Style { color: Some(theme.extended_palette().background.weak.text), + ..text::Style::default() } }), space::horizontal(), diff --git a/tiny_skia/src/vector.rs b/tiny_skia/src/vector.rs index 59cd1993..2c3b219c 100644 --- a/tiny_skia/src/vector.rs +++ b/tiny_skia/src/vector.rs @@ -1,5 +1,6 @@ use crate::core::svg::{Data, Handle}; use crate::core::{Color, Rectangle, Size}; +use crate::graphics::text; use resvg::usvg; use rustc_hash::{FxHashMap, FxHashSet}; @@ -74,6 +75,7 @@ struct Cache { rasters: FxHashMap, raster_hits: FxHashSet, fontdb: Option>, + fontdb_version: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -87,12 +89,15 @@ impl Cache { fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> { let id = handle.id(); - // TODO: Reuse `cosmic-text` font database - if self.fontdb.is_none() { - let mut fontdb = usvg::fontdb::Database::new(); - fontdb.load_system_fonts(); + // Reuse the font database already loaded by the `cosmic-text` font + // system. We clone it once and refresh only when a font is + // loaded (i.e. when the font system's version changes). + let font_system = text::font_system().read().expect("Read font system"); + let version = font_system.version(); - self.fontdb = Some(Arc::new(fontdb)); + if self.fontdb_version != Some(version) { + self.fontdb = Some(Arc::new(font_system.db().clone())); + self.fontdb_version = Some(version); } let options = usvg::Options { diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 48fca1b8..ffbcd293 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -25,6 +25,11 @@ svg = ["iced_graphics/svg", "resvg/text"] web-colors = ["iced_graphics/web-colors"] webgl = ["wgpu/webgl"] strict-assertions = [] +# Yoda: opt-in X11 backend. Pulls tiny-xlib/as-raw-xcb-connection/x11rb +# (which otherwise were unconditional direct deps on unix). Wayland-only +# builds just leave this off — window/x11.rs and the DRI3 device-id +# fallback in window/compositor.rs are cfg-gated on it. +x11 = ["dep:as-raw-xcb-connection", "dep:tiny-xlib", "dep:x11rb"] [dependencies] iced_debug.workspace = true @@ -57,9 +62,9 @@ wayland-protocols.workspace = true wayland-backend = { version = "0.3.3", features = ["client_system"] } wayland-client = { version = "0.31.2" } wayland-sys = { version = "0.31.1", features = ["dlopen"] } -as-raw-xcb-connection = "1.0.1" -tiny-xlib = "0.2.3" -x11rb = { version = "0.13.1", features = [ +as-raw-xcb-connection = { version = "1.0.1", optional = true } +tiny-xlib = { version = "0.2.3", optional = true } +x11rb = { version = "0.13.1", optional = true, features = [ "allow-unsafe-code", "dl-libxcb", "dri3", diff --git a/wgpu/src/buffer.rs b/wgpu/src/buffer.rs index 172922da..e251e979 100644 --- a/wgpu/src/buffer.rs +++ b/wgpu/src/buffer.rs @@ -63,7 +63,6 @@ impl Buffer { /// Returns the size of the written bytes. pub fn write( &mut self, - device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, offset: usize, @@ -79,7 +78,6 @@ impl Buffer { &self.raw, (offset + bytes_written) as u64, MAX_WRITE_SIZE_U64, - device, ) .copy_from_slice( &bytes[bytes_written..bytes_written + MAX_WRITE_SIZE], @@ -100,7 +98,6 @@ impl Buffer { &self.raw, (offset + bytes_written) as u64, bytes_left, - device, ) .copy_from_slice(&bytes[bytes_written..]); diff --git a/wgpu/src/color.rs b/wgpu/src/color.rs index 52fe8463..642d4ea7 100644 --- a/wgpu/src/color.rs +++ b/wgpu/src/color.rs @@ -99,7 +99,7 @@ pub fn convert( device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.offscreen.blit.pipeline_layout"), bind_group_layouts: &[&constant_layout, &texture_layout], - push_constant_ranges: &[], + immediate_size: 0, }); let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { @@ -149,7 +149,7 @@ pub fn convert( }, depth_stencil: None, multisample: wgpu::MultisampleState::default(), - multiview: None, + multiview_mask: None, cache: None, }); @@ -194,6 +194,7 @@ pub fn convert( depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); pass.set_pipeline(&pipeline); diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 09258329..d23e7452 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -132,7 +132,7 @@ impl Atlas { match &entry { Entry::Contiguous(allocation) => { self.upload_allocation( - pixels, width, 0, allocation, device, encoder, belt, + pixels, width, 0, allocation, encoder, belt, ); } Entry::Fragmented { fragments, .. } => { @@ -145,7 +145,6 @@ impl Atlas { width, offset, &fragment.allocation, - device, encoder, belt, ); @@ -312,7 +311,6 @@ impl Atlas { image_width: u32, offset: usize, allocation: &Allocation, - device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, ) { @@ -334,7 +332,6 @@ impl Atlas { let buffer_slice = belt.allocate( wgpu::BufferSize::new(total_bytes as u64).unwrap(), wgpu::BufferSize::new(8 * 4).unwrap(), - device, ); const PIXEL: usize = 4; diff --git a/wgpu/src/image/cache.rs b/wgpu/src/image/cache.rs index 097a383f..88a48640 100644 --- a/wgpu/src/image/cache.rs +++ b/wgpu/src/image/cache.rs @@ -38,7 +38,10 @@ impl Cache { raster: Raster { cache: crate::image::raster::Cache::default(), pending: HashMap::new(), - belt: wgpu::util::StagingBelt::new(2 * 1024 * 1024), + belt: wgpu::util::StagingBelt::new( + device.clone(), + 2 * 1024 * 1024, + ), }, #[cfg(feature = "svg")] vector: crate::image::vector::Cache::default(), @@ -451,7 +454,10 @@ mod worker { backend, texture_layout, shell: shell.clone(), - belt: wgpu::util::StagingBelt::new(4 * 1024 * 1024), + belt: wgpu::util::StagingBelt::new( + device.clone(), + 4 * 1024 * 1024, + ), jobs: jobs_receiver, output: work_sender, quit: quit_receiver, diff --git a/wgpu/src/image/mod.rs b/wgpu/src/image/mod.rs index ba98f443..d0665ee4 100644 --- a/wgpu/src/image/mod.rs +++ b/wgpu/src/image/mod.rs @@ -45,7 +45,7 @@ impl Pipeline { address_mode_w: wgpu::AddressMode::ClampToEdge, min_filter: wgpu::FilterMode::Nearest, mag_filter: wgpu::FilterMode::Nearest, - mipmap_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, ..Default::default() }); @@ -55,7 +55,7 @@ impl Pipeline { address_mode_w: wgpu::AddressMode::ClampToEdge, min_filter: wgpu::FilterMode::Linear, mag_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::MipmapFilterMode::Linear, ..Default::default() }); @@ -106,8 +106,8 @@ impl Pipeline { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu::image pipeline layout"), - push_constant_ranges: &[], bind_group_layouts: &[&constant_layout, &texture_layout], + immediate_size: 0, }); let shader = @@ -191,7 +191,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }); @@ -528,7 +528,6 @@ impl Layer { &self.uniforms, 0, (bytes.len() as u64).try_into().expect("Sized uniforms"), - device, ) .copy_from_slice(bytes); @@ -539,11 +538,11 @@ impl Layer { let mut offset = 0; if !nearest.is_empty() { - offset += self.instances.write(device, encoder, belt, 0, nearest); + offset += self.instances.write(encoder, belt, 0, nearest); } if !linear.is_empty() { - let _ = self.instances.write(device, encoder, belt, offset, linear); + let _ = self.instances.write(encoder, belt, offset, linear); } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 4eb52cc8..03a72042 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -126,6 +126,7 @@ impl Renderer { // It would be great if the `StagingBelt` API exposed methods // for introspection to detect when a resize may be worth it. staging_belt: wgpu::util::StagingBelt::new( + engine.device.clone(), buffer::MAX_WRITE_SIZE as u64, ), @@ -454,6 +455,7 @@ impl Renderer { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }, )); @@ -528,6 +530,7 @@ impl Renderer { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }, )); } @@ -621,6 +624,7 @@ impl Renderer { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }, )); } diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 31bf69cf..4cab2598 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -209,7 +209,7 @@ impl Layer { transformation: Transformation, scale: f32, ) { - self.update(device, encoder, belt, transformation, scale); + self.update(encoder, belt, transformation, scale); if !quads.solids.is_empty() { self.solid.prepare(device, encoder, belt, &quads.solids); @@ -223,7 +223,6 @@ impl Layer { pub fn update( &mut self, - device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, transformation: Transformation, @@ -237,7 +236,6 @@ impl Layer { &self.constants_buffer, 0, (bytes.len() as u64).try_into().expect("Sized uniforms"), - device, ) .copy_from_slice(bytes); } diff --git a/wgpu/src/quad/gradient.rs b/wgpu/src/quad/gradient.rs index 6a5eed8d..55e62e79 100644 --- a/wgpu/src/quad/gradient.rs +++ b/wgpu/src/quad/gradient.rs @@ -51,7 +51,7 @@ impl Layer { instances: &[Gradient], ) { let _ = self.instances.resize(device, instances.len()); - let _ = self.instances.write(device, encoder, belt, 0, instances); + let _ = self.instances.write(encoder, belt, 0, instances); self.instance_count = instances.len(); } @@ -75,8 +75,8 @@ impl Pipeline { let layout = device.create_pipeline_layout( &wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.quad.gradient.pipeline"), - push_constant_ranges: &[], bind_group_layouts: &[constants_layout], + immediate_size: 0, }, ); @@ -155,7 +155,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }, ); diff --git a/wgpu/src/quad/solid.rs b/wgpu/src/quad/solid.rs index 7e48358e..49e4cf01 100644 --- a/wgpu/src/quad/solid.rs +++ b/wgpu/src/quad/solid.rs @@ -45,7 +45,7 @@ impl Layer { instances: &[Solid], ) { let _ = self.instances.resize(device, instances.len()); - let _ = self.instances.write(device, encoder, belt, 0, instances); + let _ = self.instances.write(encoder, belt, 0, instances); self.instance_count = instances.len(); } @@ -65,8 +65,8 @@ impl Pipeline { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.quad.solid.pipeline"), - push_constant_ranges: &[], bind_group_layouts: &[constants_layout], + immediate_size: 0, }); let shader = @@ -139,7 +139,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }); diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 16efa092..b6d9e679 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -619,7 +619,7 @@ fn prepare( )?; Some(cryoglyph::TextArea { - buffer, + text: buffer.layout_runs(), left: position.x, top: position.y, scale: transformation.scale_factor() diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index fa5ecb9c..5607d03a 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -313,6 +313,7 @@ fn render<'a>( depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }) }; @@ -425,18 +426,13 @@ impl Layer { let indices = mesh.indices(); - index_offset += self.index_buffer.write( - device, - encoder, - belt, - index_offset, - indices, - ); + index_offset += + self.index_buffer + .write(encoder, belt, index_offset, indices); match mesh { Mesh::Solid { buffers, .. } => { solid_vertex_offset += self.solid.vertices.write( - device, encoder, belt, solid_vertex_offset, @@ -444,16 +440,14 @@ impl Layer { ); solid_uniform_offset += self.solid.uniforms.write( - device, encoder, belt, solid_uniform_offset, &[uniforms], - ); + ) } Mesh::Gradient { buffers, .. } => { gradient_vertex_offset += self.gradient.vertices.write( - device, encoder, belt, gradient_vertex_offset, @@ -461,7 +455,6 @@ impl Layer { ); gradient_uniform_offset += self.gradient.uniforms.write( - device, encoder, belt, gradient_uniform_offset, @@ -731,7 +724,7 @@ mod solid { &wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.triangle.solid.pipeline_layout"), bind_group_layouts: &[&constants_layout], - push_constant_ranges: &[], + immediate_size: 0, }, ); @@ -784,7 +777,7 @@ mod solid { primitive: triangle::primitive_state(), depth_stencil: None, multisample: triangle::multisample_state(antialiasing), - multiview: None, + multiview_mask: None, cache: None, }, ); @@ -886,7 +879,7 @@ mod gradient { &wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.triangle.gradient.pipeline_layout"), bind_group_layouts: &[&constants_layout], - push_constant_ranges: &[], + immediate_size: 0, }, ); @@ -949,7 +942,7 @@ mod gradient { primitive: triangle::primitive_state(), depth_stencil: None, multisample: triangle::multisample_state(antialiasing), - multiview: None, + multiview_mask: None, cache: None, }, ); diff --git a/wgpu/src/triangle/msaa.rs b/wgpu/src/triangle/msaa.rs index 8ca49461..46118361 100644 --- a/wgpu/src/triangle/msaa.rs +++ b/wgpu/src/triangle/msaa.rs @@ -69,8 +69,8 @@ impl Pipeline { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu::triangle::msaa pipeline layout"), - push_constant_ranges: &[], bind_group_layouts: &[&constant_layout, &texture_layout], + immediate_size: 0, }); let shader = @@ -116,7 +116,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }); @@ -177,6 +177,7 @@ impl Pipeline { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }) } } @@ -320,7 +321,6 @@ impl State { 0, NonZeroU64::new(std::mem::size_of::() as u64) .expect("non-empty ratio"), - device, ) .copy_from_slice(bytemuck::bytes_of(&ratio)); @@ -351,6 +351,7 @@ impl State { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); render_pass.set_pipeline(&pipeline.raw); diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs index b9ec54bd..f71b7d3f 100644 --- a/wgpu/src/window.rs +++ b/wgpu/src/window.rs @@ -7,7 +7,7 @@ pub mod compositor; not(target_os = "redox") ))] mod wayland; -#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] +#[cfg(all(unix, feature = "x11", not(target_os = "macos"), not(target_os = "redox")))] mod x11; pub use compositor::Compositor; diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 833a642e..d6186ab5 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -16,7 +16,7 @@ use crate::{Engine, Renderer}; not(target_os = "redox") ))] use super::wayland::get_wayland_device_ids; -#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] +#[cfg(all(unix, feature = "x11", not(target_os = "macos"), not(target_os = "redox")))] use super::x11::get_x11_device_ids; use std::future::Future; @@ -72,22 +72,29 @@ impl Compositor { not(target_os = "redox") ))] let ids = compatible_window.as_ref().and_then(|window| { - get_wayland_device_ids(window) - .or_else(|| get_x11_device_ids(window)) + let w = get_wayland_device_ids(window); + #[cfg(feature = "x11")] + let w = w.or_else(|| get_x11_device_ids(window)); + w }); + #[cfg(all( + unix, + not(feature = "cctk"), + not(target_os = "macos"), + not(target_os = "redox") + ))] + let ids = compatible_window + .as_ref() + .and_then(|window| get_x11_device_ids(window)); + // HACK: // 1. If we specifically didn't select an nvidia gpu // 2. and the user didn't specifically request an nvidia gpu // 3. and the user didn't set an adapter name, // 4. and the user didn't request the high power pref // => don't load the nvidia icd, as it might power on the gpu in hybrid setups causing severe delays - #[cfg(all( - unix, - feature = "cctk", - not(target_os = "macos"), - not(target_os = "redox") - ))] + #[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] if !matches!(ids, Some((0x10de, _))) && std::env::var_os("__NV_PRIME_RENDER_OFFLOAD") .is_none_or(|var| var == "0") @@ -126,6 +133,7 @@ impl Compositor { // if log::max_level() >= log::LevelFilter::Info { // let available_adapters: Vec<_> = instance // .enumerate_adapters(settings.backends) + // .await // .iter() // .map(wgpu::Adapter::get_info) // .collect(); @@ -148,13 +156,13 @@ impl Compositor { if std::env::var_os("WGPU_ADAPTER_NAME").is_none() { #[cfg(all( unix, - feature = "cctk", not(target_os = "macos"), not(target_os = "redox") ))] if let Some((vendor_id, device_id)) = ids { adapter = instance .enumerate_adapters(settings.backends) + .await .into_iter() .filter(|adapter| { let info = adapter.get_info(); @@ -172,6 +180,7 @@ impl Compositor { } else if let Ok(name) = std::env::var("WGPU_ADAPTER_NAME") { adapter = instance .enumerate_adapters(settings.backends) + .await .into_iter() .filter(|adapter| { let info = adapter.get_info(); @@ -184,6 +193,8 @@ impl Compositor { true } }); + } else { + adapter = instance.request_adapter(&adapter_options).await.ok(); } let adapter = match adapter { @@ -286,6 +297,14 @@ impl Compositor { ..limits }); + // Request SHADER_F16 only if the adapter supports it (e.g., not available in WebGL2) + let required_features = + if adapter.features().contains(wgpu::Features::SHADER_F16) { + wgpu::Features::SHADER_F16 + } else { + wgpu::Features::empty() + }; + let mut errors = Vec::new(); for required_limits in limits { @@ -294,7 +313,7 @@ impl Compositor { label: Some( "iced_wgpu::window::compositor device descriptor", ), - required_features: wgpu::Features::empty(), + required_features, required_limits: required_limits.clone(), memory_hints: wgpu::MemoryHints::MemoryUsage, trace: wgpu::Trace::Off, @@ -352,6 +371,14 @@ pub fn present( ) -> Result<(), compositor::SurfaceError> { match surface.get_current_texture() { Ok(frame) => { + if frame.texture.width() != viewport.physical_width() + || frame.texture.height() != viewport.physical_height() + { + return Err(compositor::SurfaceError::Outdated); + } + + let suboptimal = frame.suboptimal; + let view = &frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); @@ -367,6 +394,10 @@ pub fn present( on_pre_present(); frame.present(); + if suboptimal { + return Err(compositor::SurfaceError::Outdated); + } + Ok(()) } Err(error) => match error { diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs index 873a4541..6ac48b0e 100644 --- a/widget/src/checkbox.rs +++ b/widget/src/checkbox.rs @@ -505,6 +505,7 @@ where state.raw(), crate::text::Style { color: style.text_color, + ..crate::text::Style::default() }, viewport, ); diff --git a/widget/src/container.rs b/widget/src/container.rs index c9a300c9..a264007a 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -35,7 +35,7 @@ use crate::core::{ color, }; -use iced_runtime::{Action, Task, task}; +use iced_runtime::{Task, task}; /// A widget that aligns its contents inside of its boundaries. /// @@ -601,7 +601,7 @@ pub fn visible_bounds(id: Id) -> Task> { operate: &mut dyn FnMut(&mut dyn Operation>), ) { self.depth += 1; - self.traverse(operate); + operate(self); self.depth -= 1; } diff --git a/widget/src/keyed/column.rs b/widget/src/keyed/column.rs index baaee5c9..bb98d606 100644 --- a/widget/src/keyed/column.rs +++ b/widget/src/keyed/column.rs @@ -1,7 +1,6 @@ //! Keyed columns distribute content vertically while keeping continuity. //! Distribute content vertically. -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; @@ -293,9 +292,12 @@ where .zip(&mut tree.children) .zip(layout.children()) .for_each(|((child, state), c_layout)| { - child - .as_widget_mut() - .operate(state, c_layout.with_virtual_offset(layout.virtual_offset()), renderer, operation); + child.as_widget_mut().operate( + state, + c_layout.with_virtual_offset(layout.virtual_offset()), + renderer, + operation, + ); }); }); } @@ -318,7 +320,13 @@ where .zip(layout.children()) { child.as_widget_mut().update( - tree, event, c_layout.with_virtual_offset(layout.virtual_offset()), cursor, renderer, clipboard, shell, + tree, + event, + c_layout.with_virtual_offset(layout.virtual_offset()), + cursor, + renderer, + clipboard, + shell, viewport, ); } @@ -337,9 +345,13 @@ where .zip(&tree.children) .zip(layout.children()) .map(|((child, tree), c_layout)| { - child - .as_widget() - .mouse_interaction(tree, c_layout.with_virtual_offset(layout.virtual_offset()), cursor, viewport, renderer) + child.as_widget().mouse_interaction( + tree, + c_layout.with_virtual_offset(layout.virtual_offset()), + cursor, + viewport, + renderer, + ) }) .max() .unwrap_or_default() diff --git a/widget/src/list.rs b/widget/src/list.rs index de9fe9b8..9f33244e 100644 --- a/widget/src/list.rs +++ b/widget/src/list.rs @@ -1,5 +1,5 @@ #![allow(missing_docs)] -use crate::core::event::{self, Event}; +use crate::core::event::Event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; @@ -363,24 +363,25 @@ where let state = tree.state.downcast_mut::(); let offset = layout.position() - Point::ORIGIN; - self.visible_elements + for (element, (index, layout, tree)) in self + .visible_elements .iter_mut() .zip(&mut state.visible_layouts) - .map(|(element, (index, layout, tree))| { - element.as_widget_mut().update( - tree, - event, - Layout::with_offset( - offset + Vector::new(0.0, self.spacing * *index as f32), - layout, - ), - cursor, - renderer, - clipboard, - shell, - viewport, - ) - }); + { + element.as_widget_mut().update( + tree, + event, + Layout::with_offset( + offset + Vector::new(0.0, self.spacing * *index as f32), + layout, + ), + cursor, + renderer, + clipboard, + shell, + viewport, + ); + } if let Event::Window(window::Event::RedrawRequested(_)) = event { match &mut state.task { diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs index 3d355c52..4d808348 100644 --- a/widget/src/mouse_area.rs +++ b/widget/src/mouse_area.rs @@ -2,7 +2,6 @@ use iced_renderer::core::mouse::Click; -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs index a76010e7..4c41e3a6 100644 --- a/widget/src/pane_grid/content.rs +++ b/widget/src/pane_grid/content.rs @@ -6,7 +6,7 @@ use crate::core::renderer; use crate::core::widget::{self, Tree}; use crate::core::{ self, Clipboard, Element, Event, Layout, Point, Rectangle, Shell, Size, - Vector, event, + Vector, }; use crate::pane_grid::{Draggable, TitleBar}; diff --git a/widget/src/radio.rs b/widget/src/radio.rs index 1aa97355..bdca259c 100644 --- a/widget/src/radio.rs +++ b/widget/src/radio.rs @@ -459,6 +459,7 @@ where state.raw(), crate::text::Style { color: style.text_color, + ..crate::text::Style::default() }, viewport, ); diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index e005a7b8..c906b66e 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -27,7 +27,6 @@ use iced_runtime::core::widget::Id; #[cfg(feature = "a11y")] use std::borrow::Cow; -use crate::core::event; use crate::core::keyboard; use crate::core::layout; use crate::core::mouse; @@ -933,7 +932,7 @@ where let had_input_method = shell.input_method().is_enabled(); - let mut c_event = match event.clone() { + let c_event = match event.clone() { Event::Dnd(dnd::DndEvent::Offer( id, dnd::OfferEvent::Enter { diff --git a/widget/src/stack.rs b/widget/src/stack.rs index e85bf2af..cd30a886 100644 --- a/widget/src/stack.rs +++ b/widget/src/stack.rs @@ -1,6 +1,5 @@ //! Display content on top of other content. -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/text/rich.rs b/widget/src/text/rich.rs index cd368e83..ef44e2bf 100644 --- a/widget/src/text/rich.rs +++ b/widget/src/text/rich.rs @@ -179,7 +179,10 @@ where { let color = color.map(Into::into); - self.style(move |_theme| Style { color }) + self.style(move |_theme| Style { + color, + ..Style::default() + }) } /// Sets the default style class of the [`Rich`] text. diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index b93c96f3..34a8825f 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -544,6 +544,8 @@ pub struct State { highlighter: RefCell, highlighter_settings: Highlighter::Settings, highlighter_format_address: usize, + context_menu_position: Option, + pending_edit: Option, } #[derive(Debug, Clone)] @@ -579,6 +581,14 @@ impl State { pub fn is_focused(&self) -> bool { self.focus.is_some() } + + /// Clears focus, selection, and all interaction state. + pub fn clear_focus(&mut self) { + self.focus = None; + self.drag_click = None; + self.context_menu_position = None; + self.pending_edit = Some(Action::ClearSelection); + } } impl operation::Focusable @@ -593,7 +603,7 @@ impl operation::Focusable } fn unfocus(&mut self) { - self.focus = None; + self.clear_focus(); } } @@ -621,6 +631,8 @@ where )), highlighter_settings: self.highlighter_settings.clone(), highlighter_format_address: self.highlighter_format as usize, + context_menu_position: None, + pending_edit: None, }) } @@ -699,6 +711,58 @@ where shell: &mut Shell<'_, Message>, _viewport: &Rectangle, ) { + // Handle context menu and focus-loss on clicks outside. + { + let state = tree.state.downcast_mut::>(); + let text_bounds = layout.bounds(); + + if matches!( + event, + Event::Mouse(mouse::Event::ButtonPressed(_)) + | Event::Touch( + crate::core::touch::Event::FingerPressed { .. } + ) + ) && cursor.position_over(text_bounds).is_none() + { + state.clear_focus(); + } + + match event { + Event::Mouse(mouse::Event::ButtonPressed( + mouse::Button::Right, + )) => { + if let Some(pos) = cursor.position_over(text_bounds) { + if state.focus.is_none() { + state.focus = Some(Focus::now()); + } + state.context_menu_position = Some(pos); + shell.capture_event(); + return; + } + } + Event::Mouse(mouse::Event::ButtonPressed( + mouse::Button::Left, + )) => { + if state.context_menu_position.take().is_some() { + shell.capture_event(); + return; + } + } + _ => {} + } + } + + // Process pending edits from context menu + // publishes via on_edit so the app calls content.perform(). + { + let state = tree.state.downcast_mut::>(); + if let Some(action) = state.pending_edit.take() { + if let Some(on_edit) = self.on_edit.as_ref() { + shell.publish((on_edit)(action)); + } + } + } + let Some(on_edit) = self.on_edit.as_ref() else { return; }; @@ -1223,6 +1287,23 @@ impl Binding { return Some(binding); } + let alt_clipboard = match key.as_ref() { + keyboard::Key::Named(key::Named::Insert) if modifiers.shift() => { + Some(Self::Paste) + } + keyboard::Key::Named(key::Named::Insert) if modifiers.command() => { + Some(Self::Copy) + } + keyboard::Key::Named(key::Named::Delete) if modifiers.shift() => { + Some(Self::Cut) + } + _ => None, + }; + + if let Some(binding) = alt_clipboard { + return Some(binding); + } + #[cfg(target_os = "macos")] let modified_key = convert_macos_shortcut(&key, modifiers).unwrap_or(modified_key); @@ -1545,3 +1626,63 @@ pub(crate) fn convert_macos_shortcut( Some(keyboard::Key::Named(key)) } + +use crate::core::widget::text::HasSelectableText; + +impl HasSelectableText + for TextEditor<'_, Highlighter, Message, Theme, Renderer> +where + Highlighter: text::Highlighter, + Theme: Catalog, + Renderer: text::Renderer, +{ + fn selected_text(&self, _tree: &widget::Tree) -> Option { + self.content.selection() + } + + fn select_all(&self, tree: &mut widget::Tree) { + let state = tree.state.downcast_mut::>(); + state.pending_edit = Some(Action::SelectAll); + } + + fn is_editable(&self) -> bool { + self.on_edit.is_some() + } + + fn is_focused(&self, tree: &widget::Tree) -> bool { + tree.state.downcast_ref::>().is_focused() + } + + fn context_menu_position(&self, tree: &widget::Tree) -> Option { + tree.state + .downcast_ref::>() + .context_menu_position + } + + fn set_context_menu_position( + &self, + tree: &mut widget::Tree, + pos: Option, + ) { + tree.state + .downcast_mut::>() + .context_menu_position = pos; + } + + fn delete_selection(&self, tree: &mut widget::Tree) -> Option { + let state = tree.state.downcast_mut::>(); + state.pending_edit = Some(Action::Edit(Edit::Delete)); + Some(String::new()) + } + + fn paste_text( + &self, + tree: &mut widget::Tree, + text: &str, + ) -> Option { + let state = tree.state.downcast_mut::>(); + state.pending_edit = + Some(Action::Edit(Edit::Paste(Arc::new(text.to_owned())))); + Some(String::new()) + } +} diff --git a/widget/src/themer.rs b/widget/src/themer.rs index 306c8580..76448ae1 100644 --- a/widget/src/themer.rs +++ b/widget/src/themer.rs @@ -1,6 +1,5 @@ use crate::container; -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index d398a79b..b4e66887 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -37,7 +37,6 @@ use std::borrow::Cow; use iced_runtime::core::border::Radius; use crate::core::alignment; -use crate::core::border; use crate::core::layout; use crate::core::mouse; use crate::core::renderer; @@ -483,6 +482,7 @@ where state.raw(), crate::text::Style { color: style.text_color, + ..crate::text::Style::default() }, viewport, ); @@ -509,7 +509,7 @@ where let space = style.handle_margin; - let toggler_background_bounds = Rectangle { + let _toggler_background_bounds = Rectangle { x: bounds.x, y: bounds.y, width: bounds.width, @@ -529,7 +529,7 @@ where style.background, ); - let padding = (style.padding_ratio * bounds.height).round(); + let _padding = (style.padding_ratio * bounds.height).round(); let toggler_foreground_bounds = Rectangle { x: bounds.x + if self.is_toggled { diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 1208cc17..41e4a582 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -37,6 +37,8 @@ cctk = [ "xkeysym", "dep:cctk", ] +# Prevents multiple separate process instances. +single-instance = [] [dependencies] diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index fcb73c39..97cc97a6 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -178,7 +178,7 @@ pub fn window_attributes( ), )); } - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(target_os = "linux")] { use winit::platform::wayland::WindowAttributesWayland; @@ -387,19 +387,19 @@ pub fn window_event( self::modifiers(new_modifiers.state()), ))) } - WindowEvent::Ime(event) => Some(Event::InputMethod(match event { - Ime::Enabled => input_method::Event::Opened, - Ime::Preedit(content, size) => input_method::Event::Preedit( + WindowEvent::Ime(event) => match event { + Ime::Enabled => Some(input_method::Event::Opened), + Ime::Preedit(content, size) => Some(input_method::Event::Preedit( content, size.map(|(start, end)| start..end), - ), - Ime::Commit(content) => input_method::Event::Commit(content), - Ime::Disabled => input_method::Event::Closed, - Ime::DeleteSurrounding { - before_bytes, - after_bytes, - } => todo!(), - })), + )), + Ime::Commit(content) => Some(input_method::Event::Commit(content)), + Ime::Disabled => Some(input_method::Event::Closed), + // Upstream iced depends on the winit version which doesn't support + // this kind of ime event. + Ime::DeleteSurrounding { .. } => None, + } + .map(Event::InputMethod), WindowEvent::Focused(focused) => Some(Event::Window(if focused { window::Event::Focused } else { diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 735d73aa..918f6c2a 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -40,12 +40,6 @@ pub mod clipboard; pub mod conversion; pub mod platform_specific; -#[cfg(feature = "program")] -pub mod program; - -#[cfg(feature = "system")] -pub mod system; - mod error; mod proxy; mod window; @@ -192,11 +186,15 @@ where receiver: mpsc::UnboundedReceiver, error: Option, system_theme: Option>, - control_sender: mpsc::UnboundedSender, - #[cfg(feature = "a11y")] - adapters: std::collections::HashMap, - + control_sender: mpsc::UnboundedSender, + + #[cfg(feature = "a11y")] + adapters: std::collections::HashMap< + window::Id, + (u64, iced_accessibility::accesskit_winit::Adapter), + >, + #[cfg(target_arch = "wasm32")] is_booted: std::rc::Rc>, #[cfg(target_arch = "wasm32")] @@ -215,6 +213,7 @@ where id: settings.id, sender: event_sender, receiver: control_receiver, + #[cfg(feature = "a11y")] control_sender: control_sender.clone(), error: None, system_theme: Some(system_theme_sender), @@ -501,9 +500,15 @@ where } }; } - let window: Arc = Arc::from(window); + let window: Arc< + dyn winit::window::Window + 'static, + > = Arc::from(window); #[cfg(feature = "a11y")] - self.init_adapter(event_loop, id, window.clone()); + self.init_adapter( + event_loop, + id, + window.clone(), + ); self.process_event( event_loop, @@ -572,11 +577,13 @@ where .expect("Send event"); } Control::Winit(id, e) => { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(all( + feature = "cctk", + target_os = "linux" + ))] { if matches!(e, WindowEvent::RedrawRequested) - { - + { for id in crate::subsurface_widget::subsurface_ids(id) { _ = self.sender .unbounded_send(Event::Winit( @@ -597,7 +604,7 @@ where } } } - + self.sender .start_send(Event::Winit(id, e)) .expect("Send event"); @@ -610,7 +617,7 @@ where #[cfg(feature = "a11y")] Control::InitAdapter(id, window) => { self.init_adapter(event_loop, id, window); - + self.process_event( event_loop, Some(Event::A11yAdapter(id)), @@ -618,8 +625,8 @@ where } #[cfg(feature = "a11y")] Control::Cleanup(id) => { - _ = self.adapters.remove(&id); - }, + _ = self.adapters.remove(&id); + } }, _ => { break; @@ -633,34 +640,35 @@ where } } - #[cfg(feature = "a11y")] - fn init_adapter(&mut self, event_loop: &(dyn winit::event_loop::ActiveEventLoop + 'static), id: core::window::Id, window: Arc) { + #[cfg(feature = "a11y")] + fn init_adapter( + &mut self, + event_loop: &(dyn winit::event_loop::ActiveEventLoop + 'static), + id: core::window::Id, + window: Arc, + ) { use crate::a11y::*; use iced_accessibility::accesskit::{ - ActivationHandler, Node, NodeId, Role, - Tree, TreeUpdate, + ActivationHandler, Node, NodeId, Role, Tree, TreeUpdate, }; use iced_accessibility::accesskit_winit::Adapter; - - let node_id = - iced_runtime::core::id::window_node_id(); - - let activation_handler = - WinitActivationHandler { - proxy: self.control_sender.clone(), - title: String::new(), - }; - + + let node_id = iced_runtime::core::id::window_node_id(); + + let activation_handler = WinitActivationHandler { + proxy: self.control_sender.clone(), + title: String::new(), + }; + let action_handler = WinitActionHandler { id, proxy: self.control_sender.clone(), }; - - let deactivation_handler = - WinitDeactivationHandler { - proxy: self.control_sender.clone(), - }; - + + let deactivation_handler = WinitDeactivationHandler { + proxy: self.control_sender.clone(), + }; + _ = self.adapters.insert( id, ( @@ -674,8 +682,6 @@ where ), ), ); - - } } @@ -838,6 +844,28 @@ async fn run_instance

( log::info!("System theme: {system_theme:?}"); + macro_rules! run_action { + ($action:expr) => { + run_action( + $action, + &program, + &mut runtime, + &mut compositor, + &mut events, + &mut messages, + &mut clipboard, + &mut control_sender, + &mut user_interfaces, + &mut window_manager, + &mut ui_caches, + &mut is_window_opening, + &mut system_theme, + &mut platform_specific_handler, + is_daemon, + ) + }; + } + 'next_event: loop { // Empty the queue if possible let event = if let Ok(event) = event_receiver.try_recv() { @@ -857,35 +885,36 @@ async fn run_instance

( exit_on_close_request, make_visible, on_open, - resize_border + resize_border, } => { - #[cfg(all(feature = "cctk", target_os = "linux"))] platform_specific_handler.send_wayland( platform_specific::Action::TrackWindow(window.clone(), id), ); - match create_compositor::

( - window.clone(), - CreateCompositor { - proxy: &proxy, - runtime: &mut runtime, - display_handle: &display_handle, - graphics_settings: &graphics_settings, - default_fonts: &default_fonts, - }, - ) - .await - { - Ok(comp) => { - compositor = Some(comp); - } - Err(error) => { - control_sender - .start_send(Control::Crash( - Error::GraphicsCreationFailed(error), - )) - .expect("Send control message"); - continue; + if compositor.is_none() { + match create_compositor::

( + window.clone(), + CreateCompositor { + proxy: &proxy, + runtime: &mut runtime, + display_handle: &display_handle, + graphics_settings: &graphics_settings, + default_fonts: &default_fonts, + }, + ) + .await + { + Ok(comp) => { + compositor = Some(comp); + } + Err(error) => { + control_sender + .start_send(Control::Crash( + Error::GraphicsCreationFailed(error), + )) + .expect("Send control message"); + continue; + } } } @@ -913,7 +942,7 @@ async fn run_instance

( compositor, exit_on_close_request, system_theme, - resize_border + resize_border, ); window.raw.set_theme(conversion::window_theme( @@ -999,22 +1028,7 @@ async fn run_instance

( } } Event::UserEvent(action) => { - let exited = run_action( - action, - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - ); + let exited = run_action!(action); if exited { runtime.track(None.into_iter()); } @@ -1025,7 +1039,7 @@ async fn run_instance

( continue; }; - let Some((id, mut window)) = + let Some((id, mut window)) = window_manager.get_mut_alias(window_id) else { continue; @@ -1040,12 +1054,12 @@ async fn run_instance

( )) .expect("Send redraw event"); continue; - } + } // XX must force update to corner radius before the surface is committed. #[cfg(all(feature = "cctk", target_os = "linux"))] if (window.surface_version != window.state.surface_version() - || window.logical_size() != window.state.logical_size() - ) && !crate::subsurface_widget::is_subsurface(window_id) + || window.logical_size() != window.state.logical_size()) + && !crate::subsurface_widget::is_subsurface(window_id) { platform_specific_handler.send_wayland( platform_specific::Action::ResizeWindow(id), @@ -1156,22 +1170,7 @@ async fn run_instance

( continue; } - _ = run_action( - action, - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - ); + _ = run_action!(action); } for (window_id, window) in window_manager.iter_mut() { @@ -1326,9 +1325,7 @@ async fn run_instance

( continue; }; // Initiates a drag resize window state when found. - if let Some(func) = - window.drag_resize_window_func.as_mut() - { + if let Some(func) = window.drag_resize_window_func.as_mut() { if func(window.raw.as_ref(), &event) { continue; } @@ -1354,22 +1351,9 @@ async fn run_instance

( if matches!(event, winit::event::WindowEvent::CloseRequested) && window.exit_on_close_request { - _ = run_action( - Action::Window(runtime::window::Action::Close(id)), - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - ); + _ = run_action!(Action::Window( + runtime::window::Action::Close(id) + )); } else { window.state.update(&program, window.raw.as_ref(), &event); @@ -1547,22 +1531,7 @@ async fn run_instance

( )); for action in actions { - let exited = run_action( - action, - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - ); + let exited = run_action!(action); if exited { runtime.track(None.into_iter()); } @@ -1772,7 +1741,6 @@ async fn run_instance

( }; // search windows for widget with operation - if result.is_none() { log::warn!( "start_dnd: widget {:?} not found; drag will fail", @@ -2106,6 +2074,7 @@ fn run_action<'a, P, C>( is_window_opening: &mut bool, system_theme: &mut theme::Mode, platform_specific: &mut crate::platform_specific::PlatformSpecific, + is_daemon: bool, ) -> bool where P: Program, @@ -2148,7 +2117,7 @@ where on_open: channel, }) .expect("Send control action"); - + *is_window_opening = true; } window::Action::Close(id) => { @@ -2190,7 +2159,7 @@ where )); } - if window_manager.is_empty() { + if window_manager.is_empty() && !is_daemon { *compositor = None; } } diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index 9b74ee9c..5e84d16a 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -153,9 +153,12 @@ impl PlatformSpecific { ) -> Option> { #[cfg(all(feature = "cctk", target_os = "linux"))] { - return self.wayland.create_surface(); + self.wayland.create_surface() + } + #[cfg(not(all(feature = "cctk", target_os = "linux")))] + { + None } - None } pub(crate) fn update_surface_shm( diff --git a/winit/src/platform_specific/wayland/commands/activation.rs b/winit/src/platform_specific/wayland/commands/activation.rs index fa051031..442ee08c 100644 --- a/winit/src/platform_specific/wayland/commands/activation.rs +++ b/winit/src/platform_specific/wayland/commands/activation.rs @@ -1,8 +1,8 @@ use crate::core::window::Id as SurfaceId; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; pub fn request_token( diff --git a/winit/src/platform_specific/wayland/commands/blur.rs b/winit/src/platform_specific/wayland/commands/blur.rs new file mode 100644 index 00000000..e9a73646 --- /dev/null +++ b/winit/src/platform_specific/wayland/commands/blur.rs @@ -0,0 +1,17 @@ +use iced_futures::core::window; +use iced_runtime::{ + self, Action, Task, + platform_specific::{self, wayland}, + task, +}; + +pub fn blur( + id: window::Id, + blur: Option>, +) -> Task<()> { + task::oneshot(|_| { + Action::PlatformSpecific(platform_specific::Action::Wayland( + wayland::Action::BlurSurface(id, blur), + )) + }) +} diff --git a/winit/src/platform_specific/wayland/commands/corner_radius.rs b/winit/src/platform_specific/wayland/commands/corner_radius.rs index c5ba6016..4cc122dd 100644 --- a/winit/src/platform_specific/wayland/commands/corner_radius.rs +++ b/winit/src/platform_specific/wayland/commands/corner_radius.rs @@ -1,11 +1,11 @@ use iced_futures::core::window; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, wayland::{self, CornerRadius}, }, - task, Action, Task, + task, }; pub fn corner_radius( diff --git a/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs b/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs index 783b62c6..afc2e27b 100644 --- a/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs +++ b/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs @@ -1,7 +1,7 @@ use iced_runtime::{ - self, + self, Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; pub fn inhibit_shortcuts(inhibit: bool) -> Task<()> { diff --git a/winit/src/platform_specific/wayland/commands/layer_surface.rs b/winit/src/platform_specific/wayland/commands/layer_surface.rs index 839db95c..cdb4e93d 100644 --- a/winit/src/platform_specific/wayland/commands/layer_surface.rs +++ b/winit/src/platform_specific/wayland/commands/layer_surface.rs @@ -2,7 +2,7 @@ use crate::core::window::Id as SurfaceId; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, wayland::{ @@ -10,7 +10,7 @@ use iced_runtime::{ layer_surface::{IcedMargin, SctkLayerSurfaceSettings}, }, }, - task, Action, Task, + task, }; pub use cctk::sctk::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer}; @@ -114,3 +114,14 @@ pub fn set_layer(id: SurfaceId, layer: Layer) -> Task { )), )) } + +pub fn set_padding( + id: SurfaceId, + padding: IcedMargin, +) -> Task { + task::effect(Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::LayerSurface( + wayland::layer_surface::Action::Padding { id, padding }, + )), + )) +} diff --git a/winit/src/platform_specific/wayland/commands/mod.rs b/winit/src/platform_specific/wayland/commands/mod.rs index 191dc3a5..cd6832c7 100644 --- a/winit/src/platform_specific/wayland/commands/mod.rs +++ b/winit/src/platform_specific/wayland/commands/mod.rs @@ -1,6 +1,7 @@ //! Interact with the wayland objects of your application. pub mod activation; +pub mod blur; pub mod corner_radius; pub mod keyboard_shortcuts_inhibit; pub mod layer_surface; diff --git a/winit/src/platform_specific/wayland/commands/overlap_notify.rs b/winit/src/platform_specific/wayland/commands/overlap_notify.rs index 860838c3..417cfb24 100644 --- a/winit/src/platform_specific/wayland/commands/overlap_notify.rs +++ b/winit/src/platform_specific/wayland/commands/overlap_notify.rs @@ -1,7 +1,8 @@ use iced_futures::core::window::Id; use iced_runtime::{ + Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; /// Request subscription for overlap notification events on the surface diff --git a/winit/src/platform_specific/wayland/commands/popup.rs b/winit/src/platform_specific/wayland/commands/popup.rs index f70d97f4..c702f4f1 100644 --- a/winit/src/platform_specific/wayland/commands/popup.rs +++ b/winit/src/platform_specific/wayland/commands/popup.rs @@ -1,12 +1,15 @@ //! Interact with the popups of your application. use crate::core::window::Id as SurfaceId; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, - wayland::{self, popup::SctkPopupSettings}, + wayland::{ + self, + popup::{SctkPopupSettings, SctkPositioner}, + }, }, - task, Action, Task, + task, }; /// @@ -32,6 +35,18 @@ pub fn set_size( )) } +/// +pub fn reposition( + id: SurfaceId, + positioner: SctkPositioner, +) -> Task { + task::effect(Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::Popup( + wayland::popup::Action::Reposition { id, positioner }, + )), + )) +} + /// pub fn destroy_popup(id: SurfaceId) -> Task { task::effect(Action::PlatformSpecific( diff --git a/winit/src/platform_specific/wayland/commands/session_lock.rs b/winit/src/platform_specific/wayland/commands/session_lock.rs index 7f8748f7..a530c12e 100644 --- a/winit/src/platform_specific/wayland/commands/session_lock.rs +++ b/winit/src/platform_specific/wayland/commands/session_lock.rs @@ -1,9 +1,9 @@ use crate::core::window::Id as SurfaceId; use cctk::sctk::reexports::client::protocol::wl_output::WlOutput; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; pub fn lock() -> Task { diff --git a/winit/src/platform_specific/wayland/commands/subsurface.rs b/winit/src/platform_specific/wayland/commands/subsurface.rs index a76e3b4e..20c3cdb7 100644 --- a/winit/src/platform_specific/wayland/commands/subsurface.rs +++ b/winit/src/platform_specific/wayland/commands/subsurface.rs @@ -1,12 +1,12 @@ use crate::core::window::Id as SurfaceId; pub use cctk::sctk::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer}; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, wayland::{self, subsurface::SctkSubsurfaceSettings}, }, - task, Action, Task, + task, }; pub fn get_subsurface( diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 6c63f218..b4589840 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -7,7 +7,10 @@ use crate::platform_specific::SurfaceIdWrapper; use crate::{ Control, futures::futures::channel::mpsc, - handlers::{overlap::OverlapNotifyV1, text_input::TextInputManager}, + handlers::{ + ext_background_effect, overlap::OverlapNotifyV1, + text_input::TextInputManager, + }, platform_specific::wayland::{ handlers::{ wp_fractional_scaling::FractionalScalingManager, @@ -30,7 +33,7 @@ use cctk::{ reexports::{ calloop::{self, EventLoop}, client::{ - ConnectError, Connection, Proxy, globals::registry_queue_init, + Connection, Proxy, globals::registry_queue_init, }, }, registry::RegistryState, @@ -43,8 +46,6 @@ use cctk::{ }; use raw_window_handle::HasDisplayHandle; use state::{FrameStatus, SctkWindow, send_event}; -#[cfg(feature = "a11y")] -use std::sync::{Arc, Mutex}; use std::{ collections::{HashMap, HashSet}, fmt::Debug, @@ -68,8 +69,8 @@ pub struct SctkEventLoop { pub(crate) state: SctkState, } +#[derive(Debug)] pub enum Error { - Connect(ConnectError), Calloop(calloop::Error), Global(GlobalError), NoDisplayHandle, @@ -126,7 +127,7 @@ impl SctkEventLoop { crate::platform_specific::Action::ResizeWindow(id) => { if let Some((_, v)) = state.windows.iter() .find(|w| w.id == id) - .map(|w| w.corner_radius.as_ref()) + .map(|w| state.corner_radii.get(&id)) .unwrap_or_default() { _ = state.handle_action(iced_runtime::platform_specific::wayland::Action::RoundedCorners(id, *v)); } @@ -135,7 +136,7 @@ impl SctkEventLoop { window, id, ) => { - state.windows.push(SctkWindow { window, id, corner_radius: Default::default() }); + state.windows.push(SctkWindow { window, id }); if let Some(v) = state.pending_corner_radius.remove(&id) { _ = state.handle_action(iced_runtime::platform_specific::wayland::Action::RoundedCorners(id, Some(v))); } @@ -346,26 +347,26 @@ impl SctkEventLoop { &qh, ), corner_radius_manager: registry_state.bind_one::( - &qh, - 1..=1, - (), - ).ok(), + &qh, + 1..=2, + (), + ).ok(), toplevel_manager: ToplevelManagerState::try_new( ®istry_state, &qh, ), - inhibitor_manager: registry_state.bind_one::( - &qh, - 1..=1, - (), - ).ok(), + inhibitor_manager: registry_state.bind_one::( + &qh, + 1..=1, + (), + ).ok(), text_input_manager: TextInputManager::try_new(®istry_state, &qh), + ext_background_effect_manager: ext_background_effect::ExtBackgroundEffectManager::new(&globals, &qh).ok(), registry_state, queue_handle: qh, loop_handle, - inhibitor: None, inhibited: false, _cursor_surface: None, @@ -373,6 +374,8 @@ impl SctkEventLoop { outputs: Vec::new(), seats: Vec::new(), windows: Vec::new(), + blur_surfaces: HashMap::new(), + corner_radii: HashMap::new(), layer_surfaces: Vec::new(), popups: Vec::new(), lock_surfaces: Vec::new(), @@ -398,6 +401,7 @@ impl SctkEventLoop { preedit: None, pending_delete: None, pending_commit: None, + pending_blur: HashMap::new(), }, _features: Default::default(), }; @@ -484,6 +488,23 @@ impl SctkEventLoop { let had_events = !state.state.sctk_events.is_empty(); let mut wake_up = had_events; + for e in state.state.sctk_events.drain(..) { + if let SctkEvent::Winit(id, e) = e { + _ = state + .state + .events_sender + .unbounded_send(Control::Winit(id, e)); + } else { + _ = + state + .state + .events_sender + .unbounded_send(Control::PlatformSpecific( + crate::platform_specific::Event::Wayland(e), + )); + } + } + for s in state .state @@ -528,22 +549,6 @@ impl SctkEventLoop { ); } - for e in state.state.sctk_events.drain(..) { - if let SctkEvent::Winit(id, e) = e { - _ = state - .state - .events_sender - .unbounded_send(Control::Winit(id, e)); - } else { - _ = - state - .state - .events_sender - .unbounded_send(Control::PlatformSpecific( - crate::platform_specific::Event::Wayland(e), - )); - } - } if wake_up { state.state.proxy.wake_up(); } diff --git a/winit/src/platform_specific/wayland/event_loop/proxy.rs b/winit/src/platform_specific/wayland/event_loop/proxy.rs index bdbc44a4..58229dc1 100644 --- a/winit/src/platform_specific/wayland/event_loop/proxy.rs +++ b/winit/src/platform_specific/wayland/event_loop/proxy.rs @@ -1,8 +1,8 @@ use cctk::sctk::reexports::calloop; use iced_futures::futures::{ + Sink, channel::mpsc, task::{Context, Poll}, - Sink, }; use std::pin::Pin; diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 9c9a4e11..b817e4d5 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -2,7 +2,9 @@ use crate::{ Control, handlers::{ activation::IcedRequestData, + ext_background_effect, overlap::{OverlapNotificationV1, OverlapNotifyV1}, + shell::corner_radius::CornerRadiusWrapper, text_input::{Preedit, TextInputManager}, }, platform_specific::{ @@ -25,11 +27,10 @@ use iced_futures::{ }; use raw_window_handle::HasWindowHandle; use std::{ - collections::{HashMap, HashSet}, + collections::{HashMap, HashSet, hash_map::Entry}, convert::Infallible, fmt::Debug, sync::{Arc, Mutex, atomic::AtomicU32}, - thread::panicking, time::Duration, }; use wayland_backend::client::ObjectId; @@ -40,17 +41,13 @@ use winit::{ use cctk::{ cosmic_protocols::{ - corner_radius::v1::client::{ - cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, - cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, - }, + corner_radius::v1::client::cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, }, sctk::{ activation::{ActivationState, RequestData}, compositor::CompositorState, error::GlobalError, - globals::GlobalData, output::OutputState, reexports::{ calloop::{LoopHandle, timer::TimeoutAction}, @@ -66,11 +63,12 @@ use cctk::{ wl_touch::WlTouch, }, }, + protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, }, registry::RegistryState, seat::{ SeatState, - keyboard::KeyEvent, + keyboard::{KeyEvent, Modifiers}, pointer::{CursorIcon, PointerData, ThemedPointer}, touch::TouchData, }, @@ -96,7 +94,6 @@ use cctk::{ }; use iced_runtime::{ core::{self, Point, touch}, - keyboard::Modifiers, platform_specific::{ self, wayland::{ @@ -108,6 +105,10 @@ use iced_runtime::{ }, }; use wayland_protocols::{ + ext::background_effect::v1::client::{ + ext_background_effect_manager_v1, + ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1, + }, wp::{ fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, keyboard_shortcuts_inhibit::zv1::client::{ @@ -341,22 +342,12 @@ pub struct SctkPopupData { pub(crate) grab: bool, } -#[derive(Debug)] -pub struct MyCosmicCornerRadiusToplevelV1(CosmicCornerRadiusToplevelV1); - -impl Drop for MyCosmicCornerRadiusToplevelV1 { - fn drop(&mut self) { - self.0.destroy(); - } -} - #[derive(Debug, Clone)] -pub struct SctkCornerRadius(Arc); +pub struct SctkCornerRadius(Arc); pub struct SctkWindow { pub(crate) window: Arc, pub(crate) id: core::window::Id, - pub(crate) corner_radius: Option<(SctkCornerRadius, Option)>, } impl SctkWindow { @@ -443,6 +434,8 @@ pub struct SctkState { pub(crate) popups: Vec, pub(crate) subsurfaces: Vec, pub(crate) lock_surfaces: Vec, + pub(crate) blur_surfaces: HashMap, + pub(crate) corner_radii: HashMap)>, pub(crate) touch_points: HashMap, /// Window updates, which are coming from SCTK or the compositor, which require @@ -485,6 +478,7 @@ pub struct SctkState { pub(crate) toplevel_info: Option, pub(crate) toplevel_manager: Option, pub(crate) subsurface_state: Option, + pub(crate) ext_background_effect_manager: Option, pub(crate) activation_token_ctr: u32, pub(crate) token_senders: HashMap>>, @@ -495,6 +489,7 @@ pub struct SctkState { pub(crate) corner_radius_manager: Option, pub(crate) pending_corner_radius: HashMap, + pub(crate) pending_blur: HashMap>, pub(crate) text_input_manager: Option, pub(crate) text_input: Option>, @@ -506,6 +501,10 @@ pub struct SctkState { /// An error that occurred while running an application. #[derive(Debug, thiserror::Error)] pub enum PopupCreationError { + /// The requested ID already exists. + #[error("The requested ID already exists")] + AlreadyExists, + /// Positioner creation failed #[error("Positioner creation failed")] PositionerCreationFailed(GlobalError), @@ -526,6 +525,10 @@ pub enum PopupCreationError { /// An error that occurred while running an application. #[derive(Debug, thiserror::Error)] pub enum LayerSurfaceCreationError { + /// The requested ID already exists. + #[error("The requested ID already exists")] + AlreadyExists, + /// Layer shell is not supported by the compositor #[error("Layer shell is not supported by the compositor")] LayerShellNotSupported, @@ -542,6 +545,10 @@ pub enum LayerSurfaceCreationError { /// An error that occurred while running an application. #[derive(Debug, thiserror::Error)] pub enum SubsurfaceCreationError { + /// The requested ID already exists. + #[error("The requested ID already exists")] + AlreadyExists, + /// Subsurface creation failed #[error("Subsurface creation failed")] CreationFailed(GlobalError), @@ -666,9 +673,7 @@ impl SctkState { // TODO winit sets cursor size after handling the change for the window, so maybe that should be done as well. } -} -impl SctkState { pub fn get_popup( &mut self, settings: SctkPopupSettings, @@ -682,6 +687,18 @@ impl SctkState { ), PopupCreationError, > { + if self.layer_surfaces.iter().any(|s| s.id == settings.id) + || self.windows.iter().any(|w| w.id == settings.id) + || self.popups.iter().any(|p| p.data.id == settings.id) + || self.subsurfaces.iter().any(|s| s.id == settings.id) + { + log::warn!( + "Popup surface with id {:?} already exists", + settings.id + ); + return Err(PopupCreationError::AlreadyExists); + } + let (parent, toplevel) = if let Some(parent) = self.layer_surfaces.iter().find(|l| l.id == settings.parent) { @@ -823,6 +840,7 @@ impl SctkState { ) } }; + let toplevel = toplevel.clone(); popup.xdg_surface().set_window_geometry( 0, @@ -855,7 +873,10 @@ impl SctkState { } _ = wl_surface.frame(&self.queue_handle, wl_surface.clone()); - wl_surface.commit(); + + if let Some(blur) = self.pending_blur.remove(&settings.id) { + self.apply_blur(settings.id, Some(blur), &wl_surface); + } let wp_viewport = self.viewporter_state.as_ref().map(|state| { let viewport = @@ -888,6 +909,13 @@ impl SctkState { close_with_children: settings.close_with_children, }); + if let Some(corners) = self.pending_corner_radius.remove(&settings.id) { + self.handle_action(Action::RoundedCorners( + settings.id, + Some(corners), + )); + } + wl_surface.commit(); Ok(( settings.id, parent.wl_surface().clone(), @@ -922,6 +950,15 @@ impl SctkState { IcedOutput::Output(output) => Some(output), }; + if self.layer_surfaces.iter().any(|s| s.id == id) + || self.windows.iter().any(|w| w.id == id) + || self.popups.iter().any(|p| p.data.id == id) + || self.subsurfaces.iter().any(|s| s.id == id) + { + log::warn!("Layer surface with id {id:?} already exists"); + return Err(LayerSurfaceCreationError::AlreadyExists); + } + let layer_shell = self .layer_shell .as_ref() @@ -974,7 +1011,9 @@ impl SctkState { layer_surface.set_input_region(Some(®ion)); region.destroy(); } - layer_surface.commit(); + if let Some(blur) = self.pending_blur.remove(&id) { + self.apply_blur(id, Some(blur), &wl_surface); + } let wp_viewport = self.viewporter_state.as_ref().map(|state| { state.get_viewport(layer_surface.wl_surface(), &self.queue_handle) @@ -1008,6 +1047,10 @@ impl SctkState { wp_fractional_scale, common: common.clone(), }); + if let Some(corners) = self.pending_corner_radius.remove(&id) { + _ = self.handle_action(Action::RoundedCorners(id, Some(corners))); + } + layer_surface.commit(); Ok((id, CommonSurface::Layer(layer_surface), common)) } pub fn get_lock_surface( @@ -1015,6 +1058,14 @@ impl SctkState { id: core::window::Id, output: &WlOutput, ) -> Option<(CommonSurface, Arc>)> { + if self.layer_surfaces.iter().any(|s| s.id == id) + || self.windows.iter().any(|w| w.id == id) + || self.popups.iter().any(|p| p.data.id == id) + || self.subsurfaces.iter().any(|s| s.id == id) + { + log::warn!("Lock surface with id {id:?} already exists"); + return None; + } if let Some(lock) = self.session_lock.as_ref() { let wl_surface = self.compositor_state.create_surface(&self.queue_handle); @@ -1088,9 +1139,20 @@ impl SctkState { } }, platform_specific::wayland::layer_surface::Action::Destroy(id) => { + if let Some(p) = self + .popups + .iter().find_map(|p| + self.layer_surfaces.iter().find_map(|l| if l.id == id && l.surface.wl_surface() == p.data.parent.wl_surface() {Some(p.data.id)} else {None})) { + _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: p })); + } if let Some(i) = self.layer_surfaces.iter().position(|l| l.id == id) { let l = self.layer_surfaces.remove(i); + if let Some(blurred) = self.blur_surfaces.remove(&l.id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + let (removed, remaining): (Vec<_>, Vec<_>) = self .subsurfaces .drain(..) @@ -1112,6 +1174,7 @@ impl SctkState { if let Some(destroyed) = self.id_map.remove(&l.surface.wl_surface().id()) { _ = self.destroyed.insert(destroyed); } + send_event(&self.events_sender, &self.proxy, SctkEvent::LayerSurfaceEvent { variant: LayerSurfaceEventVariant::Done, id: l.surface.wl_surface().clone(), @@ -1186,6 +1249,14 @@ impl SctkState { } }, + platform_specific::wayland::layer_surface::Action::Padding { id, padding } => { + // corner radius padding + if let Some((protocol_object, _)) = self.corner_radii.get_mut(&id) { + if let CornerRadiusWrapper::Wlr(protocol_object) = protocol_object.0.as_ref() { + protocol_object.set_padding(padding.top, padding.right, padding.bottom, padding.left); + } + } + }, }, Action::Popup(action) => match action { platform_specific::wayland::popup::Action::Popup { popup: settings } => { @@ -1290,7 +1361,6 @@ impl SctkState { } }); } - // log::error!("Invalid popup Id {:?}", popup.id); } else { self.pending_popup = None; match self.get_popup(settings) { @@ -1344,6 +1414,12 @@ impl SctkState { _ = self.destroyed.insert(id); } + if let Some(blurred) = self.blur_surfaces.remove(&id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + + let (removed, remaining): (Vec<_>, Vec<_>) = self .subsurfaces .drain(..) @@ -1379,6 +1455,48 @@ impl SctkState { SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(width, height), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); } }, + platform_specific::wayland::popup::Action::Reposition { id, positioner } => { + if let Some(sctk_popup) = self + .popups + .iter_mut() + .find(|s| s.data.id == id) + { + sctk_popup.data.positioner.set_anchor(positioner.anchor); + sctk_popup.data.positioner.set_anchor_rect( + positioner.anchor_rect.x, + positioner.anchor_rect.y, + positioner.anchor_rect.width, + positioner.anchor_rect.height, + ); + if let Ok(constraint_adjustment) = + positioner.constraint_adjustment.try_into() + { + sctk_popup.data.positioner.set_constraint_adjustment(constraint_adjustment); + } + sctk_popup.data.positioner.set_gravity(positioner.gravity); + sctk_popup.data.positioner.set_offset( + positioner.offset.0, + positioner.offset.1, + ); + if positioner.reactive { + sctk_popup.data.positioner.set_reactive(); + } + let guard =sctk_popup.common.lock().unwrap(); + let w = guard.size.width; + let h = guard.size.height; + drop(guard); + let size = positioner.size.unwrap_or((w, h)); + sctk_popup.popup + .xdg_surface() + .set_window_geometry(0, 0, w as i32, h as i32); + sctk_popup.update_viewport(w, h); + // update positioner + sctk_popup.data.positioner.set_size(w as i32, h as i32); + sctk_popup.popup.reposition(&sctk_popup.data.positioner, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); let surface = sctk_popup.popup.wl_surface().clone(); + _ = send_event(&self.events_sender, &self.proxy, + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); + } + }, }, Action::Activation(activation_event) => match activation_event { platform_specific::wayland::activation::Action::RequestToken { app_id, window, channel } => { @@ -1455,6 +1573,7 @@ impl SctkState { // TODO how to handle this when there's no lock? if let Some((surface, _)) = self.get_lock_surface(id, &output) { let wl_surface = surface.wl_surface(); + receive_frame(&mut self.frame_status, &wl_surface); } } @@ -1465,6 +1584,11 @@ impl SctkState { }) { let surface = self.lock_surfaces.remove(i); + if let Some(blurred) = self.blur_surfaces.remove(&surface.id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + let (removed, remaining): (Vec<_>, Vec<_>) = self .subsurfaces .drain(..) @@ -1504,7 +1628,7 @@ impl SctkState { }; let notification = overlap_notify_state.notify.notify_on_overlap(wlr, &self.queue_handle, OverlapNotificationV1 { surface: layer_surface.surface.wl_surface().clone() }); _ = self.overlap_notifications.insert(my_id, notification); - } else { + } else if !enabled { _ = self.overlap_notifications.remove(&my_id); } } else { @@ -1536,7 +1660,7 @@ impl SctkState { let mut destroyed = vec![]; if let Some(subsurface) = self.subsurfaces.iter().position(|s| s.id == id) { let subsurface = self.subsurfaces.remove(subsurface); - destroyed.push((subsurface.instance.wl_surface.clone(), subsurface.instance.parent.clone())); + destroyed.push((subsurface.instance.wl_surface.clone(), subsurface.instance.parent.clone(), subsurface.id)); subsurface.instance.wl_surface.attach(None, 0, 0); subsurface.instance.wl_surface.commit(); @@ -1544,7 +1668,12 @@ impl SctkState { SctkEvent::SubsurfaceEvent( crate::sctk_event::SubsurfaceEventVariant::Destroyed(subsurface.instance) ) ); } - for (destroyed, parent) in destroyed { + for (destroyed, parent, id) in destroyed { + if let Some(blurred) = self.blur_surfaces.remove(&id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + if let Some((wl_surface, f)) = self.seats.iter_mut().find(|f| { f.kbd_focus.as_ref().is_some_and(|f| *f == destroyed) }).and_then(|f| Some((parent, &mut f.kbd_focus))) { @@ -1572,9 +1701,26 @@ impl SctkState { } Action::RoundedCorners(id, v) => { if let Some(manager) = self.corner_radius_manager.as_ref() { - if let Some(w) = self.windows.iter_mut().find(|w| w.id == id) { - let geo_size: LogicalSize = w.window.surface_size().cast::().to_logical(w.window.scale_factor()); - let half_min_dim = ((geo_size.width as u32).min(geo_size.height as u32) / 2); + enum Surface { + Xdg(XdgSurface, Option), + Wlr(ZwlrLayerSurfaceV1), + } + let s = if let Some(w) = self.windows.iter_mut().find(|w| w.id == id) { + Some((Surface::Xdg(w.xdg_surface(&self.connection), Some(w.xdg_toplevel(&self.connection))), w.window.surface_size().cast::().to_logical(w.window.scale_factor()))) + } else if let Some(p) = self.popups.iter_mut().find(|w| w.data.id == id) { + let guard = p.common.lock().unwrap(); + Some((Surface::Xdg(p.popup.xdg_surface().clone(), None), guard.size.cast::())) + } else if let Some(l) = self.layer_surfaces.iter_mut().find(|l| l.id == id) { + let guard = l.common.lock().unwrap(); + match l.surface.kind() { + SurfaceKind::Wlr(l) => Some((Surface::Wlr(l.clone()), guard.size.cast::())), + _ => None + } + } else { + None + }; + if let Some((s, geo_size)) = s { + let half_min_dim = (geo_size.width as u32).min(geo_size.height as u32) / 2; if let Some(radii) = v { let adjusted_radii = CornerRadius { @@ -1583,37 +1729,73 @@ impl SctkState { bottom_right: radii.bottom_right.min(half_min_dim), bottom_left: radii.bottom_left.min(half_min_dim), }; - if let Some((protocol_object, corner_radii)) = w.corner_radius.as_mut() { + if let Some((protocol_object, corner_radii)) = self.corner_radii.get_mut(&id) { if *corner_radii != Some(adjusted_radii) { - protocol_object.0.0.set_radius( + match protocol_object.0.as_ref() { + CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.set_radius( + adjusted_radii.top_left, + adjusted_radii.top_right, + adjusted_radii.bottom_right, + adjusted_radii.bottom_left, + ), + CornerRadiusWrapper::Wlr(protocol_object) => protocol_object.set_radius( + adjusted_radii.top_left, + adjusted_radii.top_right, + adjusted_radii.bottom_right, + adjusted_radii.bottom_left, + ) + }; + *corner_radii = Some(adjusted_radii.clone()); + } + } else { + + let protocol_object = match s { + Surface::Xdg(s, w) => { + if manager.version() == 1 { + if let Some(w) = w { + CornerRadiusWrapper::Xdg(manager.get_corner_radius(&w, &self.queue_handle, ())) + } else { + log::error!("Corner radius is not supported for popups on xdg shell v1"); + return Ok(()); + } + } else { + CornerRadiusWrapper::Xdg(manager.get_corner_radius_surface(&s, &self.queue_handle, ()))} + } + Surface::Wlr(l) => { + if manager.version() == 1 { + return Ok(()); + } + CornerRadiusWrapper::Wlr(manager.get_corner_radius_layer(&l, &self.queue_handle, ()))} + }; + match &protocol_object { + CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.set_radius( adjusted_radii.top_left, adjusted_radii.top_right, adjusted_radii.bottom_right, adjusted_radii.bottom_left, - ); - *corner_radii = Some(adjusted_radii.clone()); - } - } else { - let toplevel = w.xdg_toplevel(&self.connection); - - let protocol_object = manager.get_corner_radius(&toplevel, &self.queue_handle, ()); - - protocol_object.set_radius( - adjusted_radii.top_left, - adjusted_radii.top_right, - adjusted_radii.bottom_right, - adjusted_radii.bottom_left, - ); - w.corner_radius = Some((SctkCornerRadius(Arc::new(MyCosmicCornerRadiusToplevelV1( protocol_object))), Some(adjusted_radii.clone()))); + ), + CornerRadiusWrapper::Wlr(protocol_object) => protocol_object.set_radius( + adjusted_radii.top_left, + adjusted_radii.top_right, + adjusted_radii.bottom_right, + adjusted_radii.bottom_left, + ) + }; + _ = self.corner_radii.insert(id, (SctkCornerRadius(Arc::new(protocol_object)), Some(adjusted_radii.clone()))); } } else { - if let Some(old) = w.corner_radius.as_mut() { - old.0.0.as_ref().0.unset_radius(); + if let Some(old) = self.corner_radii.get_mut(&id) { + match old.0.0.as_ref() { + CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.unset_radius(), + CornerRadiusWrapper::Wlr(protocol_object) => { + protocol_object.unset_radius() + } + }; old.1 = None; } } } else { - if let Some(v) = v{ + if let Some(v) = v { _ = self.pending_corner_radius.insert(id, v); } else { _ = self.pending_corner_radius.remove(&id); @@ -1621,10 +1803,95 @@ impl SctkState { } } } + Action::BlurSurface(id, rectangles) => { + use wayland_protocols::ext::background_effect::v1::client::ext_background_effect_manager_v1; + + if let Some(bg_effect_mgr) = self.ext_background_effect_manager.as_mut() && !bg_effect_mgr.capabilities().contains(ext_background_effect_manager_v1::Capability::Blur) { + bg_effect_mgr.enqueue(id, rectangles.clone()); + return Ok(()); + } + + let s = if let Some(s) = self.popups.iter().find(|s| s.data.id == id) { + s.popup.wl_surface() + } else if let Some(s) = self.layer_surfaces.iter().find(|s| s.id == id) { + s.surface.wl_surface() + } else if let Some(s) = self.lock_surfaces.iter().find(|s| s.id == id) { + s.session_lock_surface.wl_surface() + } else if let Some(subsurface) = self.subsurfaces.iter().find(|s| s.id == id) { + &subsurface.instance.wl_surface + } else { + log::info!("Failed to find surface for blur action"); + if let Some(rectangles) = rectangles { + _ = self.pending_blur.insert(id, rectangles.clone()); + } + return Ok(()); + }.clone(); + self.apply_blur(id, rectangles, &s) + }, }; Ok(()) } + fn apply_blur( + &mut self, + id: core::window::Id, + rectangles: Option>, + s: &WlSurface, + ) { + let existing_blur = self.blur_surfaces.entry(id); + match (existing_blur, rectangles) { + (Entry::Occupied(occupied_entry), None) => { + let blur_surface = occupied_entry.remove(); + blur_surface.destroy(); + } + (Entry::Occupied(mut occupied_entry), Some(rectangles)) => { + let blur_surface = occupied_entry.get_mut(); + let region = self + .compositor_state + .wl_compositor() + .create_region(&self.queue_handle, ()); + for rect in rectangles.into_iter() { + region.add( + rect.x.round() as i32, + rect.y.round() as i32, + rect.width.round() as i32, + rect.height.round() as i32, + ); + } + + // update existing blur surfaces + blur_surface.set_blur_region(Some(®ion)); + } + (Entry::Vacant(..), None) => { + // nothing to remove + } + (Entry::Vacant(vacant_entry), Some(rectangles)) => { + if self.ext_background_effect_manager.is_none() { + log::error!("Blur effect is not supported."); + return; + } + let region = self + .compositor_state + .wl_compositor() + .create_region(&self.queue_handle, ()); + for rect in rectangles { + region.add( + rect.x.round() as i32, + rect.y.round() as i32, + rect.width.round() as i32, + rect.height.round() as i32, + ); + } + + let blur_manager = + self.ext_background_effect_manager.as_mut().unwrap(); + let blur_surface = blur_manager.blur(s, &self.queue_handle); + blur_surface.set_blur_region(Some(®ion)); + _ = vacant_entry.insert(blur_surface); + } + } + } + pub fn get_subsurface( &mut self, settings: SctkSubsurfaceSettings, @@ -1638,9 +1905,17 @@ impl SctkState { ), SubsurfaceCreationError, > { - let Some(subsurface_state) = self.subsurface_state.as_ref() else { + let Some(subsurface_state) = self.subsurface_state.clone() else { return Err(SubsurfaceCreationError::Unsupported); }; + if self.layer_surfaces.iter().any(|s| s.id == settings.id) + || self.windows.iter().any(|w| w.id == settings.id) + || self.popups.iter().any(|p| p.data.id == settings.id) + || self.subsurfaces.iter().any(|s| s.id == settings.id) + { + log::warn!("Subsurface with id {:?} already exists", settings.id); + return Err(SubsurfaceCreationError::AlreadyExists); + } let size = settings.size.unwrap_or(Size::new(1., 1.)); let half_w = size.width / 2.; @@ -1746,7 +2021,9 @@ impl SctkState { region.destroy(); } - wl_surface.commit(); + if let Some(blur) = self.pending_blur.remove(&settings.id) { + _ = self.apply_blur(settings.id, Some(blur), &wl_surface); + } let wp_viewport = subsurface_state.wp_viewporter.get_viewport( &wl_surface, @@ -1822,7 +2099,11 @@ impl SctkState { // XXX subsurfaces need to be sorted by z in descending order self.subsurfaces .sort_by(|a, b| b.instance.z.cmp(&a.instance.z)); + if let Some(corners) = self.pending_corner_radius.remove(&id) { + self.handle_action(Action::RoundedCorners(id, Some(corners))); + } + wl_surface.commit(); Ok(( id, parent.wl_surface().clone(), diff --git a/winit/src/platform_specific/wayland/handlers/ext_background_effect.rs b/winit/src/platform_specific/wayland/handlers/ext_background_effect.rs new file mode 100644 index 00000000..2d0df67a --- /dev/null +++ b/winit/src/platform_specific/wayland/handlers/ext_background_effect.rs @@ -0,0 +1,115 @@ +use std::collections::HashMap; + +use cctk::sctk; +use iced_futures::futures::SinkExt; +use iced_runtime::core::Rectangle; +use iced_runtime::platform_specific::wayland::Action; +use sctk::globals::GlobalData; +use sctk::reexports::client::globals::{BindError, GlobalList}; +use sctk::reexports::client::protocol::wl_surface::WlSurface; +use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, delegate_dispatch}; +use wayland_protocols::ext::background_effect::v1::client::ext_background_effect_manager_v1::{Capability, Event, ExtBackgroundEffectManagerV1}; +use wayland_protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1; + +use crate::event_loop::state::SctkState; +use crate::{platform_specific, window}; + +#[derive(Debug, Clone)] +pub struct ExtBackgroundEffectManager { + manager: ExtBackgroundEffectManagerV1, + capabilities: Capability, + queued_blur_actions: HashMap>>, +} + +impl ExtBackgroundEffectManager { + pub fn new( + globals: &GlobalList, + queue_handle: &QueueHandle, + ) -> Result { + let manager = globals.bind(queue_handle, 1..=1, GlobalData)?; + Ok(Self { + manager, + capabilities: Capability::empty(), + queued_blur_actions: HashMap::new(), + }) + } + + pub fn blur( + &mut self, + surface: &WlSurface, + queue_handle: &QueueHandle, + ) -> ExtBackgroundEffectSurfaceV1 { + self.manager + .get_background_effect(surface, queue_handle, ()) + } + + pub fn enqueue(&mut self, id: window::Id, rects: Option>) { + _ = self.queued_blur_actions.insert(id, rects); + } + + pub fn capabilities(&self) -> Capability { + self.capabilities + } +} + +impl Dispatch + for ExtBackgroundEffectManager +{ + fn event( + state: &mut SctkState, + _: &ExtBackgroundEffectManagerV1, + event: ::Event, + _: &GlobalData, + _: &Connection, + _: &QueueHandle, + ) { + match event { + Event::Capabilities { flags } => match flags { + wayland_client::WEnum::Value(capability) => { + let mut queued_actions = Vec::new(); + if let Some(bg_effect_mgr) = + state.ext_background_effect_manager.as_mut() + { + bg_effect_mgr.capabilities = capability; + if capability.contains(Capability::Blur) { + queued_actions = bg_effect_mgr + .queued_blur_actions + .drain() + .collect(); + state + .sctk_events + .push(crate::sctk_event::SctkEvent::Blur); + } + } + for (id, rects) in queued_actions { + _ = state.handle_action(Action::BlurSurface(id, rects)); + } + } + wayland_client::WEnum::Unknown(u) => { + log::warn!("Unknown value: {u:?}"); + } + }, + e => { + log::warn!("Ignored event {e:?}"); + } + } + } +} + +impl Dispatch + for ExtBackgroundEffectManager +{ + fn event( + _: &mut SctkState, + _: &ExtBackgroundEffectSurfaceV1, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + // There is no event + } +} + +delegate_dispatch!(SctkState: [ExtBackgroundEffectManagerV1: GlobalData] => ExtBackgroundEffectManager); +delegate_dispatch!(SctkState: [ExtBackgroundEffectSurfaceV1: ()] => ExtBackgroundEffectManager); diff --git a/winit/src/platform_specific/wayland/handlers/mod.rs b/winit/src/platform_specific/wayland/handlers/mod.rs index dfc73b5e..444c7e4e 100644 --- a/winit/src/platform_specific/wayland/handlers/mod.rs +++ b/winit/src/platform_specific/wayland/handlers/mod.rs @@ -1,6 +1,7 @@ // handlers pub mod activation; pub mod compositor; +pub mod ext_background_effect; pub mod output; pub mod overlap; pub mod seat; @@ -12,14 +13,14 @@ pub mod toplevel; pub mod wp_fractional_scaling; pub mod wp_viewporter; -use cctk::{sctk::{ +use cctk::sctk::{ delegate_registry, delegate_shm, output::OutputState, registry::{ProvidesRegistryState, RegistryState}, registry_handlers, seat::SeatState, shm::{Shm, ShmHandler}, -}}; +}; use crate::platform_specific::wayland::event_loop::state::SctkState; diff --git a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs index 5ff7fb4b..f83e1180 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs @@ -4,10 +4,46 @@ use crate::platform_specific::wayland::{ }; use cctk::sctk::{ delegate_keyboard, - seat::keyboard::{KeyboardHandler, Keysym}, + seat::keyboard::{KeyboardHandler, Keysym, Modifiers}, }; use cctk::sctk::{reexports::client::Proxy, seat::keyboard::RawModifiers}; +fn modifiers_from_keysyms( + keysyms: &[Keysym], + previous: Modifiers, +) -> Modifiers { + let mut modifiers = Modifiers { + caps_lock: previous.caps_lock, + num_lock: previous.num_lock, + ..Modifiers::default() + }; + + for keysym in keysyms { + match keysym.raw() { + xkeysym::key::Shift_L | xkeysym::key::Shift_R => { + modifiers.shift = true + } + xkeysym::key::Control_L | xkeysym::key::Control_R => { + modifiers.ctrl = true + } + xkeysym::key::Alt_L | xkeysym::key::Alt_R => modifiers.alt = true, + xkeysym::key::Super_L + | xkeysym::key::Super_R + | xkeysym::key::Hyper_L + | xkeysym::key::Hyper_R + | xkeysym::key::Meta_L + | xkeysym::key::Meta_R => modifiers.logo = true, + xkeysym::key::Caps_Lock | xkeysym::key::Shift_Lock => { + modifiers.caps_lock = true + } + xkeysym::key::Num_Lock => modifiers.num_lock = true, + _ => {} + } + } + + modifiers +} + impl KeyboardHandler for SctkState { fn enter( &mut self, @@ -17,9 +53,9 @@ impl KeyboardHandler for SctkState { surface: &cctk::sctk::reexports::client::protocol::wl_surface::WlSurface, _serial: u32, _raw: &[u32], - _keysyms: &[Keysym], + keysyms: &[Keysym], ) { - let (i, mut is_active, seat) = { + let (i, mut is_active, seat, modifiers) = { let (i, is_active, my_seat) = match self.seats.iter_mut().enumerate().find_map(|(i, s)| { if s.kbd.as_ref() == Some(keyboard) { @@ -41,9 +77,11 @@ impl KeyboardHandler for SctkState { surface }; _ = my_seat.kbd_focus.replace(surface.clone()); + let modifiers = modifiers_from_keysyms(keysyms, my_seat._modifiers); + my_seat._modifiers = modifiers; let seat = my_seat.seat.clone(); - (i, is_active, seat) + (i, is_active, seat, modifiers) }; if !is_active && self.seats[0].kbd_focus.is_none() { @@ -73,6 +111,12 @@ impl KeyboardHandler for SctkState { seat_id: seat.clone(), surface: surface.clone(), }); + self.sctk_events.push(SctkEvent::KeyboardEvent { + variant: KeyboardEventVariant::Modifiers(modifiers), + kbd_id: keyboard.clone(), + seat_id: seat.clone(), + surface: surface.clone(), + }); } } } @@ -126,6 +170,7 @@ impl KeyboardHandler for SctkState { if self.windows.iter().any(|w| w.window.id() == id) { continue; } + let modifiers = s._modifiers; self.sctk_events.push(SctkEvent::Winit( id, winit::event::WindowEvent::Focused(true), @@ -137,6 +182,12 @@ impl KeyboardHandler for SctkState { kbd_id: s.kbd.clone().unwrap(), seat_id: s.seat.clone(), surface: surface.clone(), + }); + self.sctk_events.push(SctkEvent::KeyboardEvent { + variant: KeyboardEventVariant::Modifiers(modifiers), + kbd_id: s.kbd.clone().unwrap(), + seat_id: s.seat.clone(), + surface: surface.clone(), }) } } @@ -248,6 +299,7 @@ impl KeyboardHandler for SctkState { }; let seat_id = my_seat.seat.clone(); let kbd_id = keyboard.clone(); + my_seat._modifiers = modifiers; if is_active { if let Some(surface) = my_seat.kbd_focus.clone() { diff --git a/winit/src/platform_specific/wayland/handlers/seat/seat.rs b/winit/src/platform_specific/wayland/handlers/seat/seat.rs index 2901ce8e..ee6b0e6e 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/seat.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/seat.rs @@ -4,10 +4,9 @@ use crate::platform_specific::wayland::{ }; use cctk::sctk::{ delegate_seat, - reexports::client::{protocol::wl_keyboard::WlKeyboard, Proxy}, - seat::{pointer::ThemeSpec, SeatHandler}, + reexports::client::{Proxy, protocol::wl_keyboard::WlKeyboard}, + seat::{SeatHandler, keyboard::Modifiers, pointer::ThemeSpec}, }; -use iced_runtime::keyboard::Modifiers; use std::sync::Arc; impl SeatHandler for SctkState { diff --git a/winit/src/platform_specific/wayland/handlers/seat/touch.rs b/winit/src/platform_specific/wayland/handlers/seat/touch.rs index f726fd93..a0b1cce0 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/touch.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/touch.rs @@ -9,12 +9,12 @@ use crate::{ use cctk::sctk::{ delegate_touch, reexports::client::{ - protocol::{wl_surface::WlSurface, wl_touch::WlTouch}, Connection, Proxy, QueueHandle, + protocol::{wl_surface::WlSurface, wl_touch::WlTouch}, }, seat::touch::TouchHandler, }; -use iced_runtime::core::{touch, Point}; +use iced_runtime::core::{Point, touch}; impl TouchHandler for SctkState { fn down( diff --git a/winit/src/platform_specific/wayland/handlers/session_lock.rs b/winit/src/platform_specific/wayland/handlers/session_lock.rs index d0eee5ef..98eb5586 100644 --- a/winit/src/platform_specific/wayland/handlers/session_lock.rs +++ b/winit/src/platform_specific/wayland/handlers/session_lock.rs @@ -1,6 +1,9 @@ use crate::{ event_loop::state::CommonSurface, - platform_specific::wayland::{handlers::SctkState, sctk_event::SctkEvent}, + platform_specific::wayland::{ + event_loop::state::receive_frame, handlers::SctkState, + sctk_event::SctkEvent, + }, }; use cctk::sctk::{ delegate_session_lock, @@ -67,6 +70,10 @@ impl SessionLockHandler for SctkState { configure, first, }); + + let wl_surface = session_lock_surface.wl_surface().clone(); + receive_frame(&mut self.frame_status, &wl_surface); + self.request_redraw(&wl_surface); } } diff --git a/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs b/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs index bd7d2409..c4bdda88 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs @@ -1,17 +1,29 @@ -use cctk::{sctk, cosmic_protocols::{ - corner_radius::v1::client::{ +use cctk::{ + cosmic_protocols::corner_radius::v1::client::{ + cosmic_corner_radius_layer_v1::CosmicCornerRadiusLayerV1, cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, }, - overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, -}}; -use sctk::reexports::{ - client::{Connection, Dispatch, Proxy}, - + sctk, }; +use sctk::reexports::client::{Connection, Dispatch, Proxy}; use crate::event_loop::state::SctkState; -use crate::platform_specific::wayland::SctkEvent; + +#[derive(Debug)] +pub enum CornerRadiusWrapper { + Xdg(CosmicCornerRadiusToplevelV1), + Wlr(CosmicCornerRadiusLayerV1), +} + +impl Drop for CornerRadiusWrapper { + fn drop(&mut self) { + match self { + Self::Xdg(c) => c.destroy(), + Self::Wlr(c) => c.destroy(), + }; + } +} impl Dispatch for SctkState { fn event( @@ -21,15 +33,11 @@ impl Dispatch for SctkState { _data: &(), _conn: &Connection, _qhandle: &sctk::reexports::client::QueueHandle, - ) {} + ) { + } } -impl - Dispatch< - CosmicCornerRadiusToplevelV1, - (), - > for SctkState -{ +impl Dispatch for SctkState { fn event( state: &mut Self, _proxy: &CosmicCornerRadiusToplevelV1, @@ -39,7 +47,22 @@ impl _qhandle: &sctk::reexports::client::QueueHandle, ) { match event { - _ => unimplemented!() + _ => unimplemented!(), + } + } +} + +impl Dispatch for SctkState { + fn event( + state: &mut Self, + _proxy: &CosmicCornerRadiusLayerV1, + event: ::Event, + _data: &(), + _conn: &Connection, + _qhandle: &sctk::reexports::client::QueueHandle, + ) { + match event { + _ => unimplemented!(), } } } diff --git a/winit/src/platform_specific/wayland/handlers/shell/layer.rs b/winit/src/platform_specific/wayland/handlers/shell/layer.rs index 65e5724b..22fd6560 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/layer.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/layer.rs @@ -1,13 +1,13 @@ use crate::platform_specific::wayland::{ - event_loop::state::{receive_frame, SctkState}, + event_loop::state::{SctkState, receive_frame}, sctk_event::{LayerSurfaceEventVariant, SctkEvent}, }; use cctk::sctk::{ delegate_layer, reexports::client::Proxy, shell::{ - wlr_layer::{Anchor, KeyboardInteractivity, LayerShellHandler}, WaylandSurface, + wlr_layer::{Anchor, KeyboardInteractivity, LayerShellHandler}, }, }; use std::fmt::Debug; diff --git a/winit/src/platform_specific/wayland/handlers/shell/mod.rs b/winit/src/platform_specific/wayland/handlers/shell/mod.rs index af8b5961..c4117eb7 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/mod.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/mod.rs @@ -1,4 +1,4 @@ +pub mod corner_radius; pub mod layer; pub mod xdg_popup; pub mod xdg_window; -pub mod corner_radius; diff --git a/winit/src/platform_specific/wayland/handlers/text_input.rs b/winit/src/platform_specific/wayland/handlers/text_input.rs index bb0c38da..eb1ed596 100644 --- a/winit/src/platform_specific/wayland/handlers/text_input.rs +++ b/winit/src/platform_specific/wayland/handlers/text_input.rs @@ -69,6 +69,10 @@ impl Dispatch for TextInputManager { _conn: &Connection, _qhandle: &QueueHandle, ) { + if cfg!(not(feature = "single-instance")) { + return; + } + let kbd_focus = match state.seats.iter_mut().find_map(|s| s.kbd_focus.clone()) { Some(surface) => surface, diff --git a/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs b/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs index 5cfe28d7..7bbd66d1 100644 --- a/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs +++ b/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs @@ -1,10 +1,10 @@ //! Handling of the wp-viewporter. +use cctk::sctk::reexports::client::Dispatch; use cctk::sctk::reexports::client::globals::{BindError, GlobalList}; use cctk::sctk::reexports::client::protocol::wl_surface::WlSurface; -use cctk::sctk::reexports::client::Dispatch; use cctk::sctk::reexports::client::{ - delegate_dispatch, Connection, Proxy, QueueHandle, + Connection, Proxy, QueueHandle, delegate_dispatch, }; use cctk::sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport; use cctk::sctk::reexports::protocols::wp::viewporter::client::wp_viewporter::WpViewporter; diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 9b3a7ec0..e98316ce 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -21,6 +21,7 @@ use iced_runtime::core::{Vector, window}; use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}; use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle}; use sctk_event::SctkEvent; +use std::sync::OnceLock; use std::{collections::HashMap, sync::Arc}; use subsurface_widget::{SubsurfaceInstance, SubsurfaceState}; use wayland_backend::client::ObjectId; @@ -128,7 +129,6 @@ impl PlatformSpecific { }; self.wayland.display_handle = Some(display); self.wayland.proxy = Some(raw); - // TODO remove this self.wayland.sender = crate::platform_specific::event_loop::SctkEventLoop::new( self.wayland.winit_event_sender.clone().unwrap(), diff --git a/winit/src/platform_specific/wayland/sctk_event.rs b/winit/src/platform_specific/wayland/sctk_event.rs index 3a1a0166..2ac54bed 100755 --- a/winit/src/platform_specific/wayland/sctk_event.rs +++ b/winit/src/platform_specific/wayland/sctk_event.rs @@ -68,10 +68,8 @@ use cctk::{ xdg::{popup::PopupConfigure, window::WindowConfigure}, }, }, - wayland_client::protocol::wl_subsurface::WlSubsurface, }; use std::{ - any::Any, collections::HashMap, num::NonZeroU32, sync::{Arc, Mutex}, @@ -98,9 +96,7 @@ use super::{ #[derive(Debug, Clone)] pub enum SctkEvent { - // - // Input events - // + Blur, SeatEvent { variant: SeatEventVariant, id: WlSeat, @@ -122,11 +118,6 @@ pub enum SctkEvent { seat_id: WlSeat, surface: WlSurface, }, - // TODO data device & touch - - // - // Surface Events - // WindowEvent { variant: WindowEventVariant, id: WlSurface, @@ -167,10 +158,6 @@ pub enum SctkEvent { }, SubsurfaceEvent(SubsurfaceEventVariant), - - // - // output events - // NewOutput { id: WlOutput, info: Option, @@ -180,9 +167,7 @@ pub enum SctkEvent { info: OutputInfo, }, RemovedOutput(WlOutput), - // - // compositor events - // + ScaleFactorChanged { factor: f64, id: WlOutput, @@ -380,6 +365,12 @@ impl SctkEvent { (variant.position.0, variant.position.1).into(), ) } + events.push(( + id.clone(), + iced_runtime::core::Event::Mouse( + mouse::Event::CursorEntered, + ), + )); events.push(( id, iced_runtime::core::Event::Mouse( @@ -1732,6 +1723,12 @@ impl SctkEvent { ), ), )), + SctkEvent::Blur => events.push(( + None, + iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland(wayland::Event::BlurEnabled), + ), + )), } } } diff --git a/winit/src/platform_specific/wayland/subsurface_widget.rs b/winit/src/platform_specific/wayland/subsurface_widget.rs index ed53d9ea..c3173fa9 100644 --- a/winit/src/platform_specific/wayland/subsurface_widget.rs +++ b/winit/src/platform_specific/wayland/subsurface_widget.rs @@ -7,7 +7,6 @@ use crate::core::{ widget::{self, Widget}, }; use std::{ - borrow::BorrowMut, cell::RefCell, collections::HashMap, fmt::Debug, @@ -410,7 +409,10 @@ impl SubsurfaceState { .unwrap(); canvas[0..width as usize * height as usize * 4].copy_from_slice(data); surface.damage_buffer(0, 0, width as i32, height as i32); - buffer.attach_to(&surface); + if let Err(err) = buffer.attach_to(&surface) { + log::warn!("failed to attach shm buffer to subsurface: {err}"); + return; + } surface.offset(offset.x as i32, offset.y as i32); wp_viewport.set_destination( (width as f64 / scale) as i32, diff --git a/winit/src/platform_specific/wayland/winit_window.rs b/winit/src/platform_specific/wayland/winit_window.rs index 296d8b67..b33b7f9e 100644 --- a/winit/src/platform_specific/wayland/winit_window.rs +++ b/winit/src/platform_specific/wayland/winit_window.rs @@ -287,7 +287,21 @@ impl winit::window::Window for SctkWinitWindow { } fn set_blur(&self, blur: bool) { - // TODO + _ = self.tx.send(Action::Action( + iced_runtime::platform_specific::wayland::Action::BlurSurface( + self.id.inner(), + if blur { + Some(vec![iced_runtime::core::Rectangle { + x: 0., + y: 0., + width: f32::MAX, + height: f32::MAX, + }]) + } else { + None + }, + ), + )); } fn set_visible(&self, visible: bool) {} diff --git a/winit/src/window.rs b/winit/src/window.rs index 87d35a5a..e56483f4 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -335,19 +335,9 @@ where } if self.ime_state != Some((cursor, purpose)) { - // Specify only the bottom-left position of the cursor on Linux - // because fcitx5 doesn't work well with cursor areas of - // the top-left position and height. - // The candidate window hides the composing text (a.k.a. preedit). - let (cursor_y, cursor_height) = - if cfg!(not(any(target_os = "windows", target_os = "macos"))) { - (cursor.y + cursor.height, 0.0) - } else { - (cursor.y, cursor.height) - }; self.raw.set_ime_cursor_area( - LogicalPosition::new(cursor.x, cursor_y).into(), - LogicalSize::new(cursor.width, cursor_height).into(), + LogicalPosition::new(cursor.x, cursor.y).into(), + LogicalSize::new(cursor.width, cursor.height).into(), ); self.raw.set_ime_purpose(conversion::ime_purpose(purpose)); diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index 98fdf9ee..1e16fc51 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -97,6 +97,7 @@ where self.ready = ready; } + #[cfg(feature = "a11y")] pub(crate) fn set_a11y_ready(&mut self, ready: bool) { self.a11y_ready = ready; }