init
This commit is contained in:
commit
539c5e2a4c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
646
Cargo.lock
generated
Normal file
646
Cargo.lock
generated
Normal file
|
@ -0,0 +1,646 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"log",
|
||||
"polling",
|
||||
"rustix",
|
||||
"slab",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "calloop-wayland-source"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
|
||||
dependencies = [
|
||||
"calloop",
|
||||
"rustix",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||
|
||||
[[package]]
|
||||
name = "cursor-icon"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
||||
|
||||
[[package]]
|
||||
name = "dlib"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||
dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "font-types"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f0189ccb084f77c5523e08288d418cbaa09c451a08515678a0aa265df9a8b60"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hboard"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
"smithay-client-toolkit",
|
||||
"swash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "read-fonts"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c141b9980e1150201b2a3a32879001c8f975fe313ec3df5471a9b5c79a880cd"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"font-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "skrifa"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abea4738067b1e628c6ce28b2c216c19e9ea95715cdb332680e821c3bec2ef23"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"read-fonts",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytemuck",
|
||||
"calloop",
|
||||
"calloop-wayland-source",
|
||||
"cursor-icon",
|
||||
"libc",
|
||||
"log",
|
||||
"memmap2 0.9.4",
|
||||
"pkg-config",
|
||||
"rustix",
|
||||
"thiserror",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-csd-frame",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
"wayland-protocols-wlr",
|
||||
"wayland-scanner",
|
||||
"xkbcommon",
|
||||
"xkeysym",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swash"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93cdc334a50fcc2aa3f04761af3b28196280a6aaadb1ef11215c478ae32615ac"
|
||||
dependencies = [
|
||||
"skrifa",
|
||||
"yazi",
|
||||
"zeno",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-backend"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"downcast-rs",
|
||||
"rustix",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.31.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rustix",
|
||||
"wayland-backend",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-csd-frame"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cursor-icon",
|
||||
"wayland-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.31.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ef9489a8df197ebf3a8ce8a7a7f0a2320035c3743f3c1bd0bdbccf07ce64f95"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.32.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62989625a776e827cc0f15d41444a3cea5205b963c3a25be48ae1b52d6b4daaa"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols-wlr"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd993de54a40a40fbe5601d9f1fbcaef0aebcc5fda447d7dc8f6dcbaae4f8953"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.31.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quick-xml",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.31.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"log",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "xcursor"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61"
|
||||
|
||||
[[package]]
|
||||
name = "xkbcommon"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memmap2 0.8.0",
|
||||
"xkeysym",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xkeysym"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yazi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
|
||||
|
||||
[[package]]
|
||||
name = "zeno"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "hboard"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
image = { version = "0.25.2", default-features = false }
|
||||
log = "0.4.22"
|
||||
smithay-client-toolkit = "0.19.2"
|
||||
swash = "0.1.18"
|
8
shell.nix
Normal file
8
shell.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell rec {
|
||||
name = "shell-rust";
|
||||
nativeBuildInputs = with pkgs; [ rustc cargo pkg-config ];
|
||||
buildInputs = with pkgs; [ libxkbcommon ];
|
||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
|
||||
}
|
364
src/graphics.rs
Normal file
364
src/graphics.rs
Normal file
|
@ -0,0 +1,364 @@
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
collections::{BTreeMap, HashMap},
|
||||
};
|
||||
|
||||
use image::Pixel;
|
||||
use swash::{
|
||||
scale::{
|
||||
image::{Content, Image},
|
||||
Render, ScaleContext, Scaler, Source, StrikeWith,
|
||||
},
|
||||
shape::{Direction, ShapeContext, Shaper},
|
||||
text::Script,
|
||||
FontRef,
|
||||
};
|
||||
|
||||
pub struct Canvas<'a> {
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) data: &'a mut [u8],
|
||||
pub(crate) glyph_cache: HashMap<(FontId, u16), Option<Image>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FontId(u16);
|
||||
|
||||
impl<'a> Canvas<'a> {
|
||||
pub fn as_image(&mut self) -> Option<image::ImageBuffer<image::Rgba<u8>, &mut [u8]>> {
|
||||
image::ImageBuffer::from_raw(self.width, self.height, self.data)
|
||||
}
|
||||
fn render<'d, 'b: 'd, 'c>(
|
||||
glyph_cache: &'b mut HashMap<(FontId, u16), Option<Image>>,
|
||||
render: &'c mut Render,
|
||||
scaler: &'c mut Scaler,
|
||||
font: FontId,
|
||||
id: u16,
|
||||
) -> Option<&'d Image> {
|
||||
glyph_cache
|
||||
.entry((font, id))
|
||||
.or_insert_with(|| {
|
||||
let mut img2 = Image::new();
|
||||
if let Some(val) = render.render_into(scaler, id, &mut img2).then_some(img2) {
|
||||
Some(val)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.as_ref()
|
||||
}
|
||||
pub fn text_size(&mut self, shaper: Shaper, scaler: &mut Scaler, font: FontId) -> (f32, f32) {
|
||||
let mut ret_x = 0.0;
|
||||
let mut ret_y = 0.0f32;
|
||||
let mut render = Render::new(&[
|
||||
Source::ColorOutline(0),
|
||||
Source::ColorBitmap(StrikeWith::BestFit),
|
||||
Source::Bitmap(StrikeWith::BestFit),
|
||||
Source::Outline,
|
||||
]);
|
||||
shaper.shape_with(|cluster| {
|
||||
for glyph in cluster.glyphs {
|
||||
ret_x += glyph.advance;
|
||||
render.offset((ret_x % 1.0, -(0.0 % 1.0)).into());
|
||||
let Some(img2) =
|
||||
Self::render(&mut self.glyph_cache, &mut render, scaler, font, glyph.id)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
ret_y = ret_y.max(img2.placement.top as f32);
|
||||
}
|
||||
});
|
||||
(ret_x, ret_y)
|
||||
}
|
||||
pub fn render_text(
|
||||
&mut self,
|
||||
shaper: Shaper,
|
||||
scaler: &mut Scaler,
|
||||
font: FontId,
|
||||
x_pos: f32,
|
||||
mut y_pos: f32,
|
||||
bounds: Rect<u32>,
|
||||
dir: Direction,
|
||||
) {
|
||||
y_pos = self.height as f32 - y_pos;
|
||||
let max_xpos = bounds.left + bounds.width;
|
||||
let max_ypos = bounds.bottom + bounds.height;
|
||||
let min_xpos = bounds.left;
|
||||
let min_ypos = bounds.bottom;
|
||||
let mut render = Render::new(&[
|
||||
Source::ColorOutline(0),
|
||||
Source::ColorBitmap(StrikeWith::BestFit),
|
||||
Source::Bitmap(StrikeWith::BestFit),
|
||||
Source::Outline,
|
||||
]);
|
||||
let mut cur_x = match dir {
|
||||
Direction::LeftToRight => x_pos,
|
||||
Direction::RightToLeft => bounds.width as f32 - x_pos,
|
||||
};
|
||||
let cur_y = y_pos;
|
||||
shaper.shape_with(|cluster| {
|
||||
for glyph in cluster.glyphs {
|
||||
match dir {
|
||||
Direction::LeftToRight => {}
|
||||
Direction::RightToLeft => cur_x -= glyph.advance,
|
||||
}
|
||||
let off_x = cur_x; // - glyph.x;
|
||||
let off_y = cur_y - glyph.y;
|
||||
match dir {
|
||||
Direction::LeftToRight => cur_x += glyph.advance,
|
||||
Direction::RightToLeft => {}
|
||||
}
|
||||
render.offset((off_x % 1.0, -(off_y % 1.0)).into());
|
||||
let id = glyph.id;
|
||||
let mut off_x = off_x as i64;
|
||||
let mut off_y = off_y as i64;
|
||||
let Some(img2) = Self::render(&mut self.glyph_cache, &mut render, scaler, font, id)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let (stride, _is_mask) = match img2.content {
|
||||
Content::Mask => (1, true),
|
||||
Content::SubpixelMask => (4, true),
|
||||
Content::Color => (4, false),
|
||||
};
|
||||
let plc = img2.placement;
|
||||
let w = plc.width;
|
||||
if w == 0 {
|
||||
continue;
|
||||
}
|
||||
// origin is bottom left,
|
||||
// so off_x is added, off_y is subtracted
|
||||
off_y -= i64::from(plc.top);
|
||||
off_x += i64::from(plc.left);
|
||||
let data = &img2.data;
|
||||
let mut img = image::ImageBuffer::<image::Rgba<u8>, &mut [u8]>::from_raw(
|
||||
self.width,
|
||||
self.height,
|
||||
self.data,
|
||||
)
|
||||
.unwrap();
|
||||
let max_h = max_ypos.saturating_sub(
|
||||
img.height()
|
||||
.saturating_sub(u32::try_from(off_y + plc.height as i64).unwrap_or(0)),
|
||||
);
|
||||
let min_h = min_ypos.saturating_sub(
|
||||
img.height()
|
||||
.saturating_sub(u32::try_from(off_y + plc.height as i64).unwrap_or(0)),
|
||||
);
|
||||
let actual_h = plc.height;
|
||||
let max_w = usize::try_from(max_xpos)
|
||||
.unwrap()
|
||||
.saturating_sub(usize::try_from(off_x).unwrap_or(0));
|
||||
let min_w = usize::try_from(min_xpos)
|
||||
.unwrap()
|
||||
.saturating_sub(usize::try_from(off_x).unwrap_or(0));
|
||||
for (row_in, (_, row_out)) in data
|
||||
.chunks_exact(usize::try_from(w * stride).unwrap())
|
||||
.skip(
|
||||
usize::try_from(-off_y).unwrap_or(0)
|
||||
+ usize::try_from(actual_h.saturating_sub(max_h)).unwrap(),
|
||||
)
|
||||
.zip(
|
||||
img.enumerate_rows_mut()
|
||||
.skip(
|
||||
usize::try_from(off_y).unwrap_or(0)
|
||||
+ usize::try_from(actual_h.saturating_sub(max_h)).unwrap(),
|
||||
)
|
||||
.take(
|
||||
actual_h
|
||||
.saturating_sub(
|
||||
u32::try_from(-off_y).unwrap_or(0)
|
||||
+ actual_h.saturating_sub(max_h),
|
||||
)
|
||||
.saturating_sub(min_h) as usize,
|
||||
),
|
||||
)
|
||||
{
|
||||
for (pix_in, pix_out) in row_in
|
||||
.chunks_exact(usize::try_from(stride).unwrap())
|
||||
.skip(usize::try_from(-off_x).unwrap_or(0) + min_w)
|
||||
.take(max_w.saturating_sub(min_w))
|
||||
.zip(
|
||||
row_out
|
||||
.skip(usize::try_from(off_x).unwrap_or(0) + min_w)
|
||||
.take(max_w.saturating_sub(min_w)),
|
||||
)
|
||||
{
|
||||
if stride == 4 {
|
||||
pix_out
|
||||
.2
|
||||
.blend(&image::Rgba(<[u8; 4]>::try_from(pix_in).unwrap()));
|
||||
} else {
|
||||
pix_out.2.blend(&image::Rgba([255, 255, 255, pix_in[0]]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct Size {
|
||||
num: u32,
|
||||
parent_size_sub: u32,
|
||||
percent_from_parent_size: f32,
|
||||
}
|
||||
|
||||
impl Size {
|
||||
pub fn zero() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
pub fn full() -> Self {
|
||||
Self::ratio(1.0)
|
||||
}
|
||||
pub fn ratio(x: f32) -> Self {
|
||||
Self {
|
||||
num: 0,
|
||||
parent_size_sub: 0,
|
||||
percent_from_parent_size: x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Widget<'a> {
|
||||
/// render with x/y as the bottom left corner
|
||||
fn render(&mut self, canvas: &mut Canvas<'a>, bounds: Rect<u32>);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Layout<'a> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
children: BTreeMap<(i32, String), (Rect<Size>, Rect<u32>, Box<dyn 'a + Widget<'a>>)>,
|
||||
z_levels: BTreeMap<String, i32>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct Rect<T> {
|
||||
pub left: T,
|
||||
pub bottom: T,
|
||||
pub width: T,
|
||||
pub height: T,
|
||||
}
|
||||
|
||||
fn resolve_size(size: Size, parent_size: u32) -> u32 {
|
||||
((parent_size.saturating_sub(size.parent_size_sub) as f64)
|
||||
* size.percent_from_parent_size as f64) as u32
|
||||
+ size.num
|
||||
}
|
||||
|
||||
fn resolve_rect_size(size: Rect<Size>, w: u32, h: u32) -> Rect<u32> {
|
||||
Rect {
|
||||
left: resolve_size(size.left, w),
|
||||
bottom: resolve_size(size.bottom, h),
|
||||
width: resolve_size(size.width, w),
|
||||
height: resolve_size(size.height, h),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Layout<'a> {
|
||||
pub fn add_child(
|
||||
&mut self,
|
||||
widget: Box<dyn 'a + Widget<'a>>,
|
||||
z: i32,
|
||||
id: &str,
|
||||
bounds: Rect<Size>,
|
||||
) {
|
||||
if let Some(old_z) = self.z_levels.insert(id.to_owned(), z) {
|
||||
self.children.remove(&(old_z, id.to_owned()));
|
||||
}
|
||||
self.children
|
||||
.insert((z, id.to_owned()), (bounds, Rect::default(), widget));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget<'a> for Layout<'a> {
|
||||
fn render(&mut self, canvas: &mut Canvas<'a>, bounds: Rect<u32>) {
|
||||
for (size, size_resolved, widget) in self.children.values_mut() {
|
||||
*size_resolved = resolve_rect_size(*size, bounds.width, bounds.height);
|
||||
size_resolved.left += bounds.left;
|
||||
size_resolved.bottom += bounds.bottom;
|
||||
size_resolved.width = size_resolved.width.min(bounds.width - size_resolved.left);
|
||||
size_resolved.height = size_resolved
|
||||
.height
|
||||
.min(bounds.height - size_resolved.bottom);
|
||||
widget.render(canvas, *size_resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub enum Alignment {
|
||||
#[default]
|
||||
Start,
|
||||
Middle,
|
||||
End,
|
||||
}
|
||||
|
||||
pub struct Text<'a> {
|
||||
pub text: Cow<'a, str>,
|
||||
pub font: FontRef<'a>,
|
||||
pub font_id: u16,
|
||||
pub font_size: f32,
|
||||
pub script: Script,
|
||||
pub direction: Direction,
|
||||
pub halign: Alignment,
|
||||
pub valign: Alignment,
|
||||
}
|
||||
|
||||
impl<'a> Widget<'a> for Text<'a> {
|
||||
fn render(&mut self, canvas: &mut Canvas<'a>, bounds: Rect<u32>) {
|
||||
let mut context = ShapeContext::new();
|
||||
let mut shaper = context
|
||||
.builder(self.font)
|
||||
.script(self.script)
|
||||
.direction(self.direction)
|
||||
.size(self.font_size)
|
||||
.build();
|
||||
shaper.add_str(&self.text);
|
||||
let mut context2 = ScaleContext::new();
|
||||
let mut scaler = context2
|
||||
.builder(self.font)
|
||||
.size(self.font_size)
|
||||
.hint(true)
|
||||
.build();
|
||||
let (text_w, mut _text_h) = canvas.text_size(shaper, &mut scaler, FontId(self.font_id));
|
||||
let text_h = self.font_size / 1.2;
|
||||
shaper = context
|
||||
.builder(self.font)
|
||||
.script(self.script)
|
||||
.direction(self.direction)
|
||||
.size(self.font_size)
|
||||
.build();
|
||||
shaper.add_str(&self.text);
|
||||
let mut x = bounds.left as i32;
|
||||
let mut y = bounds.bottom as i32;
|
||||
match self.halign {
|
||||
Alignment::End => {
|
||||
x += bounds.width as i32 - text_w as i32;
|
||||
}
|
||||
Alignment::Middle => {
|
||||
x += ((bounds.width as f32 - text_w) / 2.0) as i32;
|
||||
}
|
||||
Alignment::Start => {}
|
||||
}
|
||||
match self.valign {
|
||||
Alignment::End => {
|
||||
y += bounds.height as i32 - text_h as i32;
|
||||
}
|
||||
Alignment::Middle => {
|
||||
y += ((bounds.height as f32 - text_h) / 2.0) as i32;
|
||||
}
|
||||
Alignment::Start => {}
|
||||
}
|
||||
canvas.render_text(
|
||||
shaper,
|
||||
&mut scaler,
|
||||
FontId(self.font_id),
|
||||
x as f32,
|
||||
y as f32,
|
||||
bounds,
|
||||
self.direction,
|
||||
);
|
||||
}
|
||||
}
|
119
src/keyboard.rs
Normal file
119
src/keyboard.rs
Normal file
|
@ -0,0 +1,119 @@
|
|||
use swash::{shape::Direction, text::Script, FontRef};
|
||||
|
||||
use crate::graphics::{self, Canvas, Widget};
|
||||
|
||||
pub struct Keyboard<'a> {
|
||||
latin_font: FontRef<'a>,
|
||||
emoji_font: FontRef<'a>,
|
||||
arabic_font: FontRef<'a>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
shift: u32,
|
||||
}
|
||||
|
||||
impl<'a> Keyboard<'a> {
|
||||
pub fn new(latin_font: FontRef<'a>, emoji_font: FontRef<'a>, arabic_font: FontRef<'a>) -> Self {
|
||||
Self {
|
||||
latin_font,
|
||||
emoji_font,
|
||||
arabic_font,
|
||||
width: 720,
|
||||
height: 480,
|
||||
shift: 0,
|
||||
}
|
||||
}
|
||||
pub fn size(&self) -> (u32, u32) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
pub fn set_size(&mut self, width: u32, height: u32) {
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
}
|
||||
fn render_text(&mut self, canvas: &mut [u8]) {
|
||||
let width = self.width;
|
||||
let height = self.height;
|
||||
let mut layout = graphics::Layout::default();
|
||||
layout.add_child(
|
||||
Box::new(graphics::Text {
|
||||
text: "عَرَبِيّ".into(),
|
||||
font: self.arabic_font,
|
||||
font_id: 2,
|
||||
halign: graphics::Alignment::Middle,
|
||||
valign: graphics::Alignment::Middle,
|
||||
direction: Direction::RightToLeft,
|
||||
font_size: 128.0,
|
||||
script: Script::Arabic,
|
||||
}),
|
||||
0,
|
||||
"a",
|
||||
graphics::Rect {
|
||||
left: graphics::Size::zero(),
|
||||
bottom: graphics::Size::ratio(0.0),
|
||||
width: graphics::Size::ratio(0.5),
|
||||
height: graphics::Size::ratio(1.0),
|
||||
},
|
||||
);
|
||||
layout.add_child(
|
||||
Box::new(graphics::Text {
|
||||
text: "🔥🗣️🔥🗣️🔥🗣️".into(),
|
||||
font: self.emoji_font,
|
||||
font_id: 1,
|
||||
halign: graphics::Alignment::Middle,
|
||||
valign: graphics::Alignment::Middle,
|
||||
direction: Direction::LeftToRight,
|
||||
font_size: 128.0,
|
||||
script: Script::Latin,
|
||||
}),
|
||||
0,
|
||||
"b",
|
||||
graphics::Rect {
|
||||
left: graphics::Size::ratio(0.5),
|
||||
bottom: graphics::Size::ratio(0.0),
|
||||
width: graphics::Size::ratio(0.5),
|
||||
height: graphics::Size::ratio(1.0),
|
||||
},
|
||||
);
|
||||
let mut canvas = Canvas {
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
data: canvas,
|
||||
glyph_cache: Default::default(),
|
||||
};
|
||||
layout.render(
|
||||
&mut canvas,
|
||||
graphics::Rect {
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
width,
|
||||
height,
|
||||
},
|
||||
);
|
||||
}
|
||||
// rgba
|
||||
pub fn draw(&mut self, canvas: &mut [u8]) {
|
||||
let width = self.width;
|
||||
let height = self.height;
|
||||
canvas
|
||||
.chunks_exact_mut(4)
|
||||
.enumerate()
|
||||
.for_each(|(index, chunk)| {
|
||||
let x = ((index + self.shift as usize) % width as usize) as u32;
|
||||
let y = (index / width as usize) as u32;
|
||||
|
||||
let a = 0xFF;
|
||||
let r = u32::min(((width - x) * 0xFF) / width, ((height - y) * 0xFF) / height);
|
||||
let g = u32::min((x * 0xFF) / width, ((height - y) * 0xFF) / height);
|
||||
let b = u32::min(((width - x) * 0xFF) / width, (y * 0xFF) / height);
|
||||
|
||||
let array: &mut [u8; 4] = chunk.try_into().unwrap();
|
||||
*array = [
|
||||
r.try_into().unwrap_or(255),
|
||||
g.try_into().unwrap_or(255),
|
||||
b.try_into().unwrap_or(255),
|
||||
a.try_into().unwrap_or(255),
|
||||
];
|
||||
});
|
||||
self.render_text(canvas);
|
||||
self.shift = (self.shift + 1) % width;
|
||||
}
|
||||
}
|
25
src/main.rs
Normal file
25
src/main.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use std::{fs, io, path::Path};
|
||||
|
||||
use keyboard::Keyboard;
|
||||
use swash::FontRef;
|
||||
mod graphics;
|
||||
mod keyboard;
|
||||
mod wayland;
|
||||
|
||||
fn load_font(path: impl AsRef<Path>) -> Result<FontRef<'static>, io::Error> {
|
||||
let font_data = fs::read(path)?;
|
||||
let data = Box::leak(font_data.into_boxed_slice());
|
||||
FontRef::from_index(data, 0)
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid font file"))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let font = load_font("/home/user/.nix-profile/share/fonts/noto/NotoSans[wdth,wght].ttf")
|
||||
.expect("failed to load font");
|
||||
let font2 = load_font("/home/user/.nix-profile/share/fonts/noto/NotoColorEmoji.ttf")
|
||||
.expect("failed to load font");
|
||||
let font3 = load_font("/home/user/.nix-profile/share/fonts/noto/NotoSansArabic[wdth,wght].ttf")
|
||||
.expect("failed to load font");
|
||||
let kbd = Keyboard::new(font, font2, font3);
|
||||
wayland::run(kbd);
|
||||
}
|
350
src/wayland.rs
Normal file
350
src/wayland.rs
Normal file
|
@ -0,0 +1,350 @@
|
|||
use smithay_client_toolkit::{
|
||||
compositor::{CompositorHandler, CompositorState},
|
||||
delegate_compositor, delegate_layer, delegate_output, delegate_pointer, delegate_registry,
|
||||
delegate_seat, delegate_shm,
|
||||
output::{OutputHandler, OutputState},
|
||||
reexports::client::{
|
||||
globals::registry_queue_init,
|
||||
protocol::{wl_output, wl_pointer, wl_seat, wl_shm, wl_surface},
|
||||
Connection, QueueHandle,
|
||||
},
|
||||
registry::{ProvidesRegistryState, RegistryState},
|
||||
registry_handlers,
|
||||
seat::{
|
||||
pointer::{PointerEvent, PointerEventKind, PointerHandler},
|
||||
Capability, SeatHandler, SeatState,
|
||||
},
|
||||
shell::{
|
||||
wlr_layer::{
|
||||
Anchor, Layer, LayerShell, LayerShellHandler, LayerSurface, LayerSurfaceConfigure,
|
||||
},
|
||||
WaylandSurface,
|
||||
},
|
||||
shm::{slot::SlotPool, Shm, ShmHandler},
|
||||
};
|
||||
|
||||
use crate::keyboard::Keyboard;
|
||||
|
||||
pub fn run(keyboard: Keyboard<'static>) {
|
||||
let conn = Connection::connect_to_env().unwrap();
|
||||
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
|
||||
let qh = event_queue.handle();
|
||||
let compositor = CompositorState::bind(&globals, &qh).expect("wl_compositor is not available");
|
||||
let layer_shell = LayerShell::bind(&globals, &qh).expect("layer shell is not available");
|
||||
let shm = Shm::bind(&globals, &qh).expect("wl_shm is not available");
|
||||
let surface = compositor.create_surface(&qh);
|
||||
let layer =
|
||||
layer_shell.create_layer_surface(&qh, surface, Layer::Top, Some("simple_layer"), None);
|
||||
layer.set_anchor(Anchor::BOTTOM);
|
||||
let (w, h) = keyboard.size();
|
||||
layer.set_size(w, h);
|
||||
layer.commit();
|
||||
let pool = SlotPool::new(
|
||||
usize::try_from(w).unwrap() * usize::try_from(h).unwrap() * 4,
|
||||
&shm,
|
||||
)
|
||||
.expect("Failed to create pool");
|
||||
let mut simple_layer = KeyboardLayer {
|
||||
// Seats and outputs may be hotplugged at runtime, therefore we need to setup a registry state to
|
||||
// listen for seats and outputs.
|
||||
registry_state: RegistryState::new(&globals),
|
||||
seat_state: SeatState::new(&globals, &qh),
|
||||
output_state: OutputState::new(&globals, &qh),
|
||||
shm,
|
||||
|
||||
exit: false,
|
||||
first_configure: true,
|
||||
pool,
|
||||
width: 256,
|
||||
height: 256,
|
||||
shift: None,
|
||||
layer,
|
||||
pointer: None,
|
||||
keyboard,
|
||||
};
|
||||
loop {
|
||||
event_queue.blocking_dispatch(&mut simple_layer).unwrap();
|
||||
|
||||
if simple_layer.exit {
|
||||
println!("exiting example");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct KeyboardLayer {
|
||||
registry_state: RegistryState,
|
||||
seat_state: SeatState,
|
||||
output_state: OutputState,
|
||||
shm: Shm,
|
||||
|
||||
exit: bool,
|
||||
first_configure: bool,
|
||||
pool: SlotPool,
|
||||
width: u32,
|
||||
height: u32,
|
||||
shift: Option<u32>,
|
||||
layer: LayerSurface,
|
||||
pointer: Option<wl_pointer::WlPointer>,
|
||||
keyboard: Keyboard<'static>,
|
||||
}
|
||||
|
||||
impl KeyboardLayer {
|
||||
pub fn draw(&mut self, qh: &QueueHandle<Self>) {
|
||||
let width = self.width;
|
||||
let height = self.height;
|
||||
let stride = self.width as i32 * 4;
|
||||
|
||||
let (buffer, canvas) = self
|
||||
.pool
|
||||
.create_buffer(
|
||||
width as i32,
|
||||
height as i32,
|
||||
stride,
|
||||
wl_shm::Format::Argb8888,
|
||||
)
|
||||
.expect("create buffer");
|
||||
|
||||
// Draw to the window:
|
||||
{
|
||||
self.keyboard.set_size(width, height);
|
||||
self.keyboard.draw(canvas);
|
||||
// rgba->argb
|
||||
canvas.chunks_exact_mut(4).for_each(|chunk| {
|
||||
chunk.reverse();
|
||||
chunk.rotate_left(1);
|
||||
});
|
||||
}
|
||||
|
||||
// Damage the entire window
|
||||
self.layer
|
||||
.wl_surface()
|
||||
.damage_buffer(0, 0, width as i32, height as i32);
|
||||
|
||||
// Request our next frame
|
||||
self.layer
|
||||
.wl_surface()
|
||||
.frame(qh, self.layer.wl_surface().clone());
|
||||
|
||||
// Attach and commit to present.
|
||||
buffer
|
||||
.attach_to(self.layer.wl_surface())
|
||||
.expect("buffer attach");
|
||||
self.layer.commit();
|
||||
|
||||
// TODO save and reuse buffer when the window size is unchanged. This is especially
|
||||
// useful if you do damage tracking, since you don't need to redraw the undamaged parts
|
||||
// of the canvas.
|
||||
}
|
||||
}
|
||||
|
||||
impl CompositorHandler for KeyboardLayer {
|
||||
fn scale_factor_changed(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_surface: &wl_surface::WlSurface,
|
||||
_new_factor: i32,
|
||||
) {
|
||||
}
|
||||
|
||||
fn transform_changed(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_surface: &wl_surface::WlSurface,
|
||||
_new_transform: wl_output::Transform,
|
||||
) {
|
||||
}
|
||||
|
||||
fn frame(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
qh: &QueueHandle<Self>,
|
||||
_surface: &wl_surface::WlSurface,
|
||||
_time: u32,
|
||||
) {
|
||||
self.draw(qh);
|
||||
}
|
||||
|
||||
fn surface_enter(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_surface: &wl_surface::WlSurface,
|
||||
_output: &wl_output::WlOutput,
|
||||
) {
|
||||
}
|
||||
|
||||
fn surface_leave(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_surface: &wl_surface::WlSurface,
|
||||
_output: &wl_output::WlOutput,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputHandler for KeyboardLayer {
|
||||
fn output_state(&mut self) -> &mut OutputState {
|
||||
&mut self.output_state
|
||||
}
|
||||
|
||||
fn new_output(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_output: wl_output::WlOutput,
|
||||
) {
|
||||
}
|
||||
|
||||
fn update_output(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_output: wl_output::WlOutput,
|
||||
) {
|
||||
}
|
||||
|
||||
fn output_destroyed(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_output: wl_output::WlOutput,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl LayerShellHandler for KeyboardLayer {
|
||||
fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _layer: &LayerSurface) {
|
||||
self.exit = true;
|
||||
}
|
||||
|
||||
fn configure(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
qh: &QueueHandle<Self>,
|
||||
_layer: &LayerSurface,
|
||||
configure: LayerSurfaceConfigure,
|
||||
_serial: u32,
|
||||
) {
|
||||
if configure.new_size.0 == 0 || configure.new_size.1 == 0 {
|
||||
self.width = 256;
|
||||
self.height = 256;
|
||||
} else {
|
||||
self.width = configure.new_size.0;
|
||||
self.height = configure.new_size.1;
|
||||
}
|
||||
|
||||
// Initiate the first draw.
|
||||
if self.first_configure {
|
||||
self.first_configure = false;
|
||||
self.draw(qh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SeatHandler for KeyboardLayer {
|
||||
fn seat_state(&mut self) -> &mut SeatState {
|
||||
&mut self.seat_state
|
||||
}
|
||||
|
||||
fn new_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}
|
||||
|
||||
fn new_capability(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
qh: &QueueHandle<Self>,
|
||||
seat: wl_seat::WlSeat,
|
||||
capability: Capability,
|
||||
) {
|
||||
if capability == Capability::Pointer && self.pointer.is_none() {
|
||||
println!("Set pointer capability");
|
||||
let pointer = self
|
||||
.seat_state
|
||||
.get_pointer(qh, &seat)
|
||||
.expect("Failed to create pointer");
|
||||
self.pointer = Some(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_capability(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
_: wl_seat::WlSeat,
|
||||
capability: Capability,
|
||||
) {
|
||||
if capability == Capability::Pointer && self.pointer.is_some() {
|
||||
println!("Unset pointer capability");
|
||||
self.pointer.take().unwrap().release();
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}
|
||||
}
|
||||
|
||||
impl PointerHandler for KeyboardLayer {
|
||||
fn pointer_frame(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_pointer: &wl_pointer::WlPointer,
|
||||
events: &[PointerEvent],
|
||||
) {
|
||||
for event in events {
|
||||
// Ignore events for other surfaces
|
||||
if &event.surface != self.layer.wl_surface() {
|
||||
continue;
|
||||
}
|
||||
match event.kind {
|
||||
PointerEventKind::Enter { .. } => {
|
||||
println!("Pointer entered @{:?}", event.position);
|
||||
}
|
||||
PointerEventKind::Leave { .. } => {
|
||||
println!("Pointer left");
|
||||
}
|
||||
PointerEventKind::Motion { .. } => {}
|
||||
PointerEventKind::Press { button, .. } => {
|
||||
println!("Press {:x} @ {:?}", button, event.position);
|
||||
self.shift = self.shift.xor(Some(0));
|
||||
}
|
||||
PointerEventKind::Release { button, .. } => {
|
||||
println!("Release {:x} @ {:?}", button, event.position);
|
||||
}
|
||||
PointerEventKind::Axis {
|
||||
horizontal,
|
||||
vertical,
|
||||
..
|
||||
} => {
|
||||
println!("Scroll H:{horizontal:?}, V:{vertical:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShmHandler for KeyboardLayer {
|
||||
fn shm_state(&mut self) -> &mut Shm {
|
||||
&mut self.shm
|
||||
}
|
||||
}
|
||||
|
||||
delegate_compositor!(KeyboardLayer);
|
||||
delegate_output!(KeyboardLayer);
|
||||
delegate_shm!(KeyboardLayer);
|
||||
|
||||
delegate_seat!(KeyboardLayer);
|
||||
delegate_pointer!(KeyboardLayer);
|
||||
|
||||
delegate_layer!(KeyboardLayer);
|
||||
|
||||
delegate_registry!(KeyboardLayer);
|
||||
|
||||
impl ProvidesRegistryState for KeyboardLayer {
|
||||
fn registry(&mut self) -> &mut RegistryState {
|
||||
&mut self.registry_state
|
||||
}
|
||||
registry_handlers![OutputState, SeatState];
|
||||
}
|
Loading…
Reference in a new issue