diff --git a/Cargo.lock b/Cargo.lock index 5edc17e0..cf167e86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,11 +67,13 @@ source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111 dependencies = [ "accesskit", "accesskit_atspi_common", + "async-channel 2.5.0", + "async-executor", + "async-task", "atspi", "futures-lite", + "futures-util", "serde", - "tokio", - "tokio-stream", "zbus", ] @@ -270,6 +272,8 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2f3f79755c74fd155000314eb349864caa787c6592eace6c6882dad873d9c39" dependencies = [ + "async-fs", + "async-net", "enumflags2", "futures-channel", "futures-util", @@ -277,7 +281,6 @@ dependencies = [ "raw-window-handle", "serde", "serde_repr", - "tokio", "url", "zbus", ] @@ -288,13 +291,14 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33a3c86f3fd70c0ffa500ed189abfa90b5a52398a45d5dc372fcc38ebeb7a645" dependencies = [ + "async-fs", + "async-net", "enumflags2", "futures-channel", "futures-util", "rand 0.9.2", "serde", "serde_repr", - "tokio", "url", "wayland-backend", "wayland-client", @@ -308,12 +312,23 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "futures-core", "pin-project-lite", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -340,6 +355,32 @@ dependencies = [ "slab", ] +[[package]] +name = "async-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.5.0", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + [[package]] name = "async-io" version = "2.6.0" @@ -364,25 +405,36 @@ version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + [[package]] name = "async-process" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ - "async-channel", + "async-channel 2.5.0", "async-io", "async-lock", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener", + "event-listener 5.4.1", "futures-lite", "rustix 1.1.4", ] @@ -416,6 +468,32 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "async-std" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-task" version = "4.7.1" @@ -494,9 +572,9 @@ dependencies = [ [[package]] name = "auto_enums" -version = "0.8.9" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e4487600931c9a89f8db7ffbdf3fbdd45bb7bd85e26861f659a463cd0dff966" +checksum = "65398a2893f41bce5c9259f6e1a4f03fbae40637c1bdc755b4f387f48c613b03" dependencies = [ "derive_utils", "proc-macro2", @@ -615,7 +693,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel", + "async-channel 2.5.0", "async-task", "futures-io", "futures-lite", @@ -695,6 +773,20 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.11.0", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + [[package]] name = "calloop" version = "0.14.4" @@ -703,20 +795,31 @@ checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ "async-task", "bitflags 2.11.0", - "futures-core", "polling", "rustix 1.1.4", "slab", "tracing", ] +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop 0.13.0", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + [[package]] name = "calloop-wayland-source" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" dependencies = [ - "calloop", + "calloop 0.14.4", "rustix 1.1.4", "wayland-backend", "wayland-client", @@ -866,7 +969,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.1.14", + "unicode-width 0.2.2", ] [[package]] @@ -977,7 +1080,7 @@ dependencies = [ "bitflags 2.11.0", "cosmic-protocols", "libc", - "smithay-client-toolkit", + "smithay-client-toolkit 0.20.0", "wayland-client", "wayland-protocols", ] @@ -988,7 +1091,7 @@ version = "1.0.0" dependencies = [ "anyhow", "bitflags 2.11.0", - "calloop", + "calloop 0.14.4", "cgmath", "clap_lex", "cosmic-comp-config", @@ -1025,11 +1128,11 @@ dependencies = [ "sanitize-filename", "serde", "serde_json", + "smallvec", "smithay", "smithay-egui", "thiserror 2.0.18", "tiny-skia", - "tokio", "tracing", "tracing-journald", "tracing-subscriber", @@ -1060,8 +1163,9 @@ dependencies = [ name = "cosmic-config" version = "1.0.0" dependencies = [ + "async-std", "atomicwrites", - "calloop", + "calloop 0.14.4", "cosmic-config-derive", "cosmic-settings-daemon", "dirs", @@ -1071,7 +1175,6 @@ dependencies = [ "notify", "ron 0.12.0", "serde", - "tokio", "tracing", "xdg", "zbus", @@ -1161,7 +1264,7 @@ dependencies = [ "rustc-hash 2.1.1", "self_cell", "skrifa 0.40.0", - "smol_str", + "smol_str 0.3.5", "swash", "sys-locale", "unicode-bidi", @@ -1384,6 +1487,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + [[package]] name = "dispatch2" version = "0.3.1" @@ -1423,7 +1532,7 @@ dependencies = [ "bitflags 2.11.0", "mime 0.1.0", "raw-window-handle", - "smithay-client-toolkit", + "smithay-client-toolkit 0.20.0", "smithay-clipboard", ] @@ -1695,6 +1804,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "event-listener" version = "5.4.1" @@ -1712,7 +1827,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener", + "event-listener 5.4.1", "pin-project-lite", ] @@ -2160,6 +2275,18 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "glow" version = "0.16.0" @@ -2192,7 +2319,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.62.2", + "windows 0.61.3", ] [[package]] @@ -2483,7 +2610,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 2.1.1", "serde", - "smol_str", + "smol_str 0.3.5", "thiserror 2.0.18", "unicode-segmentation", "web-time", @@ -2507,7 +2634,6 @@ dependencies = [ "iced_core", "log", "rustc-hash 2.1.1", - "tokio", "wasm-bindgen-futures", "wasmtimer", ] @@ -2650,7 +2776,7 @@ dependencies = [ "winapi", "window_clipboard", "winit 0.31.0-beta.2", - "winit-core 0.31.0-beta.2", + "winit-core", "xkbcommon 0.7.0", "xkbcommon-dl", "xkeysym", @@ -3112,6 +3238,15 @@ dependencies = [ "smallvec", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -3126,9 +3261,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.186" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libcosmic-yoda" @@ -3136,6 +3271,7 @@ version = "0.1.0-yoda.2" dependencies = [ "apply", "ashpd 0.12.3", + "async-std", "auto_enums", "cosmic-client-toolkit", "cosmic-config", @@ -3169,7 +3305,6 @@ dependencies = [ "slotmap", "taffy", "thiserror 2.0.18", - "tokio", "tracing", "unicode-segmentation", "url", @@ -3228,14 +3363,13 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.18" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags 2.11.0", "libc", - "plain", - "redox_syscall 0.9.0", + "redox_syscall 0.7.2", ] [[package]] @@ -3345,6 +3479,9 @@ name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +dependencies = [ + "value-bag", +] [[package]] name = "log-panics" @@ -3556,9 +3693,9 @@ checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" [[package]] name = "mio" -version = "1.2.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "log", @@ -3878,6 +4015,30 @@ dependencies = [ "objc2-foundation 0.3.2", ] +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-core-data" version = "0.2.2" @@ -3925,6 +4086,18 @@ dependencies = [ "objc2-metal", ] +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-core-video" version = "0.3.2" @@ -3950,6 +4123,7 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.11.0", "block2 0.5.1", + "dispatch", "libc", "objc2 0.5.2", ] @@ -3966,6 +4140,18 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-metal" version = "0.2.2" @@ -3991,6 +4177,37 @@ dependencies = [ "objc2-metal", ] +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + [[package]] name = "objc2-ui-kit" version = "0.3.2" @@ -4003,6 +4220,30 @@ dependencies = [ "objc2-foundation 0.3.2", ] +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc_id" version = "0.1.1" @@ -4323,12 +4564,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "png" version = "0.17.16" @@ -4518,6 +4753,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick-xml" version = "0.39.2" @@ -4525,7 +4770,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" dependencies = [ "memchr", - "serde", ] [[package]] @@ -4666,14 +4910,23 @@ dependencies = [ [[package]] name = "redox_event" -version = "0.4.8" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5018d583d6d2f5499352aea8d177e9067d1eb03ab17c78169d5ba7a30001b15" +checksum = "3514da49aa6ca4cff5088a1b382ef3a0d9149964d29bb49ebd03fd66cc575a18" dependencies = [ "bitflags 2.11.0", "libredox", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -4685,9 +4938,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.9.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" +checksum = "6d94dd2f7cd932d4dc02cc8b2b50dfd38bd079a4e5d79198b99743d7fcf9a4b4" dependencies = [ "bitflags 2.11.0", ] @@ -4752,18 +5005,6 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" -[[package]] -name = "reis" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3fedd2777cde52c1be5e572efbec485eac7b801c47820eda388d4f13b9c4b" -dependencies = [ - "calloop", - "enumflags2", - "log", - "rustix 1.1.4", -] - [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -5038,7 +5279,7 @@ dependencies = [ "ab_glyph", "log", "memmap2 0.9.10", - "smithay-client-toolkit", + "smithay-client-toolkit 0.20.0", "tiny-skia", ] @@ -5256,14 +5497,14 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay" version = "0.7.0" -source = "git+https://github.com/smithay/smithay.git?rev=8eb4076#8eb4076cad8705c56f5e3bac8577b83576b6ce76" +source = "git+https://github.com/smithay/smithay.git?rev=774f2ab#774f2ab010e080a2f79176d0e12eb63d5e09d680" dependencies = [ "aliasable", "appendlist", "ash", "atomic_float", "bitflags 2.11.0", - "calloop", + "calloop 0.14.4", "cc", "cgmath", "cursor-icon", @@ -5285,7 +5526,6 @@ dependencies = [ "pkg-config", "profiling", "rand 0.9.2", - "reis", "rustix 1.1.4", "scopeguard", "sha2", @@ -5302,11 +5542,36 @@ dependencies = [ "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-server", - "winit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.30.12", "x11rb", "xkbcommon 0.9.0", ] +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.11.0", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", + "cursor-icon", + "libc", + "log", + "memmap2 0.9.10", + "rustix 0.38.44", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + [[package]] name = "smithay-client-toolkit" version = "0.20.0" @@ -5315,8 +5580,8 @@ checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ "bitflags 2.11.0", "bytemuck", - "calloop", - "calloop-wayland-source", + "calloop 0.14.4", + "calloop-wayland-source 0.4.1", "cursor-icon", "libc", "log", @@ -5343,7 +5608,7 @@ version = "0.8.0" dependencies = [ "libc", "raw-window-handle", - "smithay-client-toolkit", + "smithay-client-toolkit 0.20.0", "wayland-backend", ] @@ -5364,6 +5629,15 @@ dependencies = [ "xkbcommon 0.8.0", ] +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + [[package]] name = "smol_str" version = "0.3.5" @@ -5380,16 +5654,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1" -[[package]] -name = "socket2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "softbuffer" version = "0.4.1" @@ -5726,45 +5990,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "tokio" -version = "1.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" -dependencies = [ - "bytes", - "libc", - "mio", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "tracing", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "toml" version = "0.5.11" @@ -6050,9 +6275,9 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.13.3" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-vo" @@ -6191,6 +6416,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "value-bag" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" + [[package]] name = "version-compare" version = "0.2.1" @@ -6476,7 +6707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" dependencies = [ "proc-macro2", - "quick-xml", + "quick-xml 0.39.2", "quote", ] @@ -7223,53 +7454,77 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" -version = "0.31.0-beta.2" +version = "0.30.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" dependencies = [ + "ahash", + "android-activity", + "atomic-waker", "bitflags 2.11.0", + "block2 0.5.1", + "bytemuck", + "calloop 0.13.0", "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics", "cursor-icon", - "dpi 0.1.2", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", "libc", + "memmap2 0.9.10", + "ndk", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit 0.2.2", + "orbclient", + "percent-encoding", + "pin-project", "raw-window-handle", - "rustix 1.1.4", - "smol_str", + "redox_syscall 0.4.1", + "rustix 0.38.44", + "smithay-client-toolkit 0.19.2", + "smol_str 0.2.2", "tracing", - "winit-android 0.31.0-beta.2", - "winit-appkit 0.31.0-beta.2", - "winit-common 0.31.0-beta.2", - "winit-core 0.31.0-beta.2", - "winit-orbital 0.31.0-beta.2", - "winit-uikit 0.31.0-beta.2", - "winit-wayland 0.31.0-beta.2", - "winit-web 0.31.0-beta.2", - "winit-win32 0.31.0-beta.2", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", ] [[package]] name = "winit" version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2879d2854d1a43e48f67322d4bd097afcb6eb8f8f775c8de0260a71aea1df1aa" dependencies = [ "bitflags 2.11.0", "cfg_aliases", "cursor-icon", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dpi 0.1.2", "libc", "raw-window-handle", "rustix 1.1.4", - "smol_str", + "smol_str 0.3.5", "tracing", - "winit-android 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-appkit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-orbital 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-uikit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-wayland 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-web 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-win32 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-x11", + "winit-android", + "winit-appkit", + "winit-common", + "winit-core", + "winit-orbital", + "winit-uikit", + "winit-wayland", + "winit-web", + "winit-win32", ] [[package]] @@ -7281,25 +7536,9 @@ dependencies = [ "dpi 0.1.2", "ndk", "raw-window-handle", - "smol_str", + "smol_str 0.3.5", "tracing", - "winit-core 0.31.0-beta.2", -] - -[[package]] -name = "winit-android" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d9c0d2cd93efec3a9f9ad819cfaf0834782403af7c0d248c784ec0c61761df" -dependencies = [ - "android-activity", - "bitflags 2.11.0", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk", - "raw-window-handle", - "smol_str", - "tracing", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core", ] [[package]] @@ -7317,33 +7556,10 @@ dependencies = [ "objc2-core-video", "objc2-foundation 0.3.2", "raw-window-handle", - "smol_str", + "smol_str 0.3.5", "tracing", - "winit-common 0.31.0-beta.2", - "winit-core 0.31.0-beta.2", -] - -[[package]] -name = "winit-appkit" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21310ca07851a49c348e0c2cc768e36b52ca65afda2c2354d78ed4b90074d8aa" -dependencies = [ - "bitflags 2.11.0", - "block2 0.6.2", - "dispatch2", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "objc2 0.6.4", - "objc2-app-kit 0.3.2", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-video", - "objc2-foundation 0.3.2", - "raw-window-handle", - "smol_str", - "tracing", - "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-common", + "winit-core", ] [[package]] @@ -7353,25 +7569,9 @@ dependencies = [ "memmap2 0.9.10", "objc2 0.6.4", "objc2-core-foundation", - "smol_str", + "smol_str 0.3.5", "tracing", - "winit-core 0.31.0-beta.2", - "xkbcommon-dl", -] - -[[package]] -name = "winit-common" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45375fbac4cbb77260d83a30b1f9d8105880dbac99a9ae97f56656694680ff69" -dependencies = [ - "memmap2 0.9.10", - "objc2 0.6.4", - "objc2-core-foundation", - "smol_str", - "tracing", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "x11-dl", + "winit-core", "xkbcommon-dl", ] @@ -7384,22 +7584,7 @@ dependencies = [ "dpi 0.1.2", "keyboard-types", "raw-window-handle", - "smol_str", - "web-time", -] - -[[package]] -name = "winit-core" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4f0ccd7abb43740e2c6124ac7cae7d865ecec74eec63783e8922577ac232583" -dependencies = [ - "bitflags 2.11.0", - "cursor-icon", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keyboard-types", - "raw-window-handle", - "smol_str", + "smol_str 0.3.5", "web-time", ] @@ -7413,25 +7598,9 @@ dependencies = [ "orbclient", "raw-window-handle", "redox_event", - "smol_str", + "smol_str 0.3.5", "tracing", - "winit-core 0.31.0-beta.2", -] - -[[package]] -name = "winit-orbital" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ea1fb262e7209f265f12bd0cc792c399b14355675e65531e9c8a87db287d46" -dependencies = [ - "bitflags 2.11.0", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient", - "raw-window-handle", - "redox_syscall 0.5.18", - "smol_str", - "tracing", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core", ] [[package]] @@ -7445,33 +7614,12 @@ dependencies = [ "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", - "objc2-ui-kit", + "objc2-ui-kit 0.3.2", "raw-window-handle", - "smol_str", + "smol_str 0.3.5", "tracing", - "winit-common 0.31.0-beta.2", - "winit-core 0.31.0-beta.2", -] - -[[package]] -name = "winit-uikit" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680a356e798837d8eb274d4556e83bceaf81698194e31aafc5cfb8a9f2fab643" -dependencies = [ - "bitflags 2.11.0", - "block2 0.6.2", - "dispatch2", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "objc2 0.6.4", - "objc2-core-foundation", - "objc2-foundation 0.3.2", - "objc2-ui-kit", - "raw-window-handle", - "smol_str", - "tracing", - "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-common", + "winit-core", ] [[package]] @@ -7480,7 +7628,7 @@ version = "0.31.0-beta.2" dependencies = [ "ahash", "bitflags 2.11.0", - "calloop", + "calloop 0.14.4", "cursor-icon", "dpi 0.1.2", "libc", @@ -7488,41 +7636,15 @@ dependencies = [ "raw-window-handle", "rustix 1.1.4", "sctk-adwaita", - "smithay-client-toolkit", - "smol_str", + "smithay-client-toolkit 0.20.0", + "smol_str 0.3.5", "tracing", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-protocols-plasma", - "winit-common 0.31.0-beta.2", - "winit-core 0.31.0-beta.2", -] - -[[package]] -name = "winit-wayland" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce5afb2ba07da603f84b722c95f9f9396d2cedae3944fb6c0cda4a6f88de545" -dependencies = [ - "ahash", - "bitflags 2.11.0", - "calloop", - "cursor-icon", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc", - "memmap2 0.9.10", - "raw-window-handle", - "rustix 1.1.4", - "smithay-client-toolkit", - "smol_str", - "tracing", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-plasma", - "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-common", + "winit-core", ] [[package]] @@ -7537,36 +7659,13 @@ dependencies = [ "js-sys", "pin-project", "raw-window-handle", - "smol_str", + "smol_str 0.3.5", "tracing", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "web-time", - "winit-core 0.31.0-beta.2", -] - -[[package]] -name = "winit-web" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2490a953fb776fbbd5e295d54f1c3847f4f15b6c3929ec53c09acda6487a92" -dependencies = [ - "atomic-waker", - "bitflags 2.11.0", - "concurrent-queue", - "cursor-icon", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys", - "pin-project", - "raw-window-handle", - "smol_str", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "web-time", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core", ] [[package]] @@ -7577,52 +7676,11 @@ dependencies = [ "cursor-icon", "dpi 0.1.2", "raw-window-handle", - "smol_str", + "smol_str 0.3.5", "tracing", "unicode-segmentation", "windows-sys 0.59.0", - "winit-core 0.31.0-beta.2", -] - -[[package]] -name = "winit-win32" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644ea78af0e858aa3b092e5d1c67c41995a98220c81813f1353b28bc8bb91eaa" -dependencies = [ - "bitflags 2.11.0", - "cursor-icon", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-window-handle", - "smol_str", - "tracing", - "unicode-segmentation", - "windows-sys 0.59.0", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winit-x11" -version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa5b600756534c7041aa93cd0d244d44b09fca1b89e202bd1cd80dd9f3636c46" -dependencies = [ - "bitflags 2.11.0", - "bytemuck", - "calloop", - "cursor-icon", - "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc", - "percent-encoding", - "raw-window-handle", - "rustix 1.1.4", - "smol_str", - "tracing", - "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", - "x11-dl", - "x11rb", - "xkbcommon-dl", + "winit-core", ] [[package]] @@ -7770,7 +7828,6 @@ dependencies = [ "once_cell", "rustix 1.1.4", "x11rb-protocol", - "xcursor", ] [[package]] @@ -7905,9 +7962,9 @@ dependencies = [ [[package]] name = "zbus" -version = "5.16.0" +version = "5.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee682d202a77e4a9f3b2c2bdf48a7b28af5c08c34ddf66f98c93e5e39464285" +checksum = "c3bcbf15c8708d7fc1be0c993622e0a5cbd5e8b52bfa40afa4c3e0cd8d724ac1" dependencies = [ "async-broadcast", "async-executor", @@ -7919,7 +7976,7 @@ dependencies = [ "async-trait", "blocking", "enumflags2", - "event-listener", + "event-listener 5.4.1", "futures-core", "futures-lite", "hex", @@ -7928,7 +7985,6 @@ dependencies = [ "rustix 1.1.4", "serde", "serde_repr", - "tokio", "tracing", "uds_windows", "uuid", @@ -7965,9 +8021,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.16.0" +version = "5.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf1bd45a81a103745b1757754762a26e8cd01e4532e4d6c8ec431624b80d1d6" +checksum = "51fa5406ad9175a8c825a931f8cf347116b531b3634fcb0b627c290f1f2516ff" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7991,11 +8047,11 @@ dependencies = [ [[package]] name = "zbus_xml" -version = "5.1.1" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8067892e940ed1727dea64690378601603b31d62dfde019a5335fbb7c0e0ed9" +checksum = "441a0064125265655bccc3a6af6bef56814d9277ac83fce48b1cd7e160b80eac" dependencies = [ - "quick-xml", + "quick-xml 0.38.4", "serde", "zbus_names", "zvariant", @@ -8120,9 +8176,9 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.12.0" +version = "5.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a192a0bde63360d77a7523c833d4b4ce6070a927e2c53246e4c540b1a3e27be0" +checksum = "1c1567a6ec68df868cbbfde844cfc6d81649fe5109a62b116b19fabd53e618ee" dependencies = [ "endi", "enumflags2", @@ -8135,9 +8191,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.12.0" +version = "5.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737" +checksum = "c7d5b780599bbde114e39d9a0799577fad1ced5105d38515745f7b3099d8ceda" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8148,9 +8204,9 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.4.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8535915cfa75547e559d8c68e8139909a4aeee076831e4ef7fc59d8172c4d6" +checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 277655e7..55757aa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,12 +12,13 @@ members = ["cosmic-comp-config"] [dependencies] anyhow = { version = "1.0.102", features = ["backtrace"] } bitflags = "2.11.0" -calloop = { version = "0.14.4", features = ["executor", "stream"] } +calloop = { version = "0.14.4", features = ["executor"] } cosmic-comp-config = { path = "cosmic-comp-config", features = [ "libdisplay-info", "output", ] } cosmic-config = { path = "../libcosmic/cosmic-config", features = [ + "async-std", "calloop", "macro", ] } @@ -43,7 +44,7 @@ iced_tiny_skia = { path = "../libcosmic/iced/tiny_skia" } indexmap = "2.13" keyframe = "1.1.1" cosmic = { package = "libcosmic-yoda", path = "../libcosmic", default-features = false, features = [ - "tokio", + "async-std", "wayland", "multi-window", ] } @@ -77,7 +78,6 @@ xdg = "^3.0" xdg-user = "0.2.1" xkbcommon = "0.9" zbus = "5.14.0" -tokio = { version = "1", features = ["rt-multi-thread"] } profiling = { version = "1.0" } rustix = { version = "1.1.4", features = ["process"] } rand = "0.10" @@ -85,9 +85,10 @@ rand = "0.10" clap_lex = "1.0" parking_lot = "0.12.5" logind-zbus = { version = "5.3.2", optional = true } -futures-executor = { version = "0.3.32" } +futures-executor = { version = "0.3.32", features = ["thread-pool"] } futures-util = "0.3.32" cgmath = "0.18.0" +smallvec = "1.15.1" [dependencies.id_tree] branch = "feature/copy_clone" @@ -122,8 +123,7 @@ optional = true [features] debug = ["egui", "egui_plot", "smithay-egui", "anyhow/backtrace"] default = ["systemd"] -logind = ["logind-zbus"] -systemd = ["libsystemd", "logind"] +systemd = ["libsystemd", "logind-zbus"] profile-with-tracy = ["profiling/profile-with-tracy", "tracy-client/default"] profile-with-tracy-gpu = ["profile-with-tracy", "smithay/tracy_gpu_profiling"] @@ -175,4 +175,4 @@ dnd = { path = "../window_clipboard/dnd" } mime = { path = "../window_clipboard/mime" } [patch.crates-io] -smithay = { git = "https://github.com/smithay/smithay.git", rev = "8eb4076" } +smithay = { git = "https://github.com/smithay/smithay.git", rev = "774f2ab" } diff --git a/Makefile b/Makefile index 16f59ee6..cfe59669 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,6 @@ vendor: mkdir -p .cargo cargo vendor | head -n -1 > .cargo/config echo 'directory = "vendor"' >> .cargo/config - [ -n "$(SOURCE_GIT_HASH)" ] && printf '\n[env]\nGIT_HASH = "%s"\n' "$(SOURCE_GIT_HASH)" >> .cargo/config || true tar pcf vendor.tar vendor rm -rf vendor diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index e5e73883..8c4d9588 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -101,7 +101,6 @@ pub struct CosmicCompConfig { pub appearance_settings: AppearanceConfig, /// Hide the cursor after this many seconds of pointer inactivity (None disables) pub cursor_hide_timeout: Option, - pub activation_policy: ActivationPolicy, } impl Default for CosmicCompConfig { @@ -139,7 +138,6 @@ impl Default for CosmicCompConfig { accessibility_zoom: ZoomConfig::default(), appearance_settings: AppearanceConfig::default(), cursor_hide_timeout: None, - activation_policy: ActivationPolicy::default(), } } } @@ -229,14 +227,6 @@ pub enum EavesdroppingKeyboardMode { All, } -#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialEq, Eq)] -pub enum ActivationPolicy { - #[default] - Focus, - FocusIfActiveWorkspace, - Urgent, -} - #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum XwaylandDescaling { diff --git a/cosmic-comp-config/src/workspace.rs b/cosmic-comp-config/src/workspace.rs index 62676264..08c3dc6c 100644 --- a/cosmic-comp-config/src/workspace.rs +++ b/cosmic-comp-config/src/workspace.rs @@ -63,5 +63,5 @@ pub struct PinnedWorkspace { pub output: OutputMatch, pub tiling_enabled: bool, pub id: Option, - pub name: Option, + // TODO: name } diff --git a/data/tiling-exceptions.ron b/data/tiling-exceptions.ron index 2065c489..14976eec 100644 --- a/data/tiling-exceptions.ron +++ b/data/tiling-exceptions.ron @@ -48,6 +48,5 @@ (appid: "zoom", titles: [".*"]), (appid: "Tor Browser", titles: [".*"]), (appid: "^.*?action=join.*$", titles: [".*"]), - (appid: "^(slack|com.slack.Slack)", titles: ["^.*?(Huddle Preview).*"]), - (appid: "^(thunderbird|org.mozilla.thunderbird)(-esr|_esr)*", titles: ["^(Write:).*"]), + ] diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index 2b0e8f9d..c7a0a160 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -96,6 +96,7 @@ pub struct Device { pub inner: InnerDevice, pub drm: GbmDrmOutputManager, + supports_atomic: bool, pub texture_formats: FormatSet, event_token: Option, pub socket: Option, @@ -710,6 +711,7 @@ impl Device { let (drm, notifier) = DrmDevice::new(fd.clone(), false) .with_context(|| format!("Failed to initialize drm device for: {}", path.display()))?; let dev_node = DrmNode::from_dev_id(dev)?; + let supports_atomic = drm.is_atomic(); let gbm = GbmDevice::new(fd) .with_context(|| format!("Failed to initialize GBM device for {}", path.display()))?; @@ -829,6 +831,7 @@ impl Device { active_clients, }, + supports_atomic, texture_formats, event_token: Some(token), socket, @@ -837,7 +840,8 @@ impl Device { pub fn enumerate_surfaces(&mut self) -> Result { // enumerate our outputs - let config = drm_helpers::display_configuration(self.drm.device_mut())?; + let config = + drm_helpers::display_configuration(self.drm.device_mut(), self.supports_atomic)?; let surfaces = self .inner diff --git a/src/backend/kms/drm_helpers.rs b/src/backend/kms/drm_helpers.rs index 8629c9d7..6144e4f0 100644 --- a/src/backend/kms/drm_helpers.rs +++ b/src/backend/kms/drm_helpers.rs @@ -3,7 +3,6 @@ use anyhow::{Context, Result, anyhow}; use libdisplay_info::{edid::DisplayDescriptorTag, info::Info}; use smithay::{ - backend::drm::DrmDevice, reexports::drm::control::{ AtomicCommitFlags, Device as ControlDevice, Mode, ModeFlags, PlaneType, ResourceHandle, atomic::AtomicModeReq, @@ -17,7 +16,8 @@ use smithay::{ use std::{collections::HashMap, ops::Range}; pub fn display_configuration( - device: &mut DrmDevice, + device: &mut impl ControlDevice, + supports_atomic: bool, ) -> Result>> { let res_handles = device.resource_handles()?; let connectors = res_handles.connectors(); @@ -73,10 +73,28 @@ pub fn display_configuration( } // And then cleanup - if device.is_atomic() { + if supports_atomic { let mut req = AtomicModeReq::new(); let plane_handles = device.plane_handles()?; + for conn in connectors + .iter() + .flat_map(|conn| device.get_connector(*conn, false).ok()) + .filter(|conn| { + if let Some(enc) = conn.current_encoder() + && let Ok(enc) = device.get_encoder(enc) + && let Some(crtc) = enc.crtc() + { + return cleanup.contains(&crtc); + } + false + }) + .map(|info| info.handle()) + { + let crtc_id = get_prop(device, conn, "CRTC_ID")?; + req.add_property(conn, crtc_id, property::Value::CRTC(None)); + } + // We cannot just shortcut and use the legacy api for all cleanups because of this. // (Technically a device does not need to be atomic for planes to be used, but nobody does this otherwise.) for plane in plane_handles { @@ -90,7 +108,7 @@ pub fn display_configuration( _ => false, }, )?; - if !is_primary && !cleanup.contains(&crtc) { + if cleanup.contains(&crtc) || !is_primary { let crtc_id = get_prop(device, plane, "CRTC_ID")?; let fb_id = get_prop(device, plane, "FB_ID")?; req.add_property(plane, crtc_id, property::Value::CRTC(None)); @@ -98,78 +116,29 @@ pub fn display_configuration( } } } + + for crtc in cleanup { + let mode_id = get_prop(device, crtc, "MODE_ID")?; + let active = get_prop(device, crtc, "ACTIVE")?; + req.add_property(crtc, active, property::Value::Boolean(false)); + req.add_property(crtc, mode_id, property::Value::Unknown(0)); + } + device.atomic_commit(AtomicCommitFlags::ALLOW_MODESET, req)?; } else { for crtc in res_handles.crtcs() { #[allow(deprecated)] let _ = device.set_cursor(*crtc, Option::<&DumbBuffer>::None); } + for crtc in cleanup { + // null commit (necessary to trigger removal on the kernel side with the legacy api.) + let _ = device.set_crtc(crtc, None, (0, 0), &[], None); + } } - disable_crtcs(device, &cleanup)?; Ok(map) } -/// Disables the given CRTCs and detaches their connectors/planes. -pub fn disable_crtcs(device: &mut DrmDevice, crtcs: &[crtc::Handle]) -> Result<()> { - if crtcs.is_empty() { - return Ok(()); - } - - let res_handles = device.resource_handles()?; - - if device.is_atomic() { - let mut req = AtomicModeReq::new(); - - for conn in res_handles - .connectors() - .iter() - .flat_map(|conn| device.get_connector(*conn, false).ok()) - .filter(|conn| { - if let Some(enc) = conn.current_encoder() - && let Ok(enc) = device.get_encoder(enc) - && let Some(crtc) = enc.crtc() - { - return crtcs.contains(&crtc); - } - false - }) - .map(|info| info.handle()) - { - let crtc_id = get_prop(device, conn, "CRTC_ID")?; - req.add_property(conn, crtc_id, property::Value::CRTC(None)); - } - - for plane in device.plane_handles()? { - let info = device.get_plane(plane)?; - if let Some(crtc) = info.crtc() - && crtcs.contains(&crtc) - { - let crtc_id = get_prop(device, plane, "CRTC_ID")?; - let fb_id = get_prop(device, plane, "FB_ID")?; - req.add_property(plane, crtc_id, property::Value::CRTC(None)); - req.add_property(plane, fb_id, property::Value::Framebuffer(None)); - } - } - - for crtc in crtcs { - let mode_id = get_prop(device, *crtc, "MODE_ID")?; - let active = get_prop(device, *crtc, "ACTIVE")?; - req.add_property(*crtc, active, property::Value::Boolean(false)); - req.add_property(*crtc, mode_id, property::Value::Unknown(0)); - } - - device.atomic_commit(AtomicCommitFlags::ALLOW_MODESET, req)?; - } else { - for crtc in crtcs { - // null commit (necessary to trigger removal on the kernel side with the legacy api.) - let _ = device.set_crtc(*crtc, None, (0, 0), &[], None); - } - } - - Ok(()) -} - pub fn interface_name(device: &impl ControlDevice, connector: connector::Handle) -> Result { let conn_info = device.get_connector(connector, false)?; diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 13832da8..3a0d8c8c 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -374,7 +374,6 @@ impl State { for device in backend.drm_devices.values_mut() { if let Err(err) = device.drm.lock().activate(true) { error!(?err, "Failed to resume drm device"); - continue; } if let Some(lease_state) = device.inner.leasing_global.as_mut() { lease_state.resume::(); @@ -852,23 +851,11 @@ impl KmsGuard<'_> { // first drop old surfaces if !test_only { - let mut disabled_crtcs = Vec::new(); - device.inner.surfaces.retain(|crtc, surface| { - if outputs - .iter() - .any(|o| !o.is_enabled() && surface.output == *o) - { - disabled_crtcs.push(*crtc); - false - } else { - true - } - }); - - if let Err(err) = - drm_helpers::disable_crtcs(device.drm.device_mut(), &disabled_crtcs) - { - warn!("Failed to disable crtcs for disabled outputs: {err}"); + for output in outputs.iter().filter(|o| !o.is_enabled()) { + device + .inner + .surfaces + .retain(|_, surface| surface.output != *output); } } diff --git a/src/backend/kms/render/gles.rs b/src/backend/kms/render/gles.rs index 4a75c0ab..5d79b1ee 100644 --- a/src/backend/kms/render/gles.rs +++ b/src/backend/kms/render/gles.rs @@ -1,30 +1,21 @@ // SPDX-License-Identifier: GPL-3.0-only -use clap_lex::OsStrExt; -use rustix::path::Arg; -use smithay::{ - backend::{ - SwapBuffersError, - allocator::{ - Allocator, - dmabuf::{AnyError, Dmabuf, DmabufAllocator}, - gbm::GbmAllocator, - }, - drm::{CreateDrmNodeError, DrmNode}, - renderer::{ - RendererSuper, - gles::{GlesError, GlesRenderer, ffi}, - glow::GlowRenderer, - multigpu::{ApiDevice, Error as MultiError, GraphicsApi}, - }, +use smithay::backend::{ + SwapBuffersError, + allocator::{ + Allocator, + dmabuf::{AnyError, Dmabuf, DmabufAllocator}, + gbm::GbmAllocator, + }, + drm::{CreateDrmNodeError, DrmNode}, + renderer::{ + RendererSuper, + gles::{GlesError, GlesRenderer}, + glow::GlowRenderer, + multigpu::{ApiDevice, Error as MultiError, GraphicsApi}, }, - reexports::drm::control::Device, -}; -use std::{ - borrow::{Borrow, BorrowMut}, - cell::Cell, - ffi::{CStr, c_char}, }; +use std::{borrow::Borrow, cell::Cell}; use std::{ collections::HashMap, fmt, @@ -107,7 +98,7 @@ impl GbmGlowBackend { } } -impl GraphicsApi for GbmGlowBackend { +impl GraphicsApi for GbmGlowBackend { type Device = GbmGlowDevice; type Error = Error; @@ -132,29 +123,11 @@ impl GraphicsApi for GbmGlowBackend { .any(|renderer| renderer.node.dev_id() == node.dev_id()) }) .flat_map(|(node, (allocator, renderer))| { - let mut renderer = renderer.replace(None)?; - let is_intel = allocator - .as_ref() - .get_driver() - .is_ok_and(|drv| drv.name().contains("i915")); - let intel_export_quirk = is_intel - && BorrowMut::::borrow_mut(&mut renderer) - .with_context(|gl| unsafe { - CStr::from_ptr(gl.GetString(ffi::RENDERER) as *const c_char) - }) - .is_ok_and(|name| { - name.as_str().is_ok_and(|name| { - name.contains("TGL") - || name.contains("MTL") - || name.contains("ARL") - || name.contains("LNL") - }) - }); + let renderer = renderer.replace(None)?; Some(GbmGlowDevice { node: *node, renderer, - intel_export_quirk, allocator: Box::new(DmabufAllocator(allocator.clone())), }) }) @@ -177,7 +150,6 @@ impl GraphicsApi for GbmGlowBackend { pub struct GbmGlowDevice { node: DrmNode, renderer: GlowRenderer, - intel_export_quirk: bool, allocator: Box>, } @@ -208,14 +180,9 @@ impl ApiDevice for GbmGlowDevice { fn can_do_cross_device_imports(&self) -> bool { !Borrow::::borrow(&self.renderer).is_software() } - - fn should_do_cross_device_exports(&self) -> bool { - !self.intel_export_quirk - } } -impl FromGlesError - for MultiError, T> +impl FromGlesError for MultiError, T> where T::Error: 'static, <::Renderer as RendererSuper>::Error: 'static, diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index 62ba7c1f..6b0d42b4 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -1024,18 +1024,14 @@ impl SurfaceThreadState { let animations_going = shell.animations_going(); let output = self.mirroring.as_ref().unwrap_or(&self.output); if let Some((_, workspace)) = shell.workspaces.active(output) { - let seat = shell.seats.last_active(); - if let Some(fullscreen_surface) = workspace.get_fullscreen(seat) { + if let Some(fullscreen_surface) = workspace.get_fullscreen() { const _30_FPS: Duration = Duration::from_nanos(1_000_000_000 / 30); ( true, - fullscreen_surface - .surface - .wl_surface() - .is_some_and(|surface| { - recursive_frame_time_estimation(&self.clock, &surface) - .is_some_and(|dur| dur <= _30_FPS) - }), + fullscreen_surface.wl_surface().is_some_and(|surface| { + recursive_frame_time_estimation(&self.clock, &surface) + .is_some_and(|dur| dur <= _30_FPS) + }), animations_going, ) } else { @@ -1494,21 +1490,18 @@ fn render_node_for_output( let Some(workspace) = shell.active_space(output) else { return *target_node; }; - let fullscreens: Vec<_> = workspace - .get_fullscreen_surfaces() - .map(|f| f.surface.clone()) - .collect(); - let nodes = if !fullscreens.is_empty() { - fullscreens - } else { - workspace - .mapped() - .map(|mapped| mapped.active_window()) - .collect::>() - } - .into_iter() - .flat_map(|w| w.wl_surface().and_then(|s| source_node_for_surface(&s))) - .collect::>(); + let nodes = workspace + .get_fullscreen() + .map(|w| vec![w.clone()]) + .unwrap_or_else(|| { + workspace + .mapped() + .map(|mapped| mapped.active_window()) + .collect::>() + }) + .into_iter() + .flat_map(|w| w.wl_surface().and_then(|s| source_node_for_surface(&s))) + .collect::>(); if nodes.contains(target_node) || nodes.is_empty() { *target_node diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 0ff249a7..a35b0c98 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -26,7 +26,7 @@ use smithay::{ calloop::{EventLoop, ping}, wayland_protocols::wp::presentation_time::server::wp_presentation_feedback, wayland_server::DisplayHandle, - winit::event_loop::pump_events::PumpStatus, + winit::platform::pump_events::PumpStatus, }, utils::Transform, wayland::{dmabuf::DmabufFeedbackBuilder, presentation::Refresh}, diff --git a/src/config/mod.rs b/src/config/mod.rs index 1d9b9c92..d75eed4e 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -45,8 +45,8 @@ mod types; use cosmic::config::CosmicTk; pub use cosmic_comp_config::EdidProduct; use cosmic_comp_config::{ - ActivationPolicy, AppearanceConfig, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig, - XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, + AppearanceConfig, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig, XwaylandDescaling, + XwaylandEavesdropping, ZoomConfig, input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride}, output::comp::{ OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs, @@ -966,12 +966,6 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut } } } - "activation_policy" => { - let new = get_config::(&config, "activation_policy"); - if new != state.common.config.cosmic_conf.activation_policy { - state.common.config.cosmic_conf.activation_policy = new; - } - } _ => {} } } diff --git a/src/dbus/a11y_keyboard_monitor.rs b/src/dbus/a11y_keyboard_monitor.rs index cf66a54b..c40be081 100644 --- a/src/dbus/a11y_keyboard_monitor.rs +++ b/src/dbus/a11y_keyboard_monitor.rs @@ -1,12 +1,13 @@ // https://gitlab.gnome.org/GNOME/mutter/-/blob/main/data/dbus-interfaces/org.freedesktop.a11y.xml +use futures_executor::ThreadPool; use smithay::{ backend::input::KeyState, input::keyboard::{KeysymHandle, ModifiersState}, }; use std::{ collections::{HashMap, HashSet}, - sync::{Arc, Mutex}, + sync::{Arc, Mutex, OnceLock}, }; use tracing::debug; use xkbcommon::xkb::Keysym; @@ -71,37 +72,40 @@ impl Clients { #[derive(Debug)] pub struct A11yKeyboardMonitorState { - executor: calloop::futures::Scheduler<()>, + executor: ThreadPool, clients: Arc>, active_virtual_mods: HashSet, - conn: zbus::Connection, - name_owners: NameOwners, + conn: Arc>, + name_owners: Arc>, } impl A11yKeyboardMonitorState { - pub async fn new( - conn: &zbus::Connection, - name_owners: &NameOwners, - executor: &calloop::futures::Scheduler<()>, - ) -> zbus::Result { + pub fn new(executor: &ThreadPool) -> Self { let clients = Arc::new(Mutex::new(Clients::default())); - - let keyboard_monitor = KeyboardMonitor { - clients: clients.clone(), - name_owners: name_owners.clone(), - }; - conn.object_server() - .at("/org/freedesktop/a11y/Manager", keyboard_monitor) - .await?; - conn.request_name("org.freedesktop.a11y.Manager").await?; - - Ok(Self { + let clients_clone = clients.clone(); + let conn_cell = Arc::new(OnceLock::new()); + let conn_cell_clone = conn_cell.clone(); + let name_owners_cell = Arc::new(OnceLock::new()); + let name_owners_cell_clone = name_owners_cell.clone(); + let executor_clone = executor.clone(); + executor.spawn_ok(async move { + match serve(clients_clone, &executor_clone).await { + Ok((conn, name_owners)) => { + conn_cell_clone.set(conn).unwrap(); + name_owners_cell_clone.set(name_owners).unwrap(); + } + Err(err) => { + tracing::error!("Failed to serve `org.freedesktop.a11y.Manager`: {err}"); + } + } + }); + Self { executor: executor.clone(), clients, active_virtual_mods: HashSet::new(), - conn: conn.clone(), - name_owners: name_owners.clone(), - }) + conn: conn_cell, + name_owners: name_owners_cell, + } } pub fn has_virtual_mod(&self, keysym: Keysym) -> bool { @@ -150,6 +154,10 @@ impl A11yKeyboardMonitorState { } pub fn key_event(&self, modifiers: &ModifiersState, keysym: &KeysymHandle, state: KeyState) { + let Some(conn) = self.conn.get() else { + return; + }; + let clients = self.clients.lock().unwrap(); for (unique_name, client) in clients.0.iter() { if !client.watched && !self.has_key_grab(modifiers, keysym.modified_sym()) { @@ -157,7 +165,7 @@ impl A11yKeyboardMonitorState { } let mut signal_context = - SignalEmitter::new(&self.conn, "/org/freedesktop/a11y/Manager").unwrap(); + SignalEmitter::new(conn, "/org/freedesktop/a11y/Manager").unwrap(); // Instead of sending signal to all clients, send only to authorized // clients with registed watches. signal_context = signal_context.set_destination(unique_name.clone().into()); @@ -178,7 +186,7 @@ impl A11yKeyboardMonitorState { unichar, keysym.raw_code().raw() as u16, ); - let _ = self.executor.schedule(async { + self.executor.spawn_ok(async { let _ = future.await; }); } @@ -187,11 +195,13 @@ impl A11yKeyboardMonitorState { pub fn refresh(&mut self) { // Remove clients and associated grabs when unique names are no longer // present on bus, or no longer hold approved name on bus. - self.clients - .lock() - .unwrap() - .0 - .retain(|k, _| self.name_owners.check_owner_no_poll(k, ALLOWED_NAMES)) + if let Some(name_owners) = self.name_owners.get() { + self.clients + .lock() + .unwrap() + .0 + .retain(|k, _| name_owners.check_owner_no_poll(k, ALLOWED_NAMES)) + } } } @@ -301,3 +311,20 @@ impl KeyboardMonitor { keycode: u16, ) -> zbus::Result<()>; } + +async fn serve( + clients: Arc>, + executor: &ThreadPool, +) -> zbus::Result<(zbus::Connection, NameOwners)> { + let conn = zbus::Connection::session().await?; + let name_owners = NameOwners::new(&conn, executor).await?; + let keyboard_monitor = KeyboardMonitor { + clients, + name_owners: name_owners.clone(), + }; + conn.object_server() + .at("/org/freedesktop/a11y/Manager", keyboard_monitor) + .await?; + conn.request_name("org.freedesktop.a11y.Manager").await?; + Ok((conn, name_owners)) +} diff --git a/src/dbus/logind.rs b/src/dbus/logind.rs index 53e3b2c0..b0c59170 100644 --- a/src/dbus/logind.rs +++ b/src/dbus/logind.rs @@ -1,34 +1,24 @@ use std::os::fd::OwnedFd; use anyhow::{Context, Result}; -use logind_zbus::manager::{InhibitType::HandleLidSwitch, ManagerProxy}; +use logind_zbus::manager::{InhibitType::HandleLidSwitch, ManagerProxyBlocking}; +use zbus::blocking::Connection; -use crate::state::Common; - -pub fn inhibit_lid(common: &Common) -> Result { - let fd = futures_executor::block_on(async { - let conn = common.dbus_state.system_conn().await?; - let manager = ManagerProxy::new(conn).await?; - manager - .inhibit( - HandleLidSwitch, - "cosmic-comp", - "External output connected", - "block", - ) - .await - })?; +pub fn inhibit_lid() -> Result { + let conn = Connection::system()?; + let proxy = ManagerProxyBlocking::new(&conn)?; + let fd = proxy.inhibit( + HandleLidSwitch, + "cosmic-comp", + "External output connected", + "block", + )?; Ok(fd.into()) } -pub fn lid_closed(common: &Common) -> Result { - futures_executor::block_on(async { - let conn = common.dbus_state.system_conn().await?; - let manager = ManagerProxy::new(conn).await?; - manager - .lid_closed() - .await - .context("Failed to talk to logind") - }) +pub fn lid_closed() -> Result { + let conn = Connection::system()?; + let proxy = ManagerProxyBlocking::new(&conn)?; + proxy.lid_closed().context("Failed to talk to logind") } diff --git a/src/dbus/mod.rs b/src/dbus/mod.rs index 5b9754c3..dcb7f257 100644 --- a/src/dbus/mod.rs +++ b/src/dbus/mod.rs @@ -3,168 +3,103 @@ use crate::{ utils::prelude::OutputExt, }; use anyhow::{Context, Result}; -use calloop::{InsertError, LoopHandle, stream::StreamSource}; +use calloop::{InsertError, LoopHandle, RegistrationToken}; use cosmic_comp_config::output::comp::OutputState; -use std::{ - cell::{RefCell, RefMut}, - collections::HashMap, - rc::Rc, -}; +use futures_executor::{ThreadPool, block_on}; +use futures_util::stream::StreamExt; +use std::collections::HashMap; use tracing::{error, warn}; +use zbus::blocking::{Connection, fdo::DBusProxy}; pub mod a11y_keyboard_monitor; -use a11y_keyboard_monitor::A11yKeyboardMonitorState; -#[cfg(feature = "logind")] +#[cfg(feature = "systemd")] pub mod logind; mod name_owners; mod power; -#[derive(Clone, Debug)] -pub struct DBusState(Rc); +pub fn init( + evlh: &LoopHandle<'static, State>, + executor: &ThreadPool, +) -> Result> { + let mut tokens = Vec::new(); -#[derive(Debug)] -struct DBusStateInner { - evlh: LoopHandle<'static, State>, - executor: calloop::futures::Scheduler<()>, - session_conn: zbus::Result, - system_conn: zbus::Result, - a11y_keyboard_monitor: RefCell>, -} - -impl DBusState { - pub fn init(evlh: &LoopHandle<'static, State>) -> Self { - let (source, executor) = calloop::futures::executor().unwrap(); - let session_conn = futures_executor::block_on(zbus::Connection::session()); - let system_conn = futures_executor::block_on(zbus::Connection::system()); - let state = Self(Rc::new(DBusStateInner { - evlh: evlh.clone(), - executor, - session_conn, - system_conn, - a11y_keyboard_monitor: RefCell::new(None), - })); - evlh.insert_source(source, |_, _, _| {}).unwrap(); - let state_clone = state.clone(); - state.spawn(async move { - if let Err(err) = init_session(&state_clone).await { - tracing::error!("Failed to initialize session DBus connection: {}", err); - } - }); - let state_clone = state.clone(); - state.spawn(async move { - if let Err(err) = init_system(&state_clone).await { - tracing::error!("Failed to initialize system DBus connection: {}", err); - } - }); - state - } - - pub fn a11y_keyboard_monitor( - &self, - ) -> Option> { - RefMut::filter_map(self.0.a11y_keyboard_monitor.borrow_mut(), |x| x.as_mut()).ok() - } - - // TODO Lazy async init when we don't have anything blocking main thread - async fn session_conn(&self) -> zbus::Result<&zbus::Connection> { - self.0.session_conn.as_ref().map_err(|err| err.clone()) - } - - async fn system_conn(&self) -> zbus::Result<&zbus::Connection> { - self.0.system_conn.as_ref().map_err(|err| err.clone()) - } - - fn spawn(&self, fut: impl Future + 'static) { - let _ = self.0.executor.schedule(fut); - } -} - -async fn init_session(state: &DBusState) -> zbus::Result<()> { - let conn = state.session_conn().await?; - let name_owners = name_owners::NameOwners::new(conn, &state.0.executor).await?; - let a11y_keyboard_monitor_state = - A11yKeyboardMonitorState::new(conn, &name_owners, &state.0.executor).await?; - *state.0.a11y_keyboard_monitor.borrow_mut() = Some(a11y_keyboard_monitor_state); - Ok(()) -} - -async fn init_system(state: &DBusState) -> zbus::Result<()> { - let conn = state.system_conn().await?.clone(); - let evlh = state.0.evlh.clone(); - state.spawn(async move { - if let Err(err) = power_hot_plug_task(conn, evlh).await { - tracing::warn!(?err, "Failed to initialize dbus handlers"); - } - }); - Ok(()) -} - -async fn power_hot_plug_task( - conn: zbus::Connection, - evlh: LoopHandle<'static, State>, -) -> Result<()> { - match power::init(&conn).await { + match block_on(power::init()) { Ok(power_daemon) => { - if let Ok(stream) = power_daemon.receive_hot_plug_detect().await { - let source = StreamSource::new(stream).unwrap(); - evlh.insert_source(source, |_, _, state| { - let nodes = match &mut state.backend { - BackendData::Kms(kms) => { - kms.drm_devices.keys().cloned().collect::>() + let (tx, rx) = calloop::channel::channel(); + + let token = evlh + .insert_source(rx, |event, _, state| match event { + calloop::channel::Event::Msg(_) => { + let nodes = match &mut state.backend { + BackendData::Kms(kms) => { + kms.drm_devices.keys().cloned().collect::>() + } + _ => Vec::new(), + }; + let mut added = Vec::new(); + for node in nodes { + match state.device_changed(node.dev_id()) { + Ok(outputs) => added.extend(outputs), + Err(err) => { + tracing::error!(?err, "Failed to update drm device {}.", node) + } + } } - _ => Vec::new(), - }; - let mut added = Vec::new(); - for node in nodes { - match state.device_changed(node.dev_id()) { - Ok(outputs) => added.extend(outputs), - Err(err) => { - tracing::error!(?err, "Failed to update drm device {}.", node) - } - } - } - if let Err(err) = state.refresh_output_config() { - warn!("Unable to load output config: {}", err); - if !added.is_empty() { - for output in added { - output.config_mut().enabled = OutputState::Disabled; - } - if let Err(err) = state.refresh_output_config() { - error!("Unrecoverable config error: {}", err); + if let Err(err) = state.refresh_output_config() { + warn!("Unable to load output config: {}", err); + if !added.is_empty() { + for output in added { + output.config_mut().enabled = OutputState::Disabled; + } + if let Err(err) = state.refresh_output_config() { + error!("Unrecoverable config error: {}", err); + } } } } + calloop::channel::Event::Closed => (), }) .map_err(|InsertError { error, .. }| error) .with_context(|| "Failed to add channel to event_loop")?; - } + + // start helper thread + executor.spawn_ok(async move { + if let Ok(mut msg_iter) = power_daemon.receive_hot_plug_detect().await { + while let Some(msg) = msg_iter.next().await { + if tx.send(msg).is_err() { + break; + } + } + } + }); + + tokens.push(token); } Err(err) => { tracing::info!(?err, "Failed to connect to com.system76.PowerDaemon"); } }; - Ok(()) + + Ok(tokens) } /// Updated the D-Bus activation environment with `WAYLAND_DISPLAY` and /// `DISPLAY` variables. pub fn ready(common: &Common) -> Result<()> { - futures_executor::block_on(async { - let conn = common.dbus_state.session_conn().await?; - let dbus = zbus::fdo::DBusProxy::new(conn).await?; + let conn = Connection::session()?; + let proxy = DBusProxy::new(&conn)?; + + proxy.update_activation_environment(HashMap::from([ + ("WAYLAND_DISPLAY", common.socket.to_str().unwrap()), + ( + "DISPLAY", + &common + .xwayland_state + .as_ref() + .map(|s| format!(":{}", s.display)) + .unwrap_or_default(), + ), + ]))?; - dbus.update_activation_environment(HashMap::from([ - ("WAYLAND_DISPLAY", common.socket.to_str().unwrap()), - ( - "DISPLAY", - &common - .xwayland_state - .as_ref() - .map(|s| format!(":{}", s.display)) - .unwrap_or_default(), - ), - ])) - .await - })?; Ok(()) } diff --git a/src/dbus/name_owners.rs b/src/dbus/name_owners.rs index a2715c73..fe3591b5 100644 --- a/src/dbus/name_owners.rs +++ b/src/dbus/name_owners.rs @@ -2,10 +2,9 @@ //! //! Compare to Mutter's `MetaDbusAccessChecker` -use futures_util::{ - StreamExt, - stream::{FusedStream, FuturesUnordered}, -}; +use futures_executor::ThreadPool; +use futures_util::stream::FusedStream; +use futures_util::{StreamExt, stream::FuturesUnordered}; use std::{ collections::{HashMap, HashSet}, future::{Future, poll_fn}, @@ -95,10 +94,7 @@ fn update_task(inner: Weak>) -> impl Future { pub struct NameOwners(Arc>); impl NameOwners { - pub async fn new( - connection: &zbus::Connection, - executor: &calloop::futures::Scheduler<()>, - ) -> zbus::Result { + pub async fn new(connection: &zbus::Connection, executor: &ThreadPool) -> zbus::Result { let dbus = fdo::DBusProxy::new(connection).await?; let stream = dbus.receive_name_owner_changed().await?; @@ -130,7 +126,7 @@ impl NameOwners { })); if enforce { - let _ = executor.schedule(update_task(Arc::downgrade(&inner))); + executor.spawn_ok(update_task(Arc::downgrade(&inner))); } Ok(NameOwners(inner)) diff --git a/src/dbus/power.rs b/src/dbus/power.rs index a20e5669..346b8107 100644 --- a/src/dbus/power.rs +++ b/src/dbus/power.rs @@ -79,8 +79,9 @@ pub trait PowerDaemon { fn power_profile_switch(&self, profile: &str) -> zbus::Result<()>; } -pub async fn init(conn: &Connection) -> anyhow::Result> { - let proxy = PowerDaemonProxy::new(conn).await?; +pub async fn init() -> anyhow::Result> { + let conn = Connection::system().await?; + let proxy = PowerDaemonProxy::new(&conn).await?; proxy.0.introspect().await?; Ok(proxy) } diff --git a/src/input/mod.rs b/src/input/mod.rs index da3014ae..548a60ab 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -52,21 +52,16 @@ use smithay::{ AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, - PointerGrab, PointerHandle, RelativeMotionEvent, + PointerGrab, RelativeMotionEvent, }, touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent}, }, output::Output, reexports::{ - input::Device as InputDevice, - wayland_server::{ - Resource as _, - protocol::{wl_shm::Format as ShmFormat, wl_surface::WlSurface}, - }, + input::Device as InputDevice, wayland_server::protocol::wl_shm::Format as ShmFormat, }, - utils::{Logical, Point, Rectangle, SERIAL_COUNTER, Serial, Size}, + utils::{Point, Rectangle, SERIAL_COUNTER, Serial}, wayland::{ - compositor::CompositorHandler, image_copy_capture::{BufferConstraints, CursorSessionRef}, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat, pointer_constraints::{PointerConstraint, with_pointer_constraint}, @@ -354,6 +349,27 @@ impl State { _ => {} }); } + let original_position = position; + position += event.delta().as_global(); + + let output = shell + .outputs() + .find(|output| output.geometry().to_f64().contains(position)) + .cloned() + .unwrap_or(current_output.clone()); + + let output_geometry = output.geometry(); + position.x = position.x.clamp( + output_geometry.loc.x as f64, + (output_geometry.loc.x + output_geometry.size.w - 1) as f64, + ); + position.y = position.y.clamp( + output_geometry.loc.y as f64, + (output_geometry.loc.y + output_geometry.size.h - 1) as f64, + ); + + let new_under = State::surface_under(position, &output, &shell) + .map(|(target, pos)| (target, pos.as_logical())); std::mem::drop(shell); ptr.relative_motion( @@ -371,25 +387,6 @@ impl State { return; } - let original_position = position; - position += event.delta().as_global(); - let shell = self.common.shell.read(); - let output = shell - .outputs() - .find(|output| output.geometry().to_f64().contains(position)) - .cloned() - .unwrap_or(current_output.clone()); - drop(shell); - let output_geometry = output.geometry(); - position.x = position.x.clamp( - output_geometry.loc.x as f64, - (output_geometry.loc.x + output_geometry.size.w - 1) as f64, - ); - position.y = position.y.clamp( - output_geometry.loc.y as f64, - (output_geometry.loc.y + output_geometry.size.h - 1) as f64, - ); - if ptr.is_grabbed() { if seat .user_data() @@ -497,90 +494,50 @@ impl State { } } - // If confined, help user to update valid coordinates can improve user experience - let shell = self.common.shell.read(); - let new_under = if pointer_confined && let Some((surface, surface_loc)) = &under - { - let is_legal = |pos: Point, shell: &Shell| { - let new_under = State::surface_under(pos, &output, shell) - .map(|(target, pos)| (target, pos.as_logical())); - - // TODO: We might need a solution that allows constraints to bypass the surface without affecting the constraints themselves - if new_under.as_ref().and_then(|(under, _)| under.wl_surface()) - != surface.wl_surface() - { - return (false, None); + // If confined, don't move pointer if it would go outside surface or region + if pointer_confined && let Some((surface, surface_loc)) = &under { + if new_under.as_ref().and_then(|(under, _)| under.wl_surface()) + != surface.wl_surface() + { + ptr.frame(self); + return; + } + match surface { + PointerFocusTarget::WlSurface { surface, .. } => { + if under_from_surface_tree( + surface, + position.as_logical() - surface_loc.to_f64(), + (0, 0), + WindowSurfaceType::ALL, + ) + .is_none() + { + ptr.frame(self); + return; + } } - - match surface { - PointerFocusTarget::WlSurface { surface, .. } => { - if under_from_surface_tree( - surface, + PointerFocusTarget::X11Surface { surface, .. } => { + if surface + .surface_under( position.as_logical() - surface_loc.to_f64(), (0, 0), WindowSurfaceType::ALL, ) .is_none() - { - return (false, None); - } - } - PointerFocusTarget::X11Surface { surface, .. } => { - if surface - .surface_under( - position.as_logical() - surface_loc.to_f64(), - (0, 0), - WindowSurfaceType::ALL, - ) - .is_none() - { - return (false, None); - } - } - _ => {} - } - - if let Some(region) = &confine_region - && !region - .contains((pos.as_logical() - *surface_loc).to_i32_round()) - { - return (false, None); - } - (true, new_under) - }; - - match is_legal(position, &shell) { - (true, under) => under, - _ => { - let y_only_pos = Point::new(original_position.x, position.y); - let x_only_pos = Point::new(position.x, original_position.y); - match is_legal(y_only_pos, &shell) { - (true, under) => { - position = y_only_pos; - under - } - _ => match is_legal(x_only_pos, &shell) { - (true, under) => { - position = x_only_pos; - under - } - _ => { - position = original_position; - None - } - }, + { + ptr.frame(self); + return; } } + _ => {} + } + if let Some(region) = confine_region + && !region + .contains((position.as_logical() - *surface_loc).to_i32_round()) + { + ptr.frame(self); + return; } - } else { - State::surface_under(position, &output, &shell) - .map(|(target, pos)| (target, pos.as_logical())) - }; - - drop(shell); - if pointer_confined && new_under.is_none() { - ptr.frame(self); - return; } let serial = SERIAL_COUNTER.next_serial(); @@ -595,32 +552,24 @@ impl State { ); ptr.frame(self); - // If pointer is now in a constraint region and window is in focused, activate it + // If pointer is now in a constraint region, activate it if let Some((under, surface_location)) = new_under .and_then(|(target, loc)| Some((target.wl_surface()?.into_owned(), loc))) { - let shell = self.common.shell.read(); - let is_focused = seat - .get_keyboard() - .and_then(|k| k.current_focus()) - .is_some_and(|f| f.has_surface(&shell, &under)); - - if is_focused { - with_pointer_constraint(&under, &ptr, |constraint| match constraint { - Some(constraint) if !constraint.is_active() => { - let region = match &*constraint { - PointerConstraint::Locked(locked) => locked.region(), - PointerConstraint::Confined(confined) => confined.region(), - }; - let point = - (ptr.current_location() - surface_location).to_i32_round(); - if region.is_none_or(|region| region.contains(point)) { - constraint.activate(); - } + with_pointer_constraint(&under, &ptr, |constraint| match constraint { + Some(constraint) if !constraint.is_active() => { + let region = match &*constraint { + PointerConstraint::Locked(locked) => locked.region(), + PointerConstraint::Confined(confined) => confined.region(), + }; + let point = + (ptr.current_location() - surface_location).to_i32_round(); + if region.is_none_or(|region| region.contains(point)) { + constraint.activate(); } - _ => {} - }); - } + } + _ => {} + }); } let mut shell = self.common.shell.write(); @@ -640,13 +589,11 @@ impl State { for session in cursor_sessions_for_output(&shell, &output) { if let Some((geometry, offset)) = seat.cursor_geometry( - (position - output_geometry.loc.to_f64()) - .as_logical() - .to_buffer( - output.current_scale().fractional_scale(), - output.current_transform(), - &output_geometry.size.to_f64().as_logical(), - ), + position.as_logical().to_buffer( + output.current_scale().fractional_scale(), + output.current_transform(), + &output_geometry.size.to_f64().as_logical(), + ), self.common.clock.now(), ) { if session @@ -654,13 +601,8 @@ impl State { .map(|constraint| constraint.size != geometry.size) .unwrap_or(true) { - let mut cursor_size = geometry.size; - // Client shouldn't try to allocate 0x0 buffer - if cursor_size == Size::new(0, 0) { - cursor_size = Size::new(1, 1); - } session.update_constraints(BufferConstraints { - size: cursor_size, + size: geometry.size, shm: vec![ShmFormat::Argb8888], dma: None, }); @@ -683,11 +625,11 @@ impl State { self.common.idle_notifier_state.notify_activity(&seat); notify_cursor_activity(self, &seat); let output = seat.active_output(); - let output_geometry = output.geometry(); - let position = output_geometry.loc.to_f64() + let geometry = output.geometry(); + let position = geometry.loc.to_f64() + smithay::backend::input::AbsolutePositionEvent::position_transformed( &event, - output_geometry.size.as_logical(), + geometry.size.as_logical(), ) .as_global(); let serial = SERIAL_COUNTER.next_serial(); @@ -709,13 +651,11 @@ impl State { let shell = self.common.shell.read(); for session in cursor_sessions_for_output(&shell, &output) { if let Some((geometry, offset)) = seat.cursor_geometry( - (position - output_geometry.loc.to_f64()) - .as_logical() - .to_buffer( - output.current_scale().fractional_scale(), - output.current_transform(), - &output_geometry.size.to_f64().as_logical(), - ), + position.as_logical().to_buffer( + output.current_scale().fractional_scale(), + output.current_transform(), + &geometry.size.to_f64().as_logical(), + ), self.common.clock.now(), ) { if session @@ -723,13 +663,8 @@ impl State { .map(|constraint| constraint.size != geometry.size) .unwrap_or(true) { - let mut cursor_size = geometry.size; - // Client shouldn't try to allocate 0x0 buffer - if cursor_size == Size::new(0, 0) { - cursor_size = Size::new(1, 1); - } session.update_constraints(BufferConstraints { - size: cursor_size, + size: geometry.size, shm: vec![ShmFormat::Argb8888], dma: None, }); @@ -1600,7 +1535,7 @@ impl State { } InputEvent::Special(_) => {} InputEvent::SwitchToggle { event } => { - #[cfg(feature = "logind")] + #[cfg(feature = "systemd")] if event.switch() == Some(Switch::Lid) && self.common.inhibit_lid_fd.is_some() { let backend = self.backend.lock(); let output = backend @@ -1682,9 +1617,9 @@ impl State { .unwrap_or(false) }); - if let Some(a11y_keyboard_monitor) = self.common.dbus_state.a11y_keyboard_monitor() { - a11y_keyboard_monitor.key_event(modifiers, &handle, event.state()); - } + self.common + .a11y_keyboard_monitor_state + .key_event(modifiers, &handle, event.state()); // Leave move overview mode, if any modifier was released if let Some(Trigger::KeyboardMove(action_modifiers)) = @@ -1844,54 +1779,61 @@ impl State { ))); } - if let Some(mut a11y_keyboard_monitor) = self.common.dbus_state.a11y_keyboard_monitor() { - if event.state() == KeyState::Released { - let removed = - a11y_keyboard_monitor.remove_active_virtual_mod(handle.modified_sym()); - // If `Caps_Lock` is a virtual modifier, and is in locked state, clear it - if removed - && handle.modified_sym() == Keysym::Caps_Lock - && (modifiers.serialized.locked & 2) != 0 - { - let seat = seat.clone(); - let key_code = event.key_code(); - self.common.event_loop_handle.insert_idle(move |state| { - if let Some(keyboard) = seat.get_keyboard() { - let serial = SERIAL_COUNTER.next_serial(); - let time = state.common.clock.now().as_millis(); - keyboard.input( - state, - key_code, - KeyState::Pressed, - serial, - time, - |_, _, _| FilterResult::<()>::Forward, - ); - let serial = SERIAL_COUNTER.next_serial(); - keyboard.input( - state, - key_code, - KeyState::Released, - serial, - time, - |_, _, _| FilterResult::<()>::Forward, - ); - } - }); - } - } else if event.state() == KeyState::Pressed - && a11y_keyboard_monitor.has_virtual_mod(handle.modified_sym()) + if event.state() == KeyState::Released { + let removed = self + .common + .a11y_keyboard_monitor_state + .remove_active_virtual_mod(handle.modified_sym()); + // If `Caps_Lock` is a virtual modifier, and is in locked state, clear it + if removed + && handle.modified_sym() == Keysym::Caps_Lock + && (modifiers.serialized.locked & 2) != 0 { - a11y_keyboard_monitor.add_active_virtual_mod(handle.modified_sym()); - - tracing::debug!( - "active virtual mods: {:?}", - a11y_keyboard_monitor.active_virtual_mods() - ); - seat.supressed_keys().add(&handle, None); - - return FilterResult::Intercept(None); + let seat = seat.clone(); + let key_code = event.key_code(); + self.common.event_loop_handle.insert_idle(move |state| { + if let Some(keyboard) = seat.get_keyboard() { + let serial = SERIAL_COUNTER.next_serial(); + let time = state.common.clock.now().as_millis(); + keyboard.input( + state, + key_code, + KeyState::Pressed, + serial, + time, + |_, _, _| FilterResult::<()>::Forward, + ); + let serial = SERIAL_COUNTER.next_serial(); + keyboard.input( + state, + key_code, + KeyState::Released, + serial, + time, + |_, _, _| FilterResult::<()>::Forward, + ); + } + }); } + } else if event.state() == KeyState::Pressed + && self + .common + .a11y_keyboard_monitor_state + .has_virtual_mod(handle.modified_sym()) + { + self.common + .a11y_keyboard_monitor_state + .add_active_virtual_mod(handle.modified_sym()); + + tracing::debug!( + "active virtual mods: {:?}", + self.common + .a11y_keyboard_monitor_state + .active_virtual_mods() + ); + seat.supressed_keys().add(&handle, None); + + return FilterResult::Intercept(None); } // Skip released events for initially surpressed keys @@ -1918,10 +1860,12 @@ impl State { return FilterResult::Intercept(None); } - if let Some(a11y_keyboard_monitor) = self.common.dbus_state.a11y_keyboard_monitor() - && event.state() == KeyState::Pressed - && (a11y_keyboard_monitor.has_keyboard_grab() - || a11y_keyboard_monitor.has_key_grab(modifiers, handle.modified_sym())) + if event.state() == KeyState::Pressed + && (self.common.a11y_keyboard_monitor_state.has_keyboard_grab() + || self + .common + .a11y_keyboard_monitor_state + .has_key_grab(modifiers, handle.modified_sym())) { let modifiers_queue = seat.modifiers_shortcut_queue(); modifiers_queue.clear(); @@ -2173,14 +2117,14 @@ impl State { } Stage::StickyPopups(layout) => { if let Some(element) = - layout.popup_element_under(global_pos.to_local(output), seat) + layout.popup_element_under(global_pos.to_local(output)) { return ControlFlow::Break(Ok(Some(element))); } } Stage::Sticky(layout) => { if let Some(element) = - layout.toplevel_element_under(global_pos.to_local(output), seat) + layout.toplevel_element_under(global_pos.to_local(output)) { return ControlFlow::Break(Ok(Some(element))); } @@ -2335,7 +2279,7 @@ impl State { } Stage::StickyPopups(floating_layer) => { if let Some(under) = floating_layer - .popup_surface_under(relative_pos, seat) + .popup_surface_under(relative_pos) .map(|(target, point)| (target, point.to_global(output))) { return ControlFlow::Break(Ok(Some(under))); @@ -2343,7 +2287,7 @@ impl State { } Stage::Sticky(floating_layer) => { if let Some(under) = floating_layer - .toplevel_surface_under(relative_pos, seat) + .toplevel_surface_under(relative_pos) .map(|(target, point)| (target, point.to_global(output))) { return ControlFlow::Break(Ok(Some(under))); @@ -2373,113 +2317,8 @@ impl State { .ok() .flatten() } - - pub fn apply_cursor_hint( - &mut self, - surface: &WlSurface, - pointer: &PointerHandle, - mut location: Point, - ) { - let Some(client) = surface.client() else { - return; - }; - location = location.downscale(self.client_compositor_state(&client).client_scale()); - - let point_and_output = { - let shell = self.common.shell.read(); - let found = shell.workspaces.sets.iter().find_map(|(out, set)| { - set.surface_geometry_offset_from_toplevel(surface) - .map(|(geometry, surface_offset)| (out, geometry, surface_offset)) - }); - - if let Some((output, geometry, surface_offset)) = found { - let pos_in_element = location + surface_offset.to_f64(); - let window_size = geometry.size.to_f64(); - - let is_legal = |p: Point| { - let in_window = - p.x >= 0.0 && p.y >= 0.0 && p.x < window_size.w && p.y < window_size.h; - if !in_window { - return false; - } - - with_pointer_constraint(surface, pointer, |constraint| { - if let Some(constraint) = constraint - && let Some(region) = constraint.region() - { - let point_in_surface = (p - surface_offset.to_f64()).to_i32_round(); - return region.contains(point_in_surface); - } - true - }) - }; - - let workspace_origin = output.geometry().loc.to_f64(); - let origin = geometry.loc.to_f64(); - - if is_legal(pos_in_element) { - let x = workspace_origin.x + origin.x + pos_in_element.x; - let y = workspace_origin.y + origin.y + pos_in_element.y; - Some((Point::new(x, y), output.clone())) - } else { - None - } - } else { - None - } - }; - - if let Some((point, output)) = point_and_output { - let original_position = pointer.current_location(); - pointer.set_location(point); - - let mut shell = self.common.shell.write(); - shell.update_pointer_position(point.as_global().to_local(&output), &output); - - let seat = shell - .seats - .iter() - .find(|s| s.get_pointer().as_ref() == Some(pointer)) - .cloned(); - - if let Some(seat) = seat { - shell.update_focal_point( - &seat, - original_position.as_global(), - self.common.config.cosmic_conf.accessibility_zoom.view_moves, - ); - - let output_geometry = output.geometry(); - for session in cursor_sessions_for_output(&shell, &output) { - if let Some((geometry, offset)) = seat.cursor_geometry( - point.to_buffer( - output.current_scale().fractional_scale(), - output.current_transform(), - &output_geometry.size.to_f64().as_logical(), - ), - self.common.clock.now(), - ) { - if session - .current_constraints() - .map(|constraint| constraint.size != geometry.size) - .unwrap_or(true) - { - session.update_constraints(BufferConstraints { - size: geometry.size, - shm: vec![ShmFormat::Argb8888], - dma: None, - }); - } - session.set_cursor_hotspot(offset); - session.set_cursor_pos(Some(geometry.loc)); - } - } - } - } - } } -// Output and workspace sessions for the given output fn cursor_sessions_for_output<'a>( shell: &'a Shell, output: &'a Output, @@ -2488,9 +2327,16 @@ fn cursor_sessions_for_output<'a>( .active_space(output) .into_iter() .flat_map(|workspace| { + let maybe_fullscreen = workspace.get_fullscreen(); workspace .cursor_sessions() .into_iter() + .chain( + maybe_fullscreen + .map(|w| w.cursor_sessions()) + .into_iter() + .flatten(), + ) .chain(output.cursor_sessions()) }) } diff --git a/src/main.rs b/src/main.rs index ffa37236..7ae05991 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only fn main() { - // libcosmic-yoda enables zbus' `tokio` feature, so zbus 5.14 expects an - // ambient Tokio runtime via Handle::current(). cosmic-comp's loop is not - // async, so hold a runtime guard for the lifetime of run(). - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("failed to build tokio runtime"); - let _guard = runtime.enter(); - if let Err(err) = cosmic_comp::run(Default::default()) { tracing::error!("Error occured in main(): {}", err); std::process::exit(1); diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index f58259bf..4696aa2e 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -254,14 +254,6 @@ impl CosmicMapped { .any(|(w, _)| w.has_surface(surface, surface_type)) } - pub fn surface_offset(&self, surface: &WlSurface) -> Option> { - self.windows().find_map(|(window, window_offset)| { - window - .surface_offset(surface) - .map(|offset| window_offset + offset) - }) - } - /// Give the pointer target under a relative offset into this element. /// /// Returns Target + Offset relative to the target @@ -269,13 +261,10 @@ impl CosmicMapped { &self, relative_pos: Point, surface_type: WindowSurfaceType, - seat: &Seat, ) -> Option<(PointerFocusTarget, Point)> { match &self.element { CosmicMappedInternal::Stack(stack) => stack.focus_under(relative_pos, surface_type), - CosmicMappedInternal::Window(window) => { - window.focus_under(relative_pos, surface_type, Some(seat)) - } + CosmicMappedInternal::Window(window) => window.focus_under(relative_pos, surface_type), _ => unreachable!(), } } diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 058719e3..7d53bfcc 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -61,8 +61,8 @@ use smithay::{ PointerTarget, RelativeMotionEvent, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchTarget, + UpEvent, }, }, output::Output, @@ -79,7 +79,7 @@ use std::{ hash::Hash, sync::{ Arc, LazyLock, Mutex, - atomic::{AtomicBool, AtomicU8, AtomicU32, AtomicUsize, Ordering}, + atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering}, }, }; @@ -114,7 +114,6 @@ pub struct CosmicStackInternal { scroll_to_focus: AtomicBool, previous_keyboard: AtomicUsize, pointer_entered: AtomicU8, - touch_serial: AtomicU32, reenter: AtomicBool, potential_drag: Mutex>, override_alive: AtomicBool, @@ -172,7 +171,6 @@ impl CosmicStack { scroll_to_focus: AtomicBool::new(false), previous_keyboard: AtomicUsize::new(0), pointer_entered: AtomicU8::new(0), - touch_serial: AtomicU32::new(0), reenter: AtomicBool::new(false), potential_drag: Mutex::new(None), override_alive: AtomicBool::new(true), @@ -251,10 +249,6 @@ impl CosmicStack { window.set_tiled(false); p.active.fetch_min(windows.len() - 1, Ordering::SeqCst); - p.previous_index - .lock() - .unwrap() - .take_if(|(_, idx)| *idx >= windows.len()); }); self.0 .resize(Size::from((self.active().geometry().size.w, TAB_HEIGHT))); @@ -282,10 +276,6 @@ impl CosmicStack { window.set_tiled(false); p.active.fetch_min(windows.len() - 1, Ordering::SeqCst); - p.previous_index - .lock() - .unwrap() - .take_if(|(_, idx)| *idx >= windows.len()); Some(window) }); @@ -1817,62 +1807,55 @@ impl PointerTarget for CosmicStack { } impl TouchTarget for CosmicStack { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent, seq: Serial) { let mut event = event.clone(); let active_window_geo = self.0.with_program(|p| { p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry() }); event.location -= active_window_geo.loc.to_f64(); - self.0 - .with_program(|p| p.touch_serial.store(event.serial.into(), Ordering::Release)); - TouchTarget::down(&self.0, seat, data, &event) + TouchTarget::down(&self.0, seat, data, &event, seq) } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { - TouchTarget::up(&self.0, seat, data, event) + fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent, seq: Serial) { + TouchTarget::up(&self.0, seat, data, event, seq) } - fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent) { + fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent, seq: Serial) { let mut event = event.clone(); let active_window_geo = self.0.with_program(|p| { p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry() }); event.location -= active_window_geo.loc.to_f64(); - TouchTarget::motion(&self.0, seat, data, &event); + TouchTarget::motion(&self.0, seat, data, &event, seq); if event.location.y < 0.0 || event.location.y > TAB_HEIGHT as f64 || event.location.x < 64.0 || event.location.x > (active_window_geo.size.w as f64 - 64.0) { - self.start_drag( - data, - seat, - self.0 - .with_program(|p| p.touch_serial.load(Ordering::Acquire)) - .into(), - ); + self.start_drag(data, seat, seq); } } - fn frame(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { - TouchTarget::frame(&self.0, seat, data, frame) + fn frame(&self, seat: &Seat, data: &mut State, seq: Serial) { + TouchTarget::frame(&self.0, seat, data, seq) } - fn cancel(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { - TouchTarget::cancel(&self.0, seat, data, frame) + fn cancel(&self, seat: &Seat, data: &mut State, seq: Serial) { + TouchTarget::cancel(&self.0, seat, data, seq) } - fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent) { - TouchTarget::shape(&self.0, seat, data, event) + fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent, seq: Serial) { + TouchTarget::shape(&self.0, seat, data, event, seq) } - fn orientation(&self, seat: &Seat, data: &mut State, event: &OrientationEvent) { - TouchTarget::orientation(&self.0, seat, data, event) - } - - fn last_frame(&self, seat: &Seat, data: &mut State) -> Option { - TouchTarget::last_frame(&self.0, seat, data) + fn orientation( + &self, + _seat: &Seat, + _data: &mut State, + _event: &OrientationEvent, + _seq: Serial, + ) { } } diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 8495fe30..1a1e214b 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -45,10 +45,7 @@ use smithay::{ IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, user_data::UserDataMap, }, wayland::{ - compositor::{ - SubsurfaceCachedState, SurfaceData, TraversalAction, get_parent, with_states, - with_surface_tree_downward, - }, + compositor::{SurfaceData, TraversalAction, with_states, with_surface_tree_downward}, seat::WaylandFocus, shell::xdg::{ SurfaceCachedState, ToplevelCachedState, ToplevelSurface, XdgToplevelSurfaceData, @@ -238,8 +235,7 @@ impl CosmicSurface { toplevel.with_pending_state(|state| state.size = Some(geo.size.as_logical())) } WindowSurface::X11(surface) => { - let _ = - surface.configure_with_sync(geo.as_logical() + surface.frame_extents(), None); + let _ = surface.configure_with_sync(geo.as_logical(), None); } } } @@ -346,7 +342,7 @@ impl CosmicSurface { state.is_some_and(|state| state.states.contains(ToplevelState::Resizing)) })) } - WindowSurface::X11(surface) => surface.pending_configure().map(|_| true), + WindowSurface::X11(surface) => surface.pending_geometry().map(|_| true), } } @@ -592,7 +588,7 @@ impl CosmicSurface { } }) } - WindowSurface::X11(surface) => surface.pending_configure().is_none(), + WindowSurface::X11(surface) => surface.pending_geometry().is_none(), } } @@ -656,54 +652,6 @@ impl CosmicSurface { } } - pub fn surface_offset(&self, surface: &WlSurface) -> Option> { - match self.0.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - Self::surface_tree_offset(toplevel.wl_surface(), surface) - } - WindowSurface::X11(surface_x11) => { - if surface_x11.wl_surface().as_ref() == Some(surface) { - Some(Point::default()) - } else { - None - } - } - } - } - - pub fn surface_tree_offset( - root: &WlSurface, - surface: &WlSurface, - ) -> Option> { - let mut offset = Point::::default(); - let mut parent = surface.clone(); - loop { - if parent == *root { - return Some(offset); - } else if let Some(s) = get_parent(&parent) { - offset += with_states(&parent, |states| { - states - .cached_state - .get::() - .current() - .location - }); - parent = s; - } else { - // `parent` is now root of subsurface tree; `surface` is not a subsurface child of `root` - break; - } - } - - for (popup, popup_offset) in PopupManager::popups_for_surface(root) { - if let Some(offset) = Self::surface_tree_offset(popup.wl_surface(), surface) { - return Some(popup_offset + offset); - } - } - - None - } - pub fn focus_under( &self, relative_pos: Point, diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index ea20bb6a..562f6988 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -47,8 +47,8 @@ use smithay::{ GestureSwipeUpdateEvent, MotionEvent, PointerTarget, RelativeMotionEvent, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchTarget, + UpEvent, }, }, output::Output, @@ -57,7 +57,7 @@ use smithay::{ Buffer, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform, user_data::UserDataMap, }, - wayland::{pointer_constraints::with_pointer_constraint, seat::WaylandFocus}, + wayland::seat::WaylandFocus, }; use std::{ borrow::Cow, @@ -274,25 +274,12 @@ impl CosmicWindow { &self, mut relative_pos: Point, surface_type: WindowSurfaceType, - seat: Option<&Seat>, ) -> Option<(PointerFocusTarget, Point)> { - let has_constraint = if let Some(seat) = seat - && let Some(pointer) = seat.get_pointer() - && let Some(surface) = self.wl_surface() - && with_pointer_constraint(&surface, &pointer, |constraint| { - constraint.is_some_and(|c| c.is_active()) - }) { - true - } else { - false - }; - self.0.with_program(|p| { let mut offset = Point::from((0., 0.)); let mut window_ui = None; let has_ssd = p.has_ssd(false); - - if (!has_constraint && (has_ssd || p.has_tiled_state())) + if (has_ssd || p.has_tiled_state()) && surface_type.contains(WindowSurfaceType::TOPLEVEL) { let geo = p.window.geometry(); @@ -890,8 +877,7 @@ impl SpaceElement for CosmicWindow { }) } fn is_in_input_region(&self, point: &Point) -> bool { - self.focus_under(*point, WindowSurfaceType::ALL, None) - .is_some() + self.focus_under(*point, WindowSurfaceType::ALL).is_some() } fn set_activate(&self, activated: bool) { if self @@ -1190,42 +1176,43 @@ impl PointerTarget for CosmicWindow { } impl TouchTarget for CosmicWindow { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent, seq: Serial) { let mut event = event.clone(); self.0.with_program(|p| { event.location -= p.window.geometry().loc.to_f64(); }); - TouchTarget::down(&self.0, seat, data, &event) + TouchTarget::down(&self.0, seat, data, &event, seq) } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { - TouchTarget::up(&self.0, seat, data, event) + fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent, seq: Serial) { + TouchTarget::up(&self.0, seat, data, event, seq) } - fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent) { + fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent, seq: Serial) { let mut event = event.clone(); event.location -= self.0.with_program(|p| p.window.geometry().loc.to_f64()); - TouchTarget::motion(&self.0, seat, data, &event) + TouchTarget::motion(&self.0, seat, data, &event, seq) } - fn frame(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { - TouchTarget::frame(&self.0, seat, data, frame) + fn frame(&self, seat: &Seat, data: &mut State, seq: Serial) { + TouchTarget::frame(&self.0, seat, data, seq) } - fn cancel(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { - TouchTarget::cancel(&self.0, seat, data, frame) + fn cancel(&self, seat: &Seat, data: &mut State, seq: Serial) { + TouchTarget::cancel(&self.0, seat, data, seq) } - fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent) { - TouchTarget::shape(&self.0, seat, data, event) + fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent, seq: Serial) { + TouchTarget::shape(&self.0, seat, data, event, seq) } - fn orientation(&self, seat: &Seat, data: &mut State, event: &OrientationEvent) { - TouchTarget::orientation(&self.0, seat, data, event) - } - - fn last_frame(&self, seat: &Seat, data: &mut State) -> Option { - TouchTarget::last_frame(&self.0, seat, data) + fn orientation( + &self, + _seat: &Seat, + _data: &mut State, + _event: &OrientationEvent, + _seq: Serial, + ) { } } diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index 9374230a..58301072 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -1,6 +1,6 @@ use crate::{ shell::{CosmicSurface, MinimizedWindow, Shell, Trigger, element::CosmicMapped}, - state::{Common, State}, + state::Common, utils::prelude::*, wayland::handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData}, }; @@ -12,7 +12,6 @@ use smithay::{ reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, utils::{IsAlive, Point, SERIAL_COUNTER, Serial}, wayland::{ - pointer_constraints::with_pointer_constraint, seat::WaylandFocus, selection::{data_device::set_data_device_focus, primary_selection::set_primary_focus}, shell::wlr_layer::{KeyboardInteractivity, Layer}, @@ -288,18 +287,22 @@ impl Shell { } let workspace = &mut set.workspaces[set.active]; - for fs in workspace.get_fullscreen_surfaces() { - let is_focused = self.seats.iter().any(|seat| { + if let Some(fullscreen) = workspace.get_fullscreen() { + if self.seats.iter().any(|seat| { if let Some(KeyboardFocusTarget::Fullscreen(s)) = seat.get_keyboard().unwrap().current_focus() { - s == fs.surface + &s == fullscreen } else { false } - }); - fs.surface.set_activated(is_focused); - fs.surface.send_configure(); + }) { + fullscreen.set_activated(true); + fullscreen.send_configure(); + } else { + fullscreen.set_activated(false); + fullscreen.send_configure(); + } } for focused in focused_windows.iter() { raise_with_children(&mut workspace.floating_layer, focused); @@ -344,20 +347,6 @@ fn update_focus_state( ) { // update keyboard focus if let Some(keyboard) = seat.get_keyboard() { - // remove constraint when target changed - let old_focus = keyboard.current_focus(); - if let Some(old_target) = old_focus - && target != Some(&old_target) - && let Some(surface) = old_target.wl_surface() - && let Some(pointer) = seat.get_pointer() - { - with_pointer_constraint(&surface, &pointer, |constraint| { - if let Some(constraint) = constraint { - constraint.deactivate(); - } - }); - } - if should_update_cursor && state.common.config.cosmic_conf.cursor_follows_focus && target.is_some() @@ -657,9 +646,7 @@ fn focus_target_is_valid( .has_node(&node), KeyboardFocusTarget::Fullscreen(window) => { let workspace = shell.active_space(output).unwrap(); - workspace - .get_fullscreen_surfaces() - .any(|f| f.surface == window) + workspace.get_fullscreen().is_some_and(|w| w == &window) } KeyboardFocusTarget::Popup(_) => true, KeyboardFocusTarget::LockSurface(_) => false, @@ -712,9 +699,9 @@ fn update_focus_target( .map(KeyboardFocusTarget::Element) .or_else(|| { workspace - .get_fullscreen(seat) + .get_fullscreen() .cloned() - .map(|fs| KeyboardFocusTarget::Fullscreen(fs.surface)) + .map(KeyboardFocusTarget::Fullscreen) }) }) } diff --git a/src/shell/focus/order.rs b/src/shell/focus/order.rs index d02b310e..6a2488fe 100644 --- a/src/shell/focus/order.rs +++ b/src/shell/focus/order.rs @@ -112,8 +112,8 @@ fn render_input_order_internal( let output_size = output.geometry().size; // this is more hacky than I would like.. + let fullscreen = workspace.fullscreen.as_ref().filter(|f| !f.is_animating()); let seat = shell.seats.last_active(); - let fullscreen = workspace.get_fullscreen(seat); let is_active_workspace = seat.focused_output().is_some_and(|output| { shell .active_space(&output) @@ -144,7 +144,7 @@ fn render_input_order_internal( let Some(workspace) = shell.workspaces.space_for_handle(previous) else { return ControlFlow::Break(Err(OutputNoMode)); }; - let has_fullscreen = workspace.get_fullscreen(seat).is_some(); + let has_fullscreen = workspace.fullscreen.is_some(); let (forward, percentage) = match start { WorkspaceDelta::Shortcut(st) => ( @@ -220,18 +220,20 @@ fn render_input_order_internal( .rev() .filter(|or| { (*or) - .last_configure() + .geometry() .as_global() .intersection(output.geometry()) .is_some() }) - .map(|or| (or, or.last_configure().loc.as_global())) + .map(|or| (or, or.geometry().loc.as_global())) { callback(Stage::OverrideRedirect { surface, location })?; } // sticky window popups - callback(Stage::StickyPopups(&set.sticky_layer))?; + if !has_focused_fullscreen { + callback(Stage::StickyPopups(&set.sticky_layer))?; + } } if element_filter != ElementFilter::LayerShellOnly { @@ -311,11 +313,11 @@ fn render_input_order_internal( for (layer, location) in layer_surfaces(output, Layer::Top, element_filter) { callback(Stage::LayerSurface { layer, location })?; } - } - // sticky windows - if element_filter != ElementFilter::LayerShellOnly { - callback(Stage::Sticky(&set.sticky_layer))?; + // sticky windows + if element_filter != ElementFilter::LayerShellOnly { + callback(Stage::Sticky(&set.sticky_layer))?; + } } if element_filter != ElementFilter::LayerShellOnly { diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index fff77282..b177f00f 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -29,18 +29,15 @@ use smithay::{ MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchTarget, + UpEvent, }, }, reexports::wayland_server::{ Client, DisplayHandle, Resource, backend::ObjectId, protocol::wl_surface::WlSurface, }, utils::{IsAlive, Logical, Point, Serial, Transform}, - wayland::{ - compositor::with_states, seat::WaylandFocus, selection::data_device::WlOfferData, - session_lock::LockSurface, shell::xdg::SurfaceCachedState, - }, + wayland::{seat::WaylandFocus, selection::data_device::WlOfferData, session_lock::LockSurface}, xwayland::{ X11Surface, xwm::{XwmId, XwmOfferData}, @@ -228,63 +225,6 @@ impl PointerFocusTarget { _ => false, } } - - // Update image copy cursor position/hotspot for enter/motion event - fn update_image_copy_cursor_position( - &self, - seat: &Seat, - data: &mut State, - event: &PointerMotionEvent, - ) { - let Some(toplevel) = self.toplevel(&data.common.shell.read()) else { - return; - }; - let cursor_sessions = toplevel.cursor_sessions(); - if cursor_sessions.is_empty() { - return; - } - - let cursor_pos = if let Some(wl_surface) = self.wl_surface() { - let surface_offset = toplevel - .surface_offset(&wl_surface) - .unwrap_or(Point::from((0, 0))) - .to_f64(); - let geometry_loc = toplevel - .wl_surface() - .and_then(|s| { - with_states(&s, |states| { - states - .cached_state - .get::() - .current() - .geometry - .map(|g| g.loc.to_f64()) - }) - }) - .unwrap_or_default(); - Some( - (event.location - geometry_loc + surface_offset) - .to_buffer(1.0, Transform::Normal, &toplevel.geometry().size.to_f64()) - .to_i32_round(), - ) - } else { - // If cursor is in SSD, instead of a `wl_surface`, it is outside the captured bounds - None - }; - - let cursor_hotspot = if let Some((_, hotspot)) = - seat.cursor_geometry((0.0, 0.0), Duration::from_millis(event.time as u64).into()) - { - hotspot - } else { - Point::from((0, 0)) - }; - - for session in cursor_sessions { - session.set_cursor_pos(cursor_pos); - session.set_cursor_hotspot(cursor_hotspot); - } - } } impl KeyboardFocusTarget { @@ -341,18 +281,6 @@ impl KeyboardFocusTarget { false } } - - pub fn has_surface(&self, shell: &Shell, surface: &WlSurface) -> bool { - if let Some(fe) = shell.focused_element(self) { - fe.has_surface(surface, WindowSurfaceType::ALL) - } else if let KeyboardFocusTarget::Fullscreen(s) = self { - s.has_surface(surface, WindowSurfaceType::ALL) - } else if let Some(root) = WaylandFocus::wl_surface(self) { - CosmicSurface::surface_tree_offset(&root, surface).is_some() - } else { - false - } - } } #[derive(Debug, Clone)] @@ -397,11 +325,47 @@ impl IsAlive for KeyboardFocusTarget { impl PointerTarget for PointerFocusTarget { fn enter(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { - self.update_image_copy_cursor_position(seat, data, event); + let toplevel = self.toplevel(&data.common.shell.read()); + if let Some(element) = toplevel { + for session in element.cursor_sessions() { + session.set_cursor_pos(Some( + event + .location + .to_buffer(1.0, Transform::Normal, &element.geometry().size.to_f64()) + .to_i32_round(), + )); + if let Some((_, hotspot)) = seat + .cursor_geometry((0.0, 0.0), Duration::from_millis(event.time as u64).into()) + { + session.set_cursor_hotspot(hotspot); + } else { + session.set_cursor_hotspot((0, 0)); + } + } + } + self.inner_pointer_target().enter(seat, data, event); } fn motion(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { - self.update_image_copy_cursor_position(seat, data, event); + let toplevel = self.toplevel(&data.common.shell.read()); + if let Some(element) = toplevel { + for session in element.cursor_sessions() { + session.set_cursor_pos(Some( + event + .location + .to_buffer(1.0, Transform::Normal, &element.geometry().size.to_f64()) + .to_i32_round(), + )); + if let Some((_, hotspot)) = seat + .cursor_geometry((0.0, 0.0), Duration::from_millis(event.time as u64).into()) + { + session.set_cursor_hotspot(hotspot); + } else { + session.set_cursor_hotspot((0, 0)); + } + } + } + self.inner_pointer_target().motion(seat, data, event); } fn relative_motion(&self, seat: &Seat, data: &mut State, event: &RelativeMotionEvent) { @@ -498,36 +462,39 @@ impl PointerTarget for PointerFocusTarget { } impl TouchTarget for PointerFocusTarget { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { - self.inner_touch_target().down(seat, data, event); + fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent, seq: Serial) { + self.inner_touch_target().down(seat, data, event, seq); } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { - self.inner_touch_target().up(seat, data, event); + fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent, seq: Serial) { + self.inner_touch_target().up(seat, data, event, seq); } - fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent) { - self.inner_touch_target().motion(seat, data, event); + fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent, seq: Serial) { + self.inner_touch_target().motion(seat, data, event, seq); } - fn frame(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { - self.inner_touch_target().frame(seat, data, frame); + fn frame(&self, seat: &Seat, data: &mut State, seq: Serial) { + self.inner_touch_target().frame(seat, data, seq); } - fn cancel(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { - self.inner_touch_target().cancel(seat, data, frame); + fn cancel(&self, seat: &Seat, data: &mut State, seq: Serial) { + self.inner_touch_target().cancel(seat, data, seq); } - fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent) { - self.inner_touch_target().shape(seat, data, event); + fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent, seq: Serial) { + self.inner_touch_target().shape(seat, data, event, seq); } - fn orientation(&self, seat: &Seat, data: &mut State, event: &OrientationEvent) { - self.inner_touch_target().orientation(seat, data, event); - } - - fn last_frame(&self, seat: &Seat, data: &mut State) -> Option { - self.inner_touch_target().last_frame(seat, data) + fn orientation( + &self, + seat: &Seat, + data: &mut State, + event: &OrientationEvent, + seq: Serial, + ) { + self.inner_touch_target() + .orientation(seat, data, event, seq); } } diff --git a/src/shell/grabs/delay.rs b/src/shell/grabs/delay.rs index 96d33dc6..dbf98d91 100644 --- a/src/shell/grabs/delay.rs +++ b/src/shell/grabs/delay.rs @@ -202,12 +202,19 @@ impl> TouchGrab for DelayGrab { handle: &mut TouchInnerHandle<'_, State>, focus: Option<(::TouchFocus, Point)>, event: &DownEvent, + seq: Serial, ) { - handle.down(data, focus, event); + handle.down(data, focus, event, seq); } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { - handle.up(data, event); + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { + handle.up(data, event, seq); if event.slot == TouchGrab::start_data(self).slot { handle.unset_grab(self, data); @@ -220,8 +227,9 @@ impl> TouchGrab for DelayGrab { handle: &mut TouchInnerHandle<'_, State>, focus: Option<(::TouchFocus, Point)>, event: &TouchMotionEvent, + seq: Serial, ) { - handle.motion(data, focus, event); + handle.motion(data, focus, event, seq); let distance = self.start_data.distance(event.location); if distance >= 1. @@ -237,12 +245,12 @@ impl> TouchGrab for DelayGrab { } } - fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { - handle.frame(data) + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.frame(data, seq) } - fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { - handle.cancel(data); + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.cancel(data, seq); handle.unset_grab(self, data); } @@ -251,8 +259,9 @@ impl> TouchGrab for DelayGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &ShapeEvent, + seq: Serial, ) { - handle.shape(data, event) + handle.shape(data, event, seq) } fn orientation( @@ -260,8 +269,9 @@ impl> TouchGrab for DelayGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &OrientationEvent, + seq: Serial, ) { - handle.orientation(data, event); + handle.orientation(data, event, seq); } fn start_data(&self) -> &TouchGrabStartData { diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index 671e004a..ed00821b 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -720,6 +720,7 @@ impl TouchGrab for MenuGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &DownEvent, + seq: Serial, ) { { let mut guard = self.elements.lock().unwrap(); @@ -754,15 +755,21 @@ impl TouchGrab for MenuGrab { time: event.time, }; if element.touch_entered.is_none() { - TouchTarget::down(&element.iced, &self.seat, data, &new_event); + TouchTarget::down(&element.iced, &self.seat, data, &new_event, seq); element.touch_entered = Some(event.slot); } } } - handle.down(data, None, event); + handle.down(data, None, event, seq); } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { { let elements = self.elements.lock().unwrap(); for element in elements.iter().filter(|elem| { @@ -770,7 +777,7 @@ impl TouchGrab for MenuGrab { .as_ref() .is_some_and(|slot| *slot == event.slot) }) { - TouchTarget::up(&element.iced, &self.seat, data, event); + TouchTarget::up(&element.iced, &self.seat, data, event, seq); } } handle.unset_grab(self, data); @@ -782,6 +789,7 @@ impl TouchGrab for MenuGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &TouchMotionEvent, + seq: Serial, ) { { let elements = self.elements.lock().unwrap(); @@ -790,24 +798,24 @@ impl TouchGrab for MenuGrab { .as_ref() .is_some_and(|slot| *slot == event.slot) }) { - TouchTarget::motion(&element.iced, &self.seat, data, event); + TouchTarget::motion(&element.iced, &self.seat, data, event, seq); } } - handle.motion(data, None, event); + handle.motion(data, None, event, seq); } - fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { - handle.frame(data); + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.frame(data, seq); } - fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { { let mut elements = self.elements.lock().unwrap(); for element in elements.iter_mut() { let _ = element.touch_entered.take(); } } - handle.cancel(data); + handle.cancel(data, seq); } fn shape( @@ -815,8 +823,9 @@ impl TouchGrab for MenuGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &smithay::input::touch::ShapeEvent, + seq: Serial, ) { - handle.shape(data, event); + handle.shape(data, event, seq); } fn orientation( @@ -824,8 +833,9 @@ impl TouchGrab for MenuGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &smithay::input::touch::OrientationEvent, + seq: Serial, ) { - handle.orientation(data, event); + handle.orientation(data, event, seq); } fn start_data(&self) -> &TouchGrabStartData { diff --git a/src/shell/grabs/mod.rs b/src/shell/grabs/mod.rs index 515916fd..0c5448c1 100644 --- a/src/shell/grabs/mod.rs +++ b/src/shell/grabs/mod.rs @@ -387,17 +387,24 @@ impl TouchGrab for ResizeGrab { handle: &mut TouchInnerHandle<'_, State>, focus: Option<(PointerFocusTarget, Point)>, event: &DownEvent, + seq: Serial, ) { match self { - ResizeGrab::Floating(grab) => TouchGrab::down(grab, data, handle, focus, event), - ResizeGrab::Tiling(grab) => TouchGrab::down(grab, data, handle, focus, event), + ResizeGrab::Floating(grab) => TouchGrab::down(grab, data, handle, focus, event, seq), + ResizeGrab::Tiling(grab) => TouchGrab::down(grab, data, handle, focus, event, seq), } } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { match self { - ResizeGrab::Floating(grab) => TouchGrab::up(grab, data, handle, event), - ResizeGrab::Tiling(grab) => TouchGrab::up(grab, data, handle, event), + ResizeGrab::Floating(grab) => TouchGrab::up(grab, data, handle, event, seq), + ResizeGrab::Tiling(grab) => TouchGrab::up(grab, data, handle, event, seq), } } @@ -407,24 +414,25 @@ impl TouchGrab for ResizeGrab { handle: &mut TouchInnerHandle<'_, State>, focus: Option<(PointerFocusTarget, Point)>, event: &TouchMotionEvent, + seq: Serial, ) { match self { - ResizeGrab::Floating(grab) => TouchGrab::motion(grab, data, handle, focus, event), - ResizeGrab::Tiling(grab) => TouchGrab::motion(grab, data, handle, focus, event), + ResizeGrab::Floating(grab) => TouchGrab::motion(grab, data, handle, focus, event, seq), + ResizeGrab::Tiling(grab) => TouchGrab::motion(grab, data, handle, focus, event, seq), } } - fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { match self { - ResizeGrab::Floating(grab) => TouchGrab::frame(grab, data, handle), - ResizeGrab::Tiling(grab) => TouchGrab::frame(grab, data, handle), + ResizeGrab::Floating(grab) => TouchGrab::frame(grab, data, handle, seq), + ResizeGrab::Tiling(grab) => TouchGrab::frame(grab, data, handle, seq), } } - fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { match self { - ResizeGrab::Floating(grab) => TouchGrab::cancel(grab, data, handle), - ResizeGrab::Tiling(grab) => TouchGrab::cancel(grab, data, handle), + ResizeGrab::Floating(grab) => TouchGrab::cancel(grab, data, handle, seq), + ResizeGrab::Tiling(grab) => TouchGrab::cancel(grab, data, handle, seq), } } @@ -433,10 +441,11 @@ impl TouchGrab for ResizeGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &ShapeEvent, + seq: Serial, ) { match self { - ResizeGrab::Floating(grab) => TouchGrab::shape(grab, data, handle, event), - ResizeGrab::Tiling(grab) => TouchGrab::shape(grab, data, handle, event), + ResizeGrab::Floating(grab) => TouchGrab::shape(grab, data, handle, event, seq), + ResizeGrab::Tiling(grab) => TouchGrab::shape(grab, data, handle, event, seq), } } @@ -445,10 +454,11 @@ impl TouchGrab for ResizeGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &OrientationEvent, + seq: Serial, ) { match self { - ResizeGrab::Floating(grab) => TouchGrab::orientation(grab, data, handle, event), - ResizeGrab::Tiling(grab) => TouchGrab::orientation(grab, data, handle, event), + ResizeGrab::Floating(grab) => TouchGrab::orientation(grab, data, handle, event, seq), + ResizeGrab::Tiling(grab) => TouchGrab::orientation(grab, data, handle, event, seq), } } @@ -719,17 +729,24 @@ impl TouchGrab for MoveGrab { handle: &mut TouchInnerHandle<'_, State>, focus: Option<(PointerFocusTarget, Point)>, event: &DownEvent, + seq: Serial, ) { match self { - MoveGrab::Move(grab) => TouchGrab::down(grab, data, handle, focus, event), - MoveGrab::Delayed(grab) => TouchGrab::down(grab, data, handle, focus, event), + MoveGrab::Move(grab) => TouchGrab::down(grab, data, handle, focus, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::down(grab, data, handle, focus, event, seq), } } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { match self { - MoveGrab::Move(grab) => TouchGrab::up(grab, data, handle, event), - MoveGrab::Delayed(grab) => TouchGrab::up(grab, data, handle, event), + MoveGrab::Move(grab) => TouchGrab::up(grab, data, handle, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::up(grab, data, handle, event, seq), } } @@ -739,24 +756,25 @@ impl TouchGrab for MoveGrab { handle: &mut TouchInnerHandle<'_, State>, focus: Option<(PointerFocusTarget, Point)>, event: &TouchMotionEvent, + seq: Serial, ) { match self { - MoveGrab::Move(grab) => TouchGrab::motion(grab, data, handle, focus, event), - MoveGrab::Delayed(grab) => TouchGrab::motion(grab, data, handle, focus, event), + MoveGrab::Move(grab) => TouchGrab::motion(grab, data, handle, focus, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::motion(grab, data, handle, focus, event, seq), } } - fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { match self { - MoveGrab::Move(grab) => TouchGrab::frame(grab, data, handle), - MoveGrab::Delayed(grab) => TouchGrab::frame(grab, data, handle), + MoveGrab::Move(grab) => TouchGrab::frame(grab, data, handle, seq), + MoveGrab::Delayed(grab) => TouchGrab::frame(grab, data, handle, seq), } } - fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { match self { - MoveGrab::Move(grab) => TouchGrab::cancel(grab, data, handle), - MoveGrab::Delayed(grab) => TouchGrab::cancel(grab, data, handle), + MoveGrab::Move(grab) => TouchGrab::cancel(grab, data, handle, seq), + MoveGrab::Delayed(grab) => TouchGrab::cancel(grab, data, handle, seq), } } @@ -765,10 +783,11 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &ShapeEvent, + seq: Serial, ) { match self { - MoveGrab::Move(grab) => TouchGrab::shape(grab, data, handle, event), - MoveGrab::Delayed(grab) => TouchGrab::shape(grab, data, handle, event), + MoveGrab::Move(grab) => TouchGrab::shape(grab, data, handle, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::shape(grab, data, handle, event, seq), } } @@ -777,10 +796,11 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &OrientationEvent, + seq: Serial, ) { match self { - MoveGrab::Move(grab) => TouchGrab::orientation(grab, data, handle, event), - MoveGrab::Delayed(grab) => TouchGrab::orientation(grab, data, handle, event), + MoveGrab::Move(grab) => TouchGrab::orientation(grab, data, handle, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::orientation(grab, data, handle, event, seq), } } diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index e73b108d..ad5915f9 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -40,7 +40,7 @@ use smithay::{ touch::{self, GrabStartData as TouchGrabStartData, TouchGrab, TouchInnerHandle}, }, output::Output, - utils::{IsAlive, Logical, Point, Rectangle, SERIAL_COUNTER, Scale}, + utils::{IsAlive, Logical, Point, Rectangle, SERIAL_COUNTER, Scale, Serial}, }; use std::{ collections::HashSet, @@ -652,8 +652,9 @@ impl TouchGrab for MoveGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &touch::DownEvent, + seq: Serial, ) { - handle.down(data, None, event) + handle.down(data, None, event, seq) } fn up( @@ -661,12 +662,13 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &touch::UpEvent, + seq: Serial, ) { if event.slot == >::start_data(self).slot { handle.unset_grab(self, data); } - handle.up(data, event); + handle.up(data, event, seq); } fn motion( @@ -675,19 +677,20 @@ impl TouchGrab for MoveGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &touch::MotionEvent, + seq: Serial, ) { if event.slot == >::start_data(self).slot { self.update_location(data, event.location); } - handle.motion(data, None, event); + handle.motion(data, None, event, seq); } - fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { - handle.frame(data) + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.frame(data, seq) } - fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _seq: Serial) { handle.unset_grab(self, data); } @@ -696,8 +699,9 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &touch::ShapeEvent, + seq: Serial, ) { - handle.shape(data, event) + handle.shape(data, event, seq) } fn orientation( @@ -705,8 +709,9 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &touch::OrientationEvent, + seq: Serial, ) { - handle.orientation(data, event) + handle.orientation(data, event, seq) } fn start_data(&self) -> &TouchGrabStartData { @@ -948,7 +953,6 @@ impl Drop for MoveGrab { if let Some((target, offset)) = mapped.focus_under( current_location - position.as_logical().to_f64(), WindowSurfaceType::ALL, - &seat, ) { pointer.motion( state, diff --git a/src/shell/layout/floating/grabs/resize.rs b/src/shell/layout/floating/grabs/resize.rs index f9e5cbfd..04363207 100644 --- a/src/shell/layout/floating/grabs/resize.rs +++ b/src/shell/layout/floating/grabs/resize.rs @@ -29,7 +29,7 @@ use smithay::{ }, }, output::Output, - utils::{IsAlive, Logical, Point, Rectangle, Size}, + utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, }; use tracing::debug; @@ -330,16 +330,23 @@ impl TouchGrab for ResizeSurfaceGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &DownEvent, + seq: Serial, ) { - handle.down(data, None, event) + handle.down(data, None, event, seq) } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { if event.slot == >::start_data(self).slot { handle.unset_grab(self, data); } - handle.up(data, event); + handle.up(data, event, seq); } fn motion( @@ -348,6 +355,7 @@ impl TouchGrab for ResizeSurfaceGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &TouchMotionEvent, + seq: Serial, ) { if event.slot == >::start_data(self).slot && self.update_location(event.location.as_global()) @@ -355,14 +363,14 @@ impl TouchGrab for ResizeSurfaceGrab { handle.unset_grab(self, data); } - handle.motion(data, None, event); + handle.motion(data, None, event, seq); } - fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { - handle.frame(data) + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.frame(data, seq) } - fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _seq: Serial) { handle.unset_grab(self, data); } @@ -371,8 +379,9 @@ impl TouchGrab for ResizeSurfaceGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &ShapeEvent, + seq: Serial, ) { - handle.shape(data, event) + handle.shape(data, event, seq) } fn orientation( @@ -380,8 +389,9 @@ impl TouchGrab for ResizeSurfaceGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &OrientationEvent, + seq: Serial, ) { - handle.orientation(data, event) + handle.orientation(data, event, seq) } fn start_data(&self) -> &TouchGrabStartData { @@ -533,7 +543,7 @@ impl ResizeSurfaceGrab { ); } WindowSurface::X11(surface) => { - let mut geometry = surface.last_configure(); + let mut geometry = surface.geometry(); geometry.loc += (location - new_location).as_logical(); let _ = surface.configure(geometry); } diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index e3829e58..e399f356 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -295,7 +295,6 @@ impl FloatingLayout { for mapped in self .space .elements() - .filter(|w| w.alive()) .cloned() .collect::>() .into_iter() @@ -310,10 +309,7 @@ impl FloatingLayout { None, ); } else { - let Some(geometry) = self.space.element_geometry(&mapped) else { - continue; - }; - let geometry = geometry.to_f64(); + let geometry = self.space.element_geometry(&mapped).unwrap().to_f64(); let new_loc = ( ((geometry.loc.x - old_output_geometry.loc.x).max(0.) / old_output_geometry.size.w @@ -623,10 +619,6 @@ impl FloatingLayout { from: Rectangle, position: Point, ) { - if !mapped.alive() { - return; - } - let output = self.space.outputs().next().unwrap().clone(); let layers = layer_map_for_output(&output); let geometry = layers.non_exclusive_zone().as_local(); @@ -739,11 +731,7 @@ impl FloatingLayout { self.space.element_geometry(elem).map(RectExt::as_local) } - pub fn popup_element_under( - &self, - location: Point, - seat: &Seat, - ) -> Option { + pub fn popup_element_under(&self, location: Point) -> Option { self.space .elements() .rev() @@ -764,7 +752,6 @@ impl FloatingLayout { if e.focus_under( point.as_logical(), WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE, - seat, ) .is_some() { @@ -778,7 +765,6 @@ impl FloatingLayout { pub fn toplevel_element_under( &self, location: Point, - seat: &Seat, ) -> Option { self.space .elements() @@ -800,7 +786,6 @@ impl FloatingLayout { if e.focus_under( point.as_logical(), WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE, - seat, ) .is_some() { @@ -814,7 +799,6 @@ impl FloatingLayout { pub fn popup_surface_under( &self, location: Point, - seat: &Seat, ) -> Option<(PointerFocusTarget, Point)> { self.space .elements() @@ -836,7 +820,6 @@ impl FloatingLayout { e.focus_under( point.as_logical(), WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE, - seat, ) .map(|(surface, surface_offset)| { (surface, render_location + surface_offset.as_local()) @@ -847,7 +830,6 @@ impl FloatingLayout { pub fn toplevel_surface_under( &self, location: Point, - seat: &Seat, ) -> Option<(PointerFocusTarget, Point)> { self.space .elements() @@ -869,7 +851,6 @@ impl FloatingLayout { e.focus_under( point.as_logical(), WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE, - seat, ) .map(|(surface, surface_offset)| { (surface, render_location + surface_offset.as_local()) diff --git a/src/shell/layout/mod.rs b/src/shell/layout/mod.rs index 987f2f90..a2475411 100644 --- a/src/shell/layout/mod.rs +++ b/src/shell/layout/mod.rs @@ -32,7 +32,7 @@ pub fn is_dialog(window: &CosmicSurface) -> bool { } WindowSurface::X11(surface) => { if surface.is_override_redirect() - || surface.is_modal() + || surface.is_popup() || !matches!( surface.window_type(), None | Some(WmWindowType::Normal) | Some(WmWindowType::Utility) diff --git a/src/shell/layout/tiling/grabs/resize.rs b/src/shell/layout/tiling/grabs/resize.rs index 9b135119..51d5c9a2 100644 --- a/src/shell/layout/tiling/grabs/resize.rs +++ b/src/shell/layout/tiling/grabs/resize.rs @@ -22,13 +22,12 @@ use smithay::{ PointerTarget, RelativeMotionEvent, }, touch::{ - DownEvent, FrameMarker, GrabStartData as TouchGrabStartData, - MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab, - TouchInnerHandle, TouchTarget, UpEvent, + DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, + OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, TouchTarget, UpEvent, }, }, output::WeakOutput, - utils::{IsAlive, Logical, Point}, + utils::{IsAlive, Logical, Point, Serial}, }; use super::super::{Data, TilingLayout}; @@ -127,7 +126,7 @@ impl PointerTarget for ResizeForkTarget { } impl TouchTarget for ResizeForkTarget { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent, _seq: Serial) { let seat = seat.clone(); let node = self.node.clone(); let output = self.output.clone(); @@ -158,14 +157,25 @@ impl TouchTarget for ResizeForkTarget { }); } - fn up(&self, _seat: &Seat, _data: &mut State, _event: &UpEvent) {} - fn motion(&self, _seat: &Seat, _data: &mut State, _event: &TouchMotionEvent) {} - fn frame(&self, _seat: &Seat, _data: &mut State, _frame: FrameMarker) {} - fn cancel(&self, _seat: &Seat, _data: &mut State, _frame: FrameMarker) {} - fn shape(&self, _seat: &Seat, _data: &mut State, _event: &ShapeEvent) {} - fn orientation(&self, _seat: &Seat, _data: &mut State, _event: &OrientationEvent) {} - fn last_frame(&self, _seat: &Seat, _data: &mut State) -> Option { - None + fn up(&self, _seat: &Seat, _data: &mut State, _event: &UpEvent, _seq: Serial) {} + fn motion( + &self, + _seat: &Seat, + _data: &mut State, + _event: &TouchMotionEvent, + _seq: Serial, + ) { + } + fn frame(&self, _seat: &Seat, _data: &mut State, _seq: Serial) {} + fn cancel(&self, _seat: &Seat, _data: &mut State, _seq: Serial) {} + fn shape(&self, _seat: &Seat, _data: &mut State, _event: &ShapeEvent, _seq: Serial) {} + fn orientation( + &self, + _seat: &Seat, + _data: &mut State, + _event: &OrientationEvent, + _seq: Serial, + ) { } } @@ -498,16 +508,23 @@ impl TouchGrab for ResizeForkGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &DownEvent, + seq: Serial, ) { - handle.down(data, None, event) + handle.down(data, None, event, seq) } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { if event.slot == >::start_data(self).slot { handle.unset_grab(self, data); } - handle.up(data, event); + handle.up(data, event, seq); } fn motion( @@ -516,6 +533,7 @@ impl TouchGrab for ResizeForkGrab { handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, event: &TouchMotionEvent, + seq: Serial, ) { if event.slot == >::start_data(self).slot && self.update_location(data, event.location, false) @@ -523,14 +541,14 @@ impl TouchGrab for ResizeForkGrab { handle.unset_grab(self, data); } - handle.motion(data, None, event); + handle.motion(data, None, event, seq); } - fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { - handle.frame(data) + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.frame(data, seq) } - fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>) { + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _seq: Serial) { handle.unset_grab(self, data); } @@ -539,8 +557,9 @@ impl TouchGrab for ResizeForkGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &ShapeEvent, + seq: Serial, ) { - handle.shape(data, event) + handle.shape(data, event, seq) } fn start_data(&self) -> &TouchGrabStartData { @@ -555,8 +574,9 @@ impl TouchGrab for ResizeForkGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &OrientationEvent, + seq: Serial, ) { - handle.orientation(data, event) + handle.orientation(data, event, seq) } fn unset(&mut self, data: &mut State) { diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index e7a7f0f1..22d592bf 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -3145,7 +3145,6 @@ impl TilingLayout { pub fn popup_element_under( &self, location_f64: Point, - seat: &Seat, ) -> Option { let location = location_f64.to_i32_round(); @@ -3158,7 +3157,6 @@ impl TilingLayout { .focus_under( (location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(), WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE, - seat, ) .is_some() { @@ -3172,7 +3170,6 @@ impl TilingLayout { pub fn toplevel_element_under( &self, location_f64: Point, - seat: &Seat, ) -> Option { let location = location_f64.to_i32_round(); @@ -3185,7 +3182,6 @@ impl TilingLayout { .focus_under( (location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(), WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE, - seat, ) .is_some() { @@ -3200,7 +3196,6 @@ impl TilingLayout { &self, location_f64: Point, overview: OverviewMode, - seat: &Seat, ) -> Option<(PointerFocusTarget, Point)> { let location = location_f64.to_i32_round(); @@ -3215,7 +3210,6 @@ impl TilingLayout { if let Some((target, surface_offset)) = mapped.focus_under( (location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(), WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE, - seat, ) { return Some(( target, @@ -3233,7 +3227,6 @@ impl TilingLayout { &self, location_f64: Point, overview: OverviewMode, - seat: &Seat, ) -> Option<(PointerFocusTarget, Point)> { let tree = &self.queue.trees.back().unwrap().0; let root = tree.root_node_id()?; @@ -3250,7 +3243,6 @@ impl TilingLayout { if let Some((target, surface_offset)) = mapped.focus_under( (location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(), WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE, - seat, ) { return Some(( target, @@ -3301,7 +3293,6 @@ impl TilingLayout { .focus_under( test_point, WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE, - seat, ) .map(|(surface, surface_offset)| { ( diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 89309e88..e1a48567 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -50,13 +50,10 @@ use smithay::{ }, utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, wayland::{ - compositor::{SurfaceAttributes, get_parent, with_states}, + compositor::{SurfaceAttributes, with_states}, seat::WaylandFocus, session_lock::LockSurface, - shell::{ - wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState}, - xdg::{XDG_POPUP_ROLE, XdgPopupSurfaceData}, - }, + shell::wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState}, xdg_activation::XdgActivationState, xwayland_keyboard_grab::XWaylandKeyboardGrab, }, @@ -439,11 +436,6 @@ fn create_workspace_from_pinned( | WorkspaceCapabilities::Pin | WorkspaceCapabilities::Move, ); - - if let Some(ref name) = pinned.name { - state.set_workspace_name(&workspace_handle, name); - } - Workspace::from_pinned( pinned, workspace_handle, @@ -624,7 +616,6 @@ impl WorkspaceSet { state, self.workspaces.len() as u8 + 1, &workspace.handle, - workspace.name.as_deref(), // this method is only used by code paths related to dynamic workspaces, so this should be fine ); self.workspaces.push(workspace); @@ -686,12 +677,7 @@ impl WorkspaceSet { fn update_workspace_idxs(&self, state: &mut WorkspaceUpdateGuard<'_, State>) { for (i, workspace) in self.workspaces.iter().enumerate() { - workspace_set_idx( - state, - i as u8 + 1, - &workspace.handle, - workspace.name.as_deref(), - ); + workspace_set_idx(state, i as u8 + 1, &workspace.handle); } } @@ -742,78 +728,6 @@ impl WorkspaceSet { self.post_remove_workspace(workspace_state, &previous_active_handle); prefers } - - pub fn surface_geometry_offset_from_toplevel( - &self, - surface: &WlSurface, - ) -> Option<(Rectangle, Point)> { - let mut root = surface.clone(); - - while let Some(parent) = get_parent(&root) { - root = parent; - } - - while smithay::wayland::compositor::get_role(&root) == Some(XDG_POPUP_ROLE) { - let parent = with_states(&root, |states| { - states - .data_map - .get::() - .and_then(|m| m.lock().unwrap().parent.as_ref().cloned()) - }); - if let Some(parent) = parent { - root = parent; - } else { - break; - } - } - - self.sticky_layer - .mapped() - .find(|w| { - w.windows() - .any(|(w, _)| w.wl_surface().as_deref() == Some(&root)) - }) - .and_then(|w| { - self.sticky_layer - .element_geometry(w) - .zip(w.surface_offset(surface)) - }) - .or_else(|| { - self.workspaces.iter().find_map(|workspace| { - workspace - .get_fullscreen_surfaces() - .find_map(|fs| { - (fs.surface.wl_surface().as_deref() == Some(&root)) - .then(|| { - fs.surface.surface_offset(surface).map(|offset| { - (workspace.fullscreen_geometry_for(fs), offset) - }) - }) - .flatten() - }) - .or_else(|| { - workspace.mapped().find_map(|w| { - w.windows() - .any(|(w, _)| w.wl_surface().as_deref() == Some(&root)) - .then(|| { - workspace.element_geometry(w).zip(w.surface_offset(surface)) - }) - .flatten() - }) - }) - }) - }) - .or_else(|| { - layer_map_for_output(&self.output).layers().find_map(|l| { - (l.wl_surface() == &root) - .then(|| { - CosmicSurface::surface_tree_offset(l.wl_surface(), surface) - .map(|offset| (l.geometry().as_local(), offset)) - }) - .flatten() - }) - }) - } } #[derive(Debug)] @@ -1588,9 +1502,7 @@ impl Common { self.popups.cleanup(); self.toplevel_info_state.refresh(&self.workspace_state); self.refresh_idle_inhibit(); - if let Some(mut a11y_keyboard_monitor) = self.dbus_state.a11y_keyboard_monitor() { - a11y_keyboard_monitor.refresh(); - } + self.a11y_keyboard_monitor_state.refresh(); self.image_copy_capture_state.cleanup(); } @@ -1650,13 +1562,12 @@ impl Common { if let Some(mapped) = shell.element_for_surface(surface) { mapped.on_commit(surface); } - if let Some(fs) = shell + if let Some(surface) = shell .workspaces .spaces() - .flat_map(|w| w.get_fullscreen_surfaces()) - .find(|f| f.surface == *surface) + .find_map(|w| w.get_fullscreen().filter(|s| *s == surface)) { - fs.surface.on_commit() + surface.on_commit() }; } self.popups.commit(surface); @@ -1917,9 +1828,7 @@ impl Shell { .outputs() .find(|output| { let workspace = self.active_space(output).unwrap(); - workspace - .get_fullscreen_surfaces() - .any(|f| f.surface == elem) + workspace.get_fullscreen() == Some(&elem) }) .cloned(), KeyboardFocusTarget::Group(WindowGroup { node, .. }) => self @@ -2052,8 +1961,8 @@ impl Shell { let workspace = self.active_space(o).unwrap(); workspace - .get_fullscreen_surfaces() - .any(|f| f.surface.has_surface(surface, WindowSurfaceType::ALL)) + .get_fullscreen() + .is_some_and(|s| s.has_surface(surface, WindowSurfaceType::ALL)) || workspace .mapped() .any(|e| e.has_surface(surface, WindowSurfaceType::ALL)) @@ -2108,8 +2017,8 @@ impl Shell { .workspaces .spaces() .find(|w| { - w.get_fullscreen_surfaces() - .any(|f| f.surface.has_surface(surface, WindowSurfaceType::ALL)) + w.get_fullscreen() + .is_some_and(|s| s.has_surface(surface, WindowSurfaceType::ALL)) || w.mapped() .any(|e| e.has_surface(surface, WindowSurfaceType::ALL)) || w.minimized_windows.iter().any(|m| { @@ -2156,7 +2065,7 @@ impl Shell { .mapped() .any(|m| m.windows().any(|(s, _)| &s == surface)) || set.workspaces.iter().any(|w| { - w.get_fullscreen_surfaces().any(|f| &f.surface == surface) + w.get_fullscreen().is_some_and(|s| s == surface) || w.minimized_windows .iter() .any(|m| m.windows().any(|s| &s == surface)) @@ -2845,7 +2754,12 @@ impl Shell { let floating_exception = layout::has_floating_exception(&self.tiling_exceptions, &window); if should_be_fullscreen { - workspace.map_fullscreen(&window, &seat, None, None); + if let Some((surface, state, _)) = workspace.map_fullscreen(&window, &seat, None, None) + { + toplevel_leave_output(&surface, &workspace.output); + toplevel_leave_workspace(&surface, &workspace.handle); + self.remap_unfullscreened_window(surface, state, loop_handle); + } if was_activated { workspace_state.add_workspace_state(&workspace_handle, WState::Urgent); } @@ -3216,12 +3130,9 @@ impl Shell { let from_workspace = self.workspaces.space_for_handle_mut(from).unwrap(); // checked above let is_minimized = window.is_minimized(); - let is_fullscreen = from_workspace - .get_fullscreen_surfaces() - .any(|f| &f.surface == window); + let is_fullscreen = from_workspace.get_fullscreen().is_some_and(|f| f == window); let mut window_state = if is_fullscreen { - let (_, previous_state, previous_geometry) = - from_workspace.take_fullscreen(window).unwrap(); + let (_, previous_state, previous_geometry) = from_workspace.take_fullscreen().unwrap(); WorkspaceRestoreData::Fullscreen(previous_state.zip(previous_geometry).map( |(previous_state, previous_geometry)| FullscreenRestoreData { previous_state, @@ -3377,12 +3288,14 @@ impl Shell { ); mapped.into() } else if let WorkspaceRestoreData::Fullscreen(previous) = window_state { - to_workspace.map_fullscreen( + if let Some((old_surface, previous_state, _)) = to_workspace.map_fullscreen( window, None, previous.clone().map(|p| p.previous_state), previous.map(|p| p.previous_geometry), - ); + ) { + self.remap_unfullscreened_window(old_surface, previous_state, evlh); + } window.clone().into() } else { unreachable!() // TODO: sticky @@ -3600,12 +3513,8 @@ impl Shell { } else if let Some((workspace, output)) = self.workspace_for_surface(surface) { let workspace = self.workspaces.space_for_handle(&workspace).unwrap(); - if let Some(fs) = workspace - .get_fullscreen_surfaces() - .find(|f| &f.surface == surface) - { - let window = &fs.surface; - let global_position = (workspace.fullscreen_geometry_for(fs).loc + if let Some(window) = workspace.get_fullscreen().filter(|s| *s == surface) { + let global_position = (workspace.fullscreen_geometry().unwrap().loc + location.as_local()) .to_global(&output); @@ -3698,14 +3607,10 @@ impl Shell { let maybe_fullscreen_workspace = self .workspaces .spaces_mut() - .find(|w| w.get_fullscreen_surfaces().any(|f| &f.surface == surface)); + .find(|w| w.get_fullscreen().is_some_and(|s| s == surface)); if let Some(workspace) = maybe_fullscreen_workspace { - let fs = workspace - .get_fullscreen_surfaces() - .find(|f| &f.surface == surface) - .unwrap(); - element_geo = Some(workspace.fullscreen_geometry_for(fs)); - let (surface, state, _) = workspace.remove_fullscreen_surface(surface).unwrap(); + element_geo = Some(workspace.fullscreen_geometry().unwrap()); + let (surface, state, _) = workspace.remove_fullscreen().unwrap(); self.remap_unfullscreened_window(surface, state, evlh); }; @@ -3730,11 +3635,7 @@ impl Shell { if old_mapped.is_maximized(false) { new_mapped.set_maximized(false); } - start_data.set_focus(new_mapped.focus_under( - (0., 0.).into(), - WindowSurfaceType::ALL, - seat, - )); + start_data.set_focus(new_mapped.focus_under((0., 0.).into(), WindowSurfaceType::ALL)); new_mapped } else { old_mapped.clone() @@ -3918,15 +3819,19 @@ impl Shell { /// Get the window geometry of a keyboard focus target pub fn focused_geometry(&self, target: &KeyboardFocusTarget) -> Option> { match target { - KeyboardFocusTarget::Fullscreen(surface) => surface - .wl_surface() - .and_then(|s| self.workspace_for_surface(&s)) - .and_then(|(handle, _)| self.workspaces.space_for_handle(&handle)) - .map(|workspace| { + KeyboardFocusTarget::Fullscreen(surface) => { + if let Some(workspace) = surface + .wl_surface() + .and_then(|s| self.workspace_for_surface(&s)) + .and_then(|(handle, _)| self.workspaces.space_for_handle(&handle)) + { workspace - .fullscreen_geometry_for_surface(surface) - .to_global(workspace.output()) - }), + .fullscreen_geometry() + .map(|f| f.to_global(workspace.output())) + } else { + None + } + } _ => { if let Some(element) = self.focused_element(target) { self.element_geometry(&element) @@ -4201,7 +4106,7 @@ impl Shell { let element_offset = (new_loc - geometry.loc).as_logical(); let focus = mapped - .focus_under(element_offset.to_f64(), WindowSurfaceType::ALL, seat) + .focus_under(element_offset.to_f64(), WindowSurfaceType::ALL) .map(|(target, surface_offset)| (target, (surface_offset + element_offset.to_f64()))); start_data.set_location(new_loc.as_logical().to_f64()); start_data.set_focus(focus.clone()); @@ -4278,8 +4183,9 @@ impl Shell { self.workspaces.sets.values_mut().find_map(|set| { set.workspaces.iter_mut().find_map(|workspace| { let window = workspace - .get_fullscreen_surfaces() - .map(|f| f.surface.clone()) + .get_fullscreen() + .cloned() + .into_iter() .chain(workspace.mapped().map(|m| m.active_window())) .find(|s| s == surface); window.map(|s| (workspace, s)) @@ -4779,16 +4685,15 @@ impl Shell { &mut self, surface: &S, output: Output, - _loop_handle: &LoopHandle<'static, State>, + loop_handle: &LoopHandle<'static, State>, ) -> Option where CosmicSurface: PartialEq, { let mapped = self.element_for_surface(surface).cloned()?; - let seat = self.seats.last_active().clone(); let window; - if let Some((old_output, set)) = self + let old_fullscreen = if let Some((old_output, set)) = self .workspaces .sets .iter_mut() @@ -4835,7 +4740,7 @@ impl Shell { let workspace = self.active_space_mut(&output).unwrap(); workspace.map_fullscreen( &window, - &seat, + None, Some(FullscreenRestoreState::Sticky { output: old_output, state: FloatingRestoreData { @@ -4846,7 +4751,7 @@ impl Shell { }, }), Some(from), - ); + ) } else if let Some(workspace) = self.space_for_mut(&mapped) { if mapped.is_minimized() { // TODO: Rewrite the `MinimizedWindow` to restore to fullscreen @@ -4872,7 +4777,7 @@ impl Shell { workspace.map_fullscreen( &window, - &seat, + None, match state { WorkspaceRestoreData::Floating(floating_state) => { floating_state.map(|state| FullscreenRestoreState::Floating { @@ -4889,11 +4794,15 @@ impl Shell { WorkspaceRestoreData::Fullscreen(_) => unreachable!(), }, Some(from), - ); + ) } else { return None; }; + if let Some((old_fullscreen, restore, _)) = old_fullscreen { + self.remap_unfullscreened_window(old_fullscreen, restore, loop_handle); + } + Some(KeyboardFocusTarget::Fullscreen(window)) } @@ -4908,12 +4817,11 @@ impl Shell { let maybe_workspace = self.workspaces.iter_mut().find_map(|(_, s)| { s.workspaces .iter_mut() - .find(|w| w.get_fullscreen_surfaces().any(|f| &f.surface == surface)) + .find(|w| w.get_fullscreen().is_some_and(|f| f == surface)) }); if let Some(workspace) = maybe_workspace { - let (old_fullscreen, restore, _) = - workspace.remove_fullscreen_surface(surface).unwrap(); + let (old_fullscreen, restore, _) = workspace.remove_fullscreen().unwrap(); toplevel_leave_output(&old_fullscreen, &workspace.output); toplevel_leave_workspace(&old_fullscreen, &workspace.handle); @@ -5036,9 +4944,8 @@ fn workspace_set_idx( state: &mut WorkspaceUpdateGuard<'_, State>, idx: u8, handle: &WorkspaceHandle, - name: Option<&str>, ) { - state.set_workspace_name(handle, name.unwrap_or(&format!("{}", idx))); + state.set_workspace_name(handle, format!("{}", idx)); state.set_workspace_coordinates(handle, &[idx as u32]); } diff --git a/src/shell/seats.rs b/src/shell/seats.rs index 5273e97f..a4f14364 100644 --- a/src/shell/seats.rs +++ b/src/shell/seats.rs @@ -17,11 +17,8 @@ use smithay::{ pointer::{CursorImageAttributes, CursorImageStatus}, }, output::Output, - reexports::{ - input::Device as InputDevice, - wayland_server::{DisplayHandle, protocol::wl_surface::WlSurface}, - }, - utils::{Buffer, IsAlive, Logical, Monotonic, Point, Rectangle, Serial, Time, Transform}, + reexports::{input::Device as InputDevice, wayland_server::DisplayHandle}, + utils::{Buffer, IsAlive, Monotonic, Point, Rectangle, Serial, Time, Transform}, wayland::compositor::with_states, }; use tracing::warn; @@ -181,9 +178,6 @@ struct ActiveOutput(pub Mutex); /// The output which currently has keyboard focus struct FocusedOutput(pub Mutex>); -#[derive(Default)] -pub struct PointerConstraintHint(pub Mutex)>>); - #[derive(Default)] pub struct LastModifierChange(pub Mutex>); @@ -207,7 +201,6 @@ pub fn create_seat( userdata.insert_if_missing_threadsafe(CursorState::default); userdata.insert_if_missing_threadsafe(|| ActiveOutput(Mutex::new(output.clone()))); userdata.insert_if_missing_threadsafe(|| FocusedOutput(Mutex::new(None))); - userdata.insert_if_missing_threadsafe(PointerConstraintHint::default); userdata.insert_if_missing_threadsafe(|| Mutex::new(CursorImageStatus::default_named())); // A lot of clients bind keyboard and pointer unconditionally once on launch.. @@ -259,8 +252,6 @@ pub trait SeatExt { fn supressed_buttons(&self) -> &SupressedButtons; fn modifiers_shortcut_queue(&self) -> &ModifiersShortcutQueue; fn last_modifier_change(&self) -> Option; - fn pointer_constraint_hint(&self) -> Option<(WlSurface, Point)>; - fn set_pointer_constraint_hint(&self, hint: Option<(WlSurface, Point)>); fn cursor_geometry( &self, @@ -346,23 +337,6 @@ impl SeatExt for Seat { .unwrap() } - fn pointer_constraint_hint(&self) -> Option<(WlSurface, Point)> { - let lock = self.user_data().get::().unwrap(); - let mut hint = lock.0.lock().unwrap(); - // Check if alive - if let Some((ref surface, _)) = *hint - && !surface.alive() - { - *hint = None; - } - hint.clone() - } - - fn set_pointer_constraint_hint(&self, hint: Option<(WlSurface, Point)>) { - let lock = self.user_data().get::().unwrap(); - *lock.0.lock().unwrap() = hint; - } - fn cursor_geometry( &self, loc: impl Into>, diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 2b4db98c..a79b2acb 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -108,10 +108,9 @@ pub struct Workspace { pub floating_layer: FloatingLayout, pub minimized_windows: Vec, pub tiling_enabled: bool, - pub fullscreen_surfaces: Vec, + pub fullscreen: Option, pub pinned: bool, pub id: Option, - pub name: Option, pub handle: WorkspaceHandle, pub focus_stack: FocusStacks, @@ -384,10 +383,9 @@ impl Workspace { floating_layer, tiling_enabled, minimized_windows: Vec::new(), - fullscreen_surfaces: Vec::new(), + fullscreen: None, pinned: false, id: None, - name: None, handle, focus_stack: FocusStacks::default(), image_copy: ImageCopySessions::default(), @@ -418,10 +416,9 @@ impl Workspace { floating_layer, tiling_enabled: pinned.tiling_enabled, minimized_windows: Vec::new(), - fullscreen_surfaces: Vec::new(), + fullscreen: None, pinned: true, id: pinned.id.clone(), - name: pinned.name.clone(), handle, focus_stack: FocusStacks::default(), image_copy: ImageCopySessions::default(), @@ -439,9 +436,9 @@ impl Workspace { } pub fn to_pinned(&self) -> Option { + debug_assert!(self.id.is_some()); let output = self.explicit_output().clone(); if self.pinned { - debug_assert!(self.id.is_some()); Some(PinnedWorkspace { output: cosmic_comp_config::workspace::OutputMatch { name: output.name, @@ -449,7 +446,6 @@ impl Workspace { }, tiling_enabled: self.tiling_enabled, id: self.id.clone(), - name: self.name.clone(), }) } else { None @@ -458,10 +454,7 @@ impl Workspace { #[profiling::function] pub fn refresh(&mut self) { - // seems it removes dead windows - // self.fullscreen.take_if(|w| !w.alive()); - self.fullscreen_surfaces.retain(|w| w.alive()); - + self.fullscreen.take_if(|w| !w.alive()); self.floating_layer.refresh(); self.tiling_layer.refresh(); } @@ -485,15 +478,14 @@ impl Workspace { self.is_empty() && !self.has_activation_token(xdg_activation_state) && !self.pinned } - /// cleans up any window that is not alive anymore pub fn refresh_focus_stack(&mut self) { for (seat, stack) in self.focus_stack.0.iter_mut() { - let fullscreen_surfaces: Vec<&CosmicSurface> = self - .fullscreen_surfaces - .iter() - .filter(|f| f.alive() && f.ended_at.is_none()) - .map(|f| &f.surface) - .collect(); + let fullscreen = self + .fullscreen + .as_ref() + .filter(|f| f.alive()) + .filter(|f| f.ended_at.is_none()) + .map(|f| &f.surface); // Move grab is treated as focused, so don't change focus to a // window while grab exists. @@ -514,7 +506,7 @@ impl Workspace { .chain(move_mapped.iter()) }; stack.retain(|w| match w { - FocusTarget::Fullscreen(s) => fullscreen_surfaces.contains(&s), + FocusTarget::Fullscreen(s) => fullscreen.is_some_and(|f| f == s), FocusTarget::Window(w) => mapped().any(|m| w == m), }); } @@ -523,12 +515,15 @@ impl Workspace { pub fn animations_going(&self) -> bool { self.tiling_layer.animations_going() || self.floating_layer.animations_going() - || self.fullscreen_surfaces.iter().any(|f| f.is_animating()) + || self + .fullscreen + .as_ref() + .is_some_and(|f| f.start_at.is_some() || f.ended_at.is_some()) || self.dirty.swap(false, Ordering::SeqCst) } pub fn update_animations(&mut self) -> HashMap { - for f in self.fullscreen_surfaces.iter_mut() { + if let Some(f) = self.fullscreen.as_mut() { if let Some(start) = f.start_at.as_ref() { let duration_since = Instant::now().duration_since(*start); if duration_since > FULLSCREEN_ANIMATION_DURATION { @@ -536,17 +531,15 @@ impl Workspace { self.dirty.store(true, Ordering::SeqCst); } } - } - self.fullscreen_surfaces.retain(|f| { - if let Some(end) = f.ended_at - && Instant::now().duration_since(end) >= FULLSCREEN_ANIMATION_DURATION - { - self.dirty.store(true, Ordering::SeqCst); - return false; + if let Some(end) = f.ended_at { + let duration_since = Instant::now().duration_since(end); + if duration_since >= FULLSCREEN_ANIMATION_DURATION { + let _ = self.fullscreen.take(); + self.dirty.store(true, Ordering::SeqCst); + } } - true - }); + } let clients = self.tiling_layer.update_animation_state(); self.floating_layer.update_animation_state(); @@ -581,11 +574,7 @@ impl Workspace { toplevel_enter_output(&surface, output); } } - for f in self - .fullscreen_surfaces - .iter() - .filter(|f| f.ended_at.is_none()) - { + if let Some(f) = self.fullscreen.as_ref().filter(|f| f.ended_at.is_none()) { toplevel_leave_output(&f.surface, &self.output); toplevel_enter_output(&f.surface, output); } @@ -676,13 +665,12 @@ impl Workspace { where CosmicSurface: PartialEq, { - if let Some(idx) = self - .fullscreen_surfaces - .iter() - .position(|f| f.ended_at.is_none() && &f.surface == surface) + if self + .fullscreen + .as_ref() + .is_some_and(|f| f.ended_at.is_none() && &f.surface == surface) { - let (surface, previous_state, previous_geometry) = - self.remove_fullscreen_at(idx).unwrap(); + let (surface, previous_state, previous_geometry) = self.remove_fullscreen().unwrap(); return Some(( surface, WorkspaceRestoreData::Fullscreen(previous_state.zip(previous_geometry).map( @@ -735,28 +723,24 @@ impl Workspace { Some((mapped.active_window(), layer)) } - pub fn fullscreen_geometry_for_surface( - &self, - surface: &CosmicSurface, - ) -> Rectangle { - let bbox = surface.bbox().as_local(); + pub fn fullscreen_geometry(&self) -> Option> { + self.fullscreen.as_ref().map(|fullscreen| { + let bbox = fullscreen.surface.bbox().as_local(); - let mut full_geo = Rectangle::from_size(self.output.geometry().size.as_local()); - if bbox != full_geo { - if bbox.size.w < full_geo.size.w { - full_geo.loc.x += (full_geo.size.w - bbox.size.w) / 2; - full_geo.size.w = bbox.size.w; + let mut full_geo = Rectangle::from_size(self.output.geometry().size.as_local()); + if bbox != full_geo { + if bbox.size.w < full_geo.size.w { + full_geo.loc.x += (full_geo.size.w - bbox.size.w) / 2; + full_geo.size.w = bbox.size.w; + } + if bbox.size.h < full_geo.size.h { + full_geo.loc.y += (full_geo.size.h - bbox.size.h) / 2; + full_geo.size.h = bbox.size.h; + } } - if bbox.size.h < full_geo.size.h { - full_geo.loc.y += (full_geo.size.h - bbox.size.h) / 2; - full_geo.size.h = bbox.size.h; - } - } - full_geo - } - pub fn fullscreen_geometry_for(&self, fullscreen: &FullscreenSurface) -> Rectangle { - self.fullscreen_geometry_for_surface(&fullscreen.surface) + full_geo + }) } pub fn element_for_surface(&self, surface: &S) -> Option<&CosmicMapped> @@ -796,23 +780,24 @@ impl Workspace { let stack = self.focus_stack.get(seat); let last_focused = stack.last(); - if let Some(fullscreen) = self.fullscreen_surfaces.iter().find(|f| { - !f.is_animating() - && last_focused - .is_some_and(|t| matches!(t, FocusTarget::Fullscreen(s) if s == &f.surface)) - }) { - let geometry = self.fullscreen_geometry_for(fullscreen); + if let Some(fullscreen) = self.fullscreen.as_ref() + && last_focused.is_some_and( + |t| matches!(t, FocusTarget::Fullscreen(f) if f == &fullscreen.surface), + ) + && !fullscreen.is_animating() + { + let geometry = self.fullscreen_geometry().unwrap(); return fullscreen_element_under(fullscreen, geometry); } self.floating_layer - .popup_element_under(location, seat) - .or_else(|| self.tiling_layer.popup_element_under(location, seat)) + .popup_element_under(location) + .or_else(|| self.tiling_layer.popup_element_under(location)) .or_else(|| { if last_focused.is_none_or(|t| !matches!(t, FocusTarget::Fullscreen(_))) - && let Some(fullscreen) = self.get_fullscreen(seat) + && let Some(fullscreen) = self.fullscreen.as_ref() { - let geometry = self.fullscreen_geometry_for(fullscreen); + let geometry = self.fullscreen_geometry().unwrap(); return fullscreen_element_under(fullscreen, geometry); } None @@ -845,23 +830,24 @@ impl Workspace { let stack = self.focus_stack.get(seat); let last_focused = stack.last(); - if let Some(fullscreen) = self.fullscreen_surfaces.iter().find(|fs| { - !fs.is_animating() - && last_focused - .is_some_and(|t| matches!(t, FocusTarget::Fullscreen(f) if f == &fs.surface)) - }) { - let geometry = self.fullscreen_geometry_for(fullscreen); + if let Some(fullscreen) = self.fullscreen.as_ref() + && last_focused.is_some_and( + |t| matches!(t, FocusTarget::Fullscreen(f) if f == &fullscreen.surface), + ) + && !fullscreen.is_animating() + { + let geometry = self.fullscreen_geometry().unwrap(); return fullscreen_element_under(fullscreen, geometry); } self.floating_layer - .toplevel_element_under(location, seat) - .or_else(|| self.tiling_layer.toplevel_element_under(location, seat)) + .toplevel_element_under(location) + .or_else(|| self.tiling_layer.toplevel_element_under(location)) .or_else(|| { if last_focused.is_none_or(|t| !matches!(t, FocusTarget::Fullscreen(_))) - && let Some(fullscreen) = self.get_fullscreen(seat) + && let Some(fullscreen) = self.fullscreen.as_ref() { - let geometry = self.fullscreen_geometry_for(fullscreen); + let geometry = self.fullscreen_geometry().unwrap(); return fullscreen_element_under(fullscreen, geometry); } None @@ -881,7 +867,7 @@ impl Workspace { let check_fullscreen = |fullscreen: &FullscreenSurface| { if !fullscreen.is_animating() { - let geometry = self.fullscreen_geometry_for(fullscreen); + let geometry = self.fullscreen_geometry().unwrap(); return fullscreen .surface .0 @@ -905,16 +891,18 @@ impl Workspace { let stack = self.focus_stack.get(seat); let last_focused = stack.last(); - self.fullscreen_surfaces - .iter() - .find(|f| last_focused.is_some_and(|t| t == &f.surface)) + self.fullscreen + .as_ref() + .filter(|f| last_focused.is_some_and(|t| t == &f.surface)) .and_then(check_fullscreen) - .or_else(|| self.floating_layer.popup_surface_under(location, seat)) + .or_else(|| self.floating_layer.popup_surface_under(location)) + .or_else(|| self.tiling_layer.popup_surface_under(location, overview)) .or_else(|| { - self.tiling_layer - .popup_surface_under(location, overview, seat) + self.fullscreen + .as_ref() + .filter(|f| last_focused.is_none_or(|t| t != &f.surface)) + .and_then(check_fullscreen) }) - .or_else(|| self.get_fullscreen(seat).and_then(check_fullscreen)) .map(|(m, p)| (m, p.to_global(&self.output))) } @@ -931,7 +919,7 @@ impl Workspace { let check_fullscreen = |fullscreen: &FullscreenSurface| { if !fullscreen.is_animating() { - let geometry = self.fullscreen_geometry_for(fullscreen); + let geometry = self.fullscreen_geometry().unwrap(); return fullscreen .surface .focus_under( @@ -949,16 +937,18 @@ impl Workspace { let stack = self.focus_stack.get(seat); let last_focused = stack.last(); - self.fullscreen_surfaces - .iter() - .find(|f| last_focused.is_some_and(|t| t == &f.surface)) + self.fullscreen + .as_ref() + .filter(|f| last_focused.is_some_and(|t| t == &f.surface)) .and_then(check_fullscreen) - .or_else(|| self.floating_layer.toplevel_surface_under(location, seat)) + .or_else(|| self.floating_layer.toplevel_surface_under(location)) + .or_else(|| self.tiling_layer.toplevel_surface_under(location, overview)) .or_else(|| { - self.tiling_layer - .toplevel_surface_under(location, overview, seat) + self.fullscreen + .as_ref() + .filter(|f| last_focused.is_none_or(|t| t != &f.surface)) + .and_then(check_fullscreen) }) - .or_else(|| self.get_fullscreen(seat).and_then(check_fullscreen)) .map(|(m, p)| (m, p.to_global(&self.output))) } @@ -1030,14 +1020,10 @@ impl Workspace { where CosmicSurface: PartialEq, { - if let Some(idx) = self - .fullscreen_surfaces - .iter() - .position(|f| f.ended_at.is_none() && &f.surface == surface) - { - let fullscreen_state = self.fullscreen_surfaces.get(idx)?.clone(); + if self.get_fullscreen().is_some_and(|s| s == surface) { + let fullscreen_state = self.fullscreen.clone().unwrap(); { - let f = self.fullscreen_surfaces.get_mut(idx)?; + let f = self.fullscreen.as_mut().unwrap(); f.previous_geometry = Some(to); f.ended_at = Some( Instant::now() @@ -1141,20 +1127,16 @@ impl Workspace { )> { match window { MinimizedWindow::Fullscreen { previous, surface } => { + let old_fullscreen = self.remove_fullscreen(); surface.set_minimized(false); - // focus it so it's the top fullscreen window - self.focus_stack - .get_mut(seat) - .append(FocusTarget::Fullscreen(surface.clone())); - self.fullscreen_surfaces.push(FullscreenSurface { + self.fullscreen = Some(FullscreenSurface { surface, previous_state: previous.clone().map(|p| p.previous_state), previous_geometry: previous.map(|p| p.previous_geometry), start_at: None, ended_at: None, }); - self.dirty.store(true, Ordering::SeqCst); - None + old_fullscreen } MinimizedWindow::Floating { window, previous } => { let current_output_size = self.output.geometry().size.as_logical(); @@ -1242,7 +1224,13 @@ impl Workspace { seat: impl Into>>, restore: Option, previous_geometry: Option>, - ) { + ) -> Option<( + CosmicSurface, + Option, + Option>, + )> { + let res = self.remove_fullscreen(); + window.set_fullscreen(true); window.set_geometry(self.output.geometry(), 0); window.send_configure(); @@ -1255,137 +1243,96 @@ impl Workspace { self.focus_stack.get_mut(seat).append(window.clone()); } - self.dirty.store(true, Ordering::SeqCst); - self.fullscreen_surfaces.push(FullscreenSurface { + self.fullscreen = Some(FullscreenSurface { surface: window.clone(), previous_state: restore, previous_geometry, start_at: Some(Instant::now()), ended_at: None, }); + + res } #[must_use] - pub fn take_fullscreen( + pub fn take_fullscreen( &mut self, - surface: &S, - ) -> Option<( - CosmicSurface, - Option, - Option>, - )> - where - CosmicSurface: PartialEq, - { - let idx = self - .fullscreen_surfaces - .iter() - .position(|f| f.ended_at.is_none() && &f.surface == surface)?; - let fs = self.fullscreen_surfaces.remove(idx); - - for focus_stack in self.focus_stack.0.values_mut() { - focus_stack.retain(|t| t != &fs.surface); - } - - Some((fs.surface, fs.previous_state, fs.previous_geometry)) - } - - #[must_use] - pub fn remove_fullscreen_at( - &mut self, - idx: usize, ) -> Option<( CosmicSurface, Option, Option>, )> { - // if it doesn't exist we move on. - let surface = self.fullscreen_surfaces.get_mut(idx)?; - // if already being removed, do nothing - if surface.ended_at.is_some() { - return None; - } - - if surface.surface.alive() { - surface.surface.output_leave(&self.output); - surface.surface.set_fullscreen(false); - if let Some(previous_geometry) = surface.previous_geometry.as_ref() { - surface - .surface - .set_geometry(previous_geometry.to_global(&self.output), 0); - } - surface.surface.send_configure(); - } + let surface = self.fullscreen.take_if(|s| s.ended_at.is_none())?; for focus_stack in self.focus_stack.0.values_mut() { focus_stack.retain(|t| t != &surface.surface); } - surface.ended_at = Some( - Instant::now() - - (FULLSCREEN_ANIMATION_DURATION - - surface - .start_at - .take() - .map(|earlier| { - Instant::now() - .duration_since(earlier) - .min(FULLSCREEN_ANIMATION_DURATION) - }) - .unwrap_or(FULLSCREEN_ANIMATION_DURATION)), - ); - Some(( - surface.surface.clone(), - surface.previous_state.clone(), + surface.surface, + surface.previous_state, surface.previous_geometry, )) } #[must_use] - pub fn remove_fullscreen_surface( + pub fn remove_fullscreen( &mut self, - surface: &S, ) -> Option<( CosmicSurface, Option, Option>, - )> - where - CosmicSurface: PartialEq, - { - let idx = self - .fullscreen_surfaces - .iter() - .position(|f| f.ended_at.is_none() && &f.surface == surface)?; - self.remove_fullscreen_at(idx) - } + )> { + if let Some(surface) = self.fullscreen.as_mut() { + if surface.ended_at.is_some() { + return None; + } - pub fn get_fullscreen(&self, seat: &Seat) -> Option<&FullscreenSurface> { - let stack = self.focus_stack.get(seat); - stack - .iter() - .find_map(|t| { - if let FocusTarget::Fullscreen(s) = t { - self.fullscreen_surfaces - .iter() - .find(|f| f.alive() && f.ended_at.is_none() && &f.surface == s) - } else { - None + if surface.surface.alive() { + surface.surface.output_leave(&self.output); + surface.surface.set_fullscreen(false); + if let Some(previous_geometry) = surface.previous_geometry.as_ref() { + surface + .surface + .set_geometry(previous_geometry.to_global(&self.output), 0); } - }) - .or_else(|| { - self.fullscreen_surfaces - .iter() - .rev() - .find(|f| f.alive() && f.ended_at.is_none()) - }) + surface.surface.send_configure(); + } + + for focus_stack in self.focus_stack.0.values_mut() { + focus_stack.retain(|t| t != &surface.surface); + } + + surface.ended_at = Some( + Instant::now() + - (FULLSCREEN_ANIMATION_DURATION + - surface + .start_at + .take() + .map(|earlier| { + Instant::now() + .duration_since(earlier) + .min(FULLSCREEN_ANIMATION_DURATION) + }) + .unwrap_or(FULLSCREEN_ANIMATION_DURATION)), + ); + + Some(( + surface.surface.clone(), + surface.previous_state.clone(), + surface.previous_geometry, + )) + } else { + None + } } - pub fn get_fullscreen_surfaces(&self) -> impl Iterator { - self.fullscreen_surfaces - .iter() - .filter(|f| f.alive() && f.ended_at.is_none()) + pub fn get_fullscreen(&self) -> Option<&CosmicSurface> { + self.fullscreen + .as_ref() + .filter(|f| f.alive()) + .filter(|f| f.ended_at.is_none()) + .map(|f| &f.surface) } pub fn resize( @@ -1512,18 +1459,14 @@ impl Workspace { self.floating_layer.mapped().count() + self.tiling_layer.mapped().count() + self.minimized_windows.len() - + self - .fullscreen_surfaces - .iter() - .filter(|f| f.ended_at.is_none()) - .count() + + if self.fullscreen.is_some() { 1 } else { 0 } } pub fn is_empty(&self) -> bool { self.floating_layer.mapped().next().is_none() && self.tiling_layer.mapped().next().is_none() && self.minimized_windows.is_empty() - && self.fullscreen_surfaces.is_empty() + && self.fullscreen.is_none() } pub fn is_floating(&self, surface: &S) -> bool @@ -1630,11 +1573,8 @@ impl Workspace { }; let focused = self.focus_stack.get(last_active_seat).last().cloned(); - let render_fullscreen = |fullscreen: &FullscreenSurface, - renderer: &mut R, - output_scale: f64| - -> Vec> { - let fullscreen_geo = self.fullscreen_geometry_for(fullscreen); + let mut fullscreen_elements = if let Some(fullscreen) = self.fullscreen.as_ref() { + let fullscreen_geo = self.fullscreen_geometry().unwrap(); let previous_geo = fullscreen .previous_geometry .as_ref() @@ -1704,35 +1644,20 @@ impl Workspace { .into_iter() .map(animation_rescale) .collect::>() + } else { + Vec::new() }; - let top_fullscreen = self.get_fullscreen(last_active_seat); - - let mut fullscreen_elements: Vec> = Vec::new(); - if let Some(fs) = top_fullscreen { - fullscreen_elements.extend(render_fullscreen(fs, renderer, output_scale)); - } - // Also render any animating (entering/exiting) fullscreens - for fs in self.fullscreen_surfaces.iter().filter(|f| f.is_animating()) { - if top_fullscreen.is_none_or(|top| top.surface != fs.surface) { - fullscreen_elements.extend(render_fullscreen(fs, renderer, output_scale)); - }; - } - if matches!(focused, Some(FocusTarget::Fullscreen(_))) { elements.append(&mut fullscreen_elements); } - let any_fullscreen_animating = self - .fullscreen_surfaces - .iter() - .any(|f| f.start_at.is_some() || f.ended_at.is_some()); if !matches!(focused, Some(FocusTarget::Fullscreen(_))) - || any_fullscreen_animating || self - .fullscreen_surfaces - .iter() - .all(|f| !f.alive() || f.ended_at.is_some()) + .fullscreen + .as_ref() + .map(|f| f.start_at.is_some() || f.ended_at.is_some()) + .unwrap_or(true) { // floating surfaces let alpha = match &overview.0 { @@ -1757,17 +1682,13 @@ impl Workspace { self.floating_layer .render::( renderer, - render_focus - .then(|| { - focused.as_ref().and_then(|target| { - if let FocusTarget::Window(mapped) = target { - Some(mapped) - } else { - None - } - }) - }) - .flatten(), + focused.as_ref().and_then(|target| { + if let FocusTarget::Window(mapped) = target { + Some(mapped) + } else { + None + } + }), resize_indicator.clone(), indicator_thickness, alpha, @@ -1853,12 +1774,8 @@ impl Workspace { layer_map.non_exclusive_zone().as_local() }; - // Render popups for the top (most recently focused) fullscreen - let focus_stack = self.focus_stack.get(last_active_seat); - let top_fullscreen = self.get_fullscreen(last_active_seat); - - if let Some(fullscreen) = top_fullscreen { - let fullscreen_geo = self.fullscreen_geometry_for(fullscreen); + if let Some(fullscreen) = self.fullscreen.as_ref() { + let fullscreen_geo = self.fullscreen_geometry().unwrap(); let previous_geo = fullscreen .previous_geometry .as_ref() @@ -1915,16 +1832,13 @@ impl Workspace { ); } - let any_fullscreen_animating = self - .fullscreen_surfaces - .iter() - .any(|f| f.start_at.is_some() || f.ended_at.is_some()); + let focus_stack = self.focus_stack.get(last_active_seat); if !matches!(focus_stack.last(), Some(FocusTarget::Fullscreen(_))) - || any_fullscreen_animating || self - .fullscreen_surfaces - .iter() - .all(|f| !f.alive() || f.ended_at.is_some()) + .fullscreen + .as_ref() + .map(|f| f.start_at.is_some() || f.ended_at.is_some()) + .unwrap_or(true) { // floating surfaces let alpha = match &overview.0 { diff --git a/src/shell/zoom.rs b/src/shell/zoom.rs index f72ad8e8..24d86763 100644 --- a/src/shell/zoom.rs +++ b/src/shell/zoom.rs @@ -22,8 +22,8 @@ use smithay::{ MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchTarget, + UpEvent, }, }, output::Output, @@ -259,8 +259,10 @@ impl ZoomState { original_position: Point, movement: ZoomMovement, ) { - let output_geometry = output.geometry().to_f64(); - let mut zoomed_output_geometry = output.zoomed_geometry().unwrap().to_f64(); + let cursor_position = cursor_position.to_i32_round(); + let original_position = original_position.to_i32_round(); + let output_geometry = output.geometry(); + let mut zoomed_output_geometry = output.zoomed_geometry().unwrap(); let output_state = output.user_data().get::>().unwrap(); let mut output_state_ref = output_state.lock().unwrap(); @@ -273,40 +275,44 @@ impl ZoomState { let cursor_position = cursor_position.to_local(output); match movement { - ZoomMovement::Continuously => output_state_ref.focal_point = cursor_position, + ZoomMovement::Continuously => output_state_ref.focal_point = cursor_position.to_f64(), ZoomMovement::OnEdge => { if !zoomed_output_geometry - .overlaps_or_touches(Rectangle::new(original_position, Size::from((16., 16.)))) + .overlaps_or_touches(Rectangle::new(original_position, Size::from((16, 16)))) { zoomed_output_geometry.loc = cursor_position.to_global(output) - - zoomed_output_geometry.size.downscale(2.).to_point(); + - zoomed_output_geometry.size.downscale(2).to_point(); let mut focal_point = zoomed_output_geometry .loc .to_local(output) - .upscale(output_state_ref.level) + .upscale( + output_geometry.size.w + / (output_geometry.size.w - zoomed_output_geometry.size.w), + ) .to_global(output); focal_point.x = focal_point.x.clamp( output_geometry.loc.x, - output_geometry.loc.x + output_geometry.size.w - 1., + output_geometry.loc.x + output_geometry.size.w - 1, ); focal_point.y = focal_point.y.clamp( output_geometry.loc.y, - output_geometry.loc.y + output_geometry.size.h - 1., + output_geometry.loc.y + output_geometry.size.h - 1, ); output_state_ref.previous_point = Some((output_state_ref.focal_point, Instant::now())); - output_state_ref.focal_point = focal_point.to_local(output); + output_state_ref.focal_point = focal_point.to_local(output).to_f64(); } else if !zoomed_output_geometry.contains(cursor_position.to_global(output)) { let mut diff = output_state_ref.focal_point.to_global(output) + (cursor_position.to_global(output) - original_position) + .to_f64() .upscale(output_state_ref.level); diff.x = diff.x.clamp( - output_geometry.loc.x, - (output_geometry.loc.x + output_geometry.size.w).next_down(), + output_geometry.loc.x as f64, + ((output_geometry.loc.x + output_geometry.size.w) as f64).next_down(), ); diff.y = diff.y.clamp( - output_geometry.loc.y, - (output_geometry.loc.y + output_geometry.size.h).next_down(), + output_geometry.loc.y as f64, + ((output_geometry.loc.y + output_geometry.size.h) as f64).next_down(), ); diff -= output_state_ref.focal_point.to_global(output); @@ -315,27 +321,28 @@ impl ZoomState { } ZoomMovement::Centered => { zoomed_output_geometry.loc = cursor_position.to_global(output) - - zoomed_output_geometry.size.downscale(2.).to_point(); + - zoomed_output_geometry.size.downscale(2).to_point(); let mut focal_point = zoomed_output_geometry .loc .to_local(output) .upscale( - (output_geometry.size.w - / (output_geometry.size.w - zoomed_output_geometry.size.w) - .max(f64::EPSILON)) - .max(1.), + output_geometry + .size + .w + .checked_div(output_geometry.size.w - zoomed_output_geometry.size.w) + .unwrap_or(1), ) .to_global(output); focal_point.x = focal_point.x.clamp( output_geometry.loc.x, - output_geometry.loc.x + output_geometry.size.w - 1., + output_geometry.loc.x + output_geometry.size.w - 1, ); focal_point.y = focal_point.y.clamp( output_geometry.loc.y, - output_geometry.loc.y + output_geometry.size.h - 1., + output_geometry.loc.y + output_geometry.size.h - 1, ); - output_state_ref.focal_point = focal_point.to_local(output); + output_state_ref.focal_point = focal_point.to_local(output).to_f64(); } } } @@ -1029,59 +1036,58 @@ impl PointerTarget for ZoomFocusTarget { } impl TouchTarget for ZoomFocusTarget { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent, seq: Serial) { match self { - ZoomFocusTarget::Main(elem) => TouchTarget::down(elem, seat, data, event), - ZoomFocusTarget::Menu(elem) => TouchTarget::down(elem, seat, data, event), + ZoomFocusTarget::Main(elem) => TouchTarget::down(elem, seat, data, event, seq), + ZoomFocusTarget::Menu(elem) => TouchTarget::down(elem, seat, data, event, seq), } } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { + fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent, seq: Serial) { match self { - ZoomFocusTarget::Main(elem) => TouchTarget::up(elem, seat, data, event), - ZoomFocusTarget::Menu(elem) => TouchTarget::up(elem, seat, data, event), + ZoomFocusTarget::Main(elem) => TouchTarget::up(elem, seat, data, event, seq), + ZoomFocusTarget::Menu(elem) => TouchTarget::up(elem, seat, data, event, seq), } } - fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent) { + fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent, seq: Serial) { match self { - ZoomFocusTarget::Main(elem) => TouchTarget::motion(elem, seat, data, event), - ZoomFocusTarget::Menu(elem) => TouchTarget::motion(elem, seat, data, event), + ZoomFocusTarget::Main(elem) => TouchTarget::motion(elem, seat, data, event, seq), + ZoomFocusTarget::Menu(elem) => TouchTarget::motion(elem, seat, data, event, seq), } } - fn frame(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { + fn frame(&self, seat: &Seat, data: &mut State, seq: Serial) { match self { - ZoomFocusTarget::Main(elem) => TouchTarget::frame(elem, seat, data, frame), - ZoomFocusTarget::Menu(elem) => TouchTarget::frame(elem, seat, data, frame), + ZoomFocusTarget::Main(elem) => TouchTarget::frame(elem, seat, data, seq), + ZoomFocusTarget::Menu(elem) => TouchTarget::frame(elem, seat, data, seq), } } - fn cancel(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { + fn cancel(&self, seat: &Seat, data: &mut State, seq: Serial) { match self { - ZoomFocusTarget::Main(elem) => TouchTarget::cancel(elem, seat, data, frame), - ZoomFocusTarget::Menu(elem) => TouchTarget::cancel(elem, seat, data, frame), + ZoomFocusTarget::Main(elem) => TouchTarget::cancel(elem, seat, data, seq), + ZoomFocusTarget::Menu(elem) => TouchTarget::cancel(elem, seat, data, seq), } } - fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent) { + fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent, seq: Serial) { match self { - ZoomFocusTarget::Main(elem) => TouchTarget::shape(elem, seat, data, event), - ZoomFocusTarget::Menu(elem) => TouchTarget::shape(elem, seat, data, event), + ZoomFocusTarget::Main(elem) => TouchTarget::shape(elem, seat, data, event, seq), + ZoomFocusTarget::Menu(elem) => TouchTarget::shape(elem, seat, data, event, seq), } } - fn orientation(&self, seat: &Seat, data: &mut State, event: &OrientationEvent) { + fn orientation( + &self, + seat: &Seat, + data: &mut State, + event: &OrientationEvent, + seq: Serial, + ) { match self { - ZoomFocusTarget::Main(elem) => TouchTarget::orientation(elem, seat, data, event), - ZoomFocusTarget::Menu(elem) => TouchTarget::orientation(elem, seat, data, event), - } - } - - fn last_frame(&self, seat: &Seat, data: &mut State) -> Option { - match self { - ZoomFocusTarget::Main(elem) => TouchTarget::last_frame(elem, seat, data), - ZoomFocusTarget::Menu(elem) => TouchTarget::last_frame(elem, seat, data), + ZoomFocusTarget::Main(elem) => TouchTarget::orientation(elem, seat, data, event, seq), + ZoomFocusTarget::Menu(elem) => TouchTarget::orientation(elem, seat, data, event, seq), } } } diff --git a/src/state.rs b/src/state.rs index 18de36ba..88298a94 100644 --- a/src/state.rs +++ b/src/state.rs @@ -8,7 +8,7 @@ use crate::{ x11::X11State, }, config::{CompOutputConfig, Config, ScreenFilter}, - dbus::DBusState, + dbus::a11y_keyboard_monitor::A11yKeyboardMonitorState, input::{PointerFocusState, gestures::GestureState}, shell::{CosmicSurface, SeatExt, Shell, grabs::SeatMoveGrabState}, utils::prelude::OutputExt, @@ -32,6 +32,7 @@ use crate::{ use anyhow::Context; use calloop::RegistrationToken; use cosmic_comp_config::output::comp::{OutputConfig, OutputState}; +use futures_executor::ThreadPool; use i18n_embed::{ DesktopLanguageRequester, fluent::{FluentLanguageLoader, fluent_language_loader}, @@ -86,7 +87,6 @@ use smithay::{ output::OutputManagerState, pointer_constraints::PointerConstraintsState, pointer_gestures::PointerGesturesState, - pointer_warp::PointerWarpManager, presentation::PresentationState, seat::WaylandFocus, security_context::{SecurityContext, SecurityContextState}, @@ -117,7 +117,7 @@ use smithay::{ }; use tracing::warn; -#[cfg(feature = "logind")] +#[cfg(feature = "systemd")] use std::os::fd::OwnedFd; use std::{ @@ -234,6 +234,7 @@ pub struct Common { pub display_handle: DisplayHandle, pub event_loop_handle: LoopHandle<'static, State>, pub event_loop_signal: LoopSignal, + pub async_executor: ThreadPool, pub popups: PopupManager, pub shell: Arc>, @@ -278,7 +279,7 @@ pub struct Common { pub xdg_decoration_state: XdgDecorationState, pub overlap_notify_state: OverlapNotifyState, pub a11y_state: A11yState, - pub dbus_state: DBusState, + pub a11y_keyboard_monitor_state: A11yKeyboardMonitorState, // shell-related wayland state pub xdg_shell_state: XdgShellState, @@ -293,7 +294,7 @@ pub struct Common { pub xwayland_shell_state: XWaylandShellState, pub pointer_focus_state: Option, - #[cfg(feature = "logind")] + #[cfg(feature = "systemd")] pub inhibit_lid_fd: Option, pub with_xwayland: bool, @@ -672,7 +673,6 @@ impl State { XWaylandKeyboardGrabState::new::(dh); let xwayland_shell_state = XWaylandShellState::new::(dh); PointerConstraintsState::new::(dh); - PointerWarpManager::new::(dh); PointerGesturesState::new::(dh); TabletManagerState::new::(dh); SecurityContextState::new::(dh, client_has_no_security_context); @@ -727,9 +727,15 @@ impl State { ); let workspace_state = WorkspaceState::new(dh, client_not_sandboxed); + let async_executor = ThreadPool::builder().pool_size(1).create().unwrap(); + + if let Err(err) = crate::dbus::init(&handle, &async_executor) { + tracing::warn!(?err, "Failed to initialize dbus handlers"); + } + let a11y_state = A11yState::new::(dh, client_not_sandboxed); - let dbus_state = DBusState::init(&handle); + let a11y_keyboard_monitor_state = A11yKeyboardMonitorState::new(&async_executor); State { common: Common { @@ -738,6 +744,7 @@ impl State { display_handle: dh.clone(), event_loop_handle: handle, event_loop_signal: signal, + async_executor, popups: PopupManager::default(), shell, @@ -787,13 +794,13 @@ impl State { xdg_foreign_state, workspace_state, a11y_state, + a11y_keyboard_monitor_state, xwayland_scale: None, xwayland_state: None, xwayland_shell_state, pointer_focus_state: None, - dbus_state, - #[cfg(feature = "logind")] + #[cfg(feature = "systemd")] inhibit_lid_fd: None, with_xwayland, @@ -818,7 +825,7 @@ impl State { } fn update_inhibitor_locks(&mut self) { - #[cfg(feature = "logind")] + #[cfg(feature = "systemd")] { use smithay::backend::session::Session; use tracing::{debug, error, warn}; @@ -834,7 +841,7 @@ impl State { if should_handle_lid { if self.common.inhibit_lid_fd.is_none() { - match crate::dbus::logind::inhibit_lid(&self.common) { + match crate::dbus::logind::inhibit_lid() { Ok(fd) => { debug!("Inhibiting lid switch"); self.common.inhibit_lid_fd = Some(fd); @@ -845,8 +852,7 @@ impl State { .iter() .find(|o| o.is_internal()) .cloned(); - let closed = - crate::dbus::logind::lid_closed(&self.common).unwrap_or(false); + let closed = crate::dbus::logind::lid_closed().unwrap_or(false); if closed { backend.disable_internal_output( @@ -990,8 +996,8 @@ impl Common { // normal windows for space in shell.workspaces.spaces() { - if let Some(fs) = space.get_fullscreen(shell.seats.last_active()) { - fs.surface.with_surfaces(processor); + if let Some(window) = space.get_fullscreen() { + window.with_surfaces(processor); } space.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { @@ -1156,16 +1162,15 @@ impl Common { }); if let Some(active) = shell.active_space(output) { - if let Some(fs) = active.get_fullscreen(shell.seats.last_active()) - && let Some(feedback) = fs - .surface + if let Some(window) = active.get_fullscreen() + && let Some(feedback) = window .wl_surface() .and_then(|wl_surface| { advertised_node_for_surface(&wl_surface, &self.display_handle) }) .and_then(&mut dmabuf_feedback) { - fs.surface.send_dmabuf_feedback( + window.send_dmabuf_feedback( output, &feedback, render_element_states, @@ -1351,9 +1356,8 @@ impl Common { }); if let Some(active) = shell.active_space(output) { - if let Some(fs) = active.get_fullscreen(shell.seats.last_active()) { - fs.surface - .send_frame(output, time, throttle(&fs.surface), should_send); + if let Some(window) = active.get_fullscreen() { + window.send_frame(output, time, throttle(window), should_send); } active.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { @@ -1373,9 +1377,9 @@ impl Common { .spaces_for_output(output) .filter(|w| w.handle != active.handle) { - if let Some(fs) = space.get_fullscreen(shell.seats.last_active()) { - let throttle = min(throttle(space), throttle(&fs.surface)); - fs.surface.send_frame(output, time, throttle, |_, _| None); + if let Some(window) = space.get_fullscreen() { + let throttle = min(throttle(space), throttle(window)); + window.send_frame(output, time, throttle, |_, _| None); } space.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { diff --git a/src/utils/iced/mod.rs b/src/utils/iced/mod.rs index 44a722db..186abf04 100644 --- a/src/utils/iced/mod.rs +++ b/src/utils/iced/mod.rs @@ -51,12 +51,13 @@ use smithay::{ PointerTarget, RelativeMotionEvent, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchTarget, + UpEvent, }, }, output::Output, - reexports::calloop::{self, LoopHandle, RegistrationToken, futures::Scheduler}, + reexports::calloop::RegistrationToken, + reexports::calloop::{self, LoopHandle, futures::Scheduler}, utils::{ Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform, @@ -179,8 +180,6 @@ pub(crate) struct IcedElementInternal { last_seat: Arc, Serial)>>>, cursor_pos: Option>, touch_map: HashMap, - last_touch_frame: Option, - last_touch_serial: Option, // iced theme: Theme, @@ -229,8 +228,6 @@ impl Clone for IcedElementInternal

{ last_seat: self.last_seat.clone(), cursor_pos: self.cursor_pos, touch_map: self.touch_map.clone(), - last_touch_frame: None, - last_touch_serial: None, theme: self.theme.clone(), renderer, state, @@ -256,8 +253,6 @@ impl fmt::Debug for IcedElementInternal

{ .field("last_seat", &self.last_seat) .field("cursor_pos", &self.cursor_pos) .field("touch_map", &self.touch_map) - .field("last_touch_frame", &self.last_touch_frame) - .field("last_touch_serial", &self.last_touch_serial) .field("theme", &"...") .field("renderer", &"...") .field("state", &"...") @@ -314,8 +309,6 @@ impl IcedElement

{ cursor_pos: None, last_seat, touch_map: HashMap::new(), - last_touch_frame: None, - last_touch_serial: None, theme, renderer, state, @@ -640,6 +633,7 @@ impl TouchTarget for IcedEleme seat: &Seat, _data: &mut crate::state::State, event: &DownEvent, + seq: Serial, ) { let mut internal = self.0.lock().unwrap(); let id = Finger(i32::from(event.slot) as u64); @@ -650,8 +644,7 @@ impl TouchTarget for IcedEleme .queue_event(Event::Touch(TouchEvent::FingerPressed { id, position })); internal.touch_map.insert(id, position); internal.cursor_pos = Some(event_location); - internal.last_touch_serial = Some(event.serial); - *internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); + *internal.last_seat.lock().unwrap() = Some((seat.clone(), seq)); internal.update(false); } @@ -660,12 +653,12 @@ impl TouchTarget for IcedEleme seat: &Seat, _data: &mut crate::state::State, event: &UpEvent, + seq: Serial, ) { let mut internal = self.0.lock().unwrap(); let id = Finger(i32::from(event.slot) as u64); if let Some(position) = internal.touch_map.remove(&id) { - *internal.last_seat.lock().unwrap() = - Some((seat.clone(), internal.last_touch_serial.unwrap())); + *internal.last_seat.lock().unwrap() = Some((seat.clone(), seq)); internal .state .queue_event(Event::Touch(TouchEvent::FingerLifted { id, position })); @@ -678,13 +671,13 @@ impl TouchTarget for IcedEleme seat: &Seat, _data: &mut crate::state::State, event: &TouchMotionEvent, + seq: Serial, ) { let mut internal = self.0.lock().unwrap(); let id = Finger(i32::from(event.slot) as u64); let event_location = event.location.downscale(internal.additional_scale); let position = IcedPoint::new(event_location.x as f32, event_location.y as f32); - *internal.last_seat.lock().unwrap() = - Some((seat.clone(), internal.last_touch_serial.unwrap())); + *internal.last_seat.lock().unwrap() = Some((seat.clone(), seq)); internal .state .queue_event(Event::Touch(TouchEvent::FingerMoved { id, position })); @@ -697,19 +690,17 @@ impl TouchTarget for IcedEleme &self, _seat: &Seat, _data: &mut crate::state::State, - frame: FrameMarker, + _seq: Serial, ) { - self.0.lock().unwrap().last_touch_frame = Some(frame); } fn cancel( &self, _seat: &Seat, _data: &mut crate::state::State, - frame: FrameMarker, + _seq: Serial, ) { let mut internal = self.0.lock().unwrap(); - internal.last_touch_frame = Some(frame); for (id, position) in std::mem::take(&mut internal.touch_map) { internal .state @@ -723,6 +714,7 @@ impl TouchTarget for IcedEleme _seat: &Seat, _data: &mut crate::state::State, _event: &ShapeEvent, + _seq: Serial, ) { } @@ -731,16 +723,9 @@ impl TouchTarget for IcedEleme _seat: &Seat, _data: &mut crate::state::State, _event: &OrientationEvent, + _seq: Serial, ) { } - - fn last_frame( - &self, - _seat: &Seat, - _data: &mut crate::state::State, - ) -> Option { - self.0.lock().unwrap().last_touch_frame - } } impl KeyboardTarget for IcedElement

{ diff --git a/src/utils/quirks.rs b/src/utils/quirks.rs index e0954fd4..2ecda9fd 100644 --- a/src/utils/quirks.rs +++ b/src/utils/quirks.rs @@ -1,9 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use smithay::{ - backend::renderer::utils::with_renderer_surface_state, desktop::layer_map_for_output, - output::Output, -}; +use smithay::{desktop::layer_map_for_output, output::Output}; /// Layer shell namespace used by `cosmic-workspaces` // TODO: Avoid special case, or add protocol to expose required behavior @@ -13,14 +10,5 @@ pub const WORKSPACE_OVERVIEW_NAMESPACE: &str = "cosmic-workspace-overview"; pub fn workspace_overview_is_open(output: &Output) -> bool { layer_map_for_output(output) .layers() - .filter(|s| s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) - // Only consider the overview open once it has committed a buffer. The - // surface is inserted into the layer map on its initial (bufferless) - // commit, so checking for the namespace alone hides all toplevels for a - // frame before the overview has anything to draw, briefly flashing the - // bare wallpaper. - .any(|s| { - with_renderer_surface_state(s.wl_surface(), |state| state.buffer().is_some()) - .unwrap_or(false) - }) + .any(|s| s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) } diff --git a/src/wayland/handlers/dmabuf.rs b/src/wayland/handlers/dmabuf.rs index 4d9732bb..093f88da 100644 --- a/src/wayland/handlers/dmabuf.rs +++ b/src/wayland/handlers/dmabuf.rs @@ -51,11 +51,9 @@ impl DmabufHandler for State { let is_fullscreen = shell .workspaces .space_for_handle(&handle)? - .fullscreen_surfaces - .iter() - .any(|f| { - f.ended_at.is_none() && f.surface.has_surface(surface, WindowSurfaceType::all()) - }); + .fullscreen + .as_ref() + .is_some_and(|f| f.surface.has_surface(surface, WindowSurfaceType::all())); let node = kms .drm_devices diff --git a/src/wayland/handlers/image_copy_capture/render.rs b/src/wayland/handlers/image_copy_capture/render.rs index 21370f31..28ccd1cb 100644 --- a/src/wayland/handlers/image_copy_capture/render.rs +++ b/src/wayland/handlers/image_copy_capture/render.rs @@ -753,15 +753,11 @@ pub fn render_cursor_to_buffer( seat: &Seat, ) { let buffer = frame.buffer(); - let mut cursor_size = seat + let cursor_size = seat .cursor_geometry((0.0, 0.0), state.common.clock.now()) .map(|(geo, _hotspot)| geo.size) .unwrap_or_else(|| Size::from((64, 64))); let buffer_size = buffer_dimensions(&buffer).unwrap(); - // Client shouldn't try to allocate 0x0 buffer - if cursor_size == Size::new(0, 0) { - cursor_size = Size::new(1, 1); - } if buffer_size != cursor_size { let constraints = BufferConstraints { size: cursor_size, diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index 34d063d0..8f6547cf 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -25,7 +25,6 @@ pub mod output_configuration; pub mod output_power; pub mod overlap_notify; pub mod pointer_constraints; -pub mod pointer_warp; pub mod primary_selection; pub mod seat; pub mod security_context; diff --git a/src/wayland/handlers/pointer_constraints.rs b/src/wayland/handlers/pointer_constraints.rs index e17c1961..71e4a4d1 100644 --- a/src/wayland/handlers/pointer_constraints.rs +++ b/src/wayland/handlers/pointer_constraints.rs @@ -1,123 +1,35 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::{shell::CosmicSurface, state::State, utils::prelude::*}; +use crate::state::State; use smithay::{ input::pointer::PointerHandle, reexports::wayland_server::protocol::wl_surface::WlSurface, utils::{Logical, Point}, - wayland::{pointer_constraints::PointerConstraintsHandler, seat::WaylandFocus}, + wayland::{ + pointer_constraints::{PointerConstraintsHandler, with_pointer_constraint}, + seat::WaylandFocus, + }, }; -pub use smithay::wayland::pointer_constraints::{PointerConstraintRef, with_pointer_constraint}; - impl PointerConstraintsHandler for State { fn new_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle) { - let seat = self - .common - .shell - .read() - .seats - .iter() - .find(|s| s.get_pointer().as_ref() == Some(pointer)) - .cloned(); - - let (is_under, is_focused, surface_location) = if let Some(seat) = seat { - seat.set_pointer_constraint_hint(None); - let current_output = seat.active_output(); - let position = seat.get_pointer().unwrap().current_location().as_global(); - let shell = self.common.shell.read(); - let under = State::surface_under(position, ¤t_output, &shell); - let mut surface_location = None; - - let is_under = if let Some((target, target_loc)) = under - && let Some(under_surface) = target.wl_surface() - { - if *under_surface == *surface { - surface_location = Some(target_loc); - true - } else { - CosmicSurface::surface_tree_offset(surface, &under_surface).is_some_and( - |offset| { - surface_location = Some(target_loc - offset.to_f64().as_global()); - true - }, - ) - } - } else { - false - }; - - let is_focused = seat - .get_keyboard() - .and_then(|k| k.current_focus()) - .is_some_and(|f| f.has_surface(&shell, surface)); - - (is_under, is_focused, surface_location) - } else { - (false, false, None) - }; - - if is_focused && is_under { + // XXX region + if pointer + .current_focus() + .is_some_and(|x| x.wl_surface().as_deref() == Some(surface)) + { with_pointer_constraint(surface, pointer, |constraint| { - if let Some(constraint) = constraint { - if let Some(region) = constraint.region() { - if let Some(surface_location) = surface_location - && let position = pointer.current_location() - && let point = (position - surface_location.as_logical()).to_i32_round() - && region.contains(point) - { - constraint.activate(); - } - } else { - constraint.activate(); - } - } + constraint.unwrap().activate(); }); } } - fn remove_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle) { - if with_pointer_constraint(surface, pointer, |constraint| constraint.is_none()) { - let seat = self - .common - .shell - .read() - .seats - .iter() - .find(|s| s.get_pointer().as_ref() == Some(pointer)) - .cloned(); - - if let Some(seat) = seat - && let Some((hint_surface, hint_location)) = seat.pointer_constraint_hint() - && hint_surface == *surface - { - self.apply_cursor_hint(surface, pointer, hint_location); - seat.set_pointer_constraint_hint(None); - } - } - } - fn cursor_position_hint( &mut self, - surface: &WlSurface, - pointer: &PointerHandle, - location: Point, + _surface: &WlSurface, + _pointer: &PointerHandle, + _location: Point, ) { - if with_pointer_constraint(surface, pointer, |constraint| { - constraint.is_some_and(|c| c.is_active()) - }) { - let seat = self - .common - .shell - .read() - .seats - .iter() - .find(|s| s.get_pointer().as_ref() == Some(pointer)) - .cloned(); - - if let Some(seat) = seat { - seat.set_pointer_constraint_hint(Some((surface.clone(), location))); - } - } + // TODO } } diff --git a/src/wayland/handlers/pointer_warp.rs b/src/wayland/handlers/pointer_warp.rs deleted file mode 100644 index 971ab583..00000000 --- a/src/wayland/handlers/pointer_warp.rs +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -use crate::state::State; -use smithay::{ - input::pointer::PointerHandle, - reexports::wayland_server::protocol::{wl_pointer::WlPointer, wl_surface::WlSurface}, - utils::{Logical, Point, Serial}, - wayland::pointer_warp::PointerWarpHandler, -}; - -impl PointerWarpHandler for State { - fn warp_pointer( - &mut self, - surface: WlSurface, - pointer: WlPointer, - pos: Point, - serial: Serial, - ) { - let Some(resource_handle) = PointerHandle::::from_resource(&pointer) else { - return; - }; - - let shell = self.common.shell.read(); - - let pointer_handle = shell.seats.iter().find_map(|seat| { - if let Some(pointer_handle) = seat.get_pointer() - && resource_handle == pointer_handle - && pointer_handle.last_enter() == Some(serial) - && let Some(keyboard) = seat.get_keyboard() - && let Some(keyboard_focus) = keyboard.current_focus() - && keyboard_focus.has_surface(&shell, &surface) - { - return Some(pointer_handle); - } - None - }); - - drop(shell); - - if let Some(pointer_handle) = pointer_handle { - self.apply_cursor_hint(&surface, &pointer_handle, pos); - } - } -} diff --git a/src/wayland/handlers/toplevel_management.rs b/src/wayland/handlers/toplevel_management.rs index 3da39952..01410bb5 100644 --- a/src/wayland/handlers/toplevel_management.rs +++ b/src/wayland/handlers/toplevel_management.rs @@ -42,7 +42,7 @@ impl ToplevelManagementHandler for State { .spaces_for_output(output) .enumerate() .find(|(_, w)| { - w.get_fullscreen_surfaces().any(|f| &f.surface == window) + w.get_fullscreen().is_some_and(|f| f == window) || w.mapped() .flat_map(|m| m.windows().map(|(s, _)| s)) .any(|w| &w == window) diff --git a/src/wayland/handlers/xdg_activation.rs b/src/wayland/handlers/xdg_activation.rs index ad8ce0d0..b9674e38 100644 --- a/src/wayland/handlers/xdg_activation.rs +++ b/src/wayland/handlers/xdg_activation.rs @@ -5,7 +5,6 @@ use crate::{ state::State, wayland::protocols::workspace::{State as WState, WorkspaceHandle}, }; -use cosmic_comp_config::ActivationPolicy; use smithay::{ input::Seat, reexports::wayland_server::protocol::wl_surface::WlSurface, @@ -21,10 +20,6 @@ pub enum ActivationContext { Workspace(WorkspaceHandle), } -// It may happen that we get activation-requests, while all outputs are disabled. -// In these cases we won't be able to determine workspaces for windows and thus -// need to handle the corresponding code paths defensively. - impl XdgActivationHandler for State { fn activation_state(&mut self) -> &mut XdgActivationState { &mut self.common.xdg_activation_state @@ -56,12 +51,7 @@ impl XdgActivationHandler for State { }); let output = seat.active_output(); let mut shell = self.common.shell.write(); - let Some(workspace) = shell.active_space_mut(&output) else { - debug!(?token, "created urgent token for privileged client"); - data.user_data - .insert_if_missing(move || ActivationContext::UrgentOnly); - return true; - }; + let workspace = shell.active_space_mut(&output).unwrap(); let handle = workspace.handle; data.user_data .insert_if_missing(move || ActivationContext::Workspace(handle)); @@ -95,11 +85,7 @@ impl XdgActivationHandler for State { if valid { let output = seat.active_output(); let mut shell = self.common.shell.write(); - let Some(workspace) = shell.active_space_mut(&output) else { - data.user_data - .insert_if_missing(|| ActivationContext::UrgentOnly); - return true; - }; + let workspace = shell.active_space_mut(&output).unwrap(); let handle = workspace.handle; data.user_data .insert_if_missing(move || ActivationContext::Workspace(handle)); @@ -129,44 +115,10 @@ impl XdgActivationHandler for State { } } ActivationContext::Workspace(_) => { - match self.common.config.cosmic_conf.activation_policy { - ActivationPolicy::Focus => { - self.activate_surface( - &surface, - Some((ActivationKey::Wayland(surface.clone()), *context)), - ); - } - ActivationPolicy::FocusIfActiveWorkspace => { - let shell = self.common.shell.write(); - - let Some((target_workspace, _)) = shell.workspace_for_surface(&surface) - else { - return; - }; - - let seat = shell.seats.last_active().clone(); - let current_output = seat.active_output(); - let current_workspace = shell.active_space(¤t_output).unwrap().handle; - - if target_workspace == current_workspace { - std::mem::drop(shell); - self.activate_surface( - &surface, - Some((ActivationKey::Wayland(surface.clone()), *context)), - ); - } else { - let mut workspace_guard = self.common.workspace_state.update(); - workspace_guard.add_workspace_state(&target_workspace, WState::Urgent); - } - } - ActivationPolicy::Urgent => { - let shell = self.common.shell.write(); - if let Some((workspace, _output)) = shell.workspace_for_surface(&surface) { - let mut workspace_guard = self.common.workspace_state.update(); - workspace_guard.add_workspace_state(&workspace, WState::Urgent); - } - } - } + self.activate_surface( + &surface, + Some((ActivationKey::Wayland(surface.clone()), *context)), + ); } } } @@ -267,8 +219,8 @@ impl State { .workspaces .space_for_handle(&workspace) .unwrap() - .get_fullscreen(&seat) - .map(|f| f.surface.clone()) + .get_fullscreen() + .cloned() .map(KeyboardFocusTarget::Fullscreen) else { return; @@ -280,8 +232,8 @@ impl State { if let Some(surface) = shell .workspaces .space_for_handle(&workspace) - .and_then(|w| w.get_fullscreen(&seat)) - .map(|f| f.surface.clone()) + .and_then(|w| w.get_fullscreen()) + .cloned() { shell.append_focus_stack(surface, &seat) } diff --git a/src/wayland/handlers/xdg_shell/popup.rs b/src/wayland/handlers/xdg_shell/popup.rs index a3ee2e31..965e8908 100644 --- a/src/wayland/handlers/xdg_shell/popup.rs +++ b/src/wayland/handlers/xdg_shell/popup.rs @@ -68,7 +68,7 @@ impl Shell { unconstrain_xdg_popup(surface, window_loc, output.geometry()); } } else if let Some(output) = self.workspaces.spaces().find_map(|w| { - w.fullscreen_surfaces.iter().find_map(|f| { + w.fullscreen.as_ref().and_then(|f| { (f.surface.wl_surface().as_deref() == Some(&parent)).then_some(w.output()) }) }) { diff --git a/src/wayland/protocols/toplevel_info.rs b/src/wayland/protocols/toplevel_info.rs index 2dc76347..4643aca6 100644 --- a/src/wayland/protocols/toplevel_info.rs +++ b/src/wayland/protocols/toplevel_info.rs @@ -495,18 +495,35 @@ where .unwrap() .lock() .unwrap(); + let foreign_toplevel_handle = state.foreign_handle.as_ref(); let mut changed = false; - let new_title = (handle_state.title != window.title()).then(|| window.title()); - let new_app_id = (handle_state.app_id != window.app_id()).then(|| window.app_id()); + if handle_state.title != window.title() { + handle_state.title = window.title(); + if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE { + instance.title(handle_state.title.clone()); + } + if let Some(handle) = foreign_toplevel_handle { + handle.send_title(&handle_state.title); + } + changed = true; + } + if handle_state.app_id != window.app_id() { + handle_state.app_id = window.app_id(); + if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE { + instance.app_id(handle_state.app_id.clone()); + } + if let Some(handle) = foreign_toplevel_handle { + handle.send_app_id(&handle_state.app_id); + } + changed = true; + } - let new_states = if handle_state.states.as_ref().is_none_or(|states| { + if handle_state.states.as_ref().is_none_or(|states| { (states.contains(&States::Maximized) != window.is_maximized()) || (states.contains(&States::Fullscreen) != window.is_fullscreen()) || (states.contains(&States::Activated) != window.is_activated()) || (states.contains(&States::Minimized) != window.is_minimized()) - || (instance.version() >= zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE - && states.contains(&States::Sticky) != window.is_sticky()) }) { let mut states = Vec::new(); if window.is_maximized() { @@ -526,64 +543,8 @@ where { states.push(States::Sticky); } - Some(states) - } else { - None - }; - - let geometry_changed = if !window.is_resizing() { - let geometry = window.global_geometry(); - if handle_state.geometry != geometry { - handle_state.geometry = geometry; - true - } else { - false - } - } else { - false - }; - - let outputs_changed = state.outputs != handle_state.outputs - || handle_state.wl_outputs.iter().any(|o| !o.is_alive()); - - let workspaces_changed = state.workspaces != handle_state.workspaces; - - if new_title.is_none() - && new_app_id.is_none() - && new_states.is_none() - && !geometry_changed - && !outputs_changed - && !workspaces_changed - { - return false; - } - - let foreign_toplevel_handle = state.foreign_handle.as_ref(); - - if let Some(title) = new_title { - handle_state.title = title; - if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE { - instance.title(handle_state.title.clone()); - } - if let Some(handle) = foreign_toplevel_handle { - handle.send_title(&handle_state.title); - } - changed = true; - } - - if let Some(app_id) = new_app_id { - handle_state.app_id = app_id; - if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE { - instance.app_id(handle_state.app_id.clone()); - } - if let Some(handle) = foreign_toplevel_handle { - handle.send_app_id(&handle_state.app_id); - } - changed = true; - } - - if let Some(states) = new_states { handle_state.states = Some(states.clone()); + let states = states .iter() .flat_map(|state| (*state as u32).to_ne_bytes()) @@ -592,9 +553,17 @@ where changed = true; } - if (outputs_changed || geometry_changed) - && let Ok(client) = dh.get_client(instance.id()) - { + let mut geometry_changed = false; + if !window.is_resizing() { + let geometry = window.global_geometry(); + if handle_state.geometry != geometry { + handle_state.geometry = geometry; + changed = true; + geometry_changed = true; + } + } + + if let Ok(client) = dh.get_client(instance.id()) { handle_state.outputs = state.outputs.clone(); let handle_state = &mut *handle_state; @@ -630,29 +599,27 @@ where }); } - if workspaces_changed { - for new_workspace in state - .workspaces - .iter() - .filter(|w| !handle_state.workspaces.contains(w)) - { - for handle in workspace_state.raw_ext_workspace_handles(new_workspace, &instance.id()) { - instance.ext_workspace_enter(handle); - changed = true; - } + for new_workspace in state + .workspaces + .iter() + .filter(|w| !handle_state.workspaces.contains(w)) + { + for handle in workspace_state.raw_ext_workspace_handles(new_workspace, &instance.id()) { + instance.ext_workspace_enter(handle); + changed = true; } - for old_workspace in handle_state - .workspaces - .iter() - .filter(|w| !state.workspaces.contains(w)) - { - for handle in workspace_state.raw_ext_workspace_handles(old_workspace, &instance.id()) { - instance.ext_workspace_leave(handle); - changed = true; - } - } - handle_state.workspaces = state.workspaces.clone(); } + for old_workspace in handle_state + .workspaces + .iter() + .filter(|w| !state.workspaces.contains(w)) + { + for handle in workspace_state.raw_ext_workspace_handles(old_workspace, &instance.id()) { + instance.ext_workspace_leave(handle); + changed = true; + } + } + handle_state.workspaces = state.workspaces.clone(); if changed { if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE { diff --git a/src/wayland/protocols/toplevel_management.rs b/src/wayland/protocols/toplevel_management.rs index f252fde5..9ec5132a 100644 --- a/src/wayland/protocols/toplevel_management.rs +++ b/src/wayland/protocols/toplevel_management.rs @@ -237,10 +237,11 @@ where window_from_handle::<::Window>(toplevel).unwrap(); if let Some(toplevel_state) = window.user_data().get::() { let mut toplevel_state = toplevel_state.lock().unwrap(); - toplevel_state - .rectangles - .retain(|(s, _)| s.id() != surface.id()); - if width != 0 || height != 0 { + if width == 0 && height == 0 { + toplevel_state + .rectangles + .retain(|(s, _)| s.id() != surface.id()); + } else { toplevel_state.rectangles.push(( surface.downgrade(), Rectangle::new((x, y).into(), (width, height).into()), diff --git a/src/xwayland.rs b/src/xwayland.rs index aba65ef5..4c2f3b55 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -115,7 +115,6 @@ impl State { &self.common.display_handle, None, std::iter::empty::<(OsString, OsString)>(), - std::iter::empty::(), true, Stdio::null(), Stdio::null(), @@ -576,15 +575,16 @@ impl Common { .filter(|(i, _)| *i != set.active), ) .flat_map(|(_, workspace)| { - let focus_last = - workspace.focus_stack.get(seat).last().cloned(); workspace - .get_fullscreen_surfaces() + .get_fullscreen() .filter(|f| { - focus_last.as_ref().is_some_and(|t| t == &f.surface) + workspace + .focus_stack + .get(seat) + .last() + .is_some_and(|t| &t == f) }) - .map(|f| f.surface.clone()) - .collect::>() + .cloned() .into_iter() .chain(workspace.mapped().flat_map(|mapped| { let active = mapped.active_window(); @@ -603,14 +603,15 @@ impl Common { })) .chain( workspace - .get_fullscreen_surfaces() + .get_fullscreen() .filter(|f| { - focus_last - .as_ref() - .is_none_or(|t| t != &f.surface) + workspace + .focus_stack + .get(seat) + .last() + .is_none_or(|t| &t != f) }) - .map(|f| f.surface.clone()) - .collect::>() + .cloned() .into_iter(), ) .chain(