From d4c8d1c465e59fa9d2adaabfca118812653707f4 Mon Sep 17 00:00:00 2001 From: Stephen Hellings Date: Mon, 9 Mar 2026 15:54:29 -0400 Subject: [PATCH] Attempt 5... --- Cargo.lock | 378 ++++++++++++++++++--------- Cargo.toml | 3 + nohup.out | 1 + src/config.rs | 12 + src/cursor.rs | 155 +++++++++++ src/handlers/input.rs | 13 + src/lib.rs | 1 + src/main.rs | 296 +++++++++++++++++++-- src/nested.rs | 45 +++- src/state.rs | 26 ++ whatever.txt | 589 +++++++++++++++++++++++++++++++++++++++++- 11 files changed, 1351 insertions(+), 168 deletions(-) create mode 100644 nohup.out create mode 100644 src/cursor.rs diff --git a/Cargo.lock b/Cargo.lock index 1c5bffc..5065c25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -323,9 +323,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cef5b5a1a6827c7322ae2a636368a573006b27cfa76c7ebd53e834daeaab6a" +checksum = "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368" dependencies = [ "smallvec", "target-lexicon", @@ -682,6 +682,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.5.0" @@ -815,10 +821,23 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "gl" version = "0.14.0" @@ -845,6 +864,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -875,6 +903,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "indexmap" version = "2.13.0" @@ -882,7 +916,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -985,10 +1021,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "libc" -version = "0.2.182" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libloading" @@ -1658,6 +1700,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -1697,9 +1749,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.38.4" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" dependencies = [ "memchr", ] @@ -1719,6 +1771,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.9.2" @@ -1880,6 +1938,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -2087,12 +2151,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2132,7 +2196,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix 1.1.4", "windows-sys 0.61.2", @@ -2233,9 +2297,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.0.3+spec-1.1.0" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7614eaf19ad818347db24addfa201729cf2a9b6fdfd9eb0ab870fcacc606c0c" +checksum = "399b1124a3c9e16766831c6bba21e50192572cdd98706ea114f9502509686ffc" dependencies = [ "indexmap", "serde_core", @@ -2266,9 +2330,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.3+spec-1.1.0" +version = "0.25.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a07913e63758bc95142d9863a5a45173b71515e68b690cad70cf99c3255ce1" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" dependencies = [ "indexmap", "toml_datetime 1.0.0+spec-1.1.0", @@ -2401,10 +2465,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] -name = "uuid" -version = "1.21.0" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "uuid" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ "js-sys", "serde_core", @@ -2454,6 +2524,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.114" @@ -2514,10 +2593,44 @@ dependencies = [ ] [[package]] -name = "wayland-backend" -version = "0.3.12" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wayland-backend" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa75f400b7f719bcd68b3f47cd939ba654cedeef690f486db71331eec4c6a406" dependencies = [ "cc", "downcast-rs", @@ -2529,9 +2642,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.12" +version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec" +checksum = "ab51d9f7c071abeee76007e2b742499e535148035bb835f97aaed1338cf516c3" dependencies = [ "bitflags 2.11.0", "rustix 1.1.4", @@ -2552,9 +2665,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.12" +version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5864c4b5b6064b06b1e8b74ead4a98a6c45a285fe7a0e784d24735f011fdb078" +checksum = "4b3298683470fbdc6ca40151dfc48c8f2fd4c41a26e13042f801f85002384091" dependencies = [ "rustix 1.1.4", "wayland-client", @@ -2563,9 +2676,9 @@ dependencies = [ [[package]] name = "wayland-egl" -version = "0.32.9" +version = "0.32.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2c9ef35f3b2e11d5709d8e75dc1e7e064fd8eec5d705d56073fafca85de854" +checksum = "429e5852d67d4be674b0e413962186b5115f77012e765617ee97b6480d5d6ea7" dependencies = [ "wayland-backend", "wayland-sys", @@ -2573,9 +2686,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.10" +version = "0.32.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3" +checksum = "b23b5df31ceff1328f06ac607591d5ba360cf58f90c8fad4ac8d3a55a3c4aec7" dependencies = [ "bitflags 2.11.0", "wayland-backend", @@ -2586,9 +2699,9 @@ dependencies = [ [[package]] name = "wayland-protocols-misc" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791c58fdeec5406aa37169dd815327d1e47f334219b523444bc26d70ceb4c34e" +checksum = "429b99200febaf95d4f4e46deff6fe4382bcff3280ee16a41cf887b3c3364984" dependencies = [ "bitflags 2.11.0", "wayland-backend", @@ -2599,9 +2712,9 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa98634619300a535a9a97f338aed9a5ff1e01a461943e8346ff4ae26007306b" +checksum = "d392fc283a87774afc9beefcd6f931582bb97fe0e6ced0b306a62cb1d026527c" dependencies = [ "bitflags 2.11.0", "wayland-backend", @@ -2612,9 +2725,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3" +checksum = "78248e4cc0eff8163370ba5c158630dcae1f3497a586b826eca2ef5f348d6235" dependencies = [ "bitflags 2.11.0", "wayland-backend", @@ -2626,9 +2739,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.8" +version = "0.31.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3" +checksum = "c86287151a309799b821ca709b7345a048a2956af05957c89cb824ab919fa4e3" dependencies = [ "proc-macro2", "quick-xml", @@ -2637,9 +2750,9 @@ dependencies = [ [[package]] name = "wayland-server" -version = "0.31.11" +version = "0.31.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9297ab90f8d1f597711d36455c5b1b2290eca59b8134485e377a296b80b118c9" +checksum = "63736a4a73e781cf6a736aa32c5d6773c3eb5389197562742a8c611b49b5e359" dependencies = [ "bitflags 2.11.0", "downcast-rs", @@ -2650,9 +2763,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd" +checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17" dependencies = [ "dlib", "libc", @@ -2688,7 +2801,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -2733,15 +2846,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -2790,30 +2894,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -2832,12 +2919,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -2856,12 +2937,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -2880,24 +2955,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -2916,12 +2979,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -2940,12 +2997,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -2964,12 +3015,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -2988,17 +3033,11 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winit" -version = "0.30.12" +version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" dependencies = [ "ahash", "android-activity", @@ -3047,9 +3086,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] @@ -3059,6 +3098,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "wo" @@ -3082,13 +3203,14 @@ dependencies = [ "shellexpand", "smithay", "tokio", - "toml 1.0.3+spec-1.1.0", + "toml 1.0.6+spec-1.1.0", "tracing", "tracing-subscriber", "udev", "wayland-backend", "wayland-protocols", "wayland-server", + "xcursor", "xkbcommon 0.9.0", "zbus", ] @@ -3236,18 +3358,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c7f7e43..fae4f03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,9 @@ input = "0.9" udev = "0.9" xkbcommon = "0.9" +# Cursor themes +xcursor = "0.3" + # Rendering pixman = "0.2" drm-fourcc = "2.2.0" diff --git a/nohup.out b/nohup.out new file mode 100644 index 0000000..5939d52 --- /dev/null +++ b/nohup.out @@ -0,0 +1 @@ +error: Script not found "dev" diff --git a/src/config.rs b/src/config.rs index 3b3db92..0d8e0da 100644 --- a/src/config.rs +++ b/src/config.rs @@ -81,6 +81,14 @@ pub struct CompositorConfig { /// Pinned applications for the launcher dock #[serde(default)] pub applications: Vec, + + /// XCursor theme name (default: "breeze_cursors") + #[serde(default = "default_cursor_theme")] + pub cursor_theme: String, + + /// Cursor size in pixels (default: 24) + #[serde(default = "default_cursor_size")] + pub cursor_size: u32, } impl Default for CompositorConfig { @@ -100,6 +108,8 @@ impl Default for CompositorConfig { enable_syscalls: false, focus_notify: false, applications: vec![], + cursor_theme: default_cursor_theme(), + cursor_size: default_cursor_size(), } } } @@ -265,6 +275,8 @@ fn default_fps() -> u32 { 60 } fn default_format() -> String { "ARGB8888".into() } fn default_asset_prefix() -> String { "file".into() } fn default_true() -> bool { true } +fn default_cursor_theme() -> String { "breeze_cursors".into() } +fn default_cursor_size() -> u32 { 24 } fn expand_path(s: &str) -> String { shellexpand::full(s) diff --git a/src/cursor.rs b/src/cursor.rs new file mode 100644 index 0000000..5a28c96 --- /dev/null +++ b/src/cursor.rs @@ -0,0 +1,155 @@ +//! XCursor theme loading and per-shape texture caching. +//! +//! Loads cursor images from an installed XCursor theme and converts them to +//! GLES textures on first use, caching the result for subsequent frames. + +use smithay::backend::allocator::Fourcc; +use smithay::backend::renderer::gles::GlesRenderer; +use smithay::backend::renderer::gles::GlesTexture; +use smithay::backend::renderer::ImportMem; +use smithay::utils::{Buffer as BufferCoord, Size}; +use std::collections::HashMap; +use tracing::{info, warn}; + +/// Cached cursor texture with its hotspot offset. +#[derive(Clone)] +pub struct CursorImage { + pub texture: GlesTexture, + pub width: u32, + pub height: u32, + pub xhot: u32, + pub yhot: u32, +} + +/// Manages cursor theme loading and GL texture caching. +pub struct CursorThemeManager { + theme: xcursor::CursorTheme, + size: u32, + cache: HashMap>, +} + +impl CursorThemeManager { + /// Load an XCursor theme by name with the given nominal cursor size. + pub fn new(theme_name: &str, size: u32) -> Self { + info!( + "Loading cursor theme '{}' (size {})", + theme_name, size + ); + let theme = xcursor::CursorTheme::load(theme_name); + Self { + theme, + size, + cache: HashMap::new(), + } + } + + /// Get (or lazily load) the GL texture for the given cursor icon name. + /// + /// Returns `None` if the icon cannot be found in the theme or the texture + /// import fails. + pub fn get_cursor( + &mut self, + name: &str, + renderer: &mut GlesRenderer, + ) -> Option<&CursorImage> { + if !self.cache.contains_key(name) { + let img = self.load_cursor(name, renderer); + self.cache.insert(name.to_string(), img); + } + self.cache.get(name).and_then(|opt| opt.as_ref()) + } + + fn load_cursor( + &self, + name: &str, + renderer: &mut GlesRenderer, + ) -> Option { + let icon_path = self.theme.load_icon(name).or_else(|| { + // Try common XCursor aliases + let fallback = match name { + "default" => Some("left_ptr"), + "pointer" => Some("hand2"), + "text" => Some("xterm"), + "wait" => Some("watch"), + "progress" => Some("left_ptr_watch"), + "help" => Some("question_arrow"), + "crosshair" => Some("cross"), + "move" => Some("fleur"), + "not-allowed" => Some("crossed_circle"), + "no-drop" => Some("crossed_circle"), + "grab" => Some("openhand"), + "grabbing" => Some("closedhand"), + "e-resize" => Some("right_side"), + "w-resize" => Some("left_side"), + "n-resize" => Some("top_side"), + "s-resize" => Some("bottom_side"), + "ne-resize" => Some("top_right_corner"), + "nw-resize" => Some("top_left_corner"), + "se-resize" => Some("bottom_right_corner"), + "sw-resize" => Some("bottom_left_corner"), + "ew-resize" => Some("sb_h_double_arrow"), + "ns-resize" => Some("sb_v_double_arrow"), + "nesw-resize" => Some("fd_double_arrow"), + "nwse-resize" => Some("bd_double_arrow"), + "col-resize" => Some("sb_h_double_arrow"), + "row-resize" => Some("sb_v_double_arrow"), + "all-resize" | "all-scroll" => Some("fleur"), + "context-menu" => Some("left_ptr"), + "vertical-text" => Some("xterm"), + "alias" => Some("link"), + "copy" => Some("copy"), + "cell" => Some("plus"), + "zoom-in" => Some("zoom_in"), + "zoom-out" => Some("zoom_out"), + _ => None, + }; + fallback.and_then(|fb| self.theme.load_icon(fb)) + })?; + + let data = std::fs::read(&icon_path).ok()?; + let images = xcursor::parser::parse_xcursor(&data)?; + + // Pick the image closest to our target size. + let best = images + .iter() + .min_by_key(|img| (img.size as i32 - self.size as i32).unsigned_abs())?; + + // XCursor pixels are ARGB (native byte order). Convert to RGBA for + // GL import with Fourcc::Abgr8888 (which is RGBA in memory on little-endian). + let pixel_count = (best.width * best.height) as usize; + let mut rgba = Vec::with_capacity(pixel_count * 4); + for pixel_argb in best.pixels_argb.chunks_exact(4) { + // ARGB → RGBA + rgba.push(pixel_argb[1]); // R + rgba.push(pixel_argb[2]); // G + rgba.push(pixel_argb[3]); // B + rgba.push(pixel_argb[0]); // A + } + + let size = Size::from((best.width as i32, best.height as i32)); + match renderer.import_memory(&rgba, Fourcc::Abgr8888, size, false) { + Ok(texture) => { + info!( + "Loaded cursor '{}' ({}x{}, hotspot {},{}) from {}", + name, + best.width, + best.height, + best.xhot, + best.yhot, + icon_path.display() + ); + Some(CursorImage { + texture, + width: best.width, + height: best.height, + xhot: best.xhot, + yhot: best.yhot, + }) + } + Err(e) => { + warn!("Failed to import cursor texture for '{}': {e}", name); + None + } + } + } +} diff --git a/src/handlers/input.rs b/src/handlers/input.rs index 834d906..cc69e85 100644 --- a/src/handlers/input.rs +++ b/src/handlers/input.rs @@ -85,6 +85,13 @@ impl WoState { // the XKB offset before forwarding. let evdev_key = u32::from(key_code).saturating_sub(8); + // Check if a client is inhibiting compositor keyboard shortcuts + // (e.g. fullscreen games requesting all key events). + let shortcuts_inhibited = { + use smithay::wayland::keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat; + self.seat.keyboard_shortcuts_inhibited() + }; + // Use non-blocking send to avoid input stalls. let wayland_has_focus = self .seat @@ -116,6 +123,12 @@ impl WoState { serial, time, |state, modifiers, _handle| { + // When keyboard shortcuts are inhibited, forward all keys to the + // focused client without intercepting compositor shortcuts. + if shortcuts_inhibited { + return FilterResult::Forward; + } + if press && state.can_switch_vt { if let Some(vt) = evdev_function_key_to_vt(evdev_key) { // Accept Ctrl+Alt+Fn and Meta+Alt+Fn. diff --git a/src/lib.rs b/src/lib.rs index 49c2f3c..6231975 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ //! Wo Wayland compositor library pub mod config; +pub mod cursor; pub mod dmabuf; pub mod electron; pub mod handlers; diff --git a/src/main.rs b/src/main.rs index dbd5886..e105a86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod backend; mod config; +mod cursor; mod dmabuf; mod electron; mod handlers; @@ -24,7 +25,7 @@ use smithay::{ Swapchain, }, drm::{ - gbm::framebuffer_from_bo, DrmDevice, DrmDeviceFd, DrmNode, PlaneConfig, + gbm::{framebuffer_from_bo, GbmFramebuffer}, DrmDevice, DrmDeviceFd, DrmNode, PlaneConfig, PlaneState, }, egl::{EGLContext, EGLDisplay}, @@ -42,7 +43,9 @@ use smithay::{ utils::{Buffer, DeviceFd, Physical, Rectangle, Transform}, wayland::{ xdg_activation::XdgActivationHandler, + xwayland_shell::XWaylandShellState, }, + xwayland::{xwm::X11Wm, XWayland, XWaylandEvent}, }; use std::path::Path; use std::{ @@ -102,6 +105,99 @@ struct EventLoopData { pending_slot: Option>, } +/// Newtype wrapper around `Option` for the DRM calloop event +/// loop. The `Option` is needed because the event loop is created before the +/// DRM resources are fully initialized (`None` during pre-init, `Some` after). +/// The newtype allows implementing XWayland traits (orphan rules forbid impls +/// on `Option` directly). +struct DrmLoopData(Option); + +impl std::ops::Deref for DrmLoopData { + type Target = Option; + fn deref(&self) -> &Self::Target { &self.0 } +} +impl std::ops::DerefMut for DrmLoopData { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +} + +// XwmHandler delegation so X11Wm calloop sources work on the DRM event loop. +impl smithay::xwayland::xwm::XwmHandler for DrmLoopData { + fn xwm_state(&mut self, xwm: smithay::xwayland::xwm::XwmId) -> &mut X11Wm { + self.0.as_mut().expect("EventLoopData initialized").state.xwm_state(xwm) + } + fn new_window(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.new_window(xwm, window) + } + fn new_override_redirect_window(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.new_override_redirect_window(xwm, window) + } + fn map_window_request(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.map_window_request(xwm, window) + } + fn mapped_override_redirect_window(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.mapped_override_redirect_window(xwm, window) + } + fn unmapped_window(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.unmapped_window(xwm, window) + } + fn destroyed_window(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.destroyed_window(xwm, window) + } + fn configure_request( + &mut self, + xwm: smithay::xwayland::xwm::XwmId, + window: smithay::xwayland::xwm::X11Surface, + x: Option, + y: Option, + w: Option, + h: Option, + reorder: Option, + ) { + self.0.as_mut().expect("EventLoopData initialized").state.configure_request(xwm, window, x, y, w, h, reorder) + } + fn configure_notify( + &mut self, + xwm: smithay::xwayland::xwm::XwmId, + window: smithay::xwayland::xwm::X11Surface, + geometry: smithay::utils::Rectangle, + above: Option, + ) { + self.0.as_mut().expect("EventLoopData initialized").state.configure_notify(xwm, window, geometry, above) + } + fn resize_request( + &mut self, + xwm: smithay::xwayland::xwm::XwmId, + window: smithay::xwayland::xwm::X11Surface, + button: u32, + resize_edge: smithay::xwayland::xwm::ResizeEdge, + ) { + self.0.as_mut().expect("EventLoopData initialized").state.resize_request(xwm, window, button, resize_edge) + } + fn move_request(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface, button: u32) { + self.0.as_mut().expect("EventLoopData initialized").state.move_request(xwm, window, button) + } + fn fullscreen_request(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.fullscreen_request(xwm, window) + } + fn unfullscreen_request(&mut self, xwm: smithay::xwayland::xwm::XwmId, window: smithay::xwayland::xwm::X11Surface) { + self.0.as_mut().expect("EventLoopData initialized").state.unfullscreen_request(xwm, window) + } +} + +impl smithay::wayland::xwayland_shell::XWaylandShellHandler for DrmLoopData { + fn xwayland_shell_state(&mut self) -> &mut smithay::wayland::xwayland_shell::XWaylandShellState { + self.0.as_mut().expect("EventLoopData initialized").state.xwayland_shell_state() + } + fn surface_associated( + &mut self, + xwm: smithay::xwayland::xwm::XwmId, + wl_surface: smithay::reexports::wayland_server::protocol::wl_surface::WlSurface, + window: smithay::xwayland::xwm::X11Surface, + ) { + self.0.as_mut().expect("EventLoopData initialized").state.surface_associated(xwm, wl_surface, window) + } +} + const MAX_CONSECUTIVE_FLIP_FAILURES: u32 = 5; fn write_flip_failure_report(report: &str) { @@ -448,6 +544,35 @@ fn render_frame(data: &mut EventLoopData) { } } + // Prepare cursor elements from the cursor surface (set by Wayland clients) + let cursor_elements: Vec> = + if let smithay::input::pointer::CursorImageStatus::Surface(ref cursor_surface) = data.state.cursor_status { + render_elements_from_surface_tree( + renderer, + cursor_surface, + (data.state.pointer_location.x as i32, data.state.pointer_location.y as i32), + scale, + 1.0, + Kind::Cursor, + ) + } else { + Vec::new() + }; + + // Load themed cursor texture for Named cursor status + let themed_cursor = if let smithay::input::pointer::CursorImageStatus::Named(ref icon) = data.state.cursor_status { + data.state.cursor_theme_manager.get_cursor(icon.name(), renderer).cloned() + } else if cursor_elements.is_empty() { + // No client surface and not Hidden — use default theme cursor as fallback + if !matches!(data.state.cursor_status, smithay::input::pointer::CursorImageStatus::Hidden) { + data.state.cursor_theme_manager.get_cursor("default", renderer).cloned() + } else { + None + } + } else { + None + }; + let mut target = match renderer.bind(&mut target_dmabuf) { Ok(t) => t, Err(e) => { @@ -477,6 +602,7 @@ fn render_frame(data: &mut EventLoopData) { let mut sorted_windows: Vec<_> = data.state.config.windows.iter().collect(); sorted_windows.sort_by_key(|w| w.z_order); + let mut rendered_tex_count = 0u32; for win_cfg in sorted_windows { if let Some(texture) = data.gles_tex_cache.get(&win_cfg.name) { let (x, y, _w, _h) = data.state @@ -506,10 +632,22 @@ fn render_frame(data: &mut EventLoopData) { return false; } warn!("Electron texture rendering failed for {}: {e}", win_cfg.name); + } else { + rendered_tex_count += 1; } } } + // Log every frame for first 60 frames to diagnose flickering + if data.total_flips < 60 { + info!( + "render_frame #{}: textures_rendered={}, gles_cache={}, windows={}", + data.total_flips, rendered_tex_count, + data.gles_tex_cache.len(), + data.state.config.windows.len(), + ); + } + for element in wayland_elements { let src = element.src(); let dst = element.geometry(scale); @@ -523,6 +661,32 @@ fn render_frame(data: &mut EventLoopData) { } } + // Render cursor on top of everything + if !cursor_elements.is_empty() { + for element in &cursor_elements { + let src = element.src(); + let dst = element.geometry(scale); + if let Err(e) = element.draw(&mut frame, src, dst, &[data.output_rect], &[]) { + trace!("Failed to render cursor element: {e}"); + } + } + } else if let Some(ref cur) = themed_cursor { + let cx = data.state.pointer_location.x as i32 - cur.xhot as i32; + let cy = data.state.pointer_location.y as i32 - cur.yhot as i32; + if let Err(e) = frame.render_texture_at( + &cur.texture, + (cx, cy).into(), + 1, + 1.0, + Transform::Normal, + &[data.output_rect], + &[], + 1.0, + ) { + trace!("Failed to render themed cursor: {e}"); + } + } + // Send frame callbacks let presented_at = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -548,6 +712,18 @@ fn render_frame(data: &mut EventLoopData) { ); } + // Send frame callbacks for the cursor surface so the client keeps + // animating it (e.g. spinning/loading cursors). + if let smithay::input::pointer::CursorImageStatus::Surface(ref cursor_surface) = data.state.cursor_status { + smithay::desktop::utils::send_frames_surface_tree( + cursor_surface, + &data.state.backend.output, + presented_at, + Some(data.frame_time), + |_, _| Some(data.state.backend.output.clone()), + ); + } + // Finalize the GL frame — flushes all rendering commands to the // framebuffer. Without this, the GBM BO may contain stale or // incomplete pixel data, causing flicker. @@ -563,6 +739,15 @@ fn render_frame(data: &mut EventLoopData) { } } + // Ensure all GPU work targeting this BO completes before the DRM + // subsystem starts scanning it out. glFlush (done by finish()) + // only queues commands; glFinish blocks until they're done. + renderer.with_context(|gl| unsafe { gl.Finish() }) + .unwrap_or_else(|e| warn!("glFinish failed: {e}")); + + // Unbind the render target so the BO is no longer GL-locked. + drop(target); + true })(); @@ -581,14 +766,28 @@ fn render_frame(data: &mut EventLoopData) { data.state.damaged_windows.clear(); data.state.dirty_surfaces.clear(); - // Create framebuffer and schedule page flip - let fb = match framebuffer_from_bo(&data.drm_device_fd, &slot, false) { - Ok(fb) => fb, - Err(e) => { - warn!("Error creating framebuffer: {e}"); - data.swapchain.submitted(&slot); - return; - } + // Get or create the DRM framebuffer for this slot. + // Caching in the slot's userdata avoids a create/destroy cycle every + // frame and — critically — keeps the GbmFramebuffer alive through + // the page flip. Previously the FB was dropped at the end of + // render_frame, calling drmModeRmFB while the flip was still pending. + // While the kernel holds an internal reference, some DRM drivers + // misbehave when the userspace handle is removed before the flip + // completes, causing every-other-frame flicker. + let fb_handle = if let Some(cached_fb) = slot.userdata().get::() { + *cached_fb.as_ref() + } else { + let fb = match framebuffer_from_bo(&data.drm_device_fd, &slot, false) { + Ok(fb) => fb, + Err(e) => { + warn!("Error creating framebuffer: {e}"); + data.swapchain.submitted(&slot); + return; + } + }; + let handle = *fb.as_ref(); + slot.userdata().insert_if_missing(move || fb); + handle }; let plane_state = PlaneState { @@ -599,7 +798,7 @@ fn render_frame(data: &mut EventLoopData) { transform: Transform::Normal, alpha: 1.0, damage_clips: None, - fb: *fb.as_ref(), + fb: fb_handle, fence: None, }), }; @@ -716,15 +915,15 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { // polls the libseat fd, seat.dispatch() is never called, the EnableSeat // message from seatd/logind stays unread, and libseat_open_device() // returns EAGAIN for every attempt. - let mut event_loop: EventLoop> = + let mut event_loop: EventLoop = EventLoop::try_new().context("creating event loop")?; let loop_handle = event_loop.handle(); let loop_signal = event_loop.get_signal(); loop_handle - .insert_source(session_notifier, |event, _, data: &mut Option| { + .insert_source(session_notifier, |event, _, data: &mut DrmLoopData| { use smithay::backend::session::Event; - let Some(data) = data.as_mut() else { + let Some(data) = data.0.as_mut() else { // Pre-init phase: ActivateSession received before DRM setup is // complete. The session is now active; device opening can proceed. return; @@ -768,7 +967,7 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { if !session.is_active() { info!("Waiting for seat activation (EnableSeat from seat manager)..."); } - let mut pre_init: Option = None; + let mut pre_init = DrmLoopData(None); let deadline = Instant::now() + Duration::from_secs(5); loop { let remaining = deadline.saturating_duration_since(Instant::now()); @@ -1080,6 +1279,59 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { state.electron_ipc = Some(ipc); + // Spawn XWayland for X11 client support (mirrors nested.rs) + state.xwayland_shell_state = Some(XWaylandShellState::new::(&dh)); + + match XWayland::spawn( + &dh, + None, + std::iter::empty::<(String, String)>(), + true, + std::process::Stdio::null(), + std::process::Stdio::null(), + |_| {}, + ) { + Ok((xwayland, xw_client)) => { + let wm_handle = loop_handle.clone(); + let xw_client = std::rc::Rc::new(std::cell::RefCell::new(Some(xw_client))); + let xw_client_cb = xw_client.clone(); + + if let Err(e) = + loop_handle.insert_source(xwayland, move |event, _, drm_data: &mut DrmLoopData| { + let data = drm_data.0.as_mut().expect("EventLoopData initialized"); + match event { + XWaylandEvent::Ready { + x11_socket, + display_number, + } => { + info!("XWayland ready on DISPLAY :{display_number}"); + std::env::set_var("DISPLAY", format!(":{display_number}")); + if let Some(client) = xw_client_cb.borrow_mut().take() { + match X11Wm::start_wm(wm_handle.clone(), x11_socket, client) { + Ok(wm) => { + data.state.xwm = Some(wm); + info!("X11 window manager attached"); + } + Err(e) => error!("X11Wm::start_wm failed: {e:#}"), + } + } + } + XWaylandEvent::Error => { + warn!("XWayland server encountered an error during startup"); + } + } + }) + { + error!("Failed to register XWayland event source: {e:#}"); + } else { + info!("XWayland server starting"); + } + } + Err(e) => { + warn!("XWayland spawn failed (X11 support disabled): {e:#}"); + } + } + std::env::set_var("WAYLAND_DISPLAY", &config.compositor.socket_name); let app_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("electron"); @@ -1218,8 +1470,8 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { .expect("Error setting Ctrl-C handler"); loop_handle - .insert_source(_drm_notifier, |event, _, data: &mut Option| { - let data = data.as_mut().expect("EventLoopData initialized"); + .insert_source(_drm_notifier, |event, _, drm_data: &mut DrmLoopData| { + let data = drm_data.0.as_mut().expect("EventLoopData initialized"); use smithay::backend::drm::DrmEvent; if !data.active { if let DrmEvent::VBlank(_) = event { @@ -1245,8 +1497,8 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { loop_handle .insert_source( libinput_backend, - move |event, _, data: &mut Option| { - let data = data.as_mut().expect("EventLoopData initialized"); + move |event, _, drm_data: &mut DrmLoopData| { + let data = drm_data.0.as_mut().expect("EventLoopData initialized"); data.state.process_input_event(event); data.input_events_pending = true; }, @@ -1258,10 +1510,10 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { render_frame(&mut loop_data); // Main event loop - purely event-driven (blocking) - let mut main_data: Option = Some(loop_data); + let mut main_data = DrmLoopData(Some(loop_data)); event_loop - .run(None, &mut main_data, |opt_data| { - let data = opt_data.as_mut().expect("EventLoopData initialized"); + .run(None, &mut main_data, |drm_data| { + let data = drm_data.0.as_mut().expect("EventLoopData initialized"); if !data.state.running { loop_signal.stop(); return; @@ -2098,4 +2350,4 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { info!("DRM compositor exiting cleanly"); Ok(()) -} \ No newline at end of file +} diff --git a/src/nested.rs b/src/nested.rs index 2e04d78..06c69a0 100644 --- a/src/nested.rs +++ b/src/nested.rs @@ -612,6 +612,19 @@ pub fn run_nested(config: Config) -> Result<()> { Vec::new() }; + // Load themed cursor texture for Named cursor status + let themed_cursor = if let smithay::input::pointer::CursorImageStatus::Named(ref icon) = state.cursor_status { + state.cursor_theme_manager.get_cursor(icon.name(), renderer).cloned() + } else if cursor_elements.is_empty() { + if !matches!(state.cursor_status, smithay::input::pointer::CursorImageStatus::Hidden) { + state.cursor_theme_manager.get_cursor("default", renderer).cloned() + } else { + None + } + } else { + None + }; + // Wayland windows are exclusively rendered by comraw via off-screen buffers. // The native space.elements() rendering pass has been removed here. @@ -675,13 +688,31 @@ pub fn run_nested(config: Config) -> Result<()> { // allowing the client to fully control window compositing and layout. // Render cursor on top of everything - for element in &cursor_elements { - use smithay::utils::Scale as ScaleF; - let scale = ScaleF::from(1.0); - let src = element.src(); - let dst = element.geometry(scale); - if let Err(e) = element.draw(&mut frame, src, dst, &[output_rect], &[]) { - trace!("Failed to render cursor element: {}", e); + if !cursor_elements.is_empty() { + for element in &cursor_elements { + use smithay::utils::Scale as ScaleF; + let scale = ScaleF::from(1.0); + let src = element.src(); + let dst = element.geometry(scale); + if let Err(e) = element.draw(&mut frame, src, dst, &[output_rect], &[]) { + trace!("Failed to render cursor element: {}", e); + } + } + } else if let Some(ref cur) = themed_cursor { + use smithay::backend::renderer::Frame as _; + let cx = state.pointer_location.x as i32 - cur.xhot as i32; + let cy = state.pointer_location.y as i32 - cur.yhot as i32; + if let Err(e) = frame.render_texture_at( + &cur.texture, + (cx, cy).into(), + 1, + 1.0, + Transform::Normal, + &[output_rect], + &[], + 1.0, + ) { + trace!("Failed to render themed cursor: {}", e); } } diff --git a/src/state.rs b/src/state.rs index c56dd8b..6d59b1f 100644 --- a/src/state.rs +++ b/src/state.rs @@ -18,6 +18,7 @@ use smithay::{ }, relative_pointer::RelativePointerManagerState, pointer_constraints::{self, PointerConstraintsHandler, PointerConstraintsState}, + keyboard_shortcuts_inhibit::{KeyboardShortcutsInhibitHandler, KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor}, shell::xdg::{XdgShellState, decoration::XdgDecorationState}, shm::ShmState, single_pixel_buffer::SinglePixelBufferState, tablet_manager::TabletSeatHandler, viewporter::ViewporterState, xdg_activation::{XdgActivationHandler, XdgActivationState, XdgActivationToken, XdgActivationTokenData}, xwayland_shell::XWaylandShellState }, xwayland::{XWayland, xwm::X11Wm}, @@ -27,6 +28,7 @@ use smithay::reexports::wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_li pub mod portal; use crate::{ config::Config, + cursor::CursorThemeManager, dmabuf::TextureCache, electron::{ElectronIpc, ElectronProcess}, syscall::SyscallHandler, @@ -77,6 +79,7 @@ pub struct WoState { pub cursor_shape_manager_state: CursorShapeManagerState, pub relative_pointer_manager_state: RelativePointerManagerState, pub pointer_constraints_state: PointerConstraintsState, + pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState, pub output_manager: OutputManagerState, pub seat: Seat, @@ -109,6 +112,7 @@ pub struct WoState { /// Buffered pixel exports from offscreen rendering, written to SHM after render block. pub pending_shm_exports: Vec<(String, u32, u32, u32, Vec)>, pub grab_state: Option, + pub cursor_theme_manager: CursorThemeManager, /// Set to true inside new_toplevel to enable checkpoint logging on the /// same main-loop tick where the window appears. @@ -156,6 +160,7 @@ impl WoState { let xdg_decoration_state = XdgDecorationState::new::(&dh); let relative_pointer_manager_state = RelativePointerManagerState::new::(&dh); let pointer_constraints_state = PointerConstraintsState::new::(&dh); + let keyboard_shortcuts_inhibit_state = KeyboardShortcutsInhibitState::new::(&dh); let shm_state = ShmState::new::(&dh, vec![]); let viewporter_state = ViewporterState::new::(&dh); let xdg_activation_state = XdgActivationState::new::(&dh); @@ -249,6 +254,11 @@ impl WoState { let popup_manager = PopupManager::default(); let space = Space::default(); + let cursor_theme_manager = CursorThemeManager::new( + &config.compositor.cursor_theme, + config.compositor.cursor_size, + ); + let mut state = Self { display_handle: dh, compositor_state, @@ -269,6 +279,7 @@ impl WoState { cursor_shape_manager_state, relative_pointer_manager_state, pointer_constraints_state, + keyboard_shortcuts_inhibit_state, output_manager, seat, pointer_location: (0.0, 0.0).into(), @@ -298,6 +309,7 @@ impl WoState { window_shm_buffers: std::collections::HashMap::new(), pending_shm_exports: Vec::new(), grab_state: None, + cursor_theme_manager, debug_new_toplevel: false, wayland_window_names: std::collections::HashMap::new(), wayland_name_to_id: std::collections::HashMap::new(), @@ -624,3 +636,17 @@ impl PointerConstraintsHandler for WoState { smithay::delegate_pointer_constraints!(WoState); smithay::delegate_relative_pointer!(WoState); + +impl KeyboardShortcutsInhibitHandler for WoState { + fn keyboard_shortcuts_inhibit_state(&mut self) -> &mut KeyboardShortcutsInhibitState { + &mut self.keyboard_shortcuts_inhibit_state + } + + fn new_inhibitor(&mut self, inhibitor: KeyboardShortcutsInhibitor) { + // Automatically activate: games/fullscreen apps that request inhibition + // should receive all key events without compositor interception. + inhibitor.activate(); + } +} + +smithay::delegate_keyboard_shortcuts_inhibit!(WoState); diff --git a/whatever.txt b/whatever.txt index de12b5e..b64ded8 100644 --- a/whatever.txt +++ b/whatever.txt @@ -1,11 +1,578 @@ -2026-03-09T13:10:06.828981Z  INFO wo: wo compositor starting -2026-03-09T13:10:06.829194Z  INFO wo::config: Loading config from "/home/hellings/.config/wo/config.toml" -2026-03-09T13:10:06.829640Z  INFO wo: Running in DRM/KMS mode -2026-03-09T13:10:06.831907Z  INFO wo: LibSeat session created successfully -2026-03-09T13:10:06.832112Z  INFO wo: Session notifier registered for VT switching -2026-03-09T13:10:06.832217Z  INFO wo: Session is active, ready to open devices -2026-03-09T13:10:06.832243Z  INFO wo: Using seat: seat0 -2026-03-09T13:10:06.834656Z  INFO wo: trying DRM devices in priority order candidates=["/dev/dri/card1"] -2026-03-09T13:10:06.834715Z  INFO wo: Opening DRM device: "/dev/dri/card1" -2026-03-09T13:10:06.835267Z  INFO wo: libseat returned EAGAIN; pumping event loop and retrying device open... gpu=/dev/dri/card1 -2026-03-09T13:10:07.351716Z  WARN wo: Failed to open DRM device: Failed to open device: Resource temporarily unavailable (os error 11) gpu=/dev/dri/card1 permission_related=false attempt=10 +2026-03-09T19:05:04.695426Z  INFO wo: wo compositor starting +2026-03-09T19:05:04.696005Z  INFO wo::config: Loading config from "/home/hellings/.config/wo/config.toml" +2026-03-09T19:05:04.696508Z  INFO wo: Running in DRM/KMS mode +2026-03-09T19:05:04.698340Z  INFO wo: LibSeat session created successfully +2026-03-09T19:05:04.698373Z  INFO wo: libseat environment seat=seat0 libseat_backend=logind +2026-03-09T19:05:04.698483Z  INFO wo: Session notifier registered for VT switching +2026-03-09T19:05:04.698605Z  INFO wo: Session is active, ready to open devices +2026-03-09T19:05:04.698634Z  INFO wo: Using seat: seat0 +2026-03-09T19:05:04.701686Z  INFO wo: trying DRM devices in priority order candidates=["/dev/dri/card1", "/dev/dri/card2"] +2026-03-09T19:05:04.701715Z  INFO wo: Opening DRM device: "/dev/dri/card1" +2026-03-09T19:05:04.702165Z  INFO wo: using GPU gpu=/dev/dri/card1 +2026-03-09T19:05:04.702199Z  WARN smithay::backend::drm::device::fd: Unable to become drm master, assuming unprivileged mode +2026-03-09T19:05:04.702984Z  INFO wo: DRM device created atomic=true +2026-03-09T19:05:05.166132Z  INFO wo::electron: IPC socket listening socket="/run/user/1000/wo-ipc.sock" +2026-03-09T19:05:05.166366Z  INFO wo: resolved render node card=/dev/dri/card1 render_node=/dev/dri/renderD128 +2026-03-09T19:05:05.166392Z  INFO wo::electron: Spawning Electron for window 'main' with config: WindowConfig { name: "main", url: Some("http://localhost:5173"), html: None, css: None, js: None, width: 2560, height: 1600, x: 0, y: 0, z_order: -1073741824, fps: 60, format: "ARGB8888", focusable: false, interactive: false, floating: false } +2026-03-09T19:05:05.166450Z  INFO wo::electron: Serialized config: {"name":"main","url":"http://localhost:5173","html":null,"css":null,"js":null,"width":2560,"height":1600,"x":0,"y":0,"z_order":-1073741824,"fps":60,"format":"ARGB8888","focusable":false,"interactive":false,"floating":false} +2026-03-09T19:05:05.166833Z  INFO wo::electron: spawned Electron process window=main pid=3988 render_node="/dev/dri/renderD128" +2026-03-09T19:05:05.166880Z  INFO wo: using swapchain format/modifiers from renderer swapchain_format=DrmFourcc(XR24) modifiers=14 +2026-03-09T19:05:05.229616Z  INFO wo: Wayland socket bound socket=wo-0 +2026-03-09T19:05:05.229850Z  INFO wo: Kickstarting VBlank-driven rendering +2026-03-09T19:05:05.229867Z  INFO wo: First render: output=2560x1600, windows=1, bg=Color32F([0.0, 0.0, 0.0, 1.0]) +2026-03-09T19:05:05.232882Z  INFO wo: render_frame #0: textures_rendered=0, gles_cache=0, windows=1 +2026-03-09T19:05:05.233523Z  INFO wo: Performing modeset commit (commit_pending=false, first_frame=true, textures=0) +2026-03-09T19:05:05.234462Z  INFO wo: First successful page flip (commit_pending=false) +[Wo] Electron starting, NODE_VERSION= v22.22.0 +[Wo] WO_WINDOW_CONFIG env = {"name":"main","url":"http://localhost:5173","html":null,"css":null,"js":null,"width":2560,"height":1600,"x":0,"y":0,"z_order":-1073741824,"fps":60,"format":"ARGB8888","focusable":false,"interactive":false,"floating":false} +[Wo] WINDOW_CONFIG parsed = {"name":"main","url":"http://localhost:5173","html":null,"css":null,"js":null,"width":2560,"height":1600,"x":0,"y":0,"z_order":-1073741824,"fps":60,"format":"ARGB8888","focusable":false,"interactive":false,"floating":false} +[Wo] App ready, CLIENT_MODE= false WO_STANDALONE= undefined +[Wo] Will connect to compositor +[Wo] Connecting to compositor IPC: /run/user/1000/wo-ipc.sock +[Wo] Portal UI bridge listening at /tmp/wo-portal-ui.sock +[Wo] IPC connected, sent HELLO message +2026-03-09T19:05:05.740058Z  INFO wo::electron: Electron window connected window=main +[Wo] DMABUF sender initialized +[Wo] Creating window +[Wo] createWindow starting +[Wo] preloadPath=/home/hellings/Documents/wo/electron/dist/preload.js +[Wo] BrowserWindow created, CLIENT_MODE=false offscreen=true +[Wo] setupIpcHandlers completed +[Wo] Loading content URL: http://localhost:5173 + + VITE v8.0.0-beta.16 ready in 368 ms + + ➜ Local: http://localhost:5173/ + ➜ Network: use --host to expose +[Wo] Content loaded from: http://localhost:5173 +[Wo] Page initialized, setting up rendering +[Wo] Setting up OSR rendering, FPS=60 +[Wo] createWindow completed successfully +[Wo] Window created successfully +[Wo] ERROR sending frame: Error: gbm_bo_create failed: all buffer creation methods exhausted +2026-03-09T19:05:06.078535Z  INFO wo::electron: received FRAME, sending ACK window=main seq=1 +2026-03-09T19:05:06.091525Z  INFO wo::electron: received FRAME, sending ACK window=main seq=2 +2026-03-09T19:05:06.115813Z  INFO wo::electron: received FRAME, sending ACK window=main seq=3 +2026-03-09T19:05:06.135055Z  INFO wo::electron: received FRAME, sending ACK window=main seq=4 +2026-03-09T19:05:06.158107Z  INFO wo::electron: received FRAME, sending ACK window=main seq=5 +2026-03-09T19:05:06.167813Z  INFO wo::electron: received FRAME, sending ACK window=main seq=6 +2026-03-09T19:05:06.185891Z  INFO wo::electron: received FRAME, sending ACK window=main seq=7 +2026-03-09T19:05:06.215319Z  INFO wo::electron: received FRAME, sending ACK window=main seq=8 +2026-03-09T19:05:06.229324Z  INFO wo::electron: received FRAME, sending ACK window=main seq=9 +[Wo] SKIPPED paint due to frame backpressure inFlight=2 +2026-03-09T19:05:06.253232Z  INFO wo::electron: received FRAME, sending ACK window=main seq=10 +2026-03-09T19:05:06.267600Z  INFO wo::electron: received FRAME, sending ACK window=main seq=11 +2026-03-09T19:05:06.291503Z  INFO wo::electron: received FRAME, sending ACK window=main seq=12 +2026-03-09T19:05:06.306499Z  INFO wo::electron: received FRAME, sending ACK window=main seq=13 +2026-03-09T19:05:06.326881Z  INFO wo::electron: received FRAME, sending ACK window=main seq=14 +2026-03-09T19:05:06.344775Z  INFO wo::electron: received FRAME, sending ACK window=main seq=15 +2026-03-09T19:05:06.359875Z  INFO wo::electron: received FRAME, sending ACK window=main seq=16 +2026-03-09T19:05:06.379902Z  INFO wo::electron: received FRAME, sending ACK window=main seq=17 +2026-03-09T19:05:06.396090Z  INFO wo::electron: received FRAME, sending ACK window=main seq=18 +2026-03-09T19:05:06.418605Z  INFO wo::electron: received FRAME, sending ACK window=main seq=19 +2026-03-09T19:05:06.433523Z  INFO wo::electron: received FRAME, sending ACK window=main seq=20 +2026-03-09T19:05:06.451557Z  INFO wo::electron: received FRAME, sending ACK window=main seq=21 +2026-03-09T19:05:06.468400Z  INFO wo::electron: received FRAME, sending ACK window=main seq=22 +2026-03-09T19:05:06.487784Z  INFO wo::electron: received FRAME, sending ACK window=main seq=23 +2026-03-09T19:05:06.508063Z  INFO wo::electron: received FRAME, sending ACK window=main seq=24 +2026-03-09T19:05:06.524830Z  INFO wo::electron: received FRAME, sending ACK window=main seq=25 +2026-03-09T19:05:06.540826Z  INFO wo::electron: received FRAME, sending ACK window=main seq=26 +2026-03-09T19:05:06.560716Z  INFO wo::electron: received FRAME, sending ACK window=main seq=27 +2026-03-09T19:05:06.577925Z  INFO wo::electron: received FRAME, sending ACK window=main seq=28 +2026-03-09T19:05:06.594433Z  INFO wo::electron: received FRAME, sending ACK window=main seq=29 +2026-03-09T19:05:06.613620Z  INFO wo::electron: received FRAME, sending ACK window=main seq=30 +2026-03-09T19:05:06.630279Z  INFO wo::electron: received FRAME, sending ACK window=main seq=31 +2026-03-09T19:05:06.646498Z  INFO wo::electron: received FRAME, sending ACK window=main seq=32 +2026-03-09T19:05:06.665370Z  INFO wo::electron: received FRAME, sending ACK window=main seq=33 +2026-03-09T19:05:06.681783Z  INFO wo::electron: received FRAME, sending ACK window=main seq=34 +2026-03-09T19:05:06.698679Z  INFO wo::electron: received FRAME, sending ACK window=main seq=35 +2026-03-09T19:05:06.717124Z  INFO wo::electron: received FRAME, sending ACK window=main seq=36 +2026-03-09T19:05:06.733661Z  INFO wo::electron: received FRAME, sending ACK window=main seq=37 +2026-03-09T19:05:06.750732Z  INFO wo::electron: received FRAME, sending ACK window=main seq=38 +2026-03-09T19:05:06.768398Z  INFO wo::electron: received FRAME, sending ACK window=main seq=39 +2026-03-09T19:05:06.786759Z  INFO wo::electron: received FRAME, sending ACK window=main seq=40 +2026-03-09T19:05:06.805011Z  INFO wo::electron: received FRAME, sending ACK window=main seq=41 +2026-03-09T19:05:06.820089Z  INFO wo::electron: received FRAME, sending ACK window=main seq=42 +2026-03-09T19:05:06.841008Z  INFO wo::electron: received FRAME, sending ACK window=main seq=43 +2026-03-09T19:05:06.858484Z  INFO wo::electron: received FRAME, sending ACK window=main seq=44 +2026-03-09T19:05:06.873345Z  INFO wo::electron: received FRAME, sending ACK window=main seq=45 +2026-03-09T19:05:06.895251Z  INFO wo::electron: received FRAME, sending ACK window=main seq=46 +2026-03-09T19:05:06.913572Z  INFO wo::electron: received FRAME, sending ACK window=main seq=47 +2026-03-09T19:05:06.928565Z  INFO wo::electron: received FRAME, sending ACK window=main seq=48 +2026-03-09T19:05:06.946778Z  INFO wo::electron: received FRAME, sending ACK window=main seq=49 +2026-03-09T19:05:06.963032Z  INFO wo::electron: received FRAME, sending ACK window=main seq=50 +2026-03-09T19:05:06.981865Z  INFO wo::electron: received FRAME, sending ACK window=main seq=51 +2026-03-09T19:05:07.003166Z  INFO wo::electron: received FRAME, sending ACK window=main seq=52 +2026-03-09T19:05:07.019432Z  INFO wo::electron: received FRAME, sending ACK window=main seq=53 +2026-03-09T19:05:07.036505Z  INFO wo::electron: received FRAME, sending ACK window=main seq=54 +2026-03-09T19:05:07.055273Z  INFO wo::electron: received FRAME, sending ACK window=main seq=55 +2026-03-09T19:05:07.071839Z  INFO wo::electron: received FRAME, sending ACK window=main seq=56 +2026-03-09T19:05:07.089251Z  INFO wo::electron: received FRAME, sending ACK window=main seq=57 +2026-03-09T19:05:07.107110Z  INFO wo::electron: received FRAME, sending ACK window=main seq=58 +2026-03-09T19:05:07.125533Z  INFO wo::electron: received FRAME, sending ACK window=main seq=59 +2026-03-09T19:05:07.143999Z  INFO wo::electron: received FRAME, sending ACK window=main seq=60 +2026-03-09T19:05:07.158213Z  INFO wo::electron: received FRAME, sending ACK window=main seq=61 +2026-03-09T19:05:07.180784Z  INFO wo::electron: received FRAME, sending ACK window=main seq=62 +2026-03-09T19:05:07.198923Z  INFO wo::electron: received FRAME, sending ACK window=main seq=63 +2026-03-09T19:05:07.214403Z  INFO wo::electron: received FRAME, sending ACK window=main seq=64 +2026-03-09T19:05:07.235149Z  INFO wo::electron: received FRAME, sending ACK window=main seq=65 +2026-03-09T19:05:07.253179Z  INFO wo::electron: received FRAME, sending ACK window=main seq=66 +2026-03-09T19:05:07.270568Z  INFO wo::electron: received FRAME, sending ACK window=main seq=67 +2026-03-09T19:05:07.285814Z  INFO wo::electron: received FRAME, sending ACK window=main seq=68 +2026-03-09T19:05:07.304510Z  INFO wo::electron: received FRAME, sending ACK window=main seq=69 +2026-03-09T19:05:07.319567Z  INFO wo::electron: received FRAME, sending ACK window=main seq=70 +2026-03-09T19:05:07.342323Z  INFO wo::electron: received FRAME, sending ACK window=main seq=71 +2026-03-09T19:05:07.361423Z  INFO wo::electron: received FRAME, sending ACK window=main seq=72 +2026-03-09T19:05:07.371420Z  INFO wo: First DMABUF imported for 'main' (2560x1600, total_textures=1) +2026-03-09T19:05:07.371855Z  INFO wo: Spawned portal service: "/home/hellings/Documents/wo/target/debug/wo-portal" +2026-03-09T19:05:07.373260Z  INFO wo: render_frame #1: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.374775Z  INFO wo_portal: xdg-desktop-portal-wo starting +2026-03-09T19:05:07.374902Z  INFO wo::config: Loading config from "/home/hellings/.config/wo/config.toml" +2026-03-09T19:05:07.376323Z  INFO wo::electron: received FRAME, sending ACK window=main seq=73 +2026-03-09T19:05:07.378710Z  INFO wo_portal: Portal service registered as org.freedesktop.impl.portal.desktop.wo +2026-03-09T19:05:07.378751Z  INFO wo_portal: Compositor IPC socket: /run/user/1000/wo-ipc.sock +2026-03-09T19:05:07.378764Z  INFO wo_portal: Listening for screen capture requests... +2026-03-09T19:05:07.385634Z  INFO wo: render_frame #2: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.398533Z  INFO wo: render_frame #3: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.398557Z  INFO wo::electron: received FRAME, sending ACK window=main seq=74 +2026-03-09T19:05:07.408768Z  INFO wo: render_frame #4: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.414881Z  INFO wo::electron: received FRAME, sending ACK window=main seq=75 +2026-03-09T19:05:07.424981Z  INFO wo: render_frame #5: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.429527Z  INFO wo::electron: received FRAME, sending ACK window=main seq=76 +2026-03-09T19:05:07.441735Z  INFO wo: render_frame #6: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.449042Z  INFO wo::electron: received FRAME, sending ACK window=main seq=77 +2026-03-09T19:05:07.458571Z  INFO wo: render_frame #7: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.467037Z  INFO wo::electron: received FRAME, sending ACK window=main seq=78 +2026-03-09T19:05:07.475323Z  INFO wo: render_frame #8: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.482430Z  INFO wo::electron: received FRAME, sending ACK window=main seq=79 +2026-03-09T19:05:07.492752Z  INFO wo: render_frame #9: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.506061Z  INFO wo::electron: received FRAME, sending ACK window=main seq=80 +2026-03-09T19:05:07.510418Z  INFO wo: render_frame #10: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.519103Z  INFO wo::electron: received FRAME, sending ACK window=main seq=81 +2026-03-09T19:05:07.527895Z  INFO wo: render_frame #11: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.541595Z  INFO wo: render_frame #12: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.543444Z  INFO wo::electron: received FRAME, sending ACK window=main seq=82 +2026-03-09T19:05:07.558040Z  INFO wo::electron: received FRAME, sending ACK window=main seq=83 +2026-03-09T19:05:07.558618Z  INFO wo: render_frame #13: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.575042Z  INFO wo: render_frame #14: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.580487Z  INFO wo::electron: received FRAME, sending ACK window=main seq=84 +2026-03-09T19:05:07.592113Z  INFO wo: render_frame #15: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.598258Z  INFO wo::electron: received FRAME, sending ACK window=main seq=85 +2026-03-09T19:05:07.608849Z  INFO wo: render_frame #16: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.615962Z  INFO wo::electron: received FRAME, sending ACK window=main seq=86 +2026-03-09T19:05:07.626569Z  INFO wo: render_frame #17: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.636117Z  INFO wo::electron: received FRAME, sending ACK window=main seq=87 +2026-03-09T19:05:07.642524Z  INFO wo: render_frame #18: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.655159Z  INFO wo::electron: received FRAME, sending ACK window=main seq=88 +2026-03-09T19:05:07.659312Z  INFO wo: render_frame #19: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.671247Z  INFO wo::electron: received FRAME, sending ACK window=main seq=89 +2026-03-09T19:05:07.675380Z  INFO wo: render_frame #20: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.691736Z  INFO wo: render_frame #21: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.695107Z  INFO wo::electron: received FRAME, sending ACK window=main seq=90 +2026-03-09T19:05:07.708598Z  INFO wo: render_frame #22: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.710449Z  INFO wo::electron: received FRAME, sending ACK window=main seq=91 +2026-03-09T19:05:07.725305Z  INFO wo: render_frame #23: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.729455Z  INFO wo::electron: received FRAME, sending ACK window=main seq=92 +2026-03-09T19:05:07.741999Z  INFO wo: render_frame #24: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.742543Z  INFO wo::electron: received FRAME, sending ACK window=main seq=93 +2026-03-09T19:05:07.759094Z  INFO wo: render_frame #25: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.767284Z  INFO wo::electron: received FRAME, sending ACK window=main seq=94 +2026-03-09T19:05:07.775382Z  INFO wo: render_frame #26: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.781747Z  INFO wo::electron: received FRAME, sending ACK window=main seq=95 +2026-03-09T19:05:07.792691Z  INFO wo: render_frame #27: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.804420Z  INFO wo::electron: received FRAME, sending ACK window=main seq=96 +2026-03-09T19:05:07.808976Z  INFO wo: render_frame #28: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.819069Z  INFO wo::electron: received FRAME, sending ACK window=main seq=97 +2026-03-09T19:05:07.826573Z  INFO wo: render_frame #29: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.839607Z  INFO wo::electron: received FRAME, sending ACK window=main seq=98 +2026-03-09T19:05:07.842139Z  INFO wo: render_frame #30: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.852177Z  INFO wo::electron: received FRAME, sending ACK window=main seq=99 +2026-03-09T19:05:07.859664Z  INFO wo: render_frame #31: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.873405Z  INFO wo::electron: received FRAME, sending ACK window=main seq=100 +2026-03-09T19:05:07.875306Z  INFO wo: render_frame #32: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.889434Z  INFO wo::electron: received FRAME, sending ACK window=main seq=101 +2026-03-09T19:05:07.892493Z  INFO wo: render_frame #33: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.910140Z  INFO wo::electron: received FRAME, sending ACK window=main seq=102 +2026-03-09T19:05:07.911559Z  INFO wo: render_frame #34: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.925015Z  INFO wo::electron: received FRAME, sending ACK window=main seq=103 +2026-03-09T19:05:07.933414Z  INFO wo: render_frame #35: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.945412Z  INFO wo::electron: received FRAME, sending ACK window=main seq=104 +2026-03-09T19:05:07.955034Z  INFO wo: render_frame #36: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.964758Z  INFO wo::electron: received FRAME, sending ACK window=main seq=105 +2026-03-09T19:05:07.967527Z  INFO wo: render_frame #37: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.975407Z  INFO wo: render_frame #38: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.977139Z  INFO wo::electron: received FRAME, sending ACK window=main seq=106 +2026-03-09T19:05:07.992236Z  INFO wo: render_frame #39: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:07.994447Z  INFO wo::electron: received FRAME, sending ACK window=main seq=107 +2026-03-09T19:05:08.009142Z  INFO wo: render_frame #40: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.012236Z  INFO wo::electron: received FRAME, sending ACK window=main seq=108 +2026-03-09T19:05:08.025700Z  INFO wo: render_frame #41: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.031393Z  INFO wo::electron: received FRAME, sending ACK window=main seq=109 +2026-03-09T19:05:08.042188Z  INFO wo: render_frame #42: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.043748Z  INFO wo::electron: received FRAME, sending ACK window=main seq=110 +2026-03-09T19:05:08.060693Z  INFO wo: render_frame #43: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.072965Z  INFO wo::electron: received FRAME, sending ACK window=main seq=111 +2026-03-09T19:05:08.075576Z  INFO wo: render_frame #44: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.085621Z  INFO wo::electron: received FRAME, sending ACK window=main seq=112 +2026-03-09T19:05:08.092495Z  INFO wo: render_frame #45: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.102376Z  INFO wo::electron: received FRAME, sending ACK window=main seq=113 +2026-03-09T19:05:08.110177Z  INFO wo: render_frame #46: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.119066Z  INFO wo::electron: received FRAME, sending ACK window=main seq=114 +2026-03-09T19:05:08.126233Z  INFO wo: render_frame #47: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.135287Z  INFO wo::electron: received FRAME, sending ACK window=main seq=115 +2026-03-09T19:05:08.142536Z  INFO wo: render_frame #48: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.150631Z  INFO wo::electron: received FRAME, sending ACK window=main seq=116 +2026-03-09T19:05:08.159303Z  INFO wo: render_frame #49: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.171184Z  INFO wo::electron: received FRAME, sending ACK window=main seq=117 +2026-03-09T19:05:08.175739Z  INFO wo: render_frame #50: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.190803Z  INFO wo::electron: received FRAME, sending ACK window=main seq=118 +2026-03-09T19:05:08.192719Z  INFO wo: render_frame #51: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.209300Z  INFO wo: render_frame #52: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.211910Z  INFO wo::electron: received FRAME, sending ACK window=main seq=119 +2026-03-09T19:05:08.226057Z  INFO wo: render_frame #53: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.226385Z  INFO wo::electron: received FRAME, sending ACK window=main seq=120 +2026-03-09T19:05:08.241468Z  INFO wo::electron: received FRAME, sending ACK window=main seq=121 +2026-03-09T19:05:08.242524Z  INFO wo: render_frame #54: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.259309Z  INFO wo: render_frame #55: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.259672Z  INFO wo::electron: received FRAME, sending ACK window=main seq=122 +2026-03-09T19:05:08.275543Z  INFO wo::electron: received FRAME, sending ACK window=main seq=123 +2026-03-09T19:05:08.275965Z  INFO wo: render_frame #56: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.290724Z  INFO wo::electron: received FRAME, sending ACK window=main seq=124 +2026-03-09T19:05:08.293454Z  INFO wo: render_frame #57: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.308995Z  INFO wo: render_frame #58: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.311290Z  INFO wo::electron: received FRAME, sending ACK window=main seq=125 +2026-03-09T19:05:08.326174Z  INFO wo: render_frame #59: textures_rendered=1, gles_cache=1, windows=1 +2026-03-09T19:05:08.332259Z  INFO wo::electron: received FRAME, sending ACK window=main seq=126 +2026-03-09T19:05:08.347320Z  INFO wo::electron: received FRAME, sending ACK window=main seq=127 +2026-03-09T19:05:08.367845Z  INFO wo::electron: received FRAME, sending ACK window=main seq=128 +2026-03-09T19:05:08.386642Z  INFO wo::electron: received FRAME, sending ACK window=main seq=129 +2026-03-09T19:05:08.408885Z  INFO wo::electron: received FRAME, sending ACK window=main seq=130 +2026-03-09T19:05:08.428166Z  INFO wo::electron: received FRAME, sending ACK window=main seq=131 +2026-03-09T19:05:08.446778Z  INFO wo::electron: received FRAME, sending ACK window=main seq=132 +2026-03-09T19:05:08.461172Z  INFO wo::electron: received FRAME, sending ACK window=main seq=133 +2026-03-09T19:05:08.484331Z  INFO wo::electron: received FRAME, sending ACK window=main seq=134 +2026-03-09T19:05:08.506797Z  INFO wo::electron: received FRAME, sending ACK window=main seq=135 +2026-03-09T19:05:08.527019Z  INFO wo::electron: received FRAME, sending ACK window=main seq=136 +2026-03-09T19:05:08.544423Z  INFO wo::electron: received FRAME, sending ACK window=main seq=137 +2026-03-09T19:05:08.565329Z  INFO wo::electron: received FRAME, sending ACK window=main seq=138 +2026-03-09T19:05:08.583494Z  INFO wo::electron: received FRAME, sending ACK window=main seq=139 +2026-03-09T19:05:08.605203Z  INFO wo::electron: received FRAME, sending ACK window=main seq=140 +2026-03-09T19:05:08.757098Z  INFO wo::electron: received FRAME, sending ACK window=main seq=141 +2026-03-09T19:05:08.776883Z  INFO wo::electron: received FRAME, sending ACK window=main seq=142 +2026-03-09T19:05:08.797115Z  INFO wo::electron: received FRAME, sending ACK window=main seq=143 +2026-03-09T19:05:08.817753Z  INFO wo::electron: received FRAME, sending ACK window=main seq=144 +2026-03-09T19:05:08.837605Z  INFO wo::electron: received FRAME, sending ACK window=main seq=145 +[Wo] Load timeout, continuing +2026-03-09T19:05:08.858544Z  INFO wo::electron: received FRAME, sending ACK window=main seq=146 +2026-03-09T19:05:08.879656Z  INFO wo::electron: received FRAME, sending ACK window=main seq=147 +2026-03-09T19:05:08.896826Z  INFO wo::electron: received FRAME, sending ACK window=main seq=148 +2026-03-09T19:05:08.917898Z  INFO wo::electron: received FRAME, sending ACK window=main seq=149 +2026-03-09T19:05:08.937260Z  INFO wo::electron: received FRAME, sending ACK window=main seq=150 +2026-03-09T19:05:08.958668Z  INFO wo::electron: received FRAME, sending ACK window=main seq=151 +2026-03-09T19:05:08.974782Z  INFO wo::electron: received FRAME, sending ACK window=main seq=152 +2026-03-09T19:05:09.000150Z  INFO wo::electron: received FRAME, sending ACK window=main seq=153 +2026-03-09T19:05:09.016152Z  INFO wo::electron: received FRAME, sending ACK window=main seq=154 +2026-03-09T19:05:09.035956Z  INFO wo::electron: received FRAME, sending ACK window=main seq=155 +2026-03-09T19:05:09.055953Z  INFO wo::electron: received FRAME, sending ACK window=main seq=156 +2026-03-09T19:05:09.070892Z  INFO wo::electron: received FRAME, sending ACK window=main seq=157 +2026-03-09T19:05:09.087604Z  INFO wo::electron: received FRAME, sending ACK window=main seq=158 +2026-03-09T19:05:09.112960Z  INFO wo::electron: received FRAME, sending ACK window=main seq=159 +2026-03-09T19:05:09.143908Z  INFO wo::electron: received FRAME, sending ACK window=main seq=160 +2026-03-09T19:05:09.158543Z  INFO wo::electron: received FRAME, sending ACK window=main seq=161 +2026-03-09T19:05:09.181403Z  INFO wo::electron: received FRAME, sending ACK window=main seq=162 +2026-03-09T19:05:09.199534Z  INFO wo::electron: received FRAME, sending ACK window=main seq=163 +2026-03-09T19:05:09.215902Z  INFO wo::electron: received FRAME, sending ACK window=main seq=164 +2026-03-09T19:05:09.231086Z  INFO wo::electron: received FRAME, sending ACK window=main seq=165 +2026-03-09T19:05:09.247916Z  INFO wo::electron: received FRAME, sending ACK window=main seq=166 +2026-03-09T19:05:09.263202Z  INFO wo::electron: received FRAME, sending ACK window=main seq=167 +2026-03-09T19:05:09.279943Z  INFO wo::electron: received FRAME, sending ACK window=main seq=168 +2026-03-09T19:05:09.302232Z  INFO wo::electron: received FRAME, sending ACK window=main seq=169 +2026-03-09T19:05:09.322814Z  INFO wo::electron: received FRAME, sending ACK window=main seq=170 +2026-03-09T19:05:09.335478Z  INFO wo::electron: received FRAME, sending ACK window=main seq=171 +2026-03-09T19:05:09.358890Z  INFO wo::electron: received FRAME, sending ACK window=main seq=172 +2026-03-09T19:05:09.381262Z  INFO wo::electron: received FRAME, sending ACK window=main seq=173 +2026-03-09T19:05:09.395508Z  INFO wo::electron: received FRAME, sending ACK window=main seq=174 +2026-03-09T19:05:09.417419Z  INFO wo::electron: received FRAME, sending ACK window=main seq=175 +2026-03-09T19:05:09.433241Z  INFO wo::electron: received FRAME, sending ACK window=main seq=176 +2026-03-09T19:05:09.449443Z  INFO wo::electron: received FRAME, sending ACK window=main seq=177 +2026-03-09T19:05:09.464904Z  INFO wo::electron: received FRAME, sending ACK window=main seq=178 +2026-03-09T19:05:09.481937Z  INFO wo::electron: received FRAME, sending ACK window=main seq=179 +2026-03-09T19:05:09.497275Z  INFO wo::electron: received FRAME, sending ACK window=main seq=180 +2026-03-09T19:05:09.514493Z  INFO wo::electron: received FRAME, sending ACK window=main seq=181 +2026-03-09T19:05:09.537129Z  INFO wo::electron: received FRAME, sending ACK window=main seq=182 +2026-03-09T19:05:09.551380Z  INFO wo::electron: received FRAME, sending ACK window=main seq=183 +2026-03-09T19:05:09.574504Z  INFO wo::electron: received FRAME, sending ACK window=main seq=184 +2026-03-09T19:05:09.588673Z  INFO wo::electron: received FRAME, sending ACK window=main seq=185 +2026-03-09T19:05:09.610532Z  INFO wo::electron: received FRAME, sending ACK window=main seq=186 +2026-03-09T19:05:09.626399Z  INFO wo::electron: received FRAME, sending ACK window=main seq=187 +2026-03-09T19:05:09.643221Z  INFO wo::electron: received FRAME, sending ACK window=main seq=188 +2026-03-09T19:05:09.656890Z  INFO wo::electron: received FRAME, sending ACK window=main seq=189 +2026-03-09T19:05:09.676851Z  INFO wo::electron: received FRAME, sending ACK window=main seq=190 +2026-03-09T19:05:09.689396Z  INFO wo::electron: received FRAME, sending ACK window=main seq=191 +2026-03-09T19:05:09.705067Z  INFO wo::electron: received FRAME, sending ACK window=main seq=192 +2026-03-09T19:05:09.727534Z  INFO wo::electron: received FRAME, sending ACK window=main seq=193 +2026-03-09T19:05:09.749999Z  INFO wo::electron: received FRAME, sending ACK window=main seq=194 +2026-03-09T19:05:09.765554Z  INFO wo::electron: received FRAME, sending ACK window=main seq=195 +2026-03-09T19:05:09.784934Z  INFO wo::electron: received FRAME, sending ACK window=main seq=196 +2026-03-09T19:05:09.802931Z  INFO wo::electron: received FRAME, sending ACK window=main seq=197 +2026-03-09T19:05:09.818907Z  INFO wo::electron: received FRAME, sending ACK window=main seq=198 +2026-03-09T19:05:09.835515Z  INFO wo::electron: received FRAME, sending ACK window=main seq=199 +2026-03-09T19:05:09.858681Z  INFO wo::electron: received FRAME, sending ACK window=main seq=200 +2026-03-09T19:05:09.875952Z  INFO wo::electron: received FRAME, sending ACK window=main seq=201 +2026-03-09T19:05:09.894321Z  INFO wo::electron: received FRAME, sending ACK window=main seq=202 +2026-03-09T19:05:09.916169Z  INFO wo::electron: received FRAME, sending ACK window=main seq=203 +2026-03-09T19:05:09.928981Z  INFO wo::electron: received FRAME, sending ACK window=main seq=204 +2026-03-09T19:05:09.952677Z  INFO wo::electron: received FRAME, sending ACK window=main seq=205 +2026-03-09T19:05:09.967260Z  INFO wo::electron: received FRAME, sending ACK window=main seq=206 +2026-03-09T19:05:09.990725Z  INFO wo::electron: received FRAME, sending ACK window=main seq=207 +2026-03-09T19:05:10.006487Z  INFO wo::electron: received FRAME, sending ACK window=main seq=208 +2026-03-09T19:05:10.021208Z  INFO wo::electron: received FRAME, sending ACK window=main seq=209 +2026-03-09T19:05:10.035614Z  INFO wo::electron: received FRAME, sending ACK window=main seq=210 +2026-03-09T19:05:10.059276Z  INFO wo::electron: received FRAME, sending ACK window=main seq=211 +2026-03-09T19:05:10.077026Z  INFO wo::electron: received FRAME, sending ACK window=main seq=212 +2026-03-09T19:05:10.095038Z  INFO wo::electron: received FRAME, sending ACK window=main seq=213 +2026-03-09T19:05:10.107985Z  INFO wo::electron: received FRAME, sending ACK window=main seq=214 +2026-03-09T19:05:10.133539Z  INFO wo::electron: received FRAME, sending ACK window=main seq=215 +2026-03-09T19:05:10.149316Z  INFO wo::electron: received FRAME, sending ACK window=main seq=216 +2026-03-09T19:05:10.168667Z  INFO wo::electron: received FRAME, sending ACK window=main seq=217 +2026-03-09T19:05:10.185506Z  INFO wo::electron: received FRAME, sending ACK window=main seq=218 +2026-03-09T19:05:10.201283Z  INFO wo::electron: received FRAME, sending ACK window=main seq=219 +2026-03-09T19:05:10.220526Z  INFO wo::electron: received FRAME, sending ACK window=main seq=220 +2026-03-09T19:05:10.239132Z  INFO wo::electron: received FRAME, sending ACK window=main seq=221 +2026-03-09T19:05:10.254284Z  INFO wo::electron: received FRAME, sending ACK window=main seq=222 +2026-03-09T19:05:10.277162Z  INFO wo::electron: received FRAME, sending ACK window=main seq=223 +2026-03-09T19:05:10.291921Z  INFO wo::electron: received FRAME, sending ACK window=main seq=224 +2026-03-09T19:05:10.314433Z  INFO wo::electron: received FRAME, sending ACK window=main seq=225 +2026-03-09T19:05:10.328169Z  INFO wo::electron: received FRAME, sending ACK window=main seq=226 +2026-03-09T19:05:10.347406Z  INFO wo::electron: received FRAME, sending ACK window=main seq=227 +2026-03-09T19:05:10.360267Z  INFO wo::electron: received FRAME, sending ACK window=main seq=228 +2026-03-09T19:05:10.388525Z  INFO wo::electron: received FRAME, sending ACK window=main seq=229 +2026-03-09T19:05:10.402887Z  INFO wo::electron: received FRAME, sending ACK window=main seq=230 +2026-03-09T19:05:10.425009Z  INFO wo::electron: received FRAME, sending ACK window=main seq=231 +2026-03-09T19:05:10.446980Z  INFO wo::electron: received FRAME, sending ACK window=main seq=232 +2026-03-09T19:05:10.462289Z  INFO wo::electron: received FRAME, sending ACK window=main seq=233 +2026-03-09T19:05:10.482716Z  INFO wo::electron: received FRAME, sending ACK window=main seq=234 +2026-03-09T19:05:10.499518Z  INFO wo::electron: received FRAME, sending ACK window=main seq=235 +2026-03-09T19:05:10.519049Z  INFO wo::electron: received FRAME, sending ACK window=main seq=236 +2026-03-09T19:05:10.531616Z  INFO wo::electron: received FRAME, sending ACK window=main seq=237 +2026-03-09T19:05:10.554883Z  INFO wo::electron: received FRAME, sending ACK window=main seq=238 +2026-03-09T19:05:10.568809Z  INFO wo::electron: received FRAME, sending ACK window=main seq=239 +2026-03-09T19:05:10.588641Z  INFO wo::electron: received FRAME, sending ACK window=main seq=240 +2026-03-09T19:05:10.607131Z  INFO wo::electron: received FRAME, sending ACK window=main seq=241 +2026-03-09T19:05:10.625324Z  INFO wo::electron: received FRAME, sending ACK window=main seq=242 +2026-03-09T19:05:10.642669Z  INFO wo::electron: received FRAME, sending ACK window=main seq=243 +2026-03-09T19:05:10.660453Z  INFO wo::electron: received FRAME, sending ACK window=main seq=244 +2026-03-09T19:05:10.674928Z  INFO wo::electron: received FRAME, sending ACK window=main seq=245 +2026-03-09T19:05:10.696541Z  INFO wo::electron: received FRAME, sending ACK window=main seq=246 +2026-03-09T19:05:10.715069Z  INFO wo::electron: received FRAME, sending ACK window=main seq=247 +2026-03-09T19:05:10.729069Z  INFO wo::electron: received FRAME, sending ACK window=main seq=248 +2026-03-09T19:05:10.749994Z  INFO wo::electron: received FRAME, sending ACK window=main seq=249 +2026-03-09T19:05:10.768351Z  INFO wo::electron: received FRAME, sending ACK window=main seq=250 +2026-03-09T19:05:10.785358Z  INFO wo::electron: received FRAME, sending ACK window=main seq=251 +2026-03-09T19:05:10.805945Z  INFO wo::electron: received FRAME, sending ACK window=main seq=252 +2026-03-09T19:05:10.824142Z  INFO wo::electron: received FRAME, sending ACK window=main seq=253 +2026-03-09T19:05:10.840256Z  INFO wo::electron: received FRAME, sending ACK window=main seq=254 +2026-03-09T19:05:10.860929Z  INFO wo::electron: received FRAME, sending ACK window=main seq=255 +2026-03-09T19:05:10.879418Z  INFO wo::electron: received FRAME, sending ACK window=main seq=256 +2026-03-09T19:05:10.893761Z  INFO wo::electron: received FRAME, sending ACK window=main seq=257 +2026-03-09T19:05:10.915569Z  INFO wo::electron: received FRAME, sending ACK window=main seq=258 +2026-03-09T19:05:10.933922Z  INFO wo::electron: received FRAME, sending ACK window=main seq=259 +2026-03-09T19:05:10.948233Z  INFO wo::electron: received FRAME, sending ACK window=main seq=260 +2026-03-09T19:05:10.969982Z  INFO wo::electron: received FRAME, sending ACK window=main seq=261 +2026-03-09T19:05:10.988772Z  INFO wo::electron: received FRAME, sending ACK window=main seq=262 +2026-03-09T19:05:11.003425Z  INFO wo::electron: received FRAME, sending ACK window=main seq=263 +2026-03-09T19:05:11.024974Z  INFO wo::electron: received FRAME, sending ACK window=main seq=264 +2026-03-09T19:05:11.043851Z  INFO wo::electron: received FRAME, sending ACK window=main seq=265 +2026-03-09T19:05:11.057928Z  INFO wo::electron: received FRAME, sending ACK window=main seq=266 +2026-03-09T19:05:11.079831Z  INFO wo::electron: received FRAME, sending ACK window=main seq=267 +2026-03-09T19:05:11.098666Z  INFO wo::electron: received FRAME, sending ACK window=main seq=268 +2026-03-09T19:05:11.113216Z  INFO wo::electron: received FRAME, sending ACK window=main seq=269 +2026-03-09T19:05:11.134778Z  INFO wo::electron: received FRAME, sending ACK window=main seq=270 +2026-03-09T19:05:11.153050Z  INFO wo::electron: received FRAME, sending ACK window=main seq=271 +2026-03-09T19:05:11.167202Z  INFO wo::electron: received FRAME, sending ACK window=main seq=272 +2026-03-09T19:05:11.188755Z  INFO wo::electron: received FRAME, sending ACK window=main seq=273 +2026-03-09T19:05:11.207161Z  INFO wo::electron: received FRAME, sending ACK window=main seq=274 +2026-03-09T19:05:11.221273Z  INFO wo::electron: received FRAME, sending ACK window=main seq=275 +2026-03-09T19:05:11.242745Z  INFO wo::electron: received FRAME, sending ACK window=main seq=276 +2026-03-09T19:05:11.261659Z  INFO wo::electron: received FRAME, sending ACK window=main seq=277 +2026-03-09T19:05:11.275941Z  INFO wo::electron: received FRAME, sending ACK window=main seq=278 +2026-03-09T19:05:11.297677Z  INFO wo::electron: received FRAME, sending ACK window=main seq=279 +2026-03-09T19:05:11.316634Z  INFO wo::electron: received FRAME, sending ACK window=main seq=280 +2026-03-09T19:05:11.331408Z  INFO wo::electron: received FRAME, sending ACK window=main seq=281 +2026-03-09T19:05:11.351880Z  INFO wo::electron: received FRAME, sending ACK window=main seq=282 +2026-03-09T19:05:11.370290Z  INFO wo::electron: received FRAME, sending ACK window=main seq=283 +2026-03-09T19:05:11.384324Z  INFO wo::electron: received FRAME, sending ACK window=main seq=284 +2026-03-09T19:05:11.405958Z  INFO wo::electron: received FRAME, sending ACK window=main seq=285 +2026-03-09T19:05:11.424713Z  INFO wo::electron: received FRAME, sending ACK window=main seq=286 +2026-03-09T19:05:11.439068Z  INFO wo::electron: received FRAME, sending ACK window=main seq=287 +2026-03-09T19:05:11.460789Z  INFO wo::electron: received FRAME, sending ACK window=main seq=288 +2026-03-09T19:05:11.479149Z  INFO wo::electron: received FRAME, sending ACK window=main seq=289 +2026-03-09T19:05:11.493560Z  INFO wo::electron: received FRAME, sending ACK window=main seq=290 +2026-03-09T19:05:11.514261Z  INFO wo::electron: received FRAME, sending ACK window=main seq=291 +2026-03-09T19:05:11.532751Z  INFO wo::electron: received FRAME, sending ACK window=main seq=292 +2026-03-09T19:05:11.546625Z  INFO wo::electron: received FRAME, sending ACK window=main seq=293 +2026-03-09T19:05:11.568310Z  INFO wo::electron: received FRAME, sending ACK window=main seq=294 +2026-03-09T19:05:11.587304Z  INFO wo::electron: received FRAME, sending ACK window=main seq=295 +2026-03-09T19:05:11.602688Z  INFO wo::electron: received FRAME, sending ACK window=main seq=296 +2026-03-09T19:05:11.622009Z  INFO wo::electron: received FRAME, sending ACK window=main seq=297 +2026-03-09T19:05:11.640316Z  INFO wo::electron: received FRAME, sending ACK window=main seq=298 +2026-03-09T19:05:11.656712Z  INFO wo::electron: received FRAME, sending ACK window=main seq=299 +2026-03-09T19:05:11.677363Z  INFO wo::electron: received FRAME, sending ACK window=main seq=300 +2026-03-09T19:05:11.696314Z  INFO wo::electron: received FRAME, sending ACK window=main seq=301 +2026-03-09T19:05:11.710829Z  INFO wo::electron: received FRAME, sending ACK window=main seq=302 +2026-03-09T19:05:11.731520Z  INFO wo::electron: received FRAME, sending ACK window=main seq=303 +2026-03-09T19:05:11.749776Z  INFO wo::electron: received FRAME, sending ACK window=main seq=304 +2026-03-09T19:05:11.764112Z  INFO wo::electron: received FRAME, sending ACK window=main seq=305 +2026-03-09T19:05:11.785723Z  INFO wo::electron: received FRAME, sending ACK window=main seq=306 +2026-03-09T19:05:11.804143Z  INFO wo::electron: received FRAME, sending ACK window=main seq=307 +2026-03-09T19:05:11.818835Z  INFO wo::electron: received FRAME, sending ACK window=main seq=308 +2026-03-09T19:05:11.839330Z  INFO wo::electron: received FRAME, sending ACK window=main seq=309 +2026-03-09T19:05:11.857515Z  INFO wo::electron: received FRAME, sending ACK window=main seq=310 +2026-03-09T19:05:11.871818Z  INFO wo::electron: received FRAME, sending ACK window=main seq=311 +2026-03-09T19:05:11.893550Z  INFO wo::electron: received FRAME, sending ACK window=main seq=312 +2026-03-09T19:05:11.911740Z  INFO wo::electron: received FRAME, sending ACK window=main seq=313 +2026-03-09T19:05:11.926315Z  INFO wo::electron: received FRAME, sending ACK window=main seq=314 +2026-03-09T19:05:11.947679Z  INFO wo::electron: received FRAME, sending ACK window=main seq=315 +2026-03-09T19:05:11.966154Z  INFO wo::electron: received FRAME, sending ACK window=main seq=316 +2026-03-09T19:05:11.981056Z  INFO wo::electron: received FRAME, sending ACK window=main seq=317 +2026-03-09T19:05:12.001704Z  INFO wo::electron: received FRAME, sending ACK window=main seq=318 +2026-03-09T19:05:12.019779Z  INFO wo::electron: received FRAME, sending ACK window=main seq=319 +2026-03-09T19:05:12.034249Z  INFO wo::electron: received FRAME, sending ACK window=main seq=320 +2026-03-09T19:05:12.055935Z  INFO wo::electron: received FRAME, sending ACK window=main seq=321 +2026-03-09T19:05:12.074940Z  INFO wo::electron: received FRAME, sending ACK window=main seq=322 +2026-03-09T19:05:12.089564Z  INFO wo::electron: received FRAME, sending ACK window=main seq=323 +2026-03-09T19:05:12.110190Z  INFO wo::electron: received FRAME, sending ACK window=main seq=324 +2026-03-09T19:05:12.140751Z  INFO wo::electron: received FRAME, sending ACK window=main seq=325 +2026-03-09T19:05:12.164765Z  INFO wo::electron: received FRAME, sending ACK window=main seq=326 +2026-03-09T19:05:12.177277Z  INFO wo::electron: received FRAME, sending ACK window=main seq=327 +2026-03-09T19:05:12.202364Z  INFO wo::electron: received FRAME, sending ACK window=main seq=328 +2026-03-09T19:05:12.218435Z  INFO wo::electron: received FRAME, sending ACK window=main seq=329 +2026-03-09T19:05:12.239689Z  INFO wo::electron: received FRAME, sending ACK window=main seq=330 +2026-03-09T19:05:12.255865Z  INFO wo::electron: received FRAME, sending ACK window=main seq=331 +2026-03-09T19:05:12.271073Z  INFO wo::electron: received FRAME, sending ACK window=main seq=332 +2026-03-09T19:05:12.286363Z  INFO wo::electron: received FRAME, sending ACK window=main seq=333 +2026-03-09T19:05:12.312331Z  INFO wo::electron: received FRAME, sending ACK window=main seq=334 +2026-03-09T19:05:12.328733Z  INFO wo::electron: received FRAME, sending ACK window=main seq=335 +2026-03-09T19:05:12.346479Z  INFO wo::electron: received FRAME, sending ACK window=main seq=336 +2026-03-09T19:05:12.373025Z  INFO wo::electron: received FRAME, sending ACK window=main seq=337 +2026-03-09T19:05:12.390977Z  INFO wo::electron: received FRAME, sending ACK window=main seq=338 +2026-03-09T19:05:12.407722Z  INFO wo::electron: received FRAME, sending ACK window=main seq=339 +2026-03-09T19:05:12.424472Z  INFO wo::electron: received FRAME, sending ACK window=main seq=340 +2026-03-09T19:05:12.441822Z  INFO wo::electron: received FRAME, sending ACK window=main seq=341 +2026-03-09T19:05:12.460188Z  INFO wo::electron: received FRAME, sending ACK window=main seq=342 +2026-03-09T19:05:12.477883Z  INFO wo::electron: received FRAME, sending ACK window=main seq=343 +2026-03-09T19:05:12.492498Z  INFO wo::electron: received FRAME, sending ACK window=main seq=344 +2026-03-09T19:05:12.513175Z  INFO wo::electron: received FRAME, sending ACK window=main seq=345 +2026-03-09T19:05:12.531739Z  INFO wo::electron: received FRAME, sending ACK window=main seq=346 +2026-03-09T19:05:12.545860Z  INFO wo::electron: received FRAME, sending ACK window=main seq=347 +2026-03-09T19:05:12.567429Z  INFO wo::electron: received FRAME, sending ACK window=main seq=348 +2026-03-09T19:05:12.586376Z  INFO wo::electron: received FRAME, sending ACK window=main seq=349 +2026-03-09T19:05:12.601073Z  INFO wo::electron: received FRAME, sending ACK window=main seq=350 +2026-03-09T19:05:12.621546Z  INFO wo::electron: received FRAME, sending ACK window=main seq=351 +2026-03-09T19:05:12.640222Z  INFO wo::electron: received FRAME, sending ACK window=main seq=352 +2026-03-09T19:05:12.654652Z  INFO wo::electron: received FRAME, sending ACK window=main seq=353 +2026-03-09T19:05:12.675364Z  INFO wo::electron: received FRAME, sending ACK window=main seq=354 +2026-03-09T19:05:12.693906Z  INFO wo::electron: received FRAME, sending ACK window=main seq=355 +2026-03-09T19:05:12.708264Z  INFO wo::electron: received FRAME, sending ACK window=main seq=356 +2026-03-09T19:05:12.729829Z  INFO wo::electron: received FRAME, sending ACK window=main seq=357 +2026-03-09T19:05:12.748635Z  INFO wo::electron: received FRAME, sending ACK window=main seq=358 +2026-03-09T19:05:12.762763Z  INFO wo::electron: received FRAME, sending ACK window=main seq=359 +2026-03-09T19:05:12.787127Z  INFO wo::electron: received FRAME, sending ACK window=main seq=360 +2026-03-09T19:05:12.803766Z  INFO wo::electron: received FRAME, sending ACK window=main seq=361 +2026-03-09T19:05:12.818997Z  INFO wo::electron: received FRAME, sending ACK window=main seq=362 +2026-03-09T19:05:12.837389Z  INFO wo::electron: received FRAME, sending ACK window=main seq=363 +2026-03-09T19:05:12.852794Z  INFO wo::electron: received FRAME, sending ACK window=main seq=364 +2026-03-09T19:05:12.873555Z  INFO wo::electron: received FRAME, sending ACK window=main seq=365 +2026-03-09T19:05:12.891577Z  INFO wo::electron: received FRAME, sending ACK window=main seq=366 +2026-03-09T19:05:12.905672Z  INFO wo::electron: received FRAME, sending ACK window=main seq=367 +2026-03-09T19:05:12.927162Z  INFO wo::electron: received FRAME, sending ACK window=main seq=368 +2026-03-09T19:05:12.947907Z  INFO wo::electron: received FRAME, sending ACK window=main seq=369 +2026-03-09T19:05:12.963667Z  INFO wo::electron: received FRAME, sending ACK window=main seq=370 +2026-03-09T19:05:12.982352Z  INFO wo::electron: received FRAME, sending ACK window=main seq=371 +2026-03-09T19:05:13.000854Z  INFO wo::electron: received FRAME, sending ACK window=main seq=372 +2026-03-09T19:05:13.015132Z  INFO wo::electron: received FRAME, sending ACK window=main seq=373 +2026-03-09T19:05:13.036803Z  INFO wo::electron: received FRAME, sending ACK window=main seq=374 +2026-03-09T19:05:13.056234Z  INFO wo::electron: received FRAME, sending ACK window=main seq=375 +2026-03-09T19:05:13.071863Z  INFO wo::electron: received FRAME, sending ACK window=main seq=376 +2026-03-09T19:05:13.091266Z  INFO wo::electron: received FRAME, sending ACK window=main seq=377 +2026-03-09T19:05:13.109715Z  INFO wo::electron: received FRAME, sending ACK window=main seq=378 +2026-03-09T19:05:13.123733Z  INFO wo::electron: received FRAME, sending ACK window=main seq=379 +2026-03-09T19:05:13.145413Z  INFO wo::electron: received FRAME, sending ACK window=main seq=380 +2026-03-09T19:05:13.163979Z  INFO wo::electron: received FRAME, sending ACK window=main seq=381 +2026-03-09T19:05:13.178681Z  INFO wo::electron: received FRAME, sending ACK window=main seq=382 +2026-03-09T19:05:13.199512Z  INFO wo::electron: received FRAME, sending ACK window=main seq=383 +2026-03-09T19:05:13.218213Z  INFO wo::electron: received FRAME, sending ACK window=main seq=384 +2026-03-09T19:05:13.232930Z  INFO wo::electron: received FRAME, sending ACK window=main seq=385 +2026-03-09T19:05:13.253482Z  INFO wo::electron: received FRAME, sending ACK window=main seq=386 +2026-03-09T19:05:13.272062Z  INFO wo::electron: received FRAME, sending ACK window=main seq=387 +2026-03-09T19:05:13.287568Z  INFO wo::electron: received FRAME, sending ACK window=main seq=388 +2026-03-09T19:05:13.306257Z  INFO wo::electron: received FRAME, sending ACK window=main seq=389 +2026-03-09T19:05:13.324128Z  INFO wo::electron: received FRAME, sending ACK window=main seq=390 +2026-03-09T19:05:13.340022Z  INFO wo::electron: received FRAME, sending ACK window=main seq=391 +2026-03-09T19:05:13.360564Z  INFO wo::electron: received FRAME, sending ACK window=main seq=392 +2026-03-09T19:05:13.379982Z  INFO wo::electron: received FRAME, sending ACK window=main seq=393 +2026-03-09T19:05:13.394802Z  INFO wo::electron: received FRAME, sending ACK window=main seq=394 +2026-03-09T19:05:13.415633Z  INFO wo::electron: received FRAME, sending ACK window=main seq=395 +2026-03-09T19:05:13.439081Z  INFO wo::electron: received FRAME, sending ACK window=main seq=396 +2026-03-09T19:05:13.457838Z  INFO wo::electron: received FRAME, sending ACK window=main seq=397 +2026-03-09T19:05:13.473913Z  INFO wo::electron: received FRAME, sending ACK window=main seq=398 +2026-03-09T19:05:13.494966Z  INFO wo::electron: received FRAME, sending ACK window=main seq=399 +2026-03-09T19:05:13.508544Z  INFO wo::electron: received FRAME, sending ACK window=main seq=400 +2026-03-09T19:05:13.523620Z  INFO wo::electron: received FRAME, sending ACK window=main seq=401 +2026-03-09T19:05:13.539501Z  INFO wo::electron: received FRAME, sending ACK window=main seq=402 +2026-03-09T19:05:13.563298Z  INFO wo::electron: received FRAME, sending ACK window=main seq=403 +2026-03-09T19:05:13.579611Z  INFO wo::electron: received FRAME, sending ACK window=main seq=404 +2026-03-09T19:05:13.596487Z  INFO wo::electron: received FRAME, sending ACK window=main seq=405 +2026-03-09T19:05:13.616174Z  INFO wo::electron: received FRAME, sending ACK window=main seq=406 +2026-03-09T19:05:13.631073Z  INFO wo::electron: received FRAME, sending ACK window=main seq=407 +2026-03-09T19:05:13.646849Z  INFO wo::electron: received FRAME, sending ACK window=main seq=408 +2026-03-09T19:05:13.664197Z  INFO wo::electron: received FRAME, sending ACK window=main seq=409 +2026-03-09T19:05:13.690689Z  INFO wo::electron: received FRAME, sending ACK window=main seq=410 +2026-03-09T19:05:13.708523Z  INFO wo::electron: received FRAME, sending ACK window=main seq=411 +2026-03-09T19:05:13.722851Z  INFO wo::electron: received FRAME, sending ACK window=main seq=412 +2026-03-09T19:05:13.743455Z  INFO wo::electron: received FRAME, sending ACK window=main seq=413 +2026-03-09T19:05:13.763570Z  INFO wo::electron: received FRAME, sending ACK window=main seq=414 +2026-03-09T19:05:13.782992Z  INFO wo::electron: received FRAME, sending ACK window=main seq=415 +2026-03-09T19:05:13.801121Z  INFO wo::electron: received FRAME, sending ACK window=main seq=416 +2026-03-09T19:05:13.825578Z  INFO wo::electron: received FRAME, sending ACK window=main seq=417 +2026-03-09T19:05:13.838722Z  INFO wo::electron: received FRAME, sending ACK window=main seq=418 +2026-03-09T19:05:13.855922Z  INFO wo::electron: received FRAME, sending ACK window=main seq=419 +2026-03-09T19:05:13.876609Z  INFO wo::electron: received FRAME, sending ACK window=main seq=420 +2026-03-09T19:05:13.900907Z  INFO wo::electron: received FRAME, sending ACK window=main seq=421 +2026-03-09T19:05:13.916321Z  INFO wo::electron: received FRAME, sending ACK window=main seq=422 +2026-03-09T19:05:13.935874Z  INFO wo::electron: received FRAME, sending ACK window=main seq=423 +2026-03-09T19:05:13.955127Z  INFO wo::electron: received FRAME, sending ACK window=main seq=424 +2026-03-09T19:05:13.978076Z  INFO wo::electron: received FRAME, sending ACK window=main seq=425 +2026-03-09T19:05:14.000845Z  INFO wo::electron: received FRAME, sending ACK window=main seq=426 +2026-03-09T19:05:14.017284Z  INFO wo::electron: received FRAME, sending ACK window=main seq=427 +2026-03-09T19:05:14.038754Z  INFO wo::electron: received FRAME, sending ACK window=main seq=428 +2026-03-09T19:05:14.056086Z  INFO wo::electron: received FRAME, sending ACK window=main seq=429 +2026-03-09T19:05:14.073033Z  INFO wo::electron: received FRAME, sending ACK window=main seq=430 +2026-03-09T19:05:14.093819Z  INFO wo::electron: received FRAME, sending ACK window=main seq=431 +2026-03-09T19:05:14.110765Z  INFO wo::electron: received FRAME, sending ACK window=main seq=432 +2026-03-09T19:05:14.131288Z  INFO wo::electron: received FRAME, sending ACK window=main seq=433 +2026-03-09T19:05:14.147637Z  INFO wo::electron: received FRAME, sending ACK window=main seq=434 +2026-03-09T19:05:14.162861Z  INFO wo::electron: received FRAME, sending ACK window=main seq=435 +2026-03-09T19:05:14.180438Z  INFO wo::electron: received FRAME, sending ACK window=main seq=436 +2026-03-09T19:05:14.194591Z  INFO wo::electron: received FRAME, sending ACK window=main seq=437 +2026-03-09T19:05:14.220352Z  INFO wo::electron: received FRAME, sending ACK window=main seq=438 +2026-03-09T19:05:14.237740Z  INFO wo::electron: received FRAME, sending ACK window=main seq=439 +2026-03-09T19:05:14.253159Z  INFO wo::electron: received FRAME, sending ACK window=main seq=440 +2026-03-09T19:05:14.276561Z  INFO wo::electron: received FRAME, sending ACK window=main seq=441 +2026-03-09T19:05:14.291959Z  INFO wo::electron: received FRAME, sending ACK window=main seq=442 +2026-03-09T19:05:14.312479Z  INFO wo::electron: received FRAME, sending ACK window=main seq=443 +2026-03-09T19:05:14.325942Z  INFO wo::electron: received FRAME, sending ACK window=main seq=444 +2026-03-09T19:05:14.344599Z  INFO wo::electron: received FRAME, sending ACK window=main seq=445 +2026-03-09T19:05:14.360100Z  INFO wo::electron: received FRAME, sending ACK window=main seq=446 +2026-03-09T19:05:14.379636Z  INFO wo::electron: received FRAME, sending ACK window=main seq=447 +2026-03-09T19:05:14.393127Z  INFO wo::electron: received FRAME, sending ACK window=main seq=448 +2026-03-09T19:05:14.410253Z  INFO wo::electron: received FRAME, sending ACK window=main seq=449 +2026-03-09T19:05:14.433364Z  INFO wo::electron: received FRAME, sending ACK window=main seq=450 +2026-03-09T19:05:14.452105Z  INFO wo::electron: received FRAME, sending ACK window=main seq=451 +2026-03-09T19:05:14.470881Z  INFO wo::electron: received FRAME, sending ACK window=main seq=452 +2026-03-09T19:05:14.492229Z  INFO wo::electron: received FRAME, sending ACK window=main seq=453 +2026-03-09T19:05:14.512036Z  INFO wo::electron: received FRAME, sending ACK window=main seq=454 +[Wo] ERROR sending frame: Error: EPIPE: broken pipe, write +[Wo] ERROR sending frame: Error: EPIPE: broken pipe, write +[Wo] IPC connection closed +[Wo] SKIPPED paint (dmabufSender=false ipcConnected=false)