Compare commits
No commits in common. "da436d5814e93eaa787e4ab56cd101ebeff5e06a" and "1be08b1b63e8b4f9c3899199f7d12064ee880ad3" have entirely different histories.
da436d5814
...
1be08b1b63
10 changed files with 177 additions and 391 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://b2u3ggnem2sce"
|
uid="uid://cnyljy7e3rf70"
|
||||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
|
|
|
@ -3,14 +3,8 @@ extends Node2D
|
||||||
|
|
||||||
func _on_button_pressed() -> void:
|
func _on_button_pressed() -> void:
|
||||||
print("Starting request in godot")
|
print("Starting request in godot")
|
||||||
await $ScreencastRunner.request_capture()
|
$XdgPortals.request_screencast()
|
||||||
print("awaiting result")
|
|
||||||
await $ScreencastRunner.screencast_result
|
|
||||||
|
|
||||||
|
|
||||||
func _on_screencast_runner_screencast_failure(reason: String) -> void:
|
func _on_xdg_portals_screencast_sucess(pipewire_node_id: int) -> void:
|
||||||
push_warning("Screencast failed, ", reason)
|
print("Stream id in godot: ", pipewire_node_id)
|
||||||
|
|
||||||
|
|
||||||
func _on_screencast_runner_screencast_sucess(pipewire_node_id: int) -> void:
|
|
||||||
print("Screencast success: ", pipewire_node_id)
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ offset_right = 8.0
|
||||||
offset_bottom = 8.0
|
offset_bottom = 8.0
|
||||||
text = "Request"
|
text = "Request"
|
||||||
|
|
||||||
[node name="ScreencastRunner" type="ScreencastRunner" parent="."]
|
[node name="XdgPortals" type="XdgPortals" parent="."]
|
||||||
|
|
||||||
[connection signal="pressed" from="Button" to="." method="_on_button_pressed"]
|
[connection signal="pressed" from="Button" to="." method="_on_button_pressed"]
|
||||||
[connection signal="screencast_failure" from="ScreencastRunner" to="." method="_on_screencast_runner_screencast_failure"]
|
[connection signal="screencast_sucess" from="XdgPortals" to="." method="_on_xdg_portals_screencast_sucess"]
|
||||||
[connection signal="screencast_sucess" from="ScreencastRunner" to="." method="_on_screencast_runner_screencast_sucess"]
|
|
||||||
|
|
213
rust/Cargo.lock
generated
213
rust/Cargo.lock
generated
|
@ -71,102 +71,6 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-channel"
|
|
||||||
version = "2.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
|
|
||||||
dependencies = [
|
|
||||||
"concurrent-queue",
|
|
||||||
"event-listener-strategy",
|
|
||||||
"futures-core",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-executor"
|
|
||||||
version = "1.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
|
|
||||||
dependencies = [
|
|
||||||
"async-task",
|
|
||||||
"concurrent-queue",
|
|
||||||
"fastrand",
|
|
||||||
"futures-lite",
|
|
||||||
"slab",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-fs"
|
|
||||||
version = "2.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a"
|
|
||||||
dependencies = [
|
|
||||||
"async-lock",
|
|
||||||
"blocking",
|
|
||||||
"futures-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-io"
|
|
||||||
version = "2.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
|
|
||||||
dependencies = [
|
|
||||||
"async-lock",
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"futures-io",
|
|
||||||
"futures-lite",
|
|
||||||
"parking",
|
|
||||||
"polling",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
"slab",
|
|
||||||
"tracing",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-lock"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
|
|
||||||
dependencies = [
|
|
||||||
"event-listener",
|
|
||||||
"event-listener-strategy",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-net"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7"
|
|
||||||
dependencies = [
|
|
||||||
"async-io",
|
|
||||||
"blocking",
|
|
||||||
"futures-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-process"
|
|
||||||
version = "2.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel",
|
|
||||||
"async-io",
|
|
||||||
"async-lock",
|
|
||||||
"async-signal",
|
|
||||||
"async-task",
|
|
||||||
"blocking",
|
|
||||||
"cfg-if",
|
|
||||||
"event-listener",
|
|
||||||
"futures-lite",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-recursion"
|
name = "async-recursion"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
@ -178,30 +82,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-signal"
|
|
||||||
version = "0.2.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3"
|
|
||||||
dependencies = [
|
|
||||||
"async-io",
|
|
||||||
"async-lock",
|
|
||||||
"atomic-waker",
|
|
||||||
"cfg-if",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
"signal-hook-registry",
|
|
||||||
"slab",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-task"
|
|
||||||
version = "4.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.87"
|
version = "0.1.87"
|
||||||
|
@ -213,12 +93,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "atomic-waker"
|
|
||||||
version = "1.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -267,19 +141,6 @@ version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "blocking"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel",
|
|
||||||
"async-task",
|
|
||||||
"futures-io",
|
|
||||||
"futures-lite",
|
|
||||||
"piper",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
|
@ -577,7 +438,6 @@ dependencies = [
|
||||||
"godot",
|
"godot",
|
||||||
"godot_tokio",
|
"godot_tokio",
|
||||||
"pipewire",
|
"pipewire",
|
||||||
"smol",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -587,7 +447,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92b254068dbdb5a5a9d702039f5b741ac9a454617c28f69c5cc6c31792c7d11d"
|
checksum = "92b254068dbdb5a5a9d702039f5b741ac9a454617c28f69c5cc6c31792c7d11d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"godot",
|
"godot",
|
||||||
"smol",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -737,12 +596,6 @@ version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -963,12 +816,6 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.4.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
|
@ -1126,17 +973,6 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "piper"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
|
|
||||||
dependencies = [
|
|
||||||
"atomic-waker",
|
|
||||||
"fastrand",
|
|
||||||
"futures-io",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pipewire"
|
name = "pipewire"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -1171,21 +1007,6 @@ version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "polling"
|
|
||||||
version = "3.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"hermit-abi",
|
|
||||||
"pin-project-lite",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
"tracing",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
|
@ -1293,19 +1114,6 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.38.44"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"errno",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys 0.4.15",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -1315,7 +1123,7 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.9.2",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1389,23 +1197,6 @@ version = "1.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smol"
|
|
||||||
version = "2.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel",
|
|
||||||
"async-executor",
|
|
||||||
"async-fs",
|
|
||||||
"async-io",
|
|
||||||
"async-lock",
|
|
||||||
"async-net",
|
|
||||||
"async-process",
|
|
||||||
"blocking",
|
|
||||||
"futures-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.8"
|
version = "0.5.8"
|
||||||
|
@ -1479,7 +1270,7 @@ dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 1.0.2",
|
"rustix",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,10 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ashpd = "0.11.0"
|
ashpd = "0.11.0"
|
||||||
gdext_coroutines = {version="0.7.1", features=["async"]}
|
gdext_coroutines = "0.7.1"
|
||||||
# godot = {version="0.2.4", features=["api-4-2", "experimental-godot-api", "experimental-threads"]}
|
|
||||||
godot = "0.2.4"
|
godot = "0.2.4"
|
||||||
godot_tokio = "0.3.0"
|
godot_tokio = "0.3.0"
|
||||||
pipewire = "0.8.0"
|
pipewire = "0.8.0"
|
||||||
smol = "2.0.2"
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
#![feature(coroutine_trait)]
|
#![feature(coroutine_trait)]
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
//#![cfg_attr(feature = "async", feature(async_fn_traits))]
|
#![cfg_attr(feature = "async", feature(async_fn_traits))]
|
||||||
|
|
||||||
use godot::{classes::Engine, prelude::*};
|
use godot::{classes::Engine, prelude::*};
|
||||||
use godot_tokio::AsyncRuntime;
|
use godot_tokio::AsyncRuntime;
|
||||||
|
|
||||||
mod pipewire;
|
|
||||||
mod player;
|
mod player;
|
||||||
mod portals;
|
mod portals;
|
||||||
|
//mod screencapture;
|
||||||
|
|
||||||
struct Extension;
|
struct Extension;
|
||||||
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use godot::prelude::*;
|
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
|
||||||
#[class(base=Node)]
|
|
||||||
/// Node for interacting with Pipewire
|
|
||||||
/// Intended to not be spawned manually, as the plugin will create a
|
|
||||||
struct Pipewire {
|
|
||||||
base: Base<Node>,
|
|
||||||
/// Handle for the thread running the pipewire main loop
|
|
||||||
thread_handle: Option<thread::Thread>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[godot_api]
|
|
||||||
impl INode for Pipewire {
|
|
||||||
fn init(base: Base<Node>) -> Self {
|
|
||||||
Self {
|
|
||||||
base,
|
|
||||||
thread_handle: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[godot_api]
|
|
||||||
impl Pipewire {
|
|
||||||
pub const SINGLETON: &'static str = "Pipewire";
|
|
||||||
}
|
|
|
@ -3,14 +3,14 @@ use godot::prelude::*;
|
||||||
mod screencast;
|
mod screencast;
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
#[derive(GodotClass)]
|
||||||
#[class(base=Node)]
|
#[class(base=Object)]
|
||||||
struct XdgPortals {
|
struct XdgPortals {
|
||||||
base: Base<Node>,
|
base: Base<Object>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[godot_api]
|
#[godot_api]
|
||||||
impl INode for XdgPortals {
|
impl IObject for XdgPortals {
|
||||||
fn init(base: Base<Node>) -> Self {
|
fn init(base: Base<Object>) -> Self {
|
||||||
Self { base }
|
Self { base }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,148 +2,83 @@ use ashpd::desktop::{
|
||||||
screencast::{CursorMode, Screencast, SourceType},
|
screencast::{CursorMode, Screencast, SourceType},
|
||||||
PersistMode,
|
PersistMode,
|
||||||
};
|
};
|
||||||
use gdext_coroutines::prelude::*;
|
|
||||||
use godot::prelude::*;
|
use godot::prelude::*;
|
||||||
use godot_tokio::AsyncRuntime;
|
use godot_tokio::AsyncRuntime;
|
||||||
use smol::{channel, lock::Mutex};
|
//use std::thread;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
#[derive(GodotClass)]
|
||||||
#[class(base = Node)]
|
#[class(base=RefCounted)]
|
||||||
/// Runner node for requesting a pipewire screencast
|
struct ScreencastResult {
|
||||||
struct ScreencastRunner {
|
base: Base<RefCounted>,
|
||||||
base: Base<Node>,
|
|
||||||
runner: Arc<Mutex<Runner>>,
|
|
||||||
receiver: channel::Receiver<Result<u32, String>>,
|
|
||||||
sender: channel::Sender<Result<u32, String>>,
|
|
||||||
last_result: Option<Result<u32, String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Runner;
|
#[godot_api]
|
||||||
|
impl IRefCounted for ScreencastResult {
|
||||||
|
fn init(base: Base<RefCounted>) -> Self {
|
||||||
|
let mut result = Self { base };
|
||||||
|
//thread::spawn(|| result.capture_runner());
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[godot_api]
|
#[godot_api]
|
||||||
impl INode for ScreencastRunner {
|
impl ScreencastResult {
|
||||||
fn init(base: Base<Node>) -> Self {
|
fn capture_runner(&mut self) {
|
||||||
let (sender, receiver) = channel::unbounded();
|
AsyncRuntime::block_on(async {
|
||||||
Self {
|
let proxy = Screencast::new().await.expect("Screencast proxy failed");
|
||||||
base,
|
let session = match proxy.create_session().await {
|
||||||
receiver,
|
Ok(x) => x,
|
||||||
sender,
|
Err(err) => {
|
||||||
runner: Arc::new(Mutex::new(Runner {})),
|
godot_warn!("Failed to create session: {}", err);
|
||||||
last_result: None,
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn process(&mut self, _delta: f64) {
|
|
||||||
let channel_elements = self.receiver.len();
|
|
||||||
for _ in 0..channel_elements {
|
|
||||||
let result = self.receiver.recv();
|
|
||||||
let result = AsyncRuntime::block_on(result)
|
|
||||||
.expect("Failed to receive screencast request result");
|
|
||||||
self.last_result = Some(result.clone());
|
|
||||||
match result {
|
|
||||||
Ok(pipewire_node_id) => self
|
|
||||||
.base_mut()
|
|
||||||
.emit_signal("screencast_sucess", &[pipewire_node_id.to_variant()]),
|
|
||||||
Err(reason) => self
|
|
||||||
.base_mut()
|
|
||||||
.emit_signal("screencast_failure", &[reason.to_variant()]),
|
|
||||||
};
|
};
|
||||||
}
|
match proxy
|
||||||
}
|
.select_sources(
|
||||||
}
|
&session,
|
||||||
|
CursorMode::Metadata,
|
||||||
|
SourceType::Monitor | SourceType::Window,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
PersistMode::DoNot,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
godot_warn!("Err while selecting source: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[godot_api]
|
let starter = match proxy.start(&session, None).await {
|
||||||
impl ScreencastRunner {
|
Ok(x) => x,
|
||||||
/// Emited after a request to capture a window, if that request is successful.
|
Err(err) => {
|
||||||
/// Contains the id of the pipewire node with the stream
|
godot_warn!("Error while starting: {}", err);
|
||||||
#[signal]
|
return;
|
||||||
fn screencast_sucess(pipewire_node_id: u32);
|
}
|
||||||
/// Emited after a request to capture a window, if that request has failed.
|
};
|
||||||
/// Contains the reason (as string) for why the request failed
|
let result = match starter.response() {
|
||||||
#[signal]
|
Ok(x) => x,
|
||||||
fn screencast_failure(reason: String);
|
Err(err) => {
|
||||||
/// Emited after a request to capture a window completes
|
godot_warn!("Err for response: {}", err);
|
||||||
/// pipe_wire_node_id will contain the id of the pipewire node with the stream if ok is true
|
return;
|
||||||
/// reason will contain the reason (as String) why the request failed if ok is false
|
}
|
||||||
/// ok indicates whether the request was successful or not
|
};
|
||||||
#[signal]
|
godot_print!("Got response");
|
||||||
fn screencast_result(pipewire_node_id: u32, reason: String, ok: bool);
|
result.streams().iter().for_each(|stream| {
|
||||||
/// Request a new window/screen capture from the user.
|
|
||||||
/// Returns the async runner node.
|
|
||||||
/// You can either await the `completed` result on that node
|
|
||||||
#[func]
|
|
||||||
fn request_capture(&mut self) -> Gd<SpireCoroutine> {
|
|
||||||
let sender = self.sender.clone();
|
|
||||||
let binding = self.runner.clone();
|
|
||||||
// This is cursed. First having to spawn the task on the background runtime
|
|
||||||
let x = AsyncRuntime::spawn(async move {
|
|
||||||
let runner = binding.lock().await;
|
|
||||||
runner.run_capture(sender).await;
|
|
||||||
});
|
|
||||||
// And then using the engine's runtime to await the completion in the background
|
|
||||||
self.start_async_task(async move {
|
|
||||||
let _ = x.await;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Runner {
|
|
||||||
async fn run_capture(&self, result_chan: smol::channel::Sender<Result<u32, String>>) {
|
|
||||||
let proxy = Screencast::new().await.expect("Screencast proxy failed");
|
|
||||||
let session = match proxy.create_session().await {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(err) => {
|
|
||||||
godot_warn!("Failed to create session: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match proxy
|
|
||||||
.select_sources(
|
|
||||||
&session,
|
|
||||||
CursorMode::Metadata,
|
|
||||||
SourceType::Monitor | SourceType::Window,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
PersistMode::DoNot,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => {
|
|
||||||
godot_warn!("Err while selecting source: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let starter = match proxy.start(&session, None).await {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(err) => {
|
|
||||||
godot_warn!("Error while starting: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let result = match starter.response() {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(err) => {
|
|
||||||
godot_warn!("Err for response: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
godot_print!("Got response");
|
|
||||||
// This is ugly. But I can't await inside for_each
|
|
||||||
// so instead just collect all futures and await them in a manual loop
|
|
||||||
let things: Vec<_> = result
|
|
||||||
.streams()
|
|
||||||
.iter()
|
|
||||||
.map(|stream| {
|
|
||||||
godot_print!("node id: {}", stream.pipe_wire_node_id());
|
godot_print!("node id: {}", stream.pipe_wire_node_id());
|
||||||
godot_print!("size: {:?}", stream.size());
|
godot_print!("size: {:?}", stream.size());
|
||||||
godot_print!("position: {:?}", stream.position());
|
godot_print!("position: {:?}", stream.position());
|
||||||
result_chan.send(Ok(stream.pipe_wire_node_id()))
|
self.base_mut().emit_signal(
|
||||||
})
|
"screencast_sucess",
|
||||||
.collect();
|
&[stream.pipe_wire_node_id().to_variant()],
|
||||||
for future in things {
|
);
|
||||||
let _ = future.await;
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for ScreencastResult {}
|
||||||
|
unsafe impl Sync for ScreencastResult {}
|
||||||
|
|
97
rust/src/screencapture.rs
Normal file
97
rust/src/screencapture.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use ashpd::desktop::{
|
||||||
|
screencast::{CursorMode, Screencast, SourceType},
|
||||||
|
PersistMode,
|
||||||
|
};
|
||||||
|
use godot::classes::{INode, Node};
|
||||||
|
use godot::prelude::*;
|
||||||
|
use godot_tokio::AsyncRuntime;
|
||||||
|
|
||||||
|
#[derive(GodotClass)]
|
||||||
|
#[class(base=Node)]
|
||||||
|
struct XdgPortals {
|
||||||
|
base: Base<Node>,
|
||||||
|
last_request_completed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl INode for XdgPortals {
|
||||||
|
fn init(base: Base<Node>) -> Self {
|
||||||
|
Self {
|
||||||
|
base,
|
||||||
|
last_request_completed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl XdgPortals {
|
||||||
|
#[signal]
|
||||||
|
fn screencast_sucess(pipewire_node_id: u32);
|
||||||
|
|
||||||
|
#[func]
|
||||||
|
fn was_last_request_completed(&self) -> bool {
|
||||||
|
self.last_request_completed
|
||||||
|
}
|
||||||
|
|
||||||
|
#[func]
|
||||||
|
fn request_screencast(&mut self) {
|
||||||
|
godot_print!("Starting request");
|
||||||
|
self.last_request_completed = false;
|
||||||
|
AsyncRuntime::block_on(async {
|
||||||
|
godot_print!("Starting request async");
|
||||||
|
let proxy = Screencast::new().await.expect("Screencast proxy failed");
|
||||||
|
let session = match proxy.create_session().await {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(err) => {
|
||||||
|
godot_warn!("Failed to create session: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
godot_print!("Got proxy");
|
||||||
|
match proxy
|
||||||
|
.select_sources(
|
||||||
|
&session,
|
||||||
|
CursorMode::Metadata,
|
||||||
|
SourceType::Monitor | SourceType::Window,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
PersistMode::DoNot,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
godot_warn!("Err while selecting source: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
godot_print!("Selected source");
|
||||||
|
|
||||||
|
let starter = match proxy.start(&session, None).await {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(err) => {
|
||||||
|
godot_warn!("Error while starting: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let result = match starter.response() {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(err) => {
|
||||||
|
godot_warn!("Err for response: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
godot_print!("Got response");
|
||||||
|
result.streams().iter().for_each(|stream| {
|
||||||
|
godot_print!("node id: {}", stream.pipe_wire_node_id());
|
||||||
|
godot_print!("size: {:?}", stream.size());
|
||||||
|
godot_print!("position: {:?}", stream.position());
|
||||||
|
self.base_mut().emit_signal(
|
||||||
|
"screencast_sucess",
|
||||||
|
&[stream.pipe_wire_node_id().to_variant()],
|
||||||
|
);
|
||||||
|
self.last_request_completed = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue