Compare commits

..

2 Commits

Author SHA1 Message Date
6c3ce607e0 pref: 针对 HiDPI 屏幕捕获的优化。 2023-04-05 12:25:14 +08:00
3ec983cd95 boardcast + interval tick. 2023-04-03 23:19:45 +08:00
12 changed files with 703 additions and 490 deletions

301
src-tauri/Cargo.lock generated
View File

@ -34,9 +34,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.69" version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]] [[package]]
name = "async-channel" name = "async-channel"
@ -70,7 +70,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
@ -135,9 +135,9 @@ dependencies = [
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09"
dependencies = [ dependencies = [
"memchr", "memchr",
"serde", "serde",
@ -182,7 +182,7 @@ checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
@ -228,9 +228,9 @@ dependencies = [
[[package]] [[package]]
name = "cfg-expr" name = "cfg-expr"
version = "0.11.0" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0357a6402b295ca3a86bc148e84df46c02e41f41fef186bda662557ef6328aa" checksum = "a35b255461940a32985c627ce82900867c61db1659764d3675ea81963f72a4c6"
dependencies = [ dependencies = [
"smallvec", "smallvec",
] ]
@ -243,9 +243,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "cmake" name = "cmake"
version = "0.1.49" version = "0.1.50"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
dependencies = [ dependencies = [
"cc", "cc",
] ]
@ -268,9 +268,9 @@ dependencies = [
[[package]] [[package]]
name = "cocoa-foundation" name = "cocoa-foundation"
version = "0.1.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"block", "block",
@ -361,9 +361,9 @@ dependencies = [
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.5" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -420,7 +420,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"smallvec", "smallvec",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -430,7 +430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
dependencies = [ dependencies = [
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -440,7 +440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [ dependencies = [
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -464,7 +464,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -475,7 +475,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -488,7 +488,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustc_version", "rustc_version",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -599,13 +599,13 @@ dependencies = [
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.2.8" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0"
dependencies = [ dependencies = [
"errno-dragonfly", "errno-dragonfly",
"libc", "libc",
"winapi", "windows-sys 0.45.0",
] ]
[[package]] [[package]]
@ -651,7 +651,7 @@ checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall", "redox_syscall 0.2.16",
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
@ -707,9 +707,9 @@ dependencies = [
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -722,9 +722,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@ -732,15 +732,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@ -749,32 +749,32 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.13",
] ]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
[[package]] [[package]]
name = "futures-timer" name = "futures-timer"
@ -784,9 +784,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -848,7 +848,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
@ -865,7 +865,7 @@ dependencies = [
"libc", "libc",
"pango-sys", "pango-sys",
"pkg-config", "pkg-config",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
@ -877,7 +877,7 @@ dependencies = [
"gdk-sys", "gdk-sys",
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
"x11", "x11",
] ]
@ -896,9 +896,9 @@ dependencies = [
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.6" version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check", "version_check",
@ -952,7 +952,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
"winapi", "winapi",
] ]
@ -978,9 +978,9 @@ dependencies = [
[[package]] [[package]]
name = "glib-macros" name = "glib-macros"
version = "0.15.11" version = "0.15.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"heck 0.4.1", "heck 0.4.1",
@ -988,7 +988,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -998,7 +998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4"
dependencies = [ dependencies = [
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
@ -1028,7 +1028,7 @@ checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
@ -1069,21 +1069,21 @@ dependencies = [
"gobject-sys", "gobject-sys",
"libc", "libc",
"pango-sys", "pango-sys",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
name = "gtk3-macros" name = "gtk3-macros"
version = "0.15.4" version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9" checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"proc-macro-crate", "proc-macro-crate",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -1139,7 +1139,7 @@ dependencies = [
"markup5ever", "markup5ever",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -1211,9 +1211,9 @@ dependencies = [
[[package]] [[package]]
name = "image" name = "image"
version = "0.24.5" version = "0.24.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"byteorder", "byteorder",
@ -1224,9 +1224,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.2" version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -1252,19 +1252,20 @@ dependencies = [
[[package]] [[package]]
name = "io-lifetimes" name = "io-lifetimes"
version = "1.0.6" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
dependencies = [ dependencies = [
"hermit-abi 0.3.1",
"libc", "libc",
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.4" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8"
dependencies = [ dependencies = [
"hermit-abi 0.3.1", "hermit-abi 0.3.1",
"io-lifetimes", "io-lifetimes",
@ -1382,9 +1383,9 @@ dependencies = [
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.1.4" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -1608,7 +1609,7 @@ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -1647,20 +1648,20 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]] [[package]]
name = "open" name = "open"
version = "3.4.0" version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21ecf2487e799604735754d2c5896106785987b441b5aee58f242e4d4963179a" checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8"
dependencies = [ dependencies = [
"pathdiff", "pathdiff",
"windows-sys 0.42.0",
] ]
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.83" version = "0.9.84"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b" checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
dependencies = [ dependencies = [
"autocfg",
"cc", "cc",
"libc", "libc",
"pkg-config", "pkg-config",
@ -1721,14 +1722,14 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
name = "paris" name = "paris"
version = "1.5.13" version = "1.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eaf2319cd71dd9ff38c72bebde61b9ea657134abcf26ae4205f54f772a32810" checksum = "8fecab3723493c7851f292cb060f3ee1c42f19b8d749345d0d7eaf3fd19aa62d"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
@ -1748,7 +1749,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall", "redox_syscall 0.2.16",
"smallvec", "smallvec",
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
@ -1834,7 +1835,7 @@ dependencies = [
"proc-macro-hack", "proc-macro-hack",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -1848,7 +1849,7 @@ dependencies = [
"proc-macro-hack", "proc-macro-hack",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -1889,14 +1890,14 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]] [[package]]
name = "plist" name = "plist"
version = "1.4.2" version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffac6a51110e97610dd3ac73e34a65b27e56a1e305df41bad1f616d8e1cb22f4" checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
dependencies = [ dependencies = [
"base64 0.21.0", "base64 0.21.0",
"indexmap", "indexmap",
"line-wrap", "line-wrap",
"quick-xml 0.27.1", "quick-xml 0.28.1",
"serde", "serde",
"time", "time",
] ]
@ -1944,7 +1945,7 @@ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
"version_check", "version_check",
] ]
@ -1967,9 +1968,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.52" version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -1985,9 +1986,9 @@ dependencies = [
[[package]] [[package]]
name = "quick-xml" name = "quick-xml"
version = "0.27.1" version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffc053f057dd768a56f62cd7e434c42c831d296968997e9ac1f76ea7c2d14c41" checksum = "e5c1a97b1bc42b1d550bfb48d4262153fe400a12bab1511821736f7eac76d7e2"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -2084,9 +2085,9 @@ dependencies = [
[[package]] [[package]]
name = "raw-window-handle" name = "raw-window-handle"
version = "0.5.1" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f851a03551ceefd30132e447f07f96cb7011d6b658374f3aed847333adb5559" checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
@ -2097,6 +2098,15 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.4.3" version = "0.4.3"
@ -2104,15 +2114,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [ dependencies = [
"getrandom 0.2.8", "getrandom 0.2.8",
"redox_syscall", "redox_syscall 0.2.16",
"thiserror", "thiserror",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.7.1" version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -2130,9 +2140,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.28" version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
@ -2145,9 +2155,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.36.9" version = "0.37.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" checksum = "d097081ed288dfe45699b72f5b5d648e5f15d64d900c7080273baa20c16a6849"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@ -2227,29 +2237,29 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.156" version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.156" version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.13",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.94" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
dependencies = [ dependencies = [
"itoa 1.0.6", "itoa 1.0.6",
"ryu", "ryu",
@ -2258,13 +2268,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.11" version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "395627de918015623b32e7669714206363a7fc00382bf477e72c1f7533e8eafc" checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.13",
] ]
[[package]] [[package]]
@ -2295,7 +2305,7 @@ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -2317,7 +2327,7 @@ checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -2476,6 +2486,17 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "syn"
version = "2.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "system-deps" name = "system-deps"
version = "5.0.0" version = "5.0.0"
@ -2491,14 +2512,14 @@ dependencies = [
[[package]] [[package]]
name = "system-deps" name = "system-deps"
version = "6.0.3" version = "6.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2955b1fe31e1fa2fbd1976b71cc69a606d7d4da16f6de3333d0c92d51419aeff" checksum = "555fc8147af6256f3931a36bb83ad0023240ce9cf2b319dec8236fd1f220b05f"
dependencies = [ dependencies = [
"cfg-expr 0.11.0", "cfg-expr 0.14.0",
"heck 0.4.1", "heck 0.4.1",
"pkg-config", "pkg-config",
"toml 0.5.11", "toml 0.7.3",
"version-compare 0.1.1", "version-compare 0.1.1",
] ]
@ -2657,7 +2678,7 @@ dependencies = [
"heck 0.4.1", "heck 0.4.1",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
"tauri-codegen", "tauri-codegen",
"tauri-utils", "tauri-utils",
] ]
@ -2732,15 +2753,15 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.4.0" version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
"redox_syscall", "redox_syscall 0.3.5",
"rustix", "rustix",
"windows-sys 0.42.0", "windows-sys 0.45.0",
] ]
[[package]] [[package]]
@ -2769,6 +2790,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"color_space", "color_space",
"core-foundation",
"core-graphics", "core-graphics",
"display-info", "display-info",
"env_logger", "env_logger",
@ -2796,22 +2818,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.39" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.39" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.13",
] ]
[[package]] [[package]]
@ -2868,14 +2890,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.26.0" version = "1.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
"libc", "libc",
"memchr",
"mio", "mio",
"num_cpus", "num_cpus",
"parking_lot", "parking_lot",
@ -2888,13 +2909,13 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.8.2" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.13",
] ]
[[package]] [[package]]
@ -2929,9 +2950,9 @@ dependencies = [
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.19.7" version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274" checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"serde", "serde",
@ -2960,7 +2981,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -3019,9 +3040,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.11" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
@ -3188,7 +3209,7 @@ dependencies = [
"pango-sys", "pango-sys",
"pkg-config", "pkg-config",
"soup2-sys", "soup2-sys",
"system-deps 6.0.3", "system-deps 6.0.4",
] ]
[[package]] [[package]]
@ -3211,7 +3232,7 @@ checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -3305,7 +3326,7 @@ version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7"
dependencies = [ dependencies = [
"syn", "syn 1.0.109",
"windows-tokens", "windows-tokens",
] ]
@ -3434,9 +3455,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.3.6" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966" checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]

View File

@ -31,6 +31,7 @@ toml = "0.7.3"
paho-mqtt = "0.12.1" paho-mqtt = "0.12.1"
time = {version="0.3.20", features= ["formatting"] } time = {version="0.3.20", features= ["formatting"] }
itertools = "0.10.5" itertools = "0.10.5"
core-foundation = "0.9.3"
[features] [features]
# this feature is used for production builds or when `devPath` points to the filesystem # this feature is used for production builds or when `devPath` points to the filesystem

View File

@ -21,6 +21,8 @@ impl ConfigManager {
let configs = LedStripConfigGroup::read_config().await.unwrap(); let configs = LedStripConfigGroup::read_config().await.unwrap();
let (config_update_sender, config_update_receiver) = let (config_update_sender, config_update_receiver) =
tokio::sync::watch::channel(configs.clone()); tokio::sync::watch::channel(configs.clone());
config_update_sender.send(configs.clone()).unwrap();
ConfigManager { ConfigManager {
config: Arc::new(RwLock::new(configs)), config: Arc::new(RwLock::new(configs)),
config_update_receiver, config_update_receiver,

View File

@ -1,25 +1,31 @@
use std::{sync::Arc, time::Duration}; use std::{collections::HashMap, sync::Arc, time::Duration};
use paris::{info, warn}; use paris::warn;
use tauri::async_runtime::{Mutex, RwLock}; use tauri::async_runtime::RwLock;
use tokio::{sync::watch, time::sleep}; use tokio::{
sync::{broadcast, watch},
time::sleep,
};
use crate::{ use crate::{
ambient_light::{config, ConfigManager}, ambient_light::{config, ConfigManager},
rpc::MqttRpc, rpc::MqttRpc,
screenshot::Screenshot, screenshot::LedSamplePoints,
screenshot_manager::ScreenshotManager, led_color::LedColor, screenshot_manager::{self, ScreenshotManager},
}; };
use itertools::Itertools; use itertools::Itertools;
use super::{LedStripConfigGroup, SamplePointConfig}; use super::{LedStripConfigGroup, SamplePointConfig, SamplePointMapper};
pub struct LedColorsPublisher { pub struct LedColorsPublisher {
sorted_colors_rx: Arc<RwLock<watch::Receiver<Vec<u8>>>>, sorted_colors_rx: Arc<RwLock<watch::Receiver<Vec<u8>>>>,
sorted_colors_tx: Arc<RwLock<watch::Sender<Vec<u8>>>>, sorted_colors_tx: Arc<RwLock<watch::Sender<Vec<u8>>>>,
colors_rx: Arc<RwLock<watch::Receiver<Vec<LedColor>>>>, colors_rx: Arc<RwLock<watch::Receiver<Vec<u8>>>>,
colors_tx: Arc<RwLock<watch::Sender<Vec<LedColor>>>>, colors_tx: Arc<RwLock<watch::Sender<Vec<u8>>>>,
display_colors_rx: Arc<RwLock<broadcast::Receiver<(u32, Vec<u8>)>>>,
display_colors_tx: Arc<RwLock<broadcast::Sender<(u32, Vec<u8>)>>>,
inner_tasks_version: Arc<RwLock<usize>>,
} }
impl LedColorsPublisher { impl LedColorsPublisher {
@ -29,6 +35,7 @@ impl LedColorsPublisher {
let (sorted_tx, sorted_rx) = watch::channel(Vec::new()); let (sorted_tx, sorted_rx) = watch::channel(Vec::new());
let (tx, rx) = watch::channel(Vec::new()); let (tx, rx) = watch::channel(Vec::new());
let (display_colors_tx, display_colors_rx) = broadcast::channel(8);
LED_COLORS_PUBLISHER_GLOBAL LED_COLORS_PUBLISHER_GLOBAL
.get_or_init(|| async { .get_or_init(|| async {
@ -37,91 +44,289 @@ impl LedColorsPublisher {
sorted_colors_tx: Arc::new(RwLock::new(sorted_tx)), sorted_colors_tx: Arc::new(RwLock::new(sorted_tx)),
colors_rx: Arc::new(RwLock::new(rx)), colors_rx: Arc::new(RwLock::new(rx)),
colors_tx: Arc::new(RwLock::new(tx)), colors_tx: Arc::new(RwLock::new(tx)),
display_colors_rx: Arc::new(RwLock::new(display_colors_rx)),
display_colors_tx: Arc::new(RwLock::new(display_colors_tx)),
inner_tasks_version: Arc::new(RwLock::new(0)),
} }
}) })
.await .await
} }
pub fn start(&self) { fn start_one_display_colors_fetcher(
let sorted_colors_tx = self.sorted_colors_tx.clone(); &self,
let colors_tx = self.colors_tx.clone(); display_id: u32,
sample_points: Vec<Vec<LedSamplePoints>>,
) {
let display_colors_tx = self.display_colors_tx.clone();
let internal_tasks_version = self.inner_tasks_version.clone();
tokio::spawn(async move { tokio::spawn(async move {
let display_colors_tx = display_colors_tx.read().await.clone();
let colors = screenshot_manager::get_display_colors(display_id, &sample_points);
if let Err(err) = colors {
warn!("Failed to get colors: {}", err);
return;
}
let mut start: tokio::time::Instant = tokio::time::Instant::now();
let mut interval = tokio::time::interval(Duration::from_millis(66));
let init_version = internal_tasks_version.read().await.clone();
loop { loop {
interval.tick().await;
tokio::time::sleep(Duration::from_millis(1)).await;
if internal_tasks_version.read().await.clone() != init_version {
log::info!(
"inner task version changed, stop. {} != {}",
internal_tasks_version.read().await.clone(),
init_version
);
break;
}
// log::info!("tick: {}ms", start.elapsed().as_millis());
start = tokio::time::Instant::now();
let colors = screenshot_manager::get_display_colors(display_id, &sample_points);
if let Err(err) = colors {
warn!("Failed to get colors: {}", err);
sleep(Duration::from_millis(100)).await;
continue;
}
let colors = colors.unwrap();
let color_len = colors.len();
match display_colors_tx.send((
display_id,
colors
.into_iter()
.map(|color| color.get_rgb())
.flatten()
.collect::<Vec<_>>(),
)) {
Ok(_) => {
// log::info!("sent colors: {:?}", color_len);
}
Err(err) => {
warn!("Failed to send display_colors: {}", err);
}
};
}
});
}
fn start_all_colors_worker(&self, display_ids: Vec<u32>, mappers: Vec<SamplePointMapper>) {
let sorted_colors_tx = self.sorted_colors_tx.clone();
let colors_tx = self.colors_tx.clone();
let display_colors_rx = self.display_colors_rx.clone();
tokio::spawn(async move {
for _ in 0..10 {
let mut rx = display_colors_rx.read().await.resubscribe();
let sorted_colors_tx = sorted_colors_tx.write().await; let sorted_colors_tx = sorted_colors_tx.write().await;
let colors_tx = colors_tx.write().await; let colors_tx = colors_tx.write().await;
let screenshot_manager = ScreenshotManager::global().await;
let config_manager = ConfigManager::global().await; let mut all_colors: Vec<Option<Vec<u8>>> = vec![None; display_ids.len()];
let config_receiver = config_manager.clone_config_update_receiver(); let mut start: tokio::time::Instant = tokio::time::Instant::now();
let configs = config_receiver.borrow().clone();
let configs = Self::get_colors_configs(&configs).await;
let mut some_screenshot_receiver_is_none = false;
log::info!("start all_colors_worker");
loop { loop {
let mut screenshots = Vec::new(); // log::info!("display_colors_rx changed");
let color_info = rx.recv().await;
for rx in configs.screenshot_receivers.to_owned() { if let Err(err) = color_info {
let mut rx = rx.lock_owned().await; match err {
if rx.is_none() { broadcast::error::RecvError::Closed => {
some_screenshot_receiver_is_none = true; break;
warn!("screenshot receiver is none"); }
broadcast::error::RecvError::Lagged(_) => {
warn!("display_colors_rx lagged");
continue;
}
}
}
let (display_id, colors) = color_info.unwrap();
let index = display_ids.iter().position(|id| *id == display_id);
if index.is_none() {
warn!("display id not found");
continue; continue;
} }
let rx = rx.as_mut().unwrap(); all_colors[index.unwrap()] = Some(colors);
if let Err(err) = rx.changed().await { if all_colors.iter().all(|color| color.is_some()) {
warn!("rx changed error: {}", err); let flatten_colors = all_colors
continue; .clone()
.into_iter()
.flat_map(|c| c.unwrap())
.collect::<Vec<_>>();
match colors_tx.send(flatten_colors.clone()) {
Ok(_) => {}
Err(err) => {
warn!("Failed to send colors: {}", err);
} }
// log::info!("screenshot updated"); };
let screenshot = rx.borrow().clone();
screenshots.push(screenshot);
}
let colors = screenshot_manager
.get_all_colors(&configs.sample_point_groups, &screenshots)
.await;
let sorted_colors = let sorted_colors =
ScreenshotManager::get_sorted_colors(&colors, &configs.mappers).await; ScreenshotManager::get_sorted_colors(&flatten_colors, &mappers);
match colors_tx.send(colors) {
Ok(_) => {
// log::info!("colors updated");
}
Err(_) => {
warn!("colors update failed");
}
}
match sorted_colors_tx.send(sorted_colors) { match sorted_colors_tx.send(sorted_colors) {
Ok(_) => { Ok(_) => {}
// log::info!("colors updated"); Err(err) => {
warn!("Failed to send sorted colors: {}", err);
} }
Err(_) => { };
warn!("colors update failed"); log::info!("tick: {}ms", start.elapsed().as_millis());
} start = tokio::time::Instant::now();
}
if some_screenshot_receiver_is_none {
info!("some screenshot receiver is none. reload.");
sleep(Duration::from_millis(1000)).await;
break;
}
if config_receiver.has_changed().unwrap_or(true) {
info!("config changed. reload.");
sleep(Duration::from_millis(100)).await;
break;
} }
} }
} }
}); });
}
pub fn start(&self) {
let inner_tasks_version = self.inner_tasks_version.clone();
tokio::spawn(async move {
let publisher = Self::global().await;
let mut inner_tasks_version = inner_tasks_version.write().await;
*inner_tasks_version = inner_tasks_version.overflowing_add(1).0;
let config_manager = ConfigManager::global().await;
let mut config_receiver = config_manager.clone_config_update_receiver();
log::info!("waiting for config update...");
while config_receiver.changed().await.is_ok() {
log::info!("config updated, restart inner tasks...");
let configs = config_receiver.borrow().clone();
let configs = Self::get_colors_configs(&configs).await;
if let Err(err) = configs {
warn!("Failed to get configs: {}", err);
sleep(Duration::from_millis(100)).await;
continue;
}
let configs = configs.unwrap();
for sample_point_group in configs.sample_point_groups.clone() {
let display_id = sample_point_group.display_id;
let sample_points = sample_point_group.points;
publisher.start_one_display_colors_fetcher(display_id, sample_points);
}
let display_ids = configs.sample_point_groups;
publisher.start_all_colors_worker(
display_ids.iter().map(|c| c.display_id).collect(),
configs.mappers,
);
break;
}
});
// tokio::spawn(async move {
// loop {
// let sorted_colors_tx = sorted_colors_tx.write().await;
// let colors_tx = colors_tx.write().await;
// let screenshot_manager = ScreenshotManager::global().await;
// let config_manager = ConfigManager::global().await;
// let config_receiver = config_manager.clone_config_update_receiver();
// let configs = config_receiver.borrow().clone();
// let configs = Self::get_colors_configs(&configs).await;
// if let Err(err) = configs {
// warn!("Failed to get configs: {}", err);
// sleep(Duration::from_millis(100)).await;
// continue;
// }
// let configs = configs.unwrap();
// let mut merged_screenshot_receiver =
// screenshot_manager.clone_merged_screenshot_rx().await;
// let mut screenshots = HashMap::new();
// // let mut start = tokio::time::Instant::now();
// loop {
// let screenshot = merged_screenshot_receiver.recv().await;
// if let Err(err) = screenshot {
// match err {
// tokio::sync::broadcast::error::RecvError::Closed => {
// warn!("closed");
// continue;
// }
// tokio::sync::broadcast::error::RecvError::Lagged(_) => {
// warn!("lagged");
// continue;
// }
// }
// }
// let screenshot = screenshot.unwrap();
// // log::info!("got screenshot: {:?}", screenshot.display_id);
// screenshots.insert(screenshot.display_id, screenshot);
// if screenshots.len() == configs.sample_point_groups.len() {
// // log::info!("{}", start.elapsed().as_millis().to_string());
// {
// let screenshots = configs
// .sample_point_groups
// .iter()
// .map(|strip| screenshots.get(&strip.display_id).unwrap())
// .collect::<Vec<_>>();
// let colors = screenshot_manager
// .get_all_colors(&configs.sample_point_groups, &screenshots)
// .await;
// let sorted_colors =
// ScreenshotManager::get_sorted_colors(&colors, &configs.mappers)
// .await;
// match colors_tx.send(colors) {
// Ok(_) => {
// // log::info!("colors updated");
// }
// Err(_) => {
// warn!("colors update failed");
// }
// }
// match sorted_colors_tx.send(sorted_colors) {
// Ok(_) => {
// // log::info!("colors updated");
// }
// Err(_) => {
// warn!("colors update failed");
// }
// }
// }
// // screenshots.clear();
// // start = tokio::time::Instant::now();
// }
// }
// }
// });
let rx = self.sorted_colors_rx.clone(); let rx = self.sorted_colors_rx.clone();
tokio::spawn(async move { tokio::spawn(async move {
@ -139,7 +344,7 @@ impl LedColorsPublisher {
match Self::send_colors(colors).await { match Self::send_colors(colors).await {
Ok(_) => { Ok(_) => {
log::info!("colors sent. len: {}", len); // log::info!("colors sent. len: {}", len);
} }
Err(err) => { Err(err) => {
warn!("colors send failed: {}", err); warn!("colors send failed: {}", err);
@ -158,12 +363,11 @@ impl LedColorsPublisher {
pub async fn clone_sorted_colors_receiver(&self) -> watch::Receiver<Vec<u8>> { pub async fn clone_sorted_colors_receiver(&self) -> watch::Receiver<Vec<u8>> {
self.sorted_colors_rx.read().await.clone() self.sorted_colors_rx.read().await.clone()
} }
pub async fn get_colors_configs(
pub async fn get_colors_configs(configs: &LedStripConfigGroup) -> AllColorConfig { configs: &LedStripConfigGroup,
) -> anyhow::Result<AllColorConfig> {
let screenshot_manager = ScreenshotManager::global().await; let screenshot_manager = ScreenshotManager::global().await;
let channels = screenshot_manager.channels.read().await;
let display_ids = configs let display_ids = configs
.strips .strips
.iter() .iter()
@ -173,67 +377,83 @@ impl LedColorsPublisher {
let mappers = configs.mappers.clone(); let mappers = configs.mappers.clone();
let mut local_rx_list = Vec::new();
let mut colors_configs = Vec::new(); let mut colors_configs = Vec::new();
for display_id in display_ids.clone().iter() { let mut merged_screenshot_receiver = screenshot_manager.clone_merged_screenshot_rx().await;
let display_id = *display_id;
let channel = channels.get(&display_id); let mut screenshots = HashMap::new();
let channel = match channel {
Some(channel) => Some(channel.clone()),
None => None,
};
local_rx_list.push(Arc::new(Mutex::new(channel.clone())));
loop {
log::info!("waiting merged screenshot...");
let screenshot = merged_screenshot_receiver.recv().await;
if let Err(err) = screenshot {
match err {
tokio::sync::broadcast::error::RecvError::Closed => {
warn!("closed");
continue;
}
tokio::sync::broadcast::error::RecvError::Lagged(_) => {
warn!("lagged");
continue;
}
}
}
let screenshot = screenshot.unwrap();
// log::info!("got screenshot: {:?}", screenshot.display_id);
screenshots.insert(screenshot.display_id, screenshot);
if screenshots.len() == display_ids.len() {
for display_id in display_ids {
let led_strip_configs: Vec<_> = configs let led_strip_configs: Vec<_> = configs
.strips .strips
.iter() .iter()
.filter(|c| c.display_id == display_id) .filter(|c| c.display_id == display_id)
.collect(); .collect();
let rx = channel;
if rx.is_none() {
warn!("no channel for display_id: {}", display_id);
continue;
}
if led_strip_configs.len() == 0 { if led_strip_configs.len() == 0 {
warn!("no led strip config for display_id: {}", display_id); warn!("no led strip config for display_id: {}", display_id);
continue; continue;
} }
let mut rx = rx.unwrap().to_owned();
if rx.changed().await.is_ok() { let screenshot = screenshots.get(&display_id).unwrap();
let screenshot = rx.borrow().clone(); log::debug!("screenshot updated: {:?}", display_id);
log::info!("screenshot updated: {:?}", display_id);
let points: Vec<_> = led_strip_configs let points: Vec<_> = led_strip_configs
.iter() .iter()
.map(|config| screenshot.get_sample_points(&config)) .map(|config| screenshot.get_sample_points(&config))
.flatten()
.collect(); .collect();
let colors_config = config::SamplePointConfig { display_id, points }; let colors_config = DisplaySamplePointGroup { display_id, points };
colors_configs.push(colors_config); colors_configs.push(colors_config);
} }
}
return AllColorConfig { return Ok(AllColorConfig {
sample_point_groups: colors_configs, sample_point_groups: colors_configs,
mappers, mappers,
screenshot_receivers: local_rx_list, // screenshot_receivers: local_rx_list,
}; });
}
}
} }
pub async fn clone_colors_receiver(&self) -> watch::Receiver<Vec<LedColor>> { pub async fn clone_colors_receiver(&self) -> watch::Receiver<Vec<u8>> {
self.colors_rx.read().await.clone() self.colors_rx.read().await.clone()
} }
} }
#[derive(Debug)]
pub struct AllColorConfig { pub struct AllColorConfig {
pub sample_point_groups: Vec<SamplePointConfig>, pub sample_point_groups: Vec<DisplaySamplePointGroup>,
pub mappers: Vec<config::SamplePointMapper>, pub mappers: Vec<config::SamplePointMapper>,
pub screenshot_receivers: Vec<Arc<Mutex<Option<watch::Receiver<Screenshot>>>>>, // pub screenshot_receivers: Vec<watch::Receiver<Screenshot>>,
}
#[derive(Debug, Clone)]
pub struct DisplaySamplePointGroup {
pub display_id: u32,
pub points: Vec<Vec<LedSamplePoints>>,
} }

View File

@ -57,21 +57,6 @@ fn list_display_info() -> Result<String, String> {
Ok(json_str) Ok(json_str)
} }
#[tauri::command]
async fn subscribe_encoded_screenshot_updated(
window: tauri::Window,
display_id: u32,
) -> Result<(), String> {
let screenshot_manager = ScreenshotManager::global().await;
screenshot_manager
.subscribe_encoded_screenshot_updated(window, display_id)
.await
.map_err(|err| {
error!("subscribe_encoded_screenshot_updated: {}", err);
err.to_string()
})
}
#[tauri::command] #[tauri::command]
async fn read_led_strip_configs() -> Result<LedStripConfigGroup, String> { async fn read_led_strip_configs() -> Result<LedStripConfigGroup, String> {
let config = ambient_light::LedStripConfigGroup::read_config() let config = ambient_light::LedStripConfigGroup::read_config()
@ -121,7 +106,7 @@ async fn get_one_edge_colors(
if let Some(rx) = channels.get(&display_id) { if let Some(rx) = channels.get(&display_id) {
let rx = rx.clone(); let rx = rx.clone();
let screenshot = rx.borrow().clone(); let screenshot = rx.borrow().clone();
let bytes = screenshot.bytes.read().await; let bytes = screenshot.bytes.read().await.to_owned();
let colors = let colors =
Screenshot::get_one_edge_colors(&sample_points, &bytes, screenshot.bytes_per_row); Screenshot::get_one_edge_colors(&sample_points, &bytes, screenshot.bytes_per_row);
Ok(colors) Ok(colors)
@ -201,7 +186,6 @@ async fn main() {
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
greet, greet,
list_display_info, list_display_info,
subscribe_encoded_screenshot_updated,
read_led_strip_configs, read_led_strip_configs,
write_led_strip_configs, write_led_strip_configs,
get_led_strips_sample_points, get_led_strips_sample_points,

View File

@ -1,8 +1,9 @@
use std::iter; use std::cell::RefCell;
use std::{iter, cell::Ref};
use std::sync::Arc; use std::sync::Arc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::async_runtime::RwLock; use tauri::async_runtime::{RwLock, Mutex};
use crate::{ambient_light::LedStripConfig, led_color::LedColor}; use crate::{ambient_light::LedStripConfig, led_color::LedColor};
@ -14,9 +15,10 @@ pub struct Screenshot {
pub bytes_per_row: usize, pub bytes_per_row: usize,
pub bytes: Arc<RwLock<Vec<u8>>>, pub bytes: Arc<RwLock<Vec<u8>>>,
pub scale_factor: f32, pub scale_factor: f32,
pub sample_points: ScreenSamplePoints,
} }
static SINGLE_AXIS_POINTS: usize = 5;
impl Screenshot { impl Screenshot {
pub fn new( pub fn new(
display_id: u32, display_id: u32,
@ -25,7 +27,6 @@ impl Screenshot {
bytes_per_row: usize, bytes_per_row: usize,
bytes: Vec<u8>, bytes: Vec<u8>,
scale_factor: f32, scale_factor: f32,
sample_points: ScreenSamplePoints,
) -> Self { ) -> Self {
Self { Self {
display_id, display_id,
@ -34,7 +35,6 @@ impl Screenshot {
bytes_per_row, bytes_per_row,
bytes: Arc::new(RwLock::new(bytes)), bytes: Arc::new(RwLock::new(bytes)),
scale_factor, scale_factor,
sample_points,
} }
} }
@ -44,10 +44,10 @@ impl Screenshot {
match config.border { match config.border {
crate::ambient_light::Border::Top => { crate::ambient_light::Border::Top => {
Self::get_one_edge_sample_points(height / 8, width, config.len, 5) Self::get_one_edge_sample_points(height / 18, width, config.len, SINGLE_AXIS_POINTS)
} }
crate::ambient_light::Border::Bottom => { crate::ambient_light::Border::Bottom => {
let points = Self::get_one_edge_sample_points(height / 9, width, config.len, 5); let points = Self::get_one_edge_sample_points(height / 18, width, config.len, SINGLE_AXIS_POINTS);
points points
.into_iter() .into_iter()
.map(|groups| -> Vec<Point> { .map(|groups| -> Vec<Point> {
@ -56,7 +56,7 @@ impl Screenshot {
.collect() .collect()
} }
crate::ambient_light::Border::Left => { crate::ambient_light::Border::Left => {
let points = Self::get_one_edge_sample_points(width / 16, height, config.len, 5); let points = Self::get_one_edge_sample_points(width / 32, height, config.len, SINGLE_AXIS_POINTS);
points points
.into_iter() .into_iter()
.map(|groups| -> Vec<Point> { .map(|groups| -> Vec<Point> {
@ -65,7 +65,7 @@ impl Screenshot {
.collect() .collect()
} }
crate::ambient_light::Border::Right => { crate::ambient_light::Border::Right => {
let points = Self::get_one_edge_sample_points(width / 16, height, config.len, 5); let points = Self::get_one_edge_sample_points(width / 32, height, config.len, SINGLE_AXIS_POINTS);
points points
.into_iter() .into_iter()
.map(|groups| -> Vec<Point> { .map(|groups| -> Vec<Point> {
@ -112,46 +112,6 @@ impl Screenshot {
.collect() .collect()
} }
pub async fn get_colors(&self) -> DisplayColorsOfLedStrips {
let bitmap = self.bytes.read().await;
let top =
Self::get_one_edge_colors(&self.sample_points.top, bitmap.as_ref(), self.bytes_per_row)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
let bottom = Self::get_one_edge_colors(
&self.sample_points.bottom,
bitmap.as_ref(),
self.bytes_per_row,
)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
let left = Self::get_one_edge_colors(
&self.sample_points.left,
bitmap.as_ref(),
self.bytes_per_row,
)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
let right = Self::get_one_edge_colors(
&self.sample_points.right,
bitmap.as_ref(),
self.bytes_per_row,
)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
DisplayColorsOfLedStrips {
top,
bottom,
left,
right,
}
}
pub fn get_one_edge_colors( pub fn get_one_edge_colors(
sample_points_of_leds: &Vec<LedSamplePoints>, sample_points_of_leds: &Vec<LedSamplePoints>,
bitmap: &Vec<u8>, bitmap: &Vec<u8>,
@ -176,6 +136,30 @@ impl Screenshot {
colors colors
} }
pub fn get_one_edge_colors_by_cg_image(
sample_points_of_leds: &Vec<LedSamplePoints>,
bitmap: core_foundation::data::CFData,
bytes_per_row: usize,
) -> Vec<LedColor> {
let mut colors = vec![];
for led_points in sample_points_of_leds {
let mut r = 0.0;
let mut g = 0.0;
let mut b = 0.0;
let len = led_points.len() as f64;
for (x, y) in led_points {
// log::info!("x: {}, y: {}, bytes_per_row: {}", x, y, bytes_per_row);
let position = x * 4 + y * bytes_per_row;
b += bitmap[position] as f64;
g += bitmap[position + 1] as f64;
r += bitmap[position + 2] as f64;
}
let color = LedColor::new((r / len) as u8, (g / len) as u8, (b / len) as u8);
colors.push(color);
}
colors
}
pub async fn get_colors_by_sample_points( pub async fn get_colors_by_sample_points(
&self, &self,
points: &Vec<LedSamplePoints>, points: &Vec<LedSamplePoints>,

View File

@ -1,21 +1,24 @@
use std::cell::{Ref, RefCell};
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use core_graphics::display::{ use core_graphics::display::{
kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay, kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay,
}; };
use paris::{error, info, warn}; use core_graphics::geometry::{CGPoint, CGRect, CGSize};
use tauri::{async_runtime::RwLock, Window}; use paris::warn;
use tokio::sync::{watch, OnceCell}; use tauri::async_runtime::RwLock;
use tokio::sync::{broadcast, watch, OnceCell};
use tokio::time::{self, Duration};
use crate::screenshot::LedSamplePoints;
use crate::{ use crate::{
ambient_light::{SamplePointConfig, SamplePointMapper}, ambient_light::{SamplePointConfig, SamplePointMapper},
led_color::LedColor, led_color::LedColor,
screenshot::{ScreenSamplePoints, Screenshot, ScreenshotPayload}, screenshot::{ScreenSamplePoints, Screenshot},
}; };
pub fn take_screenshot(display_id: u32, scale_factor: f32) -> anyhow::Result<Screenshot> { pub fn take_screenshot(display_id: u32, scale_factor: f32) -> anyhow::Result<Screenshot> {
log::debug!("take_screenshot"); log::debug!("take_screenshot");
// let start_at = std::time::Instant::now();
let cg_display = CGDisplay::new(display_id); let cg_display = CGDisplay::new(display_id);
let cg_image = CGDisplay::screenshot( let cg_image = CGDisplay::screenshot(
@ -25,7 +28,6 @@ pub fn take_screenshot(display_id: u32, scale_factor: f32) -> anyhow::Result<Scr
kCGWindowImageDefault, kCGWindowImageDefault,
) )
.ok_or_else(|| anyhow::anyhow!("Display#{}: take screenshot failed", display_id))?; .ok_or_else(|| anyhow::anyhow!("Display#{}: take screenshot failed", display_id))?;
// println!("take screenshot took {}ms", start_at.elapsed().as_millis());
let buffer = cg_image.data(); let buffer = cg_image.data();
let bytes_per_row = cg_image.bytes_per_row(); let bytes_per_row = cg_image.bytes_per_row();
@ -33,8 +35,7 @@ pub fn take_screenshot(display_id: u32, scale_factor: f32) -> anyhow::Result<Scr
let height = cg_image.height(); let height = cg_image.height();
let width = cg_image.width(); let width = cg_image.width();
let mut bytes = vec![0u8; buffer.len() as usize]; let bytes = buffer.bytes().to_owned();
bytes.copy_from_slice(&buffer);
Ok(Screenshot::new( Ok(Screenshot::new(
display_id, display_id,
@ -43,18 +44,77 @@ pub fn take_screenshot(display_id: u32, scale_factor: f32) -> anyhow::Result<Scr
bytes_per_row, bytes_per_row,
bytes, bytes,
scale_factor, scale_factor,
ScreenSamplePoints {
top: vec![],
bottom: vec![],
left: vec![],
right: vec![],
},
)) ))
} }
pub fn get_display_colors(
display_id: u32,
sample_points: &Vec<Vec<LedSamplePoints>>,
) -> anyhow::Result<Vec<LedColor>> {
log::debug!("take_screenshot");
let cg_display = CGDisplay::new(display_id);
let mut colors = vec![];
let start_at = std::time::Instant::now();
for points in sample_points {
if points.len() == 0 {
continue;
}
let start_x = points[0][0].0;
let start_y = points[0][0].1;
let end_x = points.last().unwrap().last().unwrap().0;
let end_y = points.last().unwrap().last().unwrap().1;
let (start_x, end_x) = (usize::min(start_x, end_x), usize::max(start_x, end_x));
let (start_y, end_y) = (usize::min(start_y, end_y), usize::max(start_y, end_y));
let origin = CGPoint {
x: start_x as f64 + cg_display.bounds().origin.x,
y: start_y as f64 + cg_display.bounds().origin.y,
};
let size = CGSize {
width: (end_x - start_x + 1) as f64,
height: (end_y - start_y + 1) as f64,
};
let cg_image = CGDisplay::screenshot(
CGRect::new(&origin, &size),
kCGWindowListOptionOnScreenOnly,
kCGNullWindowID,
kCGWindowImageDefault,
)
.ok_or_else(|| anyhow::anyhow!("Display#{}: take screenshot failed", display_id))?;
let bitmap = cg_image.data();
let points = points
.iter()
.map(|points| {
points
.iter()
.map(|(x, y)| (*x - start_x, *y - start_y))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
let mut part_colors =
Screenshot::get_one_edge_colors_by_cg_image(&points, bitmap, cg_image.bytes_per_row());
colors.append(&mut part_colors);
}
// if display_id == 4849664 {
// log::info!(
// "======= get_display_colors {} took {}ms",
// display_id,
// start_at.elapsed().as_millis()
// );
// }
Ok(colors)
}
pub struct ScreenshotManager { pub struct ScreenshotManager {
pub channels: Arc<RwLock<HashMap<u32, watch::Receiver<Screenshot>>>>, pub channels: Arc<RwLock<HashMap<u32, watch::Receiver<Screenshot>>>>,
encode_listeners: Arc<RwLock<HashMap<u32, Vec<Window>>>>, merged_screenshot_tx: Arc<RwLock<broadcast::Sender<Screenshot>>>,
} }
impl ScreenshotManager { impl ScreenshotManager {
@ -64,10 +124,10 @@ impl ScreenshotManager {
SCREENSHOT_MANAGER SCREENSHOT_MANAGER
.get_or_init(|| async { .get_or_init(|| async {
let channels = Arc::new(RwLock::new(HashMap::new())); let channels = Arc::new(RwLock::new(HashMap::new()));
let encode_listeners = Arc::new(RwLock::new(HashMap::new())); let (merged_screenshot_tx, _) = broadcast::channel::<Screenshot>(2);
Self { Self {
channels, channels,
encode_listeners, merged_screenshot_tx: Arc::new(RwLock::new(merged_screenshot_tx)),
} }
}) })
.await .await
@ -83,6 +143,7 @@ impl ScreenshotManager {
fn start_one(&self, display_id: u32, scale_factor: f32) -> anyhow::Result<()> { fn start_one(&self, display_id: u32, scale_factor: f32) -> anyhow::Result<()> {
let channels = self.channels.to_owned(); let channels = self.channels.to_owned();
let merged_screenshot_tx = self.merged_screenshot_tx.clone();
tokio::spawn(async move { tokio::spawn(async move {
let screenshot = take_screenshot(display_id, scale_factor); let screenshot = take_screenshot(display_id, scale_factor);
@ -90,125 +151,51 @@ impl ScreenshotManager {
warn!("take_screenshot_loop: {}", screenshot.err().unwrap()); warn!("take_screenshot_loop: {}", screenshot.err().unwrap());
return; return;
} }
let mut interval = time::interval(Duration::from_millis(3300));
let mut start = tokio::time::Instant::now();
let screenshot = screenshot.unwrap(); let screenshot = screenshot.unwrap();
let (tx, rx) = watch::channel(screenshot); let (screenshot_tx, screenshot_rx) = watch::channel(screenshot);
{ {
let channels = channels.clone();
let mut channels = channels.write().await; let mut channels = channels.write().await;
channels.insert(display_id, rx); channels.insert(display_id, screenshot_rx.clone());
} }
let merged_screenshot_tx = merged_screenshot_tx.read().await.clone();
loop { loop {
Self::take_screenshot_loop(display_id, scale_factor, &tx).await; start = tokio::time::Instant::now();
tokio::time::sleep(std::time::Duration::from_millis(20)).await; Self::take_screenshot_loop(
}
});
Ok(())
}
pub async fn subscribe_encoded_screenshot_updated(
&self,
window: Window,
display_id: u32,
) -> anyhow::Result<()> {
let channels = self.channels.to_owned();
let encode_listeners = self.encode_listeners.to_owned();
// log::info!("subscribe_encoded_screenshot_updated. {}", display_id);
{
let encode_listeners = encode_listeners.read().await;
let listening_windows = encode_listeners.get(&display_id);
if listening_windows.is_some() && listening_windows.unwrap().contains(&window) {
log::debug!("subscribe_encoded_screenshot_updated: already listening. display#{}, window#{}", display_id, window.label());
return Ok(());
}
}
{
encode_listeners
.write()
.await
.entry(display_id)
.or_default()
.push(window);
}
tokio::spawn(async move {
info!("subscribe_encoded_screenshot_updated: start");
let channels = channels.read().await;
let rx = channels.get(&display_id);
if rx.is_none() {
error!(
"subscribe_encoded_screenshot_updated: can not find display_id {}",
display_id
);
return;
}
let mut rx = rx.unwrap().clone();
loop {
if let Err(err) = rx.changed().await {
error!(
"subscribe_encoded_screenshot_updated: can not wait rx {}",
err
);
break;
}
let encode_listeners = encode_listeners.read().await;
let windows = encode_listeners.get(&display_id);
if windows.is_none() || windows.unwrap().is_empty() {
info!("subscribe_encoded_screenshot_updated: no listener, stop");
break;
}
let screenshot = rx.borrow().clone();
// let base64_image = Self::encode_screenshot_to_base64(&screenshot).await;
let height = screenshot.height;
let width = screenshot.width;
// if base64_image.is_err() {
// error!(
// "subscribe_encoded_screenshot_updated: encode_screenshot_to_base64 error {}",
// base64_image.err().unwrap()
// );
// continue;
// }
// let base64_image = base64_image.unwrap();
for window in windows.unwrap().into_iter() {
// let base64_image = base64_image.clone();
let payload = ScreenshotPayload {
display_id, display_id,
// base64_image, scale_factor,
height, &screenshot_tx,
width, &merged_screenshot_tx,
};
if let Err(err) = window.emit("encoded-screenshot-updated", payload) {
error!("subscribe_encoded_screenshot_updated: emit error {}", err)
} else {
log::debug!(
"subscribe_encoded_screenshot_updated: emit success. display#{}",
display_id
) )
} .await;
} interval.tick().await;
tokio::time::sleep(Duration::from_millis(1)).await;
} }
}); });
Ok(())
}
async fn unsubscribe_encoded_screenshot_updated(&self, display_id: u32) -> anyhow::Result<()> {
let channels = self.channels.to_owned();
let mut channels = channels.write().await;
channels.remove(&display_id);
Ok(()) Ok(())
} }
async fn take_screenshot_loop( async fn take_screenshot_loop(
display_id: u32, display_id: u32,
scale_factor: f32, scale_factor: f32,
tx: &watch::Sender<Screenshot>, screenshot_tx: &watch::Sender<Screenshot>,
merged_screenshot_tx: &broadcast::Sender<Screenshot>,
) { ) {
let screenshot = take_screenshot(display_id, scale_factor); let screenshot = take_screenshot(display_id, scale_factor);
if let Ok(screenshot) = screenshot { if let Ok(screenshot) = screenshot {
tx.send(screenshot).unwrap(); match merged_screenshot_tx.send(screenshot.clone()) {
Ok(_) => {}
Err(err) => {
// warn!("take_screenshot_loop: merged_screenshot_tx.send failed. display#{}. err: {}", display_id, err);
}
}
screenshot_tx.send(screenshot).unwrap();
// log::info!("take_screenshot_loop: send success. display#{}", display_id) // log::info!("take_screenshot_loop: send success. display#{}", display_id)
} else { } else {
warn!("take_screenshot_loop: {}", screenshot.err().unwrap()); warn!("take_screenshot_loop: {}", screenshot.err().unwrap());
@ -218,7 +205,7 @@ impl ScreenshotManager {
pub async fn get_all_colors( pub async fn get_all_colors(
&self, &self,
configs: &Vec<SamplePointConfig>, configs: &Vec<SamplePointConfig>,
screenshots: &Vec<Screenshot>, screenshots: &Vec<&Screenshot>,
) -> Vec<LedColor> { ) -> Vec<LedColor> {
let mut all_colors = vec![]; let mut all_colors = vec![];
@ -232,10 +219,7 @@ impl ScreenshotManager {
all_colors all_colors
} }
pub async fn get_sorted_colors( pub fn get_sorted_colors(colors: &Vec<u8>, mappers: &Vec<SamplePointMapper>) -> Vec<u8> {
colors: &Vec<LedColor>,
mappers: &Vec<SamplePointMapper>,
) -> Vec<u8> {
let total_leds = mappers let total_leds = mappers
.iter() .iter()
.map(|mapper| usize::max(mapper.start, mapper.end)) .map(|mapper| usize::max(mapper.start, mapper.end))
@ -255,36 +239,36 @@ impl ScreenshotManager {
return; return;
} }
if color_index + group.start.abs_diff(group.end) > colors.len() { if color_index + group.start.abs_diff(group.end) * 3 > colors.len(){
warn!( warn!(
"get_sorted_colors: color_index out of range. color_index: {}, strip len: {}, colors.len(): {}", "get_sorted_colors: color_index out of range. color_index: {}, strip len: {}, colors.len(): {}",
color_index, color_index / 3,
group.start.abs_diff(group.end), group.start.abs_diff(group.end),
colors.len() colors.len() / 3
); );
return; return;
} }
if group.end > group.start { if group.end > group.start {
for i in group.start..group.end { for i in group.start..group.end {
let rgb = colors[color_index].get_rgb(); global_colors[i * 3] = colors[color_index +0];
color_index += 1; global_colors[i * 3 + 1] = colors[color_index +1];
global_colors[i * 3 + 2] = colors[color_index +2];
global_colors[i * 3] = rgb[0]; color_index += 3;
global_colors[i * 3 + 1] = rgb[1];
global_colors[i * 3 + 2] = rgb[2];
} }
} else { } else {
for i in (group.end..group.start).rev() { for i in (group.end..group.start).rev() {
let rgb = colors[color_index].get_rgb(); global_colors[i * 3] = colors[color_index +0];
color_index += 1; global_colors[i * 3 + 1] = colors[color_index +1];
global_colors[i * 3 + 2] = colors[color_index +2];
global_colors[i * 3] = rgb[0]; color_index += 3;
global_colors[i * 3 + 1] = rgb[1];
global_colors[i * 3 + 2] = rgb[2];
} }
} }
}); });
global_colors global_colors
} }
pub async fn clone_merged_screenshot_rx(&self) -> broadcast::Receiver<Screenshot> {
self.merged_screenshot_tx.read().await.subscribe()
}
} }

View File

@ -1,4 +1,4 @@
import { createContext, createEffect, onCleanup } from 'solid-js'; import { createEffect, onCleanup } from 'solid-js';
import { invoke } from '@tauri-apps/api/tauri'; import { invoke } from '@tauri-apps/api/tauri';
import { DisplayView } from './components/display-view'; import { DisplayView } from './components/display-view';
import { DisplayListContainer } from './components/display-list-container'; import { DisplayListContainer } from './components/display-list-container';
@ -44,7 +44,7 @@ function App() {
// listen to led_colors_changed event // listen to led_colors_changed event
createEffect(() => { createEffect(() => {
const unlisten = listen<Array<string>>('led_colors_changed', (event) => { const unlisten = listen<Uint8ClampedArray>('led_colors_changed', (event) => {
const colors = event.payload; const colors = event.payload;
setLedStripStore({ setLedStripStore({

View File

@ -1,5 +1,4 @@
import { invoke } from '@tauri-apps/api'; import { invoke } from '@tauri-apps/api';
import { listen } from '@tauri-apps/api/event';
import { import {
Component, Component,
createEffect, createEffect,
@ -8,7 +7,6 @@ import {
createSignal, createSignal,
For, For,
JSX, JSX,
onCleanup,
splitProps, splitProps,
useContext, useContext,
} from 'solid-js'; } from 'solid-js';
@ -77,9 +75,15 @@ export const LedStripPart: Component<LedStripPartProps> = (props) => {
return; return;
} }
const offset = mapper.pos; const offset = mapper.pos * 3;
const colors = new Array(localProps.config.len).fill(null).map((_, i) => {
const index = offset + i * 3;
return `rgb(${ledStripStore.colors[index]}, ${ledStripStore.colors[index + 1]}, ${
ledStripStore.colors[index + 2]
})`;
});
const colors = ledStripStore.colors.slice(offset, offset + localProps.config.len);
setColors(colors); setColors(colors);
}); });

View File

@ -115,31 +115,21 @@ const SorterItem: Component<{ strip: LedStripConfig; mapper: LedStripPixelMapper
// update fullLeds // update fullLeds
createEffect(() => { createEffect(() => {
const fullLeds = new Array(ledStripStore.totalLedCount).fill(null); const fullLeds = new Array(ledStripStore.totalLedCount).fill(null);
const colors = ledStripStore.colors;
// if (props.mapper.start < props.mapper.end) {
// for (
// let i = props.mapper.start, j = props.mapper.pos;
// i < props.mapper.end;
// i++, j++
// ) {
// fullLeds[i] = ledStripStore.colors[j];
// }
// } else {
// for (
// let i = props.mapper.start, j = props.mapper.pos;
// i >= props.mapper.end;
// i--, j++
// ) {
// fullLeds[i] = ledStripStore.colors[j];
// }
// }
// 优化上面的代码
const { start, end, pos } = props.mapper; const { start, end, pos } = props.mapper;
const isForward = start < end; const isForward = start < end;
const step = isForward ? 1 : -1; const step = isForward ? 1 : -1;
for (let i = start, j = pos; i !== end; i += step, j++) { for (let i = start, j = pos; i !== end; i += step, j++) {
fullLeds[i] = ledStripStore.colors[j]; let c1 = `rgb(${Math.floor(colors[j * 3] * 0.8)}, ${Math.floor(
colors[j * 3 + 1] * 0.8,
)}, ${Math.floor(colors[j * 3 + 2] * 0.8)})`;
let c2 = `rgb(${Math.min(Math.floor(colors[j * 3] * 1.2), 255)}, ${Math.min(
Math.floor(colors[j * 3 + 1] * 1.2),
255,
)}, ${Math.min(Math.floor(colors[j * 3 + 2] * 1.2), 255)})`;
fullLeds[i] = `linear-gradient(70deg, ${c1} 10%, ${c2})`;
} }
setFullLeds(fullLeds); setFullLeds(fullLeds);
@ -197,7 +187,6 @@ const SorterResult: Component = () => {
return `linear-gradient(70deg, ${c1} 10%, ${c2})`; return `linear-gradient(70deg, ${c1} 10%, ${c2})`;
}); });
console.log(fullLeds);
setFullLeds(fullLeds); setFullLeds(fullLeds);
}); });

View File

@ -1,4 +1,3 @@
import { invoke } from '@tauri-apps/api';
import { convertFileSrc } from '@tauri-apps/api/tauri'; import { convertFileSrc } from '@tauri-apps/api/tauri';
import { import {
Component, Component,
@ -30,6 +29,7 @@ export const ScreenView: Component<ScreenViewProps> = (props) => {
width: number; width: number;
height: number; height: number;
} | null>(null); } | null>(null);
const [hidden, setHidden] = createSignal(false);
const resetSize = () => { const resetSize = () => {
const aspectRatio = canvas.width / canvas.height; const aspectRatio = canvas.width / canvas.height;
@ -103,6 +103,10 @@ export const ScreenView: Component<ScreenViewProps> = (props) => {
(async () => { (async () => {
while (!stopped) { while (!stopped) {
if (hidden()) {
await new Promise((resolve) => setTimeout(resolve, 1000));
continue;
}
await frame(); await frame();
} }
})(); })();
@ -128,6 +132,26 @@ export const ScreenView: Component<ScreenViewProps> = (props) => {
}); });
}); });
// update hidden
createEffect(() => {
const hide = () => {
setHidden(true);
console.log('hide');
};
const show = () => {
setHidden(false);
console.log('show');
};
window.addEventListener('focus', show);
window.addEventListener('blur', hide);
onCleanup(() => {
window.removeEventListener('focus', show);
window.removeEventListener('blur', hide);
});
});
return ( return (
<div <div
ref={root!} ref={root!}

View File

@ -4,7 +4,7 @@ import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config'
export const [ledStripStore, setLedStripStore] = createStore({ export const [ledStripStore, setLedStripStore] = createStore({
strips: new Array<LedStripConfig>(), strips: new Array<LedStripConfig>(),
mappers: new Array<LedStripPixelMapper>(), mappers: new Array<LedStripPixelMapper>(),
colors: new Array<string>(), colors: new Uint8ClampedArray(),
sortedColors: new Uint8ClampedArray(), sortedColors: new Uint8ClampedArray(),
get totalLedCount() { get totalLedCount() {
return Math.max(0, ...ledStripStore.mappers.map((m) => Math.max(m.start, m.end))); return Math.max(0, ...ledStripStore.mappers.map((m) => Math.max(m.start, m.end)));