diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 95999ff2..f7e22aba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,8 +11,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v18 + - uses: cachix/install-nix-action@v22 with: nix_path: nixpkgs=channel:nixpkgs-unstable - - run: nix build + - run: GIT_LFS_SKIP_SMUDGE=1 nix build - run: nix flake check diff --git a/Cargo.lock b/Cargo.lock index 542f3cfa..10627f9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,17 +2,11 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - [[package]] name = "ab_glyph" -version = "0.2.20" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe21446ad43aa56417a767f3e2f3d7c4ca522904de1dd640529a76e9c5c3b33c" +checksum = "80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -24,11 +18,21 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +[[package]] +name = "accesskit" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76eb1adf08c5bcaa8490b9851fd53cca27fa9880076f178ea9d29f05196728a8" +dependencies = [ + "enumn", + "serde", +] + [[package]] name = "addr2line" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -41,9 +45,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ "getrandom", "once_cell", @@ -52,20 +56,23 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", + "getrandom", "once_cell", + "serde", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -76,6 +83,45 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "almost" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa2999eb46af81abb65c2d30d446778d7e613b60bbf4e174a027e80f90a3c14" + +[[package]] +name = "android-activity" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052ad56e336bcc615a214bffbeca6c181ee9550acec193f0327e0b103b033a4d" +dependencies = [ + "android-properties", + "bitflags 2.4.1", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -87,9 +133,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" dependencies = [ "backtrace", ] @@ -124,6 +170,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + [[package]] name = "arrayref" version = "0.3.7" @@ -132,30 +184,47 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.5.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] -name = "arrayvec" -version = "0.7.2" +name = "as-raw-xcb-connection" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "2d5f312b0a56c5cdf967c0aeb67f6289603354951683bc97ddc595ab974ba9aa" [[package]] name = "ash" -version = "0.37.2+1.3.238" +version = "0.37.3+1.3.251" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28bf19c1f0a470be5fbf7522a308a05df06610252c5bcf5143e1b23f629a9a03" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" dependencies = [ - "libloading", + "libloading 0.7.4", ] [[package]] -name = "atomic_refcell" -version = "0.1.9" +name = "async-task" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atomicwrites" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "857253367827bd9d0fd973f0ef15506a96e79e41b0ad7aa691203a4e3214f6c8" +checksum = "f4d45f362125ed144544e57b0ec6de8fd6a296d41a6252fc4a20c0cf12e9ed3a" +dependencies = [ + "rustix", + "tempfile", + "windows-sys 0.48.0", +] [[package]] name = "autocfg" @@ -165,15 +234,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", + "miniz_oxide", "object", "rustc-demangle", ] @@ -184,6 +253,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + [[package]] name = "bincode" version = "1.3.3" @@ -220,6 +295,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +dependencies = [ + "serde", +] + [[package]] name = "block" version = "0.1.6" @@ -235,61 +319,106 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd7cf50912cddc06dc5ea7c08c5e81c1b2c842a70d19def1848d54c586fed92" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys", + "objc2", +] + [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.39", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "calloop" -version = "0.10.5" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192" +checksum = "7b50b5a44d59a98c55a9eeb518f39bf7499ba19fd98ee7d22618687f3f10adbf" dependencies = [ - "futures-util", + "async-task", + "bitflags 2.4.1", "log", - "nix 0.25.1", - "slotmap", + "polling", + "rustix", + "slab", "thiserror", - "vec_map", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix", + "wayland-backend 0.3.2", + "wayland-client 0.31.1", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -318,27 +447,26 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation", - "core-graphics", - "foreign-types", + "core-graphics 0.22.3", + "foreign-types 0.3.2", "libc", "objc", ] [[package]] name = "cocoa-foundation" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", - "foreign-types", "libc", "objc", ] @@ -360,10 +488,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "const_panic" -version = "0.2.7" +name = "com-rs" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58baae561b85ca19b3122a9ddd35c8ec40c3bcd14fe89921824eae73f7baffbf" +checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +dependencies = [ + "crossbeam-utils", +] [[package]] name = "core-foundation" @@ -387,22 +534,34 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ - "bitflags", + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +dependencies = [ + "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", - "foreign-types", "libc", ] @@ -411,66 +570,109 @@ name = "cosmic-comp" version = "0.1.0" dependencies = [ "anyhow", - "bitflags", + "bitflags 2.4.1", "bytemuck", "calloop", + "cosmic-comp-config", + "cosmic-config", "cosmic-protocols", "edid-rs", "egui", - "glow 0.11.2", - "iced_softbuffer", + "egui_plot", + "glow", + "i18n-embed", + "i18n-embed-fl", + "iced_tiny_skia", "id_tree", - "indexmap", + "indexmap 2.1.0", + "keyframe", "lazy_static", + "libc", "libcosmic", "libsystemd", "log-panics", + "once_cell", "ordered-float", "png", - "puffin 0.14.3", + "puffin", "puffin_egui", "regex", "renderdoc", - "ron 0.7.1", + "ron", + "rust-embed", "sendfd", "serde", "serde_json", "smithay", "smithay-egui", "thiserror", + "tiny-skia 0.10.0", "tracing", "tracing-journald", "tracing-subscriber", - "wayland-backend", - "wayland-scanner 0.30.0", + "wayland-backend 0.3.2", + "wayland-scanner 0.31.0", "xcursor", "xdg", - "xkbcommon 0.4.1", + "xkbcommon", +] + +[[package]] +name = "cosmic-comp-config" +version = "0.1.0" +dependencies = [ + "input", + "serde", +] + +[[package]] +name = "cosmic-config" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" +dependencies = [ + "atomicwrites", + "calloop", + "cosmic-config-derive", + "dirs 5.0.1", + "iced_futures", + "notify", + "ron", + "serde", +] + +[[package]] +name = "cosmic-config-derive" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" +dependencies = [ + "quote", + "syn 1.0.109", ] [[package]] name = "cosmic-protocols" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#7d80b59afc464a8ecdb8001333f18de554f299f4" +source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#5faec87be0a1fd1d72e99431ac8e6647ff1dfd41" dependencies = [ - "bitflags", - "wayland-backend", - "wayland-protocols 0.30.0", - "wayland-scanner 0.30.0", + "bitflags 2.4.1", + "wayland-backend 0.3.2", + "wayland-protocols", + "wayland-scanner 0.31.0", "wayland-server", ] [[package]] name = "cosmic-text" -version = "0.7.0" -source = "git+https://github.com/pop-os/cosmic-text?rev=e788c175#e788c175ec31094b04dcacbc0537dba4433afcfc" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b68966c2543609f8d92f9d33ac3b719b2a67529b0c6c0b3e025637b477eef9" dependencies = [ - "fontdb 0.13.0", + "aliasable", + "fontdb", "libm", "log", - "ouroboros 0.15.6", "rangemap", - "rustybuzz 0.7.0", + "rustybuzz 0.8.0", "swash", "sys-locale", "unicode-bidi", @@ -482,22 +684,22 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-theme.git#a1258308a894c5c7bbe6e261271e8476d55955d3" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ - "anyhow", + "almost", + "cosmic-config", "csscolorparser", - "directories", "lazy_static", "palette", - "ron 0.8.0", + "ron", "serde", ] [[package]] name = "cpufeatures" -version = "0.2.6" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -534,22 +736,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.8.0", + "memoffset 0.9.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -570,6 +772,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "css-color" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d101c65424c856131a3cb818da2ddde03500dc3656972269cdf79f018ef77eb4" + [[package]] name = "csscolorparser" version = "0.6.2" @@ -581,124 +789,102 @@ dependencies = [ ] [[package]] -name = "cty" -version = "0.2.2" +name = "cursor-icon" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] name = "d3d12" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "827914e1f53b1e0e025ecd3d967a7836b7bcb54520f90e21ef8df7b4d88a2759" +checksum = "d8f0de2f5a8e7bd4a9eec0e3c781992a4ce1724f68aec7d7a3715344de8b39da" dependencies = [ - "bitflags", - "libloading", + "bitflags 1.3.2", + "libloading 0.7.4", "winapi", ] [[package]] name = "darling" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core 0.10.2", - "darling_macro 0.10.2", -] - -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - -[[package]] -name = "darling_core" -version = "0.10.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.9.3", - "syn 1.0.109", + "darling_core", + "darling_macro", ] [[package]] name = "darling_core" -version = "0.13.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 1.0.109", + "strsim", + "syn 2.0.39", ] [[package]] name = "darling_macro" -version = "0.10.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core 0.10.2", + "darling_core", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] -name = "darling_macro" -version = "0.13.4" +name = "dashmap" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", + "cfg-if", + "hashbrown 0.14.2", + "lock_api", + "once_cell", + "parking_lot_core 0.9.9", ] [[package]] name = "data-url" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" -dependencies = [ - "matches", -] +checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" [[package]] -name = "data-url" -version = "0.2.0" +name = "deranged" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] [[package]] name = "derive_setters" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1cf41b4580a37cca5ef2ada2cc43cf5d6be3983f4522e83010d67ab6925e84b" +checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d" dependencies = [ - "darling 0.10.2", + "darling", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -706,21 +892,21 @@ dependencies = [ ] [[package]] -name = "directories" -version = "4.0.1" -source = "git+https://github.com/edfloreshz/directories-rs#6a6d83d853a35ee3273034215c4defaf61286fe5" +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ - "anyhow", - "dirs-sys", + "dirs-sys 0.3.7", ] [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys", + "dirs-sys 0.4.1", ] [[package]] @@ -734,19 +920,42 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "dlib" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading", + "libloading 0.8.1", ] [[package]] @@ -763,25 +972,25 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "drm" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf9159ef4bcecd0c5e4cbeb573b8d0037493403d542780dba5d840bbf9df56f" +checksum = "97fb1b703ffbc7ebd216eba7900008049a56ace55580ecb2ee7fa801e8d8be87" dependencies = [ - "bitflags", + "bitflags 2.4.1", "bytemuck", "drm-ffi", "drm-fourcc", - "nix 0.26.2", + "nix 0.27.1", ] [[package]] name = "drm-ffi" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1352481b7b90e27a8a1bf8ef6b33cf18b98dba7c410e75c24bb3eef2f0d8d525" +checksum = "ba7d1c19c4b6270e89d59fb27dc6d02a317c658a8a54e54781e1db9b5947595d" dependencies = [ "drm-sys", - "nix 0.26.2", + "nix 0.27.1", ] [[package]] @@ -792,20 +1001,18 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" [[package]] name = "drm-sys" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1369f1679d6b706d234c4c1e0613c415c2c74b598a09ad28080ba2474b72e42d" -dependencies = [ - "libc", -] +checksum = "3a4f1c0468062a56cd5705f1e3b5409eb286d5596a2028ec8e947595d7e715ae" [[package]] name = "ecolor" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f99fe3cac305af9d6d92971af60d0f7ea4d783201ef1673571567b6699964d9" +checksum = "cfdf4e52dbbb615cfd30cf5a5265335c217b5fd8d669593cea74a517d9c605af" dependencies = [ "bytemuck", + "serde", ] [[package]] @@ -816,22 +1023,27 @@ checksum = "2ab5fa33485cd85ac354df485819a63360fefa312fe04cffe65e6f175be1522c" [[package]] name = "egui" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6412a21e0bde7c0918f7fb44bbbb86b5e1f88e63c026a4e747cc7af02f76dfbe" +checksum = "8bd69fed5fcf4fbb8225b24e80ea6193b61e17a625db105ef0c4d71dde6eb8b7" dependencies = [ - "ahash 0.8.3", + "accesskit", + "ahash 0.8.6", "epaint", "nohash-hasher", + "serde", ] [[package]] name = "egui_extras" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f051342e97dfa2445107cb7d2e720617f5c840199b5cb4fe0ffcf481fcf5cce" +checksum = "68ffe3fe5c00295f91c2a61a74ee271c32f74049c94ba0b1cea8f26eb478bc07" dependencies = [ "egui", + "enum-map", + "log", + "mime_guess", "resvg 0.28.0", "serde", "tiny-skia 0.8.4", @@ -840,176 +1052,125 @@ dependencies = [ [[package]] name = "egui_glow" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8257332fb168a965b3dca81d6a344e053153773c889cabdba0b3b76f1629ae81" +checksum = "ce6726c08798822280038bbad2e32f4fc3cbed800cd51c6e34e99cd2d60cc1bc" dependencies = [ "bytemuck", "egui", - "glow 0.12.1", + "glow", + "log", "memoffset 0.6.5", - "tracing", "wasm-bindgen", "web-sys", ] [[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "emath" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ecd80612937e0267909d5351770fe150004e24dab93954f69ca62eecd3f77e" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "encase" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a516181e9a36e8982cb37933c5e7dba638c42938cacde46ee4e5b4156f881b9" -dependencies = [ - "const_panic", - "encase_derive", - "glam", - "thiserror", -] - -[[package]] -name = "encase_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5b802412eea315f29f2bb2da3a5963cd6121f56eaa06aebcdc0c54eea578f22" -dependencies = [ - "encase_derive_impl", -] - -[[package]] -name = "encase_derive_impl" -version = "0.3.0" +name = "egui_plot" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2f4de457d974f548d2c2a16f709ebd81013579e543bd1a9b19ced88132c2cf" +checksum = "c7f33a00fe8eb1ba56535b3dbacdecc7a1365a328908a97c5f3c81bb466be72b" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "egui", ] [[package]] -name = "encoding" -version = "0.2.33" +name = "either" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" -dependencies = [ - "encoding-index-japanese", - "encoding-index-korean", - "encoding-index-simpchinese", - "encoding-index-singlebyte", - "encoding-index-tradchinese", -] +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] -name = "encoding-index-japanese" -version = "1.20141219.5" +name = "emath" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +checksum = "1ef2b29de53074e575c18b694167ccbe6e5191f7b25fe65175a0d905a32eeec0" dependencies = [ - "encoding_index_tests", + "bytemuck", + "serde", ] [[package]] -name = "encoding-index-korean" -version = "1.20141219.5" +name = "encoding_rs" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "encoding_index_tests", + "cfg-if", ] [[package]] -name = "encoding-index-simpchinese" -version = "1.20141219.5" +name = "enum-map" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +checksum = "53337c2dbf26a3c31eccc73a37b10c1614e8d4ae99b6a50d553e8936423c1f16" dependencies = [ - "encoding_index_tests", + "enum-map-derive", + "serde", ] [[package]] -name = "encoding-index-singlebyte" -version = "1.20141219.5" +name = "enum-map-derive" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +checksum = "04d0b288e3bb1d861c4403c1774a6f7a798781dfc519b3647df2a3dd4ae95f25" dependencies = [ - "encoding_index_tests", + "proc-macro2", + "quote", + "syn 2.0.39", ] [[package]] -name = "encoding-index-tradchinese" -version = "1.20141219.5" +name = "enumn" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ - "encoding_index_tests", + "proc-macro2", + "quote", + "syn 2.0.39", ] -[[package]] -name = "encoding_index_tests" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" - [[package]] name = "epaint" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e78b5c58a1f7f621f9d546add2adce20636422c9b251e29f749e8a2f713c95" +checksum = "58067b840d009143934d91d8dcb8ded054d8301d7c11a517ace0a99bb1e1595e" dependencies = [ "ab_glyph", - "ahash 0.8.3", - "atomic_refcell", + "ahash 0.8.6", "bytemuck", "ecolor", "emath", "nohash-hasher", "parking_lot 0.12.1", + "serde", ] [[package]] -name = "errno" -version = "0.2.8" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ - "errno-dragonfly", "libc", "windows-sys 0.48.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "etagere" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "5bf70b9ea3a235a7432b4f481854815e2d4fb2fe824c1f5fb09b8985dd06b3e9" dependencies = [ - "cc", - "libc", + "euclid", + "svg_fmt", ] [[package]] @@ -1023,20 +1184,26 @@ dependencies = [ [[package]] name = "exr" -version = "1.6.3" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd2162b720141a91a054640662d3edce3d50a944a50ffca5313cd951abb35b4" +checksum = "279d3efcc55e19917fff7ab3ddd6c14afb6a90881a0078465196fe2f99d08c56" dependencies = [ "bit_field", "flume", "half", "lebe", - "miniz_oxide 0.6.2", + "miniz_oxide", "rayon-core", "smallvec", "zune-inflate", ] +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fastrand" version = "1.9.0" @@ -1046,48 +1213,110 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "fdeflate" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" dependencies = [ "simd-adler32", ] +[[package]] +name = "filetime" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "windows-sys 0.48.0", +] + [[package]] name = "find-crate" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", - "miniz_oxide 0.6.2", + "miniz_oxide", ] [[package]] name = "float-cmp" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ "num-traits", ] [[package]] -name = "float-cmp" -version = "0.9.0" +name = "float_next_after" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + +[[package]] +name = "fluent" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f69378194459db76abd2ce3952b790db103ceb003008d3d50d97c41ff847a7" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash", + "self_cell", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78" +dependencies = [ + "thiserror", +] [[package]] name = "flume" @@ -1109,26 +1338,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "fontdb" -version = "0.6.2" +name = "fontconfig-parser" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d66551cc28351f0bc6a73da86459ee7765caaad03ce284f2dc36472dbf539cd" +checksum = "674e258f4b5d2dcd63888c01c68413c51f565e8af99d2f7701c7b81d79ef41c4" dependencies = [ - "log", - "memmap2 0.3.1", - "ttf-parser 0.12.3", + "roxmltree 0.18.1", ] [[package]] name = "fontdb" -version = "0.13.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfec8f19f9b89b2901219cc62604810d2bfef15dc1182e95320f57e7cbbe041a" +checksum = "af8d8cbea8f21307d7e84bca254772981296f058a1d36b461bf4d83a7499fc9e" dependencies = [ + "fontconfig-parser", "log", - "memmap2 0.5.10", + "memmap2 0.6.2", "slotmap", - "ttf-parser 0.18.1", + "tinyvec", + "ttf-parser 0.19.2", ] [[package]] @@ -1137,7 +1366,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", ] [[package]] @@ -1146,6 +1396,21 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fraction" version = "0.13.1" @@ -1158,22 +1423,31 @@ dependencies = [ [[package]] name = "freedesktop-icons" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e61ac115df4632b592d36b71fda3c259f4c8061c70b7fa429bac145890e880" +checksum = "3f9d46a9ae065c46efb83854bb10315de6d333bb6f4526ebe320c004dab7857e" dependencies = [ - "dirs", + "dirs 4.0.0", "once_cell", "rust-ini", "thiserror", "xdg", ] +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -1186,9 +1460,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -1196,15 +1470,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -1214,38 +1488,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -1259,27 +1533,18 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "gbm" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ec389cda876966cf824111bf6e533fb934c711d473498279964a990853b3c6" +checksum = "57c97c1672f2d951da311cd20b148794c4157a8879c7650e65f76c7826e2b1c1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "drm", "drm-fourcc", "gbm-sys", "libc", - "wayland-backend", + "wayland-backend 0.3.2", "wayland-server", ] @@ -1312,11 +1577,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "gethostname" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -1337,9 +1612,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "gl_generator" @@ -1354,27 +1629,15 @@ dependencies = [ [[package]] name = "glam" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" - -[[package]] -name = "glow" -version = "0.11.2" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" -dependencies = [ - "js-sys", - "slotmap", - "wasm-bindgen", - "web-sys", -] +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" [[package]] name = "glow" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e007a07a24de5ecae94160f141029e9a347282cfe25d1d58d85d845cf3130f1" +checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" dependencies = [ "js-sys", "slotmap", @@ -1383,62 +1646,24 @@ dependencies = [ ] [[package]] -name = "glow_glyph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4e62c64947b9a24fe20e2bba9ad819ecb506ef5c8df7ffc4737464c6df9510" -dependencies = [ - "bytemuck", - "glow 0.11.2", - "glyph_brush", - "log", -] - -[[package]] -name = "glyph_brush" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edefd123f28a0b1d41ec4a489c2b43020b369180800977801611084f342978d" -dependencies = [ - "glyph_brush_draw_cache", - "glyph_brush_layout", - "ordered-float", - "rustc-hash", - "twox-hash", -] - -[[package]] -name = "glyph_brush_draw_cache" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6010675390f6889e09a21e2c8b575b3ee25667ea8237a8d59423f73cb8c28610" -dependencies = [ - "ab_glyph", - "crossbeam-channel", - "crossbeam-deque", - "linked-hash-map", - "rayon", - "rustc-hash", -] - -[[package]] -name = "glyph_brush_layout" -version = "0.2.3" +name = "glyphon" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38" +checksum = "5e87caa7459145f5e5f167bf34db4532901404c679e62339fb712a0e3ccf722a" dependencies = [ - "ab_glyph", - "approx 0.5.1", - "xi-unicode", + "cosmic-text", + "etagere", + "lru", + "wgpu", ] [[package]] name = "gpu-alloc" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d" +checksum = "22beaafc29b38204457ea030f6fb7a84c9e4dd1b86e311ba0542533453d87f62" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gpu-alloc-types", ] @@ -1448,29 +1673,48 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "gpu-allocator" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +dependencies = [ + "backtrace", + "log", + "thiserror", + "winapi", + "windows", ] [[package]] name = "gpu-descriptor" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" +checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ - "bitflags", + "bitflags 2.4.1", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.14.2", ] [[package]] name = "gpu-descriptor-types" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126" +checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" dependencies = [ - "bitflags", + "bitflags 2.4.1", ] +[[package]] +name = "grid" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df00eed8d1f0db937f6be10e46e8072b0671accb504cf0f959c5c52c679f5b9" + [[package]] name = "guillotiere" version = "0.6.2" @@ -1483,10 +1727,11 @@ dependencies = [ [[package]] name = "half" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" dependencies = [ + "cfg-if", "crunchy", ] @@ -1496,23 +1741,45 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", ] [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "hashbrown" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ + "ahash 0.8.6", + "allocator-api2", +] + +[[package]] +name = "hassle-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1397650ee315e8891a0df210707f0fc61771b0cc518c3023896064c5407cb3b0" +dependencies = [ + "bitflags 1.3.2", + "com-rs", "libc", + "libloading 0.7.4", + "thiserror", + "widestring", + "winapi", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hexf-parse" @@ -1529,165 +1796,234 @@ dependencies = [ "digest", ] +[[package]] +name = "i18n-config" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ce3c48cbc21fd5b22b9331f32b5b51f6ad85d969b99e793427332e76e7640" +dependencies = [ + "log", + "serde", + "serde_derive", + "thiserror", + "toml 0.8.6", + "unic-langid", +] + +[[package]] +name = "i18n-embed" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94205d95764f5bb9db9ea98fa77f89653365ca748e27161f5bbea2ffd50e459c" +dependencies = [ + "arc-swap", + "fluent", + "fluent-langneg", + "fluent-syntax", + "i18n-embed-impl", + "intl-memoizer", + "lazy_static", + "locale_config", + "log", + "parking_lot 0.12.1", + "rust-embed", + "thiserror", + "unic-langid", + "walkdir", +] + +[[package]] +name = "i18n-embed-fl" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc1f8715195dffc4caddcf1cf3128da15fe5d8a137606ea8856c9300047d5a2" +dependencies = [ + "dashmap", + "find-crate", + "fluent", + "fluent-syntax", + "i18n-config", + "i18n-embed", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.39", + "unic-langid", +] + +[[package]] +name = "i18n-embed-impl" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a4d5bff745c9a6e1459c490059281b353a4ab0a4e1e58b3eeeaef71f97d07b" +dependencies = [ + "find-crate", + "i18n-config", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "iced" -version = "0.6.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +version = "0.10.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ "iced_core", - "iced_dyrend", "iced_futures", - "iced_glow", - "iced_graphics", - "iced_native", - "iced_softbuffer", - "iced_wgpu", + "iced_renderer", + "iced_widget", "image", "thiserror", ] [[package]] name = "iced_core" -version = "0.6.2" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" -dependencies = [ - "bitflags", - "palette", - "wasm-timer", -] - -[[package]] -name = "iced_dyrend" -version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +version = "0.10.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ - "iced_glow", - "iced_graphics", - "iced_native", - "iced_softbuffer", - "iced_wgpu", + "bitflags 1.3.2", + "instant", "log", - "raw-window-handle 0.5.2", + "palette", + "thiserror", + "twox-hash", ] [[package]] name = "iced_futures" -version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +version = "0.7.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ "futures", + "iced_core", "log", "wasm-bindgen-futures", "wasm-timer", ] -[[package]] -name = "iced_glow" -version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" -dependencies = [ - "bytemuck", - "euclid", - "glow 0.11.2", - "glow_glyph", - "glyph_brush", - "iced_graphics", - "iced_native", - "log", -] - [[package]] name = "iced_graphics" -version = "0.5.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +version = "0.9.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytemuck", "glam", - "iced_native", - "iced_style", + "half", + "iced_core", "image", "kamadak-exif", "log", + "lyon_path", "raw-window-handle 0.5.2", - "resvg 0.18.0", "thiserror", - "tiny-skia 0.6.6", - "usvg 0.18.0", ] [[package]] -name = "iced_lazy" -version = "0.3.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +name = "iced_renderer" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ - "iced_native", - "ouroboros 0.13.0", + "iced_graphics", + "iced_tiny_skia", + "iced_wgpu", + "log", + "raw-window-handle 0.5.2", + "thiserror", ] [[package]] -name = "iced_native" -version = "0.7.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +name = "iced_runtime" +version = "0.1.1" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ "iced_core", "iced_futures", - "iced_style", - "num-traits", - "twox-hash", - "unicode-segmentation", + "thiserror", +] + +[[package]] +name = "iced_style" +version = "0.9.0" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" +dependencies = [ + "iced_core", + "once_cell", + "palette", ] [[package]] -name = "iced_softbuffer" +name = "iced_tiny_skia" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ + "bytemuck", "cosmic-text", "iced_graphics", - "iced_native", - "lazy_static", + "kurbo 0.9.5", "log", - "raqote", "raw-window-handle 0.5.2", + "resvg 0.35.0", + "rustc-hash", "softbuffer", -] - -[[package]] -name = "iced_style" -version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" -dependencies = [ - "iced_core", - "once_cell", - "palette", + "tiny-skia 0.10.0", + "twox-hash", ] [[package]] name = "iced_wgpu" -version = "0.7.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +version = "0.11.1" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytemuck", - "encase", "futures", "glam", - "glyph_brush", + "glyphon", "guillotiere", "iced_graphics", - "iced_native", "log", + "lyon", + "once_cell", "raw-window-handle 0.5.2", + "resvg 0.35.0", + "rustc-hash", + "twox-hash", "wgpu", - "wgpu_glyph", +] + +[[package]] +name = "iced_widget" +version = "0.1.3" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" +dependencies = [ + "iced_renderer", + "iced_runtime", + "iced_style", + "num-traits", + "ouroboros", + "thiserror", + "unicode-segmentation", +] + +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2", + "dispatch", + "objc2", ] [[package]] name = "id_tree" version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd9db8dd5be8bde5a2624ed4b2dfb74368fe7999eb9c4940fd3ca344b61071a" +source = "git+https://github.com/Drakulix/id-tree.git?branch=feature/copy_clone#632a57d6d49160e18d7300fa7edae52281ec5482" dependencies = [ "snowflake", ] @@ -1698,18 +2034,28 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "image" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ "bytemuck", "byteorder", "color_quant", "exr", "gif", - "jpeg-decoder 0.3.0", + "jpeg-decoder", "num-rational", "num-traits", "png", @@ -1723,6 +2069,12 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df19da1e92fbfec043ca97d622955381b1f3ee72a180ec999912df31b1ccd951" +[[package]] +name = "imagesize" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" + [[package]] name = "indexmap" version = "1.9.3" @@ -1730,21 +2082,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "input" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb3afdf1f8137428002b354eaf87aa629178995683941d94b04c6d145ec8937" +checksum = "e6e74cd82cedcd66db78742a8337bdc48f188c4d2c12742cbc5cd85113f0b059" dependencies = [ - "bitflags", + "bitflags 1.3.2", "input-sys", - "io-lifetimes", + "io-lifetimes 1.0.11", "libc", - "udev", + "log", + "udev 0.7.0", ] [[package]] @@ -1763,27 +2146,65 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", +] + +[[package]] +name = "intl-memoizer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", ] [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] +[[package]] +name = "io-lifetimes" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb4def18c48926ccac55c1223e02865ce1a821751a95920448662696e7472c" + [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] [[package]] name = "jni-sys" @@ -1793,19 +2214,13 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" - [[package]] name = "jpeg-decoder" version = "0.3.0" @@ -1817,9 +2232,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -1833,6 +2248,16 @@ dependencies = [ "mutate_once", ] +[[package]] +name = "keyframe" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60708bf7981518d09095d6f5673ce5cf6a64f1e0d9708b554f670e6d9d2bd9a9" +dependencies = [ + "mint", + "num-traits", +] + [[package]] name = "khronos-egl" version = "4.1.0" @@ -1840,7 +2265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" dependencies = [ "libc", - "libloading", + "libloading 0.7.4", "pkg-config", ] @@ -1850,13 +2275,42 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "kurbo" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb348d766edbac91ba1eb83020d96f4f8867924d194393083c15a51f185e6a82" +checksum = "7a53776d271cfb873b17c618af0298445c88afc52837f3e948fa3fafd131f449" dependencies = [ - "arrayvec 0.5.2", + "arrayvec", +] + +[[package]] +name = "kurbo" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +dependencies = [ + "arrayvec", ] [[package]] @@ -1873,29 +2327,38 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic?rev=24709e9c3b#24709e9c3b56c49a0af168d1e37ebef85f112c8a" +source = "git+https://github.com/pop-os/libcosmic/#42f24b7ee2cb5f715d137e61c6b7c4af3e27196a" dependencies = [ "apply", + "cosmic-config", "cosmic-theme", + "css-color", "derive_setters", "fraction", "freedesktop-icons", "iced", "iced_core", - "iced_lazy", - "iced_native", - "iced_softbuffer", + "iced_futures", + "iced_renderer", + "iced_runtime", "iced_style", + "iced_tiny_skia", + "iced_widget", "lazy_static", "palette", "slotmap", + "taffy", + "thiserror", + "tracing", + "unicode-segmentation", + "url", ] [[package]] @@ -1908,21 +2371,53 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "libm" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] [[package]] name = "libseat" -version = "0.1.7" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "845e5c255462c9bc7c71c17b996766b76e3c66f2ddd5846bfbc83f18382aa648" +checksum = "54a0adf8d8607a73a5b74cbe4132f57cb349e4bf860103cd089461bbcbc9907e" dependencies = [ - "errno 0.2.8", + "errno", "libseat-sys", - "slog", + "log", ] [[package]] @@ -1936,14 +2431,14 @@ dependencies = [ [[package]] name = "libsystemd" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8144587c71c16756b1055d3dcb0c75cb605a10ecd6523cc33702d5f90902bf6d" +checksum = "88b9597a67aa1c81a6624603e6bd0bcefb9e0f94c9c54970ec53771082104b4e" dependencies = [ "hmac", "libc", "log", - "nix 0.23.2", + "nix 0.26.4", "nom", "once_cell", "serde", @@ -1963,22 +2458,29 @@ dependencies = [ ] [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "linux-raw-sys" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] -name = "linux-raw-sys" -version = "0.3.1" +name = "locale_config" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934" +dependencies = [ + "lazy_static", + "objc", + "objc-foundation", + "regex", + "winapi", +] [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1986,12 +2488,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "log-panics" @@ -2003,17 +2502,73 @@ dependencies = [ "log", ] +[[package]] +name = "lru" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +dependencies = [ + "hashbrown 0.14.2", +] + +[[package]] +name = "lyon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7f9cda98b5430809e63ca5197b06c7d191bf7e26dfc467d5a3f0290e2a74f" +dependencies = [ + "lyon_algorithms", + "lyon_tessellation", +] + +[[package]] +name = "lyon_algorithms" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00a0349cd8f0270781bb93a824b63df6178e3b4a27794e7be3ce3763f5a44d6e" +dependencies = [ + "lyon_path", + "num-traits", +] + [[package]] name = "lyon_geom" -version = "0.17.7" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d89ccbdafd83d259403e22061be27bccc3254bba65cdc5303250c4227c8c8e" +checksum = "74df1ff0a0147282eb10699537a03baa7d31972b58984a1d44ce0624043fe8ad" dependencies = [ - "arrayvec 0.5.2", + "arrayvec", "euclid", "num-traits", ] +[[package]] +name = "lyon_path" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca507745ba7ccbc76e5c44e7b63b1a29d2b0d6126f375806a5bbaf657c7d6c45" +dependencies = [ + "lyon_geom", + "num-traits", +] + +[[package]] +name = "lyon_tessellation" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23bcac20d47825850fabf1e869bf7c2bbe2daefa0776c3cd2eb7cb74635f6e4a" +dependencies = [ + "float_next_after", + "lyon_path", + "thiserror", +] + +[[package]] +name = "lz4_flex" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea9b256699eda7b0387ffbc776dd625e28bde3918446381781245b7a50349d8" + [[package]] name = "malloc_buf" version = "0.0.6" @@ -2029,35 +2584,38 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] -name = "matches" -version = "0.1.10" +name = "memchr" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] -name = "memchr" -version = "2.5.0" +name = "memmap2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" +dependencies = [ + "libc", +] [[package]] name = "memmap2" -version = "0.3.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" +checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" dependencies = [ "libc", ] [[package]] name = "memmap2" -version = "0.5.10" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375" dependencies = [ "libc", ] @@ -2082,9 +2640,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -2095,29 +2653,36 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", "log", "objc", ] [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "miniz_oxide" -version = "0.6.2" +name = "mime_guess" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" dependencies = [ - "adler", + "mime", + "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -2128,16 +2693,22 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + [[package]] name = "mio" -version = "0.8.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2148,15 +2719,15 @@ checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" [[package]] name = "naga" -version = "0.10.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262d2840e72dbe250e8cf2f522d080988dfca624c4112c096238a4845f591707" +checksum = "bbcc2e0513220fd2b598e6068608d4462db20322c0e77e47f6f488dfcfc279cb" dependencies = [ "bit-set", - "bitflags", + "bitflags 1.3.2", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 1.9.3", "log", "num-traits", "rustc-hash", @@ -2183,15 +2754,16 @@ checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c" [[package]] name = "ndk" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags", + "bitflags 2.4.1", "jni-sys", + "log", "ndk-sys", "num_enum", - "raw-window-handle 0.5.2", + "raw-window-handle 0.6.0", "thiserror", ] @@ -2201,64 +2773,23 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" -[[package]] -name = "ndk-glue" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f" -dependencies = [ - "libc", - "log", - "ndk", - "ndk-context", - "ndk-macro", - "ndk-sys", - "once_cell", - "parking_lot 0.12.1", -] - -[[package]] -name = "ndk-macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" -dependencies = [ - "darling 0.13.4", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ndk-sys" -version = "0.4.1+23.1.7779620" +version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ "jni-sys", ] [[package]] name = "nix" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset 0.6.5", -] - -[[package]] -name = "nix" -version = "0.24.3" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ - "bitflags", + "autocfg", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.6.5", @@ -2266,29 +2797,26 @@ dependencies = [ [[package]] name = "nix" -version = "0.25.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "autocfg", - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", - "memoffset 0.6.5", + "memoffset 0.7.1", + "pin-utils", ] [[package]] name = "nix" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags", + "bitflags 2.4.1", "cfg-if", "libc", - "memoffset 0.7.1", - "pin-utils", - "static_assertions", ] [[package]] @@ -2307,6 +2835,25 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.4.1", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2319,9 +2866,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ "num-bigint", "num-complex", @@ -2333,9 +2880,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -2344,9 +2891,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" dependencies = [ "num-traits", ] @@ -2386,42 +2933,43 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] [[package]] name = "num_enum" -version = "0.5.11" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -2434,6 +2982,39 @@ dependencies = [ "objc_exception", ] +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e1d07c6eab1ce8b6382b8e3c7246fe117ff3f8b34be065f5ebace6749fe845" + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + [[package]] name = "objc_exception" version = "0.1.2" @@ -2443,85 +3024,86 @@ dependencies = [ "cc", ] +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "object" -version = "0.30.3" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] -name = "ordered-float" -version = "3.6.0" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13a384337e997e6860ffbaa83708b2ef329fd8c54cb67a5f64d421e0f943254f" -dependencies = [ - "num-traits", -] +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "ordered-multimap" -version = "0.4.3" +name = "orbclient" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" dependencies = [ - "dlv-list", - "hashbrown", + "libredox 0.0.2", ] [[package]] -name = "ouroboros" -version = "0.13.0" +name = "ordered-float" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f357ef82d1b4db66fbed0b8d542cbd3c22d0bf5b393b3c257b9ba4568e70c9c3" +checksum = "536900a8093134cf9ccf00a27deb3532421099e958d9dd431135d0c7543ca1e8" dependencies = [ - "aliasable", - "ouroboros_macro 0.13.0", - "stable_deref_trait", + "num-traits", ] [[package]] -name = "ouroboros" -version = "0.15.6" +name = "ordered-multimap" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ - "aliasable", - "ouroboros_macro 0.15.6", + "dlv-list", + "hashbrown 0.12.3", ] [[package]] -name = "ouroboros_macro" -version = "0.13.0" +name = "ouroboros" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44a0b52c2cbaef7dffa5fec1a43274afe8bd2a644fa9fc50a9ef4ff0269b1257" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", + "aliasable", + "ouroboros_macro", + "static_assertions", ] [[package]] name = "ouroboros_macro" -version = "0.15.6" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" dependencies = [ - "Inflector", + "heck", "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -2532,21 +3114,21 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owned_ttf_parser" -version = "0.18.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228" +checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7" dependencies = [ - "ttf-parser 0.18.1", + "ttf-parser 0.20.0", ] [[package]] name = "palette" -version = "0.6.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f9cd68f7112581033f157e56c77ac4a5538ec5836a2e39284e65bd7d7275e49" +checksum = "b2e2f34147767aa758aa649415b50a69eeb46a67f9dc7db8011eeb3d84b351dc" dependencies = [ "approx 0.5.1", - "num-traits", + "fast-srgb8", "palette_derive", "phf", "serde", @@ -2554,14 +3136,13 @@ dependencies = [ [[package]] name = "palette_derive" -version = "0.6.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05eedf46a8e7c27f74af0c9cfcdb004ceca158cb1b918c6f68f8d7a549b3e427" +checksum = "b7db010ec5ff3d4385e4f133916faacd9dad0f6a09394c92d825b3aed310fa0a" dependencies = [ - "find-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -2582,7 +3163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.7", + "parking_lot_core 0.9.9", ] [[package]] @@ -2601,28 +3182,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.4.1", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.5", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "phf" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", "phf_shared", @@ -2630,9 +3211,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", @@ -2640,32 +3221,26 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - [[package]] name = "pico-args" version = "0.5.0" @@ -2674,29 +3249,29 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -2706,23 +3281,43 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "png" -version = "0.17.8" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.1", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.48.0", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2731,11 +3326,10 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "once_cell", "toml_edit", ] @@ -2765,61 +3359,62 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332cd62e95873ea4f41f3dfd6bbbfc5b52aec892d7e8d534197c4720a0bbbab2" +checksum = "f89dff0959d98c9758c88826cc002e2c3d0b9dfac4139711d1f30de442f1139b" +dependencies = [ + "profiling-procmacros", +] [[package]] -name = "puffin" -version = "0.14.3" +name = "profiling-procmacros" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7b2c7a01f569fb03e2ff1f5376537f294001447bd23ce75ca51054fcd223fe4" +checksum = "eb156a45b6b9fe8027497422179fb65afc84d36707a7ca98297bf06bccb8d43f" dependencies = [ - "byteorder", - "instant", - "once_cell", + "quote", + "syn 2.0.39", ] [[package]] name = "puffin" -version = "0.15.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f99b70359a44d98fceb167734e8cc19e232fe885a547f1b622e66d8099931b6" +checksum = "39009d69b9d547c3ffa974a20648fa02f447c05bd0a664012b1ba5a5b06fb14e" dependencies = [ "anyhow", "bincode", "byteorder", - "instant", + "cfg-if", + "lz4_flex", "once_cell", "parking_lot 0.12.1", - "ruzstd", "serde", - "zstd", ] [[package]] name = "puffin_egui" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180408bd5816f172326f52cca2b9cc335ad36db5e40f46210f7d20ed847ce15c" +checksum = "c5af236782d21bdd5a6eb2f8cc9a91f8d601c073b7f7d568c95c26604cc12b87" dependencies = [ "egui", - "indexmap", - "instant", + "indexmap 1.9.3", "natord", "once_cell", - "puffin 0.15.0", + "puffin", "time", "vec1", + "web-time", ] [[package]] @@ -2833,18 +3428,27 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.23.1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -2887,42 +3491,27 @@ checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" [[package]] name = "rangemap" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9283c6b06096b47afc7109834fdedab891175bb5241ee5d4f7d2546549f263" - -[[package]] -name = "raqote" -version = "0.8.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5b6cb89f8be6a645e5834f3ad44a7960d12343d97b5b7fb07cb0365ae36aa2d" -dependencies = [ - "euclid", - "lyon_geom", - "sw-composite", - "typed-arena", -] +checksum = "977b1e897f9d764566891689e642653e5ed90c6895106acd005eb4c1d0203991" [[package]] name = "raw-window-handle" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" -dependencies = [ - "cty", -] +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "raw-window-handle" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -2930,22 +3519,14 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] -[[package]] -name = "rctree" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae028b272a6e99d9f8260ceefa3caa09300a8d6c8d2b2001316474bc52122e9" - [[package]] name = "rctree" version = "0.5.0" @@ -2958,7 +3539,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2967,29 +3548,39 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox 0.0.1", "thiserror", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -2998,24 +3589,41 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", ] [[package]] name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "renderdoc" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42e14087d51efd3b42eb341e37b6f320af2b0750519ea849cb68bb7289643ed" +checksum = "272da9ec1e28b0ef17df4dcefad820b13f098ebe9c82697111fc57ccff621e12" dependencies = [ - "bitflags", - "float-cmp 0.8.0", - "libloading", + "bitflags 1.3.2", + "float-cmp", + "libloading 0.7.4", "once_cell", "renderdoc-sys", "winapi", @@ -3024,87 +3632,112 @@ dependencies = [ [[package]] name = "renderdoc-sys" -version = "0.7.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" +checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b" [[package]] name = "resvg" -version = "0.18.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608c6e8aa6fb2c13bc06e4184d7c7b2cc1b7c138f88a539da8be55c3c033d7f4" +checksum = "c115863f2d3621999cf187e318bc92b16402dfeff6a48c74df700d77381394c1" dependencies = [ - "jpeg-decoder 0.1.22", "log", - "pico-args 0.4.2", - "png", + "pico-args", "rgb", - "svgfilters", - "tiny-skia 0.6.6", - "usvg 0.18.0", + "svgtypes 0.8.2", + "tiny-skia 0.8.4", + "usvg 0.28.0", ] [[package]] name = "resvg" -version = "0.28.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c115863f2d3621999cf187e318bc92b16402dfeff6a48c74df700d77381394c1" +checksum = "b6554f47c38eca56827eea7f285c2a3018b4e12e0e195cc105833c008be338f1" dependencies = [ + "gif", + "jpeg-decoder", "log", - "pico-args 0.5.0", + "pico-args", + "png", "rgb", - "svgtypes", - "tiny-skia 0.8.4", - "usvg 0.28.0", + "svgtypes 0.11.0", + "tiny-skia 0.10.0", + "usvg 0.35.0", ] [[package]] name = "rgb" -version = "0.8.36" +version = "0.8.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" dependencies = [ "bytemuck", ] [[package]] name = "ron" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64", - "bitflags", + "base64 0.21.5", + "bitflags 2.4.1", "serde", + "serde_derive", ] [[package]] -name = "ron" -version = "0.8.0" +name = "roxmltree" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" +checksum = "6b9de9831a129b122e7e61f242db509fa9d0838008bf0b29bb0624669edfe48a" dependencies = [ - "base64", - "bitflags", - "serde", + "xmlparser", ] [[package]] name = "roxmltree" -version = "0.14.1" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b" +checksum = "862340e351ce1b271a378ec53f304a5558f7db87f3769dc655a8f6ecbb68b302" dependencies = [ "xmlparser", ] [[package]] -name = "roxmltree" -version = "0.15.1" +name = "rust-embed" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9de9831a129b122e7e61f242db509fa9d0838008bf0b29bb0624669edfe48a" +checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40" dependencies = [ - "xmlparser", + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.39", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada" +dependencies = [ + "sha2", + "walkdir", ] [[package]] @@ -3131,13 +3764,12 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.37.11" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags", - "errno 0.3.1", - "io-lifetimes", + "bitflags 2.4.1", + "errno", "libc", "linux-raw-sys", "windows-sys 0.48.0", @@ -3145,61 +3777,50 @@ dependencies = [ [[package]] name = "rustybuzz" -version = "0.4.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44561062e583c4873162861261f16fd1d85fe927c4904d71329a4fe43dc355ef" +checksum = "162bdf42e261bee271b3957691018634488084ef577dddeb6420a9684cab2a6a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytemuck", "smallvec", - "ttf-parser 0.12.3", + "ttf-parser 0.18.1", "unicode-bidi-mirroring", "unicode-ccc", - "unicode-general-category 0.4.0", + "unicode-general-category", "unicode-script", ] [[package]] name = "rustybuzz" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162bdf42e261bee271b3957691018634488084ef577dddeb6420a9684cab2a6a" +checksum = "82eea22c8f56965eeaf3a209b3d24508256c7b920fb3b6211b8ba0f7c0583250" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytemuck", "libm", "smallvec", - "ttf-parser 0.18.1", + "ttf-parser 0.19.2", "unicode-bidi-mirroring", "unicode-ccc", - "unicode-general-category 0.6.0", + "unicode-general-category", "unicode-script", ] -[[package]] -name = "ruzstd" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a15e661f0f9dac21f3494fe5d23a6338c0ac116a2d22c2b63010acd89467ffe" -dependencies = [ - "byteorder", - "thiserror", - "twox-hash", -] - [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] -name = "safe_arch" -version = "0.5.2" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "bytemuck", + "winapi-util", ] [[package]] @@ -3216,9 +3837,15 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "self_cell" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af" [[package]] name = "sendfd" @@ -3231,40 +3858,49 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.160" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -3273,18 +3909,18 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "simd-adler32" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "simplecss" @@ -3297,25 +3933,19 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] -[[package]] -name = "slog" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" - [[package]] name = "slotmap" version = "1.0.6" @@ -3327,80 +3957,91 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smithay" version = "0.3.0" -source = "git+https://github.com/smithay//smithay?rev=25d1176484#25d1176484e1c846c4b510f6a4bf5cc5a6d2e4e9" +source = "git+https://github.com/smithay//smithay?rev=d5b352b#d5b352b33525d21b38ad8d7ebd54c99d39246464" dependencies = [ "appendlist", "ash", - "bitflags", + "bitflags 2.4.1", "calloop", "cc", "cgmath", + "cursor-icon", "downcast-rs", "drm", "drm-ffi", "drm-fourcc", - "encoding", + "encoding_rs", + "errno", "gbm", "gl_generator", - "glow 0.12.1", - "indexmap", + "glow", + "indexmap 2.1.0", "input", "lazy_static", "libc", - "libloading", + "libloading 0.8.1", "libseat", - "nix 0.26.2", + "nix 0.27.1", "once_cell", "pkg-config", + "profiling", "rand", + "rustix", "scan_fmt", "scopeguard", + "smallvec", "tempfile", "thiserror", "tracing", - "udev", - "wayland-backend", + "udev 0.8.0", + "wayland-backend 0.3.2", "wayland-egl", - "wayland-protocols 0.30.0", + "wayland-protocols", "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-server", - "wayland-sys 0.30.1", + "wayland-sys 0.31.1", "winit", - "x11rb", - "xkbcommon 0.5.0", + "x11rb 0.12.0", + "xkbcommon", ] [[package]] name = "smithay-client-toolkit" -version = "0.16.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" +checksum = "60e3d9941fa3bacf7c2bf4b065304faa14164151254cd16ce1b1bc8fc381600f" dependencies = [ - "bitflags", + "bitflags 2.4.1", "calloop", - "dlib", - "lazy_static", + "calloop-wayland-source", + "cursor-icon", + "libc", "log", - "memmap2 0.5.10", - "nix 0.24.3", - "pkg-config", - "wayland-client 0.29.5", + "memmap2 0.9.0", + "rustix", + "thiserror", + "wayland-backend 0.3.2", + "wayland-client 0.31.1", + "wayland-csd-frame", "wayland-cursor", - "wayland-protocols 0.29.5", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner 0.31.0", + "xkeysym", ] [[package]] name = "smithay-egui" version = "0.1.0" -source = "git+https://github.com/Smithay/smithay-egui.git?rev=197606f400#197606f40067595438a90129016b1c29941c31ff" +source = "git+https://github.com/Smithay/smithay-egui.git?rev=cdc652e0#cdc652e0d4823b16a5bd9badd288e38512789dc5" dependencies = [ "cgmath", "egui", @@ -3408,9 +4049,18 @@ dependencies = [ "egui_glow", "image", "log", - "memoffset 0.8.0", + "memoffset 0.9.0", "smithay", - "xkbcommon 0.5.0", + "xkbcommon", +] + +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", ] [[package]] @@ -3422,28 +4072,28 @@ checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1" [[package]] name = "softbuffer" version = "0.2.0" -source = "git+https://github.com/pop-os/softbuffer?rev=8dcb6438b#8dcb6438b6c1688a0015b477dfa76c6c0bee3318" +source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-2.0-old#ece901a9f60dc89ca740dc3bd11f3c909e801723" dependencies = [ "bytemuck", "cfg_aliases", "cocoa", - "core-graphics", - "fastrand", - "foreign-types", + "core-graphics 0.22.3", + "fastrand 1.9.0", + "foreign-types 0.3.2", "log", - "nix 0.26.2", + "nix 0.26.4", "objc", "raw-window-handle 0.5.2", "redox_syscall 0.3.5", "thiserror", "wasm-bindgen", - "wayland-backend", - "wayland-client 0.30.1", + "wayland-backend 0.1.2", + "wayland-client 0.30.2", "wayland-sys 0.30.1", "web-sys", "windows-sys 0.42.0", "x11-dl", - "x11rb", + "x11rb 0.11.1", ] [[package]] @@ -3461,16 +4111,10 @@ version = "0.2.0+1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" dependencies = [ - "bitflags", + "bitflags 1.3.2", "num-traits", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "static_assertions" version = "1.1.0" @@ -3479,19 +4123,13 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strict-num" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9df65f20698aeed245efdde3628a6b559ea1239bbb871af1b6e3b58c413b2bd1" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" dependencies = [ - "float-cmp 0.9.0", + "float-cmp", ] -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - [[package]] name = "strsim" version = "0.10.0" @@ -3500,9 +4138,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "svg_fmt" @@ -3510,16 +4148,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2" -[[package]] -name = "svgfilters" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "639abcebc15fdc2df179f37d6f5463d660c1c79cd552c12343a4600827a04bce" -dependencies = [ - "float-cmp 0.9.0", - "rgb", -] - [[package]] name = "svgtypes" version = "0.8.2" @@ -3530,16 +4158,20 @@ dependencies = [ ] [[package]] -name = "sw-composite" -version = "0.7.16" +name = "svgtypes" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac8fb7895b4afa060ad731a32860db8755da3449a47e796d5ecf758db2671d4" +checksum = "ed4b0611e7f3277f68c0fa18e385d9e2d26923691379690039548f867cef02a7" +dependencies = [ + "kurbo 0.9.5", + "siphasher", +] [[package]] name = "swash" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba6e16b35fe4f8b2020640610575827892b4e2db5d289b3b76ff4e1cfd38752" +checksum = "3b7c73c813353c347272919aa1af2885068b05e625e5532b43049e4f641ae77f" dependencies = [ "yazi", "zeno", @@ -3558,9 +4190,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -3569,57 +4201,64 @@ dependencies = [ [[package]] name = "sys-locale" -version = "0.2.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a11bd9c338fdba09f7881ab41551932ad42e405f61d01e8406baea71c07aee" +checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" dependencies = [ - "js-sys", "libc", - "wasm-bindgen", - "web-sys", - "windows-sys 0.45.0", +] + +[[package]] +name = "taffy" +version = "0.3.11" +source = "git+https://github.com/DioxusLabs/taffy#1876f72bee5e376023eaa518aa7b8a34c769bd1b" +dependencies = [ + "arrayvec", + "grid", + "num-traits", + "slotmap", ] [[package]] name = "tempfile" -version = "3.5.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", - "fastrand", - "redox_syscall 0.3.5", + "fastrand 2.0.1", + "redox_syscall 0.4.1", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.39", ] [[package]] @@ -3634,22 +4273,24 @@ dependencies = [ [[package]] name = "tiff" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" dependencies = [ "flate2", - "jpeg-decoder 0.3.0", + "jpeg-decoder", "weezl", ] [[package]] name = "time" -version = "0.3.20" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ + "deranged", "itoa", + "powerfmt", "serde", "time-core", "time-macros", @@ -3657,45 +4298,46 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] [[package]] name = "tiny-skia" -version = "0.6.6" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d049bfef0eaa2521e75d9ffb5ce86ad54480932ae19b85f78bec6f52c4d30d78" +checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" dependencies = [ "arrayref", - "arrayvec 0.5.2", + "arrayvec", "bytemuck", "cfg-if", "png", - "safe_arch", + "tiny-skia-path 0.8.4", ] [[package]] name = "tiny-skia" -version = "0.8.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" +checksum = "7db11798945fa5c3e5490c794ccca7c6de86d3afdd54b4eb324109939c6f37bc" dependencies = [ "arrayref", - "arrayvec 0.7.2", + "arrayvec", "bytemuck", "cfg-if", + "log", "png", - "tiny-skia-path", + "tiny-skia-path 0.10.0", ] [[package]] @@ -3709,6 +4351,41 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tiny-skia-path" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f60aa35c89ac2687ace1a2556eaaea68e8c0d47408a2e3e7f5c98a489e7281c" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0e245e80bdc9b4e5356fc45a72184abbc3861992603f515270e9340f5a219" +dependencies = [ + "displaydoc", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml" version = "0.5.11" @@ -3718,30 +4395,46 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap", + "indexmap 2.1.0", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3749,20 +4442,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -3781,20 +4474,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -3810,15 +4503,21 @@ dependencies = [ [[package]] name = "ttf-parser" -version = "0.12.3" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" +checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" [[package]] name = "ttf-parser" -version = "0.18.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" +checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" + +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" [[package]] name = "twox-hash" @@ -3832,26 +4531,69 @@ dependencies = [ ] [[package]] -name = "typed-arena" -version = "2.0.2" +name = "type-map" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46" +dependencies = [ + "rustc-hash", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "udev" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebdbbd670373442a12fe9ef7aeb53aec4147a5a27a00bbc3ab639f08f48191a" +dependencies = [ + "libc", + "libudev-sys", + "pkg-config", +] + +[[package]] +name = "udev" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50051c6e22be28ee6f217d50014f3bc29e81c20dc66ff7ca0d5c5226e1dcc5a1" +dependencies = [ + "io-lifetimes 1.0.11", + "libc", + "libudev-sys", + "pkg-config", +] + +[[package]] +name = "unic-langid" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f" +dependencies = [ + "unic-langid-impl", +] [[package]] -name = "typenum" -version = "1.16.0" +name = "unic-langid-impl" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff" +dependencies = [ + "serde", + "tinystr", +] [[package]] -name = "udev" -version = "0.7.0" +name = "unicase" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebdbbd670373442a12fe9ef7aeb53aec4147a5a27a00bbc3ab639f08f48191a" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ - "libc", - "libudev-sys", - "pkg-config", + "version_check", ] [[package]] @@ -3872,12 +4614,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" -[[package]] -name = "unicode-general-category" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742" - [[package]] name = "unicode-general-category" version = "0.6.0" @@ -3886,18 +4622,23 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" -version = "0.1.4" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ - "hashbrown", - "regex", + "tinyvec", ] [[package]] @@ -3920,9 +4661,9 @@ checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unicode-xid" @@ -3930,58 +4671,103 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "usvg" -version = "0.18.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4058e0bd091a56f905e6963e40776ce6880b271275f0b493bff951433e303071" +checksum = "8b5b7c2b30845b3348c067ca3d09e20cc6e327c288f0ca4c48698712abf432e9" dependencies = [ - "base64", - "data-url 0.1.1", + "base64 0.13.1", + "data-url", "flate2", - "float-cmp 0.9.0", - "fontdb 0.6.2", - "kurbo", + "imagesize 0.10.1", + "kurbo 0.8.3", "log", - "pico-args 0.4.2", - "rctree 0.4.0", - "roxmltree 0.14.1", - "rustybuzz 0.4.0", + "rctree", + "roxmltree 0.15.1", "simplecss", "siphasher", - "svgtypes", - "ttf-parser 0.12.3", - "unicode-bidi", - "unicode-script", - "unicode-vo", - "xmlwriter", + "strict-num", + "svgtypes 0.8.2", ] [[package]] name = "usvg" -version = "0.28.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5b7c2b30845b3348c067ca3d09e20cc6e327c288f0ca4c48698712abf432e9" +checksum = "14d09ddfb0d93bf84824c09336d32e42f80961a9d1680832eb24fdf249ce11e6" +dependencies = [ + "base64 0.21.5", + "log", + "pico-args", + "usvg-parser", + "usvg-text-layout", + "usvg-tree", + "xmlwriter", +] + +[[package]] +name = "usvg-parser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19bf93d230813599927d88557014e0908ecc3531666d47c634c6838bc8db408" dependencies = [ - "base64", - "data-url 0.2.0", + "data-url", "flate2", - "imagesize", - "kurbo", + "imagesize 0.12.0", + "kurbo 0.9.5", "log", - "rctree 0.5.0", - "roxmltree 0.15.1", + "roxmltree 0.18.1", "simplecss", "siphasher", + "svgtypes 0.11.0", + "usvg-tree", +] + +[[package]] +name = "usvg-text-layout" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "035044604e89652c0a2959b8b356946997a52649ba6cade45928c2842376feb4" +dependencies = [ + "fontdb", + "kurbo 0.9.5", + "log", + "rustybuzz 0.7.0", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "usvg-tree", +] + +[[package]] +name = "usvg-tree" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7939a7e4ed21cadb5d311d6339730681c3e24c3e81d60065be80e485d3fc8b92" +dependencies = [ + "rctree", "strict-num", - "svgtypes", + "svgtypes 0.11.0", + "tiny-skia-path 0.10.0", ] [[package]] name = "uuid" -version = "0.8.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ "serde", ] @@ -3998,18 +4784,22 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bda7c41ca331fe9a1c278a9e7ee055f4be7f5eb1c2b72f079b4ff8b5fce9d5c" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -4018,9 +4808,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4028,24 +4818,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -4055,9 +4845,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4065,22 +4855,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-timer" @@ -4099,196 +4889,219 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ebd48bfc1178c9190c7ff80cc822b3335ffc83141e9aa723168f377257623e" +checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8" dependencies = [ "cc", "downcast-rs", - "io-lifetimes", - "nix 0.26.2", + "io-lifetimes 1.0.11", + "nix 0.26.4", "scoped-tls", "smallvec", "wayland-sys 0.30.1", ] [[package]] -name = "wayland-client" -version = "0.29.5" +name = "wayland-backend" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +checksum = "19152ddd73f45f024ed4534d9ca2594e0ef252c1847695255dae47f34df9fbe4" dependencies = [ - "bitflags", + "cc", "downcast-rs", - "libc", - "nix 0.24.3", + "nix 0.26.4", "scoped-tls", - "wayland-commons", - "wayland-scanner 0.29.5", - "wayland-sys 0.29.5", + "smallvec", + "wayland-sys 0.31.1", ] [[package]] name = "wayland-client" -version = "0.30.1" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bde68449abab1a808e5227b6e295f4ae3680911eb7711b4a2cb90141edb780" +checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8" dependencies = [ - "bitflags", - "nix 0.26.2", - "wayland-backend", - "wayland-scanner 0.30.0", + "bitflags 1.3.2", + "nix 0.26.4", + "wayland-backend 0.1.2", + "wayland-scanner 0.30.1", ] [[package]] -name = "wayland-commons" -version = "0.29.5" +name = "wayland-client" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +checksum = "1ca7d52347346f5473bf2f56705f360e8440873052e575e55890c4fa57843ed3" dependencies = [ - "nix 0.24.3", - "once_cell", - "smallvec", - "wayland-sys 0.29.5", + "bitflags 2.4.1", + "nix 0.26.4", + "wayland-backend 0.3.2", + "wayland-scanner 0.31.0", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.4.1", + "cursor-icon", + "wayland-backend 0.3.2", ] [[package]] name = "wayland-cursor" -version = "0.29.5" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +checksum = "a44aa20ae986659d6c77d64d808a046996a932aa763913864dc40c359ef7ad5b" dependencies = [ - "nix 0.24.3", - "wayland-client 0.29.5", + "nix 0.26.4", + "wayland-client 0.31.1", "xcursor", ] [[package]] name = "wayland-egl" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1187695fe81c3153c3163f9d2953149f638c5d7dbc6fe988914ca3f4961e28ed" +checksum = "355f652e5a24ae02d2ad536c8fc2d3dcc6c2bd635027cd6103a193e7d75eeda2" dependencies = [ - "wayland-backend", - "wayland-sys 0.30.1", + "wayland-backend 0.3.2", + "wayland-sys 0.31.1", ] [[package]] name = "wayland-protocols" -version = "0.29.5" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" dependencies = [ - "bitflags", - "wayland-client 0.29.5", - "wayland-commons", - "wayland-scanner 0.29.5", + "bitflags 2.4.1", + "wayland-backend 0.3.2", + "wayland-client 0.31.1", + "wayland-scanner 0.31.0", + "wayland-server", ] [[package]] -name = "wayland-protocols" -version = "0.30.0" +name = "wayland-protocols-misc" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fefbeb8a360abe67ab7c2efe1d297a1a50ee011f5460791bc18870c26bb84e2" +checksum = "bfa5933740b200188c9b4c38601b8212e8c154d7de0d2cb171944e137a77de1e" dependencies = [ - "bitflags", - "wayland-backend", - "wayland-scanner 0.30.0", + "bitflags 2.4.1", + "wayland-backend 0.3.2", + "wayland-protocols", + "wayland-scanner 0.31.0", "wayland-server", ] [[package]] -name = "wayland-protocols-misc" -version = "0.1.0" +name = "wayland-protocols-plasma" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897d4e99645e1ed9245e9e6b5efa78828d2b23b661016d63d55251243d812f8b" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ - "bitflags", - "wayland-backend", - "wayland-protocols 0.30.0", - "wayland-scanner 0.30.0", - "wayland-server", + "bitflags 2.4.1", + "wayland-backend 0.3.2", + "wayland-client 0.31.1", + "wayland-protocols", + "wayland-scanner 0.31.0", ] [[package]] name = "wayland-protocols-wlr" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce991093320e4a6a525876e6b629ab24da25f9baef0c2e0080ad173ec89588a" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags", - "wayland-backend", - "wayland-protocols 0.30.0", - "wayland-scanner 0.30.0", + "bitflags 2.4.1", + "wayland-backend 0.3.2", + "wayland-client 0.31.1", + "wayland-protocols", + "wayland-scanner 0.31.0", "wayland-server", ] [[package]] name = "wayland-scanner" -version = "0.29.5" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e" dependencies = [ "proc-macro2", + "quick-xml 0.28.2", "quote", - "xml-rs", ] [[package]] name = "wayland-scanner" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4834c14b3edf1d9986c83ca79b1e7e3afbe9874c7c144702f6467063259ce45d" +checksum = "fb8e28403665c9f9513202b7e1ed71ec56fde5c107816843fb14057910b2c09c" dependencies = [ "proc-macro2", - "quick-xml", + "quick-xml 0.30.0", "quote", ] [[package]] name = "wayland-server" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9062def387c1b1d80e366d8243c2b3bd6d9e4f343032a3e5da8d4aa03866cf89" +checksum = "3f3f0c52a445936ca1184c98f1a69cf4ad9c9130788884531ef04428468cb1ce" dependencies = [ - "bitflags", + "bitflags 2.4.1", "downcast-rs", - "io-lifetimes", - "nix 0.26.2", - "wayland-backend", - "wayland-scanner 0.30.0", + "io-lifetimes 2.0.2", + "nix 0.26.4", + "wayland-backend 0.3.2", + "wayland-scanner 0.31.0", ] [[package]] name = "wayland-sys" -version = "0.29.5" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" dependencies = [ "dlib", "lazy_static", + "log", "pkg-config", ] [[package]] name = "wayland-sys" -version = "0.30.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" +checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" dependencies = [ "dlib", - "lazy_static", "libc", "log", - "memoffset 0.7.1", + "memoffset 0.9.0", + "once_cell", "pkg-config", ] [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "57099a701fb3a8043f993e8228dc24229c7b942e2b009a1b962e54489ba1d3bf" dependencies = [ "js-sys", "wasm-bindgen", @@ -4302,15 +5115,17 @@ checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" [[package]] name = "wgpu" -version = "0.14.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f643110d228fd62a60c5ed2ab56c4d5b3704520bd50561174ec4ec74932937" +checksum = "480c965c9306872eb6255fa55e4b4953be55a8b64d57e61d7ff840d3dcc051cd" dependencies = [ - "arrayvec 0.7.2", + "arrayvec", + "cfg-if", "js-sys", "log", "naga", "parking_lot 0.12.1", + "profiling", "raw-window-handle 0.5.2", "smallvec", "static_assertions", @@ -4324,21 +5139,20 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.14.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6000d1284ef8eec6076fd5544a73125fd7eb9b635f18dceeb829d826f41724ca" +checksum = "8f478237b4bf0d5b70a39898a66fa67ca3a007d79f2520485b8b0c3dfc46f8c2" dependencies = [ - "arrayvec 0.7.2", + "arrayvec", "bit-vec", - "bitflags", - "cfg_aliases", + "bitflags 2.4.1", "codespan-reporting", - "fxhash", "log", "naga", "parking_lot 0.12.1", "profiling", "raw-window-handle 0.5.2", + "rustc-hash", "smallvec", "thiserror", "web-sys", @@ -4348,26 +5162,28 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.14.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cc320a61acb26be4f549c9b1b53405c10a223fbfea363ec39474c32c348d12f" +checksum = "1ecb3258078e936deee14fd4e0febe1cfe9bbb5ffef165cb60218d2ee5eb4448" dependencies = [ "android_system_properties", - "arrayvec 0.7.2", + "arrayvec", "ash", "bit-set", - "bitflags", + "bitflags 2.4.1", "block", "core-graphics-types", "d3d12", - "foreign-types", - "fxhash", - "glow 0.11.2", + "foreign-types 0.3.2", + "glow", "gpu-alloc", + "gpu-allocator", "gpu-descriptor", + "hassle-rs", "js-sys", "khronos-egl", - "libloading", + "libc", + "libloading 0.8.1", "log", "metal", "naga", @@ -4377,6 +5193,7 @@ dependencies = [ "range-alloc", "raw-window-handle 0.5.2", "renderdoc-sys", + "rustc-hash", "smallvec", "thiserror", "wasm-bindgen", @@ -4387,24 +5204,20 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.14.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb6b28ef22cac17b9109b25b3bf8c9a103eeb293d7c5f78653979b09140375f6" +checksum = "d0c153280bb108c2979eb5c7391cb18c56642dd3c072e55f52065e13e2a1252a" dependencies = [ - "bitflags", + "bitflags 2.4.1", + "js-sys", + "web-sys", ] [[package]] -name = "wgpu_glyph" -version = "0.18.0" +name = "widestring" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cafb82773e0f124a33674dab5de4dff73175aeb921949047ab014efb58fb446" -dependencies = [ - "bytemuck", - "glyph_brush", - "log", - "wgpu", -] +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" [[package]] name = "winapi" @@ -4424,9 +5237,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -4447,16 +5260,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.36.1" +name = "windows" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows-targets 0.42.2", ] [[package]] @@ -4489,7 +5298,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -4509,17 +5318,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -4530,15 +5339,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" @@ -4548,15 +5351,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" @@ -4566,15 +5363,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" @@ -4584,15 +5375,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" @@ -4602,9 +5387,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" @@ -4614,15 +5399,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" @@ -4632,47 +5411,62 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winit" -version = "0.27.5" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c" +checksum = "161598019a9da35ab6c34dc46cd13546cba9dbf9816475d4dd9a639455016563" dependencies = [ - "bitflags", - "cocoa", + "ahash 0.8.6", + "android-activity", + "atomic-waker", + "bitflags 2.4.1", + "bytemuck", + "calloop", + "cfg_aliases", "core-foundation", - "core-graphics", - "dispatch", - "instant", + "core-graphics 0.23.1", + "cursor-icon", + "icrate", + "js-sys", "libc", "log", - "mio", + "memmap2 0.9.0", "ndk", - "ndk-glue", - "objc", + "ndk-sys", + "objc2", "once_cell", - "parking_lot 0.12.1", + "orbclient", "percent-encoding", - "raw-window-handle 0.4.3", - "raw-window-handle 0.5.2", + "raw-window-handle 0.6.0", + "redox_syscall 0.3.5", + "rustix", "smithay-client-toolkit", + "smol_str", + "unicode-segmentation", "wasm-bindgen", - "wayland-client 0.29.5", - "wayland-protocols 0.29.5", + "wasm-bindgen-futures", + "wayland-backend 0.3.2", + "wayland-client 0.31.1", + "wayland-protocols", + "wayland-protocols-plasma", "web-sys", - "windows-sys 0.36.1", + "web-time", + "windows-sys 0.48.0", "x11-dl", + "x11rb 0.12.0", + "xkbcommon-dl", ] [[package]] name = "winnow" -version = "0.4.1" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] @@ -4703,14 +5497,31 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdf3c79412dd91bae7a7366b8ad1565a85e35dd049affc3a6a2c549e97419617" dependencies = [ - "gethostname", + "gethostname 0.2.3", "libc", - "libloading", + "libloading 0.7.4", "nix 0.25.1", "once_cell", "winapi", "winapi-wsapoll", - "x11rb-protocol", + "x11rb-protocol 0.11.1", +] + +[[package]] +name = "x11rb" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" +dependencies = [ + "as-raw-xcb-connection", + "gethostname 0.3.0", + "libc", + "libloading 0.7.4", + "nix 0.26.4", + "once_cell", + "winapi", + "winapi-wsapoll", + "x11rb-protocol 0.12.0", ] [[package]] @@ -4723,59 +5534,70 @@ dependencies = [ ] [[package]] -name = "xcursor" -version = "0.3.4" +name = "x11rb-protocol" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc" dependencies = [ - "nom", + "nix 0.26.4", ] [[package]] -name = "xdg" -version = "2.4.1" +name = "xcursor" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" dependencies = [ - "dirs", + "nom", ] [[package]] -name = "xi-unicode" -version = "0.3.0" +name = "xdg" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "xkbcommon" -version = "0.4.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "032ed00cc755c31221bbd6aaf9fa4196a01bf33bca185f9316e14f26d28c28cf" +checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e" dependencies = [ "libc", + "memmap2 0.8.0", + "xkeysym", ] [[package]] -name = "xkbcommon" -version = "0.5.0" +name = "xkbcommon-dl" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbee136714379ab22da0280207fdb7f47e0bb940adea97731b65598b8c7a92e" +checksum = "6924668544c48c0133152e7eec86d644a056ca3d09275eb8d5cdb9855f9d8699" dependencies = [ - "libc", - "memmap2 0.5.10", + "bitflags 2.4.1", + "dlib", + "log", + "once_cell", + "xkeysym", ] +[[package]] +name = "xkeysym" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" + [[package]] name = "xml-rs" -version = "0.8.4" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" [[package]] name = "xmlparser" -version = "0.13.5" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" [[package]] name = "xmlwriter" @@ -4785,51 +5607,41 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" [[package]] name = "yazi" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4882895da007f1fb0524971b07f60fc742f457996d970443affd44a48ce954" +checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" [[package]] name = "zeno" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c110ba09c9b3a43edd4803d570df0da2414fed6e822e22b976a4e3ef50860701" - -[[package]] -name = "zstd" -version = "0.12.3+zstd.1.5.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" -dependencies = [ - "zstd-safe", -] +checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" [[package]] -name = "zstd-safe" -version = "6.0.5+zstd.1.5.4" +name = "zerocopy" +version = "0.7.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" dependencies = [ - "libc", - "zstd-sys", + "zerocopy-derive", ] [[package]] -name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +name = "zerocopy-derive" +version = "0.7.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" dependencies = [ - "cc", - "libc", - "pkg-config", + "proc-macro2", + "quote", + "syn 2.0.39", ] [[package]] name = "zune-inflate" -version = "0.2.53" +version = "0.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "440a08fd59c6442e4b846ea9b10386c38307eae728b216e1ab2c305d1c9daaf8" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", ] diff --git a/Cargo.toml b/Cargo.toml index 967dd2bb..ad54e88d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,16 +5,22 @@ edition = "2021" license = "GPL-3.0-only" authors = ["Victoria Brekenfeld"] +[workspace] +members = [ + "cosmic-comp-config" +] + [dependencies] anyhow = { version = "1.0.51", features = ["backtrace"] } -bitflags = "1.3.2" +bitflags = "2.4" bytemuck = "1.12" -calloop = { version = "0.10.1", features = ["executor"] } +calloop = { version = "0.12.2", features = ["executor"] } serde = { version = "1", features = ["derive"] } serde_json = "1" sendfd = "0.4.1" -egui = { version = "0.21.0", optional = true } -renderdoc = { version = "0.10.1", optional = true } +egui = { version = "0.23.0", optional = true } +egui_plot = { version = "0.23.0", optional = true } +renderdoc = { version = "0.11.0", optional = true } edid-rs = { version = "0.1" } png = "0.17.5" lazy_static = "1.4.0" @@ -22,42 +28,54 @@ log-panics = { version = "2", features = ["with-backtrace"] } thiserror = "1.0.26" regex = "1" xcursor = "0.3.3" -id_tree = "1.8.0" -xkbcommon = "0.4" -indexmap = "1.8.0" +xkbcommon = "0.7" +indexmap = "2.0" xdg = "^2.1" -ron = "0.7" -libsystemd = { version = "0.5", optional = true } -wayland-backend = "0.1.0" -wayland-scanner = "0.30.0" +ron = "0.8" +libsystemd = { version = "0.6", optional = true } +wayland-backend = "0.3.2" +wayland-scanner = "0.31.0" +cosmic-comp-config = { path = "cosmic-comp-config" } +cosmic-config = { git = "https://github.com/pop-os/libcosmic/", features = ["calloop", "macro"] } cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] } -libcosmic = { git = "https://github.com/pop-os/libcosmic", rev = "24709e9c3b", default-features = false, features = ["softbuffer"] } -iced_softbuffer = { git = "https://github.com/pop-os/libcosmic", rev = "24709e9c3b" } -ordered-float = "3.0" -glow = "0.11.2" +libcosmic = { git = "https://github.com/pop-os/libcosmic/", default-features = false } +iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/" } +tiny-skia = "0.10" +ordered-float = "4.0" +glow = "0.12.0" tracing-subscriber = { version = "0.3.16", features = ["env-filter", "tracing-log"] } tracing-journald = "0.3.0" tracing = { version = "0.1.37", features = ["max_level_debug", "release_max_level_info"] } -puffin = { version = "0.14.3", optional = true } -puffin_egui = { version = "0.21.0", optional = true } +puffin = { version = "0.17.0", optional = true } +puffin_egui = { version = "0.23.0", optional = true } +keyframe = "1.1.1" +once_cell = "1.18.0" +i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] } +i18n-embed-fl = "0.7" +rust-embed = "8.0" +libc = "0.2.149" + +[dependencies.id_tree] +git = "https://github.com/Drakulix/id-tree.git" +branch = "feature/copy_clone" [dependencies.smithay] version = "0.3" git = "https://github.com/smithay/smithay.git" -rev = "9459ddd14e" +rev = "74ef59a3f" default-features = false features = ["backend_drm", "backend_gbm", "backend_egl", "backend_libinput", "backend_session_libseat", "backend_udev", "backend_winit", "backend_vulkan", "backend_x11", "desktop", "use_system_lib", "renderer_glow", "renderer_multi", "wayland_frontend", "xwayland"] [dependencies.smithay-egui] git = "https://github.com/Smithay/smithay-egui.git" -rev = "197606f400" +rev = "cdc652e0" features = ["svg"] optional = true [features] default = ["systemd"] systemd = ["libsystemd"] -debug = ["egui", "smithay-egui", "renderdoc", "puffin", "puffin_egui", "anyhow/backtrace"] +debug = ["egui", "egui_plot", "smithay-egui", "renderdoc", "puffin", "puffin_egui", "anyhow/backtrace"] [profile.dev] lto = "thin" @@ -70,4 +88,4 @@ debug = true lto = "fat" [patch."https://github.com/Smithay/smithay.git"] -smithay = { git = "https://github.com/smithay//smithay", rev = "25d1176484" } +smithay = { git = "https://github.com/smithay//smithay", rev = "d5b352b" } \ No newline at end of file diff --git a/Makefile b/Makefile index 898f4afd..76d3b4d4 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ endif VENDOR ?= 0 ifneq ($(VENDOR),0) - ARGS += --locked + ARGS += --offline --locked endif TARGET_BIN="$(DESTDIR)$(bindir)/$(BINARY)" diff --git a/config.ron b/config.ron index 19fd729f..1b111d1d 100644 --- a/config.ron +++ b/config.ron @@ -25,24 +25,10 @@ (modifiers: [Super, Shift], key: "9"): MoveToWorkspace(9), (modifiers: [Super, Shift], key: "0"): MoveToLastWorkspace, - // TODO: Depends on workspace orientation - (modifiers: [Super, Ctrl], key: "Right"): NextWorkspace, - (modifiers: [Super, Ctrl], key: "Left"): PreviousWorkspace, - (modifiers: [Super, Ctrl, Shift], key: "Right"): MoveToNextWorkspace, - (modifiers: [Super, Ctrl, Shift], key: "Left"): MoveToPreviousWorkspace, - (modifiers: [Super, Ctrl], key: "l"): NextWorkspace, - (modifiers: [Super, Ctrl], key: "h"): PreviousWorkspace, - (modifiers: [Super, Ctrl, Shift], key: "l"): MoveToNextWorkspace, - (modifiers: [Super, Ctrl, Shift], key: "h"): MoveToPreviousWorkspace, - - (modifiers: [Super, Ctrl], key: "Down"): NextOutput, - (modifiers: [Super, Ctrl], key: "Up"): PreviousOutput, - (modifiers: [Super, Ctrl, Alt], key: "Down"): NextOutput, - (modifiers: [Super, Ctrl, Alt], key: "Up"): PreviousOutput, - (modifiers: [Super, Ctrl], key: "j"): NextOutput, - (modifiers: [Super, Ctrl], key: "k"): PreviousOutput, - (modifiers: [Super, Ctrl, Alt], key: "j"): NextOutput, - (modifiers: [Super, Ctrl, Alt], key: "k"): PreviousOutput, + (modifiers: [Super, Ctrl, Alt], key: "Down"): MoveToNextOutput, + (modifiers: [Super, Ctrl, Alt], key: "Up"): MoveToPreviousOutput, + (modifiers: [Super, Ctrl, Alt], key: "j"): MoveToNextOutput, + (modifiers: [Super, Ctrl, Alt], key: "k"): MoveToPreviousOutput, (modifiers: [Super], key: "Period"): NextOutput, (modifiers: [Super], key: "Comma"): PreviousOutput, @@ -57,6 +43,8 @@ (modifiers: [Super], key: "j"): Focus(Down), (modifiers: [Super], key: "k"): Focus(Up), (modifiers: [Super], key: "l"): Focus(Right), + (modifiers: [Super], key: "u"): Focus(Out), + (modifiers: [Super], key: "i"): Focus(In), (modifiers: [Super, Shift], key: "Left"): Move(Left), (modifiers: [Super, Shift], key: "Right"): Move(Right), @@ -68,22 +56,24 @@ (modifiers: [Super, Shift], key: "l"): Move(Right), (modifiers: [Super], key: "o"): ToggleOrientation, - + (modifiers: [Super], key: "s"): ToggleStacking, (modifiers: [Super], key: "y"): ToggleTiling, (modifiers: [Super], key: "g"): ToggleWindowFloating, - + (modifiers: [Super], key: "x"): SwapWindow, + (modifiers: [Super], key: "m"): Maximize, + (modifiers: [Super], key: "r"): Resizing(Outwards), + (modifiers: [Super, Shift], key: "r"): Resizing(Inwards), - //TODO: ability to select default web browser - (modifiers: [Super], key: "b"): Spawn("firefox"), - //TODO: ability to select default file browser - (modifiers: [Super], key: "f"): Spawn("nautilus"), + (modifiers: [Super], key: "b"): Spawn("xdg-open http://"), + (modifiers: [Super], key: "f"): Spawn("xdg-open ~"), //TODO: ability to select default terminal (modifiers: [Super], key: "t"): Spawn("gnome-terminal"), - + (modifiers: [Super], key: "a"): Spawn("busctl --user call com.system76.CosmicAppLibrary /com/system76/CosmicAppLibrary com.system76.CosmicAppLibrary Toggle"), (modifiers: [Super], key: "w"): Spawn("busctl --user call com.system76.CosmicWorkspaces /com/system76/CosmicWorkspaces com.system76.CosmicWorkspaces Toggle"), (modifiers: [Super], key: "slash"): Spawn("busctl --user call com.system76.CosmicLauncher /com/system76/CosmicLauncher com.system76.CosmicLauncher Toggle"), + (modifiers: [Super]): Spawn("busctl --user call com.system76.CosmicLauncher /com/system76/CosmicLauncher com.system76.CosmicLauncher Toggle"), (modifiers: [], key: "XF86AudioRaiseVolume"): Spawn("amixer sset Master 5%+"), (modifiers: [], key: "XF86AudioLowerVolume"): Spawn("amixer sset Master 5%-"), @@ -91,7 +81,5 @@ (modifiers: [], key: "XF86MonBrightnessUp"): Spawn("busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon IncreaseDisplayBrightness"), (modifiers: [], key: "XF86MonBrightnessDown"): Spawn("busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon DecreaseDisplayBrightness"), }, - workspace_mode: OutputBound, - workspace_amount: Dynamic, tiling_enabled: false, ) diff --git a/cosmic-comp-config/Cargo.toml b/cosmic-comp-config/Cargo.toml new file mode 100644 index 00000000..7f4f6588 --- /dev/null +++ b/cosmic-comp-config/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "cosmic-comp-config" +version = "0.1.0" +edition = "2021" + +[dependencies] +input = "0.8.3" +serde = { version = "1", features = ["derive"] } diff --git a/cosmic-comp-config/src/input.rs b/cosmic-comp-config/src/input.rs new file mode 100644 index 00000000..3f14df8b --- /dev/null +++ b/cosmic-comp-config/src/input.rs @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-3.0-only + +#![allow(non_snake_case)] + +pub use input::{AccelProfile, ClickMethod, ScrollMethod, TapButtonMap}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +pub struct InputConfig { + pub state: DeviceState, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub acceleration: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub calibration: Option<[f32; 6]>, + #[serde(with = "ClickMethodDef")] + #[serde(skip_serializing_if = "Option::is_none", default)] + pub click_method: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub disable_while_typing: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub left_handed: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub middle_button_emulation: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub rotation_angle: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub scroll_config: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub tap_config: Option, +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +pub struct AccelConfig { + #[serde(with = "AccelProfileDef")] + pub profile: Option, + pub speed: f64, +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +pub struct ScrollConfig { + #[serde(with = "ScrollMethodDef")] + pub method: Option, + pub natural_scroll: Option, + pub scroll_button: Option, + pub scroll_factor: Option, +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +pub enum DeviceState { + Enabled, + Disabled, + DisabledOnExternalMouse, +} + +impl Default for DeviceState { + fn default() -> Self { + Self::Enabled + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TapConfig { + pub enabled: bool, + #[serde(with = "TapButtonMapDef")] + pub button_map: Option, + pub drag: bool, + pub drag_lock: bool, +} + +mod ClickMethodDef { + use input::ClickMethod as ClickMethodOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + pub enum ClickMethod { + ButtonAreas, + Clickfinger, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + ClickMethod::ButtonAreas => ClickMethodOrig::ButtonAreas, + ClickMethod::Clickfinger => ClickMethodOrig::Clickfinger, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(ClickMethodOrig::ButtonAreas) => Some(ClickMethod::ButtonAreas), + Some(ClickMethodOrig::Clickfinger) => Some(ClickMethod::Clickfinger), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} + +mod AccelProfileDef { + use input::AccelProfile as AccelProfileOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + enum AccelProfile { + Flat, + Adaptive, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + AccelProfile::Flat => AccelProfileOrig::Flat, + AccelProfile::Adaptive => AccelProfileOrig::Adaptive, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(AccelProfileOrig::Flat) => Some(AccelProfile::Flat), + Some(AccelProfileOrig::Adaptive) => Some(AccelProfile::Adaptive), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} + +mod ScrollMethodDef { + use input::ScrollMethod as ScrollMethodOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + pub enum ScrollMethod { + NoScroll, + TwoFinger, + Edge, + OnButtonDown, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + ScrollMethod::NoScroll => ScrollMethodOrig::NoScroll, + ScrollMethod::TwoFinger => ScrollMethodOrig::TwoFinger, + ScrollMethod::Edge => ScrollMethodOrig::Edge, + ScrollMethod::OnButtonDown => ScrollMethodOrig::OnButtonDown, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(ScrollMethodOrig::NoScroll) => Some(ScrollMethod::NoScroll), + Some(ScrollMethodOrig::TwoFinger) => Some(ScrollMethod::TwoFinger), + Some(ScrollMethodOrig::Edge) => Some(ScrollMethod::Edge), + Some(ScrollMethodOrig::OnButtonDown) => Some(ScrollMethod::OnButtonDown), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} + +mod TapButtonMapDef { + use input::TapButtonMap as TapButtonMapOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + pub enum TapButtonMap { + LeftRightMiddle, + LeftMiddleRight, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + TapButtonMap::LeftRightMiddle => TapButtonMapOrig::LeftRightMiddle, + TapButtonMap::LeftMiddleRight => TapButtonMapOrig::LeftMiddleRight, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(TapButtonMapOrig::LeftRightMiddle) => Some(TapButtonMap::LeftRightMiddle), + Some(TapButtonMapOrig::LeftMiddleRight) => Some(TapButtonMap::LeftMiddleRight), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs new file mode 100644 index 00000000..92e1c545 --- /dev/null +++ b/cosmic-comp-config/src/lib.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use serde::{Deserialize, Serialize}; + +pub mod input; +pub mod workspace; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct XkbConfig { + pub rules: String, + pub model: String, + pub layout: String, + pub variant: String, + pub options: Option, +} + +impl Default for XkbConfig { + fn default() -> XkbConfig { + XkbConfig { + rules: String::new(), + model: String::new(), + layout: String::new(), + variant: String::new(), + options: None, + } + } +} diff --git a/cosmic-comp-config/src/workspace.rs b/cosmic-comp-config/src/workspace.rs new file mode 100644 index 00000000..c27c7ee7 --- /dev/null +++ b/cosmic-comp-config/src/workspace.rs @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use serde::{Deserialize, Serialize}; + +fn default_workspace_layout() -> WorkspaceLayout { + WorkspaceLayout::Vertical +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WorkspaceConfig { + pub workspace_mode: WorkspaceMode, + pub workspace_amount: WorkspaceAmount, + #[serde(default = "default_workspace_layout")] + pub workspace_layout: WorkspaceLayout, +} + +impl Default for WorkspaceConfig { + fn default() -> Self { + Self { + workspace_mode: WorkspaceMode::OutputBound, + workspace_amount: WorkspaceAmount::Dynamic, + workspace_layout: WorkspaceLayout::Vertical, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum WorkspaceAmount { + Dynamic, + Static(u8), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum WorkspaceMode { + OutputBound, + Global, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum WorkspaceLayout { + Vertical, + Horizontal, +} diff --git a/debian/control b/debian/control index 728f7a24..4ac55e22 100644 --- a/debian/control +++ b/debian/control @@ -4,17 +4,19 @@ Priority: optional Maintainer: Victoria Brekenfeld Build-Depends: cargo, + cmake, debhelper-compat (=10), - rustc (>=1.57), - libudev-dev, libegl1-mesa-dev, + libfontconfig-dev, libgbm-dev, libinput-dev, + libseat-dev, + libsystemd-dev, + libudev-dev, libwayland-dev, libxcb1-dev, libxkbcommon-dev, - libsystemd-dev, - libseat-dev + rustc (>=1.57), Standards-Version: 4.1.1 Homepage: https://github.com/pop-os/cosmic-comp diff --git a/debian/rules b/debian/rules index c8f4dd04..5a266947 100755 --- a/debian/rules +++ b/debian/rules @@ -15,9 +15,6 @@ ifeq ($(VENDOR),1) ischroot || make vendor endif -override_dh_auto_build: - CARGO_HOME="$$(pwd)/target/cargo" make - override_dh_installinit: dh_installinit -r diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 00000000..97d96f63 --- /dev/null +++ b/debian/source/options @@ -0,0 +1,2 @@ +tar-ignore=target +tar-ignore=vendor \ No newline at end of file diff --git a/flake.lock b/flake.lock index b3c20a7d..30eed204 100644 --- a/flake.lock +++ b/flake.lock @@ -4,17 +4,15 @@ "inputs": { "flake-compat": "flake-compat", "flake-utils": "flake-utils", - "nixpkgs": [ - "nixpkgs" - ], + "nixpkgs": "nixpkgs", "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1683134812, - "narHash": "sha256-yUiArtneEBCTYt7rOg/tLr1iv4AmjFu5tdGa0OVpjbo=", + "lastModified": 1688425221, + "narHash": "sha256-DhZnju72DuX9GhOnCOBIE94aCGKC2BOaF+kGxbnP/K0=", "owner": "ipetkov", "repo": "crane", - "rev": "8708b19627b2dfc2d1ac332b74383b8abdd429f0", + "rev": "fc6a236548b31aef0be3b0a0377c4459bb39d923", "type": "github" }, "original": { @@ -23,27 +21,6 @@ "type": "github" } }, - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1683354017, - "narHash": "sha256-r0BrHDaljUKyQS5FgA4P9xgK+dGa8L0XDL0vBdriEM8=", - "owner": "nix-community", - "repo": "fenix", - "rev": "65fdcbdc0bf35510a013d8a0883b0fa7a4ecd2a8", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, "flake-compat": { "flake": false, "locked": { @@ -65,11 +42,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "lastModified": 1687709756, + "narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7", "type": "github" }, "original": { @@ -98,11 +75,11 @@ }, "nix-filter": { "locked": { - "lastModified": 1681154353, - "narHash": "sha256-MCJ5FHOlbfQRFwN0brqPbCunLEVw05D/3sRVoNVt2tI=", + "lastModified": 1687178632, + "narHash": "sha256-HS7YR5erss0JCaUijPeyg2XrisEb959FIct3n2TMGbE=", "owner": "numtide", "repo": "nix-filter", - "rev": "f529f42792ade8e32c4be274af6b6d60857fbee7", + "rev": "d90c75e8319d0dd9be67d933d8eb9d0894ec9174", "type": "github" }, "original": { @@ -113,11 +90,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1683353485, - "narHash": "sha256-Skp5El3egmoXPiINWjnoW0ktVfB7PR/xc4F4bhD+BJY=", + "lastModified": 1688221086, + "narHash": "sha256-cdW6qUL71cNWhHCpMPOJjlw0wzSRP0pVlRn2vqX/VVg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "caf436a52b25164b71e0d48b671127ac2e2a5b75", + "rev": "cd99c2b3c9f160cd004318e0697f90bbd5960825", "type": "github" }, "original": { @@ -127,29 +104,99 @@ "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1688049487, + "narHash": "sha256-100g4iaKC9MalDjUW9iN6Jl/OocTDtXdeAj7pEGIRh4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4bc72cae107788bf3f24f30db2e2f685c9298dc9", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1685591878, + "narHash": "sha256-Ib3apaLqIFkZb94q6Q214DXrz0FnJq5C7usywTv63og=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8d4d822bc0efa9de6eddc79cb0d82897a9baa750", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1681358109, + "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1688466019, + "narHash": "sha256-VeM2akYrBYMsb4W/MmBo1zmaMfgbL4cH3Pu8PGyIwJ0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8e8d955c22df93dbe24f19ea04f47a74adbdc5ec", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "root": { "inputs": { "crane": "crane", - "fenix": "fenix", - "flake-utils": "flake-utils_2", "nix-filter": "nix-filter", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs_2", + "parts": "parts", + "rust": "rust" } }, - "rust-analyzer-src": { - "flake": false, + "rust": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_3" + }, "locked": { - "lastModified": 1683321754, - "narHash": "sha256-qvyrgObeXw+h+P0VAvaARjRUWn5Ey1ckbs+1El2dc0Y=", - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "a4966c92829f945d3846eb0ca0e240ac7f7c8c60", + "lastModified": 1688438033, + "narHash": "sha256-wOmpZis06pVKTR+5meGwhrW10/buf98lnA26uQLaqek=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "c3e43223dece545cfe06ddd92fd782adc73d56c3", "type": "github" }, "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", + "owner": "oxalica", + "repo": "rust-overlay", "type": "github" } }, @@ -165,11 +212,11 @@ ] }, "locked": { - "lastModified": 1683080331, - "narHash": "sha256-nGDvJ1DAxZIwdn6ww8IFwzoHb2rqBP4wv/65Wt5vflk=", + "lastModified": 1688351637, + "narHash": "sha256-CLTufJ29VxNOIZ8UTg0lepsn3X03AmopmaLTTeHDCL4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "d59c3fa0cba8336e115b376c2d9e91053aa59e56", + "rev": "f9b92316727af9e6c7fee4a761242f7f46880329", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index f3f43bff..c9e4d17c 100644 --- a/flake.nix +++ b/flake.nix @@ -3,71 +3,75 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - flake-utils.url = "github:numtide/flake-utils"; + parts.url = "github:hercules-ci/flake-parts"; + crane.url = "github:ipetkov/crane"; + rust.url = "github:oxalica/rust-overlay"; nix-filter.url = "github:numtide/nix-filter"; - crane = { - url = "github:ipetkov/crane"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - fenix = { - url = "github:nix-community/fenix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; }; - outputs = { self, nixpkgs, flake-utils, nix-filter, crane, fenix }: - flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - craneLib = crane.lib.${system}.overrideToolchain fenix.packages.${system}.stable.toolchain; + outputs = inputs@{ self, nixpkgs, parts, crane, rust, nix-filter, ... }: + parts.lib.mkFlake { inherit inputs; } { + systems = [ "aarch64-linux" "x86_64-linux" ]; + + perSystem = { self', lib, system, ... }: + let + pkgs = nixpkgs.legacyPackages.${system}.extend rust.overlays.default; + rust-toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + craneLib = crane.lib.${system}.overrideToolchain rust-toolchain; + craneArgs = { + pname = "cosmic-comp"; + version = self.rev or "dirty"; - pkgDef = { - src = nix-filter.lib.filter { - root = ./.; - include = [ - ./src - ./Cargo.toml - ./Cargo.lock - ./resources + src = nix-filter.lib.filter { + root = ./.; + include = [ + ./src + ./i18n.toml + ./Cargo.toml + ./Cargo.lock + ./resources + ./cosmic-comp-config + ]; + }; + + nativeBuildInputs = with pkgs; [ + pkg-config + autoPatchelfHook + cmake ]; - }; - nativeBuildInputs = with pkgs; [ pkg-config autoPatchelfHook ]; - buildInputs = with pkgs; [ - wayland - systemd # For libudev - seatd # For libseat - libxkbcommon - libinput - stdenv.cc.cc.lib - mesa # For libgbm - ]; - runtimeDependencies = with pkgs; [ libglvnd ]; # For libEGL - }; - cargoArtifacts = craneLib.buildDepsOnly pkgDef; - cosmic-comp = craneLib.buildPackage (pkgDef // { - inherit cargoArtifacts; - }); - in { - checks = { - inherit cosmic-comp; - }; + buildInputs = with pkgs; [ + wayland + systemd # For libudev + seatd # For libseat + libxkbcommon + libinput + mesa # For libgbm + fontconfig + stdenv.cc.cc.lib + ]; - packages.default = cosmic-comp; + runtimeDependencies = with pkgs; [ + libglvnd # For libEGL + ]; + }; - apps.default = flake-utils.lib.mkApp { - drv = cosmic-comp; - }; + cargoArtifacts = craneLib.buildDepsOnly craneArgs; + cosmic-comp = craneLib.buildPackage (craneArgs // { inherit cargoArtifacts; }); + in + { + apps.cosmic-comp = { + type = "app"; + program = lib.getExe self'.packages.default; + }; - devShells.default = pkgs.mkShell rec { - inputsFrom = builtins.attrValues self.checks.${system}; - LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath (builtins.concatMap (d: d.runtimeDependencies) inputsFrom); - }; - }); + checks.cosmic-comp = cosmic-comp; + packages.default = cosmic-comp; - nixConfig = { - # Cache for the Rust toolchain in fenix - extra-substituters = [ "https://nix-community.cachix.org" ]; - extra-trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ]; - }; + devShells.default = pkgs.mkShell { + # Should there be packages here or use Nix purely for CI? + LD_LIBRARY_PATH = lib.makeLibraryPath (__concatMap (d: d.runtimeDependencies) (__attrValues self'.checks)); + }; + }; + }; } diff --git a/i18n.toml b/i18n.toml new file mode 100644 index 00000000..746887d6 --- /dev/null +++ b/i18n.toml @@ -0,0 +1,4 @@ +fallback_language = "en" + +[fluent] +assets_dir = "resources/i18n" \ No newline at end of file diff --git a/resources/i18n/de/cosmic_comp.ftl b/resources/i18n/de/cosmic_comp.ftl new file mode 100644 index 00000000..4ea47bb0 --- /dev/null +++ b/resources/i18n/de/cosmic_comp.ftl @@ -0,0 +1,5 @@ +grow-window = Vergrößern +shrink-window = Verkleinern +swap-windows = Fenster tauschen +stack-windows = Fenster stapeln +unknown-keybinding = \ No newline at end of file diff --git a/resources/i18n/en/cosmic_comp.ftl b/resources/i18n/en/cosmic_comp.ftl new file mode 100644 index 00000000..71e72984 --- /dev/null +++ b/resources/i18n/en/cosmic_comp.ftl @@ -0,0 +1,5 @@ +grow-window = Grow +shrink-window = Shrink +swap-windows = Swap Windows +stack-windows = Stack Windows +unknown-keybinding = \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 70772a38..f400973c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.65" \ No newline at end of file +channel = "1.70" diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 18bee99d..3ecf2927 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -6,7 +6,7 @@ use crate::{ backend::render::{workspace_elements, CLEAR_COLOR}, config::OutputConfig, shell::Shell, - state::{BackendData, ClientState, Common, Data, Fps, SurfaceDmabufFeedback}, + state::{BackendData, ClientState, Common, Fps, SurfaceDmabufFeedback}, utils::prelude::*, wayland::{ handlers::screencopy::{render_session, UserdataExt}, @@ -16,6 +16,7 @@ use crate::{ use anyhow::{Context, Result}; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::FailureReason; +use libc::dev_t; use smithay::{ backend::{ allocator::{ @@ -25,7 +26,7 @@ use smithay::{ Allocator, Format, Fourcc, }, drm::{ - compositor::{BlitFrameResultError, DrmCompositor, FrameError}, + compositor::{BlitFrameResultError, DrmCompositor, FrameError, PrimaryPlaneElement}, DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, NodeType, }, egl::{EGLContext, EGLDevice, EGLDisplay}, @@ -33,11 +34,12 @@ use smithay::{ libinput::{LibinputInputBackend, LibinputSessionInterface}, renderer::{ buffer_dimensions, - damage::{Error as RenderError, OutputNoMode}, + damage::{Error as RenderError, RenderOutputResult}, element::Element, gles::{GlesRenderbuffer, GlesTexture}, glow::GlowRenderer, multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager}, + sync::SyncPoint, Bind, ImportDma, Offscreen, }, session::{libseat::LibSeatSession, Event as SessionEvent, Session}, @@ -46,7 +48,7 @@ use smithay::{ }, desktop::utils::OutputPresentationFeedback, input::Seat, - output::{Mode as OutputMode, Output, PhysicalProperties, Subpixel}, + output::{Mode as OutputMode, Output, OutputNoMode, PhysicalProperties, Subpixel}, reexports::{ calloop::{ timer::{TimeoutAction, Timer}, @@ -56,8 +58,8 @@ use smithay::{ control::{connector, crtc, Device as ControlDevice, ModeTypeFlags}, Device as _, }, - input::Libinput, - nix::{fcntl::OFlag, sys::stat::dev_t}, + input::{self, Libinput}, + rustix::fs::OFlags, wayland_protocols::wp::{ linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1, presentation_time::server::wp_presentation_feedback, @@ -67,6 +69,7 @@ use smithay::{ utils::{DeviceFd, Size, Transform}, wayland::{ dmabuf::{get_dmabuf, DmabufFeedbackBuilder, DmabufGlobal}, + drm_lease::{DrmLease, DrmLeaseState}, relative_pointer::RelativePointerManagerState, seat::WaylandFocus, shm::{shm_format_to_fourcc, with_buffer_contents}, @@ -79,7 +82,7 @@ use std::{ cell::RefCell, collections::{HashMap, HashSet}, ffi::CStr, - os::unix::io::FromRawFd, + fmt, path::PathBuf, time::Duration, }; @@ -92,8 +95,10 @@ use super::render::{init_shaders, CursorMode, GlMultiRenderer}; // for now we assume we need at least 3ms const MIN_RENDER_TIME: Duration = Duration::from_millis(3); +#[derive(Debug)] pub struct KmsState { - devices: HashMap, + pub devices: HashMap, + pub input_devices: HashMap, pub api: GpuManager>, pub primary: DrmNode, session: LibSeatSession, @@ -103,15 +108,38 @@ pub struct KmsState { pub struct Device { render_node: DrmNode, surfaces: HashMap, - drm: DrmDevice, + pub drm: DrmDevice, gbm: GbmDevice, allocator: Box>, formats: HashSet, supports_atomic: bool, + pub non_desktop_connectors: Vec<(connector::Handle, crtc::Handle)>, + pub leasing_global: Option, + pub active_leases: Vec, event_token: Option, socket: Option, } +impl fmt::Debug for Device { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Device") + .field("render_node", &self.render_node) + .field("surfaces", &self.surfaces) + .field("drm", &self.drm) + .field("gbm", &self.gbm) + .field("allocator", &"...") + .field("formats", &self.formats) + .field("supports_atomic", &self.supports_atomic) + .field("non_desktop_connectors", &self.non_desktop_connectors) + .field("leasing_global", &self.leasing_global) + .field("active_leases", &self.active_leases) + .field("event_token", &self.event_token) + .field("socket", &self.socket) + .finish() + } +} + +#[derive(Debug)] pub struct Surface { surface: Option, connector: connector::Handle, @@ -121,6 +149,7 @@ pub struct Surface { scheduled: bool, pending: bool, dirty: bool, + last_animation_state: bool, render_timer_token: Option, fps: Fps, feedback: HashMap, @@ -135,7 +164,7 @@ pub type GbmDrmCompositor = DrmCompositor< pub fn init_backend( dh: &DisplayHandle, - event_loop: &mut EventLoop<'static, Data>, + event_loop: &mut EventLoop<'static, State>, state: &mut State, ) -> Result<()> { let (session, notifier) = LibSeatSession::new().context("Failed to acquire session")?; @@ -150,14 +179,21 @@ pub fn init_backend( let libinput_event_source = event_loop .handle() - .insert_source(libinput_backend, move |mut event, _, data| { - if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event { - data.state.common.config.read_device(device); + .insert_source(libinput_backend, move |mut event, _, state| { + if let InputEvent::DeviceAdded { ref mut device } = &mut event { + state.common.config.read_device(device); + state + .backend + .kms() + .input_devices + .insert(device.name().into(), device.clone()); + } else if let InputEvent::DeviceRemoved { device } = &event { + state.backend.kms().input_devices.remove(device.name()); } - data.state.process_input_event(event); - for output in data.state.common.shell.outputs() { - if let Err(err) = data.state.backend.kms().schedule_render( - &data.state.common.event_loop_handle, + state.process_input_event(event, true); + for output in state.common.shell.outputs() { + if let Err(err) = state.backend.kms().schedule_render( + &state.common.event_loop_handle, output, None, None, @@ -207,19 +243,17 @@ pub fn init_backend( }; info!("Using {} as primary gpu for rendering.", primary); - let udev_dispatcher = Dispatcher::new(udev_backend, move |event, _, data: &mut Data| { + let udev_dispatcher = Dispatcher::new(udev_backend, move |event, _, state: &mut State| { + let dh = state.common.display_handle.clone(); match match event { - UdevEvent::Added { device_id, path } => data - .state - .device_added(device_id, path, &data.display.handle(), true) + UdevEvent::Added { device_id, path } => state + .device_added(device_id, path, &dh, true) .with_context(|| format!("Failed to add drm device: {}", device_id)), - UdevEvent::Changed { device_id } => data - .state + UdevEvent::Changed { device_id } => state .device_changed(device_id) .with_context(|| format!("Failed to update drm device: {}", device_id)), - UdevEvent::Removed { device_id } => data - .state - .device_removed(device_id, &data.display.handle()) + UdevEvent::Removed { device_id } => state + .device_removed(device_id, &dh) .with_context(|| format!("Failed to remove drm device: {}", device_id)), } { Ok(()) => { @@ -240,16 +274,19 @@ pub fn init_backend( let dispatcher = udev_dispatcher.clone(); let session_event_source = event_loop .handle() - .insert_source(notifier, move |event, &mut (), data| match event { + .insert_source(notifier, move |event, &mut (), state| match event { SessionEvent::ActivateSession => { if let Err(err) = libinput_context.resume() { error!(?err, "Failed to resume libinput context."); } - for device in data.state.backend.kms().devices.values() { + for device in state.backend.kms().devices.values_mut() { device.drm.activate(); + if let Some(lease_state) = device.leasing_global.as_mut() { + lease_state.resume::(); + } } let dispatcher = dispatcher.clone(); - handle.insert_idle(move |data| { + handle.insert_idle(move |state| { for (dev, path) in dispatcher.as_source_ref().device_list() { let drm_node = match DrmNode::from_dev_id(dev) { Ok(node) => node, @@ -258,32 +295,27 @@ pub fn init_backend( continue; } }; - if data.state.backend.kms().devices.contains_key(&drm_node) { - if let Err(err) = data.state.device_changed(dev) { + if state.backend.kms().devices.contains_key(&drm_node) { + if let Err(err) = state.device_changed(dev) { error!(?err, "Failed to update drm device {}.", path.display(),); } } else { - if let Err(err) = data.state.device_added( - dev, - path.into(), - &data.display.handle(), - true, - ) { + let dh = state.common.display_handle.clone(); + if let Err(err) = state.device_added(dev, path.into(), &dh, true) { error!(?err, "Failed to add drm device {}.", path.display(),); } } } - let seats = data.state.common.seats().cloned().collect::>(); - data.state.common.config.read_outputs( - &mut data.state.common.output_configuration_state, - &mut data.state.backend, - &mut data.state.common.shell, + let seats = state.common.seats().cloned().collect::>(); + state.common.config.read_outputs( + &mut state.common.output_configuration_state, + &mut state.backend, + &mut state.common.shell, seats.into_iter(), - &data.state.common.event_loop_handle, + &state.common.event_loop_handle, ); - for surface in data - .state + for surface in state .backend .kms() .devices @@ -293,10 +325,10 @@ pub fn init_backend( surface.scheduled = false; surface.pending = false; } - for output in data.state.common.shell.outputs() { + for output in state.common.shell.outputs() { let sessions = output.pending_buffers().collect::>(); - if let Err(err) = data.state.backend.kms().schedule_render( - &data.state.common.event_loop_handle, + if let Err(err) = state.backend.kms().schedule_render( + &state.common.event_loop_handle, output, None, if !sessions.is_empty() { @@ -317,12 +349,15 @@ pub fn init_backend( } SessionEvent::PauseSession => { libinput_context.suspend(); - for device in data.state.backend.kms().devices.values_mut() { + for device in state.backend.kms().devices.values_mut() { device.drm.pause(); + if let Some(lease_state) = device.leasing_global.as_mut() { + lease_state.suspend(); + } for surface in device.surfaces.values_mut() { surface.surface = None; if let Some(token) = surface.render_timer_token.take() { - data.state.common.event_loop_handle.remove(token); + state.common.event_loop_handle.remove(token); } surface.scheduled = false; } @@ -342,6 +377,7 @@ pub fn init_backend( primary, session, devices: HashMap::new(), + input_devices: HashMap::new(), }); // Create relative pointer global @@ -350,9 +386,9 @@ pub fn init_backend( state.launch_xwayland(Some(primary)); for (dev, path) in udev_dispatcher.as_source_ref().device_list() { - state - .device_added(dev, path.into(), dh, false) - .with_context(|| format!("Failed to add drm device: {}", path.display()))?; + if let Err(err) = state.device_added(dev, path.into(), dh, false) { + warn!("Failed to add device {}: {:?}", path.display(), err); + } } // HACK: amdgpu doesn't like us initializing vulkan too early.. @@ -382,23 +418,21 @@ impl State { return Ok(()); } - let fd = DrmDeviceFd::new(unsafe { - DeviceFd::from_raw_fd( - self.backend - .kms() - .session - .open( - &path, - OFlag::O_RDWR | OFlag::O_CLOEXEC | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, + let fd = DrmDeviceFd::new(DeviceFd::from( + self.backend + .kms() + .session + .open( + &path, + OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK, + ) + .with_context(|| { + format!( + "Failed to optain file descriptor for drm device: {}", + path.display() ) - .with_context(|| { - format!( - "Failed to optain file descriptor for drm device: {}", - path.display() - ) - })?, - ) - }); + })?, + )); let (drm, notifier) = DrmDevice::new(fd.clone(), false) .with_context(|| format!("Failed to initialize drm device for: {}", path.display()))?; let drm_node = DrmNode::from_dev_id(dev)?; @@ -436,12 +470,13 @@ impl State { .event_loop_handle .insert_source( notifier, - move |event, metadata, data: &mut Data| match event { + move |event, metadata, state: &mut State| match event { DrmEvent::VBlank(crtc) => { let rescheduled = if let Some(device) = - data.state.backend.kms().devices.get_mut(&drm_node) + state.backend.kms().devices.get_mut(&drm_node) { if let Some(surface) = device.surfaces.get_mut(&crtc) { + trace!(?crtc, "VBlank"); #[cfg(feature = "debug")] surface.fps.displayed(); @@ -467,7 +502,7 @@ impl State { ) } else { ( - data.state.common.clock.now(), + state.common.clock.now(), wp_presentation_feedback::Kind::Vsync, ) }; @@ -477,7 +512,11 @@ impl State { surface .output .current_mode() - .map(|mode| mode.refresh as u32) + .map(|mode| { + Duration::from_secs_f64( + 1_000.0 / mode.refresh as f64, + ) + }) .unwrap_or_default(), seq as u64, flags, @@ -485,9 +524,20 @@ impl State { } surface.pending = false; - surface.dirty.then(|| { - (surface.output.clone(), surface.fps.avg_rendertime(5)) - }) + let animations_going = + state.common.shell.animations_going(); + let animation_diff = std::mem::replace( + &mut surface.last_animation_state, + animations_going, + ) != animations_going; + (surface.dirty || animations_going || animation_diff).then( + || { + ( + surface.output.clone(), + surface.fps.avg_rendertime(5), + ) + }, + ) } Some(Err(err)) => { warn!(?err, "Failed to submit frame."); @@ -504,7 +554,7 @@ impl State { if let Some((output, avg_rendertime)) = rescheduled { let mut scheduled_sessions = - data.state.workspace_session_for_output(&output); + state.workspace_session_for_output(&output); let mut output_sessions = output.pending_buffers().peekable(); if output_sessions.peek().is_some() { scheduled_sessions @@ -514,8 +564,8 @@ impl State { let estimated_rendertime = std::cmp::max(avg_rendertime, MIN_RENDER_TIME); - if let Err(err) = data.state.backend.kms().schedule_render( - &data.state.common.event_loop_handle, + if let Err(err) = state.backend.kms().schedule_render( + &state.common.event_loop_handle, &output, Some(estimated_rendertime), scheduled_sessions, @@ -554,6 +604,18 @@ impl State { drm, formats, supports_atomic, + non_desktop_connectors: Vec::new(), + leasing_global: DrmLeaseState::new::(dh, &drm_node) + .map_err(|err| { + // TODO: replace with inspect_err, once stable + warn!( + ?err, + "Failed to initialize drm lease global for: {}", drm_node + ); + err + }) + .ok(), + active_leases: Vec::new(), event_token: Some(token), socket, }; @@ -585,19 +647,62 @@ impl State { init_shaders(&mut renderer).expect("Failed to initialize renderer"); for (crtc, conn) in outputs { - match device.setup_surface(crtc, conn, (w, 0), &mut renderer) { - Ok(output) => { - w += output - .user_data() - .get::>() - .unwrap() - .borrow() - .mode_size() - .w; - wl_outputs.push(output); + let non_desktop = + match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") { + Ok((val_type, value)) => { + val_type.convert_value(value).as_boolean().unwrap() + } + Err(err) => { + warn!( + ?err, + "Failed to determine if connector is meant desktop usage, assuming so." + ); + false + } + }; + + if non_desktop { + let Ok(output_name) = drm_helpers::interface_name(&device.drm, conn) else { + continue + }; + let drm_helpers::EdidInfo { + model, + manufacturer, + } = match drm_helpers::edid_info(&device.drm, conn) { + Ok(info) => info, + Err(_) => drm_helpers::EdidInfo { + model: "Unknown".into(), + manufacturer: "Unknown".into(), + }, + }; + + device.non_desktop_connectors.push((conn, crtc)); + info!( + "Connector {} is non-desktop, setting up for leasing", + output_name + ); + if let Some(lease_state) = device.leasing_global.as_mut() { + lease_state.add_connector::( + conn, + output_name, + format!("{} {}", manufacturer, model), + ); } - Err(err) => warn!(?err, "Failed to initialize output."), - }; + } else { + match device.setup_surface(crtc, conn, (w, 0), &mut renderer) { + Ok(output) => { + w += output + .user_data() + .get::>() + .unwrap() + .borrow() + .mode_size() + .w; + wl_outputs.push(output); + } + Err(err) => warn!(?err, "Failed to initialize output."), + }; + } } backend.devices.insert(drm_node, device); } @@ -675,7 +780,16 @@ impl State { let changes = device.enumerate_surfaces()?; let mut w = self.common.shell.global_space().size.w; for crtc in changes.removed { - if let Some(surface) = device.surfaces.remove(&crtc) { + if let Some(pos) = device + .non_desktop_connectors + .iter() + .position(|(_, handle)| *handle == crtc) + { + let (conn, _) = device.non_desktop_connectors.remove(pos); + if let Some(leasing_state) = device.leasing_global.as_mut() { + leasing_state.withdraw_connector(conn); + } + } else if let Some(surface) = device.surfaces.remove(&crtc) { if let Some(token) = surface.render_timer_token { self.common.event_loop_handle.remove(token); } @@ -684,26 +798,69 @@ impl State { } } for (crtc, conn) in changes.added { - let mut renderer = match backend.api.single_renderer(&device.render_node) { - Ok(renderer) => renderer, - Err(err) => { - warn!(?err, "Failed to initialize output."); - continue; - } - }; - match device.setup_surface(crtc, conn, (w, 0), &mut renderer) { - Ok(output) => { - w += output - .user_data() - .get::>() - .unwrap() - .borrow() - .mode_size() - .w; - outputs_added.push(output); + let non_desktop = + match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") { + Ok((val_type, value)) => { + val_type.convert_value(value).as_boolean().unwrap() + } + Err(err) => { + warn!( + ?err, + "Failed to determine if connector is meant desktop usage, assuming so." + ); + false + } + }; + + if non_desktop { + let Ok(output_name) = drm_helpers::interface_name(&device.drm, conn) else { + continue + }; + let drm_helpers::EdidInfo { + model, + manufacturer, + } = match drm_helpers::edid_info(&device.drm, conn) { + Ok(info) => info, + Err(_) => drm_helpers::EdidInfo { + model: "Unknown".into(), + manufacturer: "Unknown".into(), + }, + }; + + device.non_desktop_connectors.push((conn, crtc)); + info!( + "Connector {} is non-desktop, setting up for leasing", + output_name + ); + if let Some(lease_state) = device.leasing_global.as_mut() { + lease_state.add_connector::( + conn, + output_name, + format!("{} {}", manufacturer, model), + ); } - Err(err) => warn!(?err, "Failed to initialize output."), - }; + } else { + let mut renderer = match backend.api.single_renderer(&device.render_node) { + Ok(renderer) => renderer, + Err(err) => { + warn!(?err, "Failed to initialize output."); + continue; + } + }; + match device.setup_surface(crtc, conn, (w, 0), &mut renderer) { + Ok(output) => { + w += output + .user_data() + .get::>() + .unwrap() + .borrow() + .mode_size() + .w; + outputs_added.push(output); + } + Err(err) => warn!(?err, "Failed to initialize output."), + }; + } } } } @@ -740,6 +897,9 @@ impl State { let mut outputs_removed = Vec::new(); let backend = self.backend.kms(); if let Some(mut device) = backend.devices.remove(&drm_node) { + if let Some(mut leasing_global) = device.leasing_global.take() { + leasing_global.disable_global::(); + } backend.api.as_mut().remove_node(&device.render_node); for surface in device.surfaces.values_mut() { if let Some(token) = surface.render_timer_token.take() { @@ -798,6 +958,11 @@ impl Device { .surfaces .iter() .map(|(c, s)| (*c, s.connector)) + .chain( + self.non_desktop_connectors + .iter() + .map(|(conn, crtc)| (*crtc, *conn)), + ) .collect::>(); let added = config @@ -847,8 +1012,14 @@ impl Device { interface, PhysicalProperties { size: (phys_w as i32, phys_h as i32).into(), - // TODO: We need to read that from the connector properties - subpixel: Subpixel::Unknown, + subpixel: match conn_info.subpixel() { + connector::SubPixel::HorizontalRgb => Subpixel::HorizontalRgb, + connector::SubPixel::HorizontalBgr => Subpixel::HorizontalBgr, + connector::SubPixel::VerticalRgb => Subpixel::VerticalRgb, + connector::SubPixel::VerticalBgr => Subpixel::VerticalBgr, + connector::SubPixel::None => Subpixel::None, + _ => Subpixel::Unknown, + }, make: edid_info .as_ref() .map(|info| info.manufacturer.clone()) @@ -894,6 +1065,7 @@ impl Device { scheduled: false, pending: false, dirty: false, + last_animation_state: false, render_timer_token: None, fps: Fps::new(renderer.as_mut()), feedback: HashMap::new(), @@ -925,7 +1097,7 @@ fn render_node_for_output( ) -> DrmNode { let workspace = shell.active_space(output); let nodes = workspace - .get_fullscreen(output) + .get_fullscreen() .map(|w| vec![w.clone()]) .unwrap_or_else(|| workspace.windows().collect::>()) .into_iter() @@ -960,19 +1132,20 @@ fn get_surface_dmabuf_feedback( .collect::>(); let surface = compositor.surface(); - let planes = surface.planes().unwrap(); + let planes = surface.planes(); // We limit the scan-out trache to formats we can also render from // so that there is always a fallback render path available in case // the supplied buffer can not be scanned out directly - let planes_formats = surface - .supported_formats(planes.primary.handle) - .unwrap() - .into_iter() + let planes_formats = planes + .primary + .formats + .iter() + .cloned() .chain( planes .overlay .iter() - .flat_map(|p| surface.supported_formats(p.handle).unwrap()), + .flat_map(|p| p.formats.iter().cloned()), ) .collect::>() .intersection(&combined_formats) @@ -982,7 +1155,11 @@ fn get_surface_dmabuf_feedback( let target_node = surface.device_fd().dev_id().unwrap(); let mut builder = DmabufFeedbackBuilder::new(render_node.dev_id(), render_formats); if target_node != render_node.dev_id() && !combined_formats.is_empty() { - builder = builder.add_preference_tranche(target_node, None, combined_formats); + builder = builder.add_preference_tranche( + target_node, + Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout), + combined_formats, + ); }; let render_feedback = builder.clone().build().unwrap(); @@ -1039,13 +1216,20 @@ impl Surface { ); } - let handle = state.shell.workspaces.active(&self.output).handle; + let (previous_workspace, workspace) = state.shell.workspaces.active(&self.output); + let (previous_idx, idx) = state.shell.workspaces.active_num(&self.output); + let previous_workspace = previous_workspace + .zip(previous_idx) + .map(|((w, start), idx)| (w.handle, idx, start)); + let workspace = (workspace.handle, idx); + let elements = workspace_elements( Some(&render_node), &mut renderer, state, &self.output, - &handle, + previous_workspace, + workspace, CursorMode::All, &mut Some(&mut self.fps), false, @@ -1055,8 +1239,11 @@ impl Surface { })?; self.fps.elements(); - let res = - compositor.render_frame::<_, _, GlesTexture>(&mut renderer, &elements, CLEAR_COLOR); + let res = compositor.render_frame::<_, _, GlesTexture>( + &mut renderer, + &elements, + CLEAR_COLOR, // TODO use a theme neutral color + ); self.fps.render(); match res { @@ -1067,6 +1254,11 @@ impl Surface { None }; + if frame_result.needs_sync() { + if let PrimaryPlaneElement::Swapchain(elem) = &frame_result.primary_element { + elem.sync.wait(); + } + } match compositor.queue_frame(feedback) { Ok(()) | Err(FrameError::EmptyFrame) => {} Err(err) => { @@ -1085,6 +1277,7 @@ impl Surface { |_node, buffer, renderer, dt, age| { let res = dt.damage_output(age, &elements)?; + let mut sync = SyncPoint::default(); if let (Some(ref damage), _) = &res { if let Ok(dmabuf) = get_dmabuf(buffer) { renderer.bind(dmabuf).map_err(RenderError::Rendering)?; @@ -1111,7 +1304,7 @@ impl Surface { self.output.current_scale().fractional_scale(), self.output.current_transform(), ); - frame_result + sync = frame_result .blit_frame_result( output_size, output_transform, @@ -1131,7 +1324,11 @@ impl Surface { })?; } - Ok(res) + Ok(RenderOutputResult { + damage: res.0, + states: res.1, + sync, + }) }, ) { Ok(true) => {} // success @@ -1192,14 +1389,14 @@ impl KmsState { seats: impl Iterator>, shell: &mut Shell, test_only: bool, - loop_handle: &LoopHandle<'_, Data>, + loop_handle: &LoopHandle<'_, State>, ) -> Result<(), anyhow::Error> { let recreated = if let Some(device) = self .devices .values_mut() .find(|dev| dev.surfaces.values().any(|s| s.output == *output)) { - let (crtc, mut surface) = device + let (crtc, surface) = device .surfaces .iter_mut() .find(|(_, s)| s.output == *output) @@ -1249,7 +1446,9 @@ impl KmsState { output_config.vrr, )?; } - compositor.use_mode(*mode).unwrap(); + compositor + .use_mode(*mode) + .context("Failed to apply new mode")?; false } else { surface.vrr = drm_helpers::set_vrr(drm, *crtc, conn, output_config.vrr) @@ -1270,9 +1469,7 @@ impl KmsState { let driver = drm .get_driver() .with_context(|| "Failed to query drm driver")?; - let mut planes = drm_surface - .planes() - .with_context(|| "Failed to query drm planes")?; + let mut planes = drm_surface.planes().clone(); // QUIRK: Using an overlay plane on a nvidia card breaks the display controller (wtf...) if driver .name() @@ -1322,7 +1519,6 @@ impl KmsState { false }; - shell.refresh_outputs(); if recreated { let sessions = output.pending_buffers().collect::>(); if let Err(err) = self.schedule_render( @@ -1401,7 +1597,7 @@ impl KmsState { pub fn schedule_render( &mut self, - loop_handle: &LoopHandle<'_, Data>, + loop_handle: &LoopHandle<'_, State>, output: &Output, estimated_rendertime: Option, mut screencopy_sessions: Option>, @@ -1414,9 +1610,9 @@ impl KmsState { { if surface.surface.is_none() { if let Some(sessions) = screencopy_sessions { - loop_handle.insert_idle(move |data| { + loop_handle.insert_idle(move |state| { for (session, params) in sessions.into_iter() { - data.state.common.still_pending(session, params); + state.common.still_pending(session, params); } }); } @@ -1437,8 +1633,8 @@ impl KmsState { .saturating_sub(estimated_rendertime.unwrap()), ) }, - move |_time, _, data| { - let backend = data.state.backend.kms(); + move |_time, _, state| { + let backend = state.backend.kms(); let (mut device, mut other) = backend .devices .iter_mut() @@ -1448,12 +1644,12 @@ impl KmsState { if let Some(surface) = target_device.surfaces.get_mut(&crtc) { let target_node = target_device.render_node; let render_node = render_node_for_output( - &data.display.handle(), + &state.common.display_handle, &surface.output, target_node, - &data.state.common.shell, + &state.common.shell, ); - let state = &mut data.state.common; + let common = &mut state.common; let result = if render_node != target_node { let render_device = &mut other @@ -1468,7 +1664,7 @@ impl KmsState { render_device.allocator.as_mut(), )), &target_node, - state, + common, screencopy_sessions.as_deref(), ) } else { @@ -1476,16 +1672,18 @@ impl KmsState { &mut backend.api, None, &target_node, - state, + common, screencopy_sessions.as_deref(), ) }; match result { Ok(_) => { + trace!(?crtc, "Frame pending"); surface.dirty = false; surface.pending = true; surface.scheduled = false; + surface.render_timer_token = None; return TimeoutAction::Drop; } Err(err) => { @@ -1501,18 +1699,19 @@ impl KmsState { if let Some(sessions) = screencopy_sessions.as_mut() { for (session, params) in sessions.drain(..) { - data.state.common.still_pending(session, params); + state.common.still_pending(session, params); } } TimeoutAction::Drop }, )?); + trace!(?surface.render_timer_token, ?crtc, "Frame scheduled"); surface.scheduled = true; } else { if let Some(sessions) = screencopy_sessions { - loop_handle.insert_idle(|data| { + loop_handle.insert_idle(|state| { for (session, params) in sessions.into_iter() { - data.state.common.still_pending(session, params); + state.common.still_pending(session, params); } }); } diff --git a/src/backend/kms/socket.rs b/src/backend/kms/socket.rs index b0f1c897..414c2dae 100644 --- a/src/backend/kms/socket.rs +++ b/src/backend/kms/socket.rs @@ -19,11 +19,9 @@ use smithay::{ use std::sync::Arc; use tracing::{info, warn}; -use crate::{ - state::{ClientState, Data}, - utils::prelude::*, -}; +use crate::state::{ClientState, State}; +#[derive(Debug)] pub struct Socket { pub token: RegistrationToken, pub drm_global: GlobalId, @@ -95,10 +93,10 @@ impl State { let token = self .common .event_loop_handle - .insert_source(listener, move |client_stream, _, data: &mut Data| { - if let Err(err) = data.display.handle().insert_client( + .insert_source(listener, move |client_stream, _, state: &mut State| { + if let Err(err) = state.common.display_handle.insert_client( client_stream, - Arc::new(data.state.new_client_state_with_node(render_node)), + Arc::new(state.new_client_state_with_node(render_node)), ) { warn!( socket_name = socket_name_clone, diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 940b6c42..59df16cb 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::state::{Data, State}; +use crate::state::State; use anyhow::{Context, Result}; use smithay::reexports::{calloop::EventLoop, wayland_server::DisplayHandle}; use tracing::{info, warn}; @@ -15,7 +15,7 @@ pub mod x11; pub fn init_backend_auto( dh: &DisplayHandle, - event_loop: &mut EventLoop<'static, Data>, + event_loop: &mut EventLoop<'static, State>, state: &mut State, ) -> Result<()> { let res = match std::env::var("COSMIC_BACKEND") { diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 14765568..b80c51d2 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -8,6 +8,7 @@ use smithay::{ element::{ surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, texture::{TextureBuffer, TextureRenderElement}, + Kind, }, ImportAll, ImportMem, Renderer, }, @@ -37,6 +38,26 @@ use xcursor::{ static FALLBACK_CURSOR_DATA: &[u8] = include_bytes!("../../../resources/cursor.rgba"); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum CursorShape { + Default, + ColResize, + RowResize, + Grab, +} + +impl ToString for CursorShape { + fn to_string(&self) -> String { + match self { + CursorShape::Default => "default", + CursorShape::ColResize => "col-resize", + CursorShape::RowResize => "row-resize", + CursorShape::Grab => "grabbing", + } + .to_string() + } +} + #[derive(Debug, Clone)] pub struct Cursor { icons: Vec, @@ -44,17 +65,8 @@ pub struct Cursor { } impl Cursor { - pub fn load() -> Cursor { - let name = std::env::var("XCURSOR_THEME") - .ok() - .unwrap_or_else(|| "default".into()); - let size = std::env::var("XCURSOR_SIZE") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(24); - - let theme = CursorTheme::load(&name); - let icons = load_icon(&theme) + pub fn load(theme: &CursorTheme, shape: CursorShape, size: u32) -> Cursor { + let icons = load_icon(&theme, shape) .map_err(|err| warn!(?err, "Unable to load xcursor, using fallback cursor")) .unwrap_or_else(|_| { vec![Image { @@ -78,12 +90,6 @@ impl Cursor { } } -impl Default for Cursor { - fn default() -> Cursor { - Cursor::load() - } -} - fn nearest_images(size: u32, images: &[Image]) -> impl Iterator { // Follow the nominal size of the cursor to choose the nearest let nearest_image = images @@ -120,8 +126,10 @@ enum Error { Parse, } -fn load_icon(theme: &CursorTheme) -> Result, Error> { - let icon_path = theme.load_icon("default").ok_or(Error::NoDefaultCursor)?; +fn load_icon(theme: &CursorTheme, shape: CursorShape) -> Result, Error> { + let icon_path = theme + .load_icon(&shape.to_string()) + .ok_or(Error::NoDefaultCursor)?; let mut cursor_file = std::fs::File::open(&icon_path)?; let mut cursor_data = Vec::new(); cursor_file.read_to_end(&mut cursor_data)?; @@ -162,6 +170,8 @@ where surface, position.to_physical_precise_round(scale), scale, + 1.0, + Kind::Cursor, ) } @@ -190,19 +200,60 @@ where surface, location.into().to_physical_precise_round(scale), scale, + 1.0, + Kind::Unspecified, ) } pub struct CursorState { - pub cursor: Cursor, + current_cursor: RefCell, + pub cursors: HashMap, current_image: RefCell>, image_cache: RefCell)>>>, } +impl CursorState { + pub fn set_shape(&self, shape: CursorShape) { + *self.current_cursor.borrow_mut() = shape; + } +} + +pub fn load_cursor_theme() -> (CursorTheme, u32) { + let name = std::env::var("XCURSOR_THEME") + .ok() + .unwrap_or_else(|| "default".into()); + let size = std::env::var("XCURSOR_SIZE") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(24); + (CursorTheme::load(&name), size) +} + impl Default for CursorState { fn default() -> CursorState { + let (theme, size) = load_cursor_theme(); CursorState { - cursor: Cursor::default(), + current_cursor: RefCell::new(CursorShape::Default), + cursors: { + let mut map = HashMap::new(); + map.insert( + CursorShape::Default, + Cursor::load(&theme, CursorShape::Default, size), + ); + map.insert( + CursorShape::ColResize, + Cursor::load(&theme, CursorShape::ColResize, size), + ); + map.insert( + CursorShape::RowResize, + Cursor::load(&theme, CursorShape::RowResize, size), + ); + map.insert( + CursorShape::Grab, + Cursor::load(&theme, CursorShape::Grab, size), + ); + map + }, current_image: RefCell::new(None), image_cache: RefCell::new(HashMap::new()), } @@ -232,25 +283,29 @@ where let mut cursor_status = cell.borrow_mut(); if let CursorImageStatus::Surface(ref surface) = *cursor_status { if !surface.alive() { - *cursor_status = CursorImageStatus::Default; + *cursor_status = CursorImageStatus::default_named(); } } cursor_status.clone() }) - .unwrap_or(CursorImageStatus::Default); + .unwrap_or(CursorImageStatus::default_named()); if let CursorImageStatus::Surface(ref wl_surface) = cursor_status { return draw_surface_cursor(renderer, wl_surface, location.to_i32_round(), scale); - } else if draw_default && CursorImageStatus::Default == cursor_status { + // TODO: Handle other named cursors + } else if draw_default && CursorImageStatus::default_named() == cursor_status { let integer_scale = scale.x.max(scale.y).ceil() as u32; let seat_userdata = seat.user_data(); - seat_userdata.insert_if_missing(CursorState::default); let state = seat_userdata.get::().unwrap(); - let frame = state.cursor.get_image( - integer_scale, - Into::::into(time).as_millis() as u32, - ); + let frame = state + .cursors + .get(&*state.current_cursor.borrow()) + .unwrap() + .get_image( + integer_scale, + Into::::into(time).as_millis() as u32, + ); let mut cache = state.image_cache.borrow_mut(); let pointer_images = cache @@ -293,6 +348,7 @@ where None, None, None, + Kind::Cursor, ), )]; } else { diff --git a/src/backend/render/element.rs b/src/backend/render/element.rs index 526bfafb..d1e51b9d 100644 --- a/src/backend/render/element.rs +++ b/src/backend/render/element.rs @@ -2,7 +2,10 @@ use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement}; use smithay::{ backend::renderer::{ - element::{Element, RenderElement, UnderlyingStorage}, + element::{ + utils::{Relocate, RelocateRenderElement}, + Element, RenderElement, UnderlyingStorage, + }, glow::{GlowFrame, GlowRenderer}, Frame, ImportAll, ImportMem, Renderer, }, @@ -10,11 +13,9 @@ use smithay::{ }; #[cfg(feature = "debug")] -use smithay::backend::renderer::{ - element::texture::TextureRenderElement, gles::GlesTexture, multigpu::Error as MultiError, -}; +use smithay::backend::renderer::{element::texture::TextureRenderElement, gles::GlesTexture}; -use super::{cursor::CursorRenderElement, GlMultiFrame, GlMultiRenderer}; +use super::{cursor::CursorRenderElement, GlMultiError, GlMultiFrame, GlMultiRenderer}; pub enum CosmicElement where @@ -22,7 +23,7 @@ where ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - Workspace(WorkspaceRenderElement), + Workspace(RelocateRenderElement>), Cursor(CursorRenderElement), MoveGrab(CosmicMappedRenderElement), #[cfg(feature = "debug")] @@ -118,6 +119,16 @@ where CosmicElement::Egui(elem) => elem.opaque_regions(scale), } } + + fn alpha(&self) -> f32 { + match self { + CosmicElement::Workspace(elem) => elem.alpha(), + CosmicElement::Cursor(elem) => elem.alpha(), + CosmicElement::MoveGrab(elem) => elem.alpha(), + #[cfg(feature = "debug")] + CosmicElement::Egui(elem) => elem.alpha(), + } + } } impl RenderElement for CosmicElement { @@ -157,7 +168,7 @@ impl<'a, 'b> RenderElement> for CosmicElement, dst: Rectangle, damage: &[Rectangle], - ) -> Result<(), as Renderer>::Error> { + ) -> Result<(), GlMultiError> { match self { CosmicElement::Workspace(elem) => elem.draw(frame, src, dst, damage), CosmicElement::Cursor(elem) => elem.draw(frame, src, dst, damage), @@ -167,7 +178,7 @@ impl<'a, 'b> RenderElement> for CosmicElement::draw(elem, glow_frame, src, dst, damage) - .map_err(|err| MultiError::Render(err)) + .map_err(|err| GlMultiError::Render(err)) }; elem } @@ -203,7 +214,11 @@ where CosmicMappedRenderElement: RenderElement, { fn from(elem: WorkspaceRenderElement) -> Self { - Self::Workspace(elem) + Self::Workspace(RelocateRenderElement::from_element( + elem, + (0, 0), + Relocate::Relative, + )) } } diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index e48e86c4..82dfa82c 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -3,22 +3,25 @@ use std::{ borrow::{Borrow, BorrowMut}, cell::RefCell, + collections::HashMap, + sync::Weak, + time::Instant, }; #[cfg(feature = "debug")] -use crate::{ - debug::{fps_ui, profiler_ui}, - utils::prelude::*, -}; +use crate::debug::{fps_ui, profiler_ui}; use crate::{ shell::{ - element::window::CosmicWindowRenderElement, layout::floating::SeatMoveGrabState, - CosmicMappedRenderElement, + focus::target::WindowGroup, grabs::SeatMoveGrabState, layout::tiling::ANIMATION_DURATION, + CosmicMapped, CosmicMappedRenderElement, OverviewMode, Trigger, WorkspaceRenderElement, }, - state::{Common, Fps}, - utils::prelude::SeatExt, + state::{Common, Fps, SessionLock}, + utils::prelude::*, wayland::{ - handlers::{data_device::get_dnd_icon, screencopy::render_session}, + handlers::{ + data_device::get_dnd_icon, + screencopy::{render_session, WORKSPACE_OVERVIEW_NAMESPACE}, + }, protocols::{ screencopy::{ BufferParams, CursorMode as ScreencopyCursorMode, Session as ScreencopySession, @@ -28,28 +31,37 @@ use crate::{ }, }; +use cosmic_comp_config::workspace::WorkspaceLayout; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::FailureReason; +use keyframe::{ease, functions::EaseInOutCubic}; use smithay::{ backend::{ allocator::dmabuf::Dmabuf, drm::DrmNode, renderer::{ buffer_dimensions, - damage::{Error as RenderError, OutputDamageTracker, OutputNoMode}, - element::{Element, RenderElement, RenderElementStates}, + damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult}, + element::{ + surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, + utils::{Relocate, RelocateRenderElement}, + Element, Id, Kind, RenderElement, + }, gles::{ element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform, UniformName, UniformType, }, glow::GlowRenderer, - multigpu::{gbm::GbmGlesBackend, MultiFrame, MultiRenderer}, + multigpu::{gbm::GbmGlesBackend, Error as MultiError, MultiFrame, MultiRenderer}, + sync::SyncPoint, Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter, }, }, - output::Output, - utils::{Logical, Physical, Point, Rectangle, Size}, + desktop::{layer_map_for_output, PopupManager}, + output::{Output, OutputNoMode}, + utils::{IsAlive, Logical, Point, Rectangle, Scale}, wayland::{ dmabuf::get_dmabuf, + shell::wlr_layer::Layer, shm::{shm_format_to_fourcc, with_buffer_contents}, }, }; @@ -64,13 +76,71 @@ pub type GlMultiRenderer<'a, 'b> = MultiRenderer<'a, 'a, 'b, GbmGlesBackend, GbmGlesBackend>; pub type GlMultiFrame<'a, 'b, 'frame> = MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend, GbmGlesBackend>; +pub type GlMultiError = MultiError, GbmGlesBackend>; pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0]; -pub static FOCUS_INDICATOR_COLOR: [f32; 4] = [0.580, 0.921, 0.921, 1.0]; -pub static FOCUS_INDICATOR_SHADER: &str = include_str!("./shaders/focus_indicator.frag"); +pub static OUTLINE_SHADER: &str = include_str!("./shaders/rounded_outline.frag"); +pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag"); pub struct IndicatorShader(pub GlesPixelProgram); -struct IndicatorElement(pub RefCell); + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum Usage { + OverviewBackdrop, + Overlay, + MoveGrabIndicator, + FocusIndicator, + PotentialGroupIndicator, +} + +#[derive(Clone)] +pub enum Key { + Static(Id), + Group(Weak<()>), + Window(Usage, CosmicMapped), +} +impl std::hash::Hash for Key { + fn hash(&self, state: &mut H) { + match self { + Key::Static(id) => id.hash(state), + Key::Group(arc) => (arc.as_ptr() as usize).hash(state), + Key::Window(usage, window) => { + usage.hash(state); + window.hash(state); + } + } + } +} +impl PartialEq for Key { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Key::Static(s1), Key::Static(s2)) => s1 == s2, + (Key::Group(g1), Key::Group(g2)) => Weak::ptr_eq(g1, g2), + (Key::Window(u1, w1), Key::Window(u2, w2)) => u1 == u2 && w1 == w2, + _ => false, + } + } +} +impl Eq for Key {} +impl From for Key { + fn from(group: WindowGroup) -> Self { + Key::Group(group.alive.clone()) + } +} +impl From for Key { + fn from(id: Id) -> Self { + Key::Static(id) + } +} + +#[derive(PartialEq)] +struct IndicatorSettings { + thickness: u8, + radius: u8, + alpha: f32, + color: [f32; 3], +} +type IndicatorCache = RefCell>; impl IndicatorShader { pub fn get(renderer: &R) -> GlesPixelProgram { @@ -83,52 +153,174 @@ impl IndicatorShader { .clone() } + pub fn focus_element( + renderer: &R, + key: impl Into, + mut element_geo: Rectangle, + thickness: u8, + scale: f64, + alpha: f32, + active_window_hint: [f32; 3], + ) -> PixelShaderElement { + let t = thickness as i32; + element_geo.loc -= (t, t).into(); + element_geo.size += (t * 2, t * 2).into(); + + IndicatorShader::element( + renderer, + key, + element_geo, + thickness, + thickness * 2, + alpha, + scale, + active_window_hint, + ) + } + pub fn element( renderer: &R, - geo: Rectangle, + key: impl Into, + geo: Rectangle, thickness: u8, + radius: u8, + alpha: f32, + scale: f64, + color: [f32; 3], ) -> PixelShaderElement { - let thickness: f32 = thickness as f32; - let thickness_loc = (thickness as i32, thickness as i32); - let thickness_size = ((thickness * 2.0) as i32, (thickness * 2.0) as i32); - let geo = Rectangle::from_loc_and_size( - geo.loc - Point::from(thickness_loc), - geo.size + Size::from(thickness_size), - ); + let thickness = (thickness as f64 * scale).round() as u8; + + let settings = IndicatorSettings { + thickness, + radius, + alpha, + color, + }; let user_data = Borrow::::borrow(renderer.glow_renderer()) .egl_context() .user_data(); - match user_data.get::() { - Some(elem) => { - let mut elem = elem.0.borrow_mut(); - if elem.geometry(1.0.into()).to_logical(1) != geo { - elem.resize(geo, None); - } - elem.clone() - } - None => { - let shader = Self::get(renderer); - let color = FOCUS_INDICATOR_COLOR; - - let elem = PixelShaderElement::new( - shader, - dbg!(geo), - None, //TODO - color[3], - vec![ - Uniform::new("color", [color[0], color[1], color[2]]), - Uniform::new("thickness", thickness), - Uniform::new("radius", thickness * 2.0), - ], - ); - if !user_data.insert_if_missing(|| IndicatorElement(RefCell::new(elem.clone()))) { - *user_data.get::().unwrap().0.borrow_mut() = elem.clone(); - } - elem - } + user_data.insert_if_missing(|| IndicatorCache::new(HashMap::new())); + let mut cache = user_data.get::().unwrap().borrow_mut(); + cache.retain(|k, _| match k { + Key::Static(_) => true, + Key::Group(w) => w.upgrade().is_some(), + Key::Window(_, w) => w.alive(), + }); + + let key = key.into(); + if cache + .get(&key) + .filter(|(old_settings, _)| &settings == old_settings) + .is_none() + { + let thickness: f32 = thickness as f32; + let shader = Self::get(renderer); + + let elem = PixelShaderElement::new( + shader, + geo.as_logical(), + None, //TODO + alpha, + vec![ + Uniform::new( + "color", + [color[0] * alpha, color[1] * alpha, color[2] * alpha], + ), + Uniform::new("thickness", thickness), + Uniform::new("radius", radius as f32), + ], + Kind::Unspecified, + ); + cache.insert(key.clone(), (settings, elem)); + } + + let elem = &mut cache.get_mut(&key).unwrap().1; + if elem.geometry(1.0.into()).to_logical(1) != geo.as_logical() { + elem.resize(geo.as_logical(), None); } + elem.clone() + } +} + +pub struct BackdropShader(pub GlesPixelProgram); + +#[derive(PartialEq)] +struct BackdropSettings { + radius: f32, + alpha: f32, + color: [f32; 3], +} +type BackdropCache = RefCell>; + +impl BackdropShader { + pub fn get(renderer: &R) -> GlesPixelProgram { + Borrow::::borrow(renderer.glow_renderer()) + .egl_context() + .user_data() + .get::() + .expect("Custom Shaders not initialized") + .0 + .clone() + } + + pub fn element( + renderer: &R, + key: impl Into, + geo: Rectangle, + radius: f32, + alpha: f32, + color: [f32; 3], + ) -> PixelShaderElement { + let settings = BackdropSettings { + radius, + alpha, + color, + }; + + let user_data = Borrow::::borrow(renderer.glow_renderer()) + .egl_context() + .user_data(); + + user_data.insert_if_missing(|| BackdropCache::new(HashMap::new())); + let mut cache = user_data.get::().unwrap().borrow_mut(); + cache.retain(|k, _| match k { + Key::Static(_) => true, + Key::Group(a) => a.upgrade().is_some(), + Key::Window(_, w) => w.alive(), + }); + + let key = key.into(); + if cache + .get(&key) + .filter(|(old_settings, _)| &settings == old_settings) + .is_none() + { + let shader = Self::get(renderer); + + let elem = PixelShaderElement::new( + shader, + geo.as_logical(), + None, // TODO + alpha, + vec![ + Uniform::new( + "color", + [color[0] * alpha, color[1] * alpha, color[2] * alpha], + ), + Uniform::new("radius", radius), + ], + Kind::Unspecified, + ); + cache.insert(key.clone(), (settings, elem)); + } + + let elem = &mut cache.get_mut(&key).unwrap().1; + if elem.geometry(1.0.into()).to_logical(1) != geo.as_logical() { + elem.resize(geo.as_logical(), None); + } + elem.clone() } } @@ -136,19 +328,29 @@ pub fn init_shaders(renderer: &mut R) -> Result<(), GlesError let glow_renderer = renderer.glow_renderer_mut(); let gles_renderer: &mut GlesRenderer = glow_renderer.borrow_mut(); - let indicator_shader = gles_renderer.compile_custom_pixel_shader( - FOCUS_INDICATOR_SHADER, + let outline_shader = gles_renderer.compile_custom_pixel_shader( + OUTLINE_SHADER, &[ UniformName::new("color", UniformType::_3f), UniformName::new("thickness", UniformType::_1f), UniformName::new("radius", UniformType::_1f), ], )?; + let rectangle_shader = gles_renderer.compile_custom_pixel_shader( + RECTANGLE_SHADER, + &[ + UniformName::new("color", UniformType::_3f), + UniformName::new("radius", UniformType::_1f), + ], + )?; let egl_context = gles_renderer.egl_context(); egl_context .user_data() - .insert_if_missing(|| IndicatorShader(indicator_shader)); + .insert_if_missing(|| IndicatorShader(outline_shader)); + egl_context + .user_data() + .insert_if_missing(|| BackdropShader(rectangle_shader)); Ok(()) } @@ -170,7 +372,6 @@ where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Clone + 'static, CosmicMappedRenderElement: RenderElement, - CosmicWindowRenderElement: RenderElement, E: From> + From>, { #[cfg(feature = "debug")] @@ -209,13 +410,14 @@ where ); } + let theme = state.theme.cosmic(); if let Some(grab_elements) = seat .user_data() .get::() .unwrap() .borrow() .as_ref() - .map(|state| state.render::(renderer, seat, output)) + .map(|state| state.render::(renderer, seat, output, theme)) { elements.extend(grab_elements); } @@ -229,7 +431,8 @@ pub fn workspace_elements( renderer: &mut R, state: &mut Common, output: &Output, - handle: &WorkspaceHandle, + previous: Option<(WorkspaceHandle, usize, Instant)>, + current: (WorkspaceHandle, usize), cursor_mode: CursorMode, _fps: &mut Option<&mut Fps>, exclude_workspace_overview: bool, @@ -239,7 +442,7 @@ where ::TextureId: Clone + 'static, ::Error: From, CosmicMappedRenderElement: RenderElement, - CosmicWindowRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, { #[cfg(feature = "debug")] puffin::profile_function!(); @@ -268,11 +471,11 @@ where elements.push(fps_overlay.into()); } - if state.shell.outputs.first() == Some(output) { + if state.shell.outputs().next() == Some(output) { if let Some(profiler_overlay) = profiler_ui( state, renderer.glow_renderer_mut(), - Rectangle::from_loc_and_size((0, 0), output_geo.size), + Rectangle::from_loc_and_size((0, 0), output_geo.size).as_logical(), scale, ) .map_err(::Error::from) @@ -283,7 +486,38 @@ where } } - let workspace = state.shell.space_for_handle(&handle).ok_or(OutputNoMode)?; + // If session locked, only show session lock surfaces + if let Some(session_lock) = &state.session_lock { + elements.extend( + session_lock_elements(renderer, output, session_lock) + .into_iter() + .map(|x| WorkspaceRenderElement::from(x).into()), + ); + return Ok(elements); + } + + let theme = state.theme.cosmic(); + + let overview = state.shell.overview_mode(); + let (resize_mode, resize_indicator) = state.shell.resize_mode(); + let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator)); + let swap_tree = if let OverviewMode::Started(Trigger::KeyboardSwap(_, desc), _) = &overview.0 { + if current.0 != desc.handle { + state + .shell + .space_for_handle(&desc.handle) + .map(|w| w.tiling_layer.tree()) + } else { + None + } + } else { + None + }; + let overview = ( + overview.0, + overview.1.map(|indicator| (indicator, swap_tree)), + ); + let last_active_seat = state.last_active_seat().clone(); let move_active = last_active_seat .user_data() @@ -292,28 +526,299 @@ where .borrow() .is_some(); let active_output = last_active_seat.active_output(); + let output_size = output.geometry().size; + let output_scale = output.current_scale().fractional_scale(); + + let workspace = state + .shell + .space_for_handle(¤t.0) + .ok_or(OutputNoMode)?; + + let has_fullscreen = workspace + .fullscreen + .as_ref() + .filter(|f| !f.is_animating()) + .is_some(); + let (overlay_elements, overlay_popups) = + split_layer_elements(renderer, output, Layer::Overlay, exclude_workspace_overview); + + // overlay is above everything + elements.extend(overlay_popups.into_iter().map(Into::into)); + elements.extend(overlay_elements.into_iter().map(Into::into)); + + let mut window_elements = if !has_fullscreen { + let (top_elements, top_popups) = + split_layer_elements(renderer, output, Layer::Top, exclude_workspace_overview); + elements.extend(top_popups.into_iter().map(Into::into)); + top_elements.into_iter().map(Into::into).collect() + } else { + Vec::new() + }; + let active_hint = theme.active_hint as u8; + + let offset = match previous.as_ref() { + Some((previous, previous_idx, start)) => { + let layout = state.config.workspace.workspace_layout; + + let workspace = state + .shell + .space_for_handle(&previous) + .ok_or(OutputNoMode)?; + let has_fullscreen = workspace.fullscreen.is_some(); + let is_active_space = workspace.outputs().any(|o| o == &active_output); + + let percentage = { + let percentage = Instant::now().duration_since(*start).as_millis() as f32 + / ANIMATION_DURATION.as_millis() as f32; + ease(EaseInOutCubic, 0.0, 1.0, percentage) + }; + let offset = Point::::from(match (layout, *previous_idx < current.1) { + (WorkspaceLayout::Vertical, true) => { + (0, (-output_size.h as f32 * percentage).round() as i32) + } + (WorkspaceLayout::Vertical, false) => { + (0, (output_size.h as f32 * percentage).round() as i32) + } + (WorkspaceLayout::Horizontal, true) => { + ((-output_size.w as f32 * percentage).round() as i32, 0) + } + (WorkspaceLayout::Horizontal, false) => { + ((output_size.w as f32 * percentage).round() as i32, 0) + } + }); + + let (w_elements, p_elements) = workspace + .render::( + renderer, + &state.shell.override_redirect_windows, + state.xwayland_state.as_mut(), + (!move_active && is_active_space).then_some(&last_active_seat), + overview.clone(), + resize_indicator.clone(), + active_hint, + theme, + ) + .map_err(|_| OutputNoMode)?; + elements.extend(p_elements.into_iter().map(|p_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + p_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + window_elements.extend(w_elements.into_iter().map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + + if !has_fullscreen { + let (w_elements, p_elements) = + background_layer_elements(renderer, output, exclude_workspace_overview); + elements.extend(p_elements.into_iter().map(|p_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + p_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + window_elements.extend(w_elements.into_iter().map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + } + + Point::::from(match (layout, *previous_idx < current.1) { + (WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y), + (WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)), + (WorkspaceLayout::Horizontal, true) => (output_size.w + offset.x, 0), + (WorkspaceLayout::Horizontal, false) => (-(output_size.w - offset.y), 0), + }) + } + None => (0, 0).into(), + }; + let is_active_space = workspace.outputs().any(|o| o == &active_output); - elements.extend( - workspace - .render_output::( + let (w_elements, p_elements) = workspace + .render::( + renderer, + &state.shell.override_redirect_windows, + state.xwayland_state.as_mut(), + (!move_active && is_active_space).then_some(&last_active_seat), + overview, + resize_indicator, + active_hint, + theme, + ) + .map_err(|_| OutputNoMode)?; + elements.extend(p_elements.into_iter().map(|p_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + p_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + window_elements.extend(w_elements.into_iter().map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + + if !has_fullscreen { + let (w_elements, p_elements) = + background_layer_elements(renderer, output, exclude_workspace_overview); + + elements.extend(p_elements.into_iter().map(|p_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + p_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + + window_elements.extend(w_elements.into_iter().map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + })); + } + + elements.extend(window_elements); + + Ok(elements) +} + +pub fn split_layer_elements( + renderer: &mut R, + output: &Output, + layer: Layer, + exclude_workspace_overview: bool, +) -> ( + Vec>, + Vec>, +) +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Clone + 'static, + ::Error: From, + CosmicMappedRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, +{ + let layer_map = layer_map_for_output(output); + let output_scale = output.current_scale().fractional_scale(); + + let mut popup_elements = Vec::new(); + let mut layer_elements = Vec::new(); + + layer_map + .layers_on(layer) + .rev() + .filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE)) + .filter_map(|surface| { + layer_map + .layer_geometry(surface) + .map(|geo| (geo.loc, surface)) + }) + .for_each(|(location, surface)| { + let location = location.to_physical_precise_round(output_scale); + let surface = surface.wl_surface(); + let scale = Scale::from(output_scale); + + popup_elements.extend(PopupManager::popups_for_surface(surface).flat_map( + |(popup, popup_offset)| { + let offset = (popup_offset - popup.geometry().loc) + .to_f64() + .to_physical(scale) + .to_i32_round(); + + render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + location + offset, + scale, + 1.0, + Kind::Unspecified, + ) + }, + )); + + layer_elements.extend(render_elements_from_surface_tree( renderer, - output, - &state.shell.override_redirect_windows, - state.xwayland_state.as_mut(), - (!move_active && is_active_space).then_some(&last_active_seat), - state.config.static_conf.active_hint, - exclude_workspace_overview, - ) - .map_err(|_| OutputNoMode)? - .into_iter() - .map(Into::into), + surface, + location, + scale, + 1.0, + Kind::Unspecified, + )); + }); + + (layer_elements, popup_elements) +} + +// bottom and background layer surfaces +pub fn background_layer_elements( + renderer: &mut R, + output: &Output, + exclude_workspace_overview: bool, +) -> ( + Vec>, + Vec>, +) +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Clone + 'static, + ::Error: From, + CosmicMappedRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, +{ + let (mut layer_elements, mut popup_elements) = + split_layer_elements(renderer, output, Layer::Bottom, exclude_workspace_overview); + let more = split_layer_elements( + renderer, + output, + Layer::Background, + exclude_workspace_overview, ); + layer_elements.extend(more.0); + popup_elements.extend(more.1); + (layer_elements, popup_elements) +} - Ok(elements) +fn session_lock_elements( + renderer: &mut R, + output: &Output, + session_lock: &SessionLock, +) -> Vec> +where + R: Renderer + ImportAll, + ::TextureId: Clone + 'static, +{ + if let Some(surface) = session_lock.surfaces.get(output) { + let scale = Scale::from(output.current_scale().fractional_scale()); + render_elements_from_surface_tree( + renderer, + surface.wl_surface(), + (0, 0), + scale, + 1.0, + Kind::Unspecified, + ) + } else { + Vec::new() + } } -pub fn render_output<'frame, R, Target, OffTarget, Source>( +pub fn render_output( gpu: Option<&DrmNode>, renderer: &mut R, target: Target, @@ -324,7 +829,7 @@ pub fn render_output<'frame, R, Target, OffTarget, Source>( cursor_mode: CursorMode, screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>, fps: Option<&mut Fps>, -) -> Result<(Option>>, RenderElementStates), RenderError> +) -> Result> where R: Renderer + ImportAll @@ -339,10 +844,16 @@ where ::Error: From, CosmicElement: RenderElement, CosmicMappedRenderElement: RenderElement, - CosmicWindowRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, Source: Clone, { - let handle = state.shell.workspaces.active(output).handle; + let (previous_workspace, workspace) = state.shell.workspaces.active(output); + let (previous_idx, idx) = state.shell.workspaces.active_num(output); + let previous_workspace = previous_workspace + .zip(previous_idx) + .map(|((w, start), idx)| (w.handle, idx, start)); + let workspace = (workspace.handle, idx); + let result = render_workspace( gpu, renderer, @@ -351,7 +862,8 @@ where age, state, output, - &handle, + previous_workspace, + workspace, cursor_mode, screencopy, fps, @@ -361,7 +873,7 @@ where result } -pub fn render_workspace<'frame, R, Target, OffTarget, Source>( +pub fn render_workspace( gpu: Option<&DrmNode>, renderer: &mut R, target: Target, @@ -369,12 +881,13 @@ pub fn render_workspace<'frame, R, Target, OffTarget, Source>( age: usize, state: &mut Common, output: &Output, - handle: &WorkspaceHandle, + previous: Option<(WorkspaceHandle, usize, Instant)>, + current: (WorkspaceHandle, usize), mut cursor_mode: CursorMode, screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>, mut fps: Option<&mut Fps>, exclude_workspace_overview: bool, -) -> Result<(Option>>, RenderElementStates), RenderError> +) -> Result> where R: Renderer + ImportAll @@ -389,7 +902,7 @@ where ::Error: From, CosmicElement: RenderElement, CosmicMappedRenderElement: RenderElement, - CosmicWindowRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, Source: Clone, { #[cfg(feature = "debug")] @@ -426,7 +939,8 @@ where renderer, state, output, - handle, + previous, + current, cursor_mode, &mut fps, exclude_workspace_overview, @@ -436,7 +950,12 @@ where } renderer.bind(target).map_err(RenderError::Rendering)?; - let res = damage_tracker.render_output(renderer, age, &elements, CLEAR_COLOR); + let res = damage_tracker.render_output( + renderer, + age, + &elements, + CLEAR_COLOR, // TODO use a theme neutral color + ); if let Some(fps) = fps.as_mut() { fps.render(); @@ -477,7 +996,11 @@ where } } - Ok(res) + Ok(RenderOutputResult { + damage: res.0, + sync: SyncPoint::default(), + states: res.1, + }) }, ) { Ok(true) => {} // success diff --git a/src/backend/render/shaders/focus_indicator.frag b/src/backend/render/shaders/rounded_outline.frag similarity index 76% rename from src/backend/render/shaders/focus_indicator.frag rename to src/backend/render/shaders/rounded_outline.frag index cebaf8db..749748f2 100644 --- a/src/backend/render/shaders/focus_indicator.frag +++ b/src/backend/render/shaders/rounded_outline.frag @@ -15,12 +15,12 @@ float rounded_box(vec2 center, vec2 size, float radius) { } void main() { - vec2 center = size / 2.0 - vec2(0.5); + vec2 center = size / 2.0; vec2 location = v_coords * size; vec4 mix_color; - float distance = rounded_box(location - center, size / 2.0 - vec2(thickness / 2.0), radius); - float smoothedAlpha = 1.0 - smoothstep(0.0, 2.0, abs(distance) - (thickness / 2.0)); + float distance = rounded_box(location - center, (size / 2.0) - (thickness / 2.0), radius); + float smoothedAlpha = 1.0 - smoothstep(0.0, 1.0, abs(distance) - (thickness / 2.0)); mix_color = mix(vec4(0.0, 0.0, 0.0, 0.0), vec4(color, alpha), smoothedAlpha); diff --git a/src/backend/render/shaders/rounded_rectangle.frag b/src/backend/render/shaders/rounded_rectangle.frag new file mode 100644 index 00000000..30644f51 --- /dev/null +++ b/src/backend/render/shaders/rounded_rectangle.frag @@ -0,0 +1,32 @@ +precision mediump float; +uniform float alpha; +#if defined(DEBUG_FLAGS) +uniform float tint; +#endif +uniform vec2 size; +varying vec2 v_coords; + +uniform vec3 color; +uniform float radius; + +float rounded_box(vec2 center, vec2 size, float radius) { + return length(max(abs(center) - size + radius, 0.0)) - radius; +} + +void main() { + vec2 center = size / 2.0; + vec2 location = v_coords * size; + vec4 mix_color; + + float distance = rounded_box(location - center, size / 2.0, radius); + float smoothedAlpha = 1.0 - smoothstep(0.0, 1.0, distance); + + mix_color = mix(vec4(0.0, 0.0, 0.0, 0.0), vec4(color, alpha), smoothedAlpha); + +#if defined(DEBUG_FLAGS) + if (tint == 1.0) + mix_color = vec4(0.0, 0.3, 0.0, 0.2) + mix_color * 0.8; +#endif + + gl_FragColor = mix_color; +} \ No newline at end of file diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 3bec32f6..29432f4c 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -4,7 +4,7 @@ use crate::{ backend::render, config::OutputConfig, input::Devices, - state::{BackendData, Common, Data}, + state::{BackendData, Common}, utils::prelude::*, wayland::protocols::screencopy::{BufferParams, Session as ScreencopySession}, }; @@ -13,8 +13,10 @@ use smithay::{ backend::{ egl::EGLDevice, renderer::{ - damage::OutputDamageTracker, gles::GlesRenderbuffer, glow::GlowRenderer, ImportDma, - ImportEgl, + damage::{OutputDamageTracker, RenderOutputResult}, + gles::GlesRenderbuffer, + glow::GlowRenderer, + ImportDma, ImportEgl, }, winit::{self, WinitEvent, WinitGraphicsBackend, WinitVirtualDevice}, }, @@ -24,11 +26,12 @@ use smithay::{ calloop::{ping, EventLoop}, wayland_protocols::wp::presentation_time::server::wp_presentation_feedback, wayland_server::DisplayHandle, + winit::platform::pump_events::PumpStatus, }, utils::Transform, wayland::dmabuf::DmabufFeedbackBuilder, }; -use std::cell::RefCell; +use std::{cell::RefCell, time::Duration}; use tracing::{error, info, warn}; #[cfg(feature = "debug")] @@ -36,6 +39,7 @@ use crate::state::Fps; use super::render::{init_shaders, CursorMode}; +#[derive(Debug)] pub struct WinitState { // The winit backend currently has no notion of multiple windows pub backend: WinitGraphicsBackend, @@ -73,7 +77,7 @@ impl WinitState { #[cfg(feature = "debug")] Some(&mut self.fps), ) { - Ok((damage, states)) => { + Ok(RenderOutputResult { damage, states, .. }) => { self.backend .bind() .with_context(|| "Failed to bind display")?; @@ -91,11 +95,11 @@ impl WinitState { state.clock.now(), self.output .current_mode() - .map(|mode| mode.refresh as u32) + .map(|mode| Duration::from_secs_f64(1_000.0 / mode.refresh as f64)) .unwrap_or_default(), 0, wp_presentation_feedback::Kind::Vsync, - ) + ); } } Err(err) => { @@ -122,12 +126,9 @@ impl WinitState { .get::>() .unwrap() .borrow_mut(); - if dbg!(config.mode.0) != dbg!((size.physical_size.w as i32, size.physical_size.h as i32)) { + if dbg!(config.mode.0) != dbg!((size.w as i32, size.h as i32)) { if !test_only { - config.mode = ( - (size.physical_size.w as i32, size.physical_size.h as i32), - None, - ); + config.mode = ((size.w as i32, size.h as i32), None); } Err(anyhow::anyhow!("Cannot set window size")) } else { @@ -144,7 +145,7 @@ impl WinitState { pub fn init_backend( dh: &DisplayHandle, - event_loop: &mut EventLoop, + event_loop: &mut EventLoop, state: &mut State, ) -> Result<()> { let (mut backend, mut input) = @@ -162,7 +163,7 @@ pub fn init_backend( model: name.clone(), }; let mode = Mode { - size: (size.physical_size.w as i32, size.physical_size.h as i32).into(), + size: (size.w as i32, size.h as i32).into(), refresh: 60_000, }; let output = Output::new(name, props); @@ -176,10 +177,7 @@ pub fn init_backend( ); output.user_data().insert_if_missing(|| { RefCell::new(OutputConfig { - mode: ( - (size.physical_size.w as i32, size.physical_size.h as i32), - None, - ), + mode: ((size.w as i32, size.h as i32), None), transform: Transform::Flipped180.into(), ..Default::default() }) @@ -194,13 +192,8 @@ pub fn init_backend( let mut token = Some( event_loop .handle() - .insert_source(render_source, move |_, _, data| { - if let Err(err) = data - .state - .backend - .winit() - .render_output(&mut data.state.common) - { + .insert_source(render_source, move |_, _, state| { + if let Err(err) = state.backend.winit().render_output(&mut state.common) { error!(?err, "Failed to render frame."); render_ping.ping(); } @@ -210,21 +203,18 @@ pub fn init_backend( let event_loop_handle = event_loop.handle(); event_loop .handle() - .insert_source(event_source, move |_, _, data| { - match input.dispatch_new_events(|event| { - data.state.process_winit_event(event, &render_ping_handle) - }) { - Ok(_) => { + .insert_source(event_source, move |_, _, state| { + match input + .dispatch_new_events(|event| state.process_winit_event(event, &render_ping_handle)) + { + PumpStatus::Continue => { event_ping_handle.ping(); render_ping_handle.ping(); } - Err(winit::WinitError::WindowClosed) => { - let output = data.state.backend.winit().output.clone(); - let seats = data.state.common.seats().cloned().collect::>(); - data.state - .common - .shell - .remove_output(&output, seats.into_iter()); + PumpStatus::Exit(_) => { + let output = state.backend.winit().output.clone(); + let seats = state.common.seats().cloned().collect::>(); + state.common.shell.remove_output(&output, seats.into_iter()); if let Some(token) = token.take() { event_loop_handle.remove(token); } @@ -354,11 +344,10 @@ impl State { output.change_current_state(Some(mode), None, None, None); layer_map_for_output(output).arrange(); self.common.output_configuration_state.update(); - self.common.shell.refresh_outputs(); render_ping.ping(); } - WinitEvent::Refresh => render_ping.ping(), - WinitEvent::Input(event) => self.process_input_event(event), + WinitEvent::Redraw => render_ping.ping(), + WinitEvent::Input(event) => self.process_input_event(event, false), _ => {} }; } diff --git a/src/backend/x11.rs b/src/backend/x11.rs index e63afe26..49dabcd4 100644 --- a/src/backend/x11.rs +++ b/src/backend/x11.rs @@ -4,7 +4,7 @@ use crate::{ backend::render, config::OutputConfig, input::Devices, - state::{BackendData, Common, Data}, + state::{BackendData, Common}, utils::prelude::*, wayland::protocols::screencopy::{BufferParams, Session as ScreencopySession}, }; @@ -20,8 +20,10 @@ use smithay::{ egl::{EGLContext, EGLDevice, EGLDisplay}, input::{Event, InputEvent}, renderer::{ - damage::OutputDamageTracker, gles::GlesRenderbuffer, glow::GlowRenderer, Bind, - ImportDma, ImportEgl, + damage::{OutputDamageTracker, RenderOutputResult}, + gles::GlesRenderbuffer, + glow::GlowRenderer, + Bind, ImportDma, ImportEgl, }, vulkan::{version::Version, Instance, PhysicalDevice}, x11::{Window, WindowBuilder, X11Backend, X11Event, X11Handle, X11Input, X11Surface}, @@ -37,7 +39,7 @@ use smithay::{ utils::{DeviceFd, Transform}, wayland::dmabuf::DmabufFeedbackBuilder, }; -use std::{cell::RefCell, os::unix::io::OwnedFd}; +use std::{cell::RefCell, os::unix::io::OwnedFd, time::Duration}; use tracing::{debug, error, info, warn}; #[cfg(feature = "debug")] @@ -45,11 +47,13 @@ use crate::state::Fps; use super::render::init_shaders; +#[derive(Debug)] enum Allocator { Gbm(GbmAllocator), Vulkan(PhysicalDevice), } +#[derive(Debug)] pub struct X11State { allocator: Allocator, _egl: EGLDisplay, @@ -59,7 +63,7 @@ pub struct X11State { } impl X11State { - pub fn add_window(&mut self, handle: LoopHandle<'_, Data>) -> Result { + pub fn add_window(&mut self, handle: LoopHandle<'_, State>) -> Result { let window = WindowBuilder::new() .title("COSMIC") .build(&self.handle) @@ -120,15 +124,15 @@ impl X11State { let (ping, source) = ping::make_ping().with_context(|| "Failed to create output event loop source")?; let _token = handle - .insert_source(source, move |_, _, data| { - let x11_state = data.state.backend.x11(); + .insert_source(source, move |_, _, state| { + let x11_state = state.backend.x11(); if let Some(surface) = x11_state .surfaces .iter_mut() .find(|s| s.output == output_ref) { if let Err(err) = - surface.render_output(&mut x11_state.renderer, &mut data.state.common) + surface.render_output(&mut x11_state.renderer, &mut state.common) { error!(?err, "Error rendering."); } @@ -202,6 +206,7 @@ impl X11State { } } +#[derive(Debug)] pub struct Surface { window: Window, damage_tracker: OutputDamageTracker, @@ -240,7 +245,7 @@ impl Surface { #[cfg(feature = "debug")] Some(&mut self.fps), ) { - Ok((damage, states)) => { + Ok(RenderOutputResult { damage, states, .. }) => { self.screencopy.clear(); self.surface .submit() @@ -255,7 +260,7 @@ impl Surface { state.clock.now(), self.output .current_mode() - .map(|mode| mode.refresh as u32) + .map(|mode| Duration::from_secs_f64(1_000.0 / mode.refresh as f64)) .unwrap_or_default(), 0, wp_presentation_feedback::Kind::Vsync, @@ -328,7 +333,7 @@ fn try_gbm_allocator(fd: OwnedFd) -> Option { pub fn init_backend( dh: &DisplayHandle, - event_loop: &mut EventLoop, + event_loop: &mut EventLoop, state: &mut State, ) -> Result<()> { let backend = X11Backend::new().with_context(|| "Failed to initilize X11 backend")?; @@ -386,12 +391,11 @@ pub fn init_backend( event_loop .handle() - .insert_source(backend, move |event, _, data| match event { + .insert_source(backend, move |event, _, state| match event { X11Event::CloseRequested { window_id } => { // TODO: drain_filter let mut outputs_removed = Vec::new(); - for surface in data - .state + for surface in state .backend .x11() .surfaces @@ -401,13 +405,13 @@ pub fn init_backend( surface.window.unmap(); outputs_removed.push(surface.output.clone()); } - data.state + state .backend .x11() .surfaces .retain(|s| s.window.id() != window_id); for output in outputs_removed.into_iter() { - data.state + state .common .shell .remove_output(&output, seats.iter().cloned()); @@ -422,8 +426,7 @@ pub fn init_backend( size, refresh: 60_000, }; - if let Some(surface) = data - .state + if let Some(surface) = state .backend .x11() .surfaces @@ -444,8 +447,7 @@ pub fn init_backend( output.change_current_state(Some(mode), None, None, None); output.set_preferred(mode); layer_map_for_output(output).arrange(); - data.state.common.output_configuration_state.update(); - data.state.common.shell.refresh_outputs(); + state.common.output_configuration_state.update(); surface.dirty = true; if !surface.pending { surface.render.ping(); @@ -453,8 +455,7 @@ pub fn init_backend( } } X11Event::Refresh { window_id } | X11Event::PresentCompleted { window_id } => { - if let Some(surface) = data - .state + if let Some(surface) = state .backend .x11() .surfaces @@ -468,7 +469,7 @@ pub fn init_backend( } } } - X11Event::Input(event) => data.state.process_x11_event(event), + X11Event::Input(event) => state.process_x11_event(event), }) .map_err(|_| anyhow::anyhow!("Failed to insert X11 Backend into event loop"))?; @@ -533,7 +534,7 @@ impl State { _ => {} }; - self.process_input_event(event); + self.process_input_event(event, false); // TODO actually figure out the output for output in self.common.shell.outputs() { self.backend.x11().schedule_render(output, None); diff --git a/src/config/input_config.rs b/src/config/input_config.rs new file mode 100644 index 00000000..063e80cf --- /dev/null +++ b/src/config/input_config.rs @@ -0,0 +1,218 @@ +use smithay::reexports::input::{ + Device as InputDevice, DeviceConfigError, ScrollMethod, SendEventsMode, +}; +use tracing::warn; + +use cosmic_comp_config::input::*; + +#[allow(dead_code)] +pub fn for_device(device: &InputDevice) -> InputConfig { + InputConfig { + state: match device.config_send_events_mode() { + x if x.contains(SendEventsMode::ENABLED) => DeviceState::Enabled, + x if x.contains(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE) => { + DeviceState::DisabledOnExternalMouse + } + x if x.contains(SendEventsMode::DISABLED) => DeviceState::Disabled, + _ => DeviceState::Disabled, + }, + acceleration: if device.config_accel_is_available() { + Some(AccelConfig { + profile: device.config_accel_profile(), + speed: device.config_accel_speed(), + }) + } else { + None + }, + calibration: device.config_calibration_matrix(), + click_method: device.config_click_method(), + disable_while_typing: if device.config_dwt_is_available() { + Some(device.config_dwt_enabled()) + } else { + None + }, + left_handed: if device.config_left_handed_is_available() { + Some(device.config_left_handed()) + } else { + None + }, + middle_button_emulation: if device.config_middle_emulation_is_available() { + Some(device.config_middle_emulation_enabled()) + } else { + None + }, + rotation_angle: if device.config_rotation_is_available() { + Some(device.config_rotation_angle()) + } else { + None + }, + scroll_config: if device + .config_scroll_methods() + .iter() + .any(|x| *x != ScrollMethod::NoScroll) + { + Some(ScrollConfig { + method: device.config_scroll_method(), + natural_scroll: if device.config_scroll_has_natural_scroll() { + Some(device.config_scroll_natural_scroll_enabled()) + } else { + None + }, + scroll_button: if device.config_scroll_method() == Some(ScrollMethod::OnButtonDown) + { + Some(device.config_scroll_button()) + } else { + None + }, + scroll_factor: None, + }) + } else { + None + }, + tap_config: if device.config_tap_finger_count() > 0 { + Some(TapConfig { + enabled: device.config_tap_enabled(), + button_map: device.config_tap_button_map(), + drag: device.config_tap_drag_enabled(), + drag_lock: device.config_tap_drag_lock_enabled(), + }) + } else { + None + }, + } +} + +// Get setting from `device_config` if present, then `default_config` +// Returns `is_default` to indicate this is a default value. +pub fn get_config<'a, T: 'a, F: Fn(&'a InputConfig) -> Option>( + device_config: Option<&'a InputConfig>, + default_config: &'a InputConfig, + f: F, +) -> Option<(T, bool)> { + if let Some(setting) = device_config.and_then(&f) { + Some((setting, false)) + } else if let Some(setting) = f(default_config) { + Some((setting, true)) + } else { + None + } +} + +fn config_set_error( + device: &InputDevice, + setting: &str, + value: T, + err: DeviceConfigError, + is_default: bool, +) { + if !(is_default && err == DeviceConfigError::Unsupported) { + warn!( + ?err, + "Failed to apply {} {:?} for device {:?}.", + setting, + value, + device.name(), + ); + } +} + +pub fn update_device( + device: &mut InputDevice, + device_config: Option<&InputConfig>, + default_config: &InputConfig, +) { + macro_rules! config { + ($f:expr) => { + get_config(device_config, default_config, $f) + }; + } + + let state = device_config.unwrap_or(default_config).state; + if let Err(err) = match state { + DeviceState::Enabled => device.config_send_events_set_mode(SendEventsMode::ENABLED), + DeviceState::Disabled => device.config_send_events_set_mode(SendEventsMode::DISABLED), + DeviceState::DisabledOnExternalMouse => { + device.config_send_events_set_mode(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE) + } + } { + warn!( + ?err, + "Failed to apply mode {:?} for device {:?}.", + state, + device.name(), + ); + } + if let Some((accel, is_default)) = config!(|x| x.acceleration.as_ref()) { + if let Some(profile) = accel.profile { + if let Err(err) = device.config_accel_set_profile(profile) { + config_set_error(device, "acceleration profile", profile, err, is_default); + } + } + if let Err(err) = device.config_accel_set_speed(accel.speed) { + config_set_error(device, "acceleration speed", accel.speed, err, is_default); + } + } + if let Some((matrix, is_default)) = config!(|x| x.calibration) { + if let Err(err) = device.config_calibration_set_matrix(matrix) { + config_set_error(device, "calibration matrix", matrix, err, is_default); + } + } + if let Some((method, is_default)) = config!(|x| x.click_method) { + if let Err(err) = device.config_click_set_method(method) { + config_set_error(device, "click method", method, err, is_default); + } + } + if let Some((dwt, is_default)) = config!(|x| x.disable_while_typing) { + if let Err(err) = device.config_dwt_set_enabled(dwt) { + config_set_error(device, "disable-while-typing", dwt, err, is_default); + } + } + if let Some((left, is_default)) = config!(|x| x.left_handed) { + if let Err(err) = device.config_left_handed_set(left) { + config_set_error(device, "left-handed", left, err, is_default); + } + } + if let Some((middle, is_default)) = config!(|x| x.middle_button_emulation) { + if let Err(err) = device.config_middle_emulation_set_enabled(middle) { + config_set_error(device, "middle-button-emulation", middle, err, is_default); + } + } + if let Some((angle, is_default)) = config!(|x| x.rotation_angle) { + if let Err(err) = device.config_rotation_set_angle(angle) { + config_set_error(device, "rotation-angle", angle, err, is_default); + } + } + if let Some((scroll, is_default)) = config!(|x| x.scroll_config.as_ref()) { + if let Some(method) = scroll.method { + if let Err(err) = device.config_scroll_set_method(method) { + config_set_error(device, "scroll method", scroll, err, is_default); + } + } + if let Some(natural) = scroll.natural_scroll { + if let Err(err) = device.config_scroll_set_natural_scroll_enabled(natural) { + config_set_error(device, "natural scrolling", natural, err, is_default); + } + } + if let Some(button) = scroll.scroll_button { + if let Err(err) = device.config_scroll_set_button(button) { + config_set_error(device, "scroll button", button, err, is_default); + } + } + } + if let Some((tap, is_default)) = config!(|x| x.tap_config.as_ref()) { + if let Err(err) = device.config_tap_set_enabled(tap.enabled) { + config_set_error(device, "tap-to-click", tap.enabled, err, is_default); + } + if let Some(button_map) = tap.button_map { + if let Err(err) = device.config_tap_set_button_map(button_map) { + config_set_error(device, "button map", button_map, err, is_default); + } + } + if let Err(err) = device.config_tap_set_drag_enabled(tap.drag) { + config_set_error(device, "tap-drag", tap.drag, err, is_default); + } + if let Err(err) = device.config_tap_set_drag_lock_enabled(tap.drag_lock) { + config_set_error(device, "tap-drag-lock", tap.drag_lock, err, is_default); + } + } +} diff --git a/src/config/key_bindings.rs b/src/config/key_bindings.rs new file mode 100644 index 00000000..227bbef8 --- /dev/null +++ b/src/config/key_bindings.rs @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use crate::shell::{focus::FocusDirection, grabs::ResizeEdge, Direction, ResizeDirection}; +use cosmic_comp_config::workspace::WorkspaceLayout; +use serde::Deserialize; +use smithay::{ + backend::input::KeyState, + input::keyboard::{xkb::keysym_get_name, ModifiersState}, +}; +use std::collections::HashMap; + +use super::types::*; + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +pub enum KeyModifier { + Ctrl, + Alt, + Shift, + Super, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +pub struct KeyModifiers { + pub ctrl: bool, + pub alt: bool, + pub shift: bool, + pub logo: bool, +} + +impl PartialEq for KeyModifiers { + fn eq(&self, other: &ModifiersState) -> bool { + self.ctrl == other.ctrl + && self.alt == other.alt + && self.shift == other.shift + && self.logo == other.logo + } +} + +impl Into for ModifiersState { + fn into(self) -> KeyModifiers { + KeyModifiers { + ctrl: self.ctrl, + alt: self.alt, + shift: self.shift, + logo: self.logo, + } + } +} + +impl std::ops::AddAssign for KeyModifiers { + fn add_assign(&mut self, rhs: KeyModifier) { + match rhs { + KeyModifier::Ctrl => self.ctrl = true, + KeyModifier::Alt => self.alt = true, + KeyModifier::Shift => self.shift = true, + KeyModifier::Super => self.logo = true, + }; + } +} + +impl std::ops::BitOr for KeyModifier { + type Output = KeyModifiers; + + fn bitor(self, rhs: KeyModifier) -> Self::Output { + let mut modifiers = self.into(); + modifiers += rhs; + modifiers + } +} + +impl Into for KeyModifier { + fn into(self) -> KeyModifiers { + let mut modifiers = KeyModifiers { + ctrl: false, + alt: false, + shift: false, + logo: false, + }; + modifiers += self; + modifiers + } +} + +/// Describtion of a key combination that might be +/// handled by the compositor. +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Hash)] +#[serde(deny_unknown_fields)] +pub struct KeyPattern { + /// What modifiers are expected to be pressed alongside the key + #[serde(deserialize_with = "deserialize_KeyModifiers")] + pub modifiers: KeyModifiers, + /// The actual key, that was pressed + #[serde(deserialize_with = "deserialize_Keysym", default)] + pub key: Option, +} + +impl KeyPattern { + pub fn new(modifiers: impl Into, key: Option) -> KeyPattern { + KeyPattern { + modifiers: modifiers.into(), + key, + } + } +} + +impl ToString for KeyPattern { + fn to_string(&self) -> String { + let mut result = String::new(); + if self.modifiers.logo { + result += "Super+"; + } + if self.modifiers.ctrl { + result += "Ctrl+"; + } + if self.modifiers.alt { + result += "Alt+"; + } + if self.modifiers.shift { + result += "Shift+"; + } + + if let Some(key) = self.key { + result += &keysym_get_name(key); + } else { + result.remove(result.len() - 1); + } + result + } +} + +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] +pub enum Action { + Terminate, + Debug, + Close, + + Workspace(u8), + NextWorkspace, + PreviousWorkspace, + LastWorkspace, + MoveToWorkspace(u8), + MoveToNextWorkspace, + MoveToPreviousWorkspace, + MoveToLastWorkspace, + SendToWorkspace(u8), + SendToNextWorkspace, + SendToPreviousWorkspace, + SendToLastWorkspace, + + NextOutput, + PreviousOutput, + MoveToNextOutput, + MoveToPreviousOutput, + SendToNextOutput, + SendToPreviousOutput, + + Focus(FocusDirection), + Move(Direction), + + ToggleOrientation, + Orientation(crate::shell::layout::Orientation), + + ToggleStacking, + ToggleTiling, + ToggleWindowFloating, + SwapWindow, + + Resizing(ResizeDirection), + #[serde(skip)] + _ResizingInternal(ResizeDirection, ResizeEdge, KeyState), + Maximize, + Spawn(String), +} + +fn insert_binding( + key_bindings: &mut HashMap, + modifiers: KeyModifiers, + keys: impl Iterator, + action: Action, +) { + if !key_bindings.values().any(|a| a == &action) { + for key in keys { + let pattern = KeyPattern { + modifiers: modifiers.clone(), + key: Some(key), + }; + if !key_bindings.contains_key(&pattern) { + key_bindings.insert(pattern, action.clone()); + } + } + } +} + +pub fn add_default_bindings( + key_bindings: &mut HashMap, + workspace_layout: WorkspaceLayout, +) { + let (workspace_previous, workspace_next, output_previous, output_next) = match workspace_layout + { + WorkspaceLayout::Horizontal => ( + [Keysym::Left, Keysym::h], + [Keysym::Right, Keysym::l], + [Keysym::Up, Keysym::k], + [Keysym::Down, Keysym::j], + ), + WorkspaceLayout::Vertical => ( + [Keysym::Up, Keysym::k], + [Keysym::Down, Keysym::j], + [Keysym::Left, Keysym::h], + [Keysym::Right, Keysym::l], + ), + }; + + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + ..Default::default() + }, + workspace_previous.iter().copied(), + Action::PreviousWorkspace, + ); + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + ..Default::default() + }, + workspace_next.iter().copied(), + Action::NextWorkspace, + ); + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + shift: true, + ..Default::default() + }, + workspace_previous.iter().copied(), + Action::MoveToPreviousWorkspace, + ); + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + shift: true, + ..Default::default() + }, + workspace_next.iter().copied(), + Action::MoveToNextWorkspace, + ); + + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + ..Default::default() + }, + output_previous.iter().copied(), + Action::PreviousOutput, + ); + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + ..Default::default() + }, + output_next.iter().copied(), + Action::NextOutput, + ); + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + shift: true, + ..Default::default() + }, + output_previous.iter().copied(), + Action::MoveToPreviousOutput, + ); + insert_binding( + key_bindings, + KeyModifiers { + logo: true, + ctrl: true, + shift: true, + ..Default::default() + }, + output_next.iter().copied(), + Action::MoveToNextOutput, + ); +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 3b93b9b6..bffbc380 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,10 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - shell::{focus::FocusDirection, layout::tiling::Direction, Shell, WorkspaceAmount}, - state::{BackendData, Data, State}, + shell::Shell, + state::{BackendData, State}, wayland::protocols::output_configuration::OutputConfigurationState, }; +use cosmic_config::ConfigGet; use serde::{Deserialize, Serialize}; use smithay::input::Seat; pub use smithay::{ @@ -23,36 +24,39 @@ pub use smithay::{ use std::{cell::RefCell, collections::HashMap, fs::OpenOptions, path::PathBuf}; use tracing::{debug, error, info, warn}; +mod input_config; +mod key_bindings; +pub use key_bindings::{Action, KeyModifier, KeyModifiers, KeyPattern}; mod types; pub use self::types::*; +use cosmic_comp_config::{ + input::InputConfig, + workspace::{WorkspaceConfig, WorkspaceLayout}, + XkbConfig, +}; +#[derive(Debug)] pub struct Config { pub static_conf: StaticConfig, pub dynamic_conf: DynamicConfig, + pub config: cosmic_config::Config, + pub xkb: XkbConfig, + pub input_default: InputConfig, + pub input_touchpad: InputConfig, + pub input_devices: HashMap, + pub workspace: WorkspaceConfig, } #[derive(Debug, Deserialize)] pub struct StaticConfig { - pub key_bindings: HashMap, - pub workspace_mode: WorkspaceMode, - pub workspace_amount: WorkspaceAmount, + pub key_bindings: HashMap, pub tiling_enabled: bool, - #[serde(default = "default_active_hint")] - pub active_hint: u8, - #[serde(default = "default_gaps")] - pub gaps: (u8, u8), pub data_control_enabled: bool, } -#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)] -pub enum WorkspaceMode { - OutputBound, - Global, -} - +#[derive(Debug)] pub struct DynamicConfig { outputs: (Option, OutputsConfig), - inputs: (Option, InputsConfig), } #[derive(Debug, Deserialize, Serialize)] @@ -82,14 +86,6 @@ fn default_enabled() -> bool { true } -fn default_active_hint() -> u8 { - 4 -} - -fn default_gaps() -> (u8, u8) { - (0, 4) -} - #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct OutputConfig { pub mode: ((i32, i32), Option), @@ -135,77 +131,33 @@ impl OutputConfig { } } -#[derive(Debug, Deserialize, Serialize)] -pub struct InputsConfig { - xkb: XkbConfig, - devices: HashMap, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct InputConfig { - state: DeviceState, - #[serde(skip_serializing_if = "Option::is_none", default)] - acceleration: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - calibration: Option<[f32; 6]>, - #[serde(with = "ClickMethodDef")] - #[serde(skip_serializing_if = "Option::is_none", default)] - click_method: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - disable_while_typing: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - left_handed: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - middle_button_emulation: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - rotation_angle: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - scroll_config: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - tap_config: Option, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct AccelConfig { - #[serde(with = "AccelProfileDef")] - profile: Option, - speed: f64, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct ScrollConfig { - #[serde(with = "ScrollMethodDef")] - method: Option, - natural_scroll: Option, - scroll_button: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum DeviceState { - Enabled, - Disabled, - DisabledOnExternalMouse, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct TapConfig { - enabled: bool, - #[serde(with = "TapButtonMapDef")] - button_map: Option, - drag: bool, - drag_lock: bool, -} - impl Config { - pub fn load() -> Config { + pub fn load(loop_handle: &LoopHandle<'_, State>) -> Config { + let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap(); + let source = cosmic_config::calloop::ConfigWatchSource::new(&config).unwrap(); + loop_handle + .insert_source(source, |(config, keys), (), state| { + config_changed(config, keys, state); + }) + .expect("Failed to add cosmic-config to the event loop"); let xdg = xdg::BaseDirectories::new().ok(); + let workspace = get_config::(&config, "workspaces"); Config { - static_conf: Self::load_static(xdg.as_ref()), + static_conf: Self::load_static(xdg.as_ref(), workspace.workspace_layout), dynamic_conf: Self::load_dynamic(xdg.as_ref()), + xkb: get_config(&config, "xkb-config"), + input_default: get_config(&config, "input-default"), + input_touchpad: get_config(&config, "input-touchpad"), + input_devices: get_config(&config, "input-devices"), + workspace, + config, } } - fn load_static(xdg: Option<&xdg::BaseDirectories>) -> StaticConfig { + fn load_static( + xdg: Option<&xdg::BaseDirectories>, + workspace_layout: WorkspaceLayout, + ) -> StaticConfig { let mut locations = if let Some(base) = xdg { vec![ base.get_config_file("cosmic-comp.ron"), @@ -227,18 +179,19 @@ impl Config { debug!("Trying config location: {}", path.display()); if path.exists() { info!("Using config at {}", path.display()); - return ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap()) - .expect("Malformed config file"); + let mut config: StaticConfig = + ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap()) + .expect("Malformed config file"); + + key_bindings::add_default_bindings(&mut config.key_bindings, workspace_layout); + + return config; } } StaticConfig { key_bindings: HashMap::new(), - workspace_mode: WorkspaceMode::Global, - workspace_amount: WorkspaceAmount::Dynamic, tiling_enabled: false, - active_hint: default_active_hint(), - gaps: default_gaps(), data_control_enabled: false, } } @@ -248,12 +201,8 @@ impl Config { xdg.and_then(|base| base.place_state_file("cosmic-comp/outputs.ron").ok()); let outputs = Self::load_outputs(&output_path); - let input_path = xdg.and_then(|base| base.place_state_file("cosmic-comp/inputs.ron").ok()); - let inputs = Self::load_inputs(&input_path); - DynamicConfig { outputs: (output_path, outputs), - inputs: (input_path, inputs), } } @@ -277,34 +226,13 @@ impl Config { } } - fn load_inputs(path: &Option) -> InputsConfig { - if let Some(path) = path.as_ref() { - if path.exists() { - match ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap()) { - Ok(config) => return config, - Err(err) => { - warn!(?err, "Failed to read input_config, resetting.."); - if let Err(err) = std::fs::remove_file(path) { - error!(?err, "Failed to remove input_config."); - } - } - }; - } - } - - InputsConfig { - xkb: XkbConfig::default(), - devices: HashMap::new(), - } - } - pub fn read_outputs( &mut self, output_state: &mut OutputConfigurationState, backend: &mut BackendData, shell: &mut Shell, seats: impl Iterator>, - loop_handle: &LoopHandle<'_, Data>, + loop_handle: &LoopHandle<'_, State>, ) { let seats = seats.collect::>(); let outputs = output_state.outputs().collect::>(); @@ -452,258 +380,30 @@ impl Config { } pub fn xkb_config(&self) -> XkbConfig { - self.dynamic_conf.inputs().xkb.clone() + self.xkb.clone() } - pub fn read_device(&mut self, device: &mut InputDevice) { - use std::collections::hash_map::Entry; + pub fn read_device(&self, device: &mut InputDevice) { + let (device_config, default_config) = self.get_device_config(device); + input_config::update_device(device, device_config, default_config); + } - let mut inputs = self.dynamic_conf.inputs_mut(); - match inputs.devices.entry(device.name().into()) { - Entry::Occupied(entry) => { - let config = entry.get(); - if let Err(err) = match config.state { - DeviceState::Enabled => { - device.config_send_events_set_mode(SendEventsMode::ENABLED) - } - DeviceState::Disabled => { - device.config_send_events_set_mode(SendEventsMode::DISABLED) - } - DeviceState::DisabledOnExternalMouse => device - .config_send_events_set_mode(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE), - } { - warn!( - ?err, - "Failed to apply mode {:?} for device {:?}.", - config.state, - device.name(), - ); - } - if let Some(accel) = config.acceleration.as_ref() { - if let Some(profile) = accel.profile { - if let Err(err) = device.config_accel_set_profile(profile) { - warn!( - ?err, - "Failed to apply acceleration profile {:?} for device {:?}.", - profile, - device.name(), - ); - } - } - if let Err(err) = device.config_accel_set_speed(accel.speed) { - warn!( - ?err, - "Failed to apply acceleration speed {:?} for device {:?}.", - accel.speed, - device.name(), - ); - } - } - if let Some(matrix) = config.calibration { - if let Err(err) = device.config_calibration_set_matrix(matrix) { - warn!( - ?err, - "Failed to apply calibration matrix {:?} for device {:?}.", - matrix, - device.name(), - ); - } - } - if let Some(method) = config.click_method { - if let Err(err) = device.config_click_set_method(method) { - warn!( - ?err, - "Failed to apply click method {:?} for device {:?}.", - method, - device.name(), - ); - } - } - if let Some(dwt) = config.disable_while_typing { - if let Err(err) = device.config_dwt_set_enabled(dwt) { - warn!( - ?err, - "Failed to apply disable-while-typing {:?} for device {:?}.", - dwt, - device.name(), - ); - } - } - if let Some(left) = config.left_handed { - if let Err(err) = device.config_left_handed_set(left) { - warn!( - ?err, - "Failed to apply left-handed {:?} for device {:?}.", - left, - device.name(), - ); - } - } - if let Some(middle) = config.middle_button_emulation { - if let Err(err) = device.config_middle_emulation_set_enabled(middle) { - warn!( - ?err, - "Failed to apply middle-button-emulation {:?} for device {:?}.", - middle, - device.name(), - ); - } - } - if let Some(angle) = config.rotation_angle { - if let Err(err) = device.config_rotation_set_angle(angle) { - warn!( - ?err, - "Failed to apply rotation-angle {:?} for device {:?}", - angle, - device.name(), - ); - } - } - if let Some(scroll) = config.scroll_config.as_ref() { - if let Some(method) = scroll.method { - if let Err(err) = device.config_scroll_set_method(method) { - warn!( - ?err, - "Failed to apply scroll method {:?} for device {:?}.", - method, - device.name(), - ); - } - } - if let Some(natural) = scroll.natural_scroll { - if let Err(err) = device.config_scroll_set_natural_scroll_enabled(natural) { - warn!( - ?err, - "Failed to apply natural scrolling {:?} for device {:?}.", - natural, - device.name(), - ); - } - } - if let Some(button) = scroll.scroll_button { - if let Err(err) = device.config_scroll_set_button(button) { - warn!( - ?err, - "Failed to apply scroll button {:?} for device {:?}.", - button, - device.name(), - ); - } - } - } - if let Some(tap) = config.tap_config.as_ref() { - if let Err(err) = device.config_tap_set_enabled(tap.enabled) { - warn!( - ?err, - "Failed to apply tap-to-click {:?} for device {:?}.", - tap.enabled, - device.name(), - ); - } - if let Some(button_map) = tap.button_map { - if let Err(err) = device.config_tap_set_button_map(button_map) { - warn!( - ?err, - "Failed to apply button map {:?} for device {:?}.", - button_map, - device.name(), - ); - } - } - if let Err(err) = device.config_tap_set_drag_enabled(tap.drag) { - warn!( - ?err, - "Failed to apply tap-drag {:?} for device {:?}.", - tap.drag, - device.name(), - ); - } - if let Err(err) = device.config_tap_set_drag_lock_enabled(tap.drag_lock) { - warn!( - ?err, - "Failed to apply tap-drag-lock {:?} for device {:?}.", - tap.drag_lock, - device.name(), - ); - } - } - } - Entry::Vacant(entry) => { - entry.insert(InputConfig { - state: match device.config_send_events_mode() { - x if x.contains(SendEventsMode::ENABLED) => DeviceState::Enabled, - x if x.contains(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE) => { - DeviceState::DisabledOnExternalMouse - } - x if x.contains(SendEventsMode::DISABLED) => DeviceState::Disabled, - _ => DeviceState::Disabled, - }, - acceleration: if device.config_accel_is_available() { - Some(AccelConfig { - profile: device.config_accel_profile(), - speed: device.config_accel_speed(), - }) - } else { - None - }, - calibration: device.config_calibration_matrix(), - click_method: device.config_click_method(), - disable_while_typing: if device.config_dwt_is_available() { - Some(device.config_dwt_enabled()) - } else { - None - }, - left_handed: if device.config_left_handed_is_available() { - Some(device.config_left_handed()) - } else { - None - }, - middle_button_emulation: if device.config_middle_emulation_is_available() { - Some(device.config_middle_emulation_enabled()) - } else { - None - }, - rotation_angle: if device.config_rotation_is_available() { - Some(device.config_rotation_angle()) - } else { - None - }, - scroll_config: if device - .config_scroll_methods() - .iter() - .any(|x| *x != ScrollMethod::NoScroll) - { - Some(ScrollConfig { - method: device.config_scroll_method(), - natural_scroll: if device.config_scroll_has_natural_scroll() { - Some(device.config_scroll_natural_scroll_enabled()) - } else { - None - }, - scroll_button: if device.config_scroll_method() - == Some(ScrollMethod::OnButtonDown) - { - Some(device.config_scroll_button()) - } else { - None - }, - }) - } else { - None - }, - tap_config: if device.config_tap_finger_count() > 0 { - Some(TapConfig { - enabled: device.config_tap_enabled(), - button_map: device.config_tap_button_map(), - drag: device.config_tap_drag_enabled(), - drag_lock: device.config_tap_drag_lock_enabled(), - }) - } else { - None - }, - }); - } - } + pub fn scroll_factor(&self, device: &InputDevice) -> f64 { + let (device_config, default_config) = self.get_device_config(device); + input_config::get_config(device_config, default_config, |x| { + x.scroll_config.as_ref()?.scroll_factor + }) + .map_or(1.0, |x| x.0) + } + + fn get_device_config(&self, device: &InputDevice) -> (Option<&InputConfig>, &InputConfig) { + let default_config = if device.config_tap_finger_count() > 0 { + &self.input_touchpad + } else { + &self.input_default + }; + let device_config = self.input_devices.get(device.name()); + (device_config, default_config) } } @@ -752,140 +452,72 @@ impl DynamicConfig { pub fn outputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, OutputsConfig> { PersistenceGuard(self.outputs.0.clone(), &mut self.outputs.1) } - - pub fn inputs(&self) -> &InputsConfig { - &self.inputs.1 - } - - pub fn inputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, InputsConfig> { - PersistenceGuard(self.inputs.0.clone(), &mut self.inputs.1) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -pub enum KeyModifier { - Ctrl, - Alt, - Shift, - Super, - CapsLock, - NumLock, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct KeyModifiers { - ctrl: bool, - alt: bool, - shift: bool, - logo: bool, - caps_lock: bool, - num_lock: bool, -} - -impl PartialEq for KeyModifiers { - fn eq(&self, other: &ModifiersState) -> bool { - self.ctrl == other.ctrl - && self.alt == other.alt - && self.shift == other.shift - && self.logo == other.logo - && self.caps_lock == other.caps_lock - && self.num_lock == other.num_lock - } } -impl std::ops::AddAssign for KeyModifiers { - fn add_assign(&mut self, rhs: KeyModifier) { - match rhs { - KeyModifier::Ctrl => self.ctrl = true, - KeyModifier::Alt => self.alt = true, - KeyModifier::Shift => self.shift = true, - KeyModifier::Super => self.logo = true, - KeyModifier::CapsLock => self.caps_lock = true, - KeyModifier::NumLock => self.num_lock = true, - }; - } +fn get_config( + config: &cosmic_config::Config, + key: &str, +) -> T { + config.get(key).unwrap_or_else(|err| { + error!(?err, "Failed to read config '{}'", key); + T::default() + }) } -impl std::ops::BitOr for KeyModifier { - type Output = KeyModifiers; - - fn bitor(self, rhs: KeyModifier) -> Self::Output { - let mut modifiers = self.into(); - modifiers += rhs; - modifiers - } -} - -impl Into for KeyModifier { - fn into(self) -> KeyModifiers { - let mut modifiers = KeyModifiers { - ctrl: false, - alt: false, - shift: false, - caps_lock: false, - logo: false, - num_lock: false, - }; - modifiers += self; - modifiers +fn update_input(state: &mut State) { + if let BackendData::Kms(ref mut kms_state) = &mut state.backend { + for device in kms_state.input_devices.values_mut() { + state.common.config.read_device(device); + } } } -/// Describtion of a key combination that might be -/// handled by the compositor. -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Hash)] -#[serde(deny_unknown_fields)] -pub struct KeyPattern { - /// What modifiers are expected to be pressed alongside the key - #[serde(deserialize_with = "deserialize_KeyModifiers")] - pub modifiers: KeyModifiers, - /// The actual key, that was pressed - #[serde(deserialize_with = "deserialize_Keysym")] - pub key: u32, -} - -impl KeyPattern { - pub fn new(modifiers: impl Into, key: u32) -> KeyPattern { - KeyPattern { - modifiers: modifiers.into(), - key, +fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut State) { + for key in &keys { + match key.as_str() { + "xkb-config" => { + let value = get_config::(&config, "xkb-config"); + for seat in state.common.seats().cloned().collect::>().iter() { + if let Some(keyboard) = seat.get_keyboard() { + if let Err(err) = keyboard.set_xkb_config(state, xkb_config_to_wl(&value)) { + error!(?err, "Failed to load provided xkb config"); + // TODO Revert to default? + } + } + } + state.common.config.xkb = value; + } + "input-default" => { + let value = get_config::(&config, "input-default"); + state.common.config.input_default = value; + update_input(state); + } + "input-touchpad" => { + let value = get_config::(&config, "input-touchpad"); + state.common.config.input_touchpad = value; + update_input(state); + } + "input-devices" => { + let value = get_config::>(&config, "input-devices"); + state.common.config.input_devices = value; + update_input(state); + } + "workspaces" => { + state.common.config.workspace = + get_config::(&config, "workspaces"); + state.common.shell.update_config(&state.common.config); + } + _ => {} } } } -#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] -pub enum Action { - Terminate, - Debug, - Close, - - Workspace(u8), - NextWorkspace, - PreviousWorkspace, - LastWorkspace, - MoveToWorkspace(u8), - MoveToNextWorkspace, - MoveToPreviousWorkspace, - MoveToLastWorkspace, - SendToWorkspace(u8), - SendToNextWorkspace, - SendToPreviousWorkspace, - SendToLastWorkspace, - - NextOutput, - PreviousOutput, - MoveToNextOutput, - MoveToPreviousOutput, - - Focus(FocusDirection), - Move(Direction), - - ToggleOrientation, - Orientation(crate::shell::layout::Orientation), - - ToggleTiling, - ToggleWindowFloating, - - Maximize, - Spawn(String), +pub fn xkb_config_to_wl(config: &XkbConfig) -> WlXkbConfig<'_> { + WlXkbConfig { + rules: &config.rules, + model: &config.model, + layout: &config.layout, + variant: &config.variant, + options: config.options.clone(), + } } diff --git a/src/config/types.rs b/src/config/types.rs index 584dd51c..79f4ac7b 100644 --- a/src/config/types.rs +++ b/src/config/types.rs @@ -3,6 +3,7 @@ use super::{KeyModifier, KeyModifiers}; use serde::{Deserialize, Serialize}; +use smithay::reexports::x11rb::NO_SYMBOL; pub use smithay::{ backend::input::KeyState, input::keyboard::{keysyms as KeySyms, Keysym, XkbConfig as WlXkbConfig}, @@ -13,147 +14,6 @@ pub use smithay::{ use tracing::warn; use xkbcommon::xkb; -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct XkbConfig { - pub rules: String, - pub model: String, - pub layout: String, - pub variant: String, - pub options: Option, -} - -impl Default for XkbConfig { - fn default() -> XkbConfig { - XkbConfig { - rules: String::new(), - model: String::new(), - layout: String::new(), - variant: String::new(), - options: None, - } - } -} - -impl<'a> Into> for &'a XkbConfig { - fn into(self) -> WlXkbConfig<'a> { - WlXkbConfig { - rules: &self.rules, - model: &self.model, - layout: &self.layout, - variant: &self.variant, - options: self.options.clone(), - } - } -} - -pub mod ClickMethodDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::ClickMethod as ClickMethodOrig; - - #[derive(Debug, Serialize, Deserialize)] - pub enum ClickMethod { - ButtonAreas, - Clickfinger, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - ClickMethod::ButtonAreas => ClickMethodOrig::ButtonAreas, - ClickMethod::Clickfinger => ClickMethodOrig::Clickfinger, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(ClickMethodOrig::ButtonAreas) => Some(ClickMethod::ButtonAreas), - Some(ClickMethodOrig::Clickfinger) => Some(ClickMethod::Clickfinger), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - -pub mod AccelProfileDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::AccelProfile as AccelProfileOrig; - - #[derive(Debug, Serialize, Deserialize)] - enum AccelProfile { - Flat, - Adaptive, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - AccelProfile::Flat => AccelProfileOrig::Flat, - AccelProfile::Adaptive => AccelProfileOrig::Adaptive, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(AccelProfileOrig::Flat) => Some(AccelProfile::Flat), - Some(AccelProfileOrig::Adaptive) => Some(AccelProfile::Adaptive), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - -pub mod ScrollMethodDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::ScrollMethod as ScrollMethodOrig; - - #[derive(Debug, Serialize, Deserialize)] - pub enum ScrollMethod { - NoScroll, - TwoFinger, - Edge, - OnButtonDown, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - ScrollMethod::NoScroll => ScrollMethodOrig::NoScroll, - ScrollMethod::TwoFinger => ScrollMethodOrig::TwoFinger, - ScrollMethod::Edge => ScrollMethodOrig::Edge, - ScrollMethod::OnButtonDown => ScrollMethodOrig::OnButtonDown, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(ScrollMethodOrig::NoScroll) => Some(ScrollMethod::NoScroll), - Some(ScrollMethodOrig::TwoFinger) => Some(ScrollMethod::TwoFinger), - Some(ScrollMethodOrig::Edge) => Some(ScrollMethod::Edge), - Some(ScrollMethodOrig::OnButtonDown) => Some(ScrollMethod::OnButtonDown), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - #[derive(Serialize, Deserialize)] #[serde(remote = "Transform")] pub enum TransformDef { @@ -167,40 +27,6 @@ pub enum TransformDef { Flipped270, } -pub mod TapButtonMapDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::TapButtonMap as TapButtonMapOrig; - - #[derive(Debug, Serialize, Deserialize)] - pub enum TapButtonMap { - LeftRightMiddle, - LeftMiddleRight, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - TapButtonMap::LeftRightMiddle => TapButtonMapOrig::LeftRightMiddle, - TapButtonMap::LeftMiddleRight => TapButtonMapOrig::LeftMiddleRight, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(TapButtonMapOrig::LeftRightMiddle) => Some(TapButtonMap::LeftRightMiddle), - Some(TapButtonMapOrig::LeftMiddleRight) => Some(TapButtonMap::LeftMiddleRight), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - #[derive(Deserialize)] #[serde(transparent)] pub struct KeyModifiersDef(Vec); @@ -212,9 +38,7 @@ impl From for KeyModifiers { ctrl: false, alt: false, shift: false, - caps_lock: false, logo: false, - num_lock: false, }, |mut modis, modi: KeyModifier| { modis += modi; @@ -233,7 +57,7 @@ where } #[allow(non_snake_case)] -pub fn deserialize_Keysym<'de, D>(deserializer: D) -> Result +pub fn deserialize_Keysym<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { @@ -242,20 +66,22 @@ where let name = String::deserialize(deserializer)?; //let name = format!("KEY_{}", code); match xkb::keysym_from_name(&name, xkb::KEYSYM_NO_FLAGS) { - KeySyms::KEY_NoSymbol => match xkb::keysym_from_name(&name, xkb::KEYSYM_CASE_INSENSITIVE) { - KeySyms::KEY_NoSymbol => Err(::invalid_value( - Unexpected::Str(&name), - &"One of the keysym names of xkbcommon.h without the 'KEY_' prefix", - )), - x => { - warn!( - "Key-Binding '{}' only matched case insensitive for {:?}", - name, - xkb::keysym_get_name(x) - ); - Ok(x) + x if x.raw() == NO_SYMBOL => { + match xkb::keysym_from_name(&name, xkb::KEYSYM_CASE_INSENSITIVE) { + x if x.raw() == NO_SYMBOL => Err(::invalid_value( + Unexpected::Str(&name), + &"One of the keysym names of xkbcommon.h without the 'KEY_' prefix", + )), + x => { + warn!( + "Key-Binding '{}' only matched case insensitive for {:?}", + name, + xkb::keysym_get_name(x) + ); + Ok(Some(x)) + } } - }, - x => Ok(x), + } + x => Ok(Some(x)), } } diff --git a/src/debug.rs b/src/debug.rs index 4bd5f037..c4b3f94b 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -9,7 +9,7 @@ use crate::{ }, state::{Common, Fps}, }; -use egui::{Color32, Vec2}; +use egui::{load::SizedTexture, Color32, Vec2}; use smithay::{ backend::{ drm::DrmNode, @@ -62,7 +62,7 @@ pub fn fps_ui( area: Rectangle, scale: f64, ) -> Result, GlesError> { - use egui::widgets::plot::{Bar, BarChart, Legend, Plot}; + use egui_plot::{Bar, BarChart, Legend, Plot}; let (max, min, avg, avg_fps) = ( fps.max_frametime().as_secs_f64(), @@ -176,7 +176,7 @@ pub fn fps_ui( { let factor = resp.rect.height() / size.y; size = Vec2::from([size.x * factor, resp.rect.height()]); - ui.image(*texture_id, size); + ui.image(SizedTexture::new(*texture_id, size)); } } }); @@ -337,6 +337,8 @@ fn format_pointer_focus(focus: Option) -> String { Some(LayerSurface(x)) => format!("LayerSurface {}", x.wl_surface().id().protocol_id()), Some(Popup(x)) => format!("Popup {}", x.wl_surface().id().protocol_id()), Some(OverrideRedirect(x)) => format!("Override Redirect {}", x.window_id()), + Some(PointerFocusTarget::ResizeFork(x)) => format!("Resize Fork {:?}", x.node), + Some(LockSurface(x)) => format!("LockSurface {}", x.wl_surface().id().protocol_id()), None => format!("None"), } } @@ -378,6 +380,7 @@ fn format_keyboard_focus(focus: Option) -> String { Some(LayerSurface(x)) => format!("LayerSurface {}", x.wl_surface().id().protocol_id()), Some(Popup(x)) => format!("Popup {}", x.wl_surface().id().protocol_id()), Some(Group(_)) => format!("Window Group"), + Some(LockSurface(x)) => format!("LockSurface {}", x.wl_surface().id().protocol_id()), None => format!("None"), } } diff --git a/src/input/mod.rs b/src/input/mod.rs index cc171df1..af3feedc 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1,36 +1,56 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - config::{Action, Config}, + backend::render::cursor::CursorState, + config::{xkb_config_to_wl, Action, Config, KeyPattern}, shell::{ focus::{target::PointerFocusTarget, FocusDirection}, + grabs::{ResizeEdge, SeatMoveGrabState}, layout::{ - floating::SeatMoveGrabState, - tiling::{Direction, FocusResult}, + floating::ResizeGrabMarker, + tiling::{SwapWindowGrab, TilingLayout}, }, + Direction, FocusResult, MoveResult, OverviewMode, ResizeDirection, ResizeMode, Trigger, Workspace, - }, // shell::grabs::SeatMoveGrabState - state::Common, + }, + state::{Common, SessionLock}, utils::prelude::*, - wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session}, + wayland::{ + handlers::{screencopy::ScreencopySessions, xdg_activation::ActivationContext}, + protocols::screencopy::Session, + }, }; +use calloop::{timer::Timer, RegistrationToken}; +use cosmic_comp_config::workspace::WorkspaceLayout; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType; +#[allow(deprecated)] use smithay::{ backend::input::{ - Axis, AxisSource, Device, DeviceCapability, InputBackend, InputEvent, KeyState, - PointerAxisEvent, + Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent, GestureEndEvent, + GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend, InputEvent, + KeyState, PointerAxisEvent, }, desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType}, input::{ - keyboard::{keysyms, FilterResult, KeysymHandle, XkbConfig}, - pointer::{AxisFrame, ButtonEvent, CursorImageStatus, MotionEvent, RelativeMotionEvent}, + keyboard::{FilterResult, KeysymHandle, XkbConfig}, + pointer::{ + AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent, + GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, + GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, + RelativeMotionEvent, + }, Seat, SeatState, }, output::Output, - reexports::wayland_server::DisplayHandle, - utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER}, + reexports::{ + input::event::pointer::PointerAxisEvent as LibinputPointerAxisEvent, + wayland_server::DisplayHandle, + }, + utils::{Point, Serial, SERIAL_COUNTER}, wayland::{ - keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat, seat::WaylandFocus, + keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat, + pointer_constraints::{with_pointer_constraint, PointerConstraint}, + seat::WaylandFocus, shell::wlr_layer::Layer as WlrLayer, }, xwayland::X11Surface, @@ -38,9 +58,14 @@ use smithay::{ #[cfg(not(feature = "debug"))] use tracing::info; use tracing::{error, trace, warn}; +use xkbcommon::xkb::{Keycode, Keysym}; -use std::{cell::RefCell, collections::HashMap}; -use xkbcommon::xkb::KEY_XF86Switch_VT_12; +use std::{ + any::Any, + cell::RefCell, + collections::HashMap, + time::{Duration, Instant}, +}; crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS); @@ -48,7 +73,9 @@ crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS); pub struct SeatId(pub usize); pub struct ActiveOutput(pub RefCell); #[derive(Default)] -pub struct SupressedKeys(RefCell>); +pub struct SupressedKeys(RefCell)>>); +#[derive(Default, Debug)] +pub struct ModifiersShortcutQueue(RefCell>); #[derive(Default)] pub struct Devices(RefCell>>); @@ -65,19 +92,50 @@ impl Drop for SeatId { } impl SupressedKeys { - fn add(&self, keysym: &KeysymHandle) { - self.0.borrow_mut().push(keysym.raw_code()); + fn add(&self, keysym: &KeysymHandle, token: impl Into>) { + self.0.borrow_mut().push((keysym.raw_code(), token.into())); } - fn filter(&self, keysym: &KeysymHandle) -> bool { + fn filter(&self, keysym: &KeysymHandle) -> Option> { let mut keys = self.0.borrow_mut(); - if let Some(i) = keys.iter().position(|x| *x == keysym.raw_code()) { - keys.remove(i); + let (removed, remaining) = keys + .drain(..) + .partition(|(key, _)| *key == keysym.raw_code()); + *keys = remaining; + + let removed = removed + .into_iter() + .map(|(_, token)| token) + .flatten() + .collect::>(); + if removed.is_empty() { + None + } else { + Some(removed) + } + } +} + +impl ModifiersShortcutQueue { + pub fn set(&self, binding: KeyPattern) { + let mut set = self.0.borrow_mut(); + *set = Some(binding); + } + + pub fn take(&self, binding: &KeyPattern) -> bool { + let mut set = self.0.borrow_mut(); + if set.is_some() && set.as_ref().unwrap() == binding { + *set = None; true } else { false } } + + pub fn clear(&self) { + let mut set = self.0.borrow_mut(); + *set = None; + } } impl Devices { @@ -125,9 +183,11 @@ pub fn add_seat( userdata.insert_if_missing(SeatId::default); userdata.insert_if_missing(Devices::default); userdata.insert_if_missing(SupressedKeys::default); + userdata.insert_if_missing(ModifiersShortcutQueue::default); userdata.insert_if_missing(SeatMoveGrabState::default); + userdata.insert_if_missing(CursorState::default); userdata.insert_if_missing(|| ActiveOutput(RefCell::new(output.clone()))); - userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::Default)); + userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::default_named())); // A lot of clients bind keyboard and pointer unconditionally once on launch.. // Initial clients might race the compositor on adding periheral and @@ -139,7 +199,7 @@ pub fn add_seat( // So instead of doing the right thing (and initialize these capabilities as matching // devices appear), we have to surrender to reality and just always expose a keyboard and pointer. let conf = config.xkb_config(); - if let Err(err) = seat.add_keyboard((&conf).into(), 200, 25) { + if let Err(err) = seat.add_keyboard(xkb_config_to_wl(&conf), 200, 25) { warn!( ?err, "Failed to load provided xkb config. Trying default...", @@ -153,9 +213,14 @@ pub fn add_seat( } impl State { - pub fn process_input_event(&mut self, event: InputEvent) { + pub fn process_input_event( + &mut self, + event: InputEvent, + needs_key_repetition: bool, + ) where + ::PointerAxisEvent: 'static, + { use smithay::backend::input::Event; - match event { InputEvent::DeviceAdded { device } => { let seat = &mut self.common.last_active_seat(); @@ -194,13 +259,16 @@ impl State { InputEvent::Keyboard { event, .. } => { use smithay::backend::input::KeyboardKeyEvent; - let device = event.device(); - for seat in self.common.seats().cloned().collect::>().iter() { + let loop_handle = self.common.event_loop_handle.clone(); + + if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() { + let userdata = seat.user_data(); + let current_output = seat.active_output(); let workspace = self.common.shell.active_space_mut(¤t_output); let shortcuts_inhibited = workspace .focus_stack - .get(seat) + .get(&seat) .last() .and_then(|window| { window.wl_surface().and_then(|surface| { @@ -210,18 +278,15 @@ impl State { .map(|inhibitor| inhibitor.is_active()) .unwrap_or(false); - let userdata = seat.user_data(); - let devices = userdata.get::().unwrap(); - if devices.has_device(&device) { - let keycode = event.key_code(); - let state = event.state(); - trace!(?keycode, ?state, "key"); - - let serial = SERIAL_COUNTER.next_serial(); - let time = Event::time_msec(&event); - if let Some(action) = seat - .get_keyboard() - .unwrap() + let keycode = event.key_code(); + let state = event.state(); + trace!(?keycode, ?state, "key"); + + let serial = SERIAL_COUNTER.next_serial(); + let time = Event::time_msec(&event); + let keyboard = seat.get_keyboard().unwrap(); + let current_focus = keyboard.current_focus(); + if let Some((action, pattern)) = keyboard .input( self, keycode, @@ -229,15 +294,181 @@ impl State { serial, time, |data, modifiers, handle| { - if state == KeyState::Released - && userdata.get::().unwrap().filter(&handle) + // Leave move overview mode, if any modifier was released + if let OverviewMode::Started(Trigger::KeyboardMove(action_modifiers), _) = + data.common.shell.overview_mode().0 { - return FilterResult::Intercept(None); + if (action_modifiers.ctrl && !modifiers.ctrl) + || (action_modifiers.alt && !modifiers.alt) + || (action_modifiers.logo && !modifiers.logo) + || (action_modifiers.shift && !modifiers.shift) + { + data.common.shell.set_overview_mode(None, data.common.event_loop_handle.clone()); + } + } + // Leave swap overview mode, if any key was released + if let OverviewMode::Started(Trigger::KeyboardSwap(action_pattern, old_descriptor), _) = + data.common.shell.overview_mode().0 + { + if (action_pattern.modifiers.ctrl && !modifiers.ctrl) + || (action_pattern.modifiers.alt && !modifiers.alt) + || (action_pattern.modifiers.logo && !modifiers.logo) + || (action_pattern.modifiers.shift && !modifiers.shift) + || (action_pattern.key.is_some() && handle.raw_syms().contains(&action_pattern.key.unwrap()) && state == KeyState::Released) + { + data.common.shell.set_overview_mode(None, data.common.event_loop_handle.clone()); + + if let Some(focus) = current_focus { + if let Some(new_descriptor) = data.common.shell.workspaces.active(¤t_output).1.node_desc(focus) { + let mut spaces = data.common.shell.workspaces.spaces_mut(); + if old_descriptor.handle != new_descriptor.handle { + let (mut old_w, mut other_w) = spaces.partition::, _>(|w| w.handle == old_descriptor.handle); + if let Some(old_workspace) = old_w.get_mut(0) { + if let Some(new_workspace) = other_w.iter_mut().find(|w| w.handle == new_descriptor.handle) { + if let Some(focus) = TilingLayout::swap_trees(&mut old_workspace.tiling_layer, Some(&mut new_workspace.tiling_layer), &old_descriptor, &new_descriptor, &mut data.common.shell.toplevel_info_state) { + let seat = seat.clone(); + data.common.event_loop_handle.insert_idle(move |state| { + Common::set_focus(state, Some(&focus), &seat, None); + }); + } + old_workspace.refresh_focus_stack(); + new_workspace.refresh_focus_stack(); + } + } + } else { + if let Some(workspace) = spaces.find(|w| w.handle == new_descriptor.handle) { + if let Some(focus) = TilingLayout::swap_trees(&mut workspace.tiling_layer, None, &old_descriptor, &new_descriptor, &mut data.common.shell.toplevel_info_state) { + std::mem::drop(spaces); + let seat = seat.clone(); + data.common.event_loop_handle.insert_idle(move |state| { + Common::set_focus(state, Some(&focus), &seat, None); + }); + } + workspace.refresh_focus_stack(); + } + } + } + } else { + let new_workspace = data.common.shell.workspaces.active(¤t_output).1.handle; + if new_workspace != old_descriptor.handle { + let spaces = data.common.shell.workspaces.spaces_mut(); + let (mut old_w, mut other_w) = spaces.partition::, _>(|w| w.handle == old_descriptor.handle); + if let Some(old_workspace) = old_w.get_mut(0) { + if let Some(new_workspace) = other_w.iter_mut().find(|w| w.handle == new_workspace) { + if new_workspace.tiling_layer.windows().next().is_none() { + if let Some(focus) = TilingLayout::move_tree(&mut old_workspace.tiling_layer, &mut new_workspace.tiling_layer, &new_workspace.handle, &seat, new_workspace.focus_stack.get(&seat).iter(), old_descriptor, &mut data.common.shell.toplevel_info_state) { + let seat = seat.clone(); + data.common.event_loop_handle.insert_idle(move |state| { + Common::set_focus(state, Some(&focus), &seat, None); + }); + } + old_workspace.refresh_focus_stack(); + } + } + } + } + } + } + } + + // Leave or update resize mode, if modifiers changed or initial key was released + if let (ResizeMode::Started(action_pattern, _, _), _) = + data.common.shell.resize_mode() + { + if action_pattern.key.is_some() && state == KeyState::Released + && handle.raw_syms().contains(&action_pattern.key.unwrap()) + { + data.common.shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone()); + } else if action_pattern.modifiers != *modifiers { + let mut new_pattern = action_pattern.clone(); + new_pattern.modifiers = modifiers.clone().into(); + let enabled = data + .common + .config + .static_conf + .key_bindings + .iter() + .find_map(move |(binding, action)| { + if binding == &new_pattern + && matches!(action, Action::Resizing(_)) + { + let Action::Resizing(direction) = action else { unreachable!() }; + Some((new_pattern.clone(), *direction)) + } else { + None + } + }); + data.common.shell.set_resize_mode(enabled, &data.common.config, data.common.event_loop_handle.clone()); + } } + // Special case resizing with regards to arrow keys + if let (ResizeMode::Started(_, _, direction), _) = + data.common.shell.resize_mode() + { + let resize_edge = match handle.modified_sym() { + Keysym::Left | Keysym::h | Keysym::H => Some(ResizeEdge::LEFT), + Keysym::Down | Keysym::j | Keysym::J => Some(ResizeEdge::BOTTOM), + Keysym::Up | Keysym::k | Keysym::K => Some(ResizeEdge::TOP), + Keysym::Right | Keysym::l | Keysym::L => Some(ResizeEdge::RIGHT), + _ => None, + }; + + if let Some(mut edge) = resize_edge { + if direction == ResizeDirection::Inwards { + edge.flip_direction(); + } + let action = Action::_ResizingInternal(direction, edge, state); + let key_pattern = KeyPattern { + modifiers: modifiers.clone().into(), + key: Some(Keysym::new(handle.raw_code().raw())), + }; + + if state == KeyState::Released { + if let Some(tokens) = userdata.get::().unwrap().filter(&handle) { + for token in tokens { + loop_handle.remove(token); + } + } + } else { + let token = if needs_key_repetition { + let seat_clone = seat.clone(); + let action_clone = action.clone(); + let key_pattern_clone = key_pattern.clone(); + let start = Instant::now(); + loop_handle.insert_source(Timer::from_duration(Duration::from_millis(200)), move |current, _, state| { + let duration = current.duration_since(start).as_millis(); + state.handle_action(action_clone.clone(), &seat_clone, serial, time.overflowing_add(duration as u32).0, key_pattern_clone.clone(), None); + calloop::timer::TimeoutAction::ToDuration(Duration::from_millis(25)) + }).ok() + } else { None }; + + userdata + .get::() + .unwrap() + .add(&handle, token); + } + return FilterResult::Intercept(Some(( + action, + key_pattern + ))); + } + } + + // Skip released events for initially surpressed keys + if state == KeyState::Released { + if let Some(tokens) = userdata.get::().unwrap().filter(&handle) { + for token in tokens { + loop_handle.remove(token); + } + return FilterResult::Intercept(None); + } + } + + // Pass keys to debug interface, if it has focus #[cfg(feature = "debug")] { - if data.common.seats().position(|x| x == seat).unwrap() == 0 + if data.common.seats().position(|x| x == &seat).unwrap() == 0 && data.common.egui.active { if data.common.egui.state.wants_keyboard() { @@ -249,336 +480,505 @@ impl State { userdata .get::() .unwrap() - .add(&handle); + .add(&handle, None); return FilterResult::Intercept(None); } } } + // Handle VT switches if state == KeyState::Pressed - && (keysyms::KEY_XF86Switch_VT_1..=KEY_XF86Switch_VT_12) - .contains(&handle.modified_sym()) + && (Keysym::XF86_Switch_VT_1.raw() ..= Keysym::XF86_Switch_VT_12.raw()) + .contains(&handle.modified_sym().raw()) { if let Err(err) = data.backend.kms().switch_vt( - (handle.modified_sym() - keysyms::KEY_XF86Switch_VT_1 + (handle.modified_sym().raw() - Keysym::XF86_Switch_VT_1.raw() + 1) as i32, ) { error!(?err, "Failed switching virtual terminal."); } - userdata.get::().unwrap().add(&handle); + userdata.get::().unwrap().add(&handle, None); return FilterResult::Intercept(None); } - // here we can handle global shortcuts and the like + // handle the rest of the global shortcuts + let mut can_clear_modifiers_shortcut = true; if !shortcuts_inhibited { + let modifiers_queue = userdata.get::().unwrap(); for (binding, action) in data.common.config.static_conf.key_bindings.iter() { - if state == KeyState::Pressed - && binding.modifiers == *modifiers - && handle.raw_syms().contains(&binding.key) + let modifiers_bypass = binding.key.is_none() + && state == KeyState::Released + && binding.modifiers != *modifiers + && modifiers_queue.take(binding); + + if !modifiers_bypass && binding.key.is_none() && state == KeyState::Pressed && binding.modifiers == *modifiers { + modifiers_queue.set(binding.clone()); + can_clear_modifiers_shortcut = false; + } + + if ( + binding.key.is_some() + && state == KeyState::Pressed + && handle.raw_syms().contains(&binding.key.unwrap()) + && binding.modifiers == *modifiers + ) || modifiers_bypass { + modifiers_queue.clear(); userdata .get::() .unwrap() - .add(&handle); - return FilterResult::Intercept(Some( + .add(&handle, None); + return FilterResult::Intercept(Some(( action.clone(), - )); + binding.clone(), + ))); } } } + if can_clear_modifiers_shortcut { + userdata.get::().unwrap().clear(); + } + + // keys are passed through to apps FilterResult::Forward }, ) .flatten() { - self.handle_action(action, seat, serial, time) + self.handle_action(action, &seat, serial, time, pattern, None) } - break; - } } } InputEvent::PointerMotion { event, .. } => { use smithay::backend::input::PointerMotionEvent; - let device = event.device(); - for seat in self.common.seats().cloned().collect::>().iter() { - let userdata = seat.user_data(); - let devices = userdata.get::().unwrap(); - if devices.has_device(&device) { - let current_output = seat.active_output(); - - let mut position = seat.get_pointer().unwrap().current_location(); - position += event.delta(); - - let output = self - .common - .shell - .outputs() - .find(|output| output.geometry().to_f64().contains(position)) - .cloned() - .unwrap_or(current_output.clone()); + if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() { + let current_output = seat.active_output(); + + let mut position = seat.get_pointer().unwrap().current_location().as_global(); + + let overview = self.common.shell.overview_mode(); + let workspace = self.common.shell.workspaces.active_mut(¤t_output); + let under = State::surface_under( + position, + ¤t_output, + &self.common.shell.override_redirect_windows, + overview.0.clone(), + workspace, + self.common.session_lock.as_ref(), + ) + .map(|(target, pos)| (target, pos.as_logical())); + + let ptr = seat.get_pointer().unwrap(); + + let mut pointer_locked = false; + let mut pointer_confined = false; + let mut confine_region = None; + if let Some((surface, surface_loc)) = under + .as_ref() + .and_then(|(target, l)| Some((target.wl_surface()?, l))) + { + with_pointer_constraint(&surface, &ptr, |constraint| match constraint { + Some(constraint) if constraint.is_active() => { + // Constraint does not apply if not within region + if !constraint.region().map_or(true, |x| { + x.contains(ptr.current_location().to_i32_round() - *surface_loc) + }) { + return; + } + match &*constraint { + PointerConstraint::Locked(_locked) => { + pointer_locked = true; + } + PointerConstraint::Confined(confine) => { + pointer_confined = true; + confine_region = confine.region().cloned(); + } + } + } + _ => {} + }); + } + + ptr.relative_motion( + self, + under.clone(), + &RelativeMotionEvent { + delta: event.delta(), + delta_unaccel: event.delta_unaccel(), + utime: event.time(), + }, + ); + + if pointer_locked { + ptr.frame(self); + return; + } + + position += event.delta().as_global(); + + let output = self + .common + .shell + .outputs() + .find(|output| output.geometry().to_f64().contains(position)) + .cloned() + .unwrap_or(current_output.clone()); + + if ptr.is_grabbed() + && seat + .user_data() + .get::() + .map(|marker| marker.get()) + .unwrap_or(false) + { if output != current_output { - for session in sessions_for_output(&self.common, ¤t_output) { - session.cursor_leave(seat, InputType::Pointer); + ptr.frame(self); + return; + } + } + + let output_geometry = output.geometry(); + + let workspace = self.common.shell.workspaces.active_mut(&output); + let new_under = State::surface_under( + position, + &output, + &self.common.shell.override_redirect_windows, + overview.0, + workspace, + self.common.session_lock.as_ref(), + ) + .map(|(target, pos)| (target, pos.as_logical())); + + position.x = position.x.clamp( + output_geometry.loc.x as f64, + (output_geometry.loc.x + output_geometry.size.w) as f64, + ); + position.y = position.y.clamp( + output_geometry.loc.y as f64, + (output_geometry.loc.y + output_geometry.size.h) as f64, + ); + + // If confined, don't move pointer if it would go outside surface or region + if pointer_confined { + if let Some((surface, surface_loc)) = &under { + if new_under.as_ref().and_then(|(under, _)| under.wl_surface()) + != surface.wl_surface() + { + ptr.frame(self); + return; } + if let PointerFocusTarget::Element(element) = surface { + //if !element.is_in_input_region(&(position.to_i32_round() - *surface_loc).to_f64()) { + if !element.is_in_input_region( + &(position.as_logical() - surface_loc.to_f64()), + ) { + ptr.frame(self); + return; + } + } + if let Some(region) = confine_region { + if !region + .contains(position.as_logical().to_i32_round() - *surface_loc) + { + ptr.frame(self); + return; + } + } + } + } - for session in sessions_for_output(&self.common, &output) { - session.cursor_enter(seat, InputType::Pointer); + let serial = SERIAL_COUNTER.next_serial(); + ptr.motion( + self, + under, + &MotionEvent { + location: position.as_logical(), + serial, + time: event.time_msec(), + }, + ); + ptr.frame(self); + + // If pointer is now in a constraint region, activate it + if let Some((under, surface_location)) = + new_under.and_then(|(target, loc)| Some((target.wl_surface()?, loc))) + { + with_pointer_constraint(&under, &ptr, |constraint| match constraint { + Some(constraint) if !constraint.is_active() => { + let region = match &*constraint { + PointerConstraint::Locked(locked) => locked.region(), + PointerConstraint::Confined(confined) => confined.region(), + }; + let point = + ptr.current_location().to_i32_round() - surface_location; + if region.map_or(true, |region| region.contains(point)) { + constraint.activate(); + } } + _ => {} + }); + } - seat.set_active_output(&output); + if output != current_output { + for session in sessions_for_output(&self.common, ¤t_output) { + session.cursor_leave(&seat, InputType::Pointer); } - let output_geometry = output.geometry(); - - position.x = (output_geometry.loc.x as f64) - .max(position.x) - .min((output_geometry.loc.x + output_geometry.size.w) as f64); - position.y = (output_geometry.loc.y as f64) - .max(position.y) - .min((output_geometry.loc.y + output_geometry.size.h) as f64); - - let serial = SERIAL_COUNTER.next_serial(); - let relative_pos = self.common.shell.map_global_to_space(position, &output); - let workspace = self.common.shell.active_space(&output); - let under = State::surface_under( - position, - relative_pos, - &output, - output_geometry, - &self.common.shell.override_redirect_windows, - &workspace, - ); for session in sessions_for_output(&self.common, &output) { - if let Some((geometry, offset)) = seat.cursor_geometry( - position.to_buffer( - output.current_scale().fractional_scale(), - output.current_transform(), - &output.geometry().size.to_f64(), - ), - self.common.clock.now(), - ) { - session.cursor_info(seat, InputType::Pointer, geometry, offset); - } + session.cursor_enter(&seat, InputType::Pointer); } - let ptr = seat.get_pointer().unwrap(); - ptr.motion( - self, - under.clone(), - &MotionEvent { - location: position, - serial, - time: event.time_msec(), - }, - ); - ptr.relative_motion( - self, - under, - &RelativeMotionEvent { - delta: event.delta(), - delta_unaccel: event.delta_unaccel(), - utime: event.time(), - }, - ); - #[cfg(feature = "debug")] - if self.common.seats().position(|x| x == seat).unwrap() == 0 { - let location = if let Some(output) = self.common.shell.outputs.first() { - self.common - .shell - .map_global_to_space(position, output) - .to_i32_round() - } else { - position.to_i32_round() - }; + + seat.set_active_output(&output); + } + + for session in sessions_for_output(&self.common, &output) { + if let Some((geometry, offset)) = seat.cursor_geometry( + position.as_logical().to_buffer( + output.current_scale().fractional_scale(), + output.current_transform(), + &output_geometry.size.to_f64().as_logical(), + ), + self.common.clock.now(), + ) { + session.cursor_info(&seat, InputType::Pointer, geometry, offset); + } + } + #[cfg(feature = "debug")] + if self.common.seats().position(|x| x == &seat).unwrap() == 0 { + if let Some(output) = self.common.shell.outputs().next() { + let location = position.to_local(&output).to_i32_round().as_logical(); self.common.egui.state.handle_pointer_motion(location); } - break; } } } InputEvent::PointerMotionAbsolute { event, .. } => { - let device = event.device(); - for seat in self.common.seats().cloned().collect::>().iter() { - let userdata = seat.user_data(); - let devices = userdata.get::().unwrap(); - if devices.has_device(&device) { - let output = seat.active_output(); - let geometry = output.geometry(); - let position = geometry.loc.to_f64() - + smithay::backend::input::AbsolutePositionEvent::position_transformed( - &event, - geometry.size, - ); - let relative_pos = self.common.shell.map_global_to_space(position, &output); - let workspace = self.common.shell.active_space(&output); - let serial = SERIAL_COUNTER.next_serial(); - let under = State::surface_under( - position, - relative_pos, - &output, - geometry, - &self.common.shell.override_redirect_windows, - &workspace, - ); + if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() { + let output = seat.active_output(); + let geometry = output.geometry(); + let position = geometry.loc.to_f64() + + smithay::backend::input::AbsolutePositionEvent::position_transformed( + &event, + geometry.size.as_logical(), + ) + .as_global(); + let overview = self.common.shell.overview_mode(); + let workspace = self.common.shell.workspaces.active_mut(&output); + let serial = SERIAL_COUNTER.next_serial(); + let under = State::surface_under( + position, + &output, + &self.common.shell.override_redirect_windows, + overview.0, + workspace, + self.common.session_lock.as_ref(), + ) + .map(|(target, pos)| (target, pos.as_logical())); - for session in sessions_for_output(&self.common, &output) { - if let Some((geometry, offset)) = seat.cursor_geometry( - position.to_buffer( - output.current_scale().fractional_scale(), - output.current_transform(), - &output.geometry().size.to_f64(), - ), - self.common.clock.now(), - ) { - session.cursor_info(seat, InputType::Pointer, geometry, offset); - } + for session in sessions_for_output(&self.common, &output) { + if let Some((geometry, offset)) = seat.cursor_geometry( + position.as_logical().to_buffer( + output.current_scale().fractional_scale(), + output.current_transform(), + &geometry.size.to_f64().as_logical(), + ), + self.common.clock.now(), + ) { + session.cursor_info(&seat, InputType::Pointer, geometry, offset); } - seat.get_pointer().unwrap().motion( - self, - under, - &MotionEvent { - location: position, - serial, - time: event.time_msec(), - }, - ); - #[cfg(feature = "debug")] - if self.common.seats().position(|x| x == seat).unwrap() == 0 { - let location = if let Some(output) = self.common.shell.outputs.first() { - self.common - .shell - .map_global_to_space(position, output) - .to_i32_round() - } else { - position.to_i32_round() - }; + } + let ptr = seat.get_pointer().unwrap(); + ptr.motion( + self, + under, + &MotionEvent { + location: position.as_logical(), + serial, + time: event.time_msec(), + }, + ); + ptr.frame(self); + #[cfg(feature = "debug")] + if self.common.seats().position(|x| x == &seat).unwrap() == 0 { + if let Some(output) = self.common.shell.outputs().next() { + let location = position.to_local(&output).to_i32_round().as_logical(); self.common.egui.state.handle_pointer_motion(location); } - - break; } } } InputEvent::PointerButton { event, .. } => { use smithay::backend::input::{ButtonState, PointerButtonEvent}; - let device = event.device(); - for seat in self.common.seats().cloned().collect::>().iter() { - let userdata = seat.user_data(); - let devices = userdata.get::().unwrap(); - if devices.has_device(&device) { - #[cfg(feature = "debug")] - if self.common.seats().position(|x| x == seat).unwrap() == 0 - && self.common.egui.active - { - if self.common.egui.state.wants_pointer() { - if let Some(button) = event.button() { - self.common.egui.state.handle_pointer_button( - button, - event.state() == ButtonState::Pressed, - ); - } - break; + if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() { + #[cfg(feature = "debug")] + if self.common.seats().position(|x| x == &seat).unwrap() == 0 + && self.common.egui.active + { + if self.common.egui.state.wants_pointer() { + if let Some(button) = event.button() { + self.common.egui.state.handle_pointer_button( + button, + event.state() == ButtonState::Pressed, + ); } + return; } + } - let serial = SERIAL_COUNTER.next_serial(); - let button = event.button_code(); - if event.state() == ButtonState::Pressed { - // change the keyboard focus unless the pointer or keyboard is grabbed - // We test for any matching surface type here but always use the root - // (in case of a window the toplevel) surface for the focus. - // see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/294 - if !seat.get_pointer().unwrap().is_grabbed() - && !seat.get_keyboard().map(|k| k.is_grabbed()).unwrap_or(false) - { - let output = seat.active_output(); - let pos = seat.get_pointer().unwrap().current_location(); - let relative_pos = - self.common.shell.map_global_to_space(pos, &output); - let workspace = self.common.shell.active_space_mut(&output); - let layers = layer_map_for_output(&output); - let mut under = None; + let serial = SERIAL_COUNTER.next_serial(); + let button = event.button_code(); + if event.state() == ButtonState::Pressed { + // change the keyboard focus unless the pointer or keyboard is grabbed + // We test for any matching surface type here but always use the root + // (in case of a window the toplevel) surface for the focus. + // see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/294 + if !seat.get_pointer().unwrap().is_grabbed() + && !seat.get_keyboard().map(|k| k.is_grabbed()).unwrap_or(false) + { + let output = seat.active_output(); + let pos = seat.get_pointer().unwrap().current_location().as_global(); + let relative_pos = pos.to_local(&output); + let overview = self.common.shell.overview_mode(); + let workspace = self.common.shell.active_space_mut(&output); + let mut under = None; - if let Some(window) = workspace.get_fullscreen(&output) { - if let Some(layer) = - layers.layer_under(WlrLayer::Overlay, relative_pos) + if let Some(session_lock) = self.common.session_lock.as_ref() { + under = session_lock + .surfaces + .get(&output) + .map(|lock| lock.clone().into()); + } else if let Some(window) = workspace.get_fullscreen() { + let layers = layer_map_for_output(&output); + if let Some(layer) = + layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) + { + let layer_loc = layers.layer_geometry(layer).unwrap().loc; + if layer.can_receive_keyboard_focus() + && layer + .surface_under( + relative_pos.as_logical() - layer_loc.to_f64(), + WindowSurfaceType::ALL, + ) + .is_some() { - let layer_loc = layers.layer_geometry(layer).unwrap().loc; - if layer.can_receive_keyboard_focus() - && layer - .surface_under( - relative_pos - layer_loc.to_f64(), - WindowSurfaceType::ALL, - ) - .is_some() - { - under = Some(layer.clone().into()); - } - } else { - under = Some(window.clone().into()); + under = Some(layer.clone().into()); } } else { + under = Some(window.clone().into()); + } + } else { + let done = { + let layers = layer_map_for_output(&output); if let Some(layer) = layers - .layer_under(WlrLayer::Overlay, relative_pos) - .or_else(|| layers.layer_under(WlrLayer::Top, relative_pos)) + .layer_under(WlrLayer::Overlay, relative_pos.as_logical()) + .or_else(|| { + layers.layer_under( + WlrLayer::Top, + relative_pos.as_logical(), + ) + }) { let layer_loc = layers.layer_geometry(layer).unwrap().loc; if layer.can_receive_keyboard_focus() && layer .surface_under( - relative_pos - layer_loc.to_f64(), + relative_pos.as_logical() - layer_loc.to_f64(), WindowSurfaceType::ALL, ) .is_some() { under = Some(layer.clone().into()); } - } else if let Some((window, _)) = - workspace.element_under(relative_pos) - { - under = Some(window.clone().into()); - } else if let Some(layer) = layers - .layer_under(WlrLayer::Bottom, pos) - .or_else(|| layers.layer_under(WlrLayer::Background, pos)) + true + } else { + false + } + }; + if !done { + if let Some((target, _)) = + workspace.element_under(pos, overview.0) { - let layer_loc = layers.layer_geometry(layer).unwrap().loc; - if layer.can_receive_keyboard_focus() - && layer - .surface_under( - relative_pos - layer_loc.to_f64(), - WindowSurfaceType::ALL, + under = Some(target); + } else { + let layers = layer_map_for_output(&output); + if let Some(layer) = layers + .layer_under( + WlrLayer::Bottom, + relative_pos.as_logical(), + ) + .or_else(|| { + layers.layer_under( + WlrLayer::Background, + relative_pos.as_logical(), ) - .is_some() + }) { - under = Some(layer.clone().into()); - } - }; + let layer_loc = + layers.layer_geometry(layer).unwrap().loc; + if layer.can_receive_keyboard_focus() + && layer + .surface_under( + relative_pos.as_logical() + - layer_loc.to_f64(), + WindowSurfaceType::ALL, + ) + .is_some() + { + under = Some(layer.clone().into()); + } + }; + } } - - Common::set_focus(self, under.as_ref(), seat, Some(serial)); } - }; - seat.get_pointer().unwrap().button( - self, - &ButtonEvent { - button, - state: event.state(), - serial, - time: event.time_msec(), - }, - ); - break; - } + Common::set_focus( + self, + under.and_then(|target| target.try_into().ok()).as_ref(), + &seat, + Some(serial), + ); + } + } else { + if let OverviewMode::Started(Trigger::Pointer(action_button), _) = + self.common.shell.overview_mode().0 + { + if action_button == button { + self.common + .shell + .set_overview_mode(None, self.common.event_loop_handle.clone()); + } + } + }; + let ptr = seat.get_pointer().unwrap(); + ptr.button( + self, + &ButtonEvent { + button, + state: event.state(), + serial, + time: event.time_msec(), + }, + ); + ptr.frame(self); } } InputEvent::PointerAxis { event, .. } => { - let device = event.device(); - for seat in self.common.seats().cloned().collect::>().iter() { + #[allow(deprecated)] + let scroll_factor = if let Some(event) = + ::downcast_ref::(&event) + { + self.common.config.scroll_factor(&event.device()) + } else { + 1.0 + }; + + if let Some(seat) = self.common.seat_with_device(&event.device()) { #[cfg(feature = "debug")] if self.common.seats().position(|x| x == seat).unwrap() == 0 && self.common.egui.active @@ -594,53 +994,175 @@ impl State { .or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0)) .unwrap_or(0.0), ); - break; + return; } } - let userdata = seat.user_data(); - let devices = userdata.get::().unwrap(); - if devices.has_device(&device) { - let horizontal_amount = - event.amount(Axis::Horizontal).unwrap_or_else(|| { - event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0 - }); - let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| { - event.amount_discrete(Axis::Vertical).unwrap_or(0.0) * 3.0 - }); - let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal); - let vertical_amount_discrete = event.amount_discrete(Axis::Vertical); + let horizontal_amount = event.amount(Axis::Horizontal).unwrap_or_else(|| { + event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0 + }); + let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| { + event.amount_discrete(Axis::Vertical).unwrap_or(0.0) * 3.0 + }); + let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal); + let vertical_amount_discrete = event.amount_discrete(Axis::Vertical); - { - let mut frame = - AxisFrame::new(event.time_msec()).source(event.source()); - if horizontal_amount != 0.0 { - frame = frame.value(Axis::Horizontal, horizontal_amount); - if let Some(discrete) = horizontal_amount_discrete { - frame = frame.discrete(Axis::Horizontal, discrete as i32); - } - } else if event.source() == AxisSource::Finger { - frame = frame.stop(Axis::Horizontal); + { + let mut frame = AxisFrame::new(event.time_msec()).source(event.source()); + if horizontal_amount != 0.0 { + frame = + frame.value(Axis::Horizontal, scroll_factor * horizontal_amount); + if let Some(discrete) = horizontal_amount_discrete { + frame = frame.discrete(Axis::Horizontal, discrete as i32); } - if vertical_amount != 0.0 { - frame = frame.value(Axis::Vertical, vertical_amount); - if let Some(discrete) = vertical_amount_discrete { - frame = frame.discrete(Axis::Vertical, discrete as i32); - } - } else if event.source() == AxisSource::Finger { - frame = frame.stop(Axis::Vertical); + } else if event.source() == AxisSource::Finger { + frame = frame.stop(Axis::Horizontal); + } + if vertical_amount != 0.0 { + frame = frame.value(Axis::Vertical, scroll_factor * vertical_amount); + if let Some(discrete) = vertical_amount_discrete { + frame = frame.discrete(Axis::Vertical, discrete as i32); } - seat.get_pointer().unwrap().axis(self, frame); + } else if event.source() == AxisSource::Finger { + frame = frame.stop(Axis::Vertical); } - break; + let ptr = seat.get_pointer().unwrap(); + ptr.axis(self, frame); + ptr.frame(self); } } } + InputEvent::GestureSwipeBegin { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let serial = SERIAL_COUNTER.next_serial(); + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_swipe_begin( + self, + &GestureSwipeBeginEvent { + serial, + time: event.time_msec(), + fingers: event.fingers(), + }, + ); + } + } + InputEvent::GestureSwipeUpdate { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_swipe_update( + self, + &GestureSwipeUpdateEvent { + time: event.time_msec(), + delta: event.delta(), + }, + ); + } + } + InputEvent::GestureSwipeEnd { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let serial = SERIAL_COUNTER.next_serial(); + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_swipe_end( + self, + &GestureSwipeEndEvent { + serial, + time: event.time_msec(), + cancelled: event.cancelled(), + }, + ); + } + } + InputEvent::GesturePinchBegin { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let serial = SERIAL_COUNTER.next_serial(); + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_pinch_begin( + self, + &GesturePinchBeginEvent { + serial, + time: event.time_msec(), + fingers: event.fingers(), + }, + ); + } + } + InputEvent::GesturePinchUpdate { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_pinch_update( + self, + &GesturePinchUpdateEvent { + time: event.time_msec(), + delta: event.delta(), + scale: event.scale(), + rotation: event.rotation(), + }, + ); + } + } + InputEvent::GesturePinchEnd { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let serial = SERIAL_COUNTER.next_serial(); + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_pinch_end( + self, + &GesturePinchEndEvent { + serial, + time: event.time_msec(), + cancelled: event.cancelled(), + }, + ); + } + } + InputEvent::GestureHoldBegin { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let serial = SERIAL_COUNTER.next_serial(); + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_hold_begin( + self, + &GestureHoldBeginEvent { + serial, + time: event.time_msec(), + fingers: event.fingers(), + }, + ); + } + } + InputEvent::GestureHoldEnd { event, .. } => { + if let Some(seat) = self.common.seat_with_device(&event.device()) { + let serial = SERIAL_COUNTER.next_serial(); + let pointer = seat.get_pointer().unwrap(); + pointer.gesture_hold_end( + self, + &GestureHoldEndEvent { + serial, + time: event.time_msec(), + cancelled: event.cancelled(), + }, + ); + } + } _ => { /* TODO e.g. tablet or touch events */ } } } - fn handle_action(&mut self, action: Action, seat: &Seat, serial: Serial, time: u32) { + pub fn handle_action( + &mut self, + action: Action, + seat: &Seat, + serial: Serial, + time: u32, + pattern: KeyPattern, + direction: Option, + ) { + // TODO: Detect if started from login manager or tty, and only allow + // `Terminate` if it will return to login manager. + if self.common.session_lock.is_some() + && !matches!(action, Action::Terminate | Action::Debug) + { + return; + } + match action { Action::Terminate => { self.common.should_stop = true; @@ -688,9 +1210,16 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_add(1); - // TODO: Possibly move to next output, if idx to large - let _ = self.common.shell.activate(¤t_output, workspace); + if self + .common + .shell + .activate(¤t_output, workspace) + .is_err() + { + self.handle_action(Action::NextOutput, seat, serial, time, pattern, direction); + } } Action::PreviousWorkspace => { let current_output = seat.active_output(); @@ -699,9 +1228,23 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_sub(1); - // TODO: Possibly move to prev output, if idx < 0 - let _ = self.common.shell.activate(¤t_output, workspace); + if self + .common + .shell + .activate(¤t_output, workspace) + .is_err() + { + self.handle_action( + Action::PreviousOutput, + seat, + serial, + time, + pattern, + direction, + ); + } } Action::LastWorkspace => { let current_output = seat.active_output(); @@ -721,12 +1264,13 @@ impl State { Action::MoveToWorkspace(x) | Action::SendToWorkspace(x) => x - 1, _ => unreachable!(), }; - Shell::move_current_window( + let _ = Shell::move_current_window( self, seat, ¤t_output, (¤t_output, Some(workspace as usize)), follow, + None, ); } x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => { @@ -736,15 +1280,31 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_add(1); - // TODO: Possibly move to next output, if idx too large - Shell::move_current_window( + if Shell::move_current_window( self, seat, ¤t_output, (¤t_output, Some(workspace as usize)), matches!(x, Action::MoveToNextWorkspace), - ); + direction, + ) + .is_err() + { + self.handle_action( + if matches!(x, Action::MoveToNextWorkspace) { + Action::MoveToNextOutput + } else { + Action::SendToNextOutput + }, + seat, + serial, + time, + pattern, + direction, + ) + } } x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => { let current_output = seat.active_output(); @@ -753,15 +1313,32 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_sub(1); // TODO: Possibly move to prev output, if idx < 0 - Shell::move_current_window( + if Shell::move_current_window( self, seat, ¤t_output, (¤t_output, Some(workspace as usize)), matches!(x, Action::MoveToPreviousWorkspace), - ); + direction, + ) + .is_err() + { + self.handle_action( + if matches!(x, Action::MoveToNextWorkspace) { + Action::MoveToPreviousOutput + } else { + Action::SendToPreviousOutput + }, + seat, + serial, + time, + pattern, + direction, + ) + } } x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => { let current_output = seat.active_output(); @@ -771,173 +1348,216 @@ impl State { .workspaces .len(¤t_output) .saturating_sub(1); - Shell::move_current_window( + let _ = Shell::move_current_window( self, seat, ¤t_output, (¤t_output, Some(workspace as usize)), matches!(x, Action::MoveToLastWorkspace), + None, ); } Action::NextOutput => { let current_output = seat.active_output(); - if let Some(next_output) = self + let next_output = self .common .shell - .outputs - .iter() + .outputs() .skip_while(|o| *o != ¤t_output) .skip(1) .next() - .cloned() - { - let idx = self.common.shell.workspaces.active_num(&next_output); - if let Some(new_pos) = self.common.shell.activate(&next_output, idx) { - seat.set_active_output(&next_output); - if let Some(ptr) = seat.get_pointer() { - ptr.motion( - self, - None, - &MotionEvent { - location: new_pos.to_f64(), - serial, - time, - }, - ); + .cloned(); + if let Some(next_output) = next_output { + let idx = self.common.shell.workspaces.active_num(&next_output).1; + match self.common.shell.activate(&next_output, idx) { + Ok(Some(new_pos)) => { + seat.set_active_output(&next_output); + if let Some(ptr) = seat.get_pointer() { + ptr.motion( + self, + None, + &MotionEvent { + location: new_pos.to_f64().as_logical(), + serial, + time, + }, + ); + ptr.frame(self); + } + } + Ok(None) => { + seat.set_active_output(&next_output); } + _ => {} } } } Action::PreviousOutput => { let current_output = seat.active_output(); - if let Some(prev_output) = self + let prev_output = self .common .shell - .outputs - .iter() + .outputs() .rev() .skip_while(|o| *o != ¤t_output) .skip(1) .next() - .cloned() - { - let idx = self.common.shell.workspaces.active_num(&prev_output); - if let Some(new_pos) = self.common.shell.activate(&prev_output, idx) { - seat.set_active_output(&prev_output); - if let Some(ptr) = seat.get_pointer() { - ptr.motion( - self, - None, - &MotionEvent { - location: new_pos.to_f64(), - serial, - time, - }, - ); + .cloned(); + if let Some(prev_output) = prev_output { + let idx = self.common.shell.workspaces.active_num(&prev_output).1; + match self.common.shell.activate(&prev_output, idx) { + Ok(Some(new_pos)) => { + seat.set_active_output(&prev_output); + if let Some(ptr) = seat.get_pointer() { + ptr.motion( + self, + None, + &MotionEvent { + location: new_pos.to_f64().as_logical(), + serial, + time, + }, + ); + ptr.frame(self); + } + } + Ok(None) => { + seat.set_active_output(&prev_output); } + _ => {} } } } - Action::MoveToNextOutput => { + x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => { let current_output = seat.active_output(); - if let Some(next_output) = self + let next_output = self .common .shell - .outputs - .iter() + .outputs() .skip_while(|o| *o != ¤t_output) .skip(1) .next() - .cloned() - { - if let Some(new_pos) = Shell::move_current_window( + .cloned(); + if let Some(next_output) = next_output { + if let Ok(Some(new_pos)) = Shell::move_current_window( self, seat, ¤t_output, (&next_output, None), - true, + matches!(x, Action::MoveToNextOutput), + direction, ) { if let Some(ptr) = seat.get_pointer() { ptr.motion( self, None, &MotionEvent { - location: new_pos.to_f64(), + location: new_pos.to_f64().as_logical(), serial, time, }, ); + ptr.frame(self); } } } } - Action::MoveToPreviousOutput => { + x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => { let current_output = seat.active_output(); - if let Some(prev_output) = self + let prev_output = self .common .shell - .outputs - .iter() + .outputs() .rev() .skip_while(|o| *o != ¤t_output) .skip(1) .next() - .cloned() - { - if let Some(new_pos) = Shell::move_current_window( + .cloned(); + if let Some(prev_output) = prev_output { + if let Ok(Some(new_pos)) = Shell::move_current_window( self, seat, ¤t_output, (&prev_output, None), - true, + matches!(x, Action::MoveToPreviousOutput), + direction, ) { if let Some(ptr) = seat.get_pointer() { ptr.motion( self, None, &MotionEvent { - location: new_pos.to_f64(), + location: new_pos.to_f64().as_logical(), serial, time, }, ); + ptr.frame(self); } } } } Action::Focus(focus) => { let current_output = seat.active_output(); + let overview = self.common.shell.overview_mode().0; let workspace = self.common.shell.active_space_mut(¤t_output); - let focus_stack = workspace.focus_stack.get(seat); - let mut result = workspace - .tiling_layer - .next_focus(focus, seat, focus_stack.iter()); - if workspace.get_fullscreen(¤t_output).is_some() { - result = FocusResult::None; - } + let result = workspace.next_focus( + focus, + seat, + match overview { + OverviewMode::Started(Trigger::KeyboardSwap(_, desc), _) => Some(desc), + _ => None, + }, + ); match result { FocusResult::None => { - // TODO: Handle Workspace orientation - match focus { - FocusDirection::Left => { - self.handle_action(Action::PreviousWorkspace, seat, serial, time) - } - FocusDirection::Right => { - self.handle_action(Action::NextWorkspace, seat, serial, time) - } - FocusDirection::Up => { - self.handle_action(Action::PreviousOutput, seat, serial, time) - } - FocusDirection::Down => { - self.handle_action(Action::NextOutput, seat, serial, time) - } + match (focus, self.common.config.workspace.workspace_layout) { + (FocusDirection::Left, WorkspaceLayout::Horizontal) + | (FocusDirection::Up, WorkspaceLayout::Vertical) => self + .handle_action( + Action::PreviousWorkspace, + seat, + serial, + time, + pattern, + direction, + ), + (FocusDirection::Right, WorkspaceLayout::Horizontal) + | (FocusDirection::Down, WorkspaceLayout::Vertical) => self + .handle_action( + Action::NextWorkspace, + seat, + serial, + time, + pattern, + direction, + ), + (FocusDirection::Left, WorkspaceLayout::Vertical) + | (FocusDirection::Up, WorkspaceLayout::Horizontal) => self + .handle_action( + Action::PreviousOutput, + seat, + serial, + time, + pattern, + direction, + ), + (FocusDirection::Right, WorkspaceLayout::Vertical) + | (FocusDirection::Down, WorkspaceLayout::Horizontal) => self + .handle_action( + Action::NextOutput, + seat, + serial, + time, + pattern, + direction, + ), _ => {} } } FocusResult::Handled => {} FocusResult::Some(target) => { - std::mem::drop(focus_stack); Common::set_focus(self, Some(&target), seat, None); } } @@ -945,57 +1565,120 @@ impl State { Action::Move(direction) => { let current_output = seat.active_output(); let workspace = self.common.shell.active_space_mut(¤t_output); - if workspace.get_fullscreen(¤t_output).is_some() { - return; // TODO, is this what we want? How do we indicate the switch? - } - if let Some(_move_further) = - workspace.tiling_layer.move_current_window(direction, seat) - { - // TODO: Handle Workspace orientation - // TODO: Being able to move Groups (move_further should be KeyboardFocusTarget instead) - match direction { - Direction::Left => { - self.handle_action(Action::MoveToPreviousWorkspace, seat, serial, time) - } - Direction::Right => { - self.handle_action(Action::MoveToNextWorkspace, seat, serial, time) - } - Direction::Up => { - self.handle_action(Action::MoveToPreviousOutput, seat, serial, time) + match workspace.move_current_element(direction, seat) { + MoveResult::MoveFurther(_move_further) => { + match (direction, self.common.config.workspace.workspace_layout) { + (Direction::Left, WorkspaceLayout::Horizontal) + | (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action( + Action::MoveToPreviousWorkspace, + seat, + serial, + time, + pattern, + Some(direction), + ), + (Direction::Right, WorkspaceLayout::Horizontal) + | (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action( + Action::MoveToNextWorkspace, + seat, + serial, + time, + pattern, + Some(direction), + ), + (Direction::Left, WorkspaceLayout::Vertical) + | (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action( + Action::MoveToPreviousOutput, + seat, + serial, + time, + pattern, + Some(direction), + ), + (Direction::Right, WorkspaceLayout::Vertical) + | (Direction::Down, WorkspaceLayout::Horizontal) => self.handle_action( + Action::MoveToNextOutput, + seat, + serial, + time, + pattern, + Some(direction), + ), } - Direction::Down => { - self.handle_action(Action::MoveToNextOutput, seat, serial, time) + } + MoveResult::ShiftFocus(shift) => { + Common::set_focus(self, Some(&shift), seat, None); + } + _ => { + if let Some(focused_window) = workspace.focus_stack.get(seat).last() { + if workspace.is_tiled(focused_window) { + self.common.shell.set_overview_mode( + Some(Trigger::KeyboardMove(pattern.modifiers)), + self.common.event_loop_handle.clone(), + ); + } } } } } + Action::SwapWindow => { + let current_output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(¤t_output); + if workspace.get_fullscreen().is_some() { + return; // TODO, is this what we want? Maybe disengage fullscreen instead? + } + + let keyboard_handle = seat.get_keyboard().unwrap(); + if let Some(focus) = keyboard_handle.current_focus() { + if let Some(descriptor) = workspace.node_desc(focus) { + let grab = SwapWindowGrab::new(seat.clone(), descriptor.clone()); + keyboard_handle.set_grab(grab, serial); + self.common.shell.set_overview_mode( + Some(Trigger::KeyboardSwap(pattern, descriptor)), + self.common.event_loop_handle.clone(), + ); + } + } + } Action::Maximize => { let current_output = seat.active_output(); let workspace = self.common.shell.active_space_mut(¤t_output); let focus_stack = workspace.focus_stack.get(seat); let focused_window = focus_stack.last(); if let Some(window) = focused_window.map(|f| f.active_window()) { - workspace.maximize_toggle(&window, ¤t_output); + workspace.maximize_toggle(&window); + } + } + Action::Resizing(direction) => self.common.shell.set_resize_mode( + Some((pattern, direction)), + &self.common.config, + self.common.event_loop_handle.clone(), + ), + Action::_ResizingInternal(direction, edge, state) => { + if state == KeyState::Pressed { + self.common.shell.resize(seat, direction, edge); + } else { + self.common.shell.finish_resize(direction, edge); } } Action::ToggleOrientation => { let output = seat.active_output(); let workspace = self.common.shell.active_space_mut(&output); - let focus_stack = workspace.focus_stack.get(seat); + workspace.tiling_layer.update_orientation(None, &seat); + } + Action::Orientation(orientation) => { + let output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(&output); workspace .tiling_layer - .update_orientation(None, &seat, focus_stack.iter()); + .update_orientation(Some(orientation), &seat); } - Action::Orientation(orientation) => { + Action::ToggleStacking => { let output = seat.active_output(); let workspace = self.common.shell.active_space_mut(&output); - let focus_stack = workspace.focus_stack.get(seat); - workspace.tiling_layer.update_orientation( - Some(orientation), - &seat, - focus_stack.iter(), - ); + let focus_stack = workspace.focus_stack.get_mut(seat); + workspace.tiling_layer.toggle_stacking(seat, focus_stack); } Action::ToggleTiling => { let output = seat.active_output(); @@ -1008,89 +1691,140 @@ impl State { workspace.toggle_floating_window(seat); } Action::Spawn(command) => { - if let Err(err) = std::process::Command::new("/bin/sh") - .arg("-c") + let (token, data) = self + .common + .shell + .xdg_activation_state + .create_external_token(None); + let (token, data) = (token.clone(), data.clone()); + + let seat = self.common.last_active_seat(); + let output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(&output); + workspace.pending_tokens.insert(token.clone()); + let handle = workspace.handle; + data.user_data + .insert_if_missing(move || ActivationContext::Workspace(handle)); + + let wayland_display = self.common.socket.clone(); + let display = self + .common + .xwayland_state + .as_ref() + .map(|s| format!(":{}", s.display)) + .unwrap_or_default(); + + let mut cmd = std::process::Command::new("/bin/sh"); + + cmd.arg("-c") .arg(command.clone()) - .env("WAYLAND_DISPLAY", &self.common.socket) - .env( - "DISPLAY", - &self - .common - .xwayland_state - .as_ref() - .map(|s| format!(":{}", s.display)) - .unwrap_or(String::new()), - ) - .env_remove("COSMIC_SESSION_SOCK") - .spawn() - { - warn!(?err, "Failed to spawn \"{}\"", command); - } + .env("WAYLAND_DISPLAY", &wayland_display) + .env("DISPLAY", &display) + .env("XDG_ACTIVATION_TOKEN", &*token) + .env("DESKTOP_STARTUP_ID", &*token) + .env_remove("COSMIC_SESSION_SOCK"); + + std::thread::spawn(move || match cmd.spawn() { + Ok(mut child) => { + let _res = child.wait(); + } + Err(err) => { + tracing::warn!(?err, "Failed to spawn \"{}\"", command); + } + }); } } } pub fn surface_under( - global_pos: Point, - relative_pos: Point, + global_pos: Point, output: &Output, - output_geo: Rectangle, override_redirect_windows: &[X11Surface], - workspace: &Workspace, - ) -> Option<(PointerFocusTarget, Point)> { - let layers = layer_map_for_output(output); - if let Some(window) = workspace.get_fullscreen(output) { - if let Some(layer) = layers.layer_under(WlrLayer::Overlay, relative_pos) { + overview: OverviewMode, + workspace: &mut Workspace, + session_lock: Option<&SessionLock>, + ) -> Option<(PointerFocusTarget, Point)> { + let relative_pos = global_pos.to_local(output); + let output_geo = output.geometry(); + + if let Some(session_lock) = session_lock { + return session_lock.surfaces.get(output).map(|surface| { + ( + PointerFocusTarget::LockSurface(surface.clone()), + output_geo.loc, + ) + }); + } + + if let Some(window) = workspace.get_fullscreen() { + let layers = layer_map_for_output(output); + if let Some(layer) = layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) { let layer_loc = layers.layer_geometry(layer).unwrap().loc; if layer - .surface_under(relative_pos - layer_loc.to_f64(), WindowSurfaceType::ALL) + .surface_under( + relative_pos.as_logical() - layer_loc.to_f64(), + WindowSurfaceType::ALL, + ) .is_some() { - return Some((layer.clone().into(), output_geo.loc + layer_loc)); + return Some((layer.clone().into(), output_geo.loc + layer_loc.as_global())); } } - if let Some(or) = override_redirect_windows - .iter() - .find(|or| or.is_in_input_region(&(global_pos - or.geometry().loc.to_f64()))) - { - return Some((or.clone().into(), or.geometry().loc)); + if let Some(or) = override_redirect_windows.iter().find(|or| { + or.is_in_input_region(&(global_pos.as_logical() - or.geometry().loc.to_f64())) + }) { + return Some((or.clone().into(), or.geometry().loc.as_global())); } Some((window.clone().into(), output_geo.loc)) } else { - if let Some(layer) = layers - .layer_under(WlrLayer::Overlay, relative_pos) - .or_else(|| layers.layer_under(WlrLayer::Top, relative_pos)) { - let layer_loc = layers.layer_geometry(layer).unwrap().loc; - if layer - .surface_under(relative_pos - layer_loc.to_f64(), WindowSurfaceType::ALL) - .is_some() + let layers = layer_map_for_output(output); + if let Some(layer) = layers + .layer_under(WlrLayer::Overlay, relative_pos.as_logical()) + .or_else(|| layers.layer_under(WlrLayer::Top, relative_pos.as_logical())) { - return Some((layer.clone().into(), output_geo.loc + layer_loc)); + let layer_loc = layers.layer_geometry(layer).unwrap().loc; + if layer + .surface_under( + relative_pos.as_logical() - layer_loc.to_f64(), + WindowSurfaceType::ALL, + ) + .is_some() + { + return Some(( + layer.clone().into(), + output_geo.loc + layer_loc.as_global(), + )); + } } } - if let Some(or) = override_redirect_windows - .iter() - .find(|or| or.is_in_input_region(&(global_pos - or.geometry().loc.to_f64()))) - { - return Some((or.clone().into(), or.geometry().loc)); + if let Some(or) = override_redirect_windows.iter().find(|or| { + or.is_in_input_region(&(global_pos.as_logical() - or.geometry().loc.to_f64())) + }) { + return Some((or.clone().into(), or.geometry().loc.as_global())); } - if let Some((mapped, loc)) = workspace.element_under(relative_pos) { - return Some(( - mapped.clone().into(), - loc + (global_pos - relative_pos).to_i32_round(), - )); + if let Some((target, loc)) = workspace.element_under(global_pos, overview) { + return Some((target, loc)); } - if let Some(layer) = layers - .layer_under(WlrLayer::Bottom, relative_pos) - .or_else(|| layers.layer_under(WlrLayer::Background, relative_pos)) { - let layer_loc = layers.layer_geometry(layer).unwrap().loc; - if layer - .surface_under(relative_pos - layer_loc.to_f64(), WindowSurfaceType::ALL) - .is_some() + let layers = layer_map_for_output(output); + if let Some(layer) = layers + .layer_under(WlrLayer::Bottom, relative_pos.as_logical()) + .or_else(|| layers.layer_under(WlrLayer::Background, relative_pos.as_logical())) { - return Some((layer.clone().into(), output_geo.loc + layer_loc)); + let layer_loc = layers.layer_geometry(layer).unwrap().loc; + if layer + .surface_under( + relative_pos.as_logical() - layer_loc.to_f64(), + WindowSurfaceType::ALL, + ) + .is_some() + { + return Some(( + layer.clone().into(), + output_geo.loc + layer_loc.as_global(), + )); + } } } None @@ -1100,21 +1834,27 @@ impl State { fn sessions_for_output(state: &Common, output: &Output) -> impl Iterator { let workspace = state.shell.active_space(&output); - let maybe_fullscreen = workspace.get_fullscreen(&output); + let maybe_fullscreen = workspace.get_fullscreen(); workspace .screencopy_sessions .iter() .map(|s| (&**s).clone()) .chain( maybe_fullscreen - .and_then(|w| w.user_data().get::()) - .map(|sessions| { - sessions - .0 - .borrow() - .iter() - .map(|s| (&**s).clone()) - .collect::>() + .as_ref() + .and_then(|w| { + if let Some(sessions) = w.user_data().get::() { + Some( + sessions + .0 + .borrow() + .iter() + .map(|s| (&**s).clone()) + .collect::>(), + ) + } else { + None + } }) .into_iter() .flatten(), diff --git a/src/main.rs b/src/main.rs index 5e61523a..732998e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,15 +3,17 @@ use smithay::{ reexports::{ calloop::{generic::Generic, EventLoop, Interest, Mode, PostAction}, - wayland_server::Display, + wayland_server::{Display, DisplayHandle}, }, wayland::socket::ListeningSocketSource, }; use anyhow::{Context, Result}; -use std::{ffi::OsString, os::unix::prelude::AsRawFd, sync::Arc}; +use std::{ffi::OsString, sync::Arc}; use tracing::{error, info, warn}; +use crate::wayland::handlers::compositor::client_compositor_state; + pub mod backend; pub mod config; #[cfg(feature = "debug")] @@ -23,6 +25,7 @@ pub mod shell; pub mod state; #[cfg(feature = "systemd")] pub mod systemd; +pub mod theme; pub mod utils; pub mod wayland; pub mod xwayland; @@ -33,19 +36,18 @@ fn main() -> Result<()> { info!("Cosmic starting up!"); // init event loop - let mut event_loop = - EventLoop::try_new_high_precision().with_context(|| "Failed to initialize event loop")?; + let mut event_loop = EventLoop::try_new().with_context(|| "Failed to initialize event loop")?; // init wayland let (display, socket) = init_wayland_display(&mut event_loop)?; // init state let mut state = state::State::new( - &display.handle(), + &display, socket, event_loop.handle(), event_loop.get_signal(), ); // init backend - backend::init_backend_auto(&display.handle(), &mut event_loop, &mut state)?; + backend::init_backend_auto(&display, &mut event_loop, &mut state)?; // potentially tell systemd we are setup now #[cfg(feature = "systemd")] if let state::BackendData::Kms(_) = &state.backend { @@ -54,36 +56,47 @@ fn main() -> Result<()> { // potentially tell the session we are setup now session::setup_socket(event_loop.handle(), &state)?; - let mut data = state::Data { display, state }; + if let Err(err) = theme::watch_theme(event_loop.handle()) { + warn!(?err, "Failed to watch theme"); + } + // run the event loop - event_loop.run(None, &mut data, |data| { + event_loop.run(None, &mut state, |state| { // shall we shut down? - if data.state.common.shell.outputs().next().is_none() || data.state.common.should_stop { + if state.common.shell.outputs().next().is_none() || state.common.should_stop { info!("Shutting down"); - data.state.common.event_loop_signal.stop(); - data.state.common.event_loop_signal.wakeup(); + state.common.event_loop_signal.stop(); + state.common.event_loop_signal.wakeup(); return; } // trigger routines - data.state.common.shell.refresh(); - state::Common::refresh_focus(&mut data.state); + let clients = state.common.shell.update_animations(); + { + let dh = state.common.display_handle.clone(); + for client in clients.values() { + client_compositor_state(&client).blocker_cleared(state, &dh); + } + } + state.common.shell.refresh(); + state::Common::refresh_focus(state); // send out events - let _ = data.display.flush_clients(); + let _ = state.common.display_handle.flush_clients(); })?; // drop eventloop & state before logger std::mem::drop(event_loop); - std::mem::drop(data); + std::mem::drop(state); Ok(()) } fn init_wayland_display( - event_loop: &mut EventLoop, -) -> Result<(Display, OsString)> { - let mut display = Display::new().unwrap(); + event_loop: &mut EventLoop, +) -> Result<(DisplayHandle, OsString)> { + let display = Display::new().unwrap(); + let handle = display.handle(); let source = ListeningSocketSource::new_auto().unwrap(); let socket_name = source.socket_name().to_os_string(); @@ -91,13 +104,13 @@ fn init_wayland_display( event_loop .handle() - .insert_source(source, |client_stream, _, data| { - if let Err(err) = data.display.handle().insert_client( + .insert_source(source, |client_stream, _, state| { + if let Err(err) = state.common.display_handle.insert_client( client_stream, Arc::new(if cfg!(debug_assertions) { - data.state.new_privileged_client_state() + state.new_privileged_client_state() } else { - data.state.new_client_state() + state.new_client_state() }), ) { warn!(?err, "Error adding wayland client"); @@ -107,22 +120,20 @@ fn init_wayland_display( event_loop .handle() .insert_source( - Generic::new( - display.backend().poll_fd().as_raw_fd(), - Interest::READ, - Mode::Level, - ), - move |_, _, data: &mut state::Data| match data.display.dispatch_clients(&mut data.state) - { - Ok(_) => Ok(PostAction::Continue), - Err(err) => { - error!(?err, "I/O error on the Wayland display"); - data.state.common.should_stop = true; - Err(err) + Generic::new(display, Interest::READ, Mode::Level), + move |_, display, state| { + // SAFETY: We don't drop the display + match unsafe { display.get_mut().dispatch_clients(state) } { + Ok(_) => Ok(PostAction::Continue), + Err(err) => { + error!(?err, "I/O error on the Wayland display"); + state.common.should_stop = true; + Err(err) + } } }, ) .with_context(|| "Failed to init the wayland event source.")?; - Ok((display, socket_name)) + Ok((handle, socket_name)) } diff --git a/src/session.rs b/src/session.rs index 3dba3ccf..c88d6351 100644 --- a/src/session.rs +++ b/src/session.rs @@ -2,7 +2,7 @@ use smithay::reexports::{ calloop::{generic::Generic, Interest, LoopHandle, Mode, PostAction}, - nix::{fcntl, unistd}, + rustix, }; use anyhow::{anyhow, Context, Result}; @@ -12,14 +12,14 @@ use std::{ collections::HashMap, io::{Read, Write}, os::unix::{ - io::{AsRawFd, FromRawFd, RawFd}, + io::{AsFd, BorrowedFd, FromRawFd, RawFd}, net::UnixStream, }, sync::Arc, }; use tracing::{error, warn}; -use crate::state::{Data, State}; +use crate::state::State; #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "message")] @@ -34,9 +34,9 @@ struct StreamWrapper { size: u16, read_bytes: usize, } -impl AsRawFd for StreamWrapper { - fn as_raw_fd(&self) -> RawFd { - self.stream.as_raw_fd() +impl AsFd for StreamWrapper { + fn as_fd(&self) -> BorrowedFd<'_> { + self.stream.as_fd() } } impl From for StreamWrapper { @@ -50,20 +50,24 @@ impl From for StreamWrapper { } } -pub fn setup_socket(handle: LoopHandle, state: &State) -> Result<()> { +unsafe fn set_cloexec(fd: RawFd) -> rustix::io::Result<()> { + if fd == -1 { + return Err(rustix::io::Errno::BADF); + } + let fd = BorrowedFd::borrow_raw(fd); + let flags = rustix::io::fcntl_getfd(fd)?; + rustix::io::fcntl_setfd(fd, flags | rustix::io::FdFlags::CLOEXEC) +} + +pub fn setup_socket(handle: LoopHandle, state: &State) -> Result<()> { if let Ok(fd_num) = std::env::var("COSMIC_SESSION_SOCK") { if let Ok(fd) = fd_num.parse::() { - // set CLOEXEC - let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD); - let result = flags - .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC) - .and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f))); - let mut session_socket = match result { + let mut session_socket = match unsafe { set_cloexec(fd) } { // CLOEXEC worked and we can startup with session IPC Ok(_) => unsafe { UnixStream::from_raw_fd(fd) }, // CLOEXEC didn't work, something is wrong with the fd, just close it Err(err) => { - let _ = unistd::close(fd); + unsafe { rustix::io::close(fd) }; return Err(err).with_context(|| "Failed to setup session socket"); } }; @@ -94,7 +98,10 @@ pub fn setup_socket(handle: LoopHandle, state: &State) -> Result<()> { handle.insert_source( Generic::new(StreamWrapper::from(session_socket), Interest::READ, Mode::Level), - move |_, stream, data: &mut crate::state::Data| { + move |_, stream, state| { + // SAFETY: We don't drop the stream! + let stream = unsafe { stream.get_mut() }; + if stream.size == 0 { let mut len = [0u8; 2]; match stream.stream.read_exact(&mut len) { @@ -130,8 +137,11 @@ pub fn setup_socket(handle: LoopHandle, state: &State) -> Result<()> { Ok((_, received_count)) => { assert_eq!(received_count, count); for fd in fds.into_iter().take(received_count) { + if fd == -1 { + continue; + } let stream = unsafe { UnixStream::from_raw_fd(fd) }; - if let Err(err) = data.display.handle().insert_client(stream, Arc::new(data.state.new_privileged_client_state())) { + if let Err(err) = state.common.display_handle.insert_client(stream, Arc::new(state.new_privileged_client_state())) { warn!(?err, "Failed to add privileged client to display"); } } diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 7bd840a0..75c70658 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -1,27 +1,36 @@ use crate::{ backend::render::{ element::{AsGlowFrame, AsGlowRenderer}, - GlMultiFrame, GlMultiRenderer, + GlMultiError, GlMultiFrame, GlMultiRenderer, }, state::State, - utils::prelude::SeatExt, + utils::prelude::*, }; +use calloop::LoopHandle; use id_tree::NodeId; use smithay::{ backend::{ input::KeyState, renderer::{ - element::{AsRenderElements, Element, RenderElement, UnderlyingStorage}, + element::{ + memory::MemoryRenderBufferRenderElement, + utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement}, + Element, RenderElement, UnderlyingStorage, + }, gles::element::PixelShaderElement, glow::GlowRenderer, - multigpu::Error as MultiError, ImportAll, ImportMem, Renderer, }, }, desktop::{space::SpaceElement, PopupManager, WindowSurfaceType}, input::{ keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, - pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget, RelativeMotionEvent}, + pointer::{ + AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, + GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, + GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, + PointerTarget, RelativeMotionEvent, + }, Seat, }, output::Output, @@ -45,21 +54,28 @@ use std::{ }; pub mod surface; +use self::stack::MoveResult; pub use self::surface::CosmicSurface; pub mod stack; pub use self::stack::CosmicStack; pub mod window; pub use self::window::CosmicWindow; -use self::window::CosmicWindowRenderElement; +pub mod resize_indicator; +pub mod stack_hover; +pub mod swap_indicator; #[cfg(feature = "debug")] -use egui::plot::{Corner, Legend, Plot, PlotPoints, Polygon}; +use egui_plot::{Corner, Legend, Plot, PlotPoints, Polygon}; #[cfg(feature = "debug")] use smithay::backend::renderer::{element::texture::TextureRenderElement, gles::GlesTexture}; #[cfg(feature = "debug")] use tracing::debug; -use super::{focus::FocusDirection, layout::floating::ResizeState}; +use super::{ + focus::FocusDirection, + layout::{floating::ResizeState, tiling::NodeDesc}, + Direction, ManagedLayer, +}; space_elements! { #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -68,18 +84,25 @@ space_elements! { Stack=CosmicStack, } +#[derive(Debug, Clone)] +pub struct MaximizedState { + pub original_geometry: Rectangle, + pub original_layer: ManagedLayer, +} + #[derive(Clone)] pub struct CosmicMapped { element: CosmicMappedInternal, // associated data last_cursor_position: Arc>>>, + pub maximized_state: Arc>>, //tiling - pub(super) tiling_node_id: Arc>>, + pub tiling_node_id: Arc>>, //floating - pub(super) last_geometry: Arc>>>, pub(super) resize_state: Arc>>, + pub last_geometry: Arc>>>, #[cfg(feature = "debug")] debug: Arc>>, @@ -90,8 +113,10 @@ impl fmt::Debug for CosmicMapped { f.debug_struct("CosmicMapped") .field("element", &self.element) .field("last_cursor_position", &self.last_cursor_position) + .field("maximized_state", &self.maximized_state) .field("tiling_node_id", &self.tiling_node_id) .field("resize_state", &self.resize_state) + .field("last_geometry", &self.last_geometry) .finish() } } @@ -153,14 +178,12 @@ impl CosmicMapped { CosmicMappedInternal::Stack(stack) => { let win = stack.active(); let location = stack.offset(); - let mut size = win.geometry().size; - size -= location.to_size(); + let size = win.geometry().size; Rectangle::from_loc_and_size(location, size) } CosmicMappedInternal::Window(win) => { let location = win.offset(); - let mut size = win.geometry().size; - size -= location.to_size(); + let size = win.geometry().size; Rectangle::from_loc_and_size(location, size) } _ => unreachable!(), @@ -190,7 +213,9 @@ impl CosmicMapped { pub fn has_surface(&self, surface: &WlSurface, surface_type: WindowSurfaceType) -> bool { self.windows().any(|(w, _)| { - let Some(toplevel ) = w.wl_surface() else { return false }; + let Some(toplevel) = w.wl_surface() else { + return false; + }; if surface_type.contains(WindowSurfaceType::TOPLEVEL) { if toplevel == *surface { @@ -224,10 +249,17 @@ impl CosmicMapped { }) } - pub fn handle_focus(&self, direction: FocusDirection) -> bool { + pub fn handle_move(&self, direction: Direction) -> MoveResult { if let CosmicMappedInternal::Stack(stack) = &self.element { - //TODO: stack.handle_focus(direction) - false + stack.handle_move(direction) + } else { + MoveResult::Default + } + } + + pub fn handle_focus(&self, direction: FocusDirection, swap: Option) -> bool { + if let CosmicMappedInternal::Stack(stack) = &self.element { + stack.handle_focus(direction, swap) } else { false } @@ -245,18 +277,18 @@ impl CosmicMapped { } } - pub fn is_resizing(&self) -> Option { + pub fn is_resizing(&self, pending: bool) -> Option { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; - window.is_resizing() + window.is_resizing(pending) } pub fn set_tiled(&self, tiled: bool) { - for window in match &self.element { + if let Some(window) = match &self.element { // we use the tiled state of stack windows anyway to get rid of decorations CosmicMappedInternal::Stack(_) => None, CosmicMappedInternal::Window(w) => Some(w.surface()), @@ -266,14 +298,14 @@ impl CosmicMapped { } } - pub fn is_tiled(&self) -> Option { + pub fn is_tiled(&self, pending: bool) -> Option { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; - window.is_tiled() + window.is_tiled(pending) } pub fn set_fullscreen(&self, fullscreen: bool) { @@ -288,14 +320,14 @@ impl CosmicMapped { } } - pub fn is_fullscreen(&self) -> bool { + pub fn is_fullscreen(&self, pending: bool) -> bool { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; - window.is_fullscreen() + window.is_fullscreen(pending) } pub fn set_maximized(&self, maximized: bool) { @@ -310,39 +342,43 @@ impl CosmicMapped { } } - pub fn is_maximized(&self) -> bool { + pub fn is_maximized(&self, pending: bool) -> bool { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; - window.is_maximized() + window.is_maximized(pending) } pub fn set_activated(&self, activated: bool) { - for window in match &self.element { - CosmicMappedInternal::Stack(s) => { - Box::new(s.surfaces()) as Box> - } - CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())), + match &self.element { + CosmicMappedInternal::Stack(s) => s.set_activate(activated), + CosmicMappedInternal::Window(w) => w.set_activate(activated), _ => unreachable!(), - } { - window.set_activated(activated) } } - pub fn is_activated(&self) -> bool { + pub fn is_activated(&self, pending: bool) -> bool { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; - window.is_activated() + window.is_activated(pending) + } + + pub fn pending_size(&self) -> Option> { + match &self.element { + CosmicMappedInternal::Stack(s) => s.pending_size(), + CosmicMappedInternal::Window(w) => w.pending_size(), + _ => unreachable!(), + } } - pub fn set_geometry(&self, geo: Rectangle) { + pub fn set_geometry(&self, geo: Rectangle) { match &self.element { CosmicMappedInternal::Stack(s) => s.set_geometry(geo), CosmicMappedInternal::Window(w) => w.set_geometry(geo), @@ -418,15 +454,17 @@ impl CosmicMapped { } } - pub fn configure(&self) { - for window in match &self.element { + pub fn configure(&self) -> Option { + match &self.element { CosmicMappedInternal::Stack(s) => { - Box::new(s.surfaces()) as Box> + let active = s.active(); + for surface in s.surfaces().filter(|s| s != &active) { + surface.send_configure(); + } + active.send_configure() } - CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())), + CosmicMappedInternal::Window(w) => w.surface().send_configure(), _ => unreachable!(), - } { - window.send_configure(); } } @@ -454,6 +492,76 @@ impl CosmicMapped { } } + pub fn stack_ref(&self) -> Option<&CosmicStack> { + match &self.element { + CosmicMappedInternal::Stack(stack) => Some(stack), + _ => None, + } + } + + pub fn stack_ref_mut(&mut self) -> Option<&mut CosmicStack> { + match &mut self.element { + CosmicMappedInternal::Stack(stack) => Some(stack), + _ => None, + } + } + + pub fn convert_to_stack<'a>( + &mut self, + (output, overlap): (&'a Output, Rectangle), + theme: cosmic::Theme, + ) { + match &self.element { + CosmicMappedInternal::Window(window) => { + let surface = window.surface(); + let activated = surface.is_activated(true); + let handle = window.loop_handle(); + + let stack = CosmicStack::new(std::iter::once(surface), handle, theme); + if let Some(geo) = self.last_geometry.lock().unwrap().clone() { + stack.set_geometry(geo.to_global(&output)); + } + stack.output_enter(output, overlap); + stack.set_activate(activated); + stack.active().send_configure(); + stack.refresh(); + + self.element = CosmicMappedInternal::Stack(stack); + } + _ => {} + } + } + + pub fn convert_to_surface<'a>( + &mut self, + surface: CosmicSurface, + (output, overlap): (&'a Output, Rectangle), + theme: cosmic::Theme, + ) { + let handle = self.loop_handle(); + surface.try_force_undecorated(false); + surface.set_tiled(false); + let window = CosmicWindow::new(surface, handle, theme); + + if let Some(geo) = self.last_geometry.lock().unwrap().clone() { + window.set_geometry(geo.to_global(&output)); + } + window.output_enter(output, overlap); + window.set_activate(self.is_activated(true)); + window.surface().send_configure(); + window.refresh(); + + self.element = CosmicMappedInternal::Window(window); + } + + pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::State> { + match &self.element { + CosmicMappedInternal::Stack(stack) => stack.loop_handle(), + CosmicMappedInternal::Window(window) => window.loop_handle(), + _ => unreachable!(), + } + } + #[cfg(feature = "debug")] pub fn set_debug(&self, flag: bool) { let mut debug = self.debug.lock().unwrap(); @@ -466,6 +574,222 @@ impl CosmicMapped { debug.take(); } } + + pub fn split_render_elements( + &self, + renderer: &mut R, + location: smithay::utils::Point, + scale: smithay::utils::Scale, + alpha: f32, + ) -> (Vec, Vec) + where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: 'static, + CosmicMappedRenderElement: RenderElement, + C: From>, + { + #[cfg(feature = "debug")] + let debug_elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { + let window = self.active_window(); + let window_geo = window.geometry(); + let (min_size, max_size, size) = + (window.min_size(), window.max_size(), window.geometry().size); + + let area = Rectangle::::from_loc_and_size( + location.to_f64().to_logical(scale).to_i32_round(), + self.bbox().size, + ); + + let glow_renderer = renderer.glow_renderer_mut(); + match debug.render( + |ctx| { + egui::Area::new("window") + .anchor( + egui::Align2::RIGHT_TOP, + [ + -window_geo.loc.x as f32 - 10.0, + window_geo.loc.y as f32 - 10.0, + ], + ) + .show(ctx, |ui| { + egui::Frame::none() + .fill(egui::Color32::BLACK) + .rounding(5.0) + .inner_margin(10.0) + .show(ui, |ui| { + ui.heading(window.title()); + ui.horizontal(|ui| { + ui.label("App ID: "); + ui.label(window.app_id()); + }); + ui.label(match window { + CosmicSurface::Wayland(_) => "Protocol: Wayland", + CosmicSurface::X11(_) => "Protocol: X11", + _ => unreachable!(), + }); + ui.horizontal(|ui| { + ui.label("States: "); + if window.is_maximized(true) { + ui.label("🗖"); + } + if window.is_fullscreen(true) { + ui.label("⬜"); + } + if window.is_activated(true) { + ui.label("🖱"); + } + if window.is_resizing(true).is_some() { + ui.label("↔"); + } + }); + + let plot = Plot::new("Sizes") + .legend(Legend::default().position(Corner::RightBottom)) + .data_aspect(1.0) + .view_aspect(1.0) + .show_x(false) + .show_y(false) + .width(200.0) + .height(200.0); + plot.show(ui, |plot_ui| { + let center = if let Some(max_size) = max_size { + ((max_size.w + 20) / 2, (max_size.h + 20) / 2) + } else { + (100, 100) + }; + + if let Some(max_size) = max_size { + let max_size_rect = + Polygon::new(PlotPoints::new(vec![ + [10.0, 10.0], + [max_size.w as f64 + 10.0, 10.0], + [ + max_size.w as f64 + 10.0, + max_size.h as f64 + 10.0, + ], + [10.0, max_size.h as f64 + 10.0], + [10.0, 10.0], + ])); + plot_ui.polygon( + max_size_rect + .name(format!("{}x{}", max_size.w, max_size.h)), + ); + } + + let size_rect = Polygon::new(PlotPoints::new(vec![ + [ + (center.0 - size.w / 2) as f64, + (center.1 - size.h / 2) as f64, + ], + [ + (center.0 + size.w / 2) as f64, + (center.1 - size.h / 2) as f64, + ], + [ + (center.0 + size.w / 2) as f64, + (center.1 + size.h / 2) as f64, + ], + [ + (center.0 - size.w / 2) as f64, + (center.1 + size.h / 2) as f64, + ], + [ + (center.0 - size.w / 2) as f64, + (center.1 - size.h / 2) as f64, + ], + ])); + plot_ui.polygon( + size_rect.name(format!("{}x{}", size.w, size.h)), + ); + + if let Some(min_size) = min_size { + let min_size_rect = + Polygon::new(PlotPoints::new(vec![ + [ + (center.0 - min_size.w / 2) as f64, + (center.1 - min_size.h / 2) as f64, + ], + [ + (center.0 + min_size.w / 2) as f64, + (center.1 - min_size.h / 2) as f64, + ], + [ + (center.0 + min_size.w / 2) as f64, + (center.1 + min_size.h / 2) as f64, + ], + [ + (center.0 - min_size.w / 2) as f64, + (center.1 + min_size.h / 2) as f64, + ], + [ + (center.0 - min_size.w / 2) as f64, + (center.1 - min_size.h / 2) as f64, + ], + ])); + plot_ui.polygon( + min_size_rect + .name(format!("{}x{}", min_size.w, min_size.h)), + ); + } + }) + }) + }); + }, + glow_renderer, + area, + scale.x, + 0.8, + ) { + Ok(element) => vec![element.into()], + Err(err) => { + debug!(?err, "Error rendering debug overlay."); + Vec::new() + } + } + } else { + Vec::new() + }; + #[cfg(not(feature = "debug"))] + let debug_elements = Vec::new(); + + #[cfg_attr(not(feature = "debug"), allow(unused_mut))] + let (window_elements, popup_elements) = match &self.element { + CosmicMappedInternal::Stack(s) => s + .split_render_elements::>( + renderer, location, scale, alpha, + ), + CosmicMappedInternal::Window(w) => w + .split_render_elements::>( + renderer, location, scale, alpha, + ), + _ => unreachable!(), + }; + + ( + debug_elements + .into_iter() + .map(C::from) + .chain(window_elements.into_iter().map(C::from)) + .collect(), + popup_elements.into_iter().map(C::from).collect(), + ) + } + + pub(crate) fn update_theme(&self, theme: cosmic::Theme) { + match &self.element { + CosmicMappedInternal::Window(w) => w.set_theme(theme), + CosmicMappedInternal::Stack(s) => s.set_theme(theme), + CosmicMappedInternal::_GenericCatcher(_) => {} + } + } + + pub(crate) fn force_redraw(&self) { + match &self.element { + CosmicMappedInternal::Window(w) => w.force_redraw(), + CosmicMappedInternal::Stack(s) => s.force_redraw(), + CosmicMappedInternal::_GenericCatcher(_) => {} + } + } } impl IsAlive for CosmicMapped { @@ -613,6 +937,13 @@ impl PointerTarget for CosmicMapped { _ => {} } } + fn frame(&self, seat: &Seat, data: &mut State) { + match &self.element { + CosmicMappedInternal::Stack(s) => PointerTarget::frame(s, seat, data), + CosmicMappedInternal::Window(w) => PointerTarget::frame(w, seat, data), + _ => {} + } + } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { self.last_cursor_position.lock().unwrap().remove(&seat.id()); match &self.element { @@ -621,18 +952,139 @@ impl PointerTarget for CosmicMapped { _ => {} } } -} - -impl WaylandFocus for CosmicMapped { - fn wl_surface(&self) -> Option { + fn gesture_swipe_begin( + &self, + seat: &Seat, + data: &mut State, + event: &GestureSwipeBeginEvent, + ) { match &self.element { - CosmicMappedInternal::Window(w) => w.surface().wl_surface().clone(), - CosmicMappedInternal::Stack(s) => s.active().wl_surface().clone(), - _ => None, + CosmicMappedInternal::Stack(s) => { + PointerTarget::gesture_swipe_begin(s, seat, data, event) + } + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_swipe_begin(w, seat, data, event) + } + _ => {} } } - - fn same_client_as(&self, object_id: &ObjectId) -> bool { + fn gesture_swipe_update( + &self, + seat: &Seat, + data: &mut State, + event: &GestureSwipeUpdateEvent, + ) { + match &self.element { + CosmicMappedInternal::Stack(s) => { + PointerTarget::gesture_swipe_update(s, seat, data, event) + } + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_swipe_update(w, seat, data, event) + } + _ => {} + } + } + fn gesture_swipe_end( + &self, + seat: &Seat, + data: &mut State, + event: &GestureSwipeEndEvent, + ) { + match &self.element { + CosmicMappedInternal::Stack(s) => { + PointerTarget::gesture_swipe_end(s, seat, data, event) + } + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_swipe_end(w, seat, data, event) + } + _ => {} + } + } + fn gesture_pinch_begin( + &self, + seat: &Seat, + data: &mut State, + event: &GesturePinchBeginEvent, + ) { + match &self.element { + CosmicMappedInternal::Stack(s) => { + PointerTarget::gesture_pinch_begin(s, seat, data, event) + } + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_pinch_begin(w, seat, data, event) + } + _ => {} + } + } + fn gesture_pinch_update( + &self, + seat: &Seat, + data: &mut State, + event: &GesturePinchUpdateEvent, + ) { + match &self.element { + CosmicMappedInternal::Stack(s) => { + PointerTarget::gesture_pinch_update(s, seat, data, event) + } + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_pinch_update(w, seat, data, event) + } + _ => {} + } + } + fn gesture_pinch_end( + &self, + seat: &Seat, + data: &mut State, + event: &GesturePinchEndEvent, + ) { + match &self.element { + CosmicMappedInternal::Stack(s) => { + PointerTarget::gesture_pinch_end(s, seat, data, event) + } + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_pinch_end(w, seat, data, event) + } + _ => {} + } + } + fn gesture_hold_begin( + &self, + seat: &Seat, + data: &mut State, + event: &GestureHoldBeginEvent, + ) { + match &self.element { + CosmicMappedInternal::Stack(s) => { + PointerTarget::gesture_hold_begin(s, seat, data, event) + } + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_hold_begin(w, seat, data, event) + } + _ => {} + } + } + fn gesture_hold_end(&self, seat: &Seat, data: &mut State, event: &GestureHoldEndEvent) { + match &self.element { + CosmicMappedInternal::Stack(s) => PointerTarget::gesture_hold_end(s, seat, data, event), + CosmicMappedInternal::Window(w) => { + PointerTarget::gesture_hold_end(w, seat, data, event) + } + _ => {} + } + } +} + +impl WaylandFocus for CosmicMapped { + fn wl_surface(&self) -> Option { + match &self.element { + CosmicMappedInternal::Window(w) => w.surface().wl_surface().clone(), + CosmicMappedInternal::Stack(s) => s.active().wl_surface().clone(), + _ => None, + } + } + + fn same_client_as(&self, object_id: &ObjectId) -> bool { match &self.element { CosmicMappedInternal::Window(w) => w.surface().same_client_as(object_id), CosmicMappedInternal::Stack(s) => s.surfaces().any(|w| w.same_client_as(object_id)), @@ -646,9 +1098,10 @@ impl From for CosmicMapped { CosmicMapped { element: CosmicMappedInternal::Window(w), last_cursor_position: Arc::new(Mutex::new(HashMap::new())), + maximized_state: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)), - last_geometry: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)), + last_geometry: Arc::new(Mutex::new(None)), #[cfg(feature = "debug")] debug: Arc::new(Mutex::new(None)), } @@ -660,9 +1113,10 @@ impl From for CosmicMapped { CosmicMapped { element: CosmicMappedInternal::Stack(s), last_cursor_position: Arc::new(Mutex::new(HashMap::new())), + maximized_state: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)), - last_geometry: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)), + last_geometry: Arc::new(Mutex::new(None)), #[cfg(feature = "debug")] debug: Arc::new(Mutex::new(None)), } @@ -671,26 +1125,50 @@ impl From for CosmicMapped { pub enum CosmicMappedRenderElement where - R: AsGlowRenderer + Renderer + ImportAll + ImportMem, + R: Renderer + ImportAll + ImportMem, ::TextureId: 'static, { Stack(self::stack::CosmicStackRenderElement), Window(self::window::CosmicWindowRenderElement), - Indicator(PixelShaderElement), + TiledStack( + RelocateRenderElement< + RescaleRenderElement>>, + >, + ), + TiledWindow( + RelocateRenderElement< + RescaleRenderElement>>, + >, + ), + TiledOverlay( + RelocateRenderElement>>, + ), + GrabbedStack(RescaleRenderElement>), + GrabbedWindow(RescaleRenderElement>), + FocusIndicator(PixelShaderElement), + Overlay(PixelShaderElement), + StackHoverIndicator(MemoryRenderBufferRenderElement), #[cfg(feature = "debug")] Egui(TextureRenderElement), } impl Element for CosmicMappedRenderElement where - R: AsGlowRenderer + Renderer + ImportAll + ImportMem, + R: Renderer + ImportAll + ImportMem, ::TextureId: 'static, { fn id(&self) -> &smithay::backend::renderer::element::Id { match self { CosmicMappedRenderElement::Stack(elem) => elem.id(), CosmicMappedRenderElement::Window(elem) => elem.id(), - CosmicMappedRenderElement::Indicator(elem) => elem.id(), + CosmicMappedRenderElement::TiledStack(elem) => elem.id(), + CosmicMappedRenderElement::TiledWindow(elem) => elem.id(), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.id(), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.id(), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.id(), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.id(), + CosmicMappedRenderElement::Overlay(elem) => elem.id(), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.id(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.id(), } @@ -700,7 +1178,14 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.current_commit(), CosmicMappedRenderElement::Window(elem) => elem.current_commit(), - CosmicMappedRenderElement::Indicator(elem) => elem.current_commit(), + CosmicMappedRenderElement::TiledStack(elem) => elem.current_commit(), + CosmicMappedRenderElement::TiledWindow(elem) => elem.current_commit(), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.current_commit(), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.current_commit(), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.current_commit(), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.current_commit(), + CosmicMappedRenderElement::Overlay(elem) => elem.current_commit(), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.current_commit(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.current_commit(), } @@ -710,7 +1195,14 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.src(), CosmicMappedRenderElement::Window(elem) => elem.src(), - CosmicMappedRenderElement::Indicator(elem) => elem.src(), + CosmicMappedRenderElement::TiledStack(elem) => elem.src(), + CosmicMappedRenderElement::TiledWindow(elem) => elem.src(), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.src(), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.src(), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.src(), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.src(), + CosmicMappedRenderElement::Overlay(elem) => elem.src(), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.src(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.src(), } @@ -720,7 +1212,14 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.geometry(scale), CosmicMappedRenderElement::Window(elem) => elem.geometry(scale), - CosmicMappedRenderElement::Indicator(elem) => elem.geometry(scale), + CosmicMappedRenderElement::TiledStack(elem) => elem.geometry(scale), + CosmicMappedRenderElement::TiledWindow(elem) => elem.geometry(scale), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.geometry(scale), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.geometry(scale), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.geometry(scale), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.geometry(scale), + CosmicMappedRenderElement::Overlay(elem) => elem.geometry(scale), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.geometry(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.geometry(scale), } @@ -730,7 +1229,14 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.location(scale), CosmicMappedRenderElement::Window(elem) => elem.location(scale), - CosmicMappedRenderElement::Indicator(elem) => elem.location(scale), + CosmicMappedRenderElement::TiledStack(elem) => elem.location(scale), + CosmicMappedRenderElement::TiledWindow(elem) => elem.location(scale), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.location(scale), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.location(scale), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.location(scale), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.location(scale), + CosmicMappedRenderElement::Overlay(elem) => elem.location(scale), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.location(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.location(scale), } @@ -740,7 +1246,14 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.transform(), CosmicMappedRenderElement::Window(elem) => elem.transform(), - CosmicMappedRenderElement::Indicator(elem) => elem.transform(), + CosmicMappedRenderElement::TiledStack(elem) => elem.transform(), + CosmicMappedRenderElement::TiledWindow(elem) => elem.transform(), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.transform(), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.transform(), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.transform(), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.transform(), + CosmicMappedRenderElement::Overlay(elem) => elem.transform(), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.transform(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.transform(), } @@ -754,7 +1267,16 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Window(elem) => elem.damage_since(scale, commit), - CosmicMappedRenderElement::Indicator(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::TiledStack(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::TiledWindow(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::Overlay(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::StackHoverIndicator(elem) => { + elem.damage_since(scale, commit) + } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.damage_since(scale, commit), } @@ -764,11 +1286,35 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Window(elem) => elem.opaque_regions(scale), - CosmicMappedRenderElement::Indicator(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::TiledStack(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::TiledWindow(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::Overlay(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.opaque_regions(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.opaque_regions(scale), } } + + fn alpha(&self) -> f32 { + match self { + CosmicMappedRenderElement::Stack(elem) => elem.alpha(), + CosmicMappedRenderElement::Window(elem) => elem.alpha(), + CosmicMappedRenderElement::TiledStack(elem) => elem.alpha(), + CosmicMappedRenderElement::TiledWindow(elem) => elem.alpha(), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.alpha(), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.alpha(), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.alpha(), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.alpha(), + CosmicMappedRenderElement::Overlay(elem) => elem.alpha(), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.alpha(), + #[cfg(feature = "debug")] + CosmicMappedRenderElement::Egui(elem) => elem.alpha(), + } + } } impl RenderElement for CosmicMappedRenderElement { @@ -782,7 +1328,20 @@ impl RenderElement for CosmicMappedRenderElement { match self { CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), - CosmicMappedRenderElement::Indicator(elem) => { + CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::TiledOverlay(elem) => { + RenderElement::::draw(elem, frame, src, dst, damage) + } + CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::FocusIndicator(elem) => { + RenderElement::::draw(elem, frame, src, dst, damage) + } + CosmicMappedRenderElement::Overlay(elem) => { + RenderElement::::draw(elem, frame, src, dst, damage) + } + CosmicMappedRenderElement::StackHoverIndicator(elem) => { RenderElement::::draw(elem, frame, src, dst, damage) } #[cfg(feature = "debug")] @@ -796,7 +1355,16 @@ impl RenderElement for CosmicMappedRenderElement { match self { CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), - CosmicMappedRenderElement::Indicator(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::Overlay(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::StackHoverIndicator(elem) => { + elem.underlying_storage(renderer) + } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.underlying_storage(renderer), } @@ -812,19 +1380,34 @@ impl<'a, 'b> RenderElement> src: Rectangle, dst: Rectangle, damage: &[Rectangle], - ) -> Result<(), as Renderer>::Error> { + ) -> Result<(), GlMultiError> { match self { CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), - CosmicMappedRenderElement::Indicator(elem) => { + CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::TiledOverlay(elem) => { + RenderElement::::draw(elem, frame.glow_frame_mut(), src, dst, damage) + .map_err(|err| GlMultiError::Render(err)) + } + CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::FocusIndicator(elem) => { + RenderElement::::draw(elem, frame.glow_frame_mut(), src, dst, damage) + .map_err(|err| GlMultiError::Render(err)) + } + CosmicMappedRenderElement::Overlay(elem) => { RenderElement::::draw(elem, frame.glow_frame_mut(), src, dst, damage) - .map_err(|err| MultiError::Render(err)) + .map_err(|err| GlMultiError::Render(err)) + } + CosmicMappedRenderElement::StackHoverIndicator(elem) => { + elem.draw(frame, src, dst, damage) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_frame = frame.glow_frame_mut(); RenderElement::::draw(elem, glow_frame, src, dst, damage) - .map_err(|err| MultiError::Render(err)) + .map_err(|err| GlMultiError::Render(err)) } } } @@ -836,9 +1419,22 @@ impl<'a, 'b> RenderElement> match self { CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), - CosmicMappedRenderElement::Indicator(elem) => { + CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::TiledOverlay(elem) => { + elem.underlying_storage(renderer.glow_renderer_mut()) + } + CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::FocusIndicator(elem) => { + elem.underlying_storage(renderer.glow_renderer_mut()) + } + CosmicMappedRenderElement::Overlay(elem) => { elem.underlying_storage(renderer.glow_renderer_mut()) } + CosmicMappedRenderElement::StackHoverIndicator(elem) => { + elem.underlying_storage(renderer) + } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_renderer = renderer.glow_renderer_mut(); @@ -881,215 +1477,29 @@ where CosmicMappedRenderElement: RenderElement, { fn from(elem: PixelShaderElement) -> Self { - CosmicMappedRenderElement::Indicator(elem) + CosmicMappedRenderElement::FocusIndicator(elem) } } -#[cfg(feature = "debug")] -impl From> for CosmicMappedRenderElement +impl From> for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - fn from(elem: TextureRenderElement) -> Self { - CosmicMappedRenderElement::Egui(elem) + fn from(elem: MemoryRenderBufferRenderElement) -> Self { + CosmicMappedRenderElement::StackHoverIndicator(elem) } } -impl AsRenderElements for CosmicMapped +#[cfg(feature = "debug")] +impl From> for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, - CosmicWindowRenderElement: RenderElement, { - type RenderElement = CosmicMappedRenderElement; - fn render_elements>( - &self, - renderer: &mut R, - location: Point, - scale: Scale, - ) -> Vec { - #[cfg(feature = "debug")] - let mut elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { - let window = self.active_window(); - let window_geo = window.geometry(); - let (min_size, max_size, size) = - (window.min_size(), window.max_size(), window.geometry().size); - - let area = Rectangle::::from_loc_and_size( - location.to_f64().to_logical(scale).to_i32_round(), - self.bbox().size, - ); - - let glow_renderer = renderer.glow_renderer_mut(); - match debug.render( - |ctx| { - egui::Area::new("window") - .anchor( - egui::Align2::RIGHT_TOP, - [ - -window_geo.loc.x as f32 - 10.0, - window_geo.loc.y as f32 - 10.0, - ], - ) - .show(ctx, |ui| { - egui::Frame::none() - .fill(egui::Color32::BLACK) - .rounding(5.0) - .inner_margin(10.0) - .show(ui, |ui| { - ui.heading(window.title()); - ui.horizontal(|ui| { - ui.label("App ID: "); - ui.label(window.app_id()); - }); - ui.label(match window { - CosmicSurface::Wayland(_) => "Protocol: Wayland", - CosmicSurface::X11(_) => "Protocol: X11", - _ => unreachable!(), - }); - ui.horizontal(|ui| { - ui.label("States: "); - if window.is_maximized() { - ui.label("🗖"); - } - if window.is_fullscreen() { - ui.label("⬜"); - } - if window.is_activated() { - ui.label("🖱"); - } - if window.is_resizing().is_some() { - ui.label("↔"); - } - }); - - let plot = Plot::new("Sizes") - .legend(Legend::default().position(Corner::RightBottom)) - .data_aspect(1.0) - .view_aspect(1.0) - .show_x(false) - .show_y(false) - .width(200.0) - .height(200.0); - plot.show(ui, |plot_ui| { - let center = if let Some(max_size) = max_size { - ((max_size.w + 20) / 2, (max_size.h + 20) / 2) - } else { - (100, 100) - }; - - if let Some(max_size) = max_size { - let max_size_rect = - Polygon::new(PlotPoints::new(vec![ - [10.0, 10.0], - [max_size.w as f64 + 10.0, 10.0], - [ - max_size.w as f64 + 10.0, - max_size.h as f64 + 10.0, - ], - [10.0, max_size.h as f64 + 10.0], - [10.0, 10.0], - ])); - plot_ui.polygon( - max_size_rect - .name(format!("{}x{}", max_size.w, max_size.h)), - ); - } - - let size_rect = Polygon::new(PlotPoints::new(vec![ - [ - (center.0 - size.w / 2) as f64, - (center.1 - size.h / 2) as f64, - ], - [ - (center.0 + size.w / 2) as f64, - (center.1 - size.h / 2) as f64, - ], - [ - (center.0 + size.w / 2) as f64, - (center.1 + size.h / 2) as f64, - ], - [ - (center.0 - size.w / 2) as f64, - (center.1 + size.h / 2) as f64, - ], - [ - (center.0 - size.w / 2) as f64, - (center.1 - size.h / 2) as f64, - ], - ])); - plot_ui.polygon( - size_rect.name(format!("{}x{}", size.w, size.h)), - ); - - if let Some(min_size) = min_size { - let min_size_rect = - Polygon::new(PlotPoints::new(vec![ - [ - (center.0 - min_size.w / 2) as f64, - (center.1 - min_size.h / 2) as f64, - ], - [ - (center.0 + min_size.w / 2) as f64, - (center.1 - min_size.h / 2) as f64, - ], - [ - (center.0 + min_size.w / 2) as f64, - (center.1 + min_size.h / 2) as f64, - ], - [ - (center.0 - min_size.w / 2) as f64, - (center.1 + min_size.h / 2) as f64, - ], - [ - (center.0 - min_size.w / 2) as f64, - (center.1 - min_size.h / 2) as f64, - ], - ])); - plot_ui.polygon( - min_size_rect - .name(format!("{}x{}", min_size.w, min_size.h)), - ); - } - }) - }) - }); - }, - glow_renderer, - area, - scale.x, - 0.8, - ) { - Ok(element) => vec![element.into()], - Err(err) => { - debug!(?err, "Error rendering debug overlay."); - Vec::new() - } - } - } else { - Vec::new() - }; - #[cfg(not(feature = "debug"))] - let mut elements = Vec::new(); - - #[cfg_attr(not(feature = "debug"), allow(unused_mut))] - match &self.element { - CosmicMappedInternal::Stack(s) => { - elements.extend(AsRenderElements::::render_elements::< - CosmicMappedRenderElement, - >(s, renderer, location, scale)) - } - CosmicMappedInternal::Window(w) => { - elements.extend(AsRenderElements::::render_elements::< - CosmicMappedRenderElement, - >(w, renderer, location, scale)) - } - _ => {} - }; - - elements.into_iter().map(C::from).collect() + fn from(elem: TextureRenderElement) -> Self { + CosmicMappedRenderElement::Egui(elem) } } diff --git a/src/shell/element/resize_indicator.rs b/src/shell/element/resize_indicator.rs new file mode 100644 index 00000000..e16cff25 --- /dev/null +++ b/src/shell/element/resize_indicator.rs @@ -0,0 +1,198 @@ +use std::sync::Mutex; + +use crate::{ + config::{Action, Config}, + fl, + shell::{grabs::ResizeEdge, ResizeDirection}, + utils::iced::{IcedElement, Program}, +}; + +use calloop::LoopHandle; +use cosmic::{ + iced::widget::{column, container, horizontal_space, row, vertical_space}, + iced_core::{Background, Color, Length}, + theme, + widget::{icon::from_name, text}, + Apply, +}; +use smithay::utils::Size; + +pub type ResizeIndicator = IcedElement; + +pub fn resize_indicator( + direction: ResizeDirection, + config: &Config, + evlh: LoopHandle<'static, crate::state::State>, + theme: cosmic::Theme, +) -> ResizeIndicator { + ResizeIndicator::new( + ResizeIndicatorInternal { + edges: Mutex::new(ResizeEdge::all()), + direction, + shortcut1: config + .static_conf + .key_bindings + .iter() + .find_map(|(pattern, action)| { + (*action == Action::Resizing(ResizeDirection::Outwards)).then_some(pattern) + }) + .map(|pattern| format!("{}: ", pattern.to_string())) + .unwrap_or_else(|| crate::fl!("unknown-keybinding")), + shortcut2: config + .static_conf + .key_bindings + .iter() + .find_map(|(pattern, action)| { + (*action == Action::Resizing(ResizeDirection::Inwards)).then_some(pattern) + }) + .map(|pattern| format!("{}: ", pattern.to_string())) + .unwrap_or_else(|| crate::fl!("unknown-keybinding")), + }, + Size::from((1, 1)), + evlh, + theme, + ) +} + +pub struct ResizeIndicatorInternal { + pub edges: Mutex, + pub direction: ResizeDirection, + pub shortcut1: String, + pub shortcut2: String, +} + +impl Program for ResizeIndicatorInternal { + type Message = (); + + fn view(&self) -> crate::utils::iced::Element<'_, Self::Message> { + let edges = self.edges.lock().unwrap(); + let icon_container_style = || { + theme::Container::custom(|theme| container::Appearance { + icon_color: Some(Color::from(theme.cosmic().accent.on)), + text_color: Some(Color::from(theme.cosmic().accent.on)), + background: Some(Background::Color(theme.cosmic().accent_color().into())), + border_radius: 18.0.into(), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }) + }; + + column(vec![ + if edges.contains(ResizeEdge::TOP) { + from_name(if self.direction == ResizeDirection::Outwards { + "go-up-symbolic" + } else { + "go-down-symbolic" + }) + .size(32) + .prefer_svg(true) + .apply(container) + .padding(2) + .style(icon_container_style()) + .width(Length::Shrink) + .apply(container) + .center_x() + .width(Length::Fill) + .into() + } else { + vertical_space(36).into() + }, + row(vec![ + if edges.contains(ResizeEdge::LEFT) { + from_name(if self.direction == ResizeDirection::Outwards { + "go-previous-symbolic" + } else { + "go-next-symbolic" + }) + .size(32) + .prefer_svg(true) + .apply(container) + .padding(4) + .style(icon_container_style()) + .width(Length::Shrink) + .apply(container) + .center_y() + .height(Length::Fill) + .into() + } else { + horizontal_space(36).into() + }, + row(vec![ + text(&self.shortcut1) + .font(cosmic::font::FONT_SEMIBOLD) + .size(14) + .into(), + text(fl!("grow-window")) + .font(cosmic::font::FONT) + .size(14) + .into(), + horizontal_space(40).into(), + text(&self.shortcut2) + .font(cosmic::font::FONT_SEMIBOLD) + .size(14) + .into(), + text(fl!("shrink-window")) + .font(cosmic::font::FONT) + .size(14) + .into(), + ]) + .apply(container) + .center_x() + .center_y() + .padding(16) + .apply(container) + .style(icon_container_style()) + .width(Length::Shrink) + .height(Length::Shrink) + .apply(container) + .height(Length::Fill) + .width(Length::Fill) + .center_x() + .center_y() + .into(), + if edges.contains(ResizeEdge::RIGHT) { + from_name(if self.direction == ResizeDirection::Outwards { + "go-next-symbolic" + } else { + "go-previous-symbolic" + }) + .size(32) + .prefer_svg(true) + .apply(container) + .padding(4) + .style(icon_container_style()) + .height(Length::Shrink) + .apply(container) + .center_y() + .height(Length::Fill) + .into() + } else { + horizontal_space(36).into() + }, + ]) + .width(Length::Fill) + .height(Length::Fill) + .into(), + if edges.contains(ResizeEdge::BOTTOM) { + from_name(if self.direction == ResizeDirection::Outwards { + "go-down-symbolic" + } else { + "go-up-symbolic" + }) + .size(32) + .prefer_svg(true) + .apply(container) + .padding(4) + .style(icon_container_style()) + .width(Length::Shrink) + .apply(container) + .center_x() + .width(Length::Fill) + .into() + } else { + vertical_space(36).into() + }, + ]) + .into() + } +} diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 1d7ecb5e..1a37f7a6 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -1,12 +1,23 @@ +use super::{CosmicMapped, CosmicSurface, CosmicWindow}; use crate::{ + shell::{ + focus::FocusDirection, grabs::MoveGrab, layout::tiling::NodeDesc, Direction, Shell, Trigger, + }, state::State, utils::iced::{IcedElement, Program}, - utils::prelude::SeatExt, + utils::prelude::*, wayland::handlers::screencopy::ScreencopySessions, }; use calloop::LoopHandle; -use cosmic::Element; +use cosmic::{ + iced::{id::Id, widget as iced_widget}, + iced_core::{Background, BorderRadius, Color, Length}, + iced_runtime::Command, + iced_widget::scrollable::AbsoluteOffset, + theme, widget as cosmic_widget, Apply, Element as CosmicElement, +}; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType; +use once_cell::sync::Lazy; use smithay::{ backend::{ input::KeyState, @@ -21,34 +32,47 @@ use smithay::{ desktop::space::SpaceElement, input::{ keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, - pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget, RelativeMotionEvent}, + pointer::{ + AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, + GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, + GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, + GrabStartData as PointerGrabStartData, MotionEvent, PointerTarget, RelativeMotionEvent, + }, Seat, }, output::Output, render_elements, - utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size}, + utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, + wayland::seat::WaylandFocus, }; use std::{ fmt, hash::Hash, sync::{ - atomic::{AtomicU8, AtomicUsize, Ordering}, + atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering}, Arc, Mutex, }, }; -use super::CosmicSurface; +mod tab; +mod tab_text; +mod tabs; + +use self::{ + tab::{Tab, TabMessage}, + tabs::Tabs, +}; + +static SCROLLABLE_ID: Lazy = Lazy::new(|| Id::new("scrollable")); #[derive(Clone, PartialEq, Eq, Hash)] pub struct CosmicStack(IcedElement); impl fmt::Debug for CosmicStack { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.with_program(|stack| { - f.debug_struct("CosmicStack") - .field("internal", stack) - .finish_non_exhaustive() - }) + f.debug_struct("CosmicStack") + .field("internal", &self.0) + .finish_non_exhaustive() } } @@ -56,35 +80,36 @@ impl fmt::Debug for CosmicStack { pub struct CosmicStackInternal { windows: Arc>>, active: Arc, + activated: Arc, + group_focused: Arc, + scroll_to_focus: Arc, previous_keyboard: Arc, - pointer_entered: Option>, + pointer_entered: Arc, previous_pointer: Arc, + reenter: Arc, + potential_drag: Arc>>, + override_alive: Arc, + last_seat: Arc, Serial)>>>, last_location: Arc, Serial, u32)>>>, + geometry: Arc>>>, + mask: Arc>>, } impl CosmicStackInternal { pub fn swap_focus(&self, focus: Focus) -> Focus { - if let Some(pointer_entered) = self.pointer_entered.as_ref() { - unsafe { - std::mem::transmute::( - pointer_entered.swap(focus as u8, Ordering::SeqCst), - ) - } - } else { - Focus::Window + unsafe { + std::mem::transmute::( + self.pointer_entered.swap(focus as u8, Ordering::SeqCst), + ) } } pub fn current_focus(&self) -> Focus { - if let Some(pointer_entered) = self.pointer_entered.as_ref() { - unsafe { std::mem::transmute::(pointer_entered.load(Ordering::SeqCst)) } - } else { - Focus::Window - } + unsafe { std::mem::transmute::(self.pointer_entered.load(Ordering::SeqCst)) } } } -const TAB_HEIGHT: i32 = 24; +pub const TAB_HEIGHT: i32 = 24; #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -94,30 +119,252 @@ pub enum Focus { Window, } +pub enum MoveResult { + Handled, + MoveOut(CosmicSurface, LoopHandle<'static, crate::state::State>), + Default, +} + impl CosmicStack { - pub fn new( - window: impl Into, - handle: LoopHandle<'static, crate::state::Data>, + pub fn new>( + windows: impl Iterator, + handle: LoopHandle<'static, crate::state::State>, + theme: cosmic::Theme, ) -> CosmicStack { - let window = window.into(); - let width = window.geometry().size.w; + let windows = windows.map(Into::into).collect::>(); + assert!(!windows.is_empty()); + + for window in &windows { + window.try_force_undecorated(true); + window.set_tiled(true); + window.send_configure(); + } + + let width = windows[0].geometry().size.w; CosmicStack(IcedElement::new( CosmicStackInternal { - windows: Arc::new(Mutex::new(vec![window])), + windows: Arc::new(Mutex::new(windows)), active: Arc::new(AtomicUsize::new(0)), + activated: Arc::new(AtomicBool::new(false)), + group_focused: Arc::new(AtomicBool::new(false)), + scroll_to_focus: Arc::new(AtomicBool::new(false)), previous_keyboard: Arc::new(AtomicUsize::new(0)), - pointer_entered: None, + pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)), previous_pointer: Arc::new(AtomicUsize::new(0)), + reenter: Arc::new(AtomicBool::new(false)), + potential_drag: Arc::new(Mutex::new(None)), + override_alive: Arc::new(AtomicBool::new(true)), + last_seat: Arc::new(Mutex::new(None)), last_location: Arc::new(Mutex::new(None)), + geometry: Arc::new(Mutex::new(None)), + mask: Arc::new(Mutex::new(None)), }, (width, TAB_HEIGHT), handle, + theme, )) } - //pub fn add_window() - //pub fn remove_window() - //pub fn len + pub fn add_window(&self, window: impl Into, idx: Option) { + let window = window.into(); + window.try_force_undecorated(true); + window.set_tiled(true); + self.0.with_program(|p| { + if let Some(mut geo) = p.geometry.lock().unwrap().clone() { + geo.loc.y += TAB_HEIGHT; + geo.size.h -= TAB_HEIGHT; + window.set_geometry(geo); + } + window.send_configure(); + if let Some(idx) = idx { + p.windows.lock().unwrap().insert(idx, window); + let old_idx = p.active.swap(idx, Ordering::SeqCst); + if old_idx == idx { + p.reenter.store(true, Ordering::SeqCst); + p.previous_keyboard.store(old_idx, Ordering::SeqCst); + p.previous_pointer.store(old_idx, Ordering::SeqCst); + } + } else { + let mut windows = p.windows.lock().unwrap(); + windows.push(window); + p.active.store(windows.len() - 1, Ordering::SeqCst); + } + p.scroll_to_focus.store(true, Ordering::SeqCst); + }); + self.0.force_redraw() + } + + pub fn remove_window(&self, window: &CosmicSurface) { + self.0.with_program(|p| { + let mut windows = p.windows.lock().unwrap(); + if windows.len() == 1 { + p.override_alive.store(false, Ordering::SeqCst); + let window = windows.get(0).unwrap(); + window.try_force_undecorated(false); + window.set_tiled(false); + return; + } + + let Some(idx) = windows.iter().position(|w| w == window) else { + return; + }; + if idx == p.active.load(Ordering::SeqCst) { + p.reenter.store(true, Ordering::SeqCst); + } + let window = windows.remove(idx); + window.try_force_undecorated(false); + window.set_tiled(false); + + p.active.fetch_min(windows.len() - 1, Ordering::SeqCst); + }); + self.0.force_redraw() + } + + pub fn remove_idx(&self, idx: usize) { + self.0.with_program(|p| { + let mut windows = p.windows.lock().unwrap(); + if windows.len() == 1 { + p.override_alive.store(false, Ordering::SeqCst); + let window = windows.get(0).unwrap(); + window.try_force_undecorated(false); + window.set_tiled(false); + return; + } + if windows.len() <= idx { + return; + } + if idx == p.active.load(Ordering::SeqCst) { + p.reenter.store(true, Ordering::SeqCst); + } + let window = windows.remove(idx); + window.try_force_undecorated(false); + window.set_tiled(false); + + p.active.fetch_min(windows.len() - 1, Ordering::SeqCst); + }); + self.0.force_redraw() + } + + pub fn len(&self) -> usize { + self.0.with_program(|p| p.windows.lock().unwrap().len()) + } + + pub fn handle_focus(&self, direction: FocusDirection, swap: Option) -> bool { + let result = self.0.with_program(|p| match direction { + FocusDirection::Left => { + if !p.group_focused.load(Ordering::SeqCst) { + if let Ok(old) = + p.active + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| { + val.checked_sub(1) + }) + { + p.previous_keyboard.store(old, Ordering::SeqCst); + p.previous_pointer.store(old, Ordering::SeqCst); + p.scroll_to_focus.store(true, Ordering::SeqCst); + true + } else { + false + } + } else { + false + } + } + FocusDirection::Right => { + if !p.group_focused.load(Ordering::SeqCst) { + let max = p.windows.lock().unwrap().len(); + if let Ok(old) = + p.active + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| { + if val < max - 1 { + Some(val + 1) + } else { + None + } + }) + { + p.previous_keyboard.store(old, Ordering::SeqCst); + p.previous_pointer.store(old, Ordering::SeqCst); + p.scroll_to_focus.store(true, Ordering::SeqCst); + true + } else { + false + } + } else { + false + } + } + FocusDirection::Out if swap.is_none() => { + if !p.group_focused.swap(true, Ordering::SeqCst) { + p.windows.lock().unwrap().iter().for_each(|w| { + w.set_activated(false); + w.send_configure(); + }); + true + } else { + false + } + } + FocusDirection::In if swap.is_none() => { + if !p.group_focused.swap(false, Ordering::SeqCst) { + p.windows.lock().unwrap().iter().for_each(|w| { + w.set_activated(true); + w.send_configure(); + }); + true + } else { + false + } + } + _ => false, + }); + + if result { + self.0.force_update(); + } + + result + } + + pub fn handle_move(&self, direction: Direction) -> MoveResult { + let loop_handle = self.0.loop_handle(); + self.0.with_program(|p| { + if p.group_focused.load(Ordering::SeqCst) { + return MoveResult::Default; + } + + let active = p.active.load(Ordering::SeqCst); + let mut windows = p.windows.lock().unwrap(); + + let next = match direction { + Direction::Left => active.checked_sub(1), + Direction::Right => (active + 1 < windows.len()).then_some(active + 1), + Direction::Down | Direction::Up => None, + }; + + if let Some(val) = next { + let old = p.active.swap(val, Ordering::SeqCst); + windows.swap(old, val); + p.previous_keyboard.store(old, Ordering::SeqCst); + p.previous_pointer.store(old, Ordering::SeqCst); + p.scroll_to_focus.store(true, Ordering::SeqCst); + MoveResult::Handled + } else { + if windows.len() == 1 { + return MoveResult::Default; + } + let window = windows.remove(active); + if active == windows.len() { + p.active.store(active - 1, Ordering::SeqCst); + p.scroll_to_focus.store(true, Ordering::SeqCst); + } + window.try_force_undecorated(false); + window.set_tiled(false); + + MoveResult::MoveOut(window, loop_handle) + } + }) + } pub fn active(&self) -> CosmicSurface { self.0 @@ -129,6 +376,11 @@ impl CosmicStack { .with_program(|p| &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] == window) } + pub fn whole_stack_focused(&self) -> bool { + self.0 + .with_program(|p| p.group_focused.load(Ordering::SeqCst)) + } + pub fn set_active(&self, window: &CosmicSurface) { self.0.with_program(|p| { if let Some(val) = p.windows.lock().unwrap().iter().position(|w| w == window) { @@ -136,7 +388,8 @@ impl CosmicStack { p.previous_keyboard.store(old, Ordering::SeqCst); p.previous_pointer.store(old, Ordering::SeqCst); } - }) + }); + self.0.force_redraw() } pub fn surfaces(&self) -> impl Iterator { @@ -155,14 +408,28 @@ impl CosmicStack { Point::from((0, TAB_HEIGHT)) } - pub fn set_geometry(&self, geo: Rectangle) { + pub fn pending_size(&self) -> Option> { + self.0.with_program(|p| { + p.geometry + .lock() + .unwrap() + .clone() + .map(|geo| geo.size.as_logical()) + }) + } + + pub fn set_geometry(&self, geo: Rectangle) { self.0.with_program(|p| { let loc = (geo.loc.x, geo.loc.y + TAB_HEIGHT); let size = (geo.size.w, geo.size.h - TAB_HEIGHT); + let win_geo = Rectangle::from_loc_and_size(loc, size); for window in p.windows.lock().unwrap().iter() { - window.set_geometry(Rectangle::from_loc_and_size(loc, size)); + window.set_geometry(win_geo); } + + *p.geometry.lock().unwrap() = Some(geo); + p.mask.lock().unwrap().take(); }); self.0.resize(Size::from((geo.size.w, TAB_HEIGHT))); } @@ -176,13 +443,18 @@ impl CosmicStack { self.0.with_program(|p| { let active = p.active.load(Ordering::SeqCst); let previous = p.previous_keyboard.swap(active, Ordering::SeqCst); - if previous != active { - KeyboardTarget::leave(&p.windows.lock().unwrap()[previous], seat, data, serial); + if previous != active || p.reenter.swap(false, Ordering::SeqCst) { + let windows = p.windows.lock().unwrap(); + if let Some(previous_surface) = windows.get(previous) { + if previous != active { + KeyboardTarget::leave(previous_surface, seat, data, serial); + } + } KeyboardTarget::enter( - &p.windows.lock().unwrap()[active], + &windows[active], seat, data, - Vec::new(), //seat.keys(), + Vec::new(), /* TODO */ serial, ) } @@ -202,31 +474,23 @@ impl CosmicStack { let active = p.active.load(Ordering::SeqCst); let previous = p.previous_pointer.swap(active, Ordering::SeqCst); if previous != active { - if let Some(sessions) = p.windows.lock().unwrap()[previous] - .user_data() - .get::() - { - for session in &*sessions.0.borrow() { - session.cursor_leave(seat, InputType::Pointer) + let windows = p.windows.lock().unwrap(); + if let Some(previous) = windows.get(previous) { + if let Some(sessions) = previous.user_data().get::() { + for session in &*sessions.0.borrow() { + session.cursor_leave(seat, InputType::Pointer) + } } + PointerTarget::leave(previous, seat, data, serial, time); } - PointerTarget::leave( - &p.windows.lock().unwrap()[previous], - seat, - data, - serial, - time, - ); - if let Some(sessions) = p.windows.lock().unwrap()[active] - .user_data() - .get::() - { + + if let Some(sessions) = windows[active].user_data().get::() { for session in &*sessions.0.borrow() { session.cursor_enter(seat, InputType::Pointer) } } PointerTarget::enter( - &p.windows.lock().unwrap()[active], + &windows[active], seat, data, &MotionEvent { @@ -239,20 +503,298 @@ impl CosmicStack { active }) } + + pub(in super::super) fn focus_stack(&self) { + self.0 + .with_program(|p| p.group_focused.store(true, Ordering::SeqCst)); + } + + pub(in super::super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::State> { + self.0.loop_handle() + } + + pub fn split_render_elements( + &self, + renderer: &mut R, + location: smithay::utils::Point, + scale: smithay::utils::Scale, + alpha: f32, + ) -> (Vec, Vec) + where + R: Renderer + ImportAll + ImportMem, + ::TextureId: 'static, + C: From>, + { + let stack_loc = location + + self + .0 + .with_program(|p| { + p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] + .geometry() + .loc + }) + .to_physical_precise_round(scale); + let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); + + let elements = AsRenderElements::::render_elements::>( + &self.0, renderer, stack_loc, scale, alpha, + ); + + let (window_elements, popup_elements) = self.0.with_program(|p| { + p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] + .split_render_elements::>( + renderer, window_loc, scale, alpha, + ) + }); + + ( + elements + .into_iter() + .map(C::from) + .chain(window_elements.into_iter().map(C::from)) + .collect(), + popup_elements.into_iter().map(C::from).collect(), + ) + } + + pub(crate) fn set_theme(&self, theme: cosmic::Theme) { + self.0.set_theme(theme); + } + + pub(crate) fn force_redraw(&self) { + self.0.force_redraw(); + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Message { + DragStart, + PotentialTabDragStart(usize), + Activate(usize), + Close(usize), + ScrollForward, + ScrollBack, + Scrolled, +} + +impl TabMessage for Message { + fn activate(idx: usize) -> Self { + Message::Activate(idx) + } + + fn is_activate(&self) -> Option { + match self { + Message::Activate(idx) => Some(*idx), + _ => None, + } + } + + fn scroll_back() -> Self { + Message::ScrollBack + } + + fn scroll_further() -> Self { + Message::ScrollForward + } + + fn populate_scroll(&mut self, mut current_offset: AbsoluteOffset) -> Option { + match self { + Message::ScrollBack => Some({ + current_offset.x -= 10.; + current_offset + }), + Message::ScrollForward => Some({ + current_offset.x += 10.; + current_offset + }), + _ => None, + } + } + + fn scrolled() -> Self { + Message::Scrolled + } } impl Program for CosmicStackInternal { - type Message = (); + type Message = Message; - fn view(&self) -> Element<'_, Self::Message> { - cosmic::iced::widget::text("TODO").into() + fn update( + &mut self, + message: Self::Message, + loop_handle: &LoopHandle<'static, crate::state::State>, + ) -> Command { + match message { + Message::DragStart => { + if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() { + if let Some(surface) = self.windows.lock().unwrap() + [self.active.load(Ordering::SeqCst)] + .wl_surface() + { + loop_handle.insert_idle(move |state| { + Shell::move_request(state, &surface, &seat, serial); + }); + } + } + } + Message::PotentialTabDragStart(idx) => { + *self.potential_drag.lock().unwrap() = Some(idx); + } + Message::Activate(idx) => { + *self.potential_drag.lock().unwrap() = None; + if self.windows.lock().unwrap().get(idx).is_some() { + let old = self.active.swap(idx, Ordering::SeqCst); + self.previous_keyboard.store(old, Ordering::SeqCst); + self.previous_pointer.store(old, Ordering::SeqCst); + self.scroll_to_focus.store(true, Ordering::SeqCst); + } + } + Message::Close(idx) => { + if let Some(val) = self.windows.lock().unwrap().get(idx) { + val.close() + } + } + Message::Scrolled => { + self.scroll_to_focus.store(false, Ordering::SeqCst); + } + _ => unreachable!(), + } + Command::none() + } + + fn view(&self) -> CosmicElement<'_, Self::Message> { + let windows = self.windows.lock().unwrap(); + if self.geometry.lock().unwrap().is_none() { + return iced_widget::row(Vec::new()).into(); + }; + let active = self.active.load(Ordering::SeqCst); + let group_focused = self.group_focused.load(Ordering::SeqCst); + + let elements = vec![ + cosmic_widget::icon::from_name("window-stack-symbolic") + .size(16) + .prefer_svg(true) + .icon() + .style(if group_focused { + theme::Svg::custom(|theme| iced_widget::svg::Appearance { + color: Some(if theme.cosmic().is_dark { + Color::BLACK + } else { + Color::WHITE + }), + }) + } else { + theme::Svg::Default + }) + .apply(iced_widget::container) + .padding([4, 24]) + .center_y() + .apply(iced_widget::mouse_area) + .on_press(Message::DragStart) + .into(), + CosmicElement::new( + Tabs::new( + windows.iter().enumerate().map(|(i, w)| { + let user_data = w.user_data(); + user_data.insert_if_missing(Id::unique); + Tab::new( + w.title(), + w.app_id(), + user_data.get::().unwrap().clone(), + ) + .on_press(Message::PotentialTabDragStart(i)) + .on_close(Message::Close(i)) + }), + active, + windows[active].is_activated(false), + group_focused, + ) + .id(SCROLLABLE_ID.clone()) + .force_visible( + self.scroll_to_focus + .load(Ordering::SeqCst) + .then_some(active), + ) + .height(Length::Fill) + .width(Length::Fill), + ), + iced_widget::horizontal_space(0) + .apply(iced_widget::container) + .padding([64, 24]) + .apply(iced_widget::mouse_area) + .on_press(Message::DragStart) + .into(), + ]; + + iced_widget::row(elements) + .height(TAB_HEIGHT as u16) + .width(Length::Fill) //width as u16) + .apply(iced_widget::container) + .center_y() + .style(if self.group_focused.load(Ordering::SeqCst) { + theme::Container::custom(|theme| iced_widget::container::Appearance { + icon_color: Some(Color::from(theme.cosmic().background.on)), + text_color: Some(Color::from(theme.cosmic().background.on)), + background: Some(Background::Color(theme.cosmic().accent_color().into())), + border_radius: BorderRadius::from([8.0, 8.0, 0.0, 0.0]), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }) + } else { + theme::Container::custom(|theme| iced_widget::container::Appearance { + icon_color: Some(Color::from(theme.cosmic().background.on)), + text_color: Some(Color::from(theme.cosmic().background.on)), + background: Some(Background::Color(theme.cosmic().palette.neutral_3.into())), + border_radius: BorderRadius::from([8.0, 8.0, 0.0, 0.0]), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }) + }) + .into() + } + + fn foreground( + &self, + pixels: &mut tiny_skia::PixmapMut<'_>, + damage: &[Rectangle], + scale: f32, + ) { + if self.group_focused.load(Ordering::SeqCst) { + let border = Rectangle::from_loc_and_size( + (0, ((TAB_HEIGHT as f32 * scale) - scale).floor() as i32), + (pixels.width() as i32, scale.ceil() as i32), + ); + + let mut paint = tiny_skia::Paint::default(); + let (b, g, r, a) = theme::COSMIC_DARK.accent_color().into_components(); + paint.set_color(tiny_skia::Color::from_rgba(r, g, b, a).unwrap()); + + for rect in damage { + if let Some(overlap) = rect.intersection(border) { + pixels.fill_rect( + tiny_skia::Rect::from_xywh( + overlap.loc.x as f32, + overlap.loc.y as f32, + overlap.size.w as f32, + overlap.size.h as f32, + ) + .unwrap(), + &paint, + Default::default(), + None, + ) + } + } + } } } impl IsAlive for CosmicStack { fn alive(&self) -> bool { - self.0 - .with_program(|p| p.windows.lock().unwrap().iter().any(IsAlive::alive)) + self.0.with_program(|p| { + p.override_alive.load(Ordering::SeqCst) + && p.windows.lock().unwrap().iter().any(IsAlive::alive) + }) } } @@ -280,13 +822,17 @@ impl SpaceElement for CosmicStack { } fn set_activate(&self, activated: bool) { SpaceElement::set_activate(&self.0, activated); + self.0.force_redraw(); self.0.with_program(|p| { - p.windows - .lock() - .unwrap() - .iter() - .for_each(|w| SpaceElement::set_activate(w, activated)) - }) + p.activated.store(activated, Ordering::SeqCst); + if !p.group_focused.load(Ordering::SeqCst) { + p.windows + .lock() + .unwrap() + .iter() + .for_each(|w| SpaceElement::set_activate(w, activated)) + } + }); } fn output_enter(&self, output: &Output, overlap: Rectangle) { SpaceElement::output_enter(&self.0, output, overlap); @@ -322,17 +868,25 @@ impl SpaceElement for CosmicStack { }) } fn refresh(&self) { + SpaceElement::refresh(&self.0); self.0.with_program(|p| { let mut windows = p.windows.lock().unwrap(); - windows.retain(IsAlive::alive); // TODO: We don't handle empty stacks properly + + // don't let the stack become empty + let active = windows[p.active.load(Ordering::SeqCst)].clone(); + windows.retain(IsAlive::alive); + if windows.is_empty() { + windows.push(active); + } + let len = windows.len(); let _ = p .active .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |active| { - (active > len).then_some(len - 1) + (active >= len).then_some(len - 1) }); - windows.iter().for_each(|w| SpaceElement::refresh(w)) - }) + windows.iter().for_each(|w| SpaceElement::refresh(w)); + }); } } @@ -358,7 +912,9 @@ impl KeyboardTarget for CosmicStack { } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial) { let active = self.keyboard_leave_if_previous(seat, data, serial); + self.0.force_redraw(); self.0.with_program(|p| { + p.group_focused.store(false, Ordering::SeqCst); KeyboardTarget::leave(&p.windows.lock().unwrap()[active], seat, data, serial) }) } @@ -373,15 +929,17 @@ impl KeyboardTarget for CosmicStack { ) { let active = self.keyboard_leave_if_previous(seat, data, serial); self.0.with_program(|p| { - KeyboardTarget::key( - &p.windows.lock().unwrap()[active], - seat, - data, - key, - state, - serial, - time, - ) + if !p.group_focused.load(Ordering::SeqCst) { + KeyboardTarget::key( + &p.windows.lock().unwrap()[active], + seat, + data, + key, + state, + serial, + time, + ) + } }) } fn modifiers( @@ -393,62 +951,68 @@ impl KeyboardTarget for CosmicStack { ) { let active = self.keyboard_leave_if_previous(seat, data, serial); self.0.with_program(|p| { - KeyboardTarget::modifiers( - &p.windows.lock().unwrap()[active], - seat, - data, - modifiers, - serial, - ) + if !p.group_focused.load(Ordering::SeqCst) { + KeyboardTarget::modifiers( + &p.windows.lock().unwrap()[active], + seat, + data, + modifiers, + serial, + ) + } }) } } impl PointerTarget for CosmicStack { fn enter(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { + let mut event = event.clone(); + event.location.y -= TAB_HEIGHT as f64; if self.0.with_program(|p| { - if let Some(sessions) = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] - .user_data() - .get::() - { + let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + if let Some(sessions) = active_window.user_data().get::() { for session in &*sessions.0.borrow() { session.cursor_enter(seat, InputType::Pointer) } } - if event.location.y < TAB_HEIGHT as f64 { - let focus = p.swap_focus(Focus::Header); - assert_eq!(focus, Focus::None); + if (event.location.y - active_window.geometry().loc.y as f64) < 0. { + let previous = p.swap_focus(Focus::Header); + if previous == Focus::Window { + PointerTarget::leave(active_window, seat, data, event.serial, event.time); + } true } else { - let focus = p.swap_focus(Focus::Window); - assert_eq!(focus, Focus::None); + p.swap_focus(Focus::Window); *p.last_location.lock().unwrap() = Some((event.location, event.serial, event.time)); let active = p.active.load(Ordering::SeqCst); p.previous_pointer.store(active, Ordering::SeqCst); - PointerTarget::enter( - &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)], - seat, - data, - event, - ); + PointerTarget::enter(active_window, seat, data, &event); false } }) { - PointerTarget::enter(&self.0, seat, data, event) + event.location.y += TAB_HEIGHT as f64; + event.location -= self.0.with_program(|p| { + p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] + .geometry() + .loc + .to_f64() + }); + PointerTarget::enter(&self.0, seat, data, &event) } } fn motion(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { + let mut event = event.clone(); + event.location.y -= TAB_HEIGHT as f64; let active = self.pointer_leave_if_previous(seat, data, event.serial, event.time, event.location); + if let Some((previous, next)) = self.0.with_program(|p| { - if let Some(sessions) = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] - .user_data() - .get::() - { + let active_window = &p.windows.lock().unwrap()[active]; + if let Some(sessions) = active_window.user_data().get::() { for session in &*sessions.0.borrow() { let buffer_loc = (event.location.x, event.location.y); // we always screencast windows at 1x1 scale if let Some((geo, hotspot)) = @@ -459,37 +1023,99 @@ impl PointerTarget for CosmicStack { } } - if event.location.y < TAB_HEIGHT as f64 { + if (event.location.y - active_window.geometry().loc.y as f64) < 0. { let previous = p.swap_focus(Focus::Header); if previous == Focus::Window { - PointerTarget::leave( - &p.windows.lock().unwrap()[active], - seat, - data, - event.serial, - event.time, - ); + PointerTarget::leave(active_window, seat, data, event.serial, event.time); } Some((previous, Focus::Header)) } else { - let mut event = event.clone(); - event.location.y -= TAB_HEIGHT as f64; + *p.last_location.lock().unwrap() = Some((event.location, event.serial, event.time)); let previous = p.swap_focus(Focus::Window); if previous != Focus::Window { - PointerTarget::enter(&p.windows.lock().unwrap()[active], seat, data, &event); + PointerTarget::enter(active_window, seat, data, &event); } else { - PointerTarget::motion(&p.windows.lock().unwrap()[active], seat, data, &event); + PointerTarget::motion(active_window, seat, data, &event); } Some((previous, Focus::Window)) } }) { + event.location.y += TAB_HEIGHT as f64; + event.location -= self + .0 + .with_program(|p| p.windows.lock().unwrap()[active].geometry().loc.to_f64()); match (previous, next) { - (Focus::Header, Focus::Header) => PointerTarget::motion(&self.0, seat, data, event), - (_, Focus::Header) => PointerTarget::enter(&self.0, seat, data, event), + (Focus::Header, Focus::Header) => { + PointerTarget::motion(&self.0, seat, data, &event) + } + (_, Focus::Header) => PointerTarget::enter(&self.0, seat, data, &event), (Focus::Header, _) => { - PointerTarget::leave(&self.0, seat, data, event.serial, event.time) + PointerTarget::leave(&self.0, seat, data, event.serial, event.time); + if let Some(dragged_out) = self + .0 + .with_program(|p| p.potential_drag.lock().unwrap().take()) + { + if let Some(surface) = self + .0 + .with_program(|p| p.windows.lock().unwrap().get(dragged_out).cloned()) + { + if let Some(stack_mapped) = + data.common.shell.element_for_surface(&surface) + { + if let Some(workspace) = data.common.shell.space_for(stack_mapped) { + // TODO: Unify this somehow with Shell::move_request/Workspace::move_request + let button = 0x110; // BTN_LEFT + let pos = event.location.as_global(); + let start_data = PointerGrabStartData { + focus: None, + button, + location: pos.as_logical(), + }; + let mapped = CosmicMapped::from(CosmicWindow::new( + surface, + self.0.loop_handle(), + data.common.theme.clone(), + )); + let elem_geo = + workspace.element_geometry(stack_mapped).unwrap(); + let indicator_thickness = + data.common.theme.cosmic().active_hint as u8; + let was_tiled = workspace.is_tiled(stack_mapped); + + self.remove_idx(dragged_out); + mapped.configure(); + + let grab = MoveGrab::new( + start_data, + mapped, + seat, + pos, + pos.to_i32_round() - Point::from((elem_geo.size.w / 2, 24)), + indicator_thickness, + was_tiled, + ); + if grab.is_tiling_grab() { + data.common.shell.set_overview_mode( + Some(Trigger::Pointer(button)), + data.common.event_loop_handle.clone(), + ); + } + + let seat = seat.clone(); + data.common.event_loop_handle.insert_idle(move |state| { + seat.get_pointer().unwrap().set_grab( + state, + grab, + event.serial, + smithay::input::pointer::Focus::Clear, + ); + }); + } + } + } + } } _ => {} } @@ -514,20 +1140,60 @@ impl PointerTarget for CosmicStack { } match self.0.with_program(|p| p.current_focus()) { - Focus::Header => PointerTarget::button(&self.0, seat, data, event), + Focus::Header => { + self.0.with_program(|p| { + *p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); + }); + PointerTarget::button(&self.0, seat, data, event) + } + Focus::Window => { + if self.0.with_program(|p| { + PointerTarget::button( + &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)], + seat, + data, + event, + ); + if p.group_focused.swap(false, Ordering::SeqCst) { + p.windows.lock().unwrap().iter().for_each(|w| { + SpaceElement::set_activate(w, true); + w.send_configure(); + }); + true + } else { + false + } + }) { + self.0.force_redraw(); + } + } + _ => {} + } + } + + fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { + if let Some((location, serial, time)) = self + .0 + .with_program(|p| p.last_location.lock().unwrap().clone()) + { + self.pointer_leave_if_previous(seat, data, serial, time, location); + } + + match self.0.with_program(|p| p.current_focus()) { + Focus::Header => PointerTarget::axis(&self.0, seat, data, frame), Focus::Window => self.0.with_program(|p| { - PointerTarget::button( + PointerTarget::axis( &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)], seat, data, - event, + frame, ) }), _ => {} } } - fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { + fn frame(&self, seat: &Seat, data: &mut State) { if let Some((location, serial, time)) = self .0 .with_program(|p| p.last_location.lock().unwrap().clone()) @@ -536,13 +1202,12 @@ impl PointerTarget for CosmicStack { } match self.0.with_program(|p| p.current_focus()) { - Focus::Header => PointerTarget::axis(&self.0, seat, data, frame), + Focus::Header => PointerTarget::frame(&self.0, seat, data), Focus::Window => self.0.with_program(|p| { - PointerTarget::axis( + PointerTarget::frame( &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)], seat, data, - frame, ) }), _ => {} @@ -569,7 +1234,6 @@ impl PointerTarget for CosmicStack { p.swap_focus(Focus::None) }); - assert!(previous != Focus::None); match previous { Focus::Header => PointerTarget::leave(&self.0, seat, data, serial, time), @@ -585,41 +1249,117 @@ impl PointerTarget for CosmicStack { _ => {} } } -} -render_elements! { - pub CosmicStackRenderElement where R: ImportAll + ImportMem; - Header=MemoryRenderBufferRenderElement, - Window=WaylandSurfaceRenderElement, -} + fn gesture_swipe_begin( + &self, + seat: &Seat, + data: &mut State, + event: &GestureSwipeBeginEvent, + ) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_swipe_begin(seat, data, event) + } + }) + } -impl AsRenderElements for CosmicStack -where - R: Renderer + ImportAll + ImportMem, - ::TextureId: 'static, -{ - type RenderElement = CosmicStackRenderElement; - fn render_elements>( + fn gesture_swipe_update( &self, - renderer: &mut R, - mut location: Point, - scale: Scale, - ) -> Vec { - let mut elements = AsRenderElements::::render_elements::>( - &self.0, renderer, location, scale, - ); - location.y += TAB_HEIGHT; + seat: &Seat, + data: &mut State, + event: &GestureSwipeUpdateEvent, + ) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_swipe_update(seat, data, event) + } + }) + } - elements.extend(self.0.with_program(|p| { - let elements = AsRenderElements::::render_elements::>( - &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)], - renderer, - location, - scale, - ); - elements - })); + fn gesture_swipe_end( + &self, + seat: &Seat, + data: &mut State, + event: &GestureSwipeEndEvent, + ) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_swipe_end(seat, data, event) + } + }) + } + + fn gesture_pinch_begin( + &self, + seat: &Seat, + data: &mut State, + event: &GesturePinchBeginEvent, + ) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_pinch_begin(seat, data, event) + } + }) + } - elements.into_iter().map(C::from).collect() + fn gesture_pinch_update( + &self, + seat: &Seat, + data: &mut State, + event: &GesturePinchUpdateEvent, + ) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_pinch_update(seat, data, event) + } + }) + } + + fn gesture_pinch_end( + &self, + seat: &Seat, + data: &mut State, + event: &GesturePinchEndEvent, + ) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_pinch_end(seat, data, event) + } + }) } + + fn gesture_hold_begin( + &self, + seat: &Seat, + data: &mut State, + event: &GestureHoldBeginEvent, + ) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_hold_begin(seat, data, event) + } + }) + } + + fn gesture_hold_end(&self, seat: &Seat, data: &mut State, event: &GestureHoldEndEvent) { + self.0.with_program(|p| { + if p.current_focus() == Focus::Window { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.gesture_hold_end(seat, data, event) + } + }) + } +} + +render_elements! { + pub CosmicStackRenderElement where R: ImportAll + ImportMem; + Header = MemoryRenderBufferRenderElement, + Window = WaylandSurfaceRenderElement, } diff --git a/src/shell/element/stack/tab.rs b/src/shell/element/stack/tab.rs new file mode 100644 index 00000000..48b9933e --- /dev/null +++ b/src/shell/element/stack/tab.rs @@ -0,0 +1,462 @@ +use cosmic::{ + font::Font, + iced::{ + widget::{self, container::draw_background, rule::FillMode}, + Element, + }, + iced_core::{ + alignment, event, + layout::{Layout, Limits, Node}, + mouse, overlay, renderer, + widget::{ + operation::{Operation, OperationOutputWrapper}, + text::StyleSheet as TextStyleSheet, + tree::Tree, + Id, Widget, + }, + Clipboard, Color, Length, Rectangle, Shell, Size, + }, + iced_style::{ + button::StyleSheet as ButtonStyleSheet, container::StyleSheet as ContainerStyleSheet, + rule::StyleSheet as RuleStyleSheet, + }, + iced_widget::{scrollable::AbsoluteOffset, text}, + theme, + widget::{icon::from_name, Icon}, + Apply, +}; + +use super::tab_text::tab_text; + +pub(super) enum TabRuleTheme { + ActiveActivated, + ActiveDeactivated, + Default, +} + +impl Into for TabRuleTheme { + fn into(self) -> theme::Rule { + match self { + Self::ActiveActivated => theme::Rule::custom(|theme| widget::rule::Appearance { + color: theme.cosmic().accent_color().into(), + width: 4, + radius: 0.0.into(), + fill_mode: FillMode::Full, + }), + Self::ActiveDeactivated => theme::Rule::custom(|theme| widget::rule::Appearance { + color: theme.cosmic().palette.neutral_5.into(), + width: 4, + radius: 0.0.into(), + fill_mode: FillMode::Full, + }), + Self::Default => theme::Rule::custom(|theme| widget::rule::Appearance { + color: theme.cosmic().palette.neutral_5.into(), + width: 4, + radius: 8.0.into(), + fill_mode: FillMode::Padded(4), + }), + } + } +} + +pub(super) enum TabBackgroundTheme { + ActiveActivated, + ActiveDeactivated, + Default, +} + +impl TabBackgroundTheme { + fn background_color(&self) -> Color { + match self { + TabBackgroundTheme::ActiveActivated => Color::from_rgba(0.365, 0.365, 0.365, 1.0), + TabBackgroundTheme::ActiveDeactivated => Color::from_rgba(0.365, 0.365, 0.365, 1.0), + TabBackgroundTheme::Default => Color::from_rgba(0.26, 0.26, 0.26, 1.0), + } + } +} + +impl Into for TabBackgroundTheme { + fn into(self) -> theme::Container { + let background_color = cosmic::iced::Background::Color(self.background_color()); + match self { + Self::ActiveActivated => { + theme::Container::custom(move |theme| widget::container::Appearance { + icon_color: Some(Color::from(theme.cosmic().accent_text_color())), + text_color: Some(Color::from(theme.cosmic().accent_text_color())), + background: Some(background_color), + border_radius: 0.0.into(), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }) + } + Self::ActiveDeactivated => { + theme::Container::custom(move |_theme| widget::container::Appearance { + icon_color: None, + text_color: None, + background: Some(background_color), + border_radius: 0.0.into(), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }) + } + Self::Default => theme::Container::Transparent, + } + } +} + +pub trait TabMessage: Clone { + fn activate(idx: usize) -> Self; + fn is_activate(&self) -> Option; + + fn scroll_further() -> Self; + fn scroll_back() -> Self; + fn populate_scroll(&mut self, current_offset: AbsoluteOffset) -> Option; + fn scrolled() -> Self; +} + +pub struct Tab { + id: Id, + app_icon: Icon, + title: String, + font: Font, + close_message: Option, + press_message: Option, + rule_theme: TabRuleTheme, + background_theme: TabBackgroundTheme, + active: bool, +} + +impl Tab { + pub fn new(title: impl Into, app_id: impl Into, id: Id) -> Self { + Tab { + id, + app_icon: from_name(app_id.into()).size(16).icon(), + title: title.into(), + font: cosmic::font::FONT, + close_message: None, + press_message: None, + rule_theme: TabRuleTheme::Default, + background_theme: TabBackgroundTheme::Default, + active: false, + } + } + + pub fn on_press(mut self, message: Message) -> Self { + self.press_message = Some(message); + self + } + + pub fn on_close(mut self, message: Message) -> Self { + self.close_message = Some(message); + self + } + + pub(super) fn font(mut self, font: Font) -> Self { + self.font = font; + self + } + + pub(super) fn rule_style(mut self, theme: TabRuleTheme) -> Self { + self.rule_theme = theme; + self + } + + pub(super) fn background_style(mut self, theme: TabBackgroundTheme) -> Self { + self.background_theme = theme; + self + } + + pub(super) fn non_active(mut self) -> Self { + self.active = false; + self + } + + pub(super) fn active(mut self) -> Self { + self.active = true; + self + } + + pub(super) fn internal<'a, Renderer>(self, idx: usize) -> TabInternal<'a, Message, Renderer> + where + Renderer: cosmic::iced_core::Renderer + 'a, + Renderer: cosmic::iced_core::text::Renderer, + Renderer::Theme: ButtonStyleSheet