Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/sctk-adwaita/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/sctk-adwaita/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"5dca18083537d851e45352e367583d0c44670e6ae7223b2374fbf2ba038a0b8b","Cargo.lock":"e1a4418aad5bf790ee0cd987d859fbad80e12a5f7350f1df61fdf6236184a132","Cargo.toml":"782257d78af06c7b6e8cd37147be72b8be1833155435697895667bd9db275ad1","LICENSE":"65fc947f4bac882a2cd104ef73c246b1b037059df9f2b3a58b7f77f0b9e56071","README.md":"9960aa36f327758894c75e1dc507cb3faca9ff8f3904efc0223ce468c99d4443","examples/simple.rs":"28ef853fbc65ff01b18c5e7baaaf9361e5a0f0aa88795c8d8e7a32e6f90f4757","src/buttons.rs":"b2df342560ec21e0c0afd26179ea37a9ff17e175f8f9dbfebbcd2cc6cd13265f","src/config.rs":"5b752de1cbb16b31522de3d79c2c046a3e9b63b87594de2040b1036049207922","src/lib.rs":"2495cf0e87b6100848e6d1199030e3441ef53ecb4aaca4aa91dfdb0dd1170411","src/parts.rs":"1546fdff92ef3b3cb4d64e54d90e7fb5faa055b66606219934c272dc7132b85d","src/pointer.rs":"a2f177827c8b0b2244bec431ffa0212f0b75db34a935622d86d9220e3af8274b","src/surface.rs":"5132cd9767eb7f12f60faf11bed6457bc41a860092dce727b336eb11b862ef21","src/theme.rs":"c1a65850062a1d3dee8bd5ce82e6a896b3176cdacdd47b7450c0f4ea03aab1df","src/title.rs":"db705a7d0dd2bf95832b763d6c1b369141443783a9867117a7fa6820728dc52f","src/title/Cantarell-Regular.ttf":"d15f25bcdaba2e25f54c32d4e29e68fedeb1b7a1d8fbc83f7c4475916e93b55f","src/title/ab_glyph_renderer.rs":"5881851a78d88f91c27ae84ac176970098d97e9ec4424f1516f770358e694cb0","src/title/config.rs":"b07148665c1875e921a1c2ec58b5ad5f157d9c74ed4504736e5c626b6b63f239","src/title/crossfont_renderer.rs":"3bce9368cf352edbc075d42f11b3e2dfe27a65c9781de6e9a2b243da80f64d21","src/title/dumb.rs":"67cb7b3ec19ce8e5134ccfc54b078e4ea8cf8b4a4a7608e3958df1c3943e9ee4","src/title/font_preference.rs":"3a6f4666868a45d8822b166667400cceb77571b0666c75ea0678f51b31f6ed54"},"package":"cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09"}
|
||||
28
third-party/vendor/sctk-adwaita/CHANGELOG.md
vendored
Normal file
28
third-party/vendor/sctk-adwaita/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
## 0.5.4
|
||||
- Timeout dbus call to settings portal (100ms)
|
||||
|
||||
## 0.5.3
|
||||
- `ab_glyph` titles will read the system title font using memory mapped buffers instead of reading to heap.
|
||||
Lowers RAM usage.
|
||||
- Improve titlebar-font config parsing to correctly handle more font names.
|
||||
|
||||
## 0.5.2
|
||||
- `ab_glyph` & `crossfont` titles will use gnome "titlebar-font" config if available.
|
||||
- `ab_glyph` titles are now more consistent with `crossfont` titles both using system sans
|
||||
if no better font config is available.
|
||||
- Rounded corners are now disabled on maximized and tiled windows.
|
||||
- Double click interval is now 400ms (as previous 1s interval was caused by bug fixed in 0.5.1)
|
||||
|
||||
## 0.5.1
|
||||
- Use dbus org.freedesktop.portal.Settings to automatically choose light or dark theming.
|
||||
- Double click detection fix.
|
||||
- Apply button click on release instead of press.
|
||||
|
||||
## 0.5.0
|
||||
- `title` feature got removed
|
||||
- `ab_glyph` default feature got added (for `ab_glyph` based title rendering)
|
||||
- `crossfont` feature got added (for `crossfont` based title rendering)
|
||||
- Can be enable like this:
|
||||
```toml
|
||||
sctk-adwaita = { default-features = false, features = ["crossfont"] }
|
||||
```
|
||||
793
third-party/vendor/sctk-adwaita/Cargo.lock
generated
vendored
Normal file
793
third-party/vendor/sctk-adwaita/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,793 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe21446ad43aa56417a767f3e2f3d7c4ca522904de1dd640529a76e9c5c3b33c"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph_rasterizer"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix 0.25.1",
|
||||
"slotmap",
|
||||
"thiserror",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa-foundation"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-foundation",
|
||||
"core-graphics-types",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.22.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-graphics-types",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics-types"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-text"
|
||||
version = "19.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"
|
||||
dependencies = [
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossfont"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21fd3add36ea31aba1520aa5288714dd63be506106753226d0eb387a93bc9c45"
|
||||
dependencies = [
|
||||
"cocoa",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"core-graphics",
|
||||
"core-text",
|
||||
"dwrote",
|
||||
"foreign-types 0.5.0",
|
||||
"freetype-rs",
|
||||
"libc",
|
||||
"log",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"pkg-config",
|
||||
"servo-fontconfig",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlib"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
|
||||
dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "dwrote"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winapi",
|
||||
"wio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "expat-sys"
|
||||
version = "2.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||
dependencies = [
|
||||
"foreign-types-macros",
|
||||
"foreign-types-shared 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-macros"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
||||
|
||||
[[package]]
|
||||
name = "freetype-rs"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"freetype-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "freetype-sys"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228"
|
||||
dependencies = [
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "sctk-adwaita"
|
||||
version = "0.5.4"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"crossfont",
|
||||
"log",
|
||||
"memmap2",
|
||||
"smithay-client-toolkit",
|
||||
"tiny-skia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-fontconfig"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"servo-fontconfig-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-fontconfig-sys"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388"
|
||||
dependencies = [
|
||||
"expat-sys",
|
||||
"freetype-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"calloop",
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memmap2",
|
||||
"nix 0.24.3",
|
||||
"pkg-config",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strict-num"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9df65f20698aeed245efdde3628a6b559ea1239bbb871af1b6e3b58c413b2bd1"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfef3412c6975196fdfac41ef232f910be2bb37b9dd3313a49a1a6bc815a5bdb"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"png",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia-path"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4b5edac058fc98f51c935daea4d805b695b38e2f151241cad125ade2a2ac20d"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
"strict-num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix 0.24.3",
|
||||
"scoped-tls",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-commons"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
|
||||
dependencies = [
|
||||
"nix 0.24.3",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
|
||||
dependencies = [
|
||||
"nix 0.24.3",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-client",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "wio"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xcursor"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
50
third-party/vendor/sctk-adwaita/Cargo.toml
vendored
Normal file
50
third-party/vendor/sctk-adwaita/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "sctk-adwaita"
|
||||
version = "0.5.4"
|
||||
authors = ["Poly <marynczak.bartlomiej@gmail.com>"]
|
||||
description = "Adwaita-like SCTK Frame"
|
||||
documentation = "https://docs.rs/sctk-adwaita"
|
||||
readme = "README.md"
|
||||
keywords = ["sctk"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/PolyMeilex/sctk-adwaita"
|
||||
|
||||
[dependencies.ab_glyph]
|
||||
version = "0.2.17"
|
||||
optional = true
|
||||
|
||||
[dependencies.crossfont]
|
||||
version = "0.5.0"
|
||||
features = ["force_system_fontconfig"]
|
||||
optional = true
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.memmap2]
|
||||
version = "0.5.8"
|
||||
|
||||
[dependencies.smithay-client-toolkit]
|
||||
version = "0.16"
|
||||
|
||||
[dependencies.tiny-skia]
|
||||
version = "0.8"
|
||||
features = [
|
||||
"std",
|
||||
"simd",
|
||||
]
|
||||
|
||||
[features]
|
||||
default = ["ab_glyph"]
|
||||
21
third-party/vendor/sctk-adwaita/LICENSE
vendored
Normal file
21
third-party/vendor/sctk-adwaita/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Bartłomiej Maryńczak
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
19
third-party/vendor/sctk-adwaita/README.md
vendored
Normal file
19
third-party/vendor/sctk-adwaita/README.md
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Adwaita-like SCTK Frame
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|||
|
||||
|
|
||||
|
||||
### Dark mode:
|
||||

|
||||
|
||||
## Title text: ab_glyph
|
||||
By default title text is drawn with _ab_glyph_ crate. This can be disabled by disabling default features.
|
||||
|
||||
## Title text: crossfont
|
||||
Alternatively title text may be drawn with _crossfont_ crate. This adds a requirement on _freetype_.
|
||||
|
||||
```toml
|
||||
sctk-adwaita = { default-features = false, features = ["crossfont"] }
|
||||
```
|
||||
117
third-party/vendor/sctk-adwaita/examples/simple.rs
vendored
Normal file
117
third-party/vendor/sctk-adwaita/examples/simple.rs
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
extern crate smithay_client_toolkit as sctk;
|
||||
|
||||
use sctk::reexports::calloop;
|
||||
use sctk::reexports::client::protocol::{wl_shm, wl_surface};
|
||||
use sctk::shm::AutoMemPool;
|
||||
use sctk::window::Event as WEvent;
|
||||
|
||||
sctk::default_environment!(KbdInputExample, desktop);
|
||||
|
||||
fn main() {
|
||||
let (env, display, queue) = sctk::new_default_environment!(KbdInputExample, desktop)
|
||||
.expect("Unable to connect to a Wayland compositor");
|
||||
|
||||
let mut event_loop = calloop::EventLoop::<Option<WEvent>>::try_new().unwrap();
|
||||
|
||||
let mut dimensions = (380u32, 240u32);
|
||||
|
||||
let surface = env.create_surface().detach();
|
||||
|
||||
let mut window = env
|
||||
.create_window::<sctk_adwaita::AdwaitaFrame, _>(
|
||||
surface,
|
||||
None,
|
||||
dimensions,
|
||||
move |evt, mut dispatch_data| {
|
||||
let next_action = dispatch_data.get::<Option<WEvent>>().unwrap();
|
||||
// Keep last event in priority order : Close > Configure > Refresh
|
||||
let replace = matches!(
|
||||
(&evt, &*next_action),
|
||||
(_, &None)
|
||||
| (_, &Some(WEvent::Refresh))
|
||||
| (&WEvent::Configure { .. }, &Some(WEvent::Configure { .. }))
|
||||
| (&WEvent::Close, _)
|
||||
);
|
||||
if replace {
|
||||
*next_action = Some(evt);
|
||||
}
|
||||
},
|
||||
)
|
||||
.expect("Failed to create a window !");
|
||||
|
||||
window.set_title("/usr/lib/xorg/modules/input".to_string());
|
||||
|
||||
// // uncomment to override automatic theme selection
|
||||
// window.set_frame_config(sctk_adwaita::FrameConfig::light());
|
||||
|
||||
let mut pool = env
|
||||
.create_auto_pool()
|
||||
.expect("Failed to create a memory pool !");
|
||||
|
||||
if !env.get_shell().unwrap().needs_configure() {
|
||||
// initial draw to bootstrap on wl_shell
|
||||
redraw(&mut pool, window.surface(), dimensions).expect("Failed to draw");
|
||||
window.refresh();
|
||||
}
|
||||
|
||||
println!("XDG_WINDOW: {:?}", window.surface());
|
||||
|
||||
let mut next_action = None;
|
||||
|
||||
sctk::WaylandSource::new(queue)
|
||||
.quick_insert(event_loop.handle())
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
match next_action.take() {
|
||||
Some(WEvent::Close) => break,
|
||||
Some(WEvent::Refresh) => {
|
||||
window.refresh();
|
||||
window.surface().commit();
|
||||
}
|
||||
Some(WEvent::Configure { new_size, .. }) => {
|
||||
if let Some((w, h)) = new_size {
|
||||
window.resize(w, h);
|
||||
dimensions = (w, h)
|
||||
}
|
||||
window.refresh();
|
||||
redraw(&mut pool, window.surface(), dimensions).expect("Failed to draw");
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// always flush the connection before going to sleep waiting for events
|
||||
display.flush().unwrap();
|
||||
|
||||
event_loop.dispatch(None, &mut next_action).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn redraw(
|
||||
pool: &mut AutoMemPool,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(buf_x, buf_y): (u32, u32),
|
||||
) -> Result<(), ::std::io::Error> {
|
||||
let (canvas, new_buffer) = pool.buffer(
|
||||
buf_x as i32,
|
||||
buf_y as i32,
|
||||
4 * buf_x as i32,
|
||||
wl_shm::Format::Argb8888,
|
||||
)?;
|
||||
|
||||
for pixel in canvas.chunks_exact_mut(4) {
|
||||
pixel[0] = 255;
|
||||
pixel[1] = 255;
|
||||
pixel[2] = 255;
|
||||
pixel[3] = 255;
|
||||
}
|
||||
|
||||
surface.attach(Some(&new_buffer), 0, 0);
|
||||
if surface.as_ref().version() >= 4 {
|
||||
surface.damage_buffer(0, 0, buf_x as i32, buf_y as i32);
|
||||
} else {
|
||||
surface.damage(0, 0, buf_x as i32, buf_y as i32);
|
||||
}
|
||||
surface.commit();
|
||||
Ok(())
|
||||
}
|
||||
345
third-party/vendor/sctk-adwaita/src/buttons.rs
vendored
Normal file
345
third-party/vendor/sctk-adwaita/src/buttons.rs
vendored
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
use smithay_client_toolkit::window::ButtonState;
|
||||
use tiny_skia::{FillRule, PathBuilder, PixmapMut, Rect, Stroke, Transform};
|
||||
|
||||
use crate::{
|
||||
theme::{ColorMap, BORDER_SIZE},
|
||||
Location, SkiaResult,
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ButtonKind {
|
||||
Close,
|
||||
Maximize,
|
||||
Minimize,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub(crate) struct Button {
|
||||
x: f32,
|
||||
y: f32,
|
||||
size: f32,
|
||||
}
|
||||
|
||||
impl Button {
|
||||
pub fn radius(&self) -> f32 {
|
||||
self.size / 2.0
|
||||
}
|
||||
|
||||
pub fn x(&self) -> f32 {
|
||||
self.x
|
||||
}
|
||||
|
||||
pub fn center_x(&self) -> f32 {
|
||||
self.x + self.radius()
|
||||
}
|
||||
|
||||
pub fn center_y(&self) -> f32 {
|
||||
self.y + self.radius()
|
||||
}
|
||||
|
||||
fn contains(&self, x: f32, y: f32) -> bool {
|
||||
x > self.x && x < self.x + self.size && y > self.y && y < self.y + self.size
|
||||
}
|
||||
}
|
||||
|
||||
impl Button {
|
||||
pub fn draw_minimize(
|
||||
&self,
|
||||
scale: f32,
|
||||
colors: &ColorMap,
|
||||
mouses: &[Location],
|
||||
pixmap: &mut PixmapMut,
|
||||
) -> SkiaResult {
|
||||
let btn_state = if mouses.contains(&Location::Button(ButtonKind::Minimize)) {
|
||||
ButtonState::Hovered
|
||||
} else {
|
||||
ButtonState::Idle
|
||||
};
|
||||
|
||||
let radius = self.radius();
|
||||
|
||||
let x = self.center_x();
|
||||
let y = self.center_y();
|
||||
|
||||
let circle = PathBuilder::from_circle(x, y, radius)?;
|
||||
|
||||
let button_bg = if btn_state == ButtonState::Hovered {
|
||||
colors.button_hover_paint()
|
||||
} else {
|
||||
colors.button_idle_paint()
|
||||
};
|
||||
|
||||
pixmap.fill_path(
|
||||
&circle,
|
||||
&button_bg,
|
||||
FillRule::Winding,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
let mut button_icon_paint = colors.button_icon_paint();
|
||||
button_icon_paint.anti_alias = false;
|
||||
|
||||
let len = 8.0 * scale;
|
||||
let hlen = len / 2.0;
|
||||
pixmap.fill_rect(
|
||||
Rect::from_xywh(x - hlen, y + hlen, len, 1.0 * scale)?,
|
||||
&button_icon_paint,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn draw_maximize(
|
||||
&self,
|
||||
scale: f32,
|
||||
colors: &ColorMap,
|
||||
mouses: &[Location],
|
||||
maximizable: bool,
|
||||
is_maximized: bool,
|
||||
pixmap: &mut PixmapMut,
|
||||
) -> SkiaResult {
|
||||
let btn_state = if !maximizable {
|
||||
ButtonState::Disabled
|
||||
} else if mouses
|
||||
.iter()
|
||||
.any(|&l| l == Location::Button(ButtonKind::Maximize))
|
||||
{
|
||||
ButtonState::Hovered
|
||||
} else {
|
||||
ButtonState::Idle
|
||||
};
|
||||
|
||||
let radius = self.radius();
|
||||
|
||||
let x = self.center_x();
|
||||
let y = self.center_y();
|
||||
|
||||
let path1 = {
|
||||
let mut pb = PathBuilder::new();
|
||||
pb.push_circle(x, y, radius);
|
||||
pb.finish()?
|
||||
};
|
||||
|
||||
let button_bg = if btn_state == ButtonState::Hovered {
|
||||
colors.button_hover_paint()
|
||||
} else {
|
||||
colors.button_idle_paint()
|
||||
};
|
||||
|
||||
pixmap.fill_path(
|
||||
&path1,
|
||||
&button_bg,
|
||||
FillRule::Winding,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
let path2 = {
|
||||
let size = 8.0 * scale;
|
||||
let hsize = size / 2.0;
|
||||
let mut pb = PathBuilder::new();
|
||||
|
||||
let x = x - hsize;
|
||||
let y = y - hsize;
|
||||
pb.push_rect(x, y, size, size);
|
||||
|
||||
if is_maximized {
|
||||
if let Some(rect) = Rect::from_xywh(x + 2.0, y - 2.0, size, size) {
|
||||
pb.move_to(rect.left(), rect.top());
|
||||
pb.line_to(rect.right(), rect.top());
|
||||
pb.line_to(rect.right(), rect.bottom());
|
||||
}
|
||||
}
|
||||
|
||||
pb.finish()?
|
||||
};
|
||||
|
||||
let mut button_icon_paint = colors.button_icon_paint();
|
||||
button_icon_paint.anti_alias = false;
|
||||
pixmap.stroke_path(
|
||||
&path2,
|
||||
&button_icon_paint,
|
||||
&Stroke {
|
||||
width: 1.0 * scale,
|
||||
..Default::default()
|
||||
},
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn draw_close(
|
||||
&self,
|
||||
scale: f32,
|
||||
colors: &ColorMap,
|
||||
mouses: &[Location],
|
||||
pixmap: &mut PixmapMut,
|
||||
) -> SkiaResult {
|
||||
// Draw the close button
|
||||
let btn_state = if mouses
|
||||
.iter()
|
||||
.any(|&l| l == Location::Button(ButtonKind::Close))
|
||||
{
|
||||
ButtonState::Hovered
|
||||
} else {
|
||||
ButtonState::Idle
|
||||
};
|
||||
|
||||
let radius = self.radius();
|
||||
|
||||
let x = self.center_x();
|
||||
let y = self.center_y();
|
||||
|
||||
let path1 = {
|
||||
let mut pb = PathBuilder::new();
|
||||
pb.push_circle(x, y, radius);
|
||||
pb.finish()?
|
||||
};
|
||||
|
||||
let button_bg = if btn_state == ButtonState::Hovered {
|
||||
colors.button_hover_paint()
|
||||
} else {
|
||||
colors.button_idle_paint()
|
||||
};
|
||||
|
||||
pixmap.fill_path(
|
||||
&path1,
|
||||
&button_bg,
|
||||
FillRule::Winding,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
let x_icon = {
|
||||
let size = 3.5 * scale;
|
||||
let mut pb = PathBuilder::new();
|
||||
|
||||
{
|
||||
let sx = x - size;
|
||||
let sy = y - size;
|
||||
let ex = x + size;
|
||||
let ey = y + size;
|
||||
|
||||
pb.move_to(sx, sy);
|
||||
pb.line_to(ex, ey);
|
||||
pb.close();
|
||||
}
|
||||
|
||||
{
|
||||
let sx = x - size;
|
||||
let sy = y + size;
|
||||
let ex = x + size;
|
||||
let ey = y - size;
|
||||
|
||||
pb.move_to(sx, sy);
|
||||
pb.line_to(ex, ey);
|
||||
pb.close();
|
||||
}
|
||||
|
||||
pb.finish()?
|
||||
};
|
||||
|
||||
let mut button_icon_paint = colors.button_icon_paint();
|
||||
button_icon_paint.anti_alias = true;
|
||||
pixmap.stroke_path(
|
||||
&x_icon,
|
||||
&button_icon_paint,
|
||||
&Stroke {
|
||||
width: 1.1 * scale,
|
||||
..Default::default()
|
||||
},
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Buttons {
|
||||
pub close: Button,
|
||||
pub maximize: Button,
|
||||
pub minimize: Button,
|
||||
|
||||
w: u32,
|
||||
h: u32,
|
||||
|
||||
scale: u32,
|
||||
}
|
||||
|
||||
impl Default for Buttons {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
close: Default::default(),
|
||||
maximize: Default::default(),
|
||||
minimize: Default::default(),
|
||||
scale: 1,
|
||||
|
||||
w: 0,
|
||||
h: super::theme::HEADER_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Buttons {
|
||||
pub fn arrange(&mut self, w: u32) {
|
||||
self.w = w;
|
||||
|
||||
let scale = self.scale as f32;
|
||||
let margin_top = BORDER_SIZE as f32 * scale;
|
||||
let margin = 5.0 * scale;
|
||||
let spacing = 13.0 * scale;
|
||||
let size = 12.0 * 2.0 * scale;
|
||||
|
||||
let mut x = w as f32 * scale - margin - BORDER_SIZE as f32 * scale;
|
||||
let y = margin + margin_top;
|
||||
|
||||
x -= size;
|
||||
self.close.x = x;
|
||||
self.close.y = y;
|
||||
self.close.size = size;
|
||||
|
||||
x -= size;
|
||||
x -= spacing;
|
||||
self.maximize.x = x;
|
||||
self.maximize.y = y;
|
||||
self.maximize.size = size;
|
||||
|
||||
x -= size;
|
||||
x -= spacing;
|
||||
self.minimize.x = x;
|
||||
self.minimize.y = y;
|
||||
self.minimize.size = size;
|
||||
}
|
||||
|
||||
pub fn update_scale(&mut self, scale: u32) {
|
||||
if self.scale != scale {
|
||||
self.scale = scale;
|
||||
self.arrange(self.w);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_button(&self, x: f64, y: f64) -> Location {
|
||||
let x = x as f32 * self.scale as f32;
|
||||
let y = y as f32 * self.scale as f32;
|
||||
if self.close.contains(x, y) {
|
||||
Location::Button(ButtonKind::Close)
|
||||
} else if self.maximize.contains(x, y) {
|
||||
Location::Button(ButtonKind::Maximize)
|
||||
} else if self.minimize.contains(x, y) {
|
||||
Location::Button(ButtonKind::Minimize)
|
||||
} else {
|
||||
Location::Head
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scaled_size(&self) -> (u32, u32) {
|
||||
(self.w * self.scale, self.h * self.scale)
|
||||
}
|
||||
}
|
||||
24
third-party/vendor/sctk-adwaita/src/config.rs
vendored
Normal file
24
third-party/vendor/sctk-adwaita/src/config.rs
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//! System configuration.
|
||||
use std::process::Command;
|
||||
|
||||
/// Query system to see if dark theming should be preferred.
|
||||
pub(crate) fn prefer_dark() -> bool {
|
||||
// outputs something like: `variant variant uint32 1`
|
||||
let stdout = Command::new("dbus-send")
|
||||
.arg("--reply-timeout=100")
|
||||
.arg("--print-reply=literal")
|
||||
.arg("--dest=org.freedesktop.portal.Desktop")
|
||||
.arg("/org/freedesktop/portal/desktop")
|
||||
.arg("org.freedesktop.portal.Settings.Read")
|
||||
.arg("string:org.freedesktop.appearance")
|
||||
.arg("string:color-scheme")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|out| String::from_utf8(out.stdout).ok());
|
||||
|
||||
if matches!(stdout, Some(ref s) if s.is_empty()) {
|
||||
log::error!("XDG Settings Portal did not return response in time: timeout: 100ms, key: color-scheme");
|
||||
}
|
||||
|
||||
matches!(stdout, Some(s) if s.trim().ends_with("uint32 1"))
|
||||
}
|
||||
827
third-party/vendor/sctk-adwaita/src/lib.rs
vendored
Normal file
827
third-party/vendor/sctk-adwaita/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,827 @@
|
|||
mod buttons;
|
||||
mod config;
|
||||
mod parts;
|
||||
mod pointer;
|
||||
mod surface;
|
||||
pub mod theme;
|
||||
mod title;
|
||||
|
||||
use crate::theme::ColorMap;
|
||||
use buttons::{ButtonKind, Buttons};
|
||||
use client::{
|
||||
protocol::{wl_compositor, wl_seat, wl_shm, wl_subcompositor, wl_surface},
|
||||
Attached, DispatchData,
|
||||
};
|
||||
use parts::Parts;
|
||||
use pointer::PointerUserData;
|
||||
use smithay_client_toolkit::{
|
||||
reexports::client,
|
||||
seat::pointer::{ThemeManager, ThemeSpec, ThemedPointer},
|
||||
shm::AutoMemPool,
|
||||
window::{Frame, FrameRequest, State, WindowState},
|
||||
};
|
||||
use std::{cell::RefCell, fmt, rc::Rc};
|
||||
use theme::{ColorTheme, BORDER_SIZE, HEADER_SIZE};
|
||||
use tiny_skia::{
|
||||
ClipMask, Color, FillRule, Paint, Path, PathBuilder, Pixmap, PixmapMut, PixmapPaint, Point,
|
||||
Rect, Transform,
|
||||
};
|
||||
use title::TitleText;
|
||||
|
||||
type SkiaResult = Option<()>;
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum Location {
|
||||
None,
|
||||
Head,
|
||||
Top,
|
||||
TopRight,
|
||||
Right,
|
||||
BottomRight,
|
||||
Bottom,
|
||||
BottomLeft,
|
||||
Left,
|
||||
TopLeft,
|
||||
Button(ButtonKind),
|
||||
}
|
||||
|
||||
/*
|
||||
* The core frame
|
||||
*/
|
||||
|
||||
struct Inner {
|
||||
parts: Parts,
|
||||
size: (u32, u32),
|
||||
resizable: bool,
|
||||
theme_over_surface: bool,
|
||||
implem: Box<dyn FnMut(FrameRequest, u32, DispatchData)>,
|
||||
maximized: bool,
|
||||
fullscreened: bool,
|
||||
tiled: bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Inner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Inner")
|
||||
.field("parts", &self.parts)
|
||||
.field("size", &self.size)
|
||||
.field("resizable", &self.resizable)
|
||||
.field("theme_over_surface", &self.theme_over_surface)
|
||||
.field(
|
||||
"implem",
|
||||
&"FnMut(FrameRequest, u32, DispatchData) -> { ... }",
|
||||
)
|
||||
.field("maximized", &self.maximized)
|
||||
.field("fullscreened", &self.fullscreened)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
fn precise_location(buttons: &Buttons, old: Location, width: u32, x: f64, y: f64) -> Location {
|
||||
match old {
|
||||
Location::Head
|
||||
| Location::Button(_)
|
||||
| Location::Top
|
||||
| Location::TopLeft
|
||||
| Location::TopRight => match buttons.find_button(x, y) {
|
||||
Location::Head => {
|
||||
if y <= f64::from(BORDER_SIZE) {
|
||||
if x <= f64::from(BORDER_SIZE) {
|
||||
Location::TopLeft
|
||||
} else if x >= f64::from(width + BORDER_SIZE) {
|
||||
Location::TopRight
|
||||
} else {
|
||||
Location::Top
|
||||
}
|
||||
} else if x < f64::from(BORDER_SIZE) {
|
||||
Location::TopLeft
|
||||
} else if x > f64::from(width) {
|
||||
Location::TopRight
|
||||
} else {
|
||||
Location::Head
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
},
|
||||
|
||||
Location::Bottom | Location::BottomLeft | Location::BottomRight => {
|
||||
if x <= f64::from(BORDER_SIZE) {
|
||||
Location::BottomLeft
|
||||
} else if x >= f64::from(width + BORDER_SIZE) {
|
||||
Location::BottomRight
|
||||
} else {
|
||||
Location::Bottom
|
||||
}
|
||||
}
|
||||
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FrameConfig {
|
||||
pub theme: ColorTheme,
|
||||
}
|
||||
|
||||
impl FrameConfig {
|
||||
pub fn auto() -> Self {
|
||||
Self {
|
||||
theme: ColorTheme::auto(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn light() -> Self {
|
||||
Self {
|
||||
theme: ColorTheme::light(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dark() -> Self {
|
||||
Self {
|
||||
theme: ColorTheme::dark(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple set of decorations
|
||||
#[derive(Debug)]
|
||||
pub struct AdwaitaFrame {
|
||||
base_surface: wl_surface::WlSurface,
|
||||
compositor: Attached<wl_compositor::WlCompositor>,
|
||||
subcompositor: Attached<wl_subcompositor::WlSubcompositor>,
|
||||
inner: Rc<RefCell<Inner>>,
|
||||
pool: AutoMemPool,
|
||||
active: WindowState,
|
||||
hidden: bool,
|
||||
pointers: Vec<ThemedPointer>,
|
||||
themer: ThemeManager,
|
||||
surface_version: u32,
|
||||
|
||||
buttons: Rc<RefCell<Buttons>>,
|
||||
colors: ColorTheme,
|
||||
title: Option<String>,
|
||||
title_text: Option<TitleText>,
|
||||
}
|
||||
|
||||
impl Frame for AdwaitaFrame {
|
||||
type Error = ::std::io::Error;
|
||||
type Config = FrameConfig;
|
||||
fn init(
|
||||
base_surface: &wl_surface::WlSurface,
|
||||
compositor: &Attached<wl_compositor::WlCompositor>,
|
||||
subcompositor: &Attached<wl_subcompositor::WlSubcompositor>,
|
||||
shm: &Attached<wl_shm::WlShm>,
|
||||
theme_manager: Option<ThemeManager>,
|
||||
implementation: Box<dyn FnMut(FrameRequest, u32, DispatchData)>,
|
||||
) -> Result<AdwaitaFrame, ::std::io::Error> {
|
||||
let (themer, theme_over_surface) = if let Some(theme_manager) = theme_manager {
|
||||
(theme_manager, false)
|
||||
} else {
|
||||
(
|
||||
ThemeManager::init(ThemeSpec::System, compositor.clone(), shm.clone()),
|
||||
true,
|
||||
)
|
||||
};
|
||||
|
||||
let inner = Rc::new(RefCell::new(Inner {
|
||||
parts: Parts::default(),
|
||||
size: (1, 1),
|
||||
resizable: true,
|
||||
implem: implementation,
|
||||
theme_over_surface,
|
||||
maximized: false,
|
||||
fullscreened: false,
|
||||
tiled: false,
|
||||
}));
|
||||
|
||||
let pool = AutoMemPool::new(shm.clone())?;
|
||||
|
||||
let colors = ColorTheme::auto();
|
||||
|
||||
Ok(AdwaitaFrame {
|
||||
base_surface: base_surface.clone(),
|
||||
compositor: compositor.clone(),
|
||||
subcompositor: subcompositor.clone(),
|
||||
inner,
|
||||
pool,
|
||||
active: WindowState::Inactive,
|
||||
hidden: true,
|
||||
pointers: Vec::new(),
|
||||
themer,
|
||||
surface_version: compositor.as_ref().version(),
|
||||
buttons: Default::default(),
|
||||
title: None,
|
||||
title_text: TitleText::new(colors.active.font_color),
|
||||
colors,
|
||||
})
|
||||
}
|
||||
|
||||
fn new_seat(&mut self, seat: &Attached<wl_seat::WlSeat>) {
|
||||
let inner = self.inner.clone();
|
||||
|
||||
let buttons = self.buttons.clone();
|
||||
let pointer = self.themer.theme_pointer_with_impl(
|
||||
seat,
|
||||
move |event, pointer: ThemedPointer, ddata: DispatchData| {
|
||||
if let Some(data) = pointer
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<RefCell<PointerUserData>>()
|
||||
{
|
||||
let mut data = data.borrow_mut();
|
||||
let mut inner = inner.borrow_mut();
|
||||
data.event(event, &mut inner, &buttons.borrow(), &pointer, ddata);
|
||||
}
|
||||
},
|
||||
);
|
||||
pointer
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.set(|| RefCell::new(PointerUserData::new(seat.detach())));
|
||||
self.pointers.push(pointer);
|
||||
}
|
||||
|
||||
fn remove_seat(&mut self, seat: &wl_seat::WlSeat) {
|
||||
self.pointers.retain(|pointer| {
|
||||
pointer
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<RefCell<PointerUserData>>()
|
||||
.map(|user_data| {
|
||||
let guard = user_data.borrow_mut();
|
||||
if &guard.seat == seat {
|
||||
pointer.release();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
});
|
||||
}
|
||||
|
||||
fn set_states(&mut self, states: &[State]) -> bool {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let mut need_redraw = false;
|
||||
|
||||
// Process active.
|
||||
let new_active = if states.contains(&State::Activated) {
|
||||
WindowState::Active
|
||||
} else {
|
||||
WindowState::Inactive
|
||||
};
|
||||
need_redraw |= new_active != self.active;
|
||||
self.active = new_active;
|
||||
|
||||
// Process maximized.
|
||||
let new_maximized = states.contains(&State::Maximized);
|
||||
need_redraw |= new_maximized != inner.maximized;
|
||||
inner.maximized = new_maximized;
|
||||
|
||||
// Process fullscreened.
|
||||
let new_fullscreened = states.contains(&State::Fullscreen);
|
||||
need_redraw |= new_fullscreened != inner.fullscreened;
|
||||
inner.fullscreened = new_fullscreened;
|
||||
|
||||
let new_tiled = states.contains(&State::TiledLeft)
|
||||
|| states.contains(&State::TiledRight)
|
||||
|| states.contains(&State::TiledTop)
|
||||
|| states.contains(&State::TiledBottom);
|
||||
need_redraw |= new_tiled != inner.tiled;
|
||||
inner.tiled = new_tiled;
|
||||
|
||||
need_redraw
|
||||
}
|
||||
|
||||
fn set_hidden(&mut self, hidden: bool) {
|
||||
self.hidden = hidden;
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
if !self.hidden {
|
||||
inner.parts.add_decorations(
|
||||
&self.base_surface,
|
||||
&self.compositor,
|
||||
&self.subcompositor,
|
||||
self.inner.clone(),
|
||||
);
|
||||
} else {
|
||||
inner.parts.remove_decorations();
|
||||
}
|
||||
}
|
||||
|
||||
fn set_resizable(&mut self, resizable: bool) {
|
||||
self.inner.borrow_mut().resizable = resizable;
|
||||
}
|
||||
|
||||
fn resize(&mut self, newsize: (u32, u32)) {
|
||||
self.inner.borrow_mut().size = newsize;
|
||||
self.buttons
|
||||
.borrow_mut()
|
||||
.arrange(newsize.0 + BORDER_SIZE * 2);
|
||||
}
|
||||
|
||||
fn redraw(&mut self) {
|
||||
self.redraw_inner();
|
||||
}
|
||||
|
||||
fn subtract_borders(&self, width: i32, height: i32) -> (i32, i32) {
|
||||
if self.hidden || self.inner.borrow().fullscreened {
|
||||
(width, height)
|
||||
} else {
|
||||
(width, height - HEADER_SIZE as i32)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_borders(&self, width: i32, height: i32) -> (i32, i32) {
|
||||
if self.hidden || self.inner.borrow().fullscreened {
|
||||
(width, height)
|
||||
} else {
|
||||
(width, height + HEADER_SIZE as i32)
|
||||
}
|
||||
}
|
||||
|
||||
fn location(&self) -> (i32, i32) {
|
||||
if self.hidden || self.inner.borrow().fullscreened {
|
||||
(0, 0)
|
||||
} else {
|
||||
(0, -(HEADER_SIZE as i32))
|
||||
}
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: FrameConfig) {
|
||||
self.colors = config.theme;
|
||||
}
|
||||
|
||||
fn set_title(&mut self, title: String) {
|
||||
if let Some(title_text) = self.title_text.as_mut() {
|
||||
title_text.update_title(&title);
|
||||
}
|
||||
|
||||
self.title = Some(title);
|
||||
}
|
||||
}
|
||||
|
||||
impl AdwaitaFrame {
|
||||
fn redraw_inner(&mut self) -> SkiaResult {
|
||||
let inner = self.inner.borrow_mut();
|
||||
|
||||
// Don't draw borders if the frame explicitly hidden or fullscreened.
|
||||
if self.hidden || inner.fullscreened {
|
||||
inner.parts.hide_decorations();
|
||||
return Some(());
|
||||
}
|
||||
|
||||
// `parts` can't be empty here, since the initial state for `self.hidden` is true, and
|
||||
// they will be created once `self.hidden` will become `false`.
|
||||
let parts = &inner.parts;
|
||||
|
||||
let (width, height) = inner.size;
|
||||
|
||||
if let Some(decoration) = parts.decoration() {
|
||||
// Use header scale for all the thing.
|
||||
let header_scale = decoration.header.scale();
|
||||
self.buttons.borrow_mut().update_scale(header_scale);
|
||||
|
||||
let left_scale = decoration.left.scale();
|
||||
let right_scale = decoration.right.scale();
|
||||
let bottom_scale = decoration.bottom.scale();
|
||||
|
||||
let (header_width, header_height) = self.buttons.borrow().scaled_size();
|
||||
let header_height = header_height + BORDER_SIZE * header_scale;
|
||||
|
||||
{
|
||||
// Create the buffers and draw
|
||||
|
||||
let colors = if self.active == WindowState::Active {
|
||||
&self.colors.active
|
||||
} else {
|
||||
&self.colors.inactive
|
||||
};
|
||||
|
||||
if let Some(title_text) = self.title_text.as_mut() {
|
||||
title_text.update_color(colors.font_color);
|
||||
}
|
||||
|
||||
let border_paint = colors.border_paint();
|
||||
|
||||
// -> head-subsurface
|
||||
if let Ok((canvas, buffer)) = self.pool.buffer(
|
||||
header_width as i32,
|
||||
header_height as i32,
|
||||
4 * header_width as i32,
|
||||
wl_shm::Format::Argb8888,
|
||||
) {
|
||||
let mut pixmap = PixmapMut::from_bytes(canvas, header_width, header_height)?;
|
||||
pixmap.fill(Color::TRANSPARENT);
|
||||
|
||||
if let Some(title_text) = self.title_text.as_mut() {
|
||||
title_text.update_scale(header_scale);
|
||||
}
|
||||
|
||||
draw_headerbar(
|
||||
&mut pixmap,
|
||||
self.title_text.as_ref().map(|t| t.pixmap()).unwrap_or(None),
|
||||
header_scale as f32,
|
||||
inner.resizable,
|
||||
inner.maximized,
|
||||
inner.tiled,
|
||||
self.active,
|
||||
&self.colors,
|
||||
&self.buttons.borrow(),
|
||||
&self
|
||||
.pointers
|
||||
.iter()
|
||||
.flat_map(|p| {
|
||||
if p.as_ref().is_alive() {
|
||||
let data: &RefCell<PointerUserData> =
|
||||
p.as_ref().user_data().get()?;
|
||||
Some(data.borrow().location)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Location>>(),
|
||||
);
|
||||
|
||||
decoration.header.subsurface.set_position(
|
||||
-(BORDER_SIZE as i32),
|
||||
-(HEADER_SIZE as i32 + BORDER_SIZE as i32),
|
||||
);
|
||||
decoration.header.surface.attach(Some(&buffer), 0, 0);
|
||||
if self.surface_version >= 4 {
|
||||
decoration.header.surface.damage_buffer(
|
||||
0,
|
||||
0,
|
||||
header_width as i32,
|
||||
header_height as i32,
|
||||
);
|
||||
} else {
|
||||
// surface is old and does not support damage_buffer, so we damage
|
||||
// in surface coordinates and hope it is not rescaled
|
||||
decoration
|
||||
.header
|
||||
.surface
|
||||
.damage(0, 0, width as i32, HEADER_SIZE as i32);
|
||||
}
|
||||
decoration.header.surface.commit();
|
||||
}
|
||||
|
||||
if inner.maximized {
|
||||
// Don't draw the borders.
|
||||
decoration.hide_borders();
|
||||
return Some(());
|
||||
}
|
||||
|
||||
let w = ((width + 2 * BORDER_SIZE) * bottom_scale) as i32;
|
||||
let h = (BORDER_SIZE * bottom_scale) as i32;
|
||||
// -> bottom-subsurface
|
||||
if let Ok((canvas, buffer)) = self.pool.buffer(
|
||||
w,
|
||||
h,
|
||||
(4 * bottom_scale * (width + 2 * BORDER_SIZE)) as i32,
|
||||
wl_shm::Format::Argb8888,
|
||||
) {
|
||||
let mut pixmap = PixmapMut::from_bytes(canvas, w as u32, h as u32)?;
|
||||
pixmap.fill(Color::TRANSPARENT);
|
||||
|
||||
let size = 1.0;
|
||||
let x = BORDER_SIZE as f32 * bottom_scale as f32 - 1.0;
|
||||
pixmap.fill_rect(
|
||||
Rect::from_xywh(
|
||||
x,
|
||||
0.0,
|
||||
w as f32 - BORDER_SIZE as f32 * 2.0 * bottom_scale as f32 + 2.0,
|
||||
size,
|
||||
)?,
|
||||
&border_paint,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
decoration
|
||||
.bottom
|
||||
.subsurface
|
||||
.set_position(-(BORDER_SIZE as i32), height as i32);
|
||||
decoration.bottom.surface.attach(Some(&buffer), 0, 0);
|
||||
if self.surface_version >= 4 {
|
||||
decoration.bottom.surface.damage_buffer(
|
||||
0,
|
||||
0,
|
||||
((width + 2 * BORDER_SIZE) * bottom_scale) as i32,
|
||||
(BORDER_SIZE * bottom_scale) as i32,
|
||||
);
|
||||
} else {
|
||||
// surface is old and does not support damage_buffer, so we damage
|
||||
// in surface coordinates and hope it is not rescaled
|
||||
decoration.bottom.surface.damage(
|
||||
0,
|
||||
0,
|
||||
(width + 2 * BORDER_SIZE) as i32,
|
||||
BORDER_SIZE as i32,
|
||||
);
|
||||
}
|
||||
decoration.bottom.surface.commit();
|
||||
}
|
||||
|
||||
let w = (BORDER_SIZE * left_scale) as i32;
|
||||
let h = (height * left_scale) as i32;
|
||||
// -> left-subsurface
|
||||
if let Ok((canvas, buffer)) = self.pool.buffer(
|
||||
w,
|
||||
h,
|
||||
4 * (BORDER_SIZE * left_scale) as i32,
|
||||
wl_shm::Format::Argb8888,
|
||||
) {
|
||||
let mut bg = Paint::default();
|
||||
bg.set_color_rgba8(255, 0, 0, 255);
|
||||
|
||||
let mut pixmap = PixmapMut::from_bytes(canvas, w as u32, h as u32)?;
|
||||
pixmap.fill(Color::TRANSPARENT);
|
||||
|
||||
let size = 1.0;
|
||||
pixmap.fill_rect(
|
||||
Rect::from_xywh(w as f32 - size, 0.0, w as f32, h as f32)?,
|
||||
&border_paint,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
decoration
|
||||
.left
|
||||
.subsurface
|
||||
.set_position(-(BORDER_SIZE as i32), 0);
|
||||
decoration.left.surface.attach(Some(&buffer), 0, 0);
|
||||
if self.surface_version >= 4 {
|
||||
decoration.left.surface.damage_buffer(0, 0, w, h);
|
||||
} else {
|
||||
// surface is old and does not support damage_buffer, so we damage
|
||||
// in surface coordinates and hope it is not rescaled
|
||||
decoration.left.surface.damage(
|
||||
0,
|
||||
0,
|
||||
BORDER_SIZE as i32,
|
||||
(height + HEADER_SIZE) as i32,
|
||||
);
|
||||
}
|
||||
decoration.left.surface.commit();
|
||||
}
|
||||
|
||||
let w = (BORDER_SIZE * right_scale) as i32;
|
||||
let h = (height * right_scale) as i32;
|
||||
// -> right-subsurface
|
||||
if let Ok((canvas, buffer)) = self.pool.buffer(
|
||||
w,
|
||||
h,
|
||||
4 * (BORDER_SIZE * right_scale) as i32,
|
||||
wl_shm::Format::Argb8888,
|
||||
) {
|
||||
let mut bg = Paint::default();
|
||||
bg.set_color_rgba8(255, 0, 0, 255);
|
||||
|
||||
let mut pixmap = PixmapMut::from_bytes(canvas, w as u32, h as u32)?;
|
||||
pixmap.fill(Color::TRANSPARENT);
|
||||
|
||||
let size = 1.0;
|
||||
pixmap.fill_rect(
|
||||
Rect::from_xywh(0.0, 0.0, size, h as f32)?,
|
||||
&border_paint,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
decoration.right.subsurface.set_position(width as i32, 0);
|
||||
decoration.right.surface.attach(Some(&buffer), 0, 0);
|
||||
if self.surface_version >= 4 {
|
||||
decoration.right.surface.damage_buffer(0, 0, w, h);
|
||||
} else {
|
||||
// surface is old and does not support damage_buffer, so we damage
|
||||
// in surface coordinates and hope it is not rescaled
|
||||
decoration
|
||||
.right
|
||||
.surface
|
||||
.damage(0, 0, BORDER_SIZE as i32, height as i32);
|
||||
}
|
||||
decoration.right.surface.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AdwaitaFrame {
|
||||
fn drop(&mut self) {
|
||||
for ptr in self.pointers.drain(..) {
|
||||
if ptr.as_ref().version() >= 3 {
|
||||
ptr.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_headerbar(
|
||||
pixmap: &mut PixmapMut,
|
||||
text_pixmap: Option<&Pixmap>,
|
||||
scale: f32,
|
||||
maximizable: bool,
|
||||
is_maximized: bool,
|
||||
tiled: bool,
|
||||
state: WindowState,
|
||||
colors: &ColorTheme,
|
||||
buttons: &Buttons,
|
||||
mouses: &[Location],
|
||||
) {
|
||||
let border_size = BORDER_SIZE as f32 * scale;
|
||||
|
||||
let margin_h = border_size;
|
||||
let margin_v = border_size;
|
||||
|
||||
let colors = colors.for_state(state);
|
||||
|
||||
draw_headerbar_bg(
|
||||
pixmap,
|
||||
scale,
|
||||
margin_h,
|
||||
margin_v,
|
||||
colors,
|
||||
is_maximized,
|
||||
tiled,
|
||||
);
|
||||
|
||||
if let Some(text_pixmap) = text_pixmap {
|
||||
let canvas_w = pixmap.width() as f32;
|
||||
let canvas_h = pixmap.height() as f32;
|
||||
|
||||
let header_w = canvas_w - margin_h * 2.0;
|
||||
let header_h = canvas_h - margin_v;
|
||||
|
||||
let text_w = text_pixmap.width() as f32;
|
||||
let text_h = text_pixmap.height() as f32;
|
||||
|
||||
let x = header_w / 2.0 - text_w / 2.0;
|
||||
let y = header_h / 2.0 - text_h / 2.0;
|
||||
|
||||
let x = margin_h + x;
|
||||
let y = margin_v + y;
|
||||
|
||||
let (x, y) = if x + text_w < buttons.minimize.x() - 10.0 {
|
||||
(x, y)
|
||||
} else {
|
||||
let y = header_h / 2.0 - text_h / 2.0;
|
||||
|
||||
let x = buttons.minimize.x() - text_w - 10.0;
|
||||
let y = margin_v + y;
|
||||
(x, y)
|
||||
};
|
||||
|
||||
let x = x.max(margin_h + 5.0);
|
||||
|
||||
if let Some(clip) = Rect::from_xywh(0.0, 0.0, buttons.minimize.x() - 10.0, canvas_h) {
|
||||
let mut mask = ClipMask::new();
|
||||
mask.set_path(
|
||||
canvas_w as u32,
|
||||
canvas_h as u32,
|
||||
&PathBuilder::from_rect(clip),
|
||||
FillRule::Winding,
|
||||
false,
|
||||
);
|
||||
pixmap.draw_pixmap(
|
||||
x as i32,
|
||||
y as i32,
|
||||
text_pixmap.as_ref(),
|
||||
&PixmapPaint::default(),
|
||||
Transform::identity(),
|
||||
Some(&mask),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if buttons.close.x() > margin_h {
|
||||
buttons.close.draw_close(scale, colors, mouses, pixmap);
|
||||
}
|
||||
|
||||
if buttons.maximize.x() > margin_h {
|
||||
buttons
|
||||
.maximize
|
||||
.draw_maximize(scale, colors, mouses, maximizable, is_maximized, pixmap);
|
||||
}
|
||||
|
||||
if buttons.minimize.x() > margin_h {
|
||||
buttons
|
||||
.minimize
|
||||
.draw_minimize(scale, colors, mouses, pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_headerbar_bg(
|
||||
pixmap: &mut PixmapMut,
|
||||
scale: f32,
|
||||
margin_h: f32,
|
||||
margin_v: f32,
|
||||
colors: &ColorMap,
|
||||
is_maximized: bool,
|
||||
tiled: bool,
|
||||
) -> SkiaResult {
|
||||
let w = pixmap.width() as f32;
|
||||
let h = pixmap.height() as f32;
|
||||
|
||||
let radius = if is_maximized || tiled {
|
||||
0.0
|
||||
} else {
|
||||
10.0 * scale
|
||||
};
|
||||
|
||||
let margin_h = margin_h - 1.0;
|
||||
let w = w - margin_h * 2.0;
|
||||
|
||||
let bg = rounded_headerbar_shape(margin_h, margin_v, w, h, radius)?;
|
||||
|
||||
pixmap.fill_path(
|
||||
&bg,
|
||||
&colors.headerbar_paint(),
|
||||
FillRule::Winding,
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
pixmap.fill_rect(
|
||||
Rect::from_xywh(margin_h, h - 1.0, w, h)?,
|
||||
&colors.border_paint(),
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn rounded_headerbar_shape(x: f32, y: f32, width: f32, height: f32, radius: f32) -> Option<Path> {
|
||||
use std::f32::consts::FRAC_1_SQRT_2;
|
||||
|
||||
let mut pb = PathBuilder::new();
|
||||
let mut cursor = Point::from_xy(x, y);
|
||||
|
||||
// !!!
|
||||
// This code is heavily "inspired" by https://gitlab.com/snakedye/snui/
|
||||
// So technically it should be licensed under MPL-2.0, sorry about that 🥺 👉👈
|
||||
// !!!
|
||||
|
||||
// Positioning the cursor
|
||||
cursor.y += radius;
|
||||
pb.move_to(cursor.x, cursor.y);
|
||||
|
||||
// Drawing the outline
|
||||
pb.cubic_to(
|
||||
cursor.x,
|
||||
cursor.y,
|
||||
cursor.x,
|
||||
cursor.y - FRAC_1_SQRT_2 * radius,
|
||||
{
|
||||
cursor.x += radius;
|
||||
cursor.x
|
||||
},
|
||||
{
|
||||
cursor.y -= radius;
|
||||
cursor.y
|
||||
},
|
||||
);
|
||||
pb.line_to(
|
||||
{
|
||||
cursor.x = x + width - radius;
|
||||
cursor.x
|
||||
},
|
||||
cursor.y,
|
||||
);
|
||||
pb.cubic_to(
|
||||
cursor.x,
|
||||
cursor.y,
|
||||
cursor.x + FRAC_1_SQRT_2 * radius,
|
||||
cursor.y,
|
||||
{
|
||||
cursor.x += radius;
|
||||
cursor.x
|
||||
},
|
||||
{
|
||||
cursor.y += radius;
|
||||
cursor.y
|
||||
},
|
||||
);
|
||||
pb.line_to(cursor.x, {
|
||||
cursor.y = y + height;
|
||||
cursor.y
|
||||
});
|
||||
pb.line_to(
|
||||
{
|
||||
cursor.x = x;
|
||||
cursor.x
|
||||
},
|
||||
cursor.y,
|
||||
);
|
||||
|
||||
pb.close();
|
||||
|
||||
pb.finish()
|
||||
}
|
||||
198
third-party/vendor/sctk-adwaita/src/parts.rs
vendored
Normal file
198
third-party/vendor/sctk-adwaita/src/parts.rs
vendored
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use smithay_client_toolkit::{
|
||||
reexports::client::{
|
||||
protocol::{
|
||||
wl_compositor::WlCompositor, wl_subcompositor::WlSubcompositor,
|
||||
wl_subsurface::WlSubsurface, wl_surface::WlSurface,
|
||||
},
|
||||
Attached, DispatchData,
|
||||
},
|
||||
window::FrameRequest,
|
||||
};
|
||||
|
||||
use crate::{surface, Inner, Location};
|
||||
|
||||
pub enum DecorationPartKind {
|
||||
Header,
|
||||
Top,
|
||||
Left,
|
||||
Right,
|
||||
Bottom,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Decoration {
|
||||
pub header: Part,
|
||||
|
||||
pub top: Part,
|
||||
pub left: Part,
|
||||
pub right: Part,
|
||||
pub bottom: Part,
|
||||
}
|
||||
|
||||
impl Decoration {
|
||||
pub fn iter(&self) -> [&Part; 5] {
|
||||
[
|
||||
&self.header,
|
||||
&self.top,
|
||||
&self.left,
|
||||
&self.right,
|
||||
&self.bottom,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn hide_decoration(&self) {
|
||||
for p in self.iter() {
|
||||
p.surface.attach(None, 0, 0);
|
||||
p.surface.commit();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hide_borders(&self) {
|
||||
for p in self.iter().iter().skip(1) {
|
||||
p.surface.attach(None, 0, 0);
|
||||
p.surface.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub(crate) struct Parts {
|
||||
decoration: Option<Decoration>,
|
||||
}
|
||||
|
||||
impl Parts {
|
||||
pub fn add_decorations(
|
||||
&mut self,
|
||||
parent: &WlSurface,
|
||||
compositor: &Attached<WlCompositor>,
|
||||
subcompositor: &Attached<WlSubcompositor>,
|
||||
inner: Rc<RefCell<Inner>>,
|
||||
) {
|
||||
if self.decoration.is_none() {
|
||||
let header = Part::new(parent, compositor, subcompositor, Some(inner));
|
||||
let top = Part::new(parent, compositor, subcompositor, None);
|
||||
let left = Part::new(parent, compositor, subcompositor, None);
|
||||
let right = Part::new(parent, compositor, subcompositor, None);
|
||||
let bottom = Part::new(parent, compositor, subcompositor, None);
|
||||
|
||||
self.decoration = Some(Decoration {
|
||||
header,
|
||||
top,
|
||||
left,
|
||||
right,
|
||||
bottom,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_decorations(&mut self) {
|
||||
self.decoration = None;
|
||||
}
|
||||
|
||||
pub fn hide_decorations(&self) {
|
||||
if let Some(decor) = self.decoration.as_ref() {
|
||||
decor.hide_decoration();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decoration(&self) -> Option<&Decoration> {
|
||||
self.decoration.as_ref()
|
||||
}
|
||||
|
||||
pub fn find_decoration_part(&self, surface: &WlSurface) -> DecorationPartKind {
|
||||
if let Some(decor) = self.decoration() {
|
||||
if surface.as_ref().equals(decor.header.surface.as_ref()) {
|
||||
DecorationPartKind::Header
|
||||
} else if surface.as_ref().equals(decor.top.surface.as_ref()) {
|
||||
DecorationPartKind::Top
|
||||
} else if surface.as_ref().equals(decor.bottom.surface.as_ref()) {
|
||||
DecorationPartKind::Bottom
|
||||
} else if surface.as_ref().equals(decor.left.surface.as_ref()) {
|
||||
DecorationPartKind::Left
|
||||
} else if surface.as_ref().equals(decor.right.surface.as_ref()) {
|
||||
DecorationPartKind::Right
|
||||
} else {
|
||||
DecorationPartKind::None
|
||||
}
|
||||
} else {
|
||||
DecorationPartKind::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_surface(&self, surface: &WlSurface) -> Location {
|
||||
if let Some(decor) = self.decoration() {
|
||||
if surface.as_ref().equals(decor.header.surface.as_ref()) {
|
||||
Location::Head
|
||||
} else if surface.as_ref().equals(decor.top.surface.as_ref()) {
|
||||
Location::Top
|
||||
} else if surface.as_ref().equals(decor.bottom.surface.as_ref()) {
|
||||
Location::Bottom
|
||||
} else if surface.as_ref().equals(decor.left.surface.as_ref()) {
|
||||
Location::Left
|
||||
} else if surface.as_ref().equals(decor.right.surface.as_ref()) {
|
||||
Location::Right
|
||||
} else {
|
||||
Location::None
|
||||
}
|
||||
} else {
|
||||
Location::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Part {
|
||||
pub surface: WlSurface,
|
||||
pub subsurface: WlSubsurface,
|
||||
}
|
||||
|
||||
impl Part {
|
||||
fn new(
|
||||
parent: &WlSurface,
|
||||
compositor: &Attached<WlCompositor>,
|
||||
subcompositor: &Attached<WlSubcompositor>,
|
||||
inner: Option<Rc<RefCell<Inner>>>,
|
||||
) -> Part {
|
||||
let surface = if let Some(inner) = inner {
|
||||
surface::setup_surface(
|
||||
compositor.create_surface(),
|
||||
Some(move |dpi, surface: WlSurface, ddata: DispatchData| {
|
||||
surface.set_buffer_scale(dpi);
|
||||
surface.commit();
|
||||
(inner.borrow_mut().implem)(FrameRequest::Refresh, 0, ddata);
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
surface::setup_surface(
|
||||
compositor.create_surface(),
|
||||
Some(move |dpi, surface: WlSurface, _ddata: DispatchData| {
|
||||
surface.set_buffer_scale(dpi);
|
||||
surface.commit();
|
||||
}),
|
||||
)
|
||||
};
|
||||
|
||||
let surface = surface.detach();
|
||||
|
||||
let subsurface = subcompositor.get_subsurface(&surface, parent);
|
||||
|
||||
Part {
|
||||
surface,
|
||||
subsurface: subsurface.detach(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(&self) -> u32 {
|
||||
surface::get_surface_scale_factor(&self.surface) as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Part {
|
||||
fn drop(&mut self) {
|
||||
self.subsurface.destroy();
|
||||
self.surface.destroy();
|
||||
}
|
||||
}
|
||||
260
third-party/vendor/sctk-adwaita/src/pointer.rs
vendored
Normal file
260
third-party/vendor/sctk-adwaita/src/pointer.rs
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
use log::error;
|
||||
use smithay_client_toolkit::{
|
||||
reexports::{
|
||||
client::{
|
||||
protocol::{wl_pointer, wl_seat::WlSeat},
|
||||
DispatchData,
|
||||
},
|
||||
protocols::xdg_shell::client::xdg_toplevel::ResizeEdge,
|
||||
},
|
||||
seat::pointer::ThemedPointer,
|
||||
window::FrameRequest,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
buttons::{ButtonKind, Buttons},
|
||||
parts::DecorationPartKind,
|
||||
precise_location,
|
||||
theme::{BORDER_SIZE, HEADER_SIZE},
|
||||
Inner, Location,
|
||||
};
|
||||
|
||||
pub(crate) struct PointerUserData {
|
||||
pub location: Location,
|
||||
current_surface: DecorationPartKind,
|
||||
|
||||
position: (f64, f64),
|
||||
pub seat: WlSeat,
|
||||
last_click: Option<std::time::Instant>,
|
||||
|
||||
lpm_grab: Option<ButtonKind>,
|
||||
}
|
||||
|
||||
impl PointerUserData {
|
||||
pub fn new(seat: WlSeat) -> Self {
|
||||
Self {
|
||||
location: Location::None,
|
||||
current_surface: DecorationPartKind::None,
|
||||
position: (0.0, 0.0),
|
||||
seat,
|
||||
last_click: None,
|
||||
lpm_grab: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event(
|
||||
&mut self,
|
||||
event: wl_pointer::Event,
|
||||
inner: &mut Inner,
|
||||
buttons: &Buttons,
|
||||
pointer: &ThemedPointer,
|
||||
ddata: DispatchData<'_>,
|
||||
) {
|
||||
use wl_pointer::Event;
|
||||
match event {
|
||||
Event::Enter {
|
||||
serial,
|
||||
surface,
|
||||
surface_x,
|
||||
surface_y,
|
||||
} => {
|
||||
self.location = precise_location(
|
||||
buttons,
|
||||
inner.parts.find_surface(&surface),
|
||||
inner.size.0,
|
||||
surface_x,
|
||||
surface_y,
|
||||
);
|
||||
self.current_surface = inner.parts.find_decoration_part(&surface);
|
||||
self.position = (surface_x, surface_y);
|
||||
change_pointer(pointer, inner, self.location, Some(serial))
|
||||
}
|
||||
Event::Leave { serial, .. } => {
|
||||
self.current_surface = DecorationPartKind::None;
|
||||
|
||||
self.location = Location::None;
|
||||
change_pointer(pointer, inner, self.location, Some(serial));
|
||||
(inner.implem)(FrameRequest::Refresh, 0, ddata);
|
||||
}
|
||||
Event::Motion {
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
self.position = (surface_x, surface_y);
|
||||
let newpos =
|
||||
precise_location(buttons, self.location, inner.size.0, surface_x, surface_y);
|
||||
if newpos != self.location {
|
||||
match (newpos, self.location) {
|
||||
(Location::Button(_), _) | (_, Location::Button(_)) => {
|
||||
// pointer movement involves a button, request refresh
|
||||
(inner.implem)(FrameRequest::Refresh, 0, ddata);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
// we changed of part of the decoration, pointer image
|
||||
// may need to be changed
|
||||
self.location = newpos;
|
||||
change_pointer(pointer, inner, self.location, None)
|
||||
}
|
||||
}
|
||||
Event::Button {
|
||||
serial,
|
||||
button,
|
||||
state,
|
||||
..
|
||||
} => {
|
||||
let request = if state == wl_pointer::ButtonState::Pressed {
|
||||
match button {
|
||||
// Left mouse button.
|
||||
0x110 => lmb_press(self, inner.maximized, inner.resizable),
|
||||
// Right mouse button.
|
||||
0x111 => rmb_press(self),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
// Left mouse button.
|
||||
if button == 0x110 {
|
||||
lmb_release(self, inner.maximized)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(request) = request {
|
||||
(inner.implem)(request, serial, ddata);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lmb_press(
|
||||
pointer_data: &mut PointerUserData,
|
||||
maximized: bool,
|
||||
resizable: bool,
|
||||
) -> Option<FrameRequest> {
|
||||
match pointer_data.location {
|
||||
Location::Top if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::Top,
|
||||
)),
|
||||
Location::TopLeft if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::TopLeft,
|
||||
)),
|
||||
Location::Left if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::Left,
|
||||
)),
|
||||
Location::BottomLeft if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::BottomLeft,
|
||||
)),
|
||||
Location::Bottom if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::Bottom,
|
||||
)),
|
||||
Location::BottomRight if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::BottomRight,
|
||||
)),
|
||||
Location::Right if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::Right,
|
||||
)),
|
||||
Location::TopRight if resizable => Some(FrameRequest::Resize(
|
||||
pointer_data.seat.clone(),
|
||||
ResizeEdge::TopRight,
|
||||
)),
|
||||
Location::Head => {
|
||||
let last_click = pointer_data.last_click.replace(std::time::Instant::now());
|
||||
|
||||
if let Some(last) = last_click {
|
||||
if last.elapsed() < std::time::Duration::from_millis(400) {
|
||||
pointer_data.last_click = None;
|
||||
|
||||
if maximized {
|
||||
Some(FrameRequest::UnMaximize)
|
||||
} else {
|
||||
Some(FrameRequest::Maximize)
|
||||
}
|
||||
} else {
|
||||
Some(FrameRequest::Move(pointer_data.seat.clone()))
|
||||
}
|
||||
} else {
|
||||
Some(FrameRequest::Move(pointer_data.seat.clone()))
|
||||
}
|
||||
}
|
||||
Location::Button(btn) => {
|
||||
pointer_data.lpm_grab = Some(btn);
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn lmb_release(pointer_data: &mut PointerUserData, maximized: bool) -> Option<FrameRequest> {
|
||||
let lpm_grab = pointer_data.lpm_grab.take();
|
||||
|
||||
match pointer_data.location {
|
||||
Location::Button(btn) => {
|
||||
if lpm_grab == Some(btn) {
|
||||
let req = match btn {
|
||||
ButtonKind::Close => FrameRequest::Close,
|
||||
ButtonKind::Maximize => {
|
||||
if maximized {
|
||||
FrameRequest::UnMaximize
|
||||
} else {
|
||||
FrameRequest::Maximize
|
||||
}
|
||||
}
|
||||
ButtonKind::Minimize => FrameRequest::Minimize,
|
||||
};
|
||||
|
||||
Some(req)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn rmb_press(pointer_data: &PointerUserData) -> Option<FrameRequest> {
|
||||
match pointer_data.location {
|
||||
Location::Head | Location::Button(_) => Some(FrameRequest::ShowMenu(
|
||||
pointer_data.seat.clone(),
|
||||
pointer_data.position.0 as i32 - BORDER_SIZE as i32,
|
||||
// We must offset it by header size for precise position.
|
||||
pointer_data.position.1 as i32 - (HEADER_SIZE as i32 + BORDER_SIZE as i32),
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn change_pointer(pointer: &ThemedPointer, inner: &Inner, location: Location, serial: Option<u32>) {
|
||||
// Prevent theming of the surface if it was requested.
|
||||
if !inner.theme_over_surface && location == Location::None {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = match location {
|
||||
// If we can't resize a frame we shouldn't show resize cursors.
|
||||
_ if !inner.resizable => "left_ptr",
|
||||
Location::Top => "top_side",
|
||||
Location::TopRight => "top_right_corner",
|
||||
Location::Right => "right_side",
|
||||
Location::BottomRight => "bottom_right_corner",
|
||||
Location::Bottom => "bottom_side",
|
||||
Location::BottomLeft => "bottom_left_corner",
|
||||
Location::Left => "left_side",
|
||||
Location::TopLeft => "top_left_corner",
|
||||
_ => "left_ptr",
|
||||
};
|
||||
|
||||
if pointer.set_cursor(name, serial).is_err() {
|
||||
error!("Failed to set cursor");
|
||||
}
|
||||
}
|
||||
154
third-party/vendor/sctk-adwaita/src/surface.rs
vendored
Normal file
154
third-party/vendor/sctk-adwaita/src/surface.rs
vendored
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
use std::{cell::RefCell, rc::Rc, sync::Mutex};
|
||||
|
||||
use super::client;
|
||||
use smithay_client_toolkit as sctk;
|
||||
|
||||
use client::{
|
||||
protocol::{wl_output, wl_surface},
|
||||
Attached, DispatchData, Main,
|
||||
};
|
||||
use sctk::output::{add_output_listener, with_output_info, OutputListener};
|
||||
|
||||
pub(crate) struct SurfaceUserData {
|
||||
scale_factor: i32,
|
||||
outputs: Vec<(wl_output::WlOutput, i32, OutputListener)>,
|
||||
}
|
||||
|
||||
impl SurfaceUserData {
|
||||
fn new() -> Self {
|
||||
SurfaceUserData {
|
||||
scale_factor: 1,
|
||||
outputs: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enter<F>(
|
||||
&mut self,
|
||||
output: wl_output::WlOutput,
|
||||
surface: wl_surface::WlSurface,
|
||||
callback: &Option<Rc<RefCell<F>>>,
|
||||
) where
|
||||
F: FnMut(i32, wl_surface::WlSurface, DispatchData) + 'static,
|
||||
{
|
||||
let output_scale = with_output_info(&output, |info| info.scale_factor).unwrap_or(1);
|
||||
let my_surface = surface.clone();
|
||||
// Use a UserData to safely share the callback with the other thread
|
||||
let my_callback = client::UserData::new();
|
||||
if let Some(ref cb) = callback {
|
||||
my_callback.set(|| cb.clone());
|
||||
}
|
||||
let listener = add_output_listener(&output, move |output, info, ddata| {
|
||||
let mut user_data = my_surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<Mutex<SurfaceUserData>>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap();
|
||||
// update the scale factor of the relevant output
|
||||
for (ref o, ref mut factor, _) in user_data.outputs.iter_mut() {
|
||||
if o.as_ref().equals(output.as_ref()) {
|
||||
if info.obsolete {
|
||||
// an output that no longer exists is marked by a scale factor of -1
|
||||
*factor = -1;
|
||||
} else {
|
||||
*factor = info.scale_factor;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// recompute the scale factor with the new info
|
||||
let callback = my_callback.get::<Rc<RefCell<F>>>().cloned();
|
||||
let old_scale_factor = user_data.scale_factor;
|
||||
let new_scale_factor = user_data.recompute_scale_factor();
|
||||
drop(user_data);
|
||||
if let Some(ref cb) = callback {
|
||||
if old_scale_factor != new_scale_factor {
|
||||
(*cb.borrow_mut())(new_scale_factor, surface.clone(), ddata);
|
||||
}
|
||||
}
|
||||
});
|
||||
self.outputs.push((output, output_scale, listener));
|
||||
}
|
||||
|
||||
pub(crate) fn leave(&mut self, output: &wl_output::WlOutput) {
|
||||
self.outputs
|
||||
.retain(|(ref output2, _, _)| !output.as_ref().equals(output2.as_ref()));
|
||||
}
|
||||
|
||||
fn recompute_scale_factor(&mut self) -> i32 {
|
||||
let mut new_scale_factor = 1;
|
||||
self.outputs.retain(|&(_, output_scale, _)| {
|
||||
if output_scale > 0 {
|
||||
new_scale_factor = ::std::cmp::max(new_scale_factor, output_scale);
|
||||
true
|
||||
} else {
|
||||
// cleanup obsolete output
|
||||
false
|
||||
}
|
||||
});
|
||||
if self.outputs.is_empty() {
|
||||
// don't update the scale factor if we are not displayed on any output
|
||||
return self.scale_factor;
|
||||
}
|
||||
self.scale_factor = new_scale_factor;
|
||||
new_scale_factor
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_surface<F>(
|
||||
surface: Main<wl_surface::WlSurface>,
|
||||
callback: Option<F>,
|
||||
) -> Attached<wl_surface::WlSurface>
|
||||
where
|
||||
F: FnMut(i32, wl_surface::WlSurface, DispatchData) + 'static,
|
||||
{
|
||||
let callback = callback.map(|c| Rc::new(RefCell::new(c)));
|
||||
surface.quick_assign(move |surface, event, ddata| {
|
||||
let mut user_data = surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<Mutex<SurfaceUserData>>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap();
|
||||
match event {
|
||||
wl_surface::Event::Enter { output } => {
|
||||
// Passing the callback to be added to output listener
|
||||
user_data.enter(output, surface.detach(), &callback);
|
||||
}
|
||||
wl_surface::Event::Leave { output } => {
|
||||
user_data.leave(&output);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let old_scale_factor = user_data.scale_factor;
|
||||
let new_scale_factor = user_data.recompute_scale_factor();
|
||||
drop(user_data);
|
||||
if let Some(ref cb) = callback {
|
||||
if old_scale_factor != new_scale_factor {
|
||||
(*cb.borrow_mut())(new_scale_factor, surface.detach(), ddata);
|
||||
}
|
||||
}
|
||||
});
|
||||
surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.set_threadsafe(|| Mutex::new(SurfaceUserData::new()));
|
||||
surface.into()
|
||||
}
|
||||
|
||||
/// Returns the current suggested scale factor of a surface.
|
||||
///
|
||||
/// Panics if the surface was not created using `Environment::create_surface` or
|
||||
/// `Environment::create_surface_with_dpi_callback`.
|
||||
pub fn get_surface_scale_factor(surface: &wl_surface::WlSurface) -> i32 {
|
||||
surface
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<Mutex<SurfaceUserData>>()
|
||||
.expect("SCTK: Surface was not created by SCTK.")
|
||||
.lock()
|
||||
.unwrap()
|
||||
.scale_factor
|
||||
}
|
||||
133
third-party/vendor/sctk-adwaita/src/theme.rs
vendored
Normal file
133
third-party/vendor/sctk-adwaita/src/theme.rs
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
use smithay_client_toolkit::window::WindowState;
|
||||
|
||||
pub use tiny_skia::Color;
|
||||
use tiny_skia::{Paint, Shader};
|
||||
|
||||
pub(crate) const BORDER_SIZE: u32 = 10;
|
||||
pub(crate) const HEADER_SIZE: u32 = 35;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ColorMap {
|
||||
pub headerbar: Color,
|
||||
pub button_idle: Color,
|
||||
pub button_hover: Color,
|
||||
pub button_icon: Color,
|
||||
pub border_color: Color,
|
||||
pub font_color: Color,
|
||||
}
|
||||
|
||||
impl ColorMap {
|
||||
pub(crate) fn headerbar_paint(&self) -> Paint {
|
||||
Paint {
|
||||
shader: Shader::SolidColor(self.headerbar),
|
||||
anti_alias: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn button_idle_paint(&self) -> Paint {
|
||||
Paint {
|
||||
shader: Shader::SolidColor(self.button_idle),
|
||||
anti_alias: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn button_hover_paint(&self) -> Paint {
|
||||
Paint {
|
||||
shader: Shader::SolidColor(self.button_hover),
|
||||
anti_alias: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn button_icon_paint(&self) -> Paint {
|
||||
Paint {
|
||||
shader: Shader::SolidColor(self.button_icon),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn border_paint(&self) -> Paint {
|
||||
Paint {
|
||||
shader: Shader::SolidColor(self.border_color),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ColorTheme {
|
||||
pub active: ColorMap,
|
||||
pub inactive: ColorMap,
|
||||
}
|
||||
|
||||
impl Default for ColorTheme {
|
||||
fn default() -> Self {
|
||||
Self::light()
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorTheme {
|
||||
/// Automatically choose between light & dark themes based on:
|
||||
/// * dbus org.freedesktop.portal.Settings
|
||||
/// <https://flatpak.github.io/xdg-desktop-portal/#gdbus-interface-org-freedesktop-portal-Settings>
|
||||
pub fn auto() -> Self {
|
||||
match crate::config::prefer_dark() {
|
||||
true => Self::dark(),
|
||||
false => Self::light(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn light() -> Self {
|
||||
Self {
|
||||
active: ColorMap {
|
||||
headerbar: Color::from_rgba8(235, 235, 235, 255),
|
||||
button_idle: Color::from_rgba8(216, 216, 216, 255),
|
||||
button_hover: Color::from_rgba8(207, 207, 207, 255),
|
||||
button_icon: Color::from_rgba8(42, 42, 42, 255),
|
||||
border_color: Color::from_rgba8(220, 220, 220, 255),
|
||||
font_color: Color::from_rgba8(47, 47, 47, 255),
|
||||
},
|
||||
inactive: ColorMap {
|
||||
headerbar: Color::from_rgba8(250, 250, 250, 255),
|
||||
button_idle: Color::from_rgba8(240, 240, 240, 255),
|
||||
button_hover: Color::from_rgba8(216, 216, 216, 255),
|
||||
button_icon: Color::from_rgba8(148, 148, 148, 255),
|
||||
border_color: Color::from_rgba8(220, 220, 220, 255),
|
||||
font_color: Color::from_rgba8(150, 150, 150, 255),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dark() -> Self {
|
||||
Self {
|
||||
active: ColorMap {
|
||||
headerbar: Color::from_rgba8(48, 48, 48, 255),
|
||||
button_idle: Color::from_rgba8(69, 69, 69, 255),
|
||||
button_hover: Color::from_rgba8(79, 79, 79, 255),
|
||||
button_icon: Color::from_rgba8(255, 255, 255, 255),
|
||||
border_color: Color::from_rgba8(58, 58, 58, 255),
|
||||
font_color: Color::from_rgba8(255, 255, 255, 255),
|
||||
},
|
||||
inactive: ColorMap {
|
||||
headerbar: Color::from_rgba8(36, 36, 36, 255),
|
||||
button_idle: Color::from_rgba8(47, 47, 47, 255),
|
||||
button_hover: Color::from_rgba8(57, 57, 57, 255),
|
||||
button_icon: Color::from_rgba8(144, 144, 144, 255),
|
||||
border_color: Color::from_rgba8(58, 58, 58, 255),
|
||||
font_color: Color::from_rgba8(144, 144, 144, 255),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorTheme {
|
||||
pub(crate) fn for_state(&self, state: WindowState) -> &ColorMap {
|
||||
if state == WindowState::Active {
|
||||
&self.active
|
||||
} else {
|
||||
&self.inactive
|
||||
}
|
||||
}
|
||||
}
|
||||
61
third-party/vendor/sctk-adwaita/src/title.rs
vendored
Normal file
61
third-party/vendor/sctk-adwaita/src/title.rs
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
use tiny_skia::{Color, Pixmap};
|
||||
|
||||
#[cfg(any(feature = "crossfont", feature = "ab_glyph"))]
|
||||
mod config;
|
||||
#[cfg(any(feature = "crossfont", feature = "ab_glyph"))]
|
||||
mod font_preference;
|
||||
|
||||
#[cfg(feature = "crossfont")]
|
||||
mod crossfont_renderer;
|
||||
|
||||
#[cfg(all(not(feature = "crossfont"), feature = "ab_glyph"))]
|
||||
mod ab_glyph_renderer;
|
||||
|
||||
#[cfg(all(not(feature = "crossfont"), not(feature = "ab_glyph")))]
|
||||
mod dumb;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TitleText {
|
||||
#[cfg(feature = "crossfont")]
|
||||
imp: crossfont_renderer::CrossfontTitleText,
|
||||
#[cfg(all(not(feature = "crossfont"), feature = "ab_glyph"))]
|
||||
imp: ab_glyph_renderer::AbGlyphTitleText,
|
||||
#[cfg(all(not(feature = "crossfont"), not(feature = "ab_glyph")))]
|
||||
imp: dumb::DumbTitleText,
|
||||
}
|
||||
|
||||
impl TitleText {
|
||||
pub fn new(color: Color) -> Option<Self> {
|
||||
#[cfg(feature = "crossfont")]
|
||||
return crossfont_renderer::CrossfontTitleText::new(color)
|
||||
.ok()
|
||||
.map(|imp| Self { imp });
|
||||
|
||||
#[cfg(all(not(feature = "crossfont"), feature = "ab_glyph"))]
|
||||
return Some(Self {
|
||||
imp: ab_glyph_renderer::AbGlyphTitleText::new(color),
|
||||
});
|
||||
|
||||
#[cfg(all(not(feature = "crossfont"), not(feature = "ab_glyph")))]
|
||||
{
|
||||
let _ = color;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_scale(&mut self, scale: u32) {
|
||||
self.imp.update_scale(scale)
|
||||
}
|
||||
|
||||
pub fn update_title<S: Into<String>>(&mut self, title: S) {
|
||||
self.imp.update_title(title)
|
||||
}
|
||||
|
||||
pub fn update_color(&mut self, color: Color) {
|
||||
self.imp.update_color(color)
|
||||
}
|
||||
|
||||
pub fn pixmap(&self) -> Option<&Pixmap> {
|
||||
self.imp.pixmap()
|
||||
}
|
||||
}
|
||||
BIN
third-party/vendor/sctk-adwaita/src/title/Cantarell-Regular.ttf
vendored
Normal file
BIN
third-party/vendor/sctk-adwaita/src/title/Cantarell-Regular.ttf
vendored
Normal file
Binary file not shown.
177
third-party/vendor/sctk-adwaita/src/title/ab_glyph_renderer.rs
vendored
Normal file
177
third-party/vendor/sctk-adwaita/src/title/ab_glyph_renderer.rs
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
//! Title renderer using ab_glyph.
|
||||
//!
|
||||
//! Requires no dynamically linked dependencies.
|
||||
//!
|
||||
//! Can fallback to a embedded Cantarell-Regular.ttf font (SIL Open Font Licence v1.1)
|
||||
//! if the system font doesn't work.
|
||||
use crate::title::{config, font_preference::FontPreference};
|
||||
use ab_glyph::{point, Font, FontRef, Glyph, PxScale, PxScaleFont, ScaleFont, VariableFont};
|
||||
use std::{fs::File, process::Command};
|
||||
use tiny_skia::{Color, Pixmap, PremultipliedColorU8};
|
||||
|
||||
const CANTARELL: &[u8] = include_bytes!("Cantarell-Regular.ttf");
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AbGlyphTitleText {
|
||||
title: String,
|
||||
font: Option<(memmap2::Mmap, FontPreference)>,
|
||||
original_px_size: f32,
|
||||
size: PxScale,
|
||||
color: Color,
|
||||
pixmap: Option<Pixmap>,
|
||||
}
|
||||
|
||||
impl AbGlyphTitleText {
|
||||
pub fn new(color: Color) -> Self {
|
||||
let font_pref = config::titlebar_font().unwrap_or_default();
|
||||
let font_pref_pt_size = font_pref.pt_size;
|
||||
let font = font_file_matching(&font_pref)
|
||||
.and_then(|f| mmap(&f))
|
||||
.map(|mmap| (mmap, font_pref));
|
||||
|
||||
let size = parse_font(&font)
|
||||
.pt_to_px_scale(font_pref_pt_size)
|
||||
.expect("invalid font units_per_em");
|
||||
|
||||
Self {
|
||||
title: <_>::default(),
|
||||
font,
|
||||
original_px_size: size.x,
|
||||
size,
|
||||
color,
|
||||
pixmap: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_scale(&mut self, scale: u32) {
|
||||
let new_scale = PxScale::from(self.original_px_size * scale as f32);
|
||||
if (self.size.x - new_scale.x).abs() > f32::EPSILON {
|
||||
self.size = new_scale;
|
||||
self.pixmap = self.render();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_title(&mut self, title: impl Into<String>) {
|
||||
let new_title = title.into();
|
||||
if new_title != self.title {
|
||||
self.title = new_title;
|
||||
self.pixmap = self.render();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_color(&mut self, color: Color) {
|
||||
if color != self.color {
|
||||
self.color = color;
|
||||
self.pixmap = self.render();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pixmap(&self) -> Option<&Pixmap> {
|
||||
self.pixmap.as_ref()
|
||||
}
|
||||
|
||||
/// Render returning the new `Pixmap`.
|
||||
fn render(&self) -> Option<Pixmap> {
|
||||
let font = parse_font(&self.font);
|
||||
let font = font.as_scaled(self.size);
|
||||
|
||||
let glyphs = self.layout(&font);
|
||||
let last_glyph = glyphs.last()?;
|
||||
let width = (last_glyph.position.x + font.h_advance(last_glyph.id)).ceil() as u32;
|
||||
let height = font.height().ceil() as u32;
|
||||
|
||||
let mut pixmap = Pixmap::new(width, height)?;
|
||||
|
||||
let pixels = pixmap.pixels_mut();
|
||||
|
||||
for glyph in glyphs {
|
||||
if let Some(outline) = font.outline_glyph(glyph) {
|
||||
let bounds = outline.px_bounds();
|
||||
let left = bounds.min.x as u32;
|
||||
let top = bounds.min.y as u32;
|
||||
outline.draw(|x, y, c| {
|
||||
let p_idx = (top + y) * width + (left + x);
|
||||
let old_alpha_u8 = pixels[p_idx as usize].alpha();
|
||||
let new_alpha = c + (old_alpha_u8 as f32 / 255.0);
|
||||
if let Some(px) = PremultipliedColorU8::from_rgba(
|
||||
(self.color.red() * new_alpha * 255.0) as _,
|
||||
(self.color.green() * new_alpha * 255.0) as _,
|
||||
(self.color.blue() * new_alpha * 255.0) as _,
|
||||
(new_alpha * 255.0) as _,
|
||||
) {
|
||||
pixels[p_idx as usize] = px;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Some(pixmap)
|
||||
}
|
||||
|
||||
/// Simple single-line glyph layout.
|
||||
fn layout(&self, font: &PxScaleFont<impl Font>) -> Vec<Glyph> {
|
||||
let mut caret = point(0.0, font.ascent());
|
||||
let mut last_glyph: Option<Glyph> = None;
|
||||
let mut target = Vec::new();
|
||||
for c in self.title.chars() {
|
||||
if c.is_control() {
|
||||
continue;
|
||||
}
|
||||
let mut glyph = font.scaled_glyph(c);
|
||||
if let Some(previous) = last_glyph.take() {
|
||||
caret.x += font.kern(previous.id, glyph.id);
|
||||
}
|
||||
glyph.position = caret;
|
||||
|
||||
last_glyph = Some(glyph.clone());
|
||||
caret.x += font.h_advance(glyph.id);
|
||||
|
||||
target.push(glyph);
|
||||
}
|
||||
target
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the memmapped system font or fallback to built-in cantarell.
|
||||
fn parse_font(sys_font: &Option<(memmap2::Mmap, FontPreference)>) -> FontRef<'_> {
|
||||
match sys_font {
|
||||
Some((mmap, font_pref)) => {
|
||||
FontRef::try_from_slice(mmap)
|
||||
.map(|mut f| {
|
||||
// basic "bold" handling for variable fonts
|
||||
if font_pref
|
||||
.style
|
||||
.as_deref()
|
||||
.map_or(false, |s| s.eq_ignore_ascii_case("bold"))
|
||||
{
|
||||
f.set_variation(b"wght", 700.0);
|
||||
}
|
||||
f
|
||||
})
|
||||
.unwrap_or_else(|_| FontRef::try_from_slice(CANTARELL).unwrap())
|
||||
}
|
||||
_ => FontRef::try_from_slice(CANTARELL).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Font-config without dynamically linked dependencies
|
||||
fn font_file_matching(pref: &FontPreference) -> Option<File> {
|
||||
let mut pattern = pref.name.clone();
|
||||
if let Some(style) = &pref.style {
|
||||
pattern.push(':');
|
||||
pattern.push_str(style);
|
||||
}
|
||||
Command::new("fc-match")
|
||||
.arg("-f")
|
||||
.arg("%{file}")
|
||||
.arg(&pattern)
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|out| String::from_utf8(out.stdout).ok())
|
||||
.and_then(|path| File::open(path.trim()).ok())
|
||||
}
|
||||
|
||||
fn mmap(file: &File) -> Option<memmap2::Mmap> {
|
||||
// Safety: System font files are not expected to be mutated during use
|
||||
unsafe { memmap2::Mmap::map(file).ok() }
|
||||
}
|
||||
20
third-party/vendor/sctk-adwaita/src/title/config.rs
vendored
Normal file
20
third-party/vendor/sctk-adwaita/src/title/config.rs
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//! System font configuration.
|
||||
use crate::title::font_preference::FontPreference;
|
||||
use std::process::Command;
|
||||
|
||||
/// Query system for which font to use for window titles.
|
||||
pub(crate) fn titlebar_font() -> Option<FontPreference> {
|
||||
// outputs something like: `'Cantarell Bold 12'`
|
||||
let stdout = Command::new("gsettings")
|
||||
.args(["get", "org.gnome.desktop.wm.preferences", "titlebar-font"])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|out| String::from_utf8(out.stdout).ok())?;
|
||||
|
||||
FontPreference::from_name_style_size(
|
||||
stdout
|
||||
.trim()
|
||||
.trim_end_matches('\'')
|
||||
.trim_start_matches('\''),
|
||||
)
|
||||
}
|
||||
227
third-party/vendor/sctk-adwaita/src/title/crossfont_renderer.rs
vendored
Normal file
227
third-party/vendor/sctk-adwaita/src/title/crossfont_renderer.rs
vendored
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
use crate::title::config;
|
||||
use crossfont::{GlyphKey, Rasterize, RasterizedGlyph};
|
||||
use tiny_skia::{Color, Pixmap, PixmapPaint, PixmapRef, Transform};
|
||||
|
||||
pub struct CrossfontTitleText {
|
||||
title: String,
|
||||
|
||||
font_desc: crossfont::FontDesc,
|
||||
font_key: crossfont::FontKey,
|
||||
size: crossfont::Size,
|
||||
scale: u32,
|
||||
metrics: crossfont::Metrics,
|
||||
rasterizer: crossfont::Rasterizer,
|
||||
color: Color,
|
||||
|
||||
pixmap: Option<Pixmap>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for CrossfontTitleText {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("TitleText")
|
||||
.field("title", &self.title)
|
||||
.field("font_desc", &self.font_desc)
|
||||
.field("font_key", &self.font_key)
|
||||
.field("size", &self.size)
|
||||
.field("scale", &self.scale)
|
||||
.field("pixmap", &self.pixmap)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl CrossfontTitleText {
|
||||
pub fn new(color: Color) -> Result<Self, crossfont::Error> {
|
||||
let title = "".into();
|
||||
let scale = 1;
|
||||
|
||||
let font_pref = config::titlebar_font().unwrap_or_default();
|
||||
let font_style = font_pref
|
||||
.style
|
||||
.map(crossfont::Style::Specific)
|
||||
.unwrap_or_else(|| crossfont::Style::Description {
|
||||
slant: crossfont::Slant::Normal,
|
||||
weight: crossfont::Weight::Normal,
|
||||
});
|
||||
let font_desc = crossfont::FontDesc::new(&font_pref.name, font_style);
|
||||
|
||||
let mut rasterizer = crossfont::Rasterizer::new(scale as f32)?;
|
||||
let size = crossfont::Size::new(font_pref.pt_size);
|
||||
let font_key = rasterizer.load_font(&font_desc, size)?;
|
||||
|
||||
// Need to load at least one glyph for the face before calling metrics.
|
||||
// The glyph requested here ('m' at the time of writing) has no special
|
||||
// meaning.
|
||||
rasterizer.get_glyph(GlyphKey {
|
||||
font_key,
|
||||
character: 'm',
|
||||
size,
|
||||
})?;
|
||||
|
||||
let metrics = rasterizer.metrics(font_key, size)?;
|
||||
|
||||
let mut this = Self {
|
||||
title,
|
||||
font_desc,
|
||||
font_key,
|
||||
size,
|
||||
scale,
|
||||
metrics,
|
||||
rasterizer,
|
||||
color,
|
||||
pixmap: None,
|
||||
};
|
||||
|
||||
this.rerender();
|
||||
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
fn update_metrics(&mut self) -> Result<(), crossfont::Error> {
|
||||
self.rasterizer.get_glyph(GlyphKey {
|
||||
font_key: self.font_key,
|
||||
character: 'm',
|
||||
size: self.size,
|
||||
})?;
|
||||
self.metrics = self.rasterizer.metrics(self.font_key, self.size)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_scale(&mut self, scale: u32) {
|
||||
if self.scale != scale {
|
||||
self.rasterizer.update_dpr(scale as f32);
|
||||
self.scale = scale;
|
||||
|
||||
self.update_metrics().ok();
|
||||
|
||||
self.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_title<S: Into<String>>(&mut self, title: S) {
|
||||
let title = title.into();
|
||||
if self.title != title {
|
||||
self.title = title;
|
||||
self.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_color(&mut self, color: Color) {
|
||||
if self.color != color {
|
||||
self.color = color;
|
||||
self.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
fn rerender(&mut self) {
|
||||
let glyphs: Vec<_> = self
|
||||
.title
|
||||
.chars()
|
||||
.filter_map(|character| {
|
||||
let key = GlyphKey {
|
||||
character,
|
||||
font_key: self.font_key,
|
||||
size: self.size,
|
||||
};
|
||||
|
||||
self.rasterizer
|
||||
.get_glyph(key)
|
||||
.map(|glyph| (key, glyph))
|
||||
.ok()
|
||||
})
|
||||
.collect();
|
||||
|
||||
if glyphs.is_empty() {
|
||||
self.pixmap = None;
|
||||
return;
|
||||
}
|
||||
|
||||
let width = self.calc_width(&glyphs);
|
||||
let height = self.metrics.line_height.round() as i32;
|
||||
|
||||
let mut pixmap = if let Some(p) = Pixmap::new(width as u32, height as u32) {
|
||||
p
|
||||
} else {
|
||||
self.pixmap = None;
|
||||
return;
|
||||
};
|
||||
// pixmap.fill(Color::from_rgba8(255, 0, 0, 55));
|
||||
|
||||
let mut caret = 0;
|
||||
let mut last_glyph = None;
|
||||
|
||||
for (key, glyph) in glyphs {
|
||||
let mut buffer = Vec::with_capacity(glyph.width as usize * 4);
|
||||
|
||||
let glyph_buffer = match &glyph.buffer {
|
||||
crossfont::BitmapBuffer::Rgb(v) => v.chunks(3),
|
||||
crossfont::BitmapBuffer::Rgba(v) => v.chunks(4),
|
||||
};
|
||||
|
||||
for px in glyph_buffer {
|
||||
let alpha = if let Some(alpha) = px.get(3) {
|
||||
*alpha as f32 / 255.0
|
||||
} else {
|
||||
let r = px[0] as f32 / 255.0;
|
||||
let g = px[1] as f32 / 255.0;
|
||||
let b = px[2] as f32 / 255.0;
|
||||
(r + g + b) / 3.0
|
||||
};
|
||||
|
||||
let mut color = self.color;
|
||||
color.set_alpha(alpha);
|
||||
let color = color.premultiply().to_color_u8();
|
||||
|
||||
buffer.push(color.red());
|
||||
buffer.push(color.green());
|
||||
buffer.push(color.blue());
|
||||
buffer.push(color.alpha());
|
||||
}
|
||||
|
||||
if let Some(last) = last_glyph {
|
||||
let (x, _) = self.rasterizer.kerning(last, key);
|
||||
caret += x as i32;
|
||||
}
|
||||
|
||||
if let Some(pixmap_glyph) =
|
||||
PixmapRef::from_bytes(&buffer, glyph.width as _, glyph.height as _)
|
||||
{
|
||||
pixmap.draw_pixmap(
|
||||
glyph.left + caret,
|
||||
height - glyph.top + self.metrics.descent.round() as i32,
|
||||
pixmap_glyph,
|
||||
&PixmapPaint::default(),
|
||||
Transform::identity(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
caret += glyph.advance.0;
|
||||
|
||||
last_glyph = Some(key);
|
||||
}
|
||||
|
||||
self.pixmap = Some(pixmap);
|
||||
}
|
||||
|
||||
pub fn pixmap(&self) -> Option<&Pixmap> {
|
||||
self.pixmap.as_ref()
|
||||
}
|
||||
|
||||
fn calc_width(&mut self, glyphs: &[(GlyphKey, RasterizedGlyph)]) -> i32 {
|
||||
let mut caret = 0;
|
||||
let mut last_glyph: Option<&GlyphKey> = None;
|
||||
|
||||
for (key, glyph) in glyphs.iter() {
|
||||
if let Some(last) = last_glyph {
|
||||
let (x, _) = self.rasterizer.kerning(*last, *key);
|
||||
caret += x as i32;
|
||||
}
|
||||
|
||||
caret += glyph.advance.0;
|
||||
|
||||
last_glyph = Some(key);
|
||||
}
|
||||
|
||||
caret
|
||||
}
|
||||
}
|
||||
16
third-party/vendor/sctk-adwaita/src/title/dumb.rs
vendored
Normal file
16
third-party/vendor/sctk-adwaita/src/title/dumb.rs
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
use tiny_skia::{Color, Pixmap};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DumbTitleText {}
|
||||
|
||||
impl DumbTitleText {
|
||||
pub fn update_scale(&mut self, _scale: u32) {}
|
||||
|
||||
pub fn update_title<S: Into<String>>(&mut self, _title: S) {}
|
||||
|
||||
pub fn update_color(&mut self, _color: Color) {}
|
||||
|
||||
pub fn pixmap(&self) -> Option<&Pixmap> {
|
||||
None
|
||||
}
|
||||
}
|
||||
91
third-party/vendor/sctk-adwaita/src/title/font_preference.rs
vendored
Normal file
91
third-party/vendor/sctk-adwaita/src/title/font_preference.rs
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#[derive(Debug)]
|
||||
pub(crate) struct FontPreference {
|
||||
pub name: String,
|
||||
pub style: Option<String>,
|
||||
pub pt_size: f32,
|
||||
}
|
||||
|
||||
impl Default for FontPreference {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "sans-serif".into(),
|
||||
style: None,
|
||||
pt_size: 10.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FontPreference {
|
||||
/// Parse config string like `Cantarell 12`, `Cantarell Bold 11`, `Noto Serif CJK HK Bold 12`.
|
||||
pub fn from_name_style_size(conf: &str) -> Option<Self> {
|
||||
// assume last is size, 2nd last is style and the rest is name.
|
||||
match conf.rsplit_once(' ') {
|
||||
Some((head, tail)) if tail.chars().all(|c| c.is_numeric()) => {
|
||||
let pt_size: f32 = tail.parse().unwrap_or(10.0);
|
||||
match head.rsplit_once(' ') {
|
||||
Some((name, style)) if !name.is_empty() => Some(Self {
|
||||
name: name.into(),
|
||||
style: Some(style.into()),
|
||||
pt_size,
|
||||
}),
|
||||
None if !head.is_empty() => Some(Self {
|
||||
name: head.into(),
|
||||
style: None,
|
||||
pt_size,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Some((head, tail)) if !head.is_empty() => Some(Self {
|
||||
name: head.into(),
|
||||
style: Some(tail.into()),
|
||||
pt_size: 10.0,
|
||||
}),
|
||||
None if !conf.is_empty() => Some(Self {
|
||||
name: conf.into(),
|
||||
style: None,
|
||||
pt_size: 10.0,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pref_from_multi_name_variant_size() {
|
||||
let pref = FontPreference::from_name_style_size("Noto Serif CJK HK Bold 12").unwrap();
|
||||
assert_eq!(pref.name, "Noto Serif CJK HK");
|
||||
assert_eq!(pref.style, Some("Bold".into()));
|
||||
assert!((pref.pt_size - 12.0).abs() < f32::EPSILON);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pref_from_name_variant_size() {
|
||||
let pref = FontPreference::from_name_style_size("Cantarell Bold 12").unwrap();
|
||||
assert_eq!(pref.name, "Cantarell");
|
||||
assert_eq!(pref.style, Some("Bold".into()));
|
||||
assert!((pref.pt_size - 12.0).abs() < f32::EPSILON);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pref_from_name_size() {
|
||||
let pref = FontPreference::from_name_style_size("Cantarell 12").unwrap();
|
||||
assert_eq!(pref.name, "Cantarell");
|
||||
assert_eq!(pref.style, None);
|
||||
assert!((pref.pt_size - 12.0).abs() < f32::EPSILON);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pref_from_name() {
|
||||
let pref = FontPreference::from_name_style_size("Cantarell").unwrap();
|
||||
assert_eq!(pref.name, "Cantarell");
|
||||
assert_eq!(pref.style, None);
|
||||
assert!((pref.pt_size - 10.0).abs() < f32::EPSILON);
|
||||
}
|
||||
#[test]
|
||||
fn pref_from_multi_name_style() {
|
||||
let pref = FontPreference::from_name_style_size("Foo Bar Baz Bold").unwrap();
|
||||
assert_eq!(pref.name, "Foo Bar Baz");
|
||||
assert_eq!(pref.style, Some("Bold".into()));
|
||||
assert!((pref.pt_size - 10.0).abs() < f32::EPSILON);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue