update smithay, iced; reworked window for xwayland
This commit is contained in:
parent
47dfc85314
commit
7992ad67f6
27 changed files with 2285 additions and 1106 deletions
226
Cargo.lock
generated
226
Cargo.lock
generated
|
|
@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ab_glyph"
|
name = "ab_glyph"
|
||||||
version = "0.2.18"
|
version = "0.2.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4dcdbc68024b653943864d436fe8a24b028095bc1cf91a8926f8241e4aaffe59"
|
checksum = "e5568a4aa5ba8adf5175c5c460b030e27d8893412976cc37bef0e4fbc16cfbba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ab_glyph_rasterizer",
|
"ab_glyph_rasterizer",
|
||||||
"owned_ttf_parser",
|
"owned_ttf_parser",
|
||||||
|
|
@ -20,9 +20,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ab_glyph_rasterizer"
|
name = "ab_glyph_rasterizer"
|
||||||
version = "0.1.7"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6"
|
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
|
|
@ -151,18 +151,18 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ash"
|
name = "ash"
|
||||||
version = "0.37.1+1.3.235"
|
version = "0.37.2+1.3.238"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "911015c962d56e2e4052f40182ca5462ba60a3d2ff04e827c365a0ab3d65726d"
|
checksum = "28bf19c1f0a470be5fbf7522a308a05df06610252c5bcf5143e1b23f629a9a03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic_refcell"
|
name = "atomic_refcell"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d"
|
checksum = "857253367827bd9d0fd973f0ef15506a96e79e41b0ad7aa691203a4e3214f6c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
|
|
@ -432,14 +432,15 @@ dependencies = [
|
||||||
"cosmic-protocols",
|
"cosmic-protocols",
|
||||||
"edid-rs",
|
"edid-rs",
|
||||||
"egui",
|
"egui",
|
||||||
"iced_swbuf",
|
"iced_softbuffer",
|
||||||
"id_tree",
|
"id_tree",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log-panics",
|
|
||||||
"libcosmic",
|
"libcosmic",
|
||||||
"libsystemd",
|
"libsystemd 0.5.0",
|
||||||
"log",
|
"log",
|
||||||
|
"log-panics",
|
||||||
|
"ordered-float",
|
||||||
"png",
|
"png",
|
||||||
"regex",
|
"regex",
|
||||||
"renderdoc",
|
"renderdoc",
|
||||||
|
|
@ -466,7 +467,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-protocols"
|
name = "cosmic-protocols"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#c0754ff393898d15616f165fdd1e308b4100c971"
|
source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#1615d9048198d3beac93184259046cf546d63657"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
|
|
@ -498,7 +499,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-theme"
|
name = "cosmic-theme"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/cosmic-theme.git#77aad06a6e3e2996ef24fc12e5f59d6da7226692"
|
source = "git+https://github.com/pop-os/cosmic-theme.git#5c84b81c67a69e3752bc2fdc451f9d49857ceabf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"csscolorparser",
|
"csscolorparser",
|
||||||
|
|
@ -596,6 +597,16 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csscolorparser"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf"
|
||||||
|
dependencies = [
|
||||||
|
"phf",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cty"
|
name = "cty"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|
@ -727,7 +738,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "directories"
|
name = "directories"
|
||||||
version = "4.0.1"
|
version = "4.0.1"
|
||||||
source = "git+https://github.com/edfloreshz/directories-rs#b93c018bc319f066fbeadcd8e3b865f1fccaaa8c"
|
source = "git+https://github.com/edfloreshz/directories-rs#6a6d83d853a35ee3273034215c4defaf61286fe5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dirs-sys",
|
"dirs-sys",
|
||||||
|
|
@ -1176,9 +1187,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "freedesktop-icons"
|
name = "freedesktop-icons"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e31823094643eabe14030d2f1b3f0aa10164f27b1a31e2b938ffe8ea9c9fc91b"
|
checksum = "00e61ac115df4632b592d36b71fda3c259f4c8061c70b7fa429bac145890e880"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -1488,9 +1499,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "2.2.0"
|
version = "2.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c467d36af040b7b2681f5fddd27427f6da8d3d072f575a265e181d2f8e8d157"
|
checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crunchy",
|
"crunchy",
|
||||||
]
|
]
|
||||||
|
|
@ -1550,13 +1561,14 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced"
|
name = "iced"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
"iced_glow",
|
"iced_glow",
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"iced_native",
|
"iced_native",
|
||||||
"iced_swbuf",
|
"iced_softbuffer",
|
||||||
"iced_wgpu",
|
"iced_wgpu",
|
||||||
"image",
|
"image",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
@ -1565,6 +1577,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_core"
|
name = "iced_core"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"palette",
|
"palette",
|
||||||
|
|
@ -1574,6 +1587,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_futures"
|
name = "iced_futures"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -1584,6 +1598,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_glow"
|
name = "iced_glow"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"euclid",
|
"euclid",
|
||||||
|
|
@ -1598,6 +1613,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_graphics"
|
name = "iced_graphics"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -1617,6 +1633,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_lazy"
|
name = "iced_lazy"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_native",
|
"iced_native",
|
||||||
"ouroboros 0.13.0",
|
"ouroboros 0.13.0",
|
||||||
|
|
@ -1625,6 +1642,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_native"
|
name = "iced_native"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
|
@ -1635,17 +1653,9 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_style"
|
name = "iced_softbuffer"
|
||||||
version = "0.5.1"
|
|
||||||
dependencies = [
|
|
||||||
"iced_core",
|
|
||||||
"once_cell",
|
|
||||||
"palette",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iced_swbuf"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
|
|
@ -1657,9 +1667,20 @@ dependencies = [
|
||||||
"softbuffer",
|
"softbuffer",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iced_style"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
|
dependencies = [
|
||||||
|
"iced_core",
|
||||||
|
"once_cell",
|
||||||
|
"palette",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_wgpu"
|
name = "iced_wgpu"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -1755,9 +1776,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.3"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
|
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
|
|
@ -1861,6 +1882,7 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcosmic"
|
name = "libcosmic"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/pop-os/libcosmic?branch=ci_add_without_shell#99842258b4d77dcb0657b7c299bae45579e139a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"apply",
|
"apply",
|
||||||
"cosmic-theme",
|
"cosmic-theme",
|
||||||
|
|
@ -1870,8 +1892,8 @@ dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_lazy",
|
"iced_lazy",
|
||||||
"iced_native",
|
"iced_native",
|
||||||
|
"iced_softbuffer",
|
||||||
"iced_style",
|
"iced_style",
|
||||||
"iced_swbuf",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"palette",
|
"palette",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
|
|
@ -1924,7 +1946,7 @@ dependencies = [
|
||||||
"hmac 0.11.0",
|
"hmac 0.11.0",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nix 0.23.1",
|
"nix 0.23.2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2 0.9.9",
|
"sha2 0.9.9",
|
||||||
|
|
@ -1995,6 +2017,17 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lyon_geom"
|
||||||
|
version = "0.16.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ce4e12203c428a58200b8cf1c0a3aad1cda907008ea11310bb3729593e5f933"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec 0.5.2",
|
||||||
|
"euclid",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
|
|
@ -2246,9 +2279,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.2"
|
version = "7.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c"
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
|
|
@ -2345,9 +2378,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.30.0"
|
version = "0.30.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
|
checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
@ -2358,6 +2391,12 @@ version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-float"
|
name = "ordered-float"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
|
|
@ -2424,19 +2463,13 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "opaque-debug"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owned_ttf_parser"
|
name = "owned_ttf_parser"
|
||||||
version = "0.17.1"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18904d3c65493a9f0d7542293d1a7f69bfdc309a6b9ef4f46dc3e58b0577edc5"
|
checksum = "2a5f3c7ca08b6879e7965fb25e24d1f5eeb32ea73f9ad99b3854778a38c57e93"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ttf-parser 0.17.1",
|
"ttf-parser 0.18.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2482,7 +2515,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"parking_lot_core 0.9.5",
|
"parking_lot_core 0.9.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2501,9 +2534,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.9.5"
|
version = "0.9.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
|
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -2827,9 +2860,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.7.0"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -3280,7 +3313,7 @@ dependencies = [
|
||||||
"wayland-server",
|
"wayland-server",
|
||||||
"wayland-sys 0.30.1",
|
"wayland-sys 0.30.1",
|
||||||
"winit",
|
"winit",
|
||||||
"x11rb",
|
"x11rb 0.10.1",
|
||||||
"xkbcommon 0.5.0",
|
"xkbcommon 0.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -3326,12 +3359,17 @@ checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "softbuffer"
|
name = "softbuffer"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/rust-windowing/softbuffer?rev=d5bb2c1#d5bb2c1c78811854d11225ff7cc29f0062781333"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3177eca2c15033e254b9b70c4915150200b1cf6fa777de18be9977ae5850077f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"cfg_aliases",
|
||||||
"cocoa",
|
"cocoa",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
|
"fastrand",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
|
"log",
|
||||||
"nix 0.26.1",
|
"nix 0.26.1",
|
||||||
"objc",
|
"objc",
|
||||||
"raw-window-handle 0.5.0",
|
"raw-window-handle 0.5.0",
|
||||||
|
|
@ -3344,6 +3382,7 @@ dependencies = [
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
"x11-dl",
|
"x11-dl",
|
||||||
|
"x11rb 0.11.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3493,9 +3532,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.3"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
@ -3639,6 +3678,12 @@ version = "0.17.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
|
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ttf-parser"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "twox-hash"
|
name = "twox-hash"
|
||||||
version = "1.6.3"
|
version = "1.6.3"
|
||||||
|
|
@ -3652,9 +3697,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typed-arena"
|
name = "typed-arena"
|
||||||
version = "2.0.1"
|
version = "2.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
|
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
|
|
@ -4280,19 +4325,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc 0.42.0",
|
"windows_aarch64_msvc 0.42.1",
|
||||||
"windows_i686_gnu 0.42.0",
|
"windows_i686_gnu 0.42.1",
|
||||||
"windows_i686_msvc 0.42.0",
|
"windows_i686_msvc 0.42.1",
|
||||||
"windows_x86_64_gnu 0.42.0",
|
"windows_x86_64_gnu 0.42.1",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm",
|
||||||
"windows_x86_64_msvc 0.42.0",
|
"windows_x86_64_msvc 0.42.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.0"
|
version = "0.42.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
|
|
@ -4302,9 +4347,9 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.0"
|
version = "0.42.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
|
|
@ -4314,9 +4359,9 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.0"
|
version = "0.42.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
|
|
@ -4326,9 +4371,9 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.0"
|
version = "0.42.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
|
|
@ -4338,15 +4383,15 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.0"
|
version = "0.42.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.0"
|
version = "0.42.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
|
|
@ -4356,9 +4401,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.0"
|
version = "0.42.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
|
|
@ -4422,7 +4467,23 @@ dependencies = [
|
||||||
"nix 0.24.3",
|
"nix 0.24.3",
|
||||||
"winapi",
|
"winapi",
|
||||||
"winapi-wsapoll",
|
"winapi-wsapoll",
|
||||||
"x11rb-protocol",
|
"x11rb-protocol 0.10.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x11rb"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdf3c79412dd91bae7a7366b8ad1565a85e35dd049affc3a6a2c549e97419617"
|
||||||
|
dependencies = [
|
||||||
|
"gethostname",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
"nix 0.25.1",
|
||||||
|
"once_cell",
|
||||||
|
"winapi",
|
||||||
|
"winapi-wsapoll",
|
||||||
|
"x11rb-protocol 0.11.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4434,6 +4495,15 @@ dependencies = [
|
||||||
"nix 0.24.3",
|
"nix 0.24.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x11rb-protocol"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0b1513b141123073ce54d5bb1d33f801f17508fbd61e02060b1214e96d39c56"
|
||||||
|
dependencies = [
|
||||||
|
"nix 0.25.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xcursor"
|
name = "xcursor"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,9 @@ libsystemd = "0.5"
|
||||||
wayland-backend = "0.1.0"
|
wayland-backend = "0.1.0"
|
||||||
wayland-scanner = "0.30.0"
|
wayland-scanner = "0.30.0"
|
||||||
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] }
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] }
|
||||||
libcosmic = { path = "../libcosmic", default-features = false, features = ["swbuf"] } #{ git = "https://github.com/pop-os/libcosmic", rev = "444e389496", default-features = false, features = ["swbuf"] }
|
libcosmic = { git = "https://github.com/pop-os/libcosmic", branch = "ci_add_without_shell", default-features = false, features = ["softbuffer"] }
|
||||||
iced_swbuf = { path = "../libcosmic/iced/swbuf" }
|
iced_softbuffer = { git = "https://github.com/pop-os/libcosmic", branch = "ci_add_without_shell" }
|
||||||
|
ordered-float = "3.0"
|
||||||
|
|
||||||
[dependencies.smithay]
|
[dependencies.smithay]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ use smithay::{
|
||||||
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
|
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
|
||||||
},
|
},
|
||||||
utils::{DeviceFd, Size, Transform},
|
utils::{DeviceFd, Size, Transform},
|
||||||
wayland::dmabuf::DmabufGlobal,
|
wayland::{dmabuf::DmabufGlobal, seat::WaylandFocus},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -787,7 +787,7 @@ fn render_node_for_output(
|
||||||
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|w| {
|
.flat_map(|w| {
|
||||||
dh.get_client(w.toplevel().wl_surface().id())
|
dh.get_client(w.wl_surface()?.id())
|
||||||
.ok()?
|
.ok()?
|
||||||
.get_data::<ClientState>()
|
.get_data::<ClientState>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{Element, RenderElement, UnderlyingStorage},
|
element::{Element, RenderElement, UnderlyingStorage},
|
||||||
glow::{GlowFrame, GlowRenderer},
|
glow::{GlowFrame, GlowRenderer},
|
||||||
Frame, ImportAll, Renderer,
|
Frame, ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
utils::{Buffer as BufferCoords, Physical, Point, Rectangle, Scale},
|
utils::{Buffer as BufferCoords, Physical, Point, Rectangle, Scale},
|
||||||
};
|
};
|
||||||
|
|
@ -18,7 +18,7 @@ use super::{cursor::CursorRenderElement, GlMultiFrame, GlMultiRenderer};
|
||||||
|
|
||||||
pub enum CosmicElement<R>
|
pub enum CosmicElement<R>
|
||||||
where
|
where
|
||||||
R: AsGlowRenderer + Renderer + ImportAll,
|
R: AsGlowRenderer + Renderer + ImportAll + ImportMem,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +31,7 @@ where
|
||||||
|
|
||||||
impl<R> Element for CosmicElement<R>
|
impl<R> Element for CosmicElement<R>
|
||||||
where
|
where
|
||||||
R: AsGlowRenderer + Renderer + ImportAll,
|
R: AsGlowRenderer + Renderer + ImportAll + ImportMem,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -203,7 +203,7 @@ impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicElement<GlMultiRenderer<'a
|
||||||
|
|
||||||
impl<R> From<WorkspaceRenderElement<R>> for CosmicElement<R>
|
impl<R> From<WorkspaceRenderElement<R>> for CosmicElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -214,7 +214,7 @@ where
|
||||||
|
|
||||||
impl<R> From<CursorRenderElement<R>> for CosmicElement<R>
|
impl<R> From<CursorRenderElement<R>> for CosmicElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -225,7 +225,7 @@ where
|
||||||
|
|
||||||
impl<R> From<CosmicMappedRenderElement<R>> for CosmicElement<R>
|
impl<R> From<CosmicMappedRenderElement<R>> for CosmicElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -237,7 +237,7 @@ where
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
impl<R> From<TextureRenderElement<Gles2Texture>> for CosmicElement<R>
|
impl<R> From<TextureRenderElement<Gles2Texture>> for CosmicElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use slog::Drain;
|
use slog::{Drain, Level};
|
||||||
|
|
||||||
pub struct LogState {
|
pub struct LogState {
|
||||||
_guard: slog_scope::GlobalLoggerGuard,
|
_guard: slog_scope::GlobalLoggerGuard,
|
||||||
|
|
@ -16,7 +16,27 @@ pub fn init_logger() -> Result<LogState> {
|
||||||
let drain = slog::Duplicate::new(term_drain, journald_drain);
|
let drain = slog::Duplicate::new(term_drain, journald_drain);
|
||||||
// usually we would not want to use a Mutex here, but this is usefull for a prototype,
|
// usually we would not want to use a Mutex here, but this is usefull for a prototype,
|
||||||
// to make sure we do not miss any in-flight messages, when we crash.
|
// to make sure we do not miss any in-flight messages, when we crash.
|
||||||
let logger = slog::Logger::root(std::sync::Mutex::new(drain).fuse(), slog::o!());
|
let logger = slog::Logger::root(
|
||||||
|
std::sync::Mutex::new(drain.filter(|record| {
|
||||||
|
if record.module().starts_with("smithay") || record.module().starts_with("cosmic_comp")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.module().contains("cosmic_text") {
|
||||||
|
// cosmic-text is very chatty
|
||||||
|
return record.level().is_at_least(Level::Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
record.level().is_at_least(Level::Warning)
|
||||||
|
} else {
|
||||||
|
record.level().is_at_least(Level::Error)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.fuse(),
|
||||||
|
slog::o!(),
|
||||||
|
);
|
||||||
|
|
||||||
let _guard = slog_scope::set_global_logger(logger);
|
let _guard = slog_scope::set_global_logger(logger);
|
||||||
slog_stdlog::init_with_level(if cfg!(debug_assertions) {
|
slog_stdlog::init_with_level(if cfg!(debug_assertions) {
|
||||||
|
|
|
||||||
|
|
@ -10,28 +10,24 @@ use smithay::{
|
||||||
renderer::{
|
renderer::{
|
||||||
element::{AsRenderElements, Element, RenderElement, UnderlyingStorage},
|
element::{AsRenderElements, Element, RenderElement, UnderlyingStorage},
|
||||||
glow::GlowRenderer,
|
glow::GlowRenderer,
|
||||||
ImportAll, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::{space::SpaceElement, PopupManager, Window, WindowSurfaceType},
|
desktop::{space::SpaceElement, PopupManager, WindowSurfaceType},
|
||||||
input::{
|
input::{
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
||||||
Seat,
|
Seat,
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::wayland_server::{backend::ObjectId, protocol::wl_surface::WlSurface},
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState,
|
|
||||||
wayland_server::{backend::ObjectId, protocol::wl_surface::WlSurface},
|
|
||||||
},
|
|
||||||
space_elements,
|
space_elements,
|
||||||
utils::{
|
utils::{
|
||||||
Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size,
|
Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size,
|
||||||
},
|
},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{with_states, with_surface_tree_downward, TraversalAction},
|
compositor::{with_surface_tree_downward, TraversalAction},
|
||||||
seat::WaylandFocus,
|
seat::WaylandFocus,
|
||||||
shell::xdg::XdgToplevelSurfaceRoleAttributes,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -41,6 +37,8 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod surface;
|
||||||
|
pub use self::surface::CosmicSurface;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
pub use self::stack::CosmicStack;
|
pub use self::stack::CosmicStack;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|
@ -110,68 +108,48 @@ impl Hash for CosmicMapped {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CosmicMapped {
|
impl CosmicMapped {
|
||||||
pub fn windows(&self) -> impl Iterator<Item = (Window, Point<i32, Logical>)> + '_ {
|
pub fn windows(&self) -> impl Iterator<Item = (CosmicSurface, Point<i32, Logical>)> + '_ {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Stack(stack) => Box::new(stack.windows().map(|w| {
|
CosmicMappedInternal::Stack(stack) => {
|
||||||
(
|
Box::new(stack.surfaces().map(|w| (w, stack.offset())))
|
||||||
w,
|
as Box<dyn Iterator<Item = (CosmicSurface, Point<i32, Logical>)>>
|
||||||
stack
|
}
|
||||||
.header
|
CosmicMappedInternal::Window(window) => {
|
||||||
.lock()
|
Box::new(std::iter::once((window.surface(), window.offset())))
|
||||||
.unwrap()
|
}
|
||||||
.as_ref()
|
|
||||||
.map(|header| Point::from((0, header.height() as i32)))
|
|
||||||
.unwrap_or(Point::from((0, 0))),
|
|
||||||
)
|
|
||||||
}))
|
|
||||||
as Box<dyn Iterator<Item = (Window, Point<i32, Logical>)>>,
|
|
||||||
CosmicMappedInternal::Window(window) => Box::new(std::iter::once((
|
|
||||||
window.window.clone(),
|
|
||||||
window
|
|
||||||
.header
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
.map(|header| Point::from((0, header.height() as i32)))
|
|
||||||
.unwrap_or(Point::from((0, 0))),
|
|
||||||
))),
|
|
||||||
_ => Box::new(std::iter::empty()),
|
_ => Box::new(std::iter::empty()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_window(&self) -> Window {
|
pub fn active_window(&self) -> CosmicSurface {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Stack(stack) => stack.active(),
|
CosmicMappedInternal::Stack(stack) => stack.active(),
|
||||||
CosmicMappedInternal::Window(win) => win.window.clone(),
|
CosmicMappedInternal::Window(win) => win.surface(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_window_offset(&self) -> Rectangle<i32, Logical> {
|
pub fn active_window_offset(&self) -> Point<i32, Logical> {
|
||||||
|
match &self.element {
|
||||||
|
CosmicMappedInternal::Stack(stack) => stack.offset(),
|
||||||
|
CosmicMappedInternal::Window(window) => window.offset(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn active_window_geometry(&self) -> Rectangle<i32, Logical> {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Stack(stack) => {
|
CosmicMappedInternal::Stack(stack) => {
|
||||||
let location = (
|
let win = stack.active();
|
||||||
0,
|
let location = stack.offset();
|
||||||
stack
|
let mut size = win.geometry().size;
|
||||||
.header
|
size -= location.to_size();
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
.map_or(0, |header| header.height()),
|
|
||||||
);
|
|
||||||
let size = stack.active().geometry().size;
|
|
||||||
Rectangle::from_loc_and_size(location, size)
|
Rectangle::from_loc_and_size(location, size)
|
||||||
}
|
}
|
||||||
CosmicMappedInternal::Window(win) => {
|
CosmicMappedInternal::Window(win) => {
|
||||||
let location = (
|
let location = win.offset();
|
||||||
0,
|
let mut size = win.geometry().size;
|
||||||
win.header
|
size -= location.to_size();
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
.map_or(0, |header| header.height()),
|
|
||||||
);
|
|
||||||
let size = win.window.geometry().size;
|
|
||||||
Rectangle::from_loc_and_size(location, size)
|
Rectangle::from_loc_and_size(location, size)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
@ -186,13 +164,13 @@ impl CosmicMapped {
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_active(&self, window: &Window) {
|
pub fn set_active(&self, window: &CosmicSurface) {
|
||||||
if let CosmicMappedInternal::Stack(stack) = &self.element {
|
if let CosmicMappedInternal::Stack(stack) = &self.element {
|
||||||
stack.set_active(window);
|
stack.set_active(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_window(&self, window: &Window) {
|
pub fn focus_window(&self, window: &CosmicSurface) {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Stack(stack) => stack.set_active(window),
|
CosmicMappedInternal::Stack(stack) => stack.set_active(window),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -201,10 +179,10 @@ impl CosmicMapped {
|
||||||
|
|
||||||
pub fn has_surface(&self, surface: &WlSurface, surface_type: WindowSurfaceType) -> bool {
|
pub fn has_surface(&self, surface: &WlSurface, surface_type: WindowSurfaceType) -> bool {
|
||||||
self.windows().any(|(w, _)| {
|
self.windows().any(|(w, _)| {
|
||||||
let toplevel = w.toplevel().wl_surface();
|
let Some(toplevel ) = w.wl_surface() else { return false };
|
||||||
|
|
||||||
if surface_type.contains(WindowSurfaceType::TOPLEVEL) {
|
if surface_type.contains(WindowSurfaceType::TOPLEVEL) {
|
||||||
if toplevel == surface {
|
if toplevel == *surface {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,7 +192,7 @@ impl CosmicMapped {
|
||||||
|
|
||||||
let found = AtomicBool::new(false);
|
let found = AtomicBool::new(false);
|
||||||
with_surface_tree_downward(
|
with_surface_tree_downward(
|
||||||
toplevel,
|
&toplevel,
|
||||||
surface,
|
surface,
|
||||||
|_, _, search| TraversalAction::DoChildren(search),
|
|_, _, search| TraversalAction::DoChildren(search),
|
||||||
|s, _, search| {
|
|s, _, search| {
|
||||||
|
|
@ -228,7 +206,7 @@ impl CosmicMapped {
|
||||||
}
|
}
|
||||||
|
|
||||||
if surface_type.contains(WindowSurfaceType::POPUP) {
|
if surface_type.contains(WindowSurfaceType::POPUP) {
|
||||||
PopupManager::popups_for_surface(toplevel).any(|(p, _)| p.wl_surface() == surface)
|
PopupManager::popups_for_surface(&toplevel).any(|(p, _)| p.wl_surface() == surface)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -247,158 +225,110 @@ impl CosmicMapped {
|
||||||
pub fn set_resizing(&self, resizing: bool) {
|
pub fn set_resizing(&self, resizing: bool) {
|
||||||
for window in match &self.element {
|
for window in match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => {
|
CosmicMappedInternal::Stack(s) => {
|
||||||
Box::new(s.windows()) as Box<dyn Iterator<Item = Window>>
|
Box::new(s.surfaces()) as Box<dyn Iterator<Item = CosmicSurface>>
|
||||||
}
|
}
|
||||||
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.window.clone())),
|
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
} {
|
} {
|
||||||
window.toplevel().with_pending_state(|state| {
|
window.set_resizing(resizing);
|
||||||
if resizing {
|
|
||||||
state.states.set(XdgState::Resizing);
|
|
||||||
} else {
|
|
||||||
state.states.unset(XdgState::Resizing);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_resizing(&self) -> bool {
|
pub fn is_resizing(&self) -> Option<bool> {
|
||||||
let window = match &self.element {
|
let window = match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => s.active(),
|
CosmicMappedInternal::Stack(s) => s.active(),
|
||||||
CosmicMappedInternal::Window(w) => w.window.clone(),
|
CosmicMappedInternal::Window(w) => w.surface(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xdg = window.toplevel();
|
window.is_resizing()
|
||||||
xdg.current_state().states.contains(XdgState::Resizing)
|
|
||||||
|| xdg.with_pending_state(|states| states.states.contains(XdgState::Resizing))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_tiled(&self, tiled: bool) {
|
pub fn set_tiled(&self, tiled: bool) {
|
||||||
for xdg in match &self.element {
|
for window in match &self.element {
|
||||||
// we use the tiled state of stack windows anyway to get rid of decorations
|
// we use the tiled state of stack windows anyway to get rid of decorations
|
||||||
CosmicMappedInternal::Stack(_) => None,
|
CosmicMappedInternal::Stack(_) => None,
|
||||||
CosmicMappedInternal::Window(w) => Some(w.window.toplevel()),
|
CosmicMappedInternal::Window(w) => Some(w.surface()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
} {
|
} {
|
||||||
xdg.with_pending_state(|state| {
|
window.set_tiled(tiled)
|
||||||
if tiled {
|
|
||||||
state.states.set(XdgState::TiledLeft);
|
|
||||||
state.states.set(XdgState::TiledRight);
|
|
||||||
state.states.set(XdgState::TiledTop);
|
|
||||||
state.states.set(XdgState::TiledBottom);
|
|
||||||
} else {
|
|
||||||
state.states.unset(XdgState::TiledLeft);
|
|
||||||
state.states.unset(XdgState::TiledRight);
|
|
||||||
state.states.unset(XdgState::TiledTop);
|
|
||||||
state.states.unset(XdgState::TiledBottom);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_tiled(&self) -> bool {
|
pub fn is_tiled(&self) -> Option<bool> {
|
||||||
let window = match &self.element {
|
let window = match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => s.active(),
|
CosmicMappedInternal::Stack(s) => s.active(),
|
||||||
CosmicMappedInternal::Window(w) => w.window.clone(),
|
CosmicMappedInternal::Window(w) => w.surface(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
window
|
window.is_tiled()
|
||||||
.toplevel()
|
|
||||||
.current_state()
|
|
||||||
.states
|
|
||||||
.contains(XdgState::TiledLeft)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_fullscreen(&self, fullscreen: bool) {
|
pub fn set_fullscreen(&self, fullscreen: bool) {
|
||||||
for window in match &self.element {
|
for window in match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => {
|
CosmicMappedInternal::Stack(s) => {
|
||||||
Box::new(s.windows()) as Box<dyn Iterator<Item = Window>>
|
Box::new(s.surfaces()) as Box<dyn Iterator<Item = CosmicSurface>>
|
||||||
}
|
}
|
||||||
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.window.clone())),
|
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
} {
|
} {
|
||||||
window.toplevel().with_pending_state(|state| {
|
window.set_fullscreen(fullscreen);
|
||||||
if fullscreen {
|
|
||||||
state.states.set(XdgState::Fullscreen);
|
|
||||||
} else {
|
|
||||||
state.states.unset(XdgState::Fullscreen);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_fullscreen(&self) -> bool {
|
pub fn is_fullscreen(&self) -> bool {
|
||||||
let window = match &self.element {
|
let window = match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => s.active(),
|
CosmicMappedInternal::Stack(s) => s.active(),
|
||||||
CosmicMappedInternal::Window(w) => w.window.clone(),
|
CosmicMappedInternal::Window(w) => w.surface(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xdg = window.toplevel();
|
window.is_fullscreen()
|
||||||
xdg.current_state().states.contains(XdgState::Fullscreen)
|
|
||||||
|| xdg.with_pending_state(|states| states.states.contains(XdgState::Fullscreen))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_maximized(&self, maximized: bool) {
|
pub fn set_maximized(&self, maximized: bool) {
|
||||||
for window in match &self.element {
|
for window in match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => {
|
CosmicMappedInternal::Stack(s) => {
|
||||||
Box::new(s.windows()) as Box<dyn Iterator<Item = Window>>
|
Box::new(s.surfaces()) as Box<dyn Iterator<Item = CosmicSurface>>
|
||||||
}
|
}
|
||||||
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.window.clone())),
|
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
} {
|
} {
|
||||||
window.toplevel().with_pending_state(|state| {
|
window.set_maximized(maximized)
|
||||||
if maximized {
|
|
||||||
state.states.set(XdgState::Maximized);
|
|
||||||
} else {
|
|
||||||
state.states.unset(XdgState::Maximized);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_maximized(&self) -> bool {
|
pub fn is_maximized(&self) -> bool {
|
||||||
let window = match &self.element {
|
let window = match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => s.active(),
|
CosmicMappedInternal::Stack(s) => s.active(),
|
||||||
CosmicMappedInternal::Window(w) => w.window.clone(),
|
CosmicMappedInternal::Window(w) => w.surface(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xdg = window.toplevel();
|
window.is_maximized()
|
||||||
xdg.current_state().states.contains(XdgState::Maximized)
|
|
||||||
|| xdg.with_pending_state(|states| states.states.contains(XdgState::Maximized))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_activated(&self, activated: bool) {
|
pub fn set_activated(&self, activated: bool) {
|
||||||
for window in match &self.element {
|
for window in match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => {
|
CosmicMappedInternal::Stack(s) => {
|
||||||
Box::new(s.windows()) as Box<dyn Iterator<Item = Window>>
|
Box::new(s.surfaces()) as Box<dyn Iterator<Item = CosmicSurface>>
|
||||||
}
|
}
|
||||||
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.window.clone())),
|
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
} {
|
} {
|
||||||
window.toplevel().with_pending_state(|state| {
|
window.set_activated(activated)
|
||||||
if activated {
|
|
||||||
state.states.set(XdgState::Activated);
|
|
||||||
} else {
|
|
||||||
state.states.unset(XdgState::Activated);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_activated(&self) -> bool {
|
pub fn is_activated(&self) -> bool {
|
||||||
let window = match &self.element {
|
let window = match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => s.active(),
|
CosmicMappedInternal::Stack(s) => s.active(),
|
||||||
CosmicMappedInternal::Window(w) => w.window.clone(),
|
CosmicMappedInternal::Window(w) => w.surface(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xdg = window.toplevel();
|
window.is_activated()
|
||||||
xdg.current_state().states.contains(XdgState::Activated)
|
|
||||||
|| xdg.with_pending_state(|states| states.states.contains(XdgState::Activated))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_size(&self, size: Size<i32, Logical>) {
|
pub fn set_size(&self, size: Size<i32, Logical>) {
|
||||||
|
|
@ -409,57 +339,34 @@ impl CosmicMapped {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min_size(&self) -> Size<i32, Logical> {
|
pub fn min_size(&self) -> Option<Size<i32, Logical>> {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Stack(stack) => stack
|
CosmicMappedInternal::Stack(stack) => {
|
||||||
.windows()
|
stack.surfaces().fold(None, |min_size, window| {
|
||||||
.fold(None, |min_size, window| {
|
let win_min_size = window.min_size();
|
||||||
let win_min_size = with_states(window.toplevel().wl_surface(), |states| {
|
|
||||||
let attrs = states
|
|
||||||
.data_map
|
|
||||||
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.unwrap();
|
|
||||||
attrs.min_size
|
|
||||||
});
|
|
||||||
match (min_size, win_min_size) {
|
match (min_size, win_min_size) {
|
||||||
(None, x) => Some(x),
|
(None, None) => None,
|
||||||
(Some(min1), min2) => Some((min1.w.max(min2.w), min1.h.max(min2.h)).into()),
|
(None, x) | (x, None) => x,
|
||||||
|
(Some(min1), Some(min2)) => {
|
||||||
|
Some((min1.w.max(min2.w), min1.h.max(min2.h)).into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect("Empty stack?"),
|
|
||||||
CosmicMappedInternal::Window(window) => {
|
|
||||||
with_states(window.window.toplevel().wl_surface(), |states| {
|
|
||||||
let attrs = states
|
|
||||||
.data_map
|
|
||||||
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.unwrap();
|
|
||||||
attrs.min_size
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
CosmicMappedInternal::Window(window) => window.surface().min_size(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_size(&self) -> Size<i32, Logical> {
|
pub fn max_size(&self) -> Option<Size<i32, Logical>> {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Stack(stack) => {
|
CosmicMappedInternal::Stack(stack) => {
|
||||||
let theoretical_max = stack.windows().fold(None, |max_size, window| {
|
let theoretical_max = stack.surfaces().fold(None, |max_size, window| {
|
||||||
let win_max_size = with_states(window.toplevel().wl_surface(), |states| {
|
let win_max_size = window.max_size();
|
||||||
let attrs = states
|
|
||||||
.data_map
|
|
||||||
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.unwrap();
|
|
||||||
attrs.max_size
|
|
||||||
});
|
|
||||||
match (max_size, win_max_size) {
|
match (max_size, win_max_size) {
|
||||||
(None, x) => Some(x),
|
(None, None) => None,
|
||||||
(Some(max1), max2) => Some(
|
(None, x) | (x, None) => x,
|
||||||
|
(Some(max1), Some(max2)) => Some(
|
||||||
(
|
(
|
||||||
if max1.w == 0 {
|
if max1.w == 0 {
|
||||||
max2.w
|
max2.w
|
||||||
|
|
@ -483,21 +390,12 @@ impl CosmicMapped {
|
||||||
// The problem is, with accumulated sizes, the minimum size could be larger than our maximum...
|
// The problem is, with accumulated sizes, the minimum size could be larger than our maximum...
|
||||||
let min_size = self.min_size();
|
let min_size = self.min_size();
|
||||||
match (theoretical_max, min_size) {
|
match (theoretical_max, min_size) {
|
||||||
(None, _) => (0, 0).into(),
|
(None, _) => None,
|
||||||
(Some(max), min) => (max.w.max(min.w), max.h.max(min.h)).into(),
|
(Some(max), None) => Some(max),
|
||||||
|
(Some(max), Some(min)) => Some((max.w.max(min.w), max.h.max(min.h)).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CosmicMappedInternal::Window(window) => {
|
CosmicMappedInternal::Window(window) => window.surface().max_size(),
|
||||||
with_states(window.window.toplevel().wl_surface(), |states| {
|
|
||||||
let attrs = states
|
|
||||||
.data_map
|
|
||||||
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.unwrap();
|
|
||||||
attrs.max_size
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -505,23 +403,23 @@ impl CosmicMapped {
|
||||||
pub fn configure(&self) {
|
pub fn configure(&self) {
|
||||||
for window in match &self.element {
|
for window in match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => {
|
CosmicMappedInternal::Stack(s) => {
|
||||||
Box::new(s.windows()) as Box<dyn Iterator<Item = Window>>
|
Box::new(s.surfaces()) as Box<dyn Iterator<Item = CosmicSurface>>
|
||||||
}
|
}
|
||||||
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.window.clone())),
|
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
} {
|
} {
|
||||||
window.toplevel().send_configure();
|
window.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_close(&self) {
|
pub fn send_close(&self) {
|
||||||
let window = match &self.element {
|
let window = match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => s.active(),
|
CosmicMappedInternal::Stack(s) => s.active(),
|
||||||
CosmicMappedInternal::Window(w) => w.window.clone(),
|
CosmicMappedInternal::Window(w) => w.surface(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
window.toplevel().send_close();
|
window.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
|
|
@ -680,7 +578,7 @@ impl PointerTarget<State> for CosmicMapped {
|
||||||
impl WaylandFocus for CosmicMapped {
|
impl WaylandFocus for CosmicMapped {
|
||||||
fn wl_surface(&self) -> Option<WlSurface> {
|
fn wl_surface(&self) -> Option<WlSurface> {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Window(w) => w.window.wl_surface().clone(),
|
CosmicMappedInternal::Window(w) => w.surface().wl_surface().clone(),
|
||||||
CosmicMappedInternal::Stack(s) => s.active().wl_surface().clone(),
|
CosmicMappedInternal::Stack(s) => s.active().wl_surface().clone(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
@ -688,8 +586,8 @@ impl WaylandFocus for CosmicMapped {
|
||||||
|
|
||||||
fn same_client_as(&self, object_id: &ObjectId) -> bool {
|
fn same_client_as(&self, object_id: &ObjectId) -> bool {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Window(w) => w.window.same_client_as(object_id),
|
CosmicMappedInternal::Window(w) => w.surface().same_client_as(object_id),
|
||||||
CosmicMappedInternal::Stack(s) => s.windows().any(|w| w.same_client_as(object_id)),
|
CosmicMappedInternal::Stack(s) => s.surfaces().any(|w| w.same_client_as(object_id)),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -725,7 +623,7 @@ impl From<CosmicStack> for CosmicMapped {
|
||||||
|
|
||||||
pub enum CosmicMappedRenderElement<R>
|
pub enum CosmicMappedRenderElement<R>
|
||||||
where
|
where
|
||||||
R: AsGlowRenderer + Renderer + ImportAll,
|
R: AsGlowRenderer + Renderer + ImportAll + ImportMem,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
{
|
{
|
||||||
Stack(self::stack::CosmicStackRenderElement<R>),
|
Stack(self::stack::CosmicStackRenderElement<R>),
|
||||||
|
|
@ -736,7 +634,7 @@ where
|
||||||
|
|
||||||
impl<R> Element for CosmicMappedRenderElement<R>
|
impl<R> Element for CosmicMappedRenderElement<R>
|
||||||
where
|
where
|
||||||
R: AsGlowRenderer + Renderer + ImportAll,
|
R: AsGlowRenderer + Renderer + ImportAll + ImportMem,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
{
|
{
|
||||||
fn id(&self) -> &smithay::backend::renderer::element::Id {
|
fn id(&self) -> &smithay::backend::renderer::element::Id {
|
||||||
|
|
@ -892,7 +790,7 @@ impl<'a> RenderElement<GlMultiRenderer<'a>> for CosmicMappedRenderElement<GlMult
|
||||||
|
|
||||||
impl<R> From<stack::CosmicStackRenderElement<R>> for CosmicMappedRenderElement<R>
|
impl<R> From<stack::CosmicStackRenderElement<R>> for CosmicMappedRenderElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -902,7 +800,7 @@ where
|
||||||
}
|
}
|
||||||
impl<R> From<window::CosmicWindowRenderElement<R>> for CosmicMappedRenderElement<R>
|
impl<R> From<window::CosmicWindowRenderElement<R>> for CosmicMappedRenderElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -924,7 +822,7 @@ where
|
||||||
|
|
||||||
impl<R> AsRenderElements<R> for CosmicMapped
|
impl<R> AsRenderElements<R> for CosmicMapped
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,24 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
state::State, utils::prelude::SeatExt, wayland::handlers::screencopy::ScreencopySessions,
|
state::State,
|
||||||
|
utils::iced::{IcedElement, Program},
|
||||||
|
utils::prelude::SeatExt,
|
||||||
|
wayland::handlers::screencopy::ScreencopySessions,
|
||||||
};
|
};
|
||||||
|
use calloop::LoopHandle;
|
||||||
|
use cosmic::Element;
|
||||||
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
input::KeyState,
|
input::KeyState,
|
||||||
renderer::{
|
renderer::{
|
||||||
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
|
element::{
|
||||||
ImportAll, Renderer,
|
memory::MemoryRenderBufferRenderElement, surface::WaylandSurfaceRenderElement,
|
||||||
|
AsRenderElements,
|
||||||
|
},
|
||||||
|
ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::{space::SpaceElement, Window},
|
desktop::space::SpaceElement,
|
||||||
input::{
|
input::{
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
||||||
|
|
@ -21,84 +29,136 @@ use smithay::{
|
||||||
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size},
|
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicUsize, Ordering},
|
atomic::{AtomicU8, AtomicUsize, Ordering},
|
||||||
Arc, Mutex,
|
Arc, Mutex,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::CosmicSurface;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct CosmicStack(IcedElement<CosmicStackInternal>);
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CosmicStack {
|
pub struct CosmicStackInternal {
|
||||||
windows: Arc<Mutex<Vec<Window>>>,
|
windows: Arc<Mutex<Vec<CosmicSurface>>>,
|
||||||
active: Arc<AtomicUsize>,
|
active: Arc<AtomicUsize>,
|
||||||
last_location: Arc<Mutex<Option<(Point<f64, Logical>, Serial, u32)>>>,
|
|
||||||
previous_keyboard: Arc<AtomicUsize>,
|
previous_keyboard: Arc<AtomicUsize>,
|
||||||
|
pointer_entered: Option<Arc<AtomicU8>>,
|
||||||
previous_pointer: Arc<AtomicUsize>,
|
previous_pointer: Arc<AtomicUsize>,
|
||||||
pub(super) header: Arc<Mutex<Option<HeaderBar>>>,
|
last_location: Arc<Mutex<Option<(Point<f64, Logical>, Serial, u32)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for CosmicStack {
|
impl CosmicStackInternal {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
pub fn swap_focus(&self, focus: Focus) -> Focus {
|
||||||
*self.windows.lock().unwrap() == *other.windows.lock().unwrap()
|
if let Some(pointer_entered) = self.pointer_entered.as_ref() {
|
||||||
|
unsafe {
|
||||||
|
std::mem::transmute::<u8, Focus>(
|
||||||
|
pointer_entered.swap(focus as u8, Ordering::SeqCst),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Focus::Window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_focus(&self) -> Focus {
|
||||||
|
if let Some(pointer_entered) = self.pointer_entered.as_ref() {
|
||||||
|
unsafe { std::mem::transmute::<u8, Focus>(pointer_entered.load(Ordering::SeqCst)) }
|
||||||
|
} else {
|
||||||
|
Focus::Window
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for CosmicStack {}
|
const TAB_HEIGHT: i32 = 24;
|
||||||
|
|
||||||
impl Hash for CosmicStack {
|
#[repr(u8)]
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
Arc::as_ptr(&self.windows).hash(state)
|
pub enum Focus {
|
||||||
}
|
None,
|
||||||
}
|
Header,
|
||||||
|
Window,
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct HeaderBar {}
|
|
||||||
|
|
||||||
impl HeaderBar {
|
|
||||||
pub fn height(&self) -> i32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CosmicStack {
|
impl CosmicStack {
|
||||||
pub fn active(&self) -> Window {
|
pub fn new(
|
||||||
self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)].clone()
|
window: impl Into<CosmicSurface>,
|
||||||
|
handle: LoopHandle<'static, crate::state::Data>,
|
||||||
|
) -> CosmicStack {
|
||||||
|
let window = window.into();
|
||||||
|
let width = window.geometry().size.w;
|
||||||
|
CosmicStack(IcedElement::new(
|
||||||
|
CosmicStackInternal {
|
||||||
|
windows: Arc::new(Mutex::new(vec![window])),
|
||||||
|
active: Arc::new(AtomicUsize::new(0)),
|
||||||
|
previous_keyboard: Arc::new(AtomicUsize::new(0)),
|
||||||
|
pointer_entered: None,
|
||||||
|
previous_pointer: Arc::new(AtomicUsize::new(0)),
|
||||||
|
last_location: Arc::new(Mutex::new(None)),
|
||||||
|
},
|
||||||
|
(width, TAB_HEIGHT),
|
||||||
|
handle,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_active(&self, window: &Window) {
|
//pub fn add_window()
|
||||||
if let Some(val) = self
|
//pub fn remove_window()
|
||||||
.windows
|
//pub fn len
|
||||||
.lock()
|
|
||||||
.unwrap()
|
pub fn active(&self) -> CosmicSurface {
|
||||||
.iter()
|
self.0
|
||||||
.position(|w| w == window)
|
.with_program(|p| p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].clone())
|
||||||
{
|
}
|
||||||
let old = self.active.swap(val, Ordering::SeqCst);
|
|
||||||
self.previous_keyboard.store(old, Ordering::SeqCst);
|
pub fn set_active(&self, window: &CosmicSurface) {
|
||||||
self.previous_pointer.store(old, Ordering::SeqCst);
|
self.0.with_program(|p| {
|
||||||
}
|
if let Some(val) = p.windows.lock().unwrap().iter().position(|w| w == window) {
|
||||||
|
let old = p.active.swap(val, Ordering::SeqCst);
|
||||||
|
p.previous_keyboard.store(old, Ordering::SeqCst);
|
||||||
|
p.previous_pointer.store(old, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn surfaces(&self) -> impl Iterator<Item = CosmicSurface> {
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
p.windows
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset(&self) -> Point<i32, Logical> {
|
||||||
|
Point::from((0, TAB_HEIGHT))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_size(&self, size: Size<i32, Logical>) {
|
pub fn set_size(&self, size: Size<i32, Logical>) {
|
||||||
let surface_size = (
|
self.0.with_program(|p| {
|
||||||
size.w,
|
let surface_size = (size.w, size.h - TAB_HEIGHT).into();
|
||||||
size.h
|
|
||||||
- self
|
|
||||||
.header
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
.map(|h| h.height())
|
|
||||||
.unwrap_or(0),
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
|
|
||||||
for window in self.windows.lock().unwrap().iter() {
|
for window in p.windows.lock().unwrap().iter() {
|
||||||
window
|
window.set_size(surface_size);
|
||||||
.toplevel()
|
}
|
||||||
.with_pending_state(|state| state.size = Some(surface_size));
|
});
|
||||||
}
|
self.0.resize(Size::from((size.w, TAB_HEIGHT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_leave_if_previous(
|
fn keyboard_leave_if_previous(
|
||||||
|
|
@ -107,13 +167,21 @@ impl CosmicStack {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let active = self.active.load(Ordering::SeqCst);
|
self.0.with_program(|p| {
|
||||||
let previous = self.previous_keyboard.swap(active, Ordering::SeqCst);
|
let active = p.active.load(Ordering::SeqCst);
|
||||||
if previous != active {
|
let previous = p.previous_keyboard.swap(active, Ordering::SeqCst);
|
||||||
KeyboardTarget::leave(&self.windows.lock().unwrap()[previous], seat, data, serial);
|
if previous != active {
|
||||||
// TODO: KeyboardTarget::enter(&self.windows.lock().unwrap()[active], seat, data, serial, seat.keys())
|
KeyboardTarget::leave(&p.windows.lock().unwrap()[previous], seat, data, serial);
|
||||||
}
|
KeyboardTarget::enter(
|
||||||
active
|
&p.windows.lock().unwrap()[active],
|
||||||
|
seat,
|
||||||
|
data,
|
||||||
|
Vec::new(), //seat.keys(),
|
||||||
|
serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
active
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pointer_leave_if_previous(
|
fn pointer_leave_if_previous(
|
||||||
|
|
@ -124,100 +192,141 @@ impl CosmicStack {
|
||||||
time: u32,
|
time: u32,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let active = self.active.load(Ordering::SeqCst);
|
self.0.with_program(|p| {
|
||||||
let previous = self.previous_pointer.swap(active, Ordering::SeqCst);
|
let active = p.active.load(Ordering::SeqCst);
|
||||||
if previous != active {
|
let previous = p.previous_pointer.swap(active, Ordering::SeqCst);
|
||||||
if let Some(sessions) = self.windows.lock().unwrap()[previous]
|
if previous != active {
|
||||||
.user_data()
|
if let Some(sessions) = p.windows.lock().unwrap()[previous]
|
||||||
.get::<ScreencopySessions>()
|
.user_data()
|
||||||
{
|
.get::<ScreencopySessions>()
|
||||||
for session in &*sessions.0.borrow() {
|
{
|
||||||
session.cursor_leave(seat, InputType::Pointer)
|
for session in &*sessions.0.borrow() {
|
||||||
|
session.cursor_leave(seat, InputType::Pointer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
PointerTarget::leave(
|
||||||
PointerTarget::leave(
|
&p.windows.lock().unwrap()[previous],
|
||||||
&self.windows.lock().unwrap()[previous],
|
seat,
|
||||||
seat,
|
data,
|
||||||
data,
|
|
||||||
serial,
|
|
||||||
time,
|
|
||||||
);
|
|
||||||
if let Some(sessions) = self.windows.lock().unwrap()[active]
|
|
||||||
.user_data()
|
|
||||||
.get::<ScreencopySessions>()
|
|
||||||
{
|
|
||||||
for session in &*sessions.0.borrow() {
|
|
||||||
session.cursor_enter(seat, InputType::Pointer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PointerTarget::enter(
|
|
||||||
&self.windows.lock().unwrap()[active],
|
|
||||||
seat,
|
|
||||||
data,
|
|
||||||
&MotionEvent {
|
|
||||||
location,
|
|
||||||
serial,
|
serial,
|
||||||
time,
|
time,
|
||||||
},
|
);
|
||||||
);
|
if let Some(sessions) = p.windows.lock().unwrap()[active]
|
||||||
}
|
.user_data()
|
||||||
active
|
.get::<ScreencopySessions>()
|
||||||
|
{
|
||||||
|
for session in &*sessions.0.borrow() {
|
||||||
|
session.cursor_enter(seat, InputType::Pointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PointerTarget::enter(
|
||||||
|
&p.windows.lock().unwrap()[active],
|
||||||
|
seat,
|
||||||
|
data,
|
||||||
|
&MotionEvent {
|
||||||
|
location,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
active
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Program for CosmicStackInternal {
|
||||||
|
type Message = ();
|
||||||
|
|
||||||
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
|
cosmic::iced::widget::text("TODO").into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsAlive for CosmicStack {
|
impl IsAlive for CosmicStack {
|
||||||
fn alive(&self) -> bool {
|
fn alive(&self) -> bool {
|
||||||
self.windows.lock().unwrap().iter().any(IsAlive::alive)
|
self.0
|
||||||
|
.with_program(|p| p.windows.lock().unwrap().iter().any(IsAlive::alive))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpaceElement for CosmicStack {
|
impl SpaceElement for CosmicStack {
|
||||||
fn bbox(&self) -> Rectangle<i32, Logical> {
|
fn bbox(&self) -> Rectangle<i32, Logical> {
|
||||||
SpaceElement::bbox(&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)])
|
self.0.with_program(|p| {
|
||||||
|
let mut bbox =
|
||||||
|
SpaceElement::bbox(&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]);
|
||||||
|
bbox.size.h += TAB_HEIGHT;
|
||||||
|
bbox
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
|
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
|
||||||
SpaceElement::is_in_input_region(
|
let mut point = *point;
|
||||||
&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)],
|
if point.y < TAB_HEIGHT as f64 {
|
||||||
point,
|
return true;
|
||||||
)
|
}
|
||||||
|
point.y -= TAB_HEIGHT as f64;
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
SpaceElement::is_in_input_region(
|
||||||
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
||||||
|
&point,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn set_activate(&self, activated: bool) {
|
fn set_activate(&self, activated: bool) {
|
||||||
self.windows
|
SpaceElement::set_activate(&self.0, activated);
|
||||||
.lock()
|
self.0.with_program(|p| {
|
||||||
.unwrap()
|
p.windows
|
||||||
.iter()
|
.lock()
|
||||||
.for_each(|w| SpaceElement::set_activate(w, activated))
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.for_each(|w| SpaceElement::set_activate(w, activated))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
|
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
|
||||||
self.windows
|
SpaceElement::output_enter(&self.0, output, overlap);
|
||||||
.lock()
|
self.0.with_program(|p| {
|
||||||
.unwrap()
|
p.windows
|
||||||
.iter()
|
.lock()
|
||||||
.for_each(|w| SpaceElement::output_enter(w, output, overlap))
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.for_each(|w| SpaceElement::output_enter(w, output, overlap))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn output_leave(&self, output: &Output) {
|
fn output_leave(&self, output: &Output) {
|
||||||
self.windows
|
SpaceElement::output_leave(&self.0, output);
|
||||||
.lock()
|
self.0.with_program(|p| {
|
||||||
.unwrap()
|
p.windows
|
||||||
.iter()
|
.lock()
|
||||||
.for_each(|w| SpaceElement::output_leave(w, output))
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.for_each(|w| SpaceElement::output_leave(w, output))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn geometry(&self) -> Rectangle<i32, Logical> {
|
fn geometry(&self) -> Rectangle<i32, Logical> {
|
||||||
SpaceElement::geometry(&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)])
|
self.0.with_program(|p| {
|
||||||
|
let mut geo =
|
||||||
|
SpaceElement::geometry(&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]);
|
||||||
|
geo.size.h += TAB_HEIGHT;
|
||||||
|
geo
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn z_index(&self) -> u8 {
|
fn z_index(&self) -> u8 {
|
||||||
SpaceElement::z_index(&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)])
|
self.0.with_program(|p| {
|
||||||
|
SpaceElement::z_index(&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn refresh(&self) {
|
fn refresh(&self) {
|
||||||
let mut windows = self.windows.lock().unwrap();
|
self.0.with_program(|p| {
|
||||||
windows.retain(IsAlive::alive);
|
let mut windows = p.windows.lock().unwrap();
|
||||||
let len = windows.len();
|
windows.retain(IsAlive::alive); // TODO: We don't handle empty stacks properly
|
||||||
let _ = self
|
let len = windows.len();
|
||||||
.active
|
let _ = p
|
||||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |active| {
|
.active
|
||||||
(active > len).then_some(len - 1)
|
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |active| {
|
||||||
});
|
(active > len).then_some(len - 1)
|
||||||
windows.iter().for_each(|w| SpaceElement::refresh(w))
|
});
|
||||||
|
windows.iter().for_each(|w| SpaceElement::refresh(w))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,19 +338,23 @@ impl KeyboardTarget<State> for CosmicStack {
|
||||||
keys: Vec<KeysymHandle<'_>>,
|
keys: Vec<KeysymHandle<'_>>,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) {
|
) {
|
||||||
let active = self.active.load(Ordering::SeqCst);
|
self.0.with_program(|p| {
|
||||||
self.previous_keyboard.store(active, Ordering::SeqCst);
|
let active = p.active.load(Ordering::SeqCst);
|
||||||
KeyboardTarget::enter(
|
p.previous_keyboard.store(active, Ordering::SeqCst);
|
||||||
&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)],
|
KeyboardTarget::enter(
|
||||||
seat,
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
||||||
data,
|
seat,
|
||||||
keys,
|
data,
|
||||||
serial,
|
keys,
|
||||||
)
|
serial,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
|
||||||
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
||||||
KeyboardTarget::leave(&self.windows.lock().unwrap()[active], seat, data, serial)
|
self.0.with_program(|p| {
|
||||||
|
KeyboardTarget::leave(&p.windows.lock().unwrap()[active], seat, data, serial)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn key(
|
fn key(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -253,15 +366,17 @@ impl KeyboardTarget<State> for CosmicStack {
|
||||||
time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
||||||
KeyboardTarget::key(
|
self.0.with_program(|p| {
|
||||||
&self.windows.lock().unwrap()[active],
|
KeyboardTarget::key(
|
||||||
seat,
|
&p.windows.lock().unwrap()[active],
|
||||||
data,
|
seat,
|
||||||
key,
|
data,
|
||||||
state,
|
key,
|
||||||
serial,
|
state,
|
||||||
time,
|
serial,
|
||||||
)
|
time,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn modifiers(
|
fn modifiers(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -271,132 +386,225 @@ impl KeyboardTarget<State> for CosmicStack {
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) {
|
) {
|
||||||
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
||||||
KeyboardTarget::modifiers(
|
self.0.with_program(|p| {
|
||||||
&self.windows.lock().unwrap()[active],
|
KeyboardTarget::modifiers(
|
||||||
seat,
|
&p.windows.lock().unwrap()[active],
|
||||||
data,
|
seat,
|
||||||
modifiers,
|
data,
|
||||||
serial,
|
modifiers,
|
||||||
)
|
serial,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerTarget<State> for CosmicStack {
|
impl PointerTarget<State> for CosmicStack {
|
||||||
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
||||||
if let Some(sessions) = self.active().user_data().get::<ScreencopySessions>() {
|
if self.0.with_program(|p| {
|
||||||
for session in &*sessions.0.borrow() {
|
if let Some(sessions) = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]
|
||||||
session.cursor_enter(seat, InputType::Pointer)
|
.user_data()
|
||||||
|
.get::<ScreencopySessions>()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
let focus = p.swap_focus(Focus::Window);
|
||||||
|
assert_eq!(focus, Focus::None);
|
||||||
|
|
||||||
|
*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,
|
||||||
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
PointerTarget::enter(&self.0, seat, data, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
*self.last_location.lock().unwrap() = Some((event.location, event.serial, event.time));
|
|
||||||
let active = self.active.load(Ordering::SeqCst);
|
|
||||||
self.previous_pointer.store(active, Ordering::SeqCst);
|
|
||||||
|
|
||||||
PointerTarget::enter(
|
|
||||||
&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)],
|
|
||||||
seat,
|
|
||||||
data,
|
|
||||||
event,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
||||||
let active =
|
let active =
|
||||||
self.pointer_leave_if_previous(seat, data, event.serial, event.time, event.location);
|
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) = self.active().user_data().get::<ScreencopySessions>() {
|
if let Some(sessions) = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]
|
||||||
for session in &*sessions.0.borrow() {
|
.user_data()
|
||||||
let buffer_loc = (event.location.x, event.location.y); // we always screencast windows at 1x1 scale
|
.get::<ScreencopySessions>()
|
||||||
if let Some((geo, hotspot)) =
|
{
|
||||||
seat.cursor_geometry(buffer_loc, data.common.clock.now())
|
for session in &*sessions.0.borrow() {
|
||||||
{
|
let buffer_loc = (event.location.x, event.location.y); // we always screencast windows at 1x1 scale
|
||||||
session.cursor_info(seat, InputType::Pointer, geo, hotspot);
|
if let Some((geo, hotspot)) =
|
||||||
|
seat.cursor_geometry(buffer_loc, data.common.clock.now())
|
||||||
|
{
|
||||||
|
session.cursor_info(seat, InputType::Pointer, geo, hotspot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PointerTarget::motion(&self.windows.lock().unwrap()[active], seat, data, event)
|
if event.location.y < TAB_HEIGHT as f64 {
|
||||||
|
let previous = p.swap_focus(Focus::Header);
|
||||||
|
if previous == Focus::Window {
|
||||||
|
PointerTarget::leave(
|
||||||
|
&p.windows.lock().unwrap()[active],
|
||||||
|
seat,
|
||||||
|
data,
|
||||||
|
event.serial,
|
||||||
|
event.time,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Some((previous, Focus::Header))
|
||||||
|
} else {
|
||||||
|
let mut event = event.clone();
|
||||||
|
event.location.y -= TAB_HEIGHT as f64;
|
||||||
|
|
||||||
|
let previous = p.swap_focus(Focus::Window);
|
||||||
|
if previous != Focus::Window {
|
||||||
|
PointerTarget::enter(&p.windows.lock().unwrap()[active], seat, data, &event);
|
||||||
|
} else {
|
||||||
|
PointerTarget::motion(&p.windows.lock().unwrap()[active], seat, data, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((previous, Focus::Window))
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
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, _) => {
|
||||||
|
PointerTarget::leave(&self.0, seat, data, event.serial, event.time)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
||||||
if let Some((location, _serial, _time)) = self.last_location.lock().unwrap().clone() {
|
if let Some((location, _serial, _time)) = self
|
||||||
|
.0
|
||||||
|
.with_program(|p| p.last_location.lock().unwrap().clone())
|
||||||
|
{
|
||||||
self.pointer_leave_if_previous(seat, data, event.serial, event.time, location);
|
self.pointer_leave_if_previous(seat, data, event.serial, event.time, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerTarget::button(
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)],
|
Focus::Header => PointerTarget::button(&self.0, seat, data, event),
|
||||||
seat,
|
Focus::Window => self.0.with_program(|p| {
|
||||||
data,
|
PointerTarget::button(
|
||||||
event,
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
||||||
)
|
seat,
|
||||||
|
data,
|
||||||
|
event,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
||||||
if let Some((location, serial, time)) = self.last_location.lock().unwrap().clone() {
|
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);
|
self.pointer_leave_if_previous(seat, data, serial, time, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerTarget::axis(
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)],
|
Focus::Header => PointerTarget::axis(&self.0, seat, data, frame),
|
||||||
seat,
|
Focus::Window => self.0.with_program(|p| {
|
||||||
data,
|
PointerTarget::axis(
|
||||||
frame,
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
||||||
)
|
seat,
|
||||||
|
data,
|
||||||
|
frame,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
||||||
if let Some((location, serial, time)) = self.last_location.lock().unwrap().clone() {
|
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);
|
self.pointer_leave_if_previous(seat, data, serial, time, location);
|
||||||
}
|
}
|
||||||
if let Some(sessions) = self.active().user_data().get::<ScreencopySessions>() {
|
|
||||||
for session in &*sessions.0.borrow() {
|
|
||||||
session.cursor_leave(seat, InputType::Pointer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PointerTarget::leave(
|
let previous = self.0.with_program(|p| {
|
||||||
&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)],
|
if let Some(sessions) = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]
|
||||||
seat,
|
.user_data()
|
||||||
data,
|
.get::<ScreencopySessions>()
|
||||||
serial,
|
{
|
||||||
time,
|
for session in &*sessions.0.borrow() {
|
||||||
)
|
session.cursor_leave(seat, InputType::Pointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.swap_focus(Focus::None)
|
||||||
|
});
|
||||||
|
assert!(previous != Focus::None);
|
||||||
|
|
||||||
|
match previous {
|
||||||
|
Focus::Header => PointerTarget::leave(&self.0, seat, data, serial, time),
|
||||||
|
Focus::Window => self.0.with_program(|p| {
|
||||||
|
PointerTarget::leave(
|
||||||
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
||||||
|
seat,
|
||||||
|
data,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_elements! {
|
render_elements! {
|
||||||
pub CosmicStackRenderElement<R> where R: ImportAll;
|
pub CosmicStackRenderElement<R> where R: ImportAll + ImportMem;
|
||||||
|
Header=MemoryRenderBufferRenderElement<R>,
|
||||||
Window=WaylandSurfaceRenderElement<R>,
|
Window=WaylandSurfaceRenderElement<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> AsRenderElements<R> for CosmicStack
|
impl<R> AsRenderElements<R> for CosmicStack
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll,
|
R: Renderer + ImportAll + ImportMem,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
{
|
{
|
||||||
type RenderElement = CosmicStackRenderElement<R>;
|
type RenderElement = CosmicStackRenderElement<R>;
|
||||||
fn render_elements<C: From<Self::RenderElement>>(
|
fn render_elements<C: From<Self::RenderElement>>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
location: Point<i32, Physical>,
|
mut location: Point<i32, Physical>,
|
||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
) -> Vec<C> {
|
) -> Vec<C> {
|
||||||
AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>(
|
let mut elements = AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>(
|
||||||
&self.windows.lock().unwrap()[self.active.load(Ordering::SeqCst)],
|
&self.0, renderer, location, scale,
|
||||||
renderer,
|
);
|
||||||
location,
|
location.y += TAB_HEIGHT;
|
||||||
scale,
|
|
||||||
)
|
elements.extend(self.0.with_program(|p| {
|
||||||
.into_iter()
|
let elements = AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>(
|
||||||
.map(C::from)
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
||||||
.collect()
|
renderer,
|
||||||
}
|
location,
|
||||||
}
|
scale,
|
||||||
impl CosmicStack {
|
);
|
||||||
pub fn windows(&self) -> impl Iterator<Item = Window> {
|
elements
|
||||||
self.windows
|
}));
|
||||||
.lock()
|
|
||||||
.unwrap()
|
elements.into_iter().map(C::from).collect()
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_iter()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
579
src/shell/element/surface.rs
Normal file
579
src/shell/element/surface.rs
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use smithay::{
|
||||||
|
backend::renderer::{
|
||||||
|
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
|
||||||
|
ImportAll, Renderer,
|
||||||
|
},
|
||||||
|
desktop::{
|
||||||
|
utils::{
|
||||||
|
send_frames_surface_tree, take_presentation_feedback_surface_tree,
|
||||||
|
with_surfaces_surface_tree, OutputPresentationFeedback,
|
||||||
|
},
|
||||||
|
Window,
|
||||||
|
},
|
||||||
|
input::{keyboard::KeyboardTarget, pointer::PointerTarget},
|
||||||
|
output::Output,
|
||||||
|
reexports::{
|
||||||
|
wayland_protocols::{
|
||||||
|
wp::presentation_time::server::wp_presentation_feedback::Kind,
|
||||||
|
xdg::{
|
||||||
|
decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode as DecorationMode,
|
||||||
|
shell::server::xdg_toplevel::State as ToplevelState,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wayland_server::protocol::wl_surface::WlSurface,
|
||||||
|
},
|
||||||
|
space_elements,
|
||||||
|
utils::{user_data::UserDataMap, Logical, Rectangle, Size},
|
||||||
|
wayland::{
|
||||||
|
compositor::{with_states, SurfaceData},
|
||||||
|
seat::WaylandFocus,
|
||||||
|
shell::xdg::XdgToplevelSurfaceData,
|
||||||
|
},
|
||||||
|
xwayland::X11Surface,
|
||||||
|
};
|
||||||
|
|
||||||
|
space_elements! {
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub CosmicSurface;
|
||||||
|
Wayland=Window,
|
||||||
|
X11=X11Surface,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const SSD_HEIGHT: i32 = 48;
|
||||||
|
|
||||||
|
impl CosmicSurface {
|
||||||
|
pub fn title(&self) -> String {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
with_states(window.toplevel().wl_surface(), |states| {
|
||||||
|
states
|
||||||
|
.data_map
|
||||||
|
.get::<XdgToplevelSurfaceData>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.title
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => surface.title(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn app_id(&self) -> String {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
with_states(window.toplevel().wl_surface(), |states| {
|
||||||
|
states
|
||||||
|
.data_map
|
||||||
|
.get::<XdgToplevelSurfaceData>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.app_id
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => surface.class(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_size(&self, size: Size<i32, Logical>) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window
|
||||||
|
.toplevel()
|
||||||
|
.with_pending_state(|state| state.size = Some(size)),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
let rect = Rectangle::from_loc_and_size(surface.geometry().loc, size);
|
||||||
|
let _ = surface.configure(rect);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_activated(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window
|
||||||
|
.toplevel()
|
||||||
|
.current_state()
|
||||||
|
.states
|
||||||
|
.contains(ToplevelState::Activated),
|
||||||
|
CosmicSurface::X11(surface) => surface.is_activated(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_activated(&self, activated: bool) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.toplevel().with_pending_state(|state| {
|
||||||
|
if activated {
|
||||||
|
state.states.set(ToplevelState::Activated);
|
||||||
|
} else {
|
||||||
|
state.states.unset(ToplevelState::Activated);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
let _ = surface.set_activated(activated);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_decorated(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window
|
||||||
|
.toplevel()
|
||||||
|
.current_state()
|
||||||
|
.decoration_mode
|
||||||
|
.map(|mode| mode == DecorationMode::ClientSide)
|
||||||
|
.unwrap_or(true),
|
||||||
|
CosmicSurface::X11(surface) => surface.is_decorated(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_resizing(&self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
let xdg = window.toplevel();
|
||||||
|
Some(
|
||||||
|
xdg.current_state().states.contains(ToplevelState::Resizing)
|
||||||
|
|| xdg.with_pending_state(|states| {
|
||||||
|
states.states.contains(ToplevelState::Resizing)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_resizing(&self, resizing: bool) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.toplevel().with_pending_state(|state| {
|
||||||
|
if resizing {
|
||||||
|
state.states.set(ToplevelState::Resizing);
|
||||||
|
} else {
|
||||||
|
state.states.unset(ToplevelState::Resizing);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_tiled(&self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => Some(
|
||||||
|
window
|
||||||
|
.toplevel()
|
||||||
|
.current_state()
|
||||||
|
.states
|
||||||
|
.contains(ToplevelState::TiledLeft),
|
||||||
|
),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tiled(&self, tiled: bool) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.toplevel().with_pending_state(|state| {
|
||||||
|
if tiled {
|
||||||
|
state.states.set(ToplevelState::TiledLeft);
|
||||||
|
state.states.set(ToplevelState::TiledRight);
|
||||||
|
state.states.set(ToplevelState::TiledTop);
|
||||||
|
state.states.set(ToplevelState::TiledBottom);
|
||||||
|
} else {
|
||||||
|
state.states.unset(ToplevelState::TiledLeft);
|
||||||
|
state.states.unset(ToplevelState::TiledRight);
|
||||||
|
state.states.unset(ToplevelState::TiledTop);
|
||||||
|
state.states.unset(ToplevelState::TiledBottom);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_fullscreen(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
let xdg = window.toplevel();
|
||||||
|
xdg.current_state()
|
||||||
|
.states
|
||||||
|
.contains(ToplevelState::Fullscreen)
|
||||||
|
|| xdg.with_pending_state(|state| {
|
||||||
|
state.states.contains(ToplevelState::Fullscreen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => surface.is_fullscreen(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_fullscreen(&self, fullscreen: bool) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.toplevel().with_pending_state(|state| {
|
||||||
|
if fullscreen {
|
||||||
|
state.states.set(ToplevelState::Fullscreen);
|
||||||
|
} else {
|
||||||
|
state.states.unset(ToplevelState::Fullscreen);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
let _ = surface.set_fullscreen(fullscreen);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_maximized(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
let xdg = window.toplevel();
|
||||||
|
xdg.current_state()
|
||||||
|
.states
|
||||||
|
.contains(ToplevelState::Maximized)
|
||||||
|
|| xdg
|
||||||
|
.with_pending_state(|state| state.states.contains(ToplevelState::Maximized))
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => surface.is_maximized(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_maximized(&self, maximized: bool) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.toplevel().with_pending_state(|state| {
|
||||||
|
if maximized {
|
||||||
|
state.states.set(ToplevelState::Maximized);
|
||||||
|
} else {
|
||||||
|
state.states.unset(ToplevelState::Maximized);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
let _ = surface.set_maximized(maximized);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min_size(&self) -> Option<Size<i32, Logical>> {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
Some(with_states(window.toplevel().wl_surface(), |states| {
|
||||||
|
let attrs = states
|
||||||
|
.data_map
|
||||||
|
.get::<XdgToplevelSurfaceData>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
attrs.min_size
|
||||||
|
}))
|
||||||
|
.filter(|size| !(size.w == 0 && size.h == 0))
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => surface.min_size(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_size(&self) -> Option<Size<i32, Logical>> {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
Some(with_states(window.toplevel().wl_surface(), |states| {
|
||||||
|
let attrs = states
|
||||||
|
.data_map
|
||||||
|
.get::<XdgToplevelSurfaceData>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
attrs.max_size
|
||||||
|
}))
|
||||||
|
.filter(|size| !(size.w == 0 && size.h == 0))
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => surface.max_size(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_configure(&self) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.toplevel().send_configure(),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
let _ = surface.configure(None);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.toplevel().send_close(),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
let _ = surface.close();
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_commit(&self) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.on_commit(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_frame<T, F>(
|
||||||
|
&self,
|
||||||
|
output: &Output,
|
||||||
|
time: T,
|
||||||
|
throttle: Option<Duration>,
|
||||||
|
primary_scan_out_output: F,
|
||||||
|
) where
|
||||||
|
T: Into<Duration>,
|
||||||
|
F: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
window.send_frame(output, time, throttle, primary_scan_out_output)
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
if let Some(wl_surface) = surface.wl_surface() {
|
||||||
|
send_frames_surface_tree(
|
||||||
|
&wl_surface,
|
||||||
|
output,
|
||||||
|
time,
|
||||||
|
throttle,
|
||||||
|
primary_scan_out_output,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_presentation_feedback<F1, F2>(
|
||||||
|
&self,
|
||||||
|
output_feedback: &mut OutputPresentationFeedback,
|
||||||
|
primary_scan_out_output: F1,
|
||||||
|
presentation_feedback_flags: F2,
|
||||||
|
) where
|
||||||
|
F1: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
||||||
|
F2: FnMut(&WlSurface, &SurfaceData) -> Kind + Copy,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.take_presentation_feedback(
|
||||||
|
output_feedback,
|
||||||
|
primary_scan_out_output,
|
||||||
|
presentation_feedback_flags,
|
||||||
|
),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
if let Some(wl_surface) = surface.wl_surface() {
|
||||||
|
take_presentation_feedback_surface_tree(
|
||||||
|
&wl_surface,
|
||||||
|
output_feedback,
|
||||||
|
primary_scan_out_output,
|
||||||
|
presentation_feedback_flags,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_surfaces<F>(&self, processor: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&WlSurface, &SurfaceData) + Copy,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.with_surfaces(processor),
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
if let Some(wl_surface) = surface.wl_surface() {
|
||||||
|
with_surfaces_surface_tree(&wl_surface, processor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_data(&self) -> &UserDataMap {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.user_data(),
|
||||||
|
CosmicSurface::X11(surface) => surface.user_data(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyboardTarget<crate::state::State> for CosmicSurface {
|
||||||
|
fn enter(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
keys: Vec<smithay::input::keyboard::KeysymHandle<'_>>,
|
||||||
|
serial: smithay::utils::Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
KeyboardTarget::enter(window, seat, data, keys, serial)
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => KeyboardTarget::enter(surface, seat, data, keys, serial),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
serial: smithay::utils::Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => KeyboardTarget::leave(window, seat, data, serial),
|
||||||
|
CosmicSurface::X11(surface) => KeyboardTarget::leave(surface, seat, data, serial),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
key: smithay::input::keyboard::KeysymHandle<'_>,
|
||||||
|
state: smithay::backend::input::KeyState,
|
||||||
|
serial: smithay::utils::Serial,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
KeyboardTarget::key(window, seat, data, key, state, serial, time)
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
KeyboardTarget::key(surface, seat, data, key, state, serial, time)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modifiers(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
modifiers: smithay::input::keyboard::ModifiersState,
|
||||||
|
serial: smithay::utils::Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
KeyboardTarget::modifiers(window, seat, data, modifiers, serial)
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
KeyboardTarget::modifiers(surface, seat, data, modifiers, serial)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerTarget<crate::state::State> for CosmicSurface {
|
||||||
|
fn enter(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
event: &smithay::input::pointer::MotionEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => PointerTarget::enter(window, seat, data, event),
|
||||||
|
CosmicSurface::X11(surface) => PointerTarget::enter(surface, seat, data, event),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
event: &smithay::input::pointer::MotionEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => PointerTarget::motion(window, seat, data, event),
|
||||||
|
CosmicSurface::X11(surface) => PointerTarget::motion(surface, seat, data, event),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
event: &smithay::input::pointer::ButtonEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => PointerTarget::button(window, seat, data, event),
|
||||||
|
CosmicSurface::X11(surface) => PointerTarget::button(surface, seat, data, event),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
frame: smithay::input::pointer::AxisFrame,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => PointerTarget::axis(window, seat, data, frame),
|
||||||
|
CosmicSurface::X11(surface) => PointerTarget::axis(surface, seat, data, frame),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(
|
||||||
|
&self,
|
||||||
|
seat: &smithay::input::Seat<crate::state::State>,
|
||||||
|
data: &mut crate::state::State,
|
||||||
|
serial: smithay::utils::Serial,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => {
|
||||||
|
PointerTarget::leave(window, seat, data, serial, time)
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(surface) => PointerTarget::leave(surface, seat, data, serial, time),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WaylandFocus for CosmicSurface {
|
||||||
|
fn wl_surface(&self) -> Option<WlSurface> {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.wl_surface(),
|
||||||
|
CosmicSurface::X11(surface) => surface.wl_surface(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> AsRenderElements<R> for CosmicSurface
|
||||||
|
where
|
||||||
|
R: Renderer + ImportAll,
|
||||||
|
<R as Renderer>::TextureId: 'static,
|
||||||
|
{
|
||||||
|
type RenderElement = WaylandSurfaceRenderElement<R>;
|
||||||
|
|
||||||
|
fn render_elements<C: From<Self::RenderElement>>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
location: smithay::utils::Point<i32, smithay::utils::Physical>,
|
||||||
|
scale: smithay::utils::Scale<f64>,
|
||||||
|
) -> Vec<C> {
|
||||||
|
match self {
|
||||||
|
CosmicSurface::Wayland(window) => window.render_elements(renderer, location, scale),
|
||||||
|
CosmicSurface::X11(surface) => surface.render_elements(renderer, location, scale),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,152 +1,280 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
state::State, utils::prelude::SeatExt, wayland::handlers::screencopy::ScreencopySessions,
|
state::State,
|
||||||
|
utils::{
|
||||||
|
iced::{IcedElement, Program},
|
||||||
|
prelude::SeatExt,
|
||||||
|
},
|
||||||
|
wayland::handlers::screencopy::ScreencopySessions,
|
||||||
};
|
};
|
||||||
|
use calloop::LoopHandle;
|
||||||
|
use cosmic::{iced_native::Command, Element};
|
||||||
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
||||||
|
use iced_softbuffer::native::raqote::{DrawOptions, DrawTarget, PathBuilder, SolidSource, Source};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
input::KeyState,
|
input::KeyState,
|
||||||
renderer::{
|
renderer::{
|
||||||
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
|
element::{
|
||||||
ImportAll, Renderer,
|
memory::MemoryRenderBufferRenderElement, surface::WaylandSurfaceRenderElement,
|
||||||
|
AsRenderElements,
|
||||||
|
},
|
||||||
|
ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::{space::SpaceElement, Window},
|
desktop::space::SpaceElement,
|
||||||
input::{
|
input::{
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
||||||
Seat,
|
Seat,
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode as DecorationMode,
|
|
||||||
render_elements,
|
render_elements,
|
||||||
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size},
|
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size},
|
||||||
wayland::shell::xdg::ToplevelSurface,
|
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::{Arc, Mutex},
|
sync::{
|
||||||
|
atomic::{AtomicU8, Ordering},
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::{surface::SSD_HEIGHT, CosmicSurface};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct CosmicWindow(IcedElement<CosmicWindowInternal>);
|
||||||
|
|
||||||
|
impl fmt::Debug for CosmicWindow {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.0.with_program(|window| {
|
||||||
|
f.debug_struct("CosmicWindow")
|
||||||
|
.field("internal", window)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CosmicWindow {
|
pub struct CosmicWindowInternal {
|
||||||
pub(super) window: Window,
|
pub(super) window: CosmicSurface,
|
||||||
pub(super) header: Arc<Mutex<Option<HeaderBar>>>,
|
pointer_entered: Option<Arc<AtomicU8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<Window> for CosmicWindow {
|
#[repr(u8)]
|
||||||
fn eq(&self, other: &Window) -> bool {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
&self.window == other
|
pub enum Focus {
|
||||||
|
None,
|
||||||
|
Header,
|
||||||
|
Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CosmicWindowInternal {
|
||||||
|
pub fn swap_focus(&self, focus: Focus) -> Focus {
|
||||||
|
if let Some(pointer_entered) = self.pointer_entered.as_ref() {
|
||||||
|
unsafe {
|
||||||
|
std::mem::transmute::<u8, Focus>(
|
||||||
|
pointer_entered.swap(focus as u8, Ordering::SeqCst),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Focus::Window
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<CosmicWindow> for Window {
|
pub fn current_focus(&self) -> Focus {
|
||||||
fn eq(&self, other: &CosmicWindow) -> bool {
|
if let Some(pointer_entered) = self.pointer_entered.as_ref() {
|
||||||
self == &other.window
|
unsafe { std::mem::transmute::<u8, Focus>(pointer_entered.load(Ordering::SeqCst)) }
|
||||||
|
} else {
|
||||||
|
Focus::Window
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for CosmicWindow {
|
pub fn has_ssd(&self) -> bool {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
self.pointer_entered.is_some()
|
||||||
self.window == other.window
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for CosmicWindow {}
|
|
||||||
|
|
||||||
impl Hash for CosmicWindow {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.window.hash(state)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CosmicWindow {
|
impl CosmicWindow {
|
||||||
|
pub fn new(
|
||||||
|
window: impl Into<CosmicSurface>,
|
||||||
|
handle: LoopHandle<'static, crate::state::Data>,
|
||||||
|
) -> CosmicWindow {
|
||||||
|
let window = window.into();
|
||||||
|
let needs_ssd = !window.is_decorated();
|
||||||
|
let width = window.geometry().size.w;
|
||||||
|
CosmicWindow(IcedElement::new(
|
||||||
|
CosmicWindowInternal {
|
||||||
|
window,
|
||||||
|
pointer_entered: if needs_ssd {
|
||||||
|
Some(Arc::new(AtomicU8::new(Focus::None as u8)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(width, SSD_HEIGHT),
|
||||||
|
handle,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_size(&self, size: Size<i32, Logical>) {
|
pub fn set_size(&self, size: Size<i32, Logical>) {
|
||||||
let surface_size = (
|
self.0.with_program(|p| {
|
||||||
size.w,
|
let surface_size = (size.w, size.h - if p.has_ssd() { SSD_HEIGHT } else { 0 }).into();
|
||||||
size.h
|
p.window.set_size(surface_size)
|
||||||
- self
|
});
|
||||||
.header
|
self.0.resize(Size::from((size.w, SSD_HEIGHT)));
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
.map(|h| h.height())
|
|
||||||
.unwrap_or(0),
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
self.window
|
|
||||||
.toplevel()
|
|
||||||
.with_pending_state(|state| state.size = Some(surface_size));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Window> for CosmicWindow {
|
pub fn surface(&self) -> CosmicSurface {
|
||||||
fn from(window: Window) -> Self {
|
self.0.with_program(|p| p.window.clone())
|
||||||
let is_ssd = matches!(
|
}
|
||||||
window.toplevel().current_state().decoration_mode,
|
|
||||||
Some(DecorationMode::ServerSide)
|
pub fn offset(&self) -> Point<i32, Logical> {
|
||||||
);
|
let has_ssd = self.0.with_program(|p| p.has_ssd());
|
||||||
CosmicWindow {
|
if has_ssd {
|
||||||
window,
|
Point::from((0, SSD_HEIGHT))
|
||||||
header: Arc::new(Mutex::new(is_ssd.then_some(HeaderBar::default()))),
|
} else {
|
||||||
|
Point::from((0, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ToplevelSurface> for CosmicWindow {
|
#[derive(Debug, Clone, Copy)]
|
||||||
fn from(surf: ToplevelSurface) -> Self {
|
pub enum Message {
|
||||||
let is_ssd = matches!(
|
DragStart,
|
||||||
surf.current_state().decoration_mode,
|
Maximize,
|
||||||
Some(DecorationMode::ServerSide)
|
Close,
|
||||||
);
|
}
|
||||||
CosmicWindow {
|
|
||||||
window: Window::new(surf),
|
impl Program for CosmicWindowInternal {
|
||||||
header: Arc::new(Mutex::new(is_ssd.then_some(HeaderBar::default()))),
|
type Message = Message;
|
||||||
|
|
||||||
|
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
||||||
|
/*
|
||||||
|
match message {
|
||||||
|
Message::DragStart => match &self.window {
|
||||||
|
CosmicWindowSurface::Wayland(window) => self
|
||||||
|
.with_program(|internal| internal.loop_handle())
|
||||||
|
.insert_idle(|data| {}),
|
||||||
|
CosmicWindowSurface::X11(surface) => {}
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Command::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn background(&self, target: &mut DrawTarget<&mut [u32]>) {
|
||||||
|
let radius = 8.;
|
||||||
|
let (w, h) = (target.width() as f32, target.height() as f32);
|
||||||
|
|
||||||
|
let mut pb = PathBuilder::new();
|
||||||
|
pb.move_to(0., h); // lower-left
|
||||||
|
|
||||||
|
// upper-left rounded corner
|
||||||
|
pb.line_to(0., radius);
|
||||||
|
pb.quad_to(0., 0., radius, 0.);
|
||||||
|
|
||||||
|
// upper-right rounded corner
|
||||||
|
pb.line_to(w - radius, 0.);
|
||||||
|
pb.quad_to(w, 0., w, radius);
|
||||||
|
|
||||||
|
pb.line_to(w, h); // lower-right
|
||||||
|
|
||||||
|
let path = pb.finish();
|
||||||
|
target.push_clip(&path);
|
||||||
|
|
||||||
|
if self.window.is_activated() {
|
||||||
|
target.clear(SolidSource::from_unpremultiplied_argb(u8::MAX, 30, 30, 30));
|
||||||
|
} else {
|
||||||
|
target.clear(SolidSource::from_unpremultiplied_argb(u8::MAX, 39, 39, 39));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq)]
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
pub(super) struct HeaderBar {
|
cosmic::widget::header_bar()
|
||||||
pointer_loc: Option<Point<f64, Logical>>,
|
.title(self.window.title())
|
||||||
close_button_hover: bool,
|
.on_drag(Message::DragStart)
|
||||||
maximize_button_hover: bool,
|
.on_maximize(Message::Maximize)
|
||||||
}
|
.on_close(Message::Close)
|
||||||
|
.into_element()
|
||||||
|
}
|
||||||
|
|
||||||
impl HeaderBar {
|
fn foreground(&self, target: &mut DrawTarget<&mut [u32]>) {
|
||||||
pub fn height(&self) -> i32 {
|
if !self.window.is_activated() {
|
||||||
0
|
let (w, h) = (target.width() as f32, target.height() as f32);
|
||||||
|
let mut options = DrawOptions::new();
|
||||||
|
options.alpha = 0.4;
|
||||||
|
target.fill_rect(
|
||||||
|
0.,
|
||||||
|
0.,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
&Source::Solid(SolidSource::from_unpremultiplied_argb(u8::MAX, 0, 0, 0)),
|
||||||
|
&options,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsAlive for CosmicWindow {
|
impl IsAlive for CosmicWindow {
|
||||||
fn alive(&self) -> bool {
|
fn alive(&self) -> bool {
|
||||||
self.window.alive()
|
self.0.with_program(|p| p.window.alive())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpaceElement for CosmicWindow {
|
impl SpaceElement for CosmicWindow {
|
||||||
fn bbox(&self) -> Rectangle<i32, Logical> {
|
fn bbox(&self) -> Rectangle<i32, Logical> {
|
||||||
SpaceElement::bbox(&self.window)
|
self.0.with_program(|p| {
|
||||||
|
let mut bbox = SpaceElement::bbox(&p.window);
|
||||||
|
if p.has_ssd() {
|
||||||
|
bbox.size.h += SSD_HEIGHT;
|
||||||
|
}
|
||||||
|
bbox
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
|
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
|
||||||
SpaceElement::is_in_input_region(&self.window, point)
|
let mut point = *point;
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
if p.has_ssd() {
|
||||||
|
if point.y < SSD_HEIGHT as f64 {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
point.y -= SSD_HEIGHT as f64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpaceElement::is_in_input_region(&p.window, &point)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn set_activate(&self, activated: bool) {
|
fn set_activate(&self, activated: bool) {
|
||||||
SpaceElement::set_activate(&self.window, activated)
|
SpaceElement::set_activate(&self.0, activated);
|
||||||
|
self.0
|
||||||
|
.with_program(|p| SpaceElement::set_activate(&p.window, activated));
|
||||||
}
|
}
|
||||||
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
|
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
|
||||||
SpaceElement::output_enter(&self.window, output, overlap)
|
SpaceElement::output_enter(&self.0, output, overlap);
|
||||||
|
self.0
|
||||||
|
.with_program(|p| SpaceElement::output_enter(&p.window, output, overlap));
|
||||||
}
|
}
|
||||||
fn output_leave(&self, output: &Output) {
|
fn output_leave(&self, output: &Output) {
|
||||||
SpaceElement::output_leave(&self.window, output)
|
SpaceElement::output_leave(&self.0, output);
|
||||||
|
self.0
|
||||||
|
.with_program(|p| SpaceElement::output_leave(&p.window, output));
|
||||||
}
|
}
|
||||||
fn geometry(&self) -> Rectangle<i32, Logical> {
|
fn geometry(&self) -> Rectangle<i32, Logical> {
|
||||||
SpaceElement::geometry(&self.window)
|
self.0.with_program(|p| {
|
||||||
|
let mut geo = SpaceElement::geometry(&p.window);
|
||||||
|
if p.has_ssd() {
|
||||||
|
geo.size.h += SSD_HEIGHT;
|
||||||
|
}
|
||||||
|
geo
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn z_index(&self) -> u8 {
|
fn z_index(&self) -> u8 {
|
||||||
SpaceElement::z_index(&self.window)
|
self.0.with_program(|p| SpaceElement::z_index(&p.window))
|
||||||
}
|
}
|
||||||
fn refresh(&self) {
|
fn refresh(&self) {
|
||||||
SpaceElement::refresh(&self.window)
|
self.0.with_program(|p| SpaceElement::refresh(&p.window))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,10 +286,12 @@ impl KeyboardTarget<State> for CosmicWindow {
|
||||||
keys: Vec<KeysymHandle<'_>>,
|
keys: Vec<KeysymHandle<'_>>,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) {
|
) {
|
||||||
KeyboardTarget::enter(&self.window, seat, data, keys, serial)
|
self.0
|
||||||
|
.with_program(|p| KeyboardTarget::enter(&p.window, seat, data, keys, serial))
|
||||||
}
|
}
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
|
||||||
KeyboardTarget::leave(&self.window, seat, data, serial)
|
self.0
|
||||||
|
.with_program(|p| KeyboardTarget::leave(&p.window, seat, data, serial))
|
||||||
}
|
}
|
||||||
fn key(
|
fn key(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -172,7 +302,8 @@ impl KeyboardTarget<State> for CosmicWindow {
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
KeyboardTarget::key(&self.window, seat, data, key, state, serial, time)
|
self.0
|
||||||
|
.with_program(|p| KeyboardTarget::key(&p.window, seat, data, key, state, serial, time))
|
||||||
}
|
}
|
||||||
fn modifiers(
|
fn modifiers(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -181,82 +312,169 @@ impl KeyboardTarget<State> for CosmicWindow {
|
||||||
modifiers: ModifiersState,
|
modifiers: ModifiersState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) {
|
) {
|
||||||
KeyboardTarget::modifiers(&self.window, seat, data, modifiers, serial)
|
self.0
|
||||||
|
.with_program(|p| KeyboardTarget::modifiers(&p.window, seat, data, modifiers, serial))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerTarget<State> for CosmicWindow {
|
impl PointerTarget<State> for CosmicWindow {
|
||||||
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
||||||
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
if self.0.with_program(|p| {
|
||||||
|
if let Some(sessions) = p.window.user_data().get::<ScreencopySessions>() {
|
||||||
if let Some(sessions) = self.window.user_data().get::<ScreencopySessions>() {
|
for session in &*sessions.0.borrow() {
|
||||||
for session in &*sessions.0.borrow() {
|
session.cursor_enter(seat, InputType::Pointer)
|
||||||
session.cursor_enter(seat, InputType::Pointer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PointerTarget::enter(&self.window, seat, data, event)
|
|
||||||
}
|
|
||||||
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
|
||||||
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
|
||||||
|
|
||||||
if let Some(sessions) = self.window.user_data().get::<ScreencopySessions>() {
|
|
||||||
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)) =
|
|
||||||
seat.cursor_geometry(buffer_loc, data.common.clock.now())
|
|
||||||
{
|
|
||||||
session.cursor_info(seat, InputType::Pointer, geo, hotspot);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PointerTarget::motion(&self.window, seat, data, event)
|
if p.has_ssd() {
|
||||||
}
|
if event.location.y < SSD_HEIGHT as f64 {
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
let focus = p.swap_focus(Focus::Header);
|
||||||
PointerTarget::button(&self.window, seat, data, event)
|
assert_eq!(focus, Focus::None);
|
||||||
}
|
return true;
|
||||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
} else {
|
||||||
PointerTarget::axis(&self.window, seat, data, frame)
|
let focus = p.swap_focus(Focus::Window);
|
||||||
}
|
assert_eq!(focus, Focus::None);
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
|
||||||
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
|
||||||
|
|
||||||
if let Some(sessions) = self.window.user_data().get::<ScreencopySessions>() {
|
let mut event = event.clone();
|
||||||
for session in &*sessions.0.borrow() {
|
event.location.y -= SSD_HEIGHT as f64;
|
||||||
session.cursor_leave(seat, InputType::Pointer)
|
PointerTarget::enter(&p.window, seat, data, &event)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PointerTarget::enter(&p.window, seat, data, event)
|
||||||
}
|
}
|
||||||
|
false
|
||||||
|
}) {
|
||||||
|
PointerTarget::enter(&self.0, seat, data, event)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PointerTarget::leave(&self.window, seat, data, serial, time)
|
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
||||||
|
if let Some((previous, next)) = self.0.with_program(|p| {
|
||||||
|
if let Some(sessions) = p.window.user_data().get::<ScreencopySessions>() {
|
||||||
|
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)) =
|
||||||
|
seat.cursor_geometry(buffer_loc, data.common.clock.now())
|
||||||
|
{
|
||||||
|
session.cursor_info(seat, InputType::Pointer, geo, hotspot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.has_ssd() {
|
||||||
|
if event.location.y < SSD_HEIGHT as f64 {
|
||||||
|
let previous = p.swap_focus(Focus::Header);
|
||||||
|
if previous == Focus::Window {
|
||||||
|
PointerTarget::leave(&p.window, seat, data, event.serial, event.time);
|
||||||
|
}
|
||||||
|
Some((previous, Focus::Header))
|
||||||
|
} else {
|
||||||
|
let mut event = event.clone();
|
||||||
|
event.location.y -= SSD_HEIGHT as f64;
|
||||||
|
|
||||||
|
let previous = p.swap_focus(Focus::Window);
|
||||||
|
if previous != Focus::Window {
|
||||||
|
PointerTarget::enter(&p.window, seat, data, &event);
|
||||||
|
} else {
|
||||||
|
PointerTarget::motion(&p.window, seat, data, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((previous, Focus::Window))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PointerTarget::motion(&p.window, seat, data, event);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
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, _) => {
|
||||||
|
PointerTarget::leave(&self.0, seat, data, event.serial, event.time)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
||||||
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
|
Focus::Header => PointerTarget::button(&self.0, seat, data, event),
|
||||||
|
Focus::Window => self
|
||||||
|
.0
|
||||||
|
.with_program(|p| PointerTarget::button(&p.window, seat, data, event)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
||||||
|
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::axis(&p.window, seat, data, frame)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
||||||
|
let previous = self.0.with_program(|p| {
|
||||||
|
if let Some(sessions) = p.window.user_data().get::<ScreencopySessions>() {
|
||||||
|
for session in &*sessions.0.borrow() {
|
||||||
|
session.cursor_leave(seat, InputType::Pointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.swap_focus(Focus::None)
|
||||||
|
});
|
||||||
|
assert!(previous != Focus::None);
|
||||||
|
match previous {
|
||||||
|
Focus::Header => PointerTarget::leave(&self.0, seat, data, serial, time),
|
||||||
|
Focus::Window => self
|
||||||
|
.0
|
||||||
|
.with_program(|p| PointerTarget::leave(&p.window, seat, data, serial, time)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_elements! {
|
render_elements! {
|
||||||
pub CosmicWindowRenderElement<R> where R: ImportAll;
|
pub CosmicWindowRenderElement<R> where R: ImportAll + ImportMem;
|
||||||
|
Header=MemoryRenderBufferRenderElement<R>,
|
||||||
Window=WaylandSurfaceRenderElement<R>,
|
Window=WaylandSurfaceRenderElement<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> AsRenderElements<R> for CosmicWindow
|
impl<R> AsRenderElements<R> for CosmicWindow
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll,
|
R: Renderer + ImportAll + ImportMem,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
{
|
{
|
||||||
type RenderElement = CosmicWindowRenderElement<R>;
|
type RenderElement = CosmicWindowRenderElement<R>;
|
||||||
fn render_elements<C: From<Self::RenderElement>>(
|
fn render_elements<C: From<Self::RenderElement>>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
location: Point<i32, Physical>,
|
mut location: Point<i32, Physical>,
|
||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
) -> Vec<C> {
|
) -> Vec<C> {
|
||||||
AsRenderElements::<R>::render_elements::<CosmicWindowRenderElement<R>>(
|
let has_ssd = self.0.with_program(|p| p.has_ssd());
|
||||||
&self.window,
|
|
||||||
renderer,
|
let mut elements = if has_ssd {
|
||||||
location,
|
let elements = AsRenderElements::<R>::render_elements::<CosmicWindowRenderElement<R>>(
|
||||||
scale,
|
&self.0, renderer, location, scale,
|
||||||
)
|
);
|
||||||
.into_iter()
|
location.y += SSD_HEIGHT;
|
||||||
.map(C::from)
|
elements
|
||||||
.collect()
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
elements.extend(self.0.with_program(|p| {
|
||||||
|
AsRenderElements::<R>::render_elements::<CosmicWindowRenderElement<R>>(
|
||||||
|
&p.window, renderer, location, scale,
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
}));
|
||||||
|
|
||||||
|
elements.into_iter().map(C::from).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
|
|
||||||
use crate::{shell::element::CosmicMapped, utils::prelude::*};
|
use crate::{
|
||||||
|
shell::{element::CosmicMapped, CosmicSurface},
|
||||||
|
utils::prelude::*,
|
||||||
|
};
|
||||||
use id_tree::NodeId;
|
use id_tree::NodeId;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::KeyState,
|
backend::input::KeyState,
|
||||||
desktop::{LayerSurface, PopupKind, Window},
|
desktop::{LayerSurface, PopupKind},
|
||||||
input::{
|
input::{
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget},
|
||||||
|
|
@ -19,7 +22,7 @@ use smithay::{
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum PointerFocusTarget {
|
pub enum PointerFocusTarget {
|
||||||
Element(CosmicMapped),
|
Element(CosmicMapped),
|
||||||
Fullscreen(Window),
|
Fullscreen(CosmicSurface),
|
||||||
LayerSurface(LayerSurface),
|
LayerSurface(LayerSurface),
|
||||||
Popup(PopupKind),
|
Popup(PopupKind),
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +30,7 @@ pub enum PointerFocusTarget {
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum KeyboardFocusTarget {
|
pub enum KeyboardFocusTarget {
|
||||||
Element(CosmicMapped),
|
Element(CosmicMapped),
|
||||||
Fullscreen(Window),
|
Fullscreen(CosmicSurface),
|
||||||
Group(WindowGroup),
|
Group(WindowGroup),
|
||||||
LayerSurface(LayerSurface),
|
LayerSurface(LayerSurface),
|
||||||
Popup(PopupKind),
|
Popup(PopupKind),
|
||||||
|
|
@ -263,9 +266,9 @@ impl From<CosmicMapped> for PointerFocusTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Window> for PointerFocusTarget {
|
impl From<CosmicSurface> for PointerFocusTarget {
|
||||||
fn from(w: Window) -> Self {
|
fn from(s: CosmicSurface) -> Self {
|
||||||
PointerFocusTarget::Fullscreen(w)
|
PointerFocusTarget::Fullscreen(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,9 +290,9 @@ impl From<CosmicMapped> for KeyboardFocusTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Window> for KeyboardFocusTarget {
|
impl From<CosmicSurface> for KeyboardFocusTarget {
|
||||||
fn from(w: Window) -> Self {
|
fn from(s: CosmicSurface) -> Self {
|
||||||
KeyboardFocusTarget::Fullscreen(w)
|
KeyboardFocusTarget::Fullscreen(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{AsRenderElements, RenderElement},
|
element::{AsRenderElements, RenderElement},
|
||||||
ImportAll, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
desktop::space::SpaceElement,
|
desktop::space::SpaceElement,
|
||||||
input::{
|
input::{
|
||||||
|
|
@ -38,7 +38,7 @@ pub struct MoveGrabState {
|
||||||
impl MoveGrabState {
|
impl MoveGrabState {
|
||||||
pub fn render<I, R>(&self, renderer: &mut R, seat: &Seat<State>, output: &Output) -> Vec<I>
|
pub fn render<I, R>(&self, renderer: &mut R, seat: &Seat<State>, output: &Output) -> Vec<I>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
I: From<CosmicMappedRenderElement<R>>,
|
I: From<CosmicMappedRenderElement<R>>,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::{element::CosmicMapped, focus::target::PointerFocusTarget, grabs::ResizeEdge},
|
shell::{
|
||||||
|
element::CosmicMapped, focus::target::PointerFocusTarget, grabs::ResizeEdge, CosmicSurface,
|
||||||
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
|
@ -84,18 +86,10 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
|
|
||||||
let (min_size, max_size) = (self.window.min_size(), self.window.max_size());
|
let (min_size, max_size) = (self.window.min_size(), self.window.max_size());
|
||||||
|
|
||||||
let min_width = min_size.w.max(1);
|
let min_width = min_size.map(|s| s.w).unwrap_or(1);
|
||||||
let min_height = min_size.h.max(1);
|
let min_height = min_size.map(|s| s.h).unwrap_or(1);
|
||||||
let max_width = if max_size.w == 0 {
|
let max_width = max_size.map(|s| s.w).unwrap_or(i32::max_value());
|
||||||
i32::max_value()
|
let max_height = max_size.map(|s| s.h).unwrap_or(i32::max_value());
|
||||||
} else {
|
|
||||||
max_size.w
|
|
||||||
};
|
|
||||||
let max_height = if max_size.h == 0 {
|
|
||||||
i32::max_value()
|
|
||||||
} else {
|
|
||||||
max_size.h
|
|
||||||
};
|
|
||||||
|
|
||||||
new_window_width = new_window_width.max(min_width).min(max_width);
|
new_window_width = new_window_width.max(min_width).min(max_width);
|
||||||
new_window_height = new_window_height.max(min_height).min(max_height);
|
new_window_height = new_window_height.max(min_height).min(max_height);
|
||||||
|
|
@ -210,7 +204,7 @@ impl ResizeSurfaceGrab {
|
||||||
|
|
||||||
// Finish resizing.
|
// Finish resizing.
|
||||||
if let Some(ResizeState::WaitingForCommit(_)) = *resize_state {
|
if let Some(ResizeState::WaitingForCommit(_)) = *resize_state {
|
||||||
if !window.is_resizing() {
|
if !window.is_resizing().unwrap_or(false) {
|
||||||
*resize_state = None;
|
*resize_state = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -218,11 +212,13 @@ impl ResizeSurfaceGrab {
|
||||||
|
|
||||||
if let Some(new_location) = new_location {
|
if let Some(new_location) = new_location {
|
||||||
for (window, offset) in window.windows() {
|
for (window, offset) in window.windows() {
|
||||||
update_reactive_popups(
|
if let CosmicSurface::Wayland(window) = window {
|
||||||
&window,
|
update_reactive_popups(
|
||||||
new_location + offset,
|
&window,
|
||||||
space.floating_layer.space.outputs(),
|
new_location + offset,
|
||||||
);
|
space.floating_layer.space.outputs(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
space
|
space
|
||||||
.floating_layer
|
.floating_layer
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{element::RenderElement, ImportAll, Renderer},
|
backend::renderer::{element::RenderElement, ImportAll, ImportMem, Renderer},
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, Space, Window},
|
desktop::{layer_map_for_output, space::SpaceElement, Space},
|
||||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{Logical, Point, Rectangle, Serial},
|
utils::{Logical, Point, Rectangle, Serial, Size},
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
element::{CosmicMapped, CosmicMappedRenderElement},
|
element::{CosmicMapped, CosmicMappedRenderElement},
|
||||||
grabs::ResizeEdge,
|
grabs::ResizeEdge,
|
||||||
OutputNotMapped,
|
CosmicSurface, OutputNotMapped,
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
|
@ -81,7 +81,10 @@ impl FloatingLayout {
|
||||||
win_geo.size = size;
|
win_geo.size = size;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let (min_size, max_size) = (mapped.min_size(), mapped.max_size());
|
let (min_size, max_size) = (
|
||||||
|
mapped.min_size().unwrap_or((0, 0).into()),
|
||||||
|
mapped.max_size().unwrap_or((0, 0).into()),
|
||||||
|
);
|
||||||
if win_geo.size.w > geometry.size.w / 3 * 2 {
|
if win_geo.size.w > geometry.size.w / 3 * 2 {
|
||||||
// try a more reasonable size
|
// try a more reasonable size
|
||||||
let mut width = geometry.size.w / 3 * 2;
|
let mut width = geometry.size.w / 3 * 2;
|
||||||
|
|
@ -155,7 +158,7 @@ impl FloatingLayout {
|
||||||
self.space.element_geometry(elem)
|
self.space.element_geometry(elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maximize_request(&mut self, window: &Window) {
|
pub fn maximize_request(&mut self, window: &CosmicSurface) {
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.space
|
.space
|
||||||
.elements()
|
.elements()
|
||||||
|
|
@ -170,7 +173,7 @@ impl FloatingLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmaximize_request(&mut self, window: &Window) {
|
pub fn unmaximize_request(&mut self, window: &CosmicSurface) -> Option<Size<i32, Logical>> {
|
||||||
let maybe_mapped = self
|
let maybe_mapped = self
|
||||||
.space
|
.space
|
||||||
.elements()
|
.elements()
|
||||||
|
|
@ -179,9 +182,13 @@ impl FloatingLayout {
|
||||||
|
|
||||||
if let Some(mapped) = maybe_mapped {
|
if let Some(mapped) = maybe_mapped {
|
||||||
let last_geometry = mapped.last_geometry.lock().unwrap().clone();
|
let last_geometry = mapped.last_geometry.lock().unwrap().clone();
|
||||||
mapped.set_size(last_geometry.map(|g| g.size).expect("No previous size?"));
|
let last_size = last_geometry.map(|g| g.size).expect("No previous size?");
|
||||||
|
mapped.set_size(last_size);
|
||||||
let last_location = last_geometry.map(|g| g.loc).expect("No previous location?");
|
let last_location = last_geometry.map(|g| g.loc).expect("No previous location?");
|
||||||
self.space.map_element(mapped, last_location, true);
|
self.space.map_element(mapped, last_location, true);
|
||||||
|
Some(last_size)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,7 +220,7 @@ impl FloatingLayout {
|
||||||
self.space.elements()
|
self.space.elements()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn windows(&self) -> impl Iterator<Item = Window> + '_ {
|
pub fn windows(&self) -> impl Iterator<Item = CosmicSurface> + '_ {
|
||||||
self.mapped().flat_map(|e| e.windows().map(|(w, _)| w))
|
self.mapped().flat_map(|e| e.windows().map(|(w, _)| w))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,7 +305,7 @@ impl FloatingLayout {
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
|
) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
use regex::RegexSet;
|
use regex::RegexSet;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::Window,
|
wayland::{compositor::with_states, shell::xdg::XdgToplevelSurfaceData},
|
||||||
wayland::{compositor::with_states, shell::xdg::XdgToplevelSurfaceRoleAttributes},
|
xwayland::xwm::WmWindowType,
|
||||||
};
|
};
|
||||||
use std::sync::Mutex;
|
|
||||||
|
use super::CosmicSurface;
|
||||||
|
|
||||||
pub mod floating;
|
pub mod floating;
|
||||||
pub mod tiling;
|
pub mod tiling;
|
||||||
|
|
@ -95,33 +96,52 @@ lazy_static::lazy_static! {
|
||||||
]).unwrap();
|
]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_be_floating(window: &Window) -> bool {
|
pub fn should_be_floating(window: &CosmicSurface) -> bool {
|
||||||
let surface = window.toplevel().wl_surface();
|
// Check "window type"
|
||||||
with_states(surface, |states| {
|
match window {
|
||||||
let attrs = states
|
CosmicSurface::Wayland(window) => {
|
||||||
.data_map
|
if with_states(window.toplevel().wl_surface(), |states| {
|
||||||
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
let attrs = states
|
||||||
.unwrap()
|
.data_map
|
||||||
.lock()
|
.get::<XdgToplevelSurfaceData>()
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.lock()
|
||||||
// simple heuristic taken from
|
.unwrap();
|
||||||
// sway/desktop/xdg_shell.c:188 @ 0ee54a52
|
attrs.parent.is_some()
|
||||||
if attrs.parent.is_some()
|
}) {
|
||||||
|| (attrs.min_size.w != 0 && attrs.min_size.h != 0 && attrs.min_size == attrs.max_size)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// else take a look at our exceptions
|
|
||||||
let appid_matches = EXCEPTIONS_APPID.matches(attrs.app_id.as_deref().unwrap_or(""));
|
|
||||||
let title_matches = EXCEPTIONS_TITLE.matches(attrs.app_id.as_deref().unwrap_or(""));
|
|
||||||
for idx in appid_matches.into_iter() {
|
|
||||||
if title_matches.matched(idx) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CosmicSurface::X11(surface) => {
|
||||||
|
if surface.is_override_redirect()
|
||||||
|
|| surface.is_popup()
|
||||||
|
|| !matches!(
|
||||||
|
surface.window_type(),
|
||||||
|
None | Some(WmWindowType::Normal) | Some(WmWindowType::Utility)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
false
|
// Check if sizing suggest dialog
|
||||||
})
|
let max_size = window.max_size();
|
||||||
|
let min_size = window.min_size();
|
||||||
|
|
||||||
|
if min_size.is_some() && min_size == max_size {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else take a look at our exceptions
|
||||||
|
let appid_matches = EXCEPTIONS_APPID.matches(&window.app_id());
|
||||||
|
let title_matches = EXCEPTIONS_TITLE.matches(&window.title());
|
||||||
|
for idx in appid_matches.into_iter() {
|
||||||
|
if title_matches.matched(idx) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
grabs::ResizeEdge,
|
grabs::ResizeEdge,
|
||||||
layout::Orientation,
|
layout::Orientation,
|
||||||
OutputNotMapped,
|
CosmicSurface, OutputNotMapped,
|
||||||
},
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::handlers::xdg_shell::popup::get_popup_toplevel,
|
wayland::handlers::xdg_shell::popup::get_popup_toplevel,
|
||||||
|
|
@ -20,12 +20,13 @@ use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBeh
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{AsRenderElements, RenderElement},
|
element::{AsRenderElements, RenderElement},
|
||||||
ImportAll, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, PopupKind, Window},
|
desktop::{layer_map_for_output, space::SpaceElement, PopupKind},
|
||||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{IsAlive, Logical, Point, Rectangle, Scale, Serial},
|
utils::{IsAlive, Logical, Point, Rectangle, Scale, Serial},
|
||||||
|
wayland::seat::WaylandFocus,
|
||||||
};
|
};
|
||||||
use std::{borrow::Borrow, collections::HashMap, hash::Hash, sync::Arc};
|
use std::{borrow::Borrow, collections::HashMap, hash::Hash, sync::Arc};
|
||||||
|
|
||||||
|
|
@ -1003,7 +1004,7 @@ impl TilingLayout {
|
||||||
.find(|node| match node.data() {
|
.find(|node| match node.data() {
|
||||||
Data::Mapped { mapped, .. } => mapped
|
Data::Mapped { mapped, .. } => mapped
|
||||||
.windows()
|
.windows()
|
||||||
.any(|(w, _)| w.toplevel().wl_surface() == &toplevel_surface),
|
.any(|(w, _)| w.wl_surface().as_ref() == Some(&toplevel_surface)),
|
||||||
_ => false,
|
_ => false,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
@ -1200,7 +1201,9 @@ impl TilingLayout {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn windows(&self) -> impl Iterator<Item = (Output, Window, Point<i32, Logical>)> + '_ {
|
pub fn windows(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = (Output, CosmicSurface, Point<i32, Logical>)> + '_ {
|
||||||
self.mapped().flat_map(|(output, mapped, loc)| {
|
self.mapped().flat_map(|(output, mapped, loc)| {
|
||||||
mapped
|
mapped
|
||||||
.windows()
|
.windows()
|
||||||
|
|
@ -1265,7 +1268,7 @@ impl TilingLayout {
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
|
) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::{cell::RefCell, collections::HashMap};
|
||||||
|
|
||||||
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
|
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::{layer_map_for_output, LayerSurface, PopupManager, Window, WindowSurfaceType},
|
desktop::{layer_map_for_output, LayerSurface, PopupManager, WindowSurfaceType},
|
||||||
input::Seat,
|
input::Seat,
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle},
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle},
|
||||||
|
|
@ -37,7 +37,7 @@ pub mod focus;
|
||||||
pub mod grabs;
|
pub mod grabs;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
pub use self::element::CosmicMappedRenderElement;
|
pub use self::element::{CosmicMappedRenderElement, CosmicSurface};
|
||||||
pub use self::workspace::*;
|
pub use self::workspace::*;
|
||||||
use self::{
|
use self::{
|
||||||
element::{CosmicMapped, CosmicWindow},
|
element::{CosmicMapped, CosmicWindow},
|
||||||
|
|
@ -50,12 +50,12 @@ pub struct Shell {
|
||||||
pub outputs: Vec<Output>,
|
pub outputs: Vec<Output>,
|
||||||
pub workspaces: WorkspaceMode,
|
pub workspaces: WorkspaceMode,
|
||||||
pub floating_default: bool,
|
pub floating_default: bool,
|
||||||
pub pending_windows: Vec<(Window, Seat<State>)>,
|
pub pending_windows: Vec<(CosmicSurface, Seat<State>)>,
|
||||||
pub pending_layers: Vec<(LayerSurface, Output, Seat<State>)>,
|
pub pending_layers: Vec<(LayerSurface, Output, Seat<State>)>,
|
||||||
|
|
||||||
// wayland_state
|
// wayland_state
|
||||||
pub layer_shell_state: WlrLayerShellState,
|
pub layer_shell_state: WlrLayerShellState,
|
||||||
pub toplevel_info_state: ToplevelInfoState<State>,
|
pub toplevel_info_state: ToplevelInfoState<State, CosmicSurface>,
|
||||||
pub toplevel_management_state: ToplevelManagementState,
|
pub toplevel_management_state: ToplevelManagementState,
|
||||||
pub xdg_shell_state: XdgShellState,
|
pub xdg_shell_state: XdgShellState,
|
||||||
pub workspace_state: WorkspaceState<State>,
|
pub workspace_state: WorkspaceState<State>,
|
||||||
|
|
@ -144,7 +144,7 @@ impl WorkspaceSet {
|
||||||
fn refresh<'a>(
|
fn refresh<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut WorkspaceState<State>,
|
state: &mut WorkspaceState<State>,
|
||||||
toplevel_info: &mut ToplevelInfoState<State>,
|
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
|
||||||
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
|
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
|
||||||
) {
|
) {
|
||||||
match self.amount {
|
match self.amount {
|
||||||
|
|
@ -213,7 +213,7 @@ impl WorkspaceSet {
|
||||||
&mut self,
|
&mut self,
|
||||||
amount: usize,
|
amount: usize,
|
||||||
state: &mut WorkspaceState<State>,
|
state: &mut WorkspaceState<State>,
|
||||||
toplevel_info: &mut ToplevelInfoState<State>,
|
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
|
||||||
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
|
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
|
||||||
) {
|
) {
|
||||||
if amount < self.workspaces.len() {
|
if amount < self.workspaces.len() {
|
||||||
|
|
@ -957,7 +957,7 @@ impl Shell {
|
||||||
.refresh(Some(&self.workspace_state));
|
.refresh(Some(&self.workspace_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_window(state: &mut State, window: &Window, output: &Output) {
|
pub fn map_window(state: &mut State, window: &CosmicSurface, output: &Output) {
|
||||||
let pos = state
|
let pos = state
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -979,7 +979,10 @@ impl Shell {
|
||||||
.toplevel_info_state
|
.toplevel_info_state
|
||||||
.toplevel_enter_workspace(&window, &workspace.handle);
|
.toplevel_enter_workspace(&window, &workspace.handle);
|
||||||
|
|
||||||
let mapped = CosmicMapped::from(CosmicWindow::from(window.clone()));
|
let mapped = CosmicMapped::from(CosmicWindow::new(
|
||||||
|
window.clone(),
|
||||||
|
state.common.event_loop_handle.clone(),
|
||||||
|
));
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
{
|
{
|
||||||
mapped.set_debug(state.common.egui.active);
|
mapped.set_debug(state.common.egui.active);
|
||||||
|
|
@ -1111,12 +1114,14 @@ impl Shell {
|
||||||
if let Some(workspace) = self.space_for(mapped) {
|
if let Some(workspace) = self.space_for(mapped) {
|
||||||
let element_loc = workspace.element_geometry(mapped).unwrap().loc;
|
let element_loc = workspace.element_geometry(mapped).unwrap().loc;
|
||||||
for (toplevel, offset) in mapped.windows() {
|
for (toplevel, offset) in mapped.windows() {
|
||||||
let window_geo_offset = toplevel.geometry().loc;
|
if let CosmicSurface::Wayland(toplevel) = toplevel {
|
||||||
update_reactive_popups(
|
let window_geo_offset = toplevel.geometry().loc;
|
||||||
&toplevel,
|
update_reactive_popups(
|
||||||
element_loc + offset + window_geo_offset,
|
&toplevel,
|
||||||
self.outputs.iter(),
|
element_loc + offset + window_geo_offset,
|
||||||
);
|
self.outputs.iter(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,19 @@ use indexmap::IndexSet;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{surface::WaylandSurfaceRenderElement, AsRenderElements, Element, RenderElement},
|
element::{surface::WaylandSurfaceRenderElement, AsRenderElements, Element, RenderElement},
|
||||||
ImportAll, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, LayerSurface, Window},
|
desktop::{layer_map_for_output, space::SpaceElement, LayerSurface},
|
||||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge},
|
wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
wayland_server::protocol::wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
utils::{Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial},
|
utils::{
|
||||||
wayland::shell::wlr_layer::Layer,
|
Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size,
|
||||||
|
},
|
||||||
|
wayland::{seat::WaylandFocus, shell::wlr_layer::Layer},
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -37,7 +39,7 @@ use super::{
|
||||||
element::CosmicMapped,
|
element::CosmicMapped,
|
||||||
focus::{FocusStack, FocusStackMut},
|
focus::{FocusStack, FocusStackMut},
|
||||||
grabs::ResizeGrab,
|
grabs::ResizeGrab,
|
||||||
CosmicMappedRenderElement,
|
CosmicMappedRenderElement, CosmicSurface,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -45,7 +47,7 @@ pub struct Workspace {
|
||||||
pub tiling_layer: TilingLayout,
|
pub tiling_layer: TilingLayout,
|
||||||
pub floating_layer: FloatingLayout,
|
pub floating_layer: FloatingLayout,
|
||||||
pub tiling_enabled: bool,
|
pub tiling_enabled: bool,
|
||||||
pub fullscreen: HashMap<Output, Window>,
|
pub fullscreen: HashMap<Output, CosmicSurface>,
|
||||||
pub handle: WorkspaceHandle,
|
pub handle: WorkspaceHandle,
|
||||||
pub focus_stack: FocusStacks,
|
pub focus_stack: FocusStacks,
|
||||||
pub pending_buffers: Vec<(ScreencopySession, BufferParams)>,
|
pub pending_buffers: Vec<(ScreencopySession, BufferParams)>,
|
||||||
|
|
@ -85,7 +87,7 @@ impl Workspace {
|
||||||
if let Some(mapped) = self.element_for_surface(surface) {
|
if let Some(mapped) = self.element_for_surface(surface) {
|
||||||
mapped
|
mapped
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.toplevel().wl_surface() == surface)
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.0
|
.0
|
||||||
.on_commit();
|
.on_commit();
|
||||||
|
|
@ -131,7 +133,7 @@ impl Workspace {
|
||||||
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
||||||
.find(|e| {
|
.find(|e| {
|
||||||
e.windows()
|
e.windows()
|
||||||
.any(|(w, _)| w.toplevel().wl_surface() == surface)
|
.any(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,41 +192,37 @@ impl Workspace {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maximize_request(&mut self, window: &Window, output: &Output) {
|
pub fn maximize_request(&mut self, window: &CosmicSurface, output: &Output) {
|
||||||
if self.fullscreen.contains_key(output) {
|
if self.fullscreen.contains_key(output) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.floating_layer.maximize_request(window);
|
self.floating_layer.maximize_request(window);
|
||||||
|
|
||||||
window.toplevel().with_pending_state(|state| {
|
window.set_fullscreen(false);
|
||||||
state.states.set(xdg_toplevel::State::Maximized);
|
window.set_maximized(true);
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.set_fullscreen(window, output)
|
self.set_fullscreen(window, output)
|
||||||
}
|
}
|
||||||
pub fn unmaximize_request(&mut self, window: &Window) {
|
pub fn unmaximize_request(&mut self, window: &CosmicSurface) -> Option<Size<i32, Logical>> {
|
||||||
if self.fullscreen.values().any(|w| w == window) {
|
if self.fullscreen.values().any(|w| w == window) {
|
||||||
self.unfullscreen_request(window);
|
self.unfullscreen_request(window);
|
||||||
self.floating_layer.unmaximize_request(window);
|
self.floating_layer.unmaximize_request(window)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fullscreen_request(&mut self, window: &Window, output: &Output) {
|
pub fn fullscreen_request(&mut self, window: &CosmicSurface, output: &Output) {
|
||||||
if self.fullscreen.contains_key(output) {
|
if self.fullscreen.contains_key(output) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.toplevel().with_pending_state(|state| {
|
window.set_maximized(false);
|
||||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
window.set_fullscreen(true);
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.set_fullscreen(window, output)
|
self.set_fullscreen(window, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fullscreen(&mut self, window: &Window, output: &Output) {
|
fn set_fullscreen(&mut self, window: &CosmicSurface, output: &Output) {
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.mapped()
|
.mapped()
|
||||||
.find(|m| m.windows().any(|(w, _)| &w == window))
|
.find(|m| m.windows().any(|(w, _)| &w == window))
|
||||||
|
|
@ -232,46 +230,39 @@ impl Workspace {
|
||||||
mapped.set_active(window);
|
mapped.set_active(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
let xdg = window.toplevel();
|
window.set_size(
|
||||||
xdg.with_pending_state(|state| {
|
output
|
||||||
state.size = Some(
|
.current_mode()
|
||||||
output
|
.map(|m| m.size)
|
||||||
.current_mode()
|
.unwrap_or((0, 0).into())
|
||||||
.map(|m| m.size)
|
.to_f64()
|
||||||
.unwrap_or((0, 0).into())
|
.to_logical(output.current_scale().fractional_scale())
|
||||||
.to_f64()
|
.to_i32_round(),
|
||||||
.to_logical(output.current_scale().fractional_scale())
|
);
|
||||||
.to_i32_round(),
|
window.send_configure();
|
||||||
);
|
|
||||||
});
|
|
||||||
xdg.send_configure();
|
|
||||||
self.fullscreen.insert(output.clone(), window.clone());
|
self.fullscreen.insert(output.clone(), window.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unfullscreen_request(&mut self, window: &Window) {
|
pub fn unfullscreen_request(&mut self, window: &CosmicSurface) {
|
||||||
if self.fullscreen.values().any(|w| w == window) {
|
if self.fullscreen.values().any(|w| w == window) {
|
||||||
let xdg = window.toplevel();
|
window.set_maximized(false);
|
||||||
xdg.with_pending_state(|state| {
|
window.set_fullscreen(false);
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
|
||||||
state.size = None;
|
|
||||||
});
|
|
||||||
self.floating_layer.refresh();
|
self.floating_layer.refresh();
|
||||||
self.tiling_layer.refresh();
|
self.tiling_layer.refresh();
|
||||||
xdg.send_configure();
|
window.send_configure();
|
||||||
self.fullscreen.retain(|_, w| w != window);
|
self.fullscreen.retain(|_, w| w != window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maximize_toggle(&mut self, window: &Window, output: &Output) {
|
pub fn maximize_toggle(&mut self, window: &CosmicSurface, output: &Output) {
|
||||||
if self.fullscreen.contains_key(output) {
|
if self.fullscreen.contains_key(output) {
|
||||||
self.unmaximize_request(window)
|
self.unmaximize_request(window);
|
||||||
} else {
|
} else {
|
||||||
self.maximize_request(window, output)
|
self.maximize_request(window, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fullscreen(&self, output: &Output) -> Option<&Window> {
|
pub fn get_fullscreen(&self, output: &Output) -> Option<&CosmicSurface> {
|
||||||
self.fullscreen.get(output).filter(|w| w.alive())
|
self.fullscreen.get(output).filter(|w| w.alive())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,7 +294,7 @@ impl Workspace {
|
||||||
|
|
||||||
pub fn move_request(
|
pub fn move_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
window: &Window,
|
window: &CosmicSurface,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
_serial: Serial,
|
_serial: Serial,
|
||||||
|
|
@ -312,15 +303,12 @@ impl Workspace {
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
let pos = pointer.current_location();
|
let pos = pointer.current_location();
|
||||||
|
|
||||||
let mapped = self
|
let mapped = self.element_for_surface(&window.wl_surface()?)?.clone();
|
||||||
.element_for_surface(window.toplevel().wl_surface())?
|
|
||||||
.clone();
|
|
||||||
let mut initial_window_location = self.element_geometry(&mapped).unwrap().loc;
|
let mut initial_window_location = self.element_geometry(&mapped).unwrap().loc;
|
||||||
|
|
||||||
if mapped.is_fullscreen() || mapped.is_maximized() {
|
if mapped.is_fullscreen() || mapped.is_maximized() {
|
||||||
// If surface is maximized then unmaximize it
|
// If surface is maximized then unmaximize it
|
||||||
self.unmaximize_request(window);
|
let new_size = self.unmaximize_request(window);
|
||||||
let new_size = window.toplevel().with_pending_state(|state| state.size);
|
|
||||||
let ratio = pos.x / output.geometry().size.w as f64;
|
let ratio = pos.x / output.geometry().size.w as f64;
|
||||||
|
|
||||||
initial_window_location = new_size
|
initial_window_location = new_size
|
||||||
|
|
@ -396,7 +384,7 @@ impl Workspace {
|
||||||
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn windows(&self) -> impl Iterator<Item = Window> + '_ {
|
pub fn windows(&self) -> impl Iterator<Item = CosmicSurface> + '_ {
|
||||||
self.floating_layer
|
self.floating_layer
|
||||||
.windows()
|
.windows()
|
||||||
.chain(self.tiling_layer.windows().map(|(_, w, _)| w))
|
.chain(self.tiling_layer.windows().map(|(_, w, _)| w))
|
||||||
|
|
@ -408,7 +396,7 @@ impl Workspace {
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
|
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -534,7 +522,7 @@ pub struct OutputNotMapped;
|
||||||
|
|
||||||
pub enum WorkspaceRenderElement<R>
|
pub enum WorkspaceRenderElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
{
|
{
|
||||||
Wayland(WaylandSurfaceRenderElement<R>),
|
Wayland(WaylandSurfaceRenderElement<R>),
|
||||||
|
|
@ -543,7 +531,7 @@ where
|
||||||
|
|
||||||
impl<R> Element for WorkspaceRenderElement<R>
|
impl<R> Element for WorkspaceRenderElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
{
|
{
|
||||||
fn id(&self) -> &smithay::backend::renderer::element::Id {
|
fn id(&self) -> &smithay::backend::renderer::element::Id {
|
||||||
|
|
@ -609,7 +597,7 @@ where
|
||||||
|
|
||||||
impl<R> RenderElement<R> for WorkspaceRenderElement<R>
|
impl<R> RenderElement<R> for WorkspaceRenderElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -640,7 +628,7 @@ where
|
||||||
|
|
||||||
impl<R> From<WaylandSurfaceRenderElement<R>> for WorkspaceRenderElement<R>
|
impl<R> From<WaylandSurfaceRenderElement<R>> for WorkspaceRenderElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
@ -651,7 +639,7 @@ where
|
||||||
|
|
||||||
impl<R> From<CosmicMappedRenderElement<R>> for WorkspaceRenderElement<R>
|
impl<R> From<CosmicMappedRenderElement<R>> for WorkspaceRenderElement<R>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,31 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
fmt,
|
fmt,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
sync::{mpsc::Receiver, Arc, Mutex},
|
sync::{mpsc::Receiver, Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cosmic::iced_native::{
|
|
||||||
command::Action,
|
|
||||||
event::Event,
|
|
||||||
keyboard::{Event as KeyboardEvent, Modifiers as IcedModifiers},
|
|
||||||
mouse::{Button as MouseButton, Event as MouseEvent, ScrollDelta},
|
|
||||||
program::{Program, State},
|
|
||||||
renderer::Style,
|
|
||||||
window::{Event as WindowEvent, Id},
|
|
||||||
Debug, Point as IcedPoint, Size as IcedSize,
|
|
||||||
};
|
|
||||||
pub use cosmic::Renderer as IcedRenderer;
|
pub use cosmic::Renderer as IcedRenderer;
|
||||||
use cosmic::Theme;
|
use cosmic::Theme;
|
||||||
use iced_swbuf::{native::*, Backend};
|
use cosmic::{
|
||||||
|
iced_native::{
|
||||||
|
command::Action,
|
||||||
|
event::Event,
|
||||||
|
keyboard::{Event as KeyboardEvent, Modifiers as IcedModifiers},
|
||||||
|
mouse::{Button as MouseButton, Event as MouseEvent, ScrollDelta},
|
||||||
|
program::{Program as IcedProgram, State},
|
||||||
|
renderer::Style,
|
||||||
|
window::{Event as WindowEvent, Id},
|
||||||
|
Command, Debug, Point as IcedPoint, Size as IcedSize,
|
||||||
|
},
|
||||||
|
Element,
|
||||||
|
};
|
||||||
|
use iced_softbuffer::{
|
||||||
|
native::{raqote::DrawTarget, *},
|
||||||
|
Backend,
|
||||||
|
};
|
||||||
|
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
input::{ButtonState, KeyState},
|
input::{ButtonState, KeyState},
|
||||||
|
|
@ -41,30 +50,64 @@ use smithay::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IcedElement<P: Program<Renderer = IcedRenderer> + Send + 'static>(
|
pub struct IcedElement<P: Program + Send + 'static>(Arc<Mutex<IcedElementInternal<P>>>);
|
||||||
Arc<Mutex<IcedElementInternal<P>>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
// SAFETY: We cannot really be sure about `iced_native::program::State` sadly,
|
// SAFETY: We cannot really be sure about `iced_native::program::State` sadly,
|
||||||
// but the rest should be fine.
|
// but the rest should be fine.
|
||||||
unsafe impl<P: Program<Renderer = IcedRenderer> + Send + 'static> Send for IcedElementInternal<P> {}
|
unsafe impl<P: Program + Send + 'static> Send for IcedElementInternal<P> {}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> Clone for IcedElement<P> {
|
impl<P: Program + Send + 'static> Clone for IcedElement<P> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
IcedElement(self.0.clone())
|
IcedElement(self.0.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> PartialEq for IcedElement<P> {
|
impl<P: Program + Send + 'static> PartialEq for IcedElement<P> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
Arc::ptr_eq(&self.0, &other.0)
|
Arc::ptr_eq(&self.0, &other.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<P: Program + Send + 'static> Eq for IcedElement<P> {}
|
||||||
|
|
||||||
struct IcedElementInternal<P: Program<Renderer = IcedRenderer> + Send + 'static> {
|
impl<P: Program + Send + 'static> Hash for IcedElement<P> {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
(Arc::as_ptr(&self.0) as usize).hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Program {
|
||||||
|
type Message: std::fmt::Debug + Send;
|
||||||
|
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
||||||
|
let _ = message;
|
||||||
|
Command::none()
|
||||||
|
}
|
||||||
|
fn view(&self) -> Element<'_, Self::Message>;
|
||||||
|
|
||||||
|
fn background(&self, target: &mut DrawTarget<&mut [u32]>) {
|
||||||
|
let _ = target;
|
||||||
|
}
|
||||||
|
fn foreground(&self, target: &mut DrawTarget<&mut [u32]>) {
|
||||||
|
let _ = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProgramWrapper<P: Program>(P);
|
||||||
|
impl<P: Program> IcedProgram for ProgramWrapper<P> {
|
||||||
|
type Message = <P as Program>::Message;
|
||||||
|
type Renderer = IcedRenderer;
|
||||||
|
|
||||||
|
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
||||||
|
self.0.update(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
|
self.0.view()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IcedElementInternal<P: Program + Send + 'static> {
|
||||||
// draw buffer
|
// draw buffer
|
||||||
memory: MemoryRenderBuffer,
|
buffers: HashMap<OrderedFloat<f64>, (MemoryRenderBuffer, bool)>,
|
||||||
needs_redraw: bool,
|
|
||||||
|
|
||||||
// state
|
// state
|
||||||
size: Size<i32, Logical>,
|
size: Size<i32, Logical>,
|
||||||
|
|
@ -73,7 +116,7 @@ struct IcedElementInternal<P: Program<Renderer = IcedRenderer> + Send + 'static>
|
||||||
// iced
|
// iced
|
||||||
theme: Theme,
|
theme: Theme,
|
||||||
renderer: IcedRenderer,
|
renderer: IcedRenderer,
|
||||||
state: State<P>,
|
state: State<ProgramWrapper<P>>,
|
||||||
debug: Debug,
|
debug: Debug,
|
||||||
|
|
||||||
// futures
|
// futures
|
||||||
|
|
@ -83,53 +126,57 @@ struct IcedElementInternal<P: Program<Renderer = IcedRenderer> + Send + 'static>
|
||||||
rx: Receiver<<P as Program>::Message>,
|
rx: Receiver<<P as Program>::Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> fmt::Debug for IcedElementInternal<P> {
|
impl<P: Program + Send + 'static> fmt::Debug for IcedElementInternal<P> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("IcedElementInternal")
|
f.debug_struct("IcedElementInternal")
|
||||||
.field("memory", &self.memory)
|
.field("buffers", &"...")
|
||||||
.field("needs_redraw", &self.needs_redraw)
|
|
||||||
.field("size", &self.size)
|
.field("size", &self.size)
|
||||||
.field("cursor_pos", &self.cursor_pos)
|
.field("cursor_pos", &self.cursor_pos)
|
||||||
.field("theme", &self.theme)
|
.field("theme", &self.theme)
|
||||||
.finish_non_exhaustive()
|
.field("renderer", &"...")
|
||||||
|
.field("state", &"...")
|
||||||
|
.field("debug", &self.debug)
|
||||||
|
.field("handle", &self.handle)
|
||||||
|
.field("scheduler", &self.scheduler)
|
||||||
|
.field("executor_token", &self.executor_token)
|
||||||
|
.field("rx", &self.rx)
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> Drop for IcedElementInternal<P> {
|
impl<P: Program + Send + 'static> Drop for IcedElementInternal<P> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.handle.remove(self.executor_token.take().unwrap());
|
self.handle.remove(self.executor_token.take().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> IcedElement<P> {
|
impl<P: Program + Send + 'static> IcedElement<P> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
program: P,
|
program: P,
|
||||||
size: impl Into<Size<i32, Logical>>,
|
size: impl Into<Size<i32, Logical>>,
|
||||||
scale: i32,
|
|
||||||
handle: LoopHandle<'static, crate::state::Data>,
|
handle: LoopHandle<'static, crate::state::Data>,
|
||||||
) -> calloop::error::Result<IcedElement<P>> {
|
) -> IcedElement<P> {
|
||||||
let size = size.into();
|
let size = size.into();
|
||||||
let buffer_size = size.to_buffer(scale, Transform::Normal);
|
|
||||||
|
|
||||||
let mut renderer = IcedRenderer::new(Backend::new());
|
let mut renderer = IcedRenderer::new(Backend::new());
|
||||||
let mut debug = Debug::new();
|
let mut debug = Debug::new();
|
||||||
|
|
||||||
let state = State::new(
|
let state = State::new(
|
||||||
program,
|
ProgramWrapper(program),
|
||||||
IcedSize::new(size.w as f32, size.h as f32),
|
IcedSize::new(size.w as f32, size.h as f32),
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&mut debug,
|
&mut debug,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (executor, scheduler) = calloop::futures::executor()?;
|
let (executor, scheduler) = calloop::futures::executor().expect("Out of file descriptors");
|
||||||
let (tx, rx) = std::sync::mpsc::channel();
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
let executor_token = handle.insert_source(executor, |message, _, _| {
|
let executor_token = handle
|
||||||
tx.send(message);
|
.insert_source(executor, move |message, _, _| {
|
||||||
})?;
|
let _ = tx.send(message);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
let mut internal = IcedElementInternal {
|
let mut internal = IcedElementInternal {
|
||||||
memory: MemoryRenderBuffer::new(buffer_size, scale, Transform::Normal, None),
|
buffers: HashMap::new(),
|
||||||
needs_redraw: true,
|
|
||||||
size,
|
size,
|
||||||
cursor_pos: None,
|
cursor_pos: None,
|
||||||
theme: Theme::Dark, // TODO
|
theme: Theme::Dark, // TODO
|
||||||
|
|
@ -138,16 +185,41 @@ impl<P: Program<Renderer = IcedRenderer> + Send + 'static> IcedElement<P> {
|
||||||
debug,
|
debug,
|
||||||
handle,
|
handle,
|
||||||
scheduler,
|
scheduler,
|
||||||
executor_token: Some(executor_token),
|
executor_token,
|
||||||
rx,
|
rx,
|
||||||
};
|
};
|
||||||
let _ = internal.update(true);
|
let _ = internal.update(true);
|
||||||
|
|
||||||
Ok(IcedElement(Arc::new(Mutex::new(internal))))
|
IcedElement(Arc::new(Mutex::new(internal)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_program<R>(&self, func: impl FnOnce(&P) -> R) -> R {
|
||||||
|
let internal = self.0.lock().unwrap();
|
||||||
|
func(&internal.state.program().0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> {
|
||||||
|
self.0.lock().unwrap().handle.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(&self, size: Size<i32, Logical>) {
|
||||||
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
let internal_ref = &mut *internal;
|
||||||
|
internal_ref.size = size;
|
||||||
|
for (scale, (buffer, needs_redraw)) in internal_ref.buffers.iter_mut() {
|
||||||
|
let buffer_size = internal_ref
|
||||||
|
.size
|
||||||
|
.to_f64()
|
||||||
|
.to_buffer(**scale, Transform::Normal)
|
||||||
|
.to_i32_round();
|
||||||
|
*buffer = MemoryRenderBuffer::new(buffer_size, 1, Transform::Normal, None);
|
||||||
|
*needs_redraw = true;
|
||||||
|
}
|
||||||
|
let _ = internal_ref.update(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> IcedElementInternal<P> {
|
impl<P: Program + Send + 'static> IcedElementInternal<P> {
|
||||||
fn update(&mut self, mut force: bool) -> Vec<Action<<P as Program>::Message>> {
|
fn update(&mut self, mut force: bool) -> Vec<Action<<P as Program>::Message>> {
|
||||||
let cursor_pos = self.cursor_pos.unwrap_or(Point::from((-1.0, -1.0)));
|
let cursor_pos = self.cursor_pos.unwrap_or(Point::from((-1.0, -1.0)));
|
||||||
|
|
||||||
|
|
@ -177,7 +249,9 @@ impl<P: Program<Renderer = IcedRenderer> + Send + 'static> IcedElementInternal<P
|
||||||
.map(|command| command.actions());
|
.map(|command| command.actions());
|
||||||
|
|
||||||
if actions.is_some() {
|
if actions.is_some() {
|
||||||
self.needs_redraw = true;
|
for (_buffer, ref mut needs_redraw) in self.buffers.values_mut() {
|
||||||
|
*needs_redraw = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let actions = actions.unwrap_or_default();
|
let actions = actions.unwrap_or_default();
|
||||||
actions
|
actions
|
||||||
|
|
@ -194,9 +268,7 @@ impl<P: Program<Renderer = IcedRenderer> + Send + 'static> IcedElementInternal<P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> PointerTarget<crate::state::State>
|
impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedElement<P> {
|
||||||
for IcedElement<P>
|
|
||||||
{
|
|
||||||
fn enter(
|
fn enter(
|
||||||
&self,
|
&self,
|
||||||
_seat: &Seat<crate::state::State>,
|
_seat: &Seat<crate::state::State>,
|
||||||
|
|
@ -290,9 +362,7 @@ impl<P: Program<Renderer = IcedRenderer> + Send + 'static> PointerTarget<crate::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> KeyboardTarget<crate::state::State>
|
impl<P: Program + Send + 'static> KeyboardTarget<crate::state::State> for IcedElement<P> {
|
||||||
for IcedElement<P>
|
|
||||||
{
|
|
||||||
fn enter(
|
fn enter(
|
||||||
&self,
|
&self,
|
||||||
_seat: &Seat<crate::state::State>,
|
_seat: &Seat<crate::state::State>,
|
||||||
|
|
@ -352,13 +422,13 @@ impl<P: Program<Renderer = IcedRenderer> + Send + 'static> KeyboardTarget<crate:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> IsAlive for IcedElement<P> {
|
impl<P: Program + Send + 'static> IsAlive for IcedElement<P> {
|
||||||
fn alive(&self) -> bool {
|
fn alive(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Program<Renderer = IcedRenderer> + Send + 'static> SpaceElement for IcedElement<P> {
|
impl<P: Program + Send + 'static> SpaceElement for IcedElement<P> {
|
||||||
fn bbox(&self) -> Rectangle<i32, Logical> {
|
fn bbox(&self) -> Rectangle<i32, Logical> {
|
||||||
Rectangle::from_loc_and_size((0, 0), self.0.lock().unwrap().size)
|
Rectangle::from_loc_and_size((0, 0), self.0.lock().unwrap().size)
|
||||||
}
|
}
|
||||||
|
|
@ -380,12 +450,29 @@ impl<P: Program<Renderer = IcedRenderer> + Send + 'static> SpaceElement for Iced
|
||||||
let _ = internal.update(true); // TODO
|
let _ = internal.update(true); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_enter(&self, _output: &Output, _overlap: Rectangle<i32, Logical>) {
|
fn output_enter(&self, output: &Output, _overlap: Rectangle<i32, Logical>) {
|
||||||
// TODO: Update scale, once supported to the highest one
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
let scale = output.current_scale().fractional_scale();
|
||||||
|
if !internal.buffers.contains_key(&OrderedFloat(scale)) {
|
||||||
|
let buffer_size = internal
|
||||||
|
.size
|
||||||
|
.to_f64()
|
||||||
|
.to_buffer(scale, Transform::Normal)
|
||||||
|
.to_i32_round();
|
||||||
|
internal.buffers.insert(
|
||||||
|
OrderedFloat(scale),
|
||||||
|
(
|
||||||
|
MemoryRenderBuffer::new(buffer_size, 1, Transform::Normal, None),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_leave(&self, _output: &Output) {
|
fn output_leave(&self, output: &Output) {
|
||||||
// TODO: Update scale, once supported to the highest one
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
let scale = output.current_scale().fractional_scale();
|
||||||
|
internal.buffers.remove(&OrderedFloat(scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn z_index(&self) -> u8 {
|
fn z_index(&self) -> u8 {
|
||||||
|
|
@ -398,7 +485,7 @@ impl<P: Program<Renderer = IcedRenderer> + Send + 'static> SpaceElement for Iced
|
||||||
|
|
||||||
impl<P, R> AsRenderElements<R> for IcedElement<P>
|
impl<P, R> AsRenderElements<R> for IcedElement<P>
|
||||||
where
|
where
|
||||||
P: Program<Renderer = IcedRenderer> + Send + 'static,
|
P: Program + Send + 'static,
|
||||||
R: Renderer + ImportMem,
|
R: Renderer + ImportMem,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
{
|
{
|
||||||
|
|
@ -408,69 +495,79 @@ where
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
location: Point<i32, Physical>,
|
location: Point<i32, Physical>,
|
||||||
_scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
) -> Vec<C> {
|
) -> Vec<C> {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
|
||||||
let _ = internal.update(false); // TODO
|
let _ = internal.update(false); // TODO
|
||||||
|
// makes partial borrows easier
|
||||||
// makes partial borrows easier
|
|
||||||
let internal_ref = &mut *internal;
|
let internal_ref = &mut *internal;
|
||||||
if internal_ref.needs_redraw {
|
if let Some((buffer, ref mut needs_redraw)) =
|
||||||
let renderer = &mut internal_ref.renderer;
|
internal_ref.buffers.get_mut(&OrderedFloat(scale.x))
|
||||||
let size = internal_ref.size;
|
{
|
||||||
internal_ref
|
if *needs_redraw {
|
||||||
.memory
|
let renderer = &mut internal_ref.renderer;
|
||||||
.render()
|
let size = internal_ref
|
||||||
.draw(move |buf| {
|
.size
|
||||||
let mut target = raqote::DrawTarget::from_backing(
|
.to_f64()
|
||||||
size.w,
|
.to_buffer(scale.x, Transform::Normal)
|
||||||
size.h,
|
.to_i32_round();
|
||||||
bytemuck::cast_slice_mut::<_, u32>(buf),
|
let state_ref = &internal_ref.state;
|
||||||
);
|
buffer
|
||||||
|
.render()
|
||||||
|
.draw(move |buf| {
|
||||||
|
let mut target = raqote::DrawTarget::from_backing(
|
||||||
|
size.w,
|
||||||
|
size.h,
|
||||||
|
bytemuck::cast_slice_mut::<_, u32>(buf),
|
||||||
|
);
|
||||||
|
|
||||||
target.clear(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0));
|
target.clear(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0));
|
||||||
|
state_ref.program().0.background(&mut target);
|
||||||
|
|
||||||
let draw_options = raqote::DrawOptions {
|
let draw_options = raqote::DrawOptions {
|
||||||
// Default to antialiasing off for now
|
// Default to antialiasing off for now
|
||||||
antialias: raqote::AntialiasMode::None,
|
antialias: raqote::AntialiasMode::None,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Having at least one clip fixes some font rendering issues
|
// Having at least one clip fixes some font rendering issues
|
||||||
target.push_clip_rect(raqote::IntRect::new(
|
target.push_clip_rect(raqote::IntRect::new(
|
||||||
raqote::IntPoint::new(0, 0),
|
raqote::IntPoint::new(0, 0),
|
||||||
raqote::IntPoint::new(size.w, size.h),
|
raqote::IntPoint::new(size.w, size.h),
|
||||||
));
|
));
|
||||||
|
|
||||||
renderer.with_primitives(|backend, primitives| {
|
renderer.with_primitives(|backend, primitives| {
|
||||||
for primitive in primitives.iter() {
|
for primitive in primitives.iter() {
|
||||||
draw_primitive(&mut target, &draw_options, backend, primitive);
|
draw_primitive(
|
||||||
}
|
&mut target,
|
||||||
});
|
&draw_options,
|
||||||
|
backend,
|
||||||
|
scale.x as f32,
|
||||||
|
primitive,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
target.pop_clip();
|
state_ref.program().0.foreground(&mut target);
|
||||||
|
Result::<_, ()>::Ok(vec![Rectangle::from_loc_and_size((0, 0), size)])
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
*needs_redraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
Result::<_, ()>::Ok(vec![Rectangle::from_loc_and_size(
|
if let Ok(buffer) = MemoryRenderBufferRenderElement::from_buffer(
|
||||||
(0, 0),
|
renderer,
|
||||||
size.to_buffer(1, Transform::Normal),
|
location.to_f64(),
|
||||||
)])
|
&buffer,
|
||||||
})
|
None,
|
||||||
.unwrap();
|
None,
|
||||||
internal_ref.needs_redraw = false;
|
None,
|
||||||
|
slog_scope::logger(),
|
||||||
|
) {
|
||||||
|
return vec![C::from(buffer)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Vec::new()
|
||||||
let Ok(buffer) = MemoryRenderBufferRenderElement::from_buffer(
|
|
||||||
renderer,
|
|
||||||
location.to_f64(),
|
|
||||||
&internal.memory,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
slog_scope::logger(),
|
|
||||||
) else {
|
|
||||||
return Vec::new()
|
|
||||||
};
|
|
||||||
vec![C::from(buffer)]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{state::BackendData, utils::prelude::*, wayland::protocols::screencopy::SessionType};
|
use crate::{
|
||||||
|
shell::CosmicSurface, state::BackendData, utils::prelude::*,
|
||||||
|
wayland::protocols::screencopy::SessionType,
|
||||||
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state},
|
backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state},
|
||||||
delegate_compositor,
|
delegate_compositor,
|
||||||
|
|
@ -8,6 +11,7 @@ use smithay::{
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{with_states, CompositorHandler, CompositorState},
|
compositor::{with_states, CompositorHandler, CompositorState},
|
||||||
|
seat::WaylandFocus,
|
||||||
shell::{
|
shell::{
|
||||||
wlr_layer::LayerSurfaceAttributes,
|
wlr_layer::LayerSurfaceAttributes,
|
||||||
xdg::{
|
xdg::{
|
||||||
|
|
@ -113,17 +117,28 @@ impl CompositorHandler for State {
|
||||||
.shell
|
.shell
|
||||||
.pending_windows
|
.pending_windows
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(window, _)| window.toplevel().wl_surface() == surface)
|
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
let toplevel = window.toplevel();
|
match window {
|
||||||
if self.toplevel_ensure_initial_configure(&toplevel)
|
CosmicSurface::Wayland(ref wl_window) => {
|
||||||
&& with_renderer_surface_state(&surface, |state| state.wl_buffer().is_some())
|
let toplevel = wl_window.toplevel();
|
||||||
{
|
if self.toplevel_ensure_initial_configure(&toplevel)
|
||||||
let output = seat.active_output();
|
&& with_renderer_surface_state(&surface, |state| {
|
||||||
Shell::map_window(self, &window, &output);
|
state.wl_buffer().is_some()
|
||||||
} else {
|
})
|
||||||
return;
|
{
|
||||||
|
let output = seat.active_output();
|
||||||
|
Shell::map_window(self, &window, &output);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CosmicSurface::X11(_) => {
|
||||||
|
let output = seat.active_output();
|
||||||
|
Shell::map_window(self, &window, &output);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ use smithay::{
|
||||||
Bind, Blit, BufferType, ExportMem, ImportAll, ImportMem, Offscreen, Renderer,
|
Bind, Blit, BufferType, ExportMem, ImportAll, ImportMem, Offscreen, Renderer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::Window,
|
desktop::space::SpaceElement,
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_server::{
|
reexports::wayland_server::{
|
||||||
protocol::{wl_buffer::WlBuffer, wl_shm::Format as ShmFormat, wl_surface::WlSurface},
|
protocol::{wl_buffer::WlBuffer, wl_shm::Format as ShmFormat, wl_surface::WlSurface},
|
||||||
|
|
@ -33,6 +33,7 @@ use smithay::{
|
||||||
utils::{IsAlive, Logical, Physical, Rectangle, Scale, Transform},
|
utils::{IsAlive, Logical, Physical, Rectangle, Scale, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::get_dmabuf,
|
dmabuf::get_dmabuf,
|
||||||
|
seat::WaylandFocus,
|
||||||
shm::{with_buffer_contents, with_buffer_contents_mut},
|
shm::{with_buffer_contents, with_buffer_contents_mut},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -43,7 +44,7 @@ use crate::{
|
||||||
element::{AsGlowRenderer, CosmicElement},
|
element::{AsGlowRenderer, CosmicElement},
|
||||||
render_output, render_workspace, CursorMode, CLEAR_COLOR,
|
render_output, render_workspace, CursorMode, CLEAR_COLOR,
|
||||||
},
|
},
|
||||||
shell::CosmicMappedRenderElement,
|
shell::{CosmicMappedRenderElement, CosmicSurface},
|
||||||
state::{BackendData, ClientState, Common, State},
|
state::{BackendData, ClientState, Common, State},
|
||||||
utils::prelude::OutputExt,
|
utils::prelude::OutputExt,
|
||||||
wayland::protocols::{
|
wayland::protocols::{
|
||||||
|
|
@ -159,8 +160,8 @@ impl ScreencopyHandler for State {
|
||||||
formats
|
formats
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capture_toplevel(&mut self, toplevel: Window, session: Session) -> Vec<BufferInfo> {
|
fn capture_toplevel(&mut self, toplevel: CosmicSurface, session: Session) -> Vec<BufferInfo> {
|
||||||
let surface = toplevel.toplevel().wl_surface();
|
let Some(surface) = toplevel.wl_surface() else { return Vec::new() };
|
||||||
let size = toplevel.geometry().size.to_buffer(1, Transform::Normal);
|
let size = toplevel.geometry().size.to_buffer(1, Transform::Normal);
|
||||||
|
|
||||||
let mut _kms_renderer = None;
|
let mut _kms_renderer = None;
|
||||||
|
|
@ -843,7 +844,7 @@ pub fn render_window_to_buffer(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
session: &Session,
|
session: &Session,
|
||||||
params: BufferParams,
|
params: BufferParams,
|
||||||
window: &Window,
|
window: &CosmicSurface,
|
||||||
) -> Result<bool, (FailureReason, anyhow::Error)> {
|
) -> Result<bool, (FailureReason, anyhow::Error)> {
|
||||||
let geometry = window.geometry();
|
let geometry = window.geometry();
|
||||||
let buffer_size = buffer_dimensions(¶ms.buffer).unwrap();
|
let buffer_size = buffer_dimensions(¶ms.buffer).unwrap();
|
||||||
|
|
@ -858,7 +859,7 @@ pub fn render_window_to_buffer(
|
||||||
age: usize,
|
age: usize,
|
||||||
session: &Session,
|
session: &Session,
|
||||||
common: &mut Common,
|
common: &mut Common,
|
||||||
window: &Window,
|
window: &CosmicSurface,
|
||||||
geometry: Rectangle<i32, Logical>,
|
geometry: Rectangle<i32, Logical>,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates),
|
(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates),
|
||||||
|
|
@ -889,12 +890,12 @@ pub fn render_window_to_buffer(
|
||||||
for seat in common.seats() {
|
for seat in common.seats() {
|
||||||
if let Some(location) = {
|
if let Some(location) = {
|
||||||
// we need to find the mapped element in that case
|
// we need to find the mapped element in that case
|
||||||
if let Some(mapped) = common
|
if let Some(mapped) = window
|
||||||
.shell
|
.wl_surface()
|
||||||
.element_for_surface(window.toplevel().wl_surface())
|
.and_then(|surf| common.shell.element_for_surface(&surf))
|
||||||
{
|
{
|
||||||
mapped.cursor_position(seat).and_then(|mut p| {
|
mapped.cursor_position(seat).and_then(|mut p| {
|
||||||
p -= mapped.active_window_offset().loc.to_f64();
|
p -= mapped.active_window_offset().to_f64();
|
||||||
if p.x < 0. || p.y < 0. {
|
if p.x < 0. || p.y < 0. {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1076,7 +1077,7 @@ impl UserdataExt for Output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserdataExt for Window {
|
impl UserdataExt for CosmicSurface {
|
||||||
fn sessions(&self) -> Vec<Session> {
|
fn sessions(&self) -> Vec<Session> {
|
||||||
self.user_data()
|
self.user_data()
|
||||||
.get::<ScreencopySessions>()
|
.get::<ScreencopySessions>()
|
||||||
|
|
@ -1101,7 +1102,7 @@ impl State {
|
||||||
pub fn schedule_window_session(&mut self, surface: &WlSurface) {
|
pub fn schedule_window_session(&mut self, surface: &WlSurface) {
|
||||||
if let Some(element) = self.common.shell.element_for_surface(surface).cloned() {
|
if let Some(element) = self.common.shell.element_for_surface(surface).cloned() {
|
||||||
let active = element.active_window();
|
let active = element.active_window();
|
||||||
if active.toplevel().wl_surface() == surface {
|
if active.wl_surface().as_ref() == Some(surface) {
|
||||||
for (session, params) in active.pending_buffers() {
|
for (session, params) in active.pending_buffers() {
|
||||||
let window = active.clone();
|
let window = active.clone();
|
||||||
self.common.event_loop_handle.insert_idle(move |data| {
|
self.common.event_loop_handle.insert_idle(move |data| {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,54 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use smithay::utils::user_data::UserDataMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
shell::CosmicSurface,
|
||||||
state::State,
|
state::State,
|
||||||
wayland::protocols::toplevel_info::{
|
wayland::protocols::toplevel_info::{
|
||||||
delegate_toplevel_info, ToplevelInfoHandler, ToplevelInfoState,
|
delegate_toplevel_info, ToplevelInfoHandler, ToplevelInfoState, Window,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl ToplevelInfoHandler for State {
|
impl ToplevelInfoHandler for State {
|
||||||
fn toplevel_info_state(&self) -> &ToplevelInfoState<State> {
|
type Window = CosmicSurface;
|
||||||
|
|
||||||
|
fn toplevel_info_state(&self) -> &ToplevelInfoState<State, Self::Window> {
|
||||||
&self.common.shell.toplevel_info_state
|
&self.common.shell.toplevel_info_state
|
||||||
}
|
}
|
||||||
fn toplevel_info_state_mut(&mut self) -> &mut ToplevelInfoState<State> {
|
fn toplevel_info_state_mut(&mut self) -> &mut ToplevelInfoState<State, Self::Window> {
|
||||||
&mut self.common.shell.toplevel_info_state
|
&mut self.common.shell.toplevel_info_state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate_toplevel_info!(State);
|
impl Window for CosmicSurface {
|
||||||
|
fn title(&self) -> String {
|
||||||
|
CosmicSurface::title(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app_id(&self) -> String {
|
||||||
|
CosmicSurface::app_id(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_activated(&self) -> bool {
|
||||||
|
CosmicSurface::is_activated(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_maximized(&self) -> bool {
|
||||||
|
CosmicSurface::is_maximized(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_fullscreen(&self) -> bool {
|
||||||
|
CosmicSurface::is_fullscreen(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_minimized(&self) -> bool {
|
||||||
|
false // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_data(&self) -> &UserDataMap {
|
||||||
|
CosmicSurface::user_data(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate_toplevel_info!(State, CosmicSurface);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,16 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use smithay::{desktop::Window, input::Seat, reexports::wayland_server::DisplayHandle};
|
use smithay::{input::Seat, reexports::wayland_server::DisplayHandle};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
shell::CosmicSurface,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::protocols::toplevel_management::{
|
wayland::protocols::{
|
||||||
delegate_toplevel_management, ToplevelManagementHandler, ToplevelManagementState,
|
toplevel_info::ToplevelInfoHandler,
|
||||||
|
toplevel_management::{
|
||||||
|
delegate_toplevel_management, ManagementWindow, ToplevelManagementHandler,
|
||||||
|
ToplevelManagementState,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -14,7 +19,12 @@ impl ToplevelManagementHandler for State {
|
||||||
&mut self.common.shell.toplevel_management_state
|
&mut self.common.shell.toplevel_management_state
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(&mut self, _dh: &DisplayHandle, window: &Window, seat: Option<Seat<Self>>) {
|
fn activate(
|
||||||
|
&mut self,
|
||||||
|
_dh: &DisplayHandle,
|
||||||
|
window: &<Self as ToplevelInfoHandler>::Window,
|
||||||
|
seat: Option<Seat<Self>>,
|
||||||
|
) {
|
||||||
for output in self
|
for output in self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -47,8 +57,14 @@ impl ToplevelManagementHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&mut self, _dh: &DisplayHandle, window: &Window) {
|
fn close(&mut self, _dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
|
||||||
window.toplevel().send_close();
|
window.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ManagementWindow for CosmicSurface {
|
||||||
|
fn close(&self) {
|
||||||
|
CosmicSurface::close(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{utils::prelude::*, wayland::protocols::screencopy::SessionType};
|
use crate::{shell::CosmicSurface, utils::prelude::*, wayland::protocols::screencopy::SessionType};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
delegate_xdg_shell,
|
delegate_xdg_shell,
|
||||||
desktop::{
|
desktop::{
|
||||||
|
|
@ -39,7 +39,7 @@ impl XdgShellHandler for State {
|
||||||
|
|
||||||
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.last_active_seat().clone();
|
||||||
let window = Window::new(surface);
|
let window = CosmicSurface::Wayland(Window::new(surface));
|
||||||
self.common.shell.toplevel_info_state.new_toplevel(&window);
|
self.common.shell.toplevel_info_state.new_toplevel(&window);
|
||||||
self.common.shell.pending_windows.push((window, seat));
|
self.common.shell.pending_windows.push((window, seat));
|
||||||
// We will position the window after the first commit, when we know its size hints
|
// We will position the window after the first commit, when we know its size hints
|
||||||
|
|
@ -149,7 +149,7 @@ impl XdgShellHandler for State {
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let (window, _) = mapped
|
let (window, _) = mapped
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.toplevel() == &surface)
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if let Some(grab) =
|
if let Some(grab) =
|
||||||
workspace.move_request(&window, &seat, &output, serial, start_data)
|
workspace.move_request(&window, &seat, &output, serial, start_data)
|
||||||
|
|
@ -213,7 +213,7 @@ impl XdgShellHandler for State {
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
let (window, _) = mapped
|
let (window, _) = mapped
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.toplevel() == &surface)
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
workspace.maximize_request(&window, &output)
|
workspace.maximize_request(&window, &output)
|
||||||
}
|
}
|
||||||
|
|
@ -230,9 +230,9 @@ impl XdgShellHandler for State {
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
let (window, _) = mapped
|
let (window, _) = mapped
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.toplevel() == &surface)
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
workspace.unmaximize_request(&window)
|
workspace.unmaximize_request(&window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -255,7 +255,7 @@ impl XdgShellHandler for State {
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
let (window, _) = mapped
|
let (window, _) = mapped
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.toplevel() == &surface)
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
workspace.fullscreen_request(&window, &output)
|
workspace.fullscreen_request(&window, &output)
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +272,7 @@ impl XdgShellHandler for State {
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
let (window, _) = mapped
|
let (window, _) = mapped
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.toplevel() == &surface)
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
workspace.unfullscreen_request(&window)
|
workspace.unfullscreen_request(&window)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
use crate::{shell::Shell, utils::prelude::*};
|
use crate::{shell::Shell, utils::prelude::*};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::{
|
desktop::{
|
||||||
layer_map_for_output, LayerSurface, PopupKind, PopupManager, Window, WindowSurfaceType,
|
layer_map_for_output, space::SpaceElement, LayerSurface, PopupKind, PopupManager, Window,
|
||||||
|
WindowSurfaceType,
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::{
|
||||||
|
|
@ -15,6 +16,7 @@ use smithay::{
|
||||||
utils::{Logical, Point, Rectangle},
|
utils::{Logical, Point, Rectangle},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{get_role, with_states},
|
compositor::{get_role, with_states},
|
||||||
|
seat::WaylandFocus,
|
||||||
shell::xdg::{
|
shell::xdg::{
|
||||||
PopupSurface, PositionerState, SurfaceCachedState, XdgPopupSurfaceRoleAttributes,
|
PopupSurface, PositionerState, SurfaceCachedState, XdgPopupSurfaceRoleAttributes,
|
||||||
XDG_POPUP_ROLE,
|
XDG_POPUP_ROLE,
|
||||||
|
|
@ -31,12 +33,12 @@ impl Shell {
|
||||||
let element_geo = workspace.element_geometry(elem).unwrap();
|
let element_geo = workspace.element_geometry(elem).unwrap();
|
||||||
let (window, offset) = elem
|
let (window, offset) = elem
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.toplevel().wl_surface() == &parent)
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(&parent))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let window_geo_offset = window.geometry().loc;
|
let window_geo_offset = window.geometry().loc;
|
||||||
let window_loc = element_geo.loc + offset + window_geo_offset;
|
let window_loc = element_geo.loc + offset + window_geo_offset;
|
||||||
let anchor_point = get_anchor_point(&positioner) + window_loc;
|
let anchor_point = get_anchor_point(&positioner) + window_loc;
|
||||||
if elem.is_tiled() {
|
if elem.is_tiled().unwrap() {
|
||||||
if !unconstrain_xdg_popup_tile(surface, element_geo) {
|
if !unconstrain_xdg_popup_tile(surface, element_geo) {
|
||||||
if let Some(output) = workspace.output_under(anchor_point) {
|
if let Some(output) = workspace.output_under(anchor_point) {
|
||||||
unconstrain_xdg_popup(surface, window_loc, output.geometry());
|
unconstrain_xdg_popup(surface, window_loc, output.geometry());
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ use smithay::{
|
||||||
allocator::Fourcc as DrmFourcc,
|
allocator::Fourcc as DrmFourcc,
|
||||||
drm::{DrmNode, NodeType},
|
drm::{DrmNode, NodeType},
|
||||||
},
|
},
|
||||||
desktop::Window,
|
|
||||||
input::{Seat, SeatHandler},
|
input::{Seat, SeatHandler},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_server::{
|
reexports::wayland_server::{
|
||||||
|
|
@ -30,10 +29,10 @@ use wayland_backend::{
|
||||||
server::{GlobalId, ObjectId},
|
server::{GlobalId, ObjectId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::{shell::CosmicSurface, state::State};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
toplevel_info::window_from_handle,
|
toplevel_info::{window_from_handle, ToplevelInfoHandler},
|
||||||
workspace::{WorkspaceHandle, WorkspaceHandler},
|
workspace::{WorkspaceHandle, WorkspaceHandler},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -112,11 +111,11 @@ impl SessionDataInnerInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum SessionType {
|
pub enum SessionType {
|
||||||
Output(Output),
|
Output(Output),
|
||||||
Workspace(Output, WorkspaceHandle),
|
Workspace(Output, WorkspaceHandle),
|
||||||
Window(Window),
|
Window(CosmicSurface),
|
||||||
Cursor(Seat<State>),
|
Cursor(Seat<State>),
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
Unknown,
|
Unknown,
|
||||||
|
|
@ -490,7 +489,7 @@ pub trait ScreencopyHandler {
|
||||||
session: Session,
|
session: Session,
|
||||||
) -> Vec<BufferInfo>;
|
) -> Vec<BufferInfo>;
|
||||||
|
|
||||||
fn capture_toplevel(&mut self, toplevel: Window, session: Session) -> Vec<BufferInfo>;
|
fn capture_toplevel(&mut self, toplevel: CosmicSurface, session: Session) -> Vec<BufferInfo>;
|
||||||
|
|
||||||
fn capture_cursor(&mut self, session: CursorSession) -> Vec<BufferInfo>;
|
fn capture_cursor(&mut self, session: CursorSession) -> Vec<BufferInfo>;
|
||||||
|
|
||||||
|
|
@ -605,6 +604,7 @@ where
|
||||||
D: GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData>
|
D: GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData>
|
||||||
+ Dispatch<ZcosmicScreencopyManagerV1, Vec<WlCursorMode>>
|
+ Dispatch<ZcosmicScreencopyManagerV1, Vec<WlCursorMode>>
|
||||||
+ Dispatch<ZcosmicScreencopySessionV1, SessionData>
|
+ Dispatch<ZcosmicScreencopySessionV1, SessionData>
|
||||||
|
+ ToplevelInfoHandler<Window = CosmicSurface>
|
||||||
+ ScreencopyHandler
|
+ ScreencopyHandler
|
||||||
+ WorkspaceHandler
|
+ WorkspaceHandler
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
|
@ -664,7 +664,7 @@ where
|
||||||
} => {
|
} => {
|
||||||
let Some(cursor) = check_cursor(cursor, &data, resource) else { return; };
|
let Some(cursor) = check_cursor(cursor, &data, resource) else { return; };
|
||||||
|
|
||||||
match window_from_handle(toplevel) {
|
match window_from_handle::<<D as ToplevelInfoHandler>::Window>(toplevel) {
|
||||||
Some(window) => {
|
Some(window) => {
|
||||||
let session = match init_session(
|
let session = match init_session(
|
||||||
data_init,
|
data_init,
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,13 @@
|
||||||
use std::{collections::HashMap, sync::Mutex};
|
use std::{collections::HashMap, sync::Mutex};
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::Window,
|
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::wayland_server::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
backend::{ClientId, GlobalId, ObjectId},
|
||||||
wayland_server::{
|
protocol::wl_surface::WlSurface,
|
||||||
backend::{ClientId, GlobalId, ObjectId},
|
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
|
||||||
protocol::wl_surface::WlSurface,
|
|
||||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
utils::{IsAlive, Logical, Rectangle},
|
utils::{user_data::UserDataMap, IsAlive, Logical, Rectangle},
|
||||||
wayland::{compositor::with_states, shell::xdg::XdgToplevelSurfaceRoleAttributes},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::workspace::{WorkspaceHandle, WorkspaceHandler, WorkspaceState};
|
use super::workspace::{WorkspaceHandle, WorkspaceHandler, WorkspaceState};
|
||||||
|
|
@ -24,17 +19,28 @@ use cosmic_protocols::toplevel_info::v1::server::{
|
||||||
zcosmic_toplevel_info_v1::{self, ZcosmicToplevelInfoV1},
|
zcosmic_toplevel_info_v1::{self, ZcosmicToplevelInfoV1},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ToplevelInfoState<D> {
|
pub trait Window: IsAlive + Clone + Send {
|
||||||
|
fn title(&self) -> String;
|
||||||
|
fn app_id(&self) -> String;
|
||||||
|
fn is_activated(&self) -> bool;
|
||||||
|
fn is_maximized(&self) -> bool;
|
||||||
|
fn is_fullscreen(&self) -> bool;
|
||||||
|
fn is_minimized(&self) -> bool;
|
||||||
|
fn user_data(&self) -> &UserDataMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ToplevelInfoState<D, W: Window> {
|
||||||
dh: DisplayHandle,
|
dh: DisplayHandle,
|
||||||
pub(super) toplevels: Vec<Window>,
|
pub(super) toplevels: Vec<W>,
|
||||||
instances: Vec<ZcosmicToplevelInfoV1>,
|
instances: Vec<ZcosmicToplevelInfoV1>,
|
||||||
global: GlobalId,
|
global: GlobalId,
|
||||||
_dispatch_data: std::marker::PhantomData<D>,
|
_dispatch_data: std::marker::PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToplevelInfoHandler: WorkspaceHandler + Sized {
|
pub trait ToplevelInfoHandler: WorkspaceHandler + Sized {
|
||||||
fn toplevel_info_state(&self) -> &ToplevelInfoState<Self>;
|
type Window: Window;
|
||||||
fn toplevel_info_state_mut(&mut self) -> &mut ToplevelInfoState<Self>;
|
fn toplevel_info_state(&self) -> &ToplevelInfoState<Self, Self::Window>;
|
||||||
|
fn toplevel_info_state_mut(&mut self) -> &mut ToplevelInfoState<Self, Self::Window>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ToplevelInfoGlobalData {
|
pub struct ToplevelInfoGlobalData {
|
||||||
|
|
@ -46,23 +52,22 @@ pub(super) struct ToplevelStateInner {
|
||||||
instances: Vec<ZcosmicToplevelHandleV1>,
|
instances: Vec<ZcosmicToplevelHandleV1>,
|
||||||
outputs: Vec<Output>,
|
outputs: Vec<Output>,
|
||||||
workspaces: Vec<WorkspaceHandle>,
|
workspaces: Vec<WorkspaceHandle>,
|
||||||
minimized: bool,
|
|
||||||
pub(super) rectangles: HashMap<ClientId, (WlSurface, Rectangle<i32, Logical>)>,
|
pub(super) rectangles: HashMap<ClientId, (WlSurface, Rectangle<i32, Logical>)>,
|
||||||
}
|
}
|
||||||
pub(super) type ToplevelState = Mutex<ToplevelStateInner>;
|
pub(super) type ToplevelState = Mutex<ToplevelStateInner>;
|
||||||
|
|
||||||
pub struct ToplevelHandleStateInner {
|
pub struct ToplevelHandleStateInner<W: Window> {
|
||||||
outputs: Vec<Output>,
|
outputs: Vec<Output>,
|
||||||
workspaces: Vec<WorkspaceHandle>,
|
workspaces: Vec<WorkspaceHandle>,
|
||||||
title: String,
|
title: String,
|
||||||
app_id: String,
|
app_id: String,
|
||||||
states: Vec<States>,
|
states: Vec<States>,
|
||||||
pub(super) window: Window,
|
pub(super) window: W,
|
||||||
}
|
}
|
||||||
pub type ToplevelHandleState = Mutex<ToplevelHandleStateInner>;
|
pub type ToplevelHandleState<W> = Mutex<ToplevelHandleStateInner<W>>;
|
||||||
|
|
||||||
impl ToplevelHandleStateInner {
|
impl<W: Window> ToplevelHandleStateInner<W> {
|
||||||
fn from_window(window: &Window) -> ToplevelHandleState {
|
fn from_window(window: &W) -> ToplevelHandleState<W> {
|
||||||
ToplevelHandleState::new(ToplevelHandleStateInner {
|
ToplevelHandleState::new(ToplevelHandleStateInner {
|
||||||
outputs: Vec::new(),
|
outputs: Vec::new(),
|
||||||
workspaces: Vec::new(),
|
workspaces: Vec::new(),
|
||||||
|
|
@ -74,13 +79,15 @@ impl ToplevelHandleStateInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData, D> for ToplevelInfoState<D>
|
impl<D, W> GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData, D>
|
||||||
|
for ToplevelInfoState<D, W>
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
||||||
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
||||||
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState>
|
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
|
||||||
+ ToplevelInfoHandler
|
+ ToplevelInfoHandler<Window = W>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
W: Window + 'static,
|
||||||
{
|
{
|
||||||
fn bind(
|
fn bind(
|
||||||
state: &mut D,
|
state: &mut D,
|
||||||
|
|
@ -92,7 +99,7 @@ where
|
||||||
) {
|
) {
|
||||||
let instance = data_init.init(resource, ());
|
let instance = data_init.init(resource, ());
|
||||||
for window in &state.toplevel_info_state().toplevels {
|
for window in &state.toplevel_info_state().toplevels {
|
||||||
send_toplevel_to_client::<D>(dh, Some(state.workspace_state()), &instance, window);
|
send_toplevel_to_client::<D, W>(dh, Some(state.workspace_state()), &instance, window);
|
||||||
}
|
}
|
||||||
state.toplevel_info_state_mut().instances.push(instance);
|
state.toplevel_info_state_mut().instances.push(instance);
|
||||||
}
|
}
|
||||||
|
|
@ -102,13 +109,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> Dispatch<ZcosmicToplevelInfoV1, (), D> for ToplevelInfoState<D>
|
impl<D, W> Dispatch<ZcosmicToplevelInfoV1, (), D> for ToplevelInfoState<D, W>
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
||||||
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
||||||
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState>
|
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
|
||||||
+ ToplevelInfoHandler
|
+ ToplevelInfoHandler<Window = W>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
W: Window,
|
||||||
{
|
{
|
||||||
fn request(
|
fn request(
|
||||||
state: &mut D,
|
state: &mut D,
|
||||||
|
|
@ -138,20 +146,21 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState, D> for ToplevelInfoState<D>
|
impl<D, W> Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>, D> for ToplevelInfoState<D, W>
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
||||||
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
||||||
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState>
|
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
|
||||||
+ ToplevelInfoHandler
|
+ ToplevelInfoHandler<Window = W>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
W: Window,
|
||||||
{
|
{
|
||||||
fn request(
|
fn request(
|
||||||
_state: &mut D,
|
_state: &mut D,
|
||||||
_client: &Client,
|
_client: &Client,
|
||||||
_obj: &ZcosmicToplevelHandleV1,
|
_obj: &ZcosmicToplevelHandleV1,
|
||||||
request: zcosmic_toplevel_handle_v1::Request,
|
request: zcosmic_toplevel_handle_v1::Request,
|
||||||
_data: &ToplevelHandleState,
|
_data: &ToplevelHandleState<W>,
|
||||||
_dh: &DisplayHandle,
|
_dh: &DisplayHandle,
|
||||||
_data_init: &mut DataInit<'_, D>,
|
_data_init: &mut DataInit<'_, D>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -165,7 +174,7 @@ where
|
||||||
state: &mut D,
|
state: &mut D,
|
||||||
_client: ClientId,
|
_client: ClientId,
|
||||||
resource: ObjectId,
|
resource: ObjectId,
|
||||||
_data: &ToplevelHandleState,
|
_data: &ToplevelHandleState<W>,
|
||||||
) {
|
) {
|
||||||
for toplevel in &state.toplevel_info_state_mut().toplevels {
|
for toplevel in &state.toplevel_info_state_mut().toplevels {
|
||||||
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
||||||
|
|
@ -179,15 +188,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ToplevelInfoState<D>
|
impl<D, W> ToplevelInfoState<D, W>
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
||||||
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
||||||
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState>
|
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
|
||||||
+ ToplevelInfoHandler
|
+ ToplevelInfoHandler<Window = W>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
W: Window + 'static,
|
||||||
{
|
{
|
||||||
pub fn new<F>(dh: &DisplayHandle, client_filter: F) -> ToplevelInfoState<D>
|
pub fn new<F>(dh: &DisplayHandle, client_filter: F) -> ToplevelInfoState<D, W>
|
||||||
where
|
where
|
||||||
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
|
|
@ -206,35 +216,35 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_toplevel(&mut self, toplevel: &Window) {
|
pub fn new_toplevel(&mut self, toplevel: &W) {
|
||||||
toplevel
|
toplevel
|
||||||
.user_data()
|
.user_data()
|
||||||
.insert_if_missing(ToplevelState::default);
|
.insert_if_missing(ToplevelState::default);
|
||||||
for instance in &self.instances {
|
for instance in &self.instances {
|
||||||
send_toplevel_to_client::<D>(&self.dh, None, instance, toplevel);
|
send_toplevel_to_client::<D, W>(&self.dh, None, instance, toplevel);
|
||||||
}
|
}
|
||||||
self.toplevels.push(toplevel.clone());
|
self.toplevels.push(toplevel.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toplevel_enter_output(&mut self, toplevel: &Window, output: &Output) {
|
pub fn toplevel_enter_output(&mut self, toplevel: &W, output: &Output) {
|
||||||
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
||||||
state.lock().unwrap().outputs.push(output.clone());
|
state.lock().unwrap().outputs.push(output.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toplevel_leave_output(&mut self, toplevel: &Window, output: &Output) {
|
pub fn toplevel_leave_output(&mut self, toplevel: &W, output: &Output) {
|
||||||
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
||||||
state.lock().unwrap().outputs.retain(|o| o != output);
|
state.lock().unwrap().outputs.retain(|o| o != output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toplevel_enter_workspace(&mut self, toplevel: &Window, workspace: &WorkspaceHandle) {
|
pub fn toplevel_enter_workspace(&mut self, toplevel: &W, workspace: &WorkspaceHandle) {
|
||||||
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
||||||
state.lock().unwrap().workspaces.push(workspace.clone());
|
state.lock().unwrap().workspaces.push(workspace.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toplevel_leave_workspace(&mut self, toplevel: &Window, workspace: &WorkspaceHandle) {
|
pub fn toplevel_leave_workspace(&mut self, toplevel: &W, workspace: &WorkspaceHandle) {
|
||||||
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
|
||||||
state.lock().unwrap().workspaces.retain(|w| w != workspace);
|
state.lock().unwrap().workspaces.retain(|w| w != workspace);
|
||||||
}
|
}
|
||||||
|
|
@ -252,7 +262,7 @@ where
|
||||||
if window.alive() {
|
if window.alive() {
|
||||||
std::mem::drop(state);
|
std::mem::drop(state);
|
||||||
for instance in &self.instances {
|
for instance in &self.instances {
|
||||||
send_toplevel_to_client::<D>(&self.dh, workspace_state, instance, window);
|
send_toplevel_to_client::<D, W>(&self.dh, workspace_state, instance, window);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -276,17 +286,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_toplevel_to_client<D>(
|
fn send_toplevel_to_client<D, W: 'static>(
|
||||||
dh: &DisplayHandle,
|
dh: &DisplayHandle,
|
||||||
workspace_state: Option<&WorkspaceState<D>>,
|
workspace_state: Option<&WorkspaceState<D>>,
|
||||||
info: &ZcosmicToplevelInfoV1,
|
info: &ZcosmicToplevelInfoV1,
|
||||||
window: &Window,
|
window: &W,
|
||||||
) where
|
) where
|
||||||
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
|
||||||
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
+ Dispatch<ZcosmicToplevelInfoV1, ()>
|
||||||
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState>
|
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
|
||||||
+ ToplevelInfoHandler
|
+ ToplevelInfoHandler<Window = W>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
W: Window,
|
||||||
{
|
{
|
||||||
let mut state = window
|
let mut state = window
|
||||||
.user_data()
|
.user_data()
|
||||||
|
|
@ -322,90 +333,53 @@ fn send_toplevel_to_client<D>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut handle_state = instance
|
let mut handle_state = instance
|
||||||
.data::<ToplevelHandleState>()
|
.data::<ToplevelHandleState<W>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
with_states(window.toplevel().wl_surface(), |states| {
|
if handle_state.title != window.title() {
|
||||||
let attributes = states
|
handle_state.title = window.title();
|
||||||
.data_map
|
instance.title(handle_state.title.clone());
|
||||||
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
changed = true;
|
||||||
.unwrap()
|
}
|
||||||
.lock()
|
if handle_state.app_id != window.app_id() {
|
||||||
.unwrap();
|
handle_state.app_id = window.app_id();
|
||||||
|
instance.app_id(handle_state.app_id.clone());
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if handle_state.title != attributes.title.as_deref().unwrap_or(&"") {
|
if (handle_state.states.contains(&States::Maximized) != window.is_maximized())
|
||||||
handle_state.title = attributes.title.clone().unwrap_or_else(String::new);
|
|| (handle_state.states.contains(&States::Fullscreen) != window.is_fullscreen())
|
||||||
instance.title(handle_state.title.clone());
|
|| (handle_state.states.contains(&States::Activated) != window.is_activated())
|
||||||
changed = true;
|
|| (handle_state.states.contains(&States::Minimized) != window.is_minimized())
|
||||||
|
{
|
||||||
|
let mut states = Vec::new();
|
||||||
|
if window.is_maximized() {
|
||||||
|
states.push(States::Maximized);
|
||||||
}
|
}
|
||||||
if handle_state.app_id != attributes.app_id.as_deref().unwrap_or(&"") {
|
if window.is_fullscreen() {
|
||||||
handle_state.app_id = attributes.app_id.clone().unwrap_or_else(String::new);
|
states.push(States::Fullscreen);
|
||||||
instance.app_id(handle_state.app_id.clone());
|
|
||||||
changed = true;
|
|
||||||
}
|
}
|
||||||
|
if window.is_activated() {
|
||||||
|
states.push(States::Activated);
|
||||||
|
}
|
||||||
|
if window.is_minimized() {
|
||||||
|
states.push(States::Minimized);
|
||||||
|
}
|
||||||
|
handle_state.states = states.clone();
|
||||||
|
|
||||||
if (handle_state.states.contains(&States::Maximized)
|
let states: Vec<u8> = {
|
||||||
!= attributes
|
let ratio = std::mem::size_of::<States>() / std::mem::size_of::<u8>();
|
||||||
.current
|
let ptr = states.as_mut_ptr() as *mut u8;
|
||||||
.states
|
let len = states.len() * ratio;
|
||||||
.contains(xdg_toplevel::State::Maximized))
|
let cap = states.capacity() * ratio;
|
||||||
|| (handle_state.states.contains(&States::Fullscreen)
|
std::mem::forget(states);
|
||||||
!= attributes
|
unsafe { Vec::from_raw_parts(ptr, len, cap) }
|
||||||
.current
|
};
|
||||||
.states
|
instance.state(states);
|
||||||
.contains(xdg_toplevel::State::Fullscreen))
|
changed = true;
|
||||||
|| (handle_state.states.contains(&States::Activated)
|
}
|
||||||
!= attributes
|
|
||||||
.current
|
|
||||||
.states
|
|
||||||
.contains(xdg_toplevel::State::Activated))
|
|
||||||
|| (handle_state.states.contains(&States::Minimized) != state.minimized)
|
|
||||||
{
|
|
||||||
let mut states = Vec::new();
|
|
||||||
if attributes
|
|
||||||
.current
|
|
||||||
.states
|
|
||||||
.contains(xdg_toplevel::State::Maximized)
|
|
||||||
{
|
|
||||||
states.push(States::Maximized);
|
|
||||||
}
|
|
||||||
if attributes
|
|
||||||
.current
|
|
||||||
.states
|
|
||||||
.contains(xdg_toplevel::State::Fullscreen)
|
|
||||||
{
|
|
||||||
states.push(States::Fullscreen);
|
|
||||||
}
|
|
||||||
if attributes
|
|
||||||
.current
|
|
||||||
.states
|
|
||||||
.contains(xdg_toplevel::State::Activated)
|
|
||||||
{
|
|
||||||
states.push(States::Activated);
|
|
||||||
}
|
|
||||||
if attributes
|
|
||||||
.current
|
|
||||||
.states
|
|
||||||
.contains(xdg_toplevel::State::Maximized)
|
|
||||||
{
|
|
||||||
states.push(States::Maximized);
|
|
||||||
}
|
|
||||||
handle_state.states = states.clone();
|
|
||||||
|
|
||||||
let states: Vec<u8> = {
|
|
||||||
let ratio = std::mem::size_of::<States>() / std::mem::size_of::<u8>();
|
|
||||||
let ptr = states.as_mut_ptr() as *mut u8;
|
|
||||||
let len = states.len() * ratio;
|
|
||||||
let cap = states.capacity() * ratio;
|
|
||||||
std::mem::forget(states);
|
|
||||||
unsafe { Vec::from_raw_parts(ptr, len, cap) }
|
|
||||||
};
|
|
||||||
instance.state(states);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Ok(client) = dh.get_client(instance.id()) {
|
if let Ok(client) = dh.get_client(instance.id()) {
|
||||||
for new_output in state
|
for new_output in state
|
||||||
|
|
@ -464,23 +438,23 @@ fn send_toplevel_to_client<D>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_from_handle(handle: ZcosmicToplevelHandleV1) -> Option<Window> {
|
pub fn window_from_handle<W: Window + 'static>(handle: ZcosmicToplevelHandleV1) -> Option<W> {
|
||||||
handle
|
handle
|
||||||
.data::<ToplevelHandleState>()
|
.data::<ToplevelHandleState<W>>()
|
||||||
.map(|state| state.lock().unwrap().window.clone())
|
.map(|state| state.lock().unwrap().window.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! delegate_toplevel_info {
|
macro_rules! delegate_toplevel_info {
|
||||||
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, $window: ty) => {
|
||||||
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||||
cosmic_protocols::toplevel_info::v1::server::zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1: $crate::wayland::protocols::toplevel_info::ToplevelInfoGlobalData
|
cosmic_protocols::toplevel_info::v1::server::zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1: $crate::wayland::protocols::toplevel_info::ToplevelInfoGlobalData
|
||||||
] => $crate::wayland::protocols::toplevel_info::ToplevelInfoState<Self>);
|
] => $crate::wayland::protocols::toplevel_info::ToplevelInfoState<Self, $window>);
|
||||||
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||||
cosmic_protocols::toplevel_info::v1::server::zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1: ()
|
cosmic_protocols::toplevel_info::v1::server::zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1: ()
|
||||||
] => $crate::wayland::protocols::toplevel_info::ToplevelInfoState<Self>);
|
] => $crate::wayland::protocols::toplevel_info::ToplevelInfoState<Self, $window>);
|
||||||
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||||
cosmic_protocols::toplevel_info::v1::server::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1: $crate::wayland::protocols::toplevel_info::ToplevelHandleState
|
cosmic_protocols::toplevel_info::v1::server::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1: $crate::wayland::protocols::toplevel_info::ToplevelHandleState<$window>
|
||||||
] => $crate::wayland::protocols::toplevel_info::ToplevelInfoState<Self>);
|
] => $crate::wayland::protocols::toplevel_info::ToplevelInfoState<Self, $window>);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub(crate) use delegate_toplevel_info;
|
pub(crate) use delegate_toplevel_info;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::Window,
|
|
||||||
input::{Seat, SeatHandler},
|
input::{Seat, SeatHandler},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_server::{
|
reexports::wayland_server::{
|
||||||
|
|
@ -17,7 +16,7 @@ use cosmic_protocols::toplevel_management::v1::server::zcosmic_toplevel_manager_
|
||||||
self, ZcosmicToplevelManagerV1,
|
self, ZcosmicToplevelManagerV1,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::toplevel_info::{window_from_handle, ToplevelInfoHandler, ToplevelState};
|
use super::toplevel_info::{window_from_handle, ToplevelInfoHandler, ToplevelState, Window};
|
||||||
|
|
||||||
pub struct ToplevelManagementState {
|
pub struct ToplevelManagementState {
|
||||||
instances: Vec<ZcosmicToplevelManagerV1>,
|
instances: Vec<ZcosmicToplevelManagerV1>,
|
||||||
|
|
@ -25,19 +24,39 @@ pub struct ToplevelManagementState {
|
||||||
global: GlobalId,
|
global: GlobalId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ManagementWindow: Window {
|
||||||
|
fn close(&self);
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait ToplevelManagementHandler: ToplevelInfoHandler + SeatHandler {
|
pub trait ToplevelManagementHandler: ToplevelInfoHandler + SeatHandler
|
||||||
|
where
|
||||||
|
<Self as ToplevelInfoHandler>::Window: ManagementWindow,
|
||||||
|
{
|
||||||
fn toplevel_management_state(&mut self) -> &mut ToplevelManagementState;
|
fn toplevel_management_state(&mut self) -> &mut ToplevelManagementState;
|
||||||
|
|
||||||
fn activate(&mut self, dh: &DisplayHandle, window: &Window, seat: Option<Seat<Self>>) {}
|
fn activate(
|
||||||
fn close(&mut self, dh: &DisplayHandle, window: &Window) {}
|
&mut self,
|
||||||
|
dh: &DisplayHandle,
|
||||||
|
window: &<Self as ToplevelInfoHandler>::Window,
|
||||||
|
seat: Option<Seat<Self>>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn close(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
|
||||||
|
|
||||||
fn fullscreen(&mut self, dh: &DisplayHandle, window: &Window, output: Option<Output>) {}
|
fn fullscreen(
|
||||||
fn unfullscreen(&mut self, dh: &DisplayHandle, window: &Window) {}
|
&mut self,
|
||||||
fn maximize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
dh: &DisplayHandle,
|
||||||
fn unmaximize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
window: &<Self as ToplevelInfoHandler>::Window,
|
||||||
fn minimize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
output: Option<Output>,
|
||||||
fn unminimize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
) {
|
||||||
|
}
|
||||||
|
fn unfullscreen(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
|
||||||
|
}
|
||||||
|
fn maximize(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
|
||||||
|
fn unmaximize(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
|
||||||
|
fn minimize(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
|
||||||
|
fn unminimize(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ToplevelManagerGlobalData {
|
pub struct ToplevelManagerGlobalData {
|
||||||
|
|
@ -55,6 +74,7 @@ impl ToplevelManagementState {
|
||||||
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
||||||
+ ToplevelManagementHandler
|
+ ToplevelManagementHandler
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
<D as ToplevelInfoHandler>::Window: ManagementWindow,
|
||||||
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>(
|
let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>(
|
||||||
|
|
@ -72,7 +92,7 @@ impl ToplevelManagementState {
|
||||||
|
|
||||||
pub fn rectangle_for(
|
pub fn rectangle_for(
|
||||||
&mut self,
|
&mut self,
|
||||||
window: &Window,
|
window: &impl ManagementWindow,
|
||||||
client: &ClientId,
|
client: &ClientId,
|
||||||
) -> Option<(WlSurface, Rectangle<i32, Logical>)> {
|
) -> Option<(WlSurface, Rectangle<i32, Logical>)> {
|
||||||
if let Some(state) = window.user_data().get::<ToplevelState>() {
|
if let Some(state) = window.user_data().get::<ToplevelState>() {
|
||||||
|
|
@ -94,6 +114,7 @@ where
|
||||||
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
||||||
+ ToplevelManagementHandler
|
+ ToplevelManagementHandler
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
<D as ToplevelInfoHandler>::Window: ManagementWindow,
|
||||||
{
|
{
|
||||||
fn bind(
|
fn bind(
|
||||||
state: &mut D,
|
state: &mut D,
|
||||||
|
|
@ -128,6 +149,7 @@ where
|
||||||
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
||||||
+ ToplevelManagementHandler
|
+ ToplevelManagementHandler
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
<D as ToplevelInfoHandler>::Window: ManagementWindow,
|
||||||
{
|
{
|
||||||
fn request(
|
fn request(
|
||||||
state: &mut D,
|
state: &mut D,
|
||||||
|
|
@ -179,7 +201,8 @@ where
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
} => {
|
} => {
|
||||||
let window = window_from_handle(toplevel).unwrap();
|
let window =
|
||||||
|
window_from_handle::<<D as ToplevelInfoHandler>::Window>(toplevel).unwrap();
|
||||||
if let Some(toplevel_state) = window.user_data().get::<ToplevelState>() {
|
if let Some(toplevel_state) = window.user_data().get::<ToplevelState>() {
|
||||||
let mut toplevel_state = toplevel_state.lock().unwrap();
|
let mut toplevel_state = toplevel_state.lock().unwrap();
|
||||||
if let Some(client) = surface.client() {
|
if let Some(client) = surface.client() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue