From 90879145b24923acade97275248532d3ed905b76 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Tue, 20 Oct 2026 15:40:34 +0100 Subject: [PATCH] Upgrade Smithay to pinned upstream Git Pin 8a270232f1bfc416c781273c98a3f52a812a0bba and adapt protocol dispatch, input timestamps, configure state and rendering APIs. Preserve custom lock and toplevel validation, compositor-owned key repeats, and valid layer remapping sequences. Add native icon-buffer lifecycle regressions for the GoLand and Spotify launch failure. --- Cargo.lock | 771 +++++++++--------- Cargo.toml | 4 +- compositor/src/backends/direct.rs | 9 +- compositor/src/backends/direct/capture.rs | 3 + compositor/src/backends/direct/feedback.rs | 9 +- compositor/src/backends/direct/mirror.rs | 2 + compositor/src/backends/direct/redraw.rs | 7 +- compositor/src/backends/direct/transaction.rs | 2 +- compositor/src/cursor/tests.rs | 3 +- compositor/src/display_presentation.rs | 2 + compositor/src/dmabuf_feedback/tests.rs | 3 +- compositor/src/handlers/activation.rs | 6 +- compositor/src/handlers/dispatch.rs | 134 +++ .../src/handlers/layer_shell/output_tests.rs | 14 +- compositor/src/handlers/mod.rs | 113 ++- compositor/src/handlers/security_context.rs | 2 - .../src/handlers/toplevel_icon_tests.rs | 109 +++ compositor/src/handlers/xdg_shell.rs | 8 +- compositor/src/input.rs | 143 ++-- compositor/src/input/binding_mode_tests.rs | 4 +- compositor/src/input/layer_focus_tests.rs | 89 +- compositor/src/input_capture.rs | 4 +- compositor/src/ipc_events.rs | 1 + compositor/src/presentation.rs | 10 +- compositor/src/render/corner_tests.rs | 2 + compositor/src/render/mod.rs | 6 +- compositor/src/render/scene.rs | 8 +- compositor/src/render/shader.rs | 5 +- compositor/src/render/window_content.rs | 1 + compositor/src/session_lock.rs | 22 +- compositor/src/session_lock/tests.rs | 23 +- compositor/src/shell_control.rs | 1 + compositor/src/startup_tests.rs | 9 +- compositor/src/state.rs | 4 +- compositor/src/state/animation.rs | 1 + compositor/src/state/capture_privacy_tests.rs | 52 +- compositor/src/state/focus.rs | 1 + compositor/src/state/outputs.rs | 7 +- compositor/src/state/panel_clearance_tests.rs | 13 +- compositor/src/state/prediction.rs | 5 + compositor/src/state/reconciliation.rs | 13 +- .../src/state/window_lifecycle_tests.rs | 40 +- compositor/src/state/windows.rs | 27 +- compositor/src/winit.rs | 11 +- 44 files changed, 1069 insertions(+), 634 deletions(-) create mode 100644 compositor/src/handlers/dispatch.rs create mode 100644 compositor/src/handlers/toplevel_icon_tests.rs diff --git a/Cargo.lock b/Cargo.lock index ee07fca..ac8fcf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,15 +253,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f47b57fc4521e3cae26a4d45b5227f8fadee4c345be0fefd8d5d1711afb8aeb9" -[[package]] -name = "approx" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" -dependencies = [ - "num-traits", -] - [[package]] name = "approx" version = "0.5.1" @@ -482,12 +473,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atomic_float" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" - [[package]] name = "atomicwrites" version = "0.4.2" @@ -636,7 +621,7 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "cpufeatures 0.3.1", + "cpufeatures", ] [[package]] @@ -645,15 +630,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.12.1" @@ -784,51 +760,24 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "calloop" -version = "0.13.0" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" -dependencies = [ - "bitflags 2.13.2", - "log", - "polling", - "rustix 0.38.44", - "slab", - "thiserror 1.0.69", -] - -[[package]] -name = "calloop" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" +checksum = "43b32313e937c8721c9d17ee9bf60699a6402b4b7c2cb6ac1bee0ffcaa4b4e5e" dependencies = [ "bitflags 2.13.2", "nix", "polling", "rustix 1.1.5", - "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 0.14.4", + "calloop", "rustix 1.1.5", "wayland-backend", "wayland-client", @@ -878,13 +827,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] -name = "cgmath" -version = "0.18.0" +name = "chacha20" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ - "approx 0.4.0", - "num-traits", + "cfg-if", + "cpufeatures", + "rand_core 0.10.1", ] [[package]] @@ -1236,7 +1186,7 @@ dependencies = [ "rustc-hash 2.1.3", "self_cell", "skrifa 0.40.0", - "smol_str 0.3.2", + "smol_str", "swash", "sys-locale", "unicode-bidi", @@ -1263,15 +1213,6 @@ dependencies = [ "thiserror 2.0.21", ] -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - [[package]] name = "cpufeatures" version = "0.3.1" @@ -1351,16 +1292,6 @@ dependencies = [ "wgpu", ] -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "crypto-common" version = "0.2.2" @@ -1504,25 +1435,15 @@ dependencies = [ "syn 3.0.6", ] -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "crypto-common 0.1.7", -] - [[package]] name = "digest" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.12.1", + "block-buffer", "const-oid", - "crypto-common 0.2.2", + "crypto-common", ] [[package]] @@ -1567,12 +1488,6 @@ 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" @@ -1852,7 +1767,7 @@ version = "0.1.0-beta.2" dependencies = [ "ab_glyph", "async-channel", - "calloop 0.14.4", + "calloop", "ferese-activities", "ferese-animation", "ferese-config", @@ -2512,16 +2427,6 @@ dependencies = [ "libc", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "gethostname" version = "1.1.0" @@ -2564,6 +2469,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", ] [[package]] @@ -2628,6 +2534,12 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" +[[package]] +name = "glam" +version = "0.33.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37bfe73dc8ec21f54d181e5a60554327ec3f1c600c455a75ccbfc65d2106a6c4" + [[package]] name = "glib" version = "0.21.5" @@ -3071,7 +2983,7 @@ dependencies = [ "cosmic-client-toolkit", "dnd", "ferese-shape", - "glam", + "glam 0.25.0", "iced_accessibility", "lilt", "log", @@ -3081,7 +2993,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 2.1.3", "serde", - "smol_str 0.3.2", + "smol_str", "thiserror 2.0.21", "unicode-segmentation", "web-time", @@ -3200,7 +3112,7 @@ dependencies = [ "cosmic-client-toolkit", "cryoglyph", "futures", - "glam", + "glam 0.25.0", "guillotiere", "iced_debug", "iced_graphics", @@ -3268,7 +3180,7 @@ dependencies = [ "winapi", "window_clipboard", "winit 0.31.0-beta.2", - "winit-core", + "winit-core 0.31.0-beta.2", "xkbcommon 0.7.0", "xkbcommon-dl", "xkeysym", @@ -3465,9 +3377,9 @@ dependencies = [ [[package]] name = "input" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdc09524a91f9cacd26f16734ff63d7dc650daffadd2b6f84d17a285bd875a9" +checksum = "f9793345a65d71317763a33066b5d8351f8760dde8d4930fe9e39b5f14a7959d" dependencies = [ "bitflags 2.13.2", "input-sys", @@ -4530,30 +4442,6 @@ 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.13.2", - "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" @@ -4601,18 +4489,6 @@ 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-services" version = "0.3.2" @@ -4648,7 +4524,6 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.13.2", "block2 0.5.1", - "dispatch", "libc", "objc2 0.5.2", ] @@ -4665,18 +4540,6 @@ 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" @@ -4702,37 +4565,6 @@ 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.13.2", - "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" @@ -4745,30 +4577,6 @@ 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.13.2", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-core-location", - "objc2-foundation 0.2.2", -] - [[package]] name = "objc_id" version = "0.1.1" @@ -4815,6 +4623,15 @@ dependencies = [ "libredox", ] +[[package]] +name = "orbclient" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01f140a738f180203d7912dfd369936fff2fb0ad6f426c0aa007ed3e2b443e6b" +dependencies = [ + "libredox", +] + [[package]] name = "ordered-float" version = "5.4.0" @@ -4883,7 +4700,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" dependencies = [ - "approx 0.5.1", + "approx", "palette_derive", "palette_math", "phf 0.13.1", @@ -5360,6 +5177,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -5398,6 +5226,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "range-alloc" version = "0.1.5" @@ -5468,15 +5302,6 @@ dependencies = [ "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" @@ -5552,7 +5377,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b967ec6489a42067a20724f11987bb96178ea796873cbe1afd25fb93ee6f85f" dependencies = [ - "calloop 0.14.4", + "calloop", "enumflags2", "log", "rustix 1.1.5", @@ -5679,7 +5504,7 @@ version = "8.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ffa149f6aa81b58a5b3011d01a857c4ed12c7a732d2c51947a4c7c692185f0" dependencies = [ - "sha2 0.11.0", + "sha2", "walkdir", ] @@ -5899,17 +5724,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.11.0" @@ -5917,8 +5731,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", - "cpufeatures 0.3.1", - "digest 0.11.3", + "cpufeatures", + "digest", ] [[package]] @@ -6033,33 +5847,34 @@ checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" [[package]] name = "smithay" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740cea6927892bc182d5bf70c8f79806c8bc9f68f2fb96e55a30be171b63af98" +source = "git+https://github.com/Smithay/smithay?rev=8a270232f1bfc416c781273c98a3f52a812a0bba#8a270232f1bfc416c781273c98a3f52a812a0bba" dependencies = [ "appendlist", - "atomic_float", "bitflags 2.13.2", - "calloop 0.14.4", + "calloop", "cc", - "cgmath", "cursor-icon", "downcast-rs", "drm 0.14.1", "drm-ffi 0.9.1", "drm-fourcc", + "drm-sys 0.8.1", "errno", "gbm", "gl_generator", + "glam 0.33.12", "indexmap", "input", "libc", "libloading", "libseat", "pkg-config", + "portable-atomic", "profiling", - "rand 0.9.5", + "rand 0.10.3", + "reis", "rustix 1.1.5", - "sha2 0.10.9", + "siphasher", "smallvec", "tempfile", "thiserror 2.0.21", @@ -6072,33 +5887,8 @@ dependencies = [ "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-server", - "winit 0.30.13", - "xkbcommon 0.8.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.13.2", - "calloop 0.13.0", - "calloop-wayland-source 0.3.0", - "cursor-icon", - "libc", - "log", - "memmap2 0.9.11", - "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", + "winit 0.31.0-beta.3", + "xkbcommon 0.9.0", ] [[package]] @@ -6109,8 +5899,8 @@ checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ "bitflags 2.13.2", "bytemuck", - "calloop 0.14.4", - "calloop-wayland-source 0.4.1", + "calloop", + "calloop-wayland-source", "cursor-icon", "libc", "log", @@ -6123,7 +5913,7 @@ dependencies = [ "wayland-csd-frame", "wayland-cursor", "wayland-protocols", - "wayland-protocols-experimental", + "wayland-protocols-experimental 20250721.0.1", "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-scanner", @@ -6131,6 +5921,31 @@ dependencies = [ "xkeysym", ] +[[package]] +name = "smithay-client-toolkit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dc9ee14b0fdcb535f9556141bacac070c994a977d2240ee455d7438a617f00" +dependencies = [ + "bitflags 2.13.2", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "log", + "memmap2 0.9.11", + "rustix 1.1.5", + "thiserror 2.0.21", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-experimental 20251230.0.3", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + [[package]] name = "smithay-clipboard" version = "0.8.0" @@ -6142,15 +5957,6 @@ dependencies = [ "wayland-backend", ] -[[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.2" @@ -7159,6 +6965,19 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-protocols-experimental" +version = "20251230.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c6c3e7178e553d093d46999032bc79aafea9dedd71dd702c8ace7bbc25cf13" +dependencies = [ + "bitflags 2.13.2", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + [[package]] name = "wayland-protocols-misc" version = "0.3.12" @@ -7906,57 +7725,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" -[[package]] -name = "winit" -version = "0.30.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" -dependencies = [ - "ahash", - "android-activity", - "atomic-waker", - "bitflags 2.13.2", - "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 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys", - "libc", - "memmap2 0.9.11", - "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", - "redox_syscall 0.4.1", - "rustix 0.38.44", - "smithay-client-toolkit 0.19.2", - "smol_str 0.2.2", - "tracing", - "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" @@ -7969,18 +7737,45 @@ dependencies = [ "libc", "raw-window-handle", "rustix 1.1.5", - "smol_str 0.3.2", + "smol_str", "tracing", - "winit-android", - "winit-appkit", - "winit-common", - "winit-core", - "winit-orbital", - "winit-uikit", - "winit-wayland", - "winit-web", - "winit-win32", - "winit-x11", + "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", + "winit-x11 0.31.0-beta.2", +] + +[[package]] +name = "winit" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f431156a3e4f0f1b35eaaf37674e55838e3652908c8088f570466274d1902e2b" +dependencies = [ + "bitflags 2.13.2", + "cfg_aliases", + "cursor-icon", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "raw-window-handle", + "rustix 1.1.5", + "smol_str", + "tracing", + "winit-android 0.31.0-beta.3", + "winit-appkit 0.31.0-beta.3", + "winit-common 0.31.0-beta.3", + "winit-core 0.31.0-beta.3", + "winit-orbital 0.31.0-beta.3", + "winit-uikit 0.31.0-beta.3", + "winit-wayland 0.31.0-beta.3", + "winit-web 0.31.0-beta.3", + "winit-win32 0.31.0-beta.3", + "winit-x11 0.31.0-beta.3", ] [[package]] @@ -7993,9 +7788,25 @@ dependencies = [ "dpi 0.1.2 (git+https://github.com/pop-os/winit.git?rev=9567503)", "ndk", "raw-window-handle", - "smol_str 0.3.2", + "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-android" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d60d944a564986b9311e325334cc22e7e4cf726dd0ff7475fd925404215af4" +dependencies = [ + "android-activity", + "bitflags 2.13.2", + "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.3", ] [[package]] @@ -8014,10 +7825,33 @@ dependencies = [ "objc2-core-video", "objc2-foundation 0.3.2", "raw-window-handle", - "smol_str 0.3.2", + "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-appkit" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23343ec0ea7ac6aa72f38009a6ff66fb63bcf6395e0622fba72794d2a762ab42" +dependencies = [ + "bitflags 2.13.2", + "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.3", + "winit-core 0.31.0-beta.3", ] [[package]] @@ -8028,9 +7862,28 @@ dependencies = [ "memmap2 0.9.11", "objc2 0.6.4", "objc2-core-foundation", - "smol_str 0.3.2", + "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2", + "x11-dl", + "xkbcommon-dl", +] + +[[package]] +name = "winit-common" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90422ff1c04502aaaac1dad1d099791c2bbb3fbb3f823019e0ce5cdeee04025" +dependencies = [ + "block2 0.6.2", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap2 0.9.11", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.3", "x11-dl", "xkbcommon-dl", ] @@ -8045,7 +7898,23 @@ dependencies = [ "dpi 0.1.2 (git+https://github.com/pop-os/winit.git?rev=9567503)", "keyboard-types", "raw-window-handle", - "smol_str 0.3.2", + "smol_str", + "web-time", +] + +[[package]] +name = "winit-core" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8af6307236c51847199950c15cf80e0481a250bb96ce9132f5026df4ad3d0f9" +dependencies = [ + "bitflags 2.13.2", + "cursor-icon", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "keyboard-types", + "raw-window-handle", + "smol_str", + "url", "web-time", ] @@ -8057,12 +7926,29 @@ dependencies = [ "bitflags 2.13.2", "dpi 0.1.2 (git+https://github.com/pop-os/winit.git?rev=9567503)", "libredox", - "orbclient", + "orbclient 0.3.55", "raw-window-handle", "redox_event", - "smol_str 0.3.2", + "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-orbital" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278a8ae837902a3bc95dd2fd696d680da33f32130eecc29905358c9089cf6c50" +dependencies = [ + "bitflags 2.13.2", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libredox", + "orbclient 0.4.6", + "raw-window-handle", + "redox_event", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.3", ] [[package]] @@ -8077,12 +7963,33 @@ dependencies = [ "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", - "objc2-ui-kit 0.3.2", + "objc2-ui-kit", "raw-window-handle", - "smol_str 0.3.2", + "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-uikit" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83315a3ea1739c8466cf23d35e3b0a2cb20c9515d8857666b633afef484740b5" +dependencies = [ + "bitflags 2.13.2", + "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.3", + "winit-core 0.31.0-beta.3", ] [[package]] @@ -8092,7 +7999,7 @@ source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e3 dependencies = [ "ahash", "bitflags 2.13.2", - "calloop 0.14.4", + "calloop", "cursor-icon", "dpi 0.1.2 (git+https://github.com/pop-os/winit.git?rev=9567503)", "libc", @@ -8101,14 +8008,41 @@ dependencies = [ "rustix 1.1.5", "sctk-adwaita", "smithay-client-toolkit 0.20.0", - "smol_str 0.3.2", + "smol_str", "tracing", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-protocols-plasma", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-wayland" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b64ceed06de0c45886eef05102106abe1413e703384e337bc57c7e95b71f803" +dependencies = [ + "bitflags 2.13.2", + "calloop", + "cursor-icon", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "foldhash 0.2.0", + "libc", + "memmap2 0.9.11", + "percent-encoding", + "raw-window-handle", + "rustix 1.1.5", + "smithay-client-toolkit 0.21.1", + "smol_str", + "tracing", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "winit-common 0.31.0-beta.3", + "winit-core 0.31.0-beta.3", ] [[package]] @@ -8124,13 +8058,36 @@ dependencies = [ "js-sys", "pin-project", "raw-window-handle", - "smol_str 0.3.2", + "smol_str", "tracing", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "web-time", - "winit-core", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-web" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f539be45f95cc297bdfb80569aef38d925d64aec4133852a4d3fc5cb3660f1c9" +dependencies = [ + "atomic-waker", + "bitflags 2.13.2", + "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.3", ] [[package]] @@ -8142,11 +8099,30 @@ dependencies = [ "cursor-icon", "dpi 0.1.2 (git+https://github.com/pop-os/winit.git?rev=9567503)", "raw-window-handle", - "smol_str 0.3.2", + "smol_str", "tracing", "unicode-segmentation", "windows-sys 0.59.0", - "winit-core", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-win32" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fb480c41df01d351f656cbf3ad74013f8a9d22bb5b2dcab59f9167e7a0b6ec" +dependencies = [ + "bitflags 2.13.2", + "cursor-icon", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-window-handle", + "smol_str", + "tracing", + "unicode-segmentation", + "url", + "windows-sys 0.61.2", + "winit-common 0.31.0-beta.3", + "winit-core 0.31.0-beta.3", ] [[package]] @@ -8156,17 +8132,41 @@ source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e3 dependencies = [ "bitflags 2.13.2", "bytemuck", - "calloop 0.14.4", + "calloop", "cursor-icon", "dpi 0.1.2 (git+https://github.com/pop-os/winit.git?rev=9567503)", "libc", "percent-encoding", "raw-window-handle", "rustix 1.1.5", - "smol_str 0.3.2", + "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winit-x11" +version = "0.31.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb5746cd907e514b7895491a1c6f7d0cb70077f9e16928cd74ae6f987ffd96aa" +dependencies = [ + "bitflags 2.13.2", + "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.5", + "smol_str", + "tracing", + "winit-common 0.31.0-beta.3", + "winit-core 0.31.0-beta.3", "x11-dl", "x11rb", "xkbcommon-dl", @@ -8251,7 +8251,7 @@ checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" name = "xdg-desktop-portal-ferese" version = "0.1.0-beta.2" dependencies = [ - "calloop 0.14.4", + "calloop", "dirs 6.0.0", "ferese-config", "ferese-ipc", @@ -8301,6 +8301,17 @@ dependencies = [ "xkeysym", ] +[[package]] +name = "xkbcommon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a974f48060a14e95705c01f24ad9c3345022f4d97441b8a36beb7ed5c4a02d" +dependencies = [ + "libc", + "memmap2 0.9.11", + "xkeysym", +] + [[package]] name = "xkbcommon-dl" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index 3ee9ad9..4710bbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,12 +30,12 @@ rust-version = "1.95" [workspace.dependencies] ferese-shape = { git = "https://github.com/ferese-wm/ferese-shape", tag = "v0.1.0" } bitflags = "2.9.4" -calloop = { version = "0.14.4", features = ["signals"] } +calloop = { version = "0.14.5", features = ["signals"] } jiff = "0.2.37" libc = "0.2.176" iced_accessibility = { git = "https://github.com/ferese-wm/libcosmic", tag = "ferese-v0.1.3-rc.2" } libcosmic = { git = "https://github.com/ferese-wm/libcosmic", tag = "ferese-v0.1.3-rc.2", default-features = false, features = ["multi-window", "tokio", "wayland"] } -smithay = { version = "0.7.0", default-features = false, features = [ +smithay = { git = "https://github.com/Smithay/smithay", rev = "8a270232f1bfc416c781273c98a3f52a812a0bba", default-features = false, features = [ "backend_drm", "backend_gbm", "backend_libinput", diff --git a/compositor/src/backends/direct.rs b/compositor/src/backends/direct.rs index 42b6f4e..3fb054e 100644 --- a/compositor/src/backends/direct.rs +++ b/compositor/src/backends/direct.rs @@ -474,18 +474,18 @@ fn configure_libinput_device(state: &Ferese, device: &mut LibinputDevice) { if device.config_tap_finger_count() > 0 && let Err(error) = device.config_tap_set_enabled(settings.tap) { - tracing::warn!(device = device.name(), ?error, "failed to configure tap-to-click"); + tracing::warn!(device = %device.name(), ?error, "failed to configure tap-to-click"); } if device.config_scroll_has_natural_scroll() && let Err(error) = device.config_scroll_set_natural_scroll_enabled(settings.natural_scroll) { - tracing::warn!(device = device.name(), ?error, "failed to configure natural scrolling"); + tracing::warn!(device = %device.name(), ?error, "failed to configure natural scrolling"); } if device.config_dwt_is_available() && let Err(error) = device.config_dwt_set_enabled(settings.disable_while_typing) { tracing::warn!( - device = device.name(), + device = %device.name(), ?error, "failed to configure disable-while-typing" ); @@ -2264,7 +2264,7 @@ fn create_direct_output( drm_surface, None, allocator, - GbmFramebufferExporter::new(gbm.clone(), Some(render_node)), + GbmFramebufferExporter::new(gbm.clone(), Some(render_node).into()), [Fourcc::Argb8888, Fourcc::Abgr8888], renderer.dmabuf_formats(), drm.cursor_size(), @@ -2341,6 +2341,7 @@ fn create_output( let output = Output::new( name, PhysicalProperties { + serial_number: String::new(), size: (physical_size.0 as i32, physical_size.1 as i32).into(), subpixel: Subpixel::from(connector.subpixel()), make: edid_identity diff --git a/compositor/src/backends/direct/capture.rs b/compositor/src/backends/direct/capture.rs index 1da5b1b..67916fb 100644 --- a/compositor/src/backends/direct/capture.rs +++ b/compositor/src/backends/direct/capture.rs @@ -175,6 +175,7 @@ mod tests { let output = Output::new( "capture".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -273,6 +274,7 @@ mod failure_tests { let output = Output::new( "capture-failure".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -292,6 +294,7 @@ mod failure_tests { let other_output = Output::new( "other-capture".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/backends/direct/feedback.rs b/compositor/src/backends/direct/feedback.rs index 82d3841..1410473 100644 --- a/compositor/src/backends/direct/feedback.rs +++ b/compositor/src/backends/direct/feedback.rs @@ -73,7 +73,7 @@ impl OutputFeedback { // without ALLOW_PRIMARY_PLANE_SCANOUT_ANY Smithay compares the full // format with the swapchain. Renderer-only formats remain in fallback. match DmabufFeedbackBuilder::new(self.render_device, self.render_formats.iter().copied()) - .add_preference_tranche(self.scanout_device, Some(TrancheFlags::Scanout), [format]) + .add_preference_tranche(self.scanout_device, TrancheFlags::Scanout, [format], 4..=6) .build() { Ok(feedback) => self.preferred = Some(feedback), @@ -260,6 +260,7 @@ mod tests { states.states.insert( id.clone(), RenderElementState { + needs_capture: false, visible_area: 100, presentation_state: RenderElementPresentationState::Rendering { reason: None }, }, @@ -287,7 +288,7 @@ mod tests { assert!(o.preferred.is_none()); o.observe_format(Some(linear)); let expected = DmabufFeedbackBuilder::new(10, [linear, other]) - .add_preference_tranche(20, Some(TrancheFlags::Scanout), [linear]) + .add_preference_tranche(20, TrancheFlags::Scanout, [linear], 4..=6) .build() .unwrap(); assert_eq!(o.preferred.as_ref(), Some(&expected)); @@ -413,6 +414,7 @@ mod tests { for (state, expected) in [ ( RenderElementState { + needs_capture: false, visible_area: 100, presentation_state: RenderElementPresentationState::Rendering { reason: Some(RenderingReason::FormatUnsupported), @@ -422,6 +424,7 @@ mod tests { ), ( RenderElementState { + needs_capture: false, visible_area: 100, presentation_state: RenderElementPresentationState::Rendering { reason: Some(RenderingReason::ScanoutFailed), @@ -431,6 +434,7 @@ mod tests { ), ( RenderElementState { + needs_capture: false, visible_area: 0, presentation_state: RenderElementPresentationState::Skipped, }, @@ -438,6 +442,7 @@ mod tests { ), ( RenderElementState { + needs_capture: false, visible_area: 100, presentation_state: RenderElementPresentationState::ZeroCopy, }, diff --git a/compositor/src/backends/direct/mirror.rs b/compositor/src/backends/direct/mirror.rs index 05e6362..3c04a25 100644 --- a/compositor/src/backends/direct/mirror.rs +++ b/compositor/src/backends/direct/mirror.rs @@ -28,6 +28,7 @@ pub(super) fn elements( Output::new( "mirror-canvas".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "Ferese".into(), @@ -121,6 +122,7 @@ mod tests { Output::new( name.into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/backends/direct/redraw.rs b/compositor/src/backends/direct/redraw.rs index 58be599..f2f68be 100644 --- a/compositor/src/backends/direct/redraw.rs +++ b/compositor/src/backends/direct/redraw.rs @@ -279,6 +279,7 @@ mod tests { let output = Output::new( format!("cursor-test-{index}"), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -313,7 +314,7 @@ mod tests { &MotionEvent { location: (x, 500.0).into(), serial: SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); let current = [ @@ -337,7 +338,7 @@ mod tests { &MotionEvent { location: (1919.0, 500.0).into(), serial: SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); assert!(cursor_on_output(&state, &outputs[0])); @@ -351,7 +352,7 @@ mod tests { &MotionEvent { location: (x, 500.0).into(), serial: SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); assert!( diff --git a/compositor/src/backends/direct/transaction.rs b/compositor/src/backends/direct/transaction.rs index 98c63e7..1352326 100644 --- a/compositor/src/backends/direct/transaction.rs +++ b/compositor/src/backends/direct/transaction.rs @@ -83,7 +83,7 @@ pub(super) fn validate_device(device: &DirectDevice, scan: &OutputScan) -> Resul let mut buffers = Vec::new(); let mut framebuffers = Vec::new(); let mut allocator = GbmAllocator::new(device.gbm.clone(), GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT); - let exporter = GbmFramebufferExporter::new(device.gbm.clone(), Some(device.render_node)); + let exporter = GbmFramebufferExporter::new(device.gbm.clone(), Some(device.render_node).into()); let mut used_planes = HashSet::new(); let desired_crtcs = scan .selections diff --git a/compositor/src/cursor/tests.rs b/compositor/src/cursor/tests.rs index 81edbad..a4991bf 100644 --- a/compositor/src/cursor/tests.rs +++ b/compositor/src/cursor/tests.rs @@ -133,7 +133,7 @@ fn delayed_loading_does_not_block_cursor_callbacks_or_pointer_dispatch() { &MotionEvent { location: (10.0, 20.0).into(), serial: SERIAL_COUNTER.next_serial(), - time: 1, + time: smithay::backend::input::InputTime::from_millis(1), }, ); state.cursor_image(&seat, CursorImageStatus::Named(CursorIcon::Text)); @@ -162,6 +162,7 @@ fn cursor_animation_advances_and_cancels_on_hide_and_shape_change() { let output = Output::new( "cursor-test".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/display_presentation.rs b/compositor/src/display_presentation.rs index 6b461a1..ffc7e4b 100644 --- a/compositor/src/display_presentation.rs +++ b/compositor/src/display_presentation.rs @@ -76,6 +76,7 @@ mod tests { Output::new( name.into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -89,6 +90,7 @@ mod tests { states.states.insert( id.clone(), RenderElementState { + needs_capture: false, visible_area: 20, presentation_state: RenderElementPresentationState::ZeroCopy, }, diff --git a/compositor/src/dmabuf_feedback/tests.rs b/compositor/src/dmabuf_feedback/tests.rs index 33cde74..422bde8 100644 --- a/compositor/src/dmabuf_feedback/tests.rs +++ b/compositor/src/dmabuf_feedback/tests.rs @@ -66,6 +66,7 @@ fn subscriptions_update_deduplicate_and_retire_device_preferences() { let output = Output::new( "feedback-test".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -89,7 +90,7 @@ fn subscriptions_update_deduplicate_and_retire_device_preferences() { }; let fallback = DmabufFeedbackBuilder::new(10, [f]).build().unwrap(); let preferred = DmabufFeedbackBuilder::new(10, [f]) - .add_preference_tranche(20, Some(TrancheFlags::Scanout), [f]) + .add_preference_tranche(20, TrancheFlags::Scanout, [f], 4..=6) .build() .unwrap(); let global = state diff --git a/compositor/src/handlers/activation.rs b/compositor/src/handlers/activation.rs index 740dd79..a1fe670 100644 --- a/compositor/src/handlers/activation.rs +++ b/compositor/src/handlers/activation.rs @@ -234,7 +234,11 @@ mod tests { use smithay::reexports::wayland_server::protocol::wl_compositor::WlCompositor; use smithay::wayland::shell::xdg::XdgWmBaseUserData; let compositor = recipient - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let shell = recipient .create_resource::(&state.display_handle, 6, Default::default()) diff --git a/compositor/src/handlers/dispatch.rs b/compositor/src/handlers/dispatch.rs new file mode 100644 index 0000000..bb4735c --- /dev/null +++ b/compositor/src/handlers/dispatch.rs @@ -0,0 +1,134 @@ +use crate::Ferese; +use smithay::reexports::wayland_server::{ + Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, backend::ClientId, protocol as wl, +}; +use smithay::reexports::{ + wayland_protocols as protocols, wayland_protocols_misc as misc, wayland_protocols_wlr as wlr, +}; +use smithay::wayland::{Dispatch2, GlobalDispatch2}; + +// Forward stock protocol interfaces through Smithay's current dispatch API. +// Keep xdg_toplevel and ext_session_lock_v1 explicit: Ferese validates their +// requests before delegation, including ownership of the active session lock. +macro_rules! delegate_protocols { + ($($interface:path),* $(,)?) => { + $( + impl> Dispatch<$interface, U> for Ferese { + fn request( + state: &mut Self, + client: &Client, + resource: &$interface, + request: <$interface as Resource>::Request, + data: &U, + display: &DisplayHandle, + init: &mut DataInit<'_, Self>, + ) { + data.request(state, client, resource, request, display, init); + } + + fn destroyed(state: &mut Self, client: ClientId, resource: &$interface, data: &U) { + data.destroyed(state, client, resource); + } + } + + impl> GlobalDispatch<$interface, U> for Ferese { + fn bind( + state: &mut Self, + display: &DisplayHandle, + client: &Client, + resource: New<$interface>, + data: &U, + init: &mut DataInit<'_, Self>, + ) { + data.bind(state, display, client, resource, init); + } + + fn can_view(client: Client, data: &U) -> bool { + data.can_view(&client) + } + } + )* + }; +} + +delegate_protocols!( + protocols::wp::idle_inhibit::zv1::server::zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1, + protocols::wp::idle_inhibit::zv1::server::zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1, + protocols::ext::data_control::v1::server::ext_data_control_device_v1::ExtDataControlDeviceV1, + protocols::ext::data_control::v1::server::ext_data_control_manager_v1::ExtDataControlManagerV1, + protocols::ext::data_control::v1::server::ext_data_control_source_v1::ExtDataControlSourceV1, + protocols::ext::idle_notify::v1::server::ext_idle_notification_v1::ExtIdleNotificationV1, + protocols::ext::idle_notify::v1::server::ext_idle_notifier_v1::ExtIdleNotifierV1, + protocols::ext::session_lock::v1::server::ext_session_lock_manager_v1::ExtSessionLockManagerV1, + protocols::ext::session_lock::v1::server::ext_session_lock_surface_v1::ExtSessionLockSurfaceV1, + protocols::wp::alpha_modifier::v1::server::wp_alpha_modifier_surface_v1::WpAlphaModifierSurfaceV1, + protocols::wp::alpha_modifier::v1::server::wp_alpha_modifier_v1::WpAlphaModifierV1, + protocols::wp::cursor_shape::v1::server::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1, + protocols::wp::cursor_shape::v1::server::wp_cursor_shape_manager_v1::WpCursorShapeManagerV1, + protocols::wp::fractional_scale::v1::server::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1, + protocols::wp::fractional_scale::v1::server::wp_fractional_scale_v1::WpFractionalScaleV1, + protocols::wp::keyboard_shortcuts_inhibit::zv1::server::zwp_keyboard_shortcuts_inhibit_manager_v1::ZwpKeyboardShortcutsInhibitManagerV1, + protocols::wp::keyboard_shortcuts_inhibit::zv1::server::zwp_keyboard_shortcuts_inhibitor_v1::ZwpKeyboardShortcutsInhibitorV1, + protocols::wp::linux_dmabuf::zv1::server::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1, + protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1, + protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1, + protocols::wp::pointer_constraints::zv1::server::zwp_confined_pointer_v1::ZwpConfinedPointerV1, + protocols::wp::pointer_constraints::zv1::server::zwp_locked_pointer_v1::ZwpLockedPointerV1, + protocols::wp::pointer_constraints::zv1::server::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, + protocols::wp::presentation_time::server::wp_presentation::WpPresentation, + protocols::wp::presentation_time::server::wp_presentation_feedback::WpPresentationFeedback, + protocols::wp::primary_selection::zv1::server::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1, + protocols::wp::primary_selection::zv1::server::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1, + protocols::wp::primary_selection::zv1::server::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, + protocols::wp::relative_pointer::zv1::server::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, + protocols::wp::relative_pointer::zv1::server::zwp_relative_pointer_v1::ZwpRelativePointerV1, + protocols::wp::security_context::v1::server::wp_security_context_manager_v1::WpSecurityContextManagerV1, + protocols::wp::security_context::v1::server::wp_security_context_v1::WpSecurityContextV1, + protocols::wp::single_pixel_buffer::v1::server::wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1, + protocols::wp::text_input::zv3::server::zwp_text_input_manager_v3::ZwpTextInputManagerV3, + protocols::wp::text_input::zv3::server::zwp_text_input_v3::ZwpTextInputV3, + protocols::wp::viewporter::server::wp_viewport::WpViewport, + protocols::wp::viewporter::server::wp_viewporter::WpViewporter, + protocols::xdg::activation::v1::server::xdg_activation_token_v1::XdgActivationTokenV1, + protocols::xdg::activation::v1::server::xdg_activation_v1::XdgActivationV1, + protocols::xdg::decoration::zv1::server::zxdg_decoration_manager_v1::ZxdgDecorationManagerV1, + protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, + protocols::xdg::foreign::zv2::server::zxdg_exported_v2::ZxdgExportedV2, + protocols::xdg::foreign::zv2::server::zxdg_exporter_v2::ZxdgExporterV2, + protocols::xdg::foreign::zv2::server::zxdg_imported_v2::ZxdgImportedV2, + protocols::xdg::foreign::zv2::server::zxdg_importer_v2::ZxdgImporterV2, + protocols::xdg::shell::server::xdg_popup::XdgPopup, + protocols::xdg::shell::server::xdg_positioner::XdgPositioner, + protocols::xdg::shell::server::xdg_surface::XdgSurface, + protocols::xdg::shell::server::xdg_wm_base::XdgWmBase, + protocols::xdg::toplevel_icon::v1::server::xdg_toplevel_icon_manager_v1::XdgToplevelIconManagerV1, + protocols::xdg::toplevel_icon::v1::server::xdg_toplevel_icon_v1::XdgToplevelIconV1, + protocols::xdg::xdg_output::zv1::server::zxdg_output_manager_v1::ZxdgOutputManagerV1, + protocols::xdg::xdg_output::zv1::server::zxdg_output_v1::ZxdgOutputV1, + misc::zwp_input_method_v2::server::zwp_input_method_keyboard_grab_v2::ZwpInputMethodKeyboardGrabV2, + misc::zwp_input_method_v2::server::zwp_input_method_manager_v2::ZwpInputMethodManagerV2, + misc::zwp_input_method_v2::server::zwp_input_method_v2::ZwpInputMethodV2, + misc::zwp_input_method_v2::server::zwp_input_popup_surface_v2::ZwpInputPopupSurfaceV2, + wlr::data_control::v1::server::zwlr_data_control_device_v1::ZwlrDataControlDeviceV1, + wlr::data_control::v1::server::zwlr_data_control_manager_v1::ZwlrDataControlManagerV1, + wlr::data_control::v1::server::zwlr_data_control_source_v1::ZwlrDataControlSourceV1, + wlr::layer_shell::v1::server::zwlr_layer_shell_v1::ZwlrLayerShellV1, + wlr::layer_shell::v1::server::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, + wl::wl_buffer::WlBuffer, + wl::wl_callback::WlCallback, + wl::wl_compositor::WlCompositor, + wl::wl_data_device::WlDataDevice, + wl::wl_data_device_manager::WlDataDeviceManager, + wl::wl_data_source::WlDataSource, + wl::wl_keyboard::WlKeyboard, + wl::wl_output::WlOutput, + wl::wl_pointer::WlPointer, + wl::wl_region::WlRegion, + wl::wl_seat::WlSeat, + wl::wl_shm::WlShm, + wl::wl_shm_pool::WlShmPool, + wl::wl_subcompositor::WlSubcompositor, + wl::wl_subsurface::WlSubsurface, + wl::wl_surface::WlSurface, + wl::wl_touch::WlTouch, +); diff --git a/compositor/src/handlers/layer_shell/output_tests.rs b/compositor/src/handlers/layer_shell/output_tests.rs index 21d2db9..3ddf8ec 100644 --- a/compositor/src/handlers/layer_shell/output_tests.rs +++ b/compositor/src/handlers/layer_shell/output_tests.rs @@ -19,6 +19,7 @@ fn output(state: &mut Ferese, name: &str, x: i32) -> Output { let output = Output::new( name.into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -78,10 +79,18 @@ impl Client { .insert_client(server, Arc::new(ClientState::default())) .unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let shell = client - .create_resource::(&state.display_handle, 4, ()) + .create_resource::( + &state.display_handle, + 4, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, 1, 1, &[2], None); // Registry. request(&mut wire, compositor.id().protocol_id(), 0, &[3], None); @@ -281,6 +290,7 @@ fn unregistered_output_is_not_a_creation_fallback() { let ghost = Output::new( "ghost".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/handlers/mod.rs b/compositor/src/handlers/mod.rs index e142678..fa2b732 100644 --- a/compositor/src/handlers/mod.rs +++ b/compositor/src/handlers/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod activation; mod compositor; +mod dispatch; pub(crate) mod gamma_control; mod input_method; mod layer_shell; @@ -7,13 +8,15 @@ pub(crate) mod screencopy; pub(crate) mod screenshot; pub(crate) mod screenshot_worker; pub(crate) mod security_context; +#[cfg(test)] +mod toplevel_icon_tests; pub(crate) mod window_capture; mod xdg_shell; use smithay::desktop::{PopupManager, layer_map_for_output}; use smithay::input::pointer::{CursorImageStatus, PointerHandle}; +use smithay::input::tablet::TabletSeatHandler; use smithay::input::{Seat, SeatHandler, SeatState}; -use smithay::reexports::wayland_protocols::xdg::shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_wm_base}; use smithay::reexports::wayland_server::Resource; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::wayland::compositor::{TraversalAction, with_states, with_surface_tree_downward}; @@ -28,15 +31,11 @@ use smithay::wayland::output::OutputHandler; use smithay::wayland::pointer_constraints::{PointerConstraint, PointerConstraintsHandler, with_pointer_constraint}; use smithay::wayland::selection::SelectionHandler; use smithay::wayland::selection::data_device::{ - ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, set_data_device_focus, + DataDeviceHandler, DataDeviceState, WaylandDndGrabHandler, set_data_device_focus, }; use smithay::wayland::selection::primary_selection::{ PrimarySelectionHandler, PrimarySelectionState, set_primary_focus, }; -use smithay::wayland::shell::xdg::{ - XdgPositionerUserData, XdgShellState, XdgShellSurfaceUserData, XdgSurfaceUserData, XdgWmBaseUserData, -}; -use smithay::wayland::tablet_manager::TabletSeatHandler; use smithay::wayland::xdg_foreign::{XdgForeignHandler, XdgForeignState}; use smithay::wayland::xdg_toplevel_icon::XdgToplevelIconHandler; @@ -99,6 +98,7 @@ impl SeatHandler for Ferese { } impl OutputHandler for Ferese {} +impl smithay::wayland::text_input::TextInputActivation for Ferese {} impl FractionalScaleHandler for Ferese { fn new_fractional_scale(&mut self, surface: WlSurface) { @@ -285,31 +285,66 @@ impl SelectionHandler for Ferese { type SelectionUserData = (); } -impl ClientDndGrabHandler for Ferese {} -impl ServerDndGrabHandler for Ferese {} -impl TabletSeatHandler for Ferese {} +impl smithay::input::dnd::DndGrabHandler for Ferese {} + +impl WaylandDndGrabHandler for Ferese { + fn dnd_requested( + &mut self, + source: S, + _icon: Option, + seat: Seat, + serial: smithay::utils::Serial, + type_: smithay::input::dnd::GrabType, + ) { + use smithay::input::dnd::{DnDGrab, GrabType}; + match type_ { + GrabType::Pointer => { + let pointer = seat.get_pointer().expect("validated pointer drag"); + let start = pointer.grab_start_data().expect("validated pointer grab"); + pointer.set_grab( + self, + DnDGrab::new_pointer(&self.display_handle, start, source, seat), + serial, + smithay::input::pointer::Focus::Keep, + ); + } + GrabType::Touch => { + let touch = seat.get_touch().expect("validated touch drag"); + let start = touch.grab_start_data().expect("validated touch grab"); + touch.set_grab( + self, + DnDGrab::new_touch(&self.display_handle, start, source, seat), + serial, + ); + } + } + } +} +impl TabletSeatHandler for Ferese { + type ToolFocus = WlSurface; +} impl DataDeviceHandler for Ferese { - fn data_device_state(&self) -> &DataDeviceState { - &self.data_device_state + fn data_device_state(&mut self) -> &mut DataDeviceState { + &mut self.data_device_state } } impl PrimarySelectionHandler for Ferese { - fn primary_selection_state(&self) -> &PrimarySelectionState { - &self.primary_selection_state + fn primary_selection_state(&mut self) -> &mut PrimarySelectionState { + &mut self.primary_selection_state } } impl smithay::wayland::selection::wlr_data_control::DataControlHandler for Ferese { - fn data_control_state(&self) -> &smithay::wayland::selection::wlr_data_control::DataControlState { - &self.wlr_data_control_state + fn data_control_state(&mut self) -> &mut smithay::wayland::selection::wlr_data_control::DataControlState { + &mut self.wlr_data_control_state } } impl smithay::wayland::selection::ext_data_control::DataControlHandler for Ferese { - fn data_control_state(&self) -> &smithay::wayland::selection::ext_data_control::DataControlState { - &self.ext_data_control_state + fn data_control_state(&mut self) -> &mut smithay::wayland::selection::ext_data_control::DataControlState { + &mut self.ext_data_control_state } } @@ -320,47 +355,3 @@ impl XdgForeignHandler for Ferese { } impl XdgToplevelIconHandler for Ferese {} - -smithay::delegate_compositor!(Ferese); -smithay::delegate_alpha_modifier!(Ferese); -smithay::delegate_cursor_shape!(Ferese); -smithay::delegate_data_device!(Ferese); -smithay::delegate_dmabuf!(Ferese); -smithay::delegate_fractional_scale!(Ferese); -smithay::delegate_idle_inhibit!(Ferese); -smithay::delegate_idle_notify!(Ferese); -smithay::delegate_input_method_manager!(Ferese); -smithay::delegate_keyboard_shortcuts_inhibit!(Ferese); -smithay::delegate_layer_shell!(Ferese); -smithay::delegate_output!(Ferese); -smithay::delegate_pointer_constraints!(Ferese); -smithay::delegate_presentation!(Ferese); -smithay::delegate_primary_selection!(Ferese); -smithay::delegate_relative_pointer!(Ferese); -smithay::delegate_seat!(Ferese); -smithay::delegate_shm!(Ferese); -smithay::delegate_single_pixel_buffer!(Ferese); -smithay::delegate_text_input_manager!(Ferese); -smithay::delegate_viewporter!(Ferese); -smithay::delegate_xdg_activation!(Ferese); -smithay::delegate_xdg_decoration!(Ferese); -smithay::delegate_xdg_foreign!(Ferese); -smithay::reexports::wayland_server::delegate_global_dispatch!( - Ferese: [xdg_wm_base::XdgWmBase: ()] => XdgShellState -); -smithay::reexports::wayland_server::delegate_dispatch!( - Ferese: [xdg_wm_base::XdgWmBase: XdgWmBaseUserData] => XdgShellState -); -smithay::reexports::wayland_server::delegate_dispatch!( - Ferese: [xdg_positioner::XdgPositioner: XdgPositionerUserData] => XdgShellState -); -smithay::reexports::wayland_server::delegate_dispatch!( - Ferese: [xdg_popup::XdgPopup: XdgShellSurfaceUserData] => XdgShellState -); -smithay::reexports::wayland_server::delegate_dispatch!( - Ferese: [xdg_surface::XdgSurface: XdgSurfaceUserData] => XdgShellState -); -smithay::delegate_xdg_toplevel_icon!(Ferese); - -smithay::delegate_data_control!(Ferese); -smithay::delegate_ext_data_control!(Ferese); diff --git a/compositor/src/handlers/security_context.rs b/compositor/src/handlers/security_context.rs index 61b7e85..79ee424 100644 --- a/compositor/src/handlers/security_context.rs +++ b/compositor/src/handlers/security_context.rs @@ -27,5 +27,3 @@ impl SecurityContextHandler for Ferese { } } } - -smithay::delegate_security_context!(Ferese); diff --git a/compositor/src/handlers/toplevel_icon_tests.rs b/compositor/src/handlers/toplevel_icon_tests.rs new file mode 100644 index 0000000..ee71db2 --- /dev/null +++ b/compositor/src/handlers/toplevel_icon_tests.rs @@ -0,0 +1,109 @@ +use std::io::{Read, Write}; +use std::os::fd::AsRawFd; +use std::os::unix::net::UnixStream; +use std::sync::Arc; + +use smithay::reexports::calloop::EventLoop; +use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_wm_base::XdgWmBase; +use smithay::reexports::wayland_protocols::xdg::toplevel_icon::v1::server::xdg_toplevel_icon_manager_v1::XdgToplevelIconManagerV1; +use smithay::reexports::wayland_server::Resource; +use smithay::reexports::wayland_server::protocol::{wl_compositor::WlCompositor, wl_shm::WlShm}; +use smithay::wayland::GlobalData; +use smithay::wayland::shell::xdg::XdgWmBaseUserData; + +use crate::Ferese; +use crate::state::{ClientState, dispatch_test_client, test_client_request as request}; + +// Replay the native JetBrains lifecycle: assign an icon, destroy the icon +// object, then free its SHM buffer. The next sync must still reach the client. +fn icon_cleanup_messages(destroy_icon: bool) -> Vec<(u32, u16, Vec)> { + let mut events = EventLoop::try_new().unwrap(); + let mut state = crate::startup_tests::state(&mut events); + let (server, mut wire) = UnixStream::pair().unwrap(); + let client = state + .display_handle + .insert_client(server, Arc::new(ClientState::default())) + .unwrap(); + let compositor = client + .create_resource::(&state.display_handle, 6, GlobalData) + .unwrap(); + let shell = client + .create_resource::(&state.display_handle, 6, Default::default()) + .unwrap(); + let shm = client + .create_resource::(&state.display_handle, 1, GlobalData) + .unwrap(); + let manager = client + .create_resource::(&state.display_handle, 1, GlobalData) + .unwrap(); + request(&mut wire, compositor.id().protocol_id(), 0, &[2], None); + request(&mut wire, shell.id().protocol_id(), 2, &[3, 2], None); + request(&mut wire, 3, 1, &[4], None); + let mut file = tempfile::tempfile().unwrap(); + file.write_all(&0xff112233u32.to_ne_bytes().repeat(32 * 32)).unwrap(); + request( + &mut wire, + shm.id().protocol_id(), + 0, + &[5, 32 * 32 * 4], + Some(file.as_raw_fd()), + ); + request(&mut wire, 5, 0, &[6, 0, 32, 32, 128, 0], None); + request(&mut wire, manager.id().protocol_id(), 1, &[7], None); + request(&mut wire, 7, 2, &[6, 1], None); + request(&mut wire, manager.id().protocol_id(), 2, &[4, 7], None); + if destroy_icon { + request(&mut wire, 7, 0, &[], None); + } + request(&mut wire, 6, 0, &[], None); + request(&mut wire, 1, 0, &[8], None); + dispatch_test_client(&mut events, &mut state); + wire.set_nonblocking(true).unwrap(); + let mut bytes = Vec::new(); + let _ = wire.read_to_end(&mut bytes); + let mut messages = Vec::new(); + let mut offset = 0; + while offset < bytes.len() { + let object = u32::from_ne_bytes(bytes[offset..offset + 4].try_into().unwrap()); + let header = u32::from_ne_bytes(bytes[offset + 4..offset + 8].try_into().unwrap()); + let size = (header >> 16) as usize; + let arguments = bytes[offset + 8..offset + size] + .chunks_exact(4) + .map(|word| u32::from_ne_bytes(word.try_into().unwrap())) + .collect(); + messages.push((object, header as u16, arguments)); + offset += size; + } + messages +} + +#[test] +fn destroying_an_assigned_icon_before_its_buffer_keeps_the_client_connected() { + if !crate::startup_tests::private_runtime( + "handlers::toplevel_icon_tests::destroying_an_assigned_icon_before_its_buffer_keeps_the_client_connected", + ) { + return; + } + let messages = icon_cleanup_messages(true); + assert!(!messages.iter().any(|(object, opcode, _)| *object == 1 && *opcode == 0)); + assert!( + messages.iter().any(|(object, opcode, _)| *object == 8 && *opcode == 0), + "valid icon cleanup disconnected the client before its sync reply: {messages:?}" + ); +} + +#[test] +fn destroying_a_buffer_while_its_icon_is_alive_still_reports_no_buffer() { + if !crate::startup_tests::private_runtime( + "handlers::toplevel_icon_tests::destroying_a_buffer_while_its_icon_is_alive_still_reports_no_buffer", + ) { + return; + } + let messages = icon_cleanup_messages(false); + assert!( + messages.iter().any(|(object, opcode, args)| { + *object == 1 && *opcode == 0 && args.first() == Some(&7) && args.get(1) == Some(&3) + }), + "destroying a live icon's buffer must report the protocol error: {messages:?}" + ); +} diff --git a/compositor/src/handlers/xdg_shell.rs b/compositor/src/handlers/xdg_shell.rs index 8969245..c56e6aa 100644 --- a/compositor/src/handlers/xdg_shell.rs +++ b/compositor/src/handlers/xdg_shell.rs @@ -490,9 +490,7 @@ impl Dispatch for Ferese { return; } - >::request( - state, client, resource, request, data, dhandle, data_init, - ); + smithay::wayland::Dispatch2::request(data, state, client, resource, request, dhandle, data_init); } fn destroyed( @@ -501,9 +499,7 @@ impl Dispatch for Ferese { resource: &xdg_toplevel::XdgToplevel, data: &XdgShellSurfaceUserData, ) { - >::destroyed( - state, client, resource, data, - ); + smithay::wayland::Dispatch2::destroyed(data, state, client, resource); } } diff --git a/compositor/src/input.rs b/compositor/src/input.rs index f4856ae..a49e93d 100644 --- a/compositor/src/input.rs +++ b/compositor/src/input.rs @@ -180,7 +180,8 @@ impl Ferese { self.input_settings.touchpad.swipe_threshold, ); - self.swipe.start_time(std::time::Duration::from_micros(event.time())); + self.swipe + .start_time(std::time::Duration::from_micros(event.time().micros())); if self.swipe.active() { self.focus_output_at(pointer.current_location()); @@ -189,7 +190,7 @@ impl Ferese { self, &GestureSwipeBeginEvent { serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), fingers: event.fingers(), }, ); @@ -200,7 +201,7 @@ impl Ferese { self.swipe.update_at( event.delta_x(), event.delta_y(), - std::time::Duration::from_micros(event.time()), + std::time::Duration::from_micros(event.time().micros()), ); if self.swipe_navigation_blocked() { @@ -230,7 +231,7 @@ impl Ferese { seat.get_pointer().expect("seat has a pointer").gesture_swipe_update( self, &GestureSwipeUpdateEvent { - time: event.time_msec(), + time: event.time(), delta: event.delta(), }, ); @@ -242,7 +243,7 @@ impl Ferese { let cancelled = event.cancelled() || self.swipe_navigation_blocked(); let direction = self .swipe - .finish_at(cancelled, std::time::Duration::from_micros(event.time())); + .finish_at(cancelled, std::time::Duration::from_micros(event.time().micros())); let workspace_handled = self.finish_workspace_swipe(direction); let focus_handled = self.finish_focus_swipe(direction); let handled = workspace_handled || focus_handled || self.swipe.preview_started(); @@ -269,7 +270,7 @@ impl Ferese { self, &GestureSwipeEndEvent { serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), cancelled: event.cancelled(), }, ); @@ -291,6 +292,13 @@ impl Ferese { } } + // Smithay filters duplicate pressed transitions before calling + // the binding filter. Repeat only the compositor-owned action; + // clients receive their initial press and repeat it themselves. + if state == KeyState::Pressed && self.binding_mode_pressed.contains(&keycode) { + self.repeat_intercepted_key(keycode); + return; + } let serial = SERIAL_COUNTER.next_serial(); let interaction_focus = keyboard.current_focus(); let client_grab = keyboard @@ -301,7 +309,7 @@ impl Ferese { keycode, state, serial, - event.time_msec(), + event.time(), |data, modifiers, keysym| { if data.focus_cycle.is_some() { if data.session_lock.active() || data.input_capture.captures(1) { @@ -314,7 +322,7 @@ impl Ferese { if state == KeyState::Released { data.binding_mode_pressed.remove(&keycode); data.binding_mode_repeats.remove(&keycode); - data.portal_shortcuts.release(keycode, Event::time(&event)); + data.portal_shortcuts.release(keycode, Event::time(&event).micros()); if data.intercepted_keys.remove(&keycode) { return FilterResult::Intercept(()); } @@ -326,12 +334,8 @@ impl Ferese { return FilterResult::Forward; } let raw_symbols = keysym.raw_syms().into_iter().map(|symbol| symbol.raw()).collect::>(); - let first_press = data.binding_mode_pressed.insert(keycode); + data.binding_mode_pressed.insert(keycode); if data.session_lock.active() { - // Preserve ownership of keys held across the lock transition. - if !first_press && !data.intercepted_keys.contains(&keycode) { - return FilterResult::Forward; - } if let Some(step) = locked_brightness_step(keysym.modified_sym().raw()) { data.intercepted_keys.insert(keycode); // Never execute configurable commands while locked. @@ -350,29 +354,6 @@ impl Ferese { FilterResult::Forward }; } - if !first_press { - // A held key belongs to the recipient of its first - // press, even when a mode or configuration changes. - return if data.intercepted_keys.contains(&keycode) { - if !data.session_lock.active() && !data.input_capture.active() - && !data.seat.keyboard_shortcuts_inhibited() - && let Some(binding) = data.binding_mode_repeats.get(&keycode) - .filter(|binding| binding.matches(keycode, &raw_symbols, - modifiers.logo, modifiers.ctrl, modifiers.alt, modifiers.shift)) - .cloned() - { - let action = binding.action; - if let BindingAction::FocusMru(reverse) = action { - data.cycle_focus(reverse, modifiers.alt); - } else { - data.execute_binding(action); - } - } - FilterResult::Intercept(()) - } else { - FilterResult::Forward - }; - } let symbol = keysym.modified_sym().raw(); if data.binding_modes.active().is_some() && symbol == keysyms::KEY_Escape { if state == KeyState::Pressed { @@ -480,7 +461,7 @@ impl Ferese { keycode, &raw_symbols, modifiers, - Event::time(&event), + Event::time(&event).micros(), ) { data.intercepted_keys.insert(keycode); @@ -515,7 +496,7 @@ impl Ferese { } } InputEvent::PointerMotionAbsolute { event, .. } => { - self.last_pointer_time = event.time_msec(); + self.last_pointer_time = event.time(); let Some(position) = self.absolute_event_position(&event) else { return; }; @@ -532,7 +513,7 @@ impl Ferese { &MotionEvent { location: position, serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), }, ); pointer.frame(self); @@ -541,7 +522,7 @@ impl Ferese { crate::backends::direct::render_cursor(self); } InputEvent::PointerMotion { event, .. } => { - self.last_pointer_time = event.time_msec(); + self.last_pointer_time = event.time(); let pointer = self.seat.get_pointer().expect("seat has a pointer"); let position = pointer.current_location(); let focus = self.surface_under(position); @@ -564,7 +545,7 @@ impl Ferese { &RelativeMotionEvent { delta: (delta.x / scale_x, delta.y / scale_y).into(), delta_unaccel: (delta_unaccel.x / scale_x, delta_unaccel.y / scale_y).into(), - utime: event.time(), + time: event.time(), }, ); let requested = self.clamp_pointer_position(position + delta); @@ -577,7 +558,7 @@ impl Ferese { &MotionEvent { location, serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), }, ); pointer.frame(self); @@ -586,7 +567,7 @@ impl Ferese { crate::backends::direct::render_cursor(self); } InputEvent::PointerButton { event, .. } => { - self.last_pointer_time = event.time_msec(); + self.last_pointer_time = event.time(); if self.input_capture.active() { if self.input_capture.captures(2) { self.input_capture.push(serde_json::json!({"type":"button", "button":event.button_code(), "pressed":event.state() == ButtonState::Pressed})); @@ -609,7 +590,7 @@ impl Ferese { &MotionEvent { location: pointer.current_location(), serial, - time: event.time_msec(), + time: event.time(), }, ); } @@ -620,7 +601,7 @@ impl Ferese { button: event.button_code(), state: event.state(), serial, - time: event.time_msec(), + time: event.time(), }, ); pointer.frame(self); @@ -666,7 +647,7 @@ impl Ferese { popup, crate::focus_effect::BoundedFade::new(f64::from(opacity)), )); - pointer.unset_grab(self, serial, event.time_msec()); + pointer.unset_grab(self, serial, event.time()); self.focus_window_at(pointer.current_location(), serial, true); crate::backends::direct::render_surface(self, &root); } @@ -684,7 +665,7 @@ impl Ferese { button: event.button_code(), state: event.state(), serial, - time: event.time_msec(), + time: event.time(), }, ); pointer.frame(self); @@ -717,7 +698,7 @@ impl Ferese { button: event.button_code(), state: event.state(), serial, - time: event.time_msec(), + time: event.time(), }, ); pointer.frame(self); @@ -744,13 +725,13 @@ impl Ferese { button: event.button_code(), state: event.state(), serial, - time: event.time_msec(), + time: event.time(), }, ); pointer.frame(self); } InputEvent::PointerAxis { event, .. } => { - self.last_pointer_time = event.time_msec(); + self.last_pointer_time = event.time(); let source = event.source(); let horizontal = event .amount(Axis::Horizontal) @@ -777,7 +758,7 @@ impl Ferese { ) { return; } - let mut frame = AxisFrame::new(event.time_msec()).source(source); + let mut frame = AxisFrame::new(event.time()).source(source); if horizontal != 0.0 { frame = frame.value(Axis::Horizontal, horizontal); if let Some(value) = event.amount_v120(Axis::Horizontal) { @@ -829,7 +810,7 @@ impl Ferese { slot: event.slot(), location, serial, - time: event.time_msec(), + time: event.time(), }, ); } @@ -848,7 +829,7 @@ impl Ferese { &TouchMotionEvent { slot: event.slot(), location, - time: event.time_msec(), + time: event.time(), }, ); } @@ -862,7 +843,7 @@ impl Ferese { &UpEvent { slot: event.slot(), serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), }, ); } @@ -1012,6 +993,60 @@ impl Ferese { candidates.get(neighbor).copied() } + fn repeat_intercepted_key(&mut self, keycode: smithay::input::keyboard::Keycode) { + if !self.intercepted_keys.contains(&keycode) { + return; + } + let keyboard = self.seat.get_keyboard().expect("seat has a keyboard"); + let modifiers = keyboard.modifier_state(); + let raw_symbols = keyboard.with_xkb_state(self, |context| { + let xkb = context.xkb().lock().unwrap(); + xkb.raw_syms_for_key_in_layout(keycode, xkb.active_layout()) + .iter() + .map(|symbol| symbol.raw()) + .collect::>() + }); + if self.session_lock.active() { + // Repeats retain press ownership and never run configurable commands + // on the lock screen, including keys held before locking. + if let Some(step) = raw_symbols.iter().find_map(|symbol| locked_brightness_step(*symbol)) + && let Some(child) = spawn_client( + self, + ["brightnessctl", "set", step], + crate::private_client::ClientCapabilities::default(), + ) + { + crate::process::watch_client_exit(&self.loop_handle, child); + } + return; + } + if self.input_capture.active() || self.seat.keyboard_shortcuts_inhibited() { + return; + } + let Some(binding) = self + .binding_mode_repeats + .get(&keycode) + .filter(|binding| { + binding.matches( + keycode, + &raw_symbols, + modifiers.logo, + modifiers.ctrl, + modifiers.alt, + modifiers.shift, + ) + }) + .cloned() + else { + return; + }; + if let BindingAction::FocusMru(reverse) = binding.action { + self.cycle_focus(reverse, modifiers.alt); + } else { + self.execute_binding(binding.action); + } + } + fn focus_window_at(&mut self, position: Point, serial: Serial, raise: bool) { self.pending_layer_focus = None; if self.input_capture.captures(1) { diff --git a/compositor/src/input/binding_mode_tests.rs b/compositor/src/input/binding_mode_tests.rs index 1643287..62948ef 100644 --- a/compositor/src/input/binding_mode_tests.rs +++ b/compositor/src/input/binding_mode_tests.rs @@ -38,8 +38,8 @@ impl InputBackend for TestInput { #[derive(Debug)] struct TestKey(Keycode, KeyState); impl Event for TestKey { - fn time(&self) -> u64 { - 1_000 + fn time(&self) -> smithay::backend::input::InputTime { + smithay::backend::input::InputTime::from_micros(1_000) } fn device(&self) -> WinitVirtualDevice { WinitVirtualDevice diff --git a/compositor/src/input/layer_focus_tests.rs b/compositor/src/input/layer_focus_tests.rs index 2891864..7cb896e 100644 --- a/compositor/src/input/layer_focus_tests.rs +++ b/compositor/src/input/layer_focus_tests.rs @@ -29,13 +29,25 @@ fn layer_with_policy( .insert_client(server, Arc::new(ClientState::default())) .unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let layers = client - .create_resource::(&state.display_handle, 4, ()) + .create_resource::( + &state.display_handle, + 4, + smithay::wayland::GlobalData, + ) .unwrap(); let shm = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, compositor.id().protocol_id(), 0, &[2], None); request( @@ -126,6 +138,7 @@ fn on_demand_layer_focus_follows_opening_and_outside_clicks() { let output = Output::new( "focus".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -153,7 +166,7 @@ fn on_demand_layer_focus_follows_opening_and_outside_clicks() { &MotionEvent { location: inside, serial: SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); // The opening click arrives while the collapsed panel is noninteractive. @@ -181,7 +194,7 @@ fn on_demand_layer_focus_follows_opening_and_outside_clicks() { &MotionEvent { location: outside, serial: SERIAL_COUNTER.next_serial(), - time: 1, + time: smithay::backend::input::InputTime::from_millis(1), }, ); state.focus_window_at(outside, SERIAL_COUNTER.next_serial(), true); @@ -263,6 +276,7 @@ fn fixture_with_animations(animations: bool) -> (Ferese, EventLoop<'static, Fere let output = Output::new( "layers".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -289,6 +303,27 @@ fn commit_policy(state: &mut Ferese, events: &mut EventLoop<'static, Ferese>, wi dispatch(events, state); } +// Unmapping resets the layer's pending state. Reapply its policy and complete +// the initial bufferless configure/ack exchange before attaching again. +fn remap_layer( + state: &mut Ferese, + events: &mut EventLoop<'static, Ferese>, + wire: &mut UnixStream, + keyboard: u32, + level: u32, +) { + request(wire, 3, 0, &[65, 48], None); + request(wire, 3, 1, &[1 | 4], None); + request(wire, 3, 4, &[keyboard], None); + request(wire, 3, 8, &[level], None); + request(wire, 2, 6, &[], None); + dispatch(events, state); + ack_latest_configure(wire); + request(wire, 2, 1, &[5, 0, 0], None); + request(wire, 2, 6, &[], None); + dispatch(events, state); +} + #[test] fn null_buffer_commit_revokes_layer_focus_without_destroying_role() { if !crate::startup_tests::private_runtime( @@ -328,6 +363,12 @@ fn null_buffer_commit_revokes_layer_focus_without_destroying_role() { fallback, "null commit must revoke keyboard focus for policy {interactivity}" ); + // An unmapped surface is back in its initial state. Keep this commit + // valid while asserting that keyboard policy alone cannot remap it. + request(&mut wire, 3, 0, &[64, 48], None); + request(&mut wire, 3, 1, &[1 | 4], None); + request(&mut wire, 3, 4, &[interactivity], None); + request(&mut wire, 3, 8, &[2], None); request(&mut wire, 2, 6, &[], None); dispatch(&mut events, &mut state); assert_eq!( @@ -335,16 +376,7 @@ fn null_buffer_commit_revokes_layer_focus_without_destroying_role() { fallback, "unmapped commits must not reclaim focus" ); - // Reconfigure with a changed size before mapping again. This follows - // the protocol's bufferless-commit/configure/ack sequence, including - // with Smithay 0.7 which retains configure state on null commits. - request(&mut wire, 3, 0, &[65, 48], None); - request(&mut wire, 2, 6, &[], None); - dispatch(&mut events, &mut state); - ack_latest_configure(&mut wire); - request(&mut wire, 2, 1, &[5, 0, 0], None); - request(&mut wire, 2, 6, &[], None); - dispatch(&mut events, &mut state); + remap_layer(&mut state, &mut events, &mut wire, interactivity, 2); if interactivity == 2 { assert_eq!( keyboard.current_focus(), @@ -443,7 +475,11 @@ fn layer_mapping_commits_do_not_override_session_lock() { let (panel, mut wire) = layer_with_policy(&mut state, &mut events, &output, 1, 3); let client = panel.wl_surface().client().unwrap(); let manager = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, manager.id().protocol_id(), 1, &[6], None); dispatch(&mut events, &mut state); @@ -458,9 +494,7 @@ fn layer_mapping_commits_do_not_override_session_lock() { request(&mut wire, 2, 1, &[0, 0, 0], None); request(&mut wire, 2, 6, &[], None); dispatch(&mut events, &mut state); - request(&mut wire, 2, 1, &[5, 0, 0], None); - request(&mut wire, 2, 6, &[], None); - dispatch(&mut events, &mut state); + remap_layer(&mut state, &mut events, &mut wire, 1, 3); assert_eq!(keyboard.current_focus(), None, "layer remapping cannot bypass the lock"); request(&mut wire, 3, 7, &[], None); dispatch(&mut events, &mut state); @@ -532,13 +566,7 @@ fn fullscreen_hidden_top_commits_cannot_steal_keyboard_focus() { request(&mut top_wire, 2, 1, &[0, 0, 0], None); request(&mut top_wire, 2, 6, &[], None); dispatch(&mut events, &mut state); - request(&mut top_wire, 3, 0, &[65, 48], None); - request(&mut top_wire, 2, 6, &[], None); - dispatch(&mut events, &mut state); - ack_latest_configure(&mut top_wire); - request(&mut top_wire, 2, 1, &[5, 0, 0], None); - request(&mut top_wire, 2, 6, &[], None); - dispatch(&mut events, &mut state); + remap_layer(&mut state, &mut events, &mut top_wire, 1, 2); assert_eq!( keyboard.current_focus(), fallback, @@ -555,7 +583,7 @@ fn fullscreen_hidden_top_commits_cannot_steal_keyboard_focus() { &MotionEvent { location: (20., 20.).into(), serial: SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); state.set_window_fullscreen(id, true); @@ -596,7 +624,11 @@ fn valid_layer_popup_grab_survives_commits_but_not_parent_unmapping() { state.focus_window_at((20., 20.).into(), SERIAL_COUNTER.next_serial(), true); let client = top.wl_surface().client().unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let shell = client .create_resource::(&state.display_handle, 6, Default::default()) @@ -684,6 +716,7 @@ fn fullscreen_layer_eligibility_is_per_output_and_respects_overview() { let other = Output::new( "other".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/input_capture.rs b/compositor/src/input_capture.rs index f8106f5..b6292d5 100644 --- a/compositor/src/input_capture.rs +++ b/compositor/src/input_capture.rs @@ -459,7 +459,7 @@ impl crate::Ferese { &smithay::input::pointer::MotionEvent { location, serial: smithay::utils::SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); pointer.frame(self); @@ -499,7 +499,7 @@ impl crate::Ferese { &smithay::input::pointer::MotionEvent { location: from, serial: smithay::utils::SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); pointer.frame(self); diff --git a/compositor/src/ipc_events.rs b/compositor/src/ipc_events.rs index a9c5f94..51ad365 100644 --- a/compositor/src/ipc_events.rs +++ b/compositor/src/ipc_events.rs @@ -234,6 +234,7 @@ mod tests { output: Output::new( name.into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/presentation.rs b/compositor/src/presentation.rs index c3046f5..6d5e757 100644 --- a/compositor/src/presentation.rs +++ b/compositor/src/presentation.rs @@ -101,7 +101,7 @@ pub(crate) fn take_output_feedback( let visible_output = |surface: &WlSurface, _: &SurfaceData| rendered_feedback_output(output, surface.into(), rendered); let surface_flags = |surface: &WlSurface, _: &SurfaceData| { - flags | surface_presentation_feedback_flags_from_states(surface, rendered) + flags | surface_presentation_feedback_flags_from_states(surface, None, rendered) }; for window in state.space.elements().filter(|window| { @@ -288,8 +288,9 @@ impl RenderElement for PhysicalShaderElement { dst: Rectangle, damage: &[Rectangle], opaque: &[Rectangle], + cache: Option<&smithay::utils::user_data::UserDataMap>, ) -> Result<(), GlesError> { - self.inner.draw(frame, src, dst, damage, opaque) + self.inner.draw(frame, src, dst, damage, opaque, cache) } } @@ -349,6 +350,7 @@ impl RenderElement for NativeTextureElement { dst: Rectangle, damage: &[Rectangle], opaque: &[Rectangle], + _cache: Option<&smithay::utils::user_data::UserDataMap>, ) -> Result<(), GlesError> { frame.render_texture_from_to( &self.texture, @@ -532,6 +534,7 @@ mod tests { let output = Output::new( "owner".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -543,10 +546,12 @@ mod tests { assert!(rendered_feedback_output(&output, id.clone(), &states).is_none()); for state in [ RenderElementState { + needs_capture: false, visible_area: 0, presentation_state: RenderElementPresentationState::Skipped, }, RenderElementState { + needs_capture: false, visible_area: 0, presentation_state: RenderElementPresentationState::Rendering { reason: None }, }, @@ -561,6 +566,7 @@ mod tests { states.states.insert( id.clone(), RenderElementState { + needs_capture: false, visible_area: 32, presentation_state, }, diff --git a/compositor/src/render/corner_tests.rs b/compositor/src/render/corner_tests.rs index 0b4043b..e21ae14 100644 --- a/compositor/src/render/corner_tests.rs +++ b/compositor/src/render/corner_tests.rs @@ -832,6 +832,7 @@ fn window_tint_does_not_inherit_panel_geometry() { geometry, &[Rectangle::from_size(geometry.size)], &[], + None, ) .unwrap(); let _ = frame.finish().unwrap(); @@ -845,6 +846,7 @@ fn window_tint_does_not_inherit_panel_geometry() { let output = Output::new( "tint-test".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/render/mod.rs b/compositor/src/render/mod.rs index c76e4b2..27cbf28 100644 --- a/compositor/src/render/mod.rs +++ b/compositor/src/render/mod.rs @@ -243,6 +243,7 @@ impl RenderElement for BlurRenderElement { dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + _cache: Option<&smithay::utils::user_data::UserDataMap>, ) -> Result<(), GlesError> { let texture = self.texture.tex_id(); let [x, y, width, height] = self.capture_rect; @@ -558,6 +559,7 @@ impl RenderElement for RoundedSurfaceRenderElement { dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + _cache: Option<&smithay::utils::user_data::UserDataMap>, ) -> Result<(), GlesError> { match self.inner.texture() { WaylandSurfaceTexture::Texture(texture) => frame.render_texture_from_to( @@ -1036,8 +1038,8 @@ mod tests { for y in [geometry.loc.y, geometry.loc.y + geometry.size.h] { let nx = 2.0 * x as f32 / element_size.w as f32 - 1.0; let ny = 1.0 - 2.0 * y as f32 / element_size.h as f32; - let tx = matrix[0][0] * nx + matrix[1][0] * ny; - let ty = matrix[0][1] * nx + matrix[1][1] * ny; + let tx = matrix.matrix2.x_axis.x * nx + matrix.matrix2.y_axis.x * ny; + let ty = matrix.matrix2.x_axis.y * nx + matrix.matrix2.y_axis.y * ny; xs.push((tx + 1.0) * output_size.w as f32 / 2.0); ys.push((1.0 - ty) * output_size.h as f32 / 2.0); } diff --git a/compositor/src/render/scene.rs b/compositor/src/render/scene.rs index 56972fd..aa1fe84 100644 --- a/compositor/src/render/scene.rs +++ b/compositor/src/render/scene.rs @@ -351,7 +351,13 @@ fn scene_elements( elements.push(shadow.into()); } } else { - elements.extend(constrain_space_element::( + elements.extend(constrain_space_element::< + GlesRenderer, + _, + AnimatedWindowRenderElement, + _, + _, + >( renderer, &window, constrain.loc, diff --git a/compositor/src/render/shader.rs b/compositor/src/render/shader.rs index 4417581..692d30a 100644 --- a/compositor/src/render/shader.rs +++ b/compositor/src/render/shader.rs @@ -107,6 +107,7 @@ impl RenderElement for SharedPixelShaderElement { dst: Rectangle, damage: &[Rectangle], _opaque: &[Rectangle], + _cache: Option<&smithay::utils::user_data::UserDataMap>, ) -> Result<(), GlesError> { frame.render_pixel_shader_to( &self.shader, @@ -143,7 +144,9 @@ mod tests { .render(&mut target, (32, 32).into(), Transform::Normal) .unwrap(); frame.clear(Color32F::TRANSPARENT, &[rect]).unwrap(); - element.draw(&mut frame, element.src(), rect, &[rect], &[]).unwrap(); + element + .draw(&mut frame, element.src(), rect, &[rect], &[], None) + .unwrap(); let _ = frame.finish().unwrap(); } diff --git a/compositor/src/render/window_content.rs b/compositor/src/render/window_content.rs index 81196fb..79eb577 100644 --- a/compositor/src/render/window_content.rs +++ b/compositor/src/render/window_content.rs @@ -67,6 +67,7 @@ mod tests { let output = Output::new( "snapshot-test".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/session_lock.rs b/compositor/src/session_lock.rs index 9648ce6..5fba7dd 100644 --- a/compositor/src/session_lock.rs +++ b/compositor/src/session_lock.rs @@ -4,8 +4,8 @@ use std::time::{Duration, Instant}; use smithay::output::Output; use smithay::reexports::calloop::RegistrationToken; use smithay::reexports::calloop::timer::{TimeoutAction, Timer}; +#[cfg(test)] use smithay::reexports::wayland_protocols::ext::session_lock::v1::server::ext_session_lock_manager_v1::ExtSessionLockManagerV1; -use smithay::reexports::wayland_protocols::ext::session_lock::v1::server::ext_session_lock_surface_v1::ExtSessionLockSurfaceV1; use smithay::reexports::wayland_protocols::ext::session_lock::v1::server::ext_session_lock_v1; use smithay::reexports::wayland_protocols::ext::session_lock::v1::server::ext_session_lock_v1::ExtSessionLockV1; use smithay::reexports::wayland_server::protocol::wl_output::WlOutput; @@ -457,14 +457,14 @@ impl SessionLockHandler for Ferese { self.set_overview_active(false); let serial = SERIAL_COUNTER.next_serial(); if let Some(pointer) = self.seat.get_pointer() { - pointer.unset_grab(self, serial, 0); + pointer.unset_grab(self, serial, smithay::backend::input::InputTime::now()); pointer.motion( self, None, &smithay::input::pointer::MotionEvent { location: pointer.current_location(), serial, - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }, ); pointer.frame(self); @@ -512,8 +512,8 @@ impl SessionLockHandler for Ferese { } } -// Smithay delegates unlock even after posting InvalidUnlock. Check ownership -// and confirmation first so a rejected/unfinished lock cannot unlock the owner. +// Tie requests to Ferese's confirmed lock owner before delegating to Smithay. +// Rejected lockers cannot create lock surfaces or release another client's lock. impl Dispatch for Ferese { fn request( state: &mut Self, @@ -538,17 +538,16 @@ impl Dispatch for Ferese { lock.post_error(ext_session_lock_v1::Error::InvalidUnlock, "not the active lock owner"); return; } - >::request( - state, client, lock, request, data, display, data_init, - ); + smithay::wayland::Dispatch2::request(data, state, client, lock, request, display, data_init); } fn destroyed( state: &mut Self, - _: smithay::reexports::wayland_server::backend::ClientId, + client: smithay::reexports::wayland_server::backend::ClientId, lock: &ExtSessionLockV1, - _: &SessionLockState, + data: &SessionLockState, ) { + smithay::wayland::Dispatch2::destroyed(data, state, client, lock); if state.session_lock.lifecycle.owner() == Some(lock) { state.session_lock.lifecycle = Lifecycle::Orphaned; state.session_lock.surfaces.clear(); @@ -557,9 +556,6 @@ impl Dispatch for Ferese { } } } -smithay::reexports::wayland_server::delegate_global_dispatch!(Ferese: [ExtSessionLockManagerV1: smithay::wayland::session_lock::SessionLockManagerGlobalData] => SessionLockManagerState); -smithay::reexports::wayland_server::delegate_dispatch!(Ferese: [ExtSessionLockManagerV1: ()] => SessionLockManagerState); -smithay::reexports::wayland_server::delegate_dispatch!(Ferese: [ExtSessionLockSurfaceV1: smithay::wayland::session_lock::ExtLockSurfaceUserData] => SessionLockManagerState); #[cfg(test)] mod tests; diff --git a/compositor/src/session_lock/tests.rs b/compositor/src/session_lock/tests.rs index dae0b47..ac00bdc 100644 --- a/compositor/src/session_lock/tests.rs +++ b/compositor/src/session_lock/tests.rs @@ -71,6 +71,7 @@ fn mirror_must_present_protected_frame_before_lock_is_ready() { Output::new( name.into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -106,6 +107,7 @@ fn protected_fallback_frames_allow_idle_after_early_locker_crash() { let output = Output::new( "test".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -221,6 +223,7 @@ impl Fixture { let output = Output::new( name.into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -249,7 +252,11 @@ impl Fixture { .insert_client(server, Arc::new(crate::state::ClientState::default())) .unwrap(); let manager = client - .create_resource::(&self.state.display_handle, 1, ()) + .create_resource::( + &self.state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, manager.id().protocol_id(), 1, &[2]); self.dispatch(); @@ -318,7 +325,11 @@ impl Locker { request(&mut self.wire, registry, 0, &args); let compositor = self .client - .create_resource::(&fixture.state.display_handle, 6, ()) + .create_resource::( + &fixture.state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let surface_id = self.id(); request(&mut self.wire, compositor.id().protocol_id(), 0, &[surface_id]); @@ -694,7 +705,7 @@ fn lock_input_preserves_owner_click_grabs_and_rejects_retired_surfaces() { &smithay::input::pointer::MotionEvent { location: (10.0, 10.0).into(), serial, - time: 1, + time: smithay::backend::input::InputTime::from_millis(1), }, ); pointer.button( @@ -703,7 +714,7 @@ fn lock_input_preserves_owner_click_grabs_and_rejects_retired_surfaces() { button: 0x110, state: smithay::backend::input::ButtonState::Pressed, serial, - time: 2, + time: smithay::backend::input::InputTime::from_millis(2), }, ); assert!(pointer.is_grabbed()); @@ -718,7 +729,7 @@ fn lock_input_preserves_owner_click_grabs_and_rejects_retired_surfaces() { button: 0x110, state: smithay::backend::input::ButtonState::Released, serial: SERIAL_COUNTER.next_serial(), - time: 3, + time: smithay::backend::input::InputTime::from_millis(3), }, ); assert!(!pointer.is_grabbed()); @@ -728,7 +739,7 @@ fn lock_input_preserves_owner_click_grabs_and_rejects_retired_surfaces() { button: 0x110, state: smithay::backend::input::ButtonState::Pressed, serial: SERIAL_COUNTER.next_serial(), - time: 4, + time: smithay::backend::input::InputTime::from_millis(4), }, ); assert!(pointer.is_grabbed()); diff --git a/compositor/src/shell_control.rs b/compositor/src/shell_control.rs index 98060a5..4a0f20a 100644 --- a/compositor/src/shell_control.rs +++ b/compositor/src/shell_control.rs @@ -795,6 +795,7 @@ mod tests { let output = Output::new( "snapshot-test".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/startup_tests.rs b/compositor/src/startup_tests.rs index b3f9dba..bcd4105 100644 --- a/compositor/src/startup_tests.rs +++ b/compositor/src/startup_tests.rs @@ -112,6 +112,7 @@ fn nested_instances_share_a_runtime_and_route_launched_clients_to_their_own_ipc( let output = Output::new( name.into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -294,7 +295,11 @@ fn deferred_cursor_redraw_runs_after_input_lock_is_released() { .insert_client(server, Arc::new(crate::state::ClientState::default())) .unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); // wl_compositor.create_surface(new_id=2). for word in [compositor.id().protocol_id(), 12u32 << 16, 2] { @@ -314,7 +319,7 @@ fn deferred_cursor_redraw_runs_after_input_lock_is_released() { let event = MotionEvent { location: (10.0, 20.0).into(), serial: SERIAL_COUNTER.next_serial(), - time: 0, + time: smithay::backend::input::InputTime::from_millis(0), }; pointer.motion(state, Some((surface.clone(), (0.0, 0.0).into())), &event); // Smithay invokes Ferese::cursor_image while holding its real pointer lock. diff --git a/compositor/src/state.rs b/compositor/src/state.rs index e760173..ea44b50 100644 --- a/compositor/src/state.rs +++ b/compositor/src/state.rs @@ -500,7 +500,7 @@ pub struct Ferese { pub(crate) cursor_redraw_pending: bool, pub(crate) output_redraw_pending: Vec, pub(crate) locked_pointer_hint: Option, - pub(crate) last_pointer_time: u32, + pub(crate) last_pointer_time: smithay::backend::input::InputTime, pub(crate) cursor_loader: crate::cursor::Loader, pub(crate) cursor_animation: crate::cursor::Animation, pub(crate) named_cursors: HashMap, @@ -814,7 +814,7 @@ impl Ferese { cursor_redraw_pending: false, output_redraw_pending: Vec::new(), locked_pointer_hint: None, - last_pointer_time: 0, + last_pointer_time: smithay::backend::input::InputTime::from_millis(0), cursor_loader, cursor_animation: crate::cursor::Animation::default(), named_cursors, diff --git a/compositor/src/state/animation.rs b/compositor/src/state/animation.rs index 4f63860..90ec06a 100644 --- a/compositor/src/state/animation.rs +++ b/compositor/src/state/animation.rs @@ -850,6 +850,7 @@ mod tests { let output = Output::new( "pause-test".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/state/capture_privacy_tests.rs b/compositor/src/state/capture_privacy_tests.rs index 2610ea6..e98a667 100644 --- a/compositor/src/state/capture_privacy_tests.rs +++ b/compositor/src/state/capture_privacy_tests.rs @@ -86,13 +86,21 @@ pub(crate) fn window(state: &mut Ferese, events: &mut EventLoop<'static, Ferese> .insert_client(server, Arc::new(ClientState::default())) .unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let shell = client .create_resource::(&state.display_handle, 6, Default::default()) .unwrap(); let shm = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, compositor.id().protocol_id(), 0, &[2], None); request(&mut wire, shell.id().protocol_id(), 2, &[3, 2], None); @@ -141,10 +149,18 @@ fn attach_children( use smithay::reexports::wayland_server::protocol::wl_subcompositor::WlSubcompositor; let client = window.toplevel().unwrap().wl_surface().client().unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let subcompositor = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); request(wire, compositor.id().protocol_id(), 0, &[7], None); request(wire, subcompositor.id().protocol_id(), 1, &[8, 7, 2], None); @@ -242,6 +258,7 @@ fn lock_scene_draws_the_pointer_and_delivers_client_cursor_frames() { let output = Output::new( "lock-cursor".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -266,7 +283,11 @@ fn lock_scene_draws_the_pointer_and_delivers_client_cursor_frames() { let (desktop, mut wire) = window(&mut state, &mut events, 0xffff0000); let client = desktop.toplevel().unwrap().wl_surface().client().unwrap(); let manager = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, manager.id().protocol_id(), 1, &[7], None); let deadline = std::time::Instant::now() + Duration::from_secs(1); @@ -311,7 +332,11 @@ fn lock_scene_draws_the_pointer_and_delivers_client_cursor_frames() { } let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, compositor.id().protocol_id(), 0, &[8], None); request(&mut wire, 8, 1, &[6, 0, 0], None); @@ -388,6 +413,7 @@ fn capture_privacy_pixels_and_policy_transitions() { let output = Output::new( "privacy".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -563,6 +589,7 @@ fn capture_privacy_pixels_and_policy_transitions() { let second = Output::new( "second".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -649,7 +676,11 @@ fn capture_privacy_pixels_and_policy_transitions() { use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; let client = secret.toplevel().unwrap().wl_surface().client().unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut secret_wire, compositor.id().protocol_id(), 0, &[13], None); request(&mut secret_wire, 13, 1, &[6, 0, 0], None); @@ -756,6 +787,7 @@ fn resize_dependencies_protocol_and_pixels() { let output = Output::new( "resize".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -944,7 +976,11 @@ fn resize_dependencies_protocol_and_pixels() { assert_ne!(state.viewports[&workspace].motion().current, frozen); let client = b.toplevel().unwrap().wl_surface().client().unwrap(); let shm = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); let mut resized = tempfile::tempfile().unwrap(); resized.write_all(&0xff00ff00u32.to_ne_bytes().repeat(32 * 48)).unwrap(); diff --git a/compositor/src/state/focus.rs b/compositor/src/state/focus.rs index 730b64c..bf351ff 100644 --- a/compositor/src/state/focus.rs +++ b/compositor/src/state/focus.rs @@ -150,6 +150,7 @@ mod tests { let output = Output::new( "focus".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/state/outputs.rs b/compositor/src/state/outputs.rs index f8664bc..23fee87 100644 --- a/compositor/src/state/outputs.rs +++ b/compositor/src/state/outputs.rs @@ -216,8 +216,8 @@ mod tests { struct TestButton(ButtonState); impl Event for TestButton { - fn time(&self) -> u64 { - 1_000 + fn time(&self) -> smithay::backend::input::InputTime { + smithay::backend::input::InputTime::from_micros(1_000) } fn device(&self) -> WinitVirtualDevice { WinitVirtualDevice @@ -241,7 +241,7 @@ mod tests { &MotionEvent { location: position, serial: SERIAL_COUNTER.next_serial(), - time: 1, + time: smithay::backend::input::InputTime::from_millis(1), }, ); pointer.frame(state); @@ -268,6 +268,7 @@ mod tests { let output = Output::new( name.into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/state/panel_clearance_tests.rs b/compositor/src/state/panel_clearance_tests.rs index fa4d61d..2102035 100644 --- a/compositor/src/state/panel_clearance_tests.rs +++ b/compositor/src/state/panel_clearance_tests.rs @@ -33,6 +33,7 @@ fn every_panel_style_owns_clearance_at_its_reserved_edge() { let output = Output::new( "clearance".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -60,10 +61,18 @@ fn every_panel_style_owns_clearance_at_its_reserved_edge() { .insert_client(server, Arc::new(ClientState::default())) .unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let layers = client - .create_resource::(&state.display_handle, 4, ()) + .create_resource::( + &state.display_handle, + 4, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut wire, compositor.id().protocol_id(), 0, &[2]); let mut namespace = b"ferese-shell-top-bar\0".to_vec(); diff --git a/compositor/src/state/prediction.rs b/compositor/src/state/prediction.rs index 7f24f00..48e275c 100644 --- a/compositor/src/state/prediction.rs +++ b/compositor/src/state/prediction.rs @@ -427,6 +427,7 @@ mod tests { let output = Output::new( "resize-idle".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -548,6 +549,7 @@ mod tests { let output = Output::new( format!("focus-{index}"), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -657,6 +659,7 @@ mod tests { let output = Output::new( "overview-slide-test".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -780,6 +783,7 @@ mod tests { let output = Output::new( "forecast-test".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -829,6 +833,7 @@ mod tests { let other = Output::new( "other-forecast".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/state/reconciliation.rs b/compositor/src/state/reconciliation.rs index 17d6770..abda2da 100644 --- a/compositor/src/state/reconciliation.rs +++ b/compositor/src/state/reconciliation.rs @@ -214,6 +214,7 @@ mod tests { output: Output::new( name.into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -250,7 +251,11 @@ mod tests { .insert_client(server, Arc::new(ClientState::default())) .unwrap(); let compositor = client - .create_resource::(&state.display_handle, 6, ()) + .create_resource::( + &state.display_handle, + 6, + smithay::wayland::GlobalData, + ) .unwrap(); let shell = client .create_resource::(&state.display_handle, 6, Default::default()) @@ -519,7 +524,11 @@ mod tests { .insert_client(server, Arc::new(ClientState::default())) .unwrap(); let lock = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); request(&mut lock_wire, lock.id().protocol_id(), 1, &[2]); event_loop.dispatch(Duration::from_millis(10), &mut state).unwrap(); diff --git a/compositor/src/state/window_lifecycle_tests.rs b/compositor/src/state/window_lifecycle_tests.rs index d14ceff..4f93b19 100644 --- a/compositor/src/state/window_lifecycle_tests.rs +++ b/compositor/src/state/window_lifecycle_tests.rs @@ -11,6 +11,7 @@ fn fixture() -> (smithay::reexports::calloop::EventLoop<'static, Ferese>, Ferese let output = Output::new( "test".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), @@ -778,7 +779,11 @@ fn floating_maximize_and_restore_work_in_both_layouts() { use std::os::fd::AsRawFd; let client = window.toplevel().unwrap().wl_surface().client().unwrap(); let shm = client - .create_resource::(&state.display_handle, 1, ()) + .create_resource::( + &state.display_handle, + 1, + smithay::wayland::GlobalData, + ) .unwrap(); let (width, height) = (maximized.width.round() as u32, maximized.height.round() as u32); let mut file = tempfile::tempfile().unwrap(); @@ -803,14 +808,9 @@ fn floating_maximize_and_restore_work_in_both_layouts() { next_object += 2; request(&mut wire, 2, 6, &[], None); dispatch(&mut events, &mut state); - assert!( - window - .toplevel() - .unwrap() - .current_state() - .states - .contains(xdg_toplevel::State::Maximized) - ); + assert!(window.toplevel().unwrap().with_committed_state(|state| { + state.is_some_and(|state| state.states.contains(xdg_toplevel::State::Maximized)) + })); state.set_window_maximized(id, false); assert_eq!(state.windows.geometry(&id).unwrap().logical, normal, "{mode:?}"); @@ -820,14 +820,9 @@ fn floating_maximize_and_restore_work_in_both_layouts() { request(&mut wire, 2, 1, &[6, 0, 0], None); request(&mut wire, 2, 6, &[], None); dispatch(&mut events, &mut state); - assert!( - !window - .toplevel() - .unwrap() - .current_state() - .states - .contains(xdg_toplevel::State::Maximized) - ); + assert!(!window.toplevel().unwrap().with_committed_state(|state| { + state.is_some_and(|state| state.states.contains(xdg_toplevel::State::Maximized)) + })); assert_eq!( state.workspaces.placement(id), Some(WindowPlacement::Floating { rect: normal }) @@ -846,7 +841,7 @@ fn malformed_resize_limits_disconnect_only_the_client_and_motion_survives() { let (mut events, mut state, _) = fixture(); for (minimum, maximum) in [ - ((800, 0), (400, 0)), + ((800i32, 0), (400, 0)), ((0, 800), (0, 400)), ((-1, 0), (0, 0)), ((0, 0), (-1, 0)), @@ -883,10 +878,14 @@ fn malformed_resize_limits_disconnect_only_the_client_and_motion_survives() { &MotionEvent { location: (120.0, 130.0).into(), serial: SERIAL_COUNTER.next_serial(), - time: 1, + time: smithay::backend::input::InputTime::from_millis(1), }, ); - pointer.unset_grab(&mut state, SERIAL_COUNTER.next_serial(), 2); + pointer.unset_grab( + &mut state, + SERIAL_COUNTER.next_serial(), + smithay::backend::input::InputTime::from_millis(2), + ); wire.set_nonblocking(true).unwrap(); let mut messages = Vec::new(); let _ = wire.read_to_end(&mut messages); @@ -1310,6 +1309,7 @@ fn shell_can_move_a_window_to_the_current_workspace_on_another_output() { let second = Output::new( "second".into(), smithay::output::PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: smithay::output::Subpixel::Unknown, make: "test".into(), diff --git a/compositor/src/state/windows.rs b/compositor/src/state/windows.rs index 5350358..bc0d344 100644 --- a/compositor/src/state/windows.rs +++ b/compositor/src/state/windows.rs @@ -531,11 +531,8 @@ impl Ferese { return; }; - let serial = with_states(surface, |states| { - states - .data_map - .get::() - .and_then(|data| data.lock().ok().and_then(|data| data.current_serial)) + let serial = window.toplevel().and_then(|toplevel| { + toplevel.with_cached_state(|state| state.last_acked.as_ref().map(|configure| configure.serial)) }); if !transaction.accepts(serial) { return; @@ -601,15 +598,10 @@ impl Ferese { let Some(&id) = self.windows.ids().get(window) else { return; }; - // current_serial is promoted by Smithay on commit, unlike - // configure_serial, which only records an acknowledgement. + // Read the acknowledgement attached to this commit, not a newer ack + // that arrived without its corresponding buffer. let committed_serial = window.toplevel().and_then(|toplevel| { - with_states(toplevel.wl_surface(), |states| { - states - .data_map - .get::() - .and_then(|data| data.lock().ok().and_then(|data| data.current_serial)) - }) + toplevel.with_cached_state(|state| state.last_acked.as_ref().map(|configure| configure.serial)) }); if self .windows @@ -687,14 +679,17 @@ impl Ferese { // Never let an old buffer undo a newer resize or a fullscreen transition. self.windows.update(id, |w| w.placement_anchor = None); let settled_configure = window.toplevel().is_some_and(|toplevel| { + let committed = toplevel.with_cached_state(|state| state.last_acked.clone()); with_states(toplevel.wl_surface(), |states| { states.data_map.get::().is_some_and(|data| { let Ok(data) = data.lock() else { return false }; floating_commit_is_current( data.pending_configures().is_empty(), - data.current_serial, - data.configure_serial, - data.current.states.contains(xdg_toplevel::State::Resizing), + committed.as_ref().map(|configure| configure.serial), + data.last_acked.as_ref().map(|configure| configure.serial), + committed + .as_ref() + .is_some_and(|configure| configure.state.states.contains(xdg_toplevel::State::Resizing)), ) }) }) diff --git a/compositor/src/winit.rs b/compositor/src/winit.rs index 290fafb..2db693e 100644 --- a/compositor/src/winit.rs +++ b/compositor/src/winit.rs @@ -45,12 +45,15 @@ pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<() refresh: backend .window() .current_monitor() - .and_then(|monitor| monitor.refresh_rate_millihertz()) + .and_then(|monitor| monitor.current_video_mode()) + .and_then(|mode| mode.refresh_rate_millihertz()) + .map(|rate| rate.get()) .unwrap_or(60_000) as i32, }; let output = Output::new( "ferese-winit".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "Ferese".into(), @@ -104,7 +107,9 @@ pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<() let rate = backend .window() .current_monitor() - .and_then(|monitor| monitor.refresh_rate_millihertz()) + .and_then(|monitor| monitor.current_video_mode()) + .and_then(|mode| mode.refresh_rate_millihertz()) + .map(|rate| rate.get()) .unwrap_or(60_000) as i32; if !resize_nested_output(state, &output, &drawable, (size.w, size.h), scale_factor, rate) { return; @@ -355,6 +360,7 @@ mod tests { let output = Output::new( "nested".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(), @@ -471,6 +477,7 @@ mod tests { let output = Output::new( "nested".into(), PhysicalProperties { + serial_number: String::new(), size: (0, 0).into(), subpixel: Subpixel::Unknown, make: "test".into(),