Display Nodes/Ports/Links obtained from pipewire server

This commit is contained in:
Tom A. Wagner
2021-01-03 19:01:47 +01:00
parent 438383e92f
commit b129d84fa2
8 changed files with 666 additions and 102 deletions

409
Cargo.lock generated
View File

@@ -1,5 +1,23 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.34" version = "1.0.34"
@@ -29,7 +47,41 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps", "system-deps 1.3.2",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bindgen"
version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"clap",
"env_logger",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
] ]
[[package]] [[package]]
@@ -61,7 +113,7 @@ checksum = "2ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps", "system-deps 1.3.2",
] ]
[[package]] [[package]]
@@ -70,12 +122,72 @@ version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
[[package]]
name = "cexpr"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0659001ab56b791be01d4b729c44376edc6718cf389a502e579b77b758f3296c"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "env_logger"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.8" version = "0.3.8"
@@ -216,7 +328,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps", "system-deps 1.3.2",
] ]
[[package]] [[package]]
@@ -233,7 +345,7 @@ dependencies = [
"libc", "libc",
"pango-sys", "pango-sys",
"pkg-config", "pkg-config",
"system-deps", "system-deps 1.3.2",
] ]
[[package]] [[package]]
@@ -266,7 +378,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps", "system-deps 1.3.2",
"winapi", "winapi",
] ]
@@ -312,9 +424,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1"
dependencies = [ dependencies = [
"libc", "libc",
"system-deps", "system-deps 1.3.2",
] ]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]] [[package]]
name = "gobject-sys" name = "gobject-sys"
version = "0.10.0" version = "0.10.0"
@@ -323,7 +441,7 @@ checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps", "system-deps 1.3.2",
] ]
[[package]] [[package]]
@@ -335,6 +453,7 @@ dependencies = [
"gio", "gio",
"glib", "glib",
"gtk", "gtk",
"pipewire",
] ]
[[package]] [[package]]
@@ -380,7 +499,7 @@ dependencies = [
"gobject-sys", "gobject-sys",
"libc", "libc",
"pango-sys", "pango-sys",
"system-deps", "system-deps 1.3.2",
] ]
[[package]] [[package]]
@@ -392,6 +511,21 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "hermit-abi"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.9.0" version = "0.9.0"
@@ -401,18 +535,90 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.80" version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "libloading"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc"
dependencies = [
"cfg-if 1.0.0",
"winapi",
]
[[package]]
name = "libspa"
version = "0.1.0"
source = "git+https://gitlab.freedesktop.org/gdesmott/pipewire-rs?branch=proxies#6560d4f769cc0d9937d6091f2f3eb298ef31cbfc"
dependencies = [
"bitflags",
"libspa-sys",
]
[[package]]
name = "libspa-sys"
version = "0.1.0"
source = "git+https://gitlab.freedesktop.org/gdesmott/pipewire-rs?branch=proxies#6560d4f769cc0d9937d6091f2f3eb298ef31cbfc"
dependencies = [
"bindgen",
"system-deps 2.0.2",
]
[[package]]
name = "log"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if 0.1.10",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.4" version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "nix"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
dependencies = [
"bitflags",
"cc",
"cfg-if 0.1.10",
"libc",
"void",
]
[[package]]
name = "nom"
version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"memchr",
"version_check",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.5.0" version = "1.5.0"
@@ -443,9 +649,15 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps", "system-deps 1.3.2",
] ]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.0.1" version = "1.0.1"
@@ -472,6 +684,31 @@ 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 = "pipewire"
version = "0.1.0"
source = "git+https://gitlab.freedesktop.org/gdesmott/pipewire-rs?branch=proxies#6560d4f769cc0d9937d6091f2f3eb298ef31cbfc"
dependencies = [
"anyhow",
"bitflags",
"libc",
"libspa",
"libspa-sys",
"pipewire-sys",
"signal",
"thiserror",
]
[[package]]
name = "pipewire-sys"
version = "0.1.0"
source = "git+https://gitlab.freedesktop.org/gdesmott/pipewire-rs?branch=proxies#6560d4f769cc0d9937d6091f2f3eb298ef31cbfc"
dependencies = [
"bindgen",
"libspa-sys",
"system-deps 2.0.2",
]
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.19" version = "0.3.19"
@@ -541,24 +778,76 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "regex"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.117" version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
[[package]]
name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "signal"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f6ce83b159ab6984d2419f495134972b48754d13ff2e3f8c998339942b56ed9"
dependencies = [
"libc",
"nix",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.2" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.18.0" version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
[[package]]
name = "strum"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c"
[[package]] [[package]]
name = "strum_macros" name = "strum_macros"
version = "0.18.0" version = "0.18.0"
@@ -571,6 +860,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "strum_macros"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.48" version = "1.0.48"
@@ -590,11 +891,44 @@ checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b"
dependencies = [ dependencies = [
"heck", "heck",
"pkg-config", "pkg-config",
"strum", "strum 0.18.0",
"strum_macros", "strum_macros 0.18.0",
"thiserror", "thiserror",
"toml", "toml",
"version-compare", "version-compare 0.0.10",
]
[[package]]
name = "system-deps"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f0e2c9cfeb7afa05a18802454f8b467ba12e459301af4b17ea69bce3f63e990"
dependencies = [
"heck",
"pkg-config",
"strum 0.20.0",
"strum_macros 0.20.1",
"thiserror",
"toml",
"version-compare 0.0.11",
]
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
] ]
[[package]] [[package]]
@@ -617,6 +951,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.7" version = "0.5.7"
@@ -632,24 +975,57 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "version-compare" name = "version-compare"
version = "0.0.10" version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1"
[[package]]
name = "version-compare"
version = "0.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.2" version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -666,6 +1042,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View File

@@ -11,4 +11,6 @@ cairo-rs = "0.9.1"
glib = "0.10.3" glib = "0.10.3"
gdk = "0.13.2" gdk = "0.13.2"
gtk = "0.9.2" gtk = "0.9.2"
gio = "0.9.1" gio = "0.9.1"
pipewire = { git = "https://gitlab.freedesktop.org/gdesmott/pipewire-rs", branch = "proxies"}

View File

@@ -1,11 +1,13 @@
mod pipewire_connection;
mod view; mod view;
use gio::prelude::*; use gio::prelude::*;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use std::rc::Rc; use std::{cell::RefCell, rc::Rc};
#[derive(Debug)]
pub struct PipewireLink { pub struct PipewireLink {
pub node_from: u32, pub node_from: u32,
pub port_from: u32, pub port_from: u32,
@@ -15,33 +17,18 @@ pub struct PipewireLink {
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
gtk::init()?; gtk::init()?;
let mut graphview = view::GraphView::new(); let graphview = Rc::new(RefCell::new(view::GraphView::new()));
// For UI Testing purposes // Create the connection to the pipewire server and do an initial roundtrip before showing the view,
let mut node = view::PipewireNode::new("Test Node"); // so that the graph is already populated when the window opens.
node.add_ingoing_port(10, gtk::Button::with_label("Ingoing Port")); let pw_con = pipewire_connection::PipewireConnection::new(graphview.clone())
node.add_outgoing_port(11, gtk::Button::with_label("Outgoing Port")); .expect("Failed to initialize pipewire connection");
node.add_outgoing_port(12, gtk::Button::with_label("Outgoing Port 2")); pw_con.roundtrip();
// From now on, call roundtrip() every second.
let mut node2 = view::PipewireNode::new("Test Node 2"); glib::timeout_add_seconds_local(1, move || {
node2.add_ingoing_port(13, gtk::Button::with_label("Ingoing Port")); pw_con.roundtrip();
node2.add_outgoing_port(14, gtk::Button::with_label("Outgoing Port")); Continue(true)
node2.add_outgoing_port(15, gtk::Button::with_label("Outgoing Port 2")); });
graphview.add_node(0, node);
graphview.add_node(1, node2);
graphview.add_link(
2,
PipewireLink {
node_from: 0,
port_from: 12,
node_to: 1,
port_to: 13,
},
);
// End UI Testing
let graphview = Rc::new(graphview);
let app = gtk::Application::new( let app = gtk::Application::new(
Some("org.freedesktop.pipewire.graphui"), Some("org.freedesktop.pipewire.graphui"),
@@ -53,7 +40,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let window = gtk::ApplicationWindow::new(app); let window = gtk::ApplicationWindow::new(app);
window.set_default_size(800, 600); window.set_default_size(800, 600);
window.set_title("Pipewire Graph Editor"); window.set_title("Pipewire Graph Editor");
window.add(&graphview.widget); window.add(&graphview.borrow().widget);
window.show_all(); window.show_all();
})); }));

155
src/pipewire_connection.rs Normal file
View File

@@ -0,0 +1,155 @@
use std::{
cell::{Cell, RefCell},
rc::Rc,
};
use glib::clone;
use pipewire as pw;
use pw::{port::Direction, registry::ObjectType, PW_ID_CORE};
use crate::PipewireLink;
pub struct PipewireConnection {
mainloop: pw::MainLoop,
_context: pw::Context<pw::MainLoop>,
core: pw::Core,
_registry: pw::registry::Registry,
_reg_listeners: pw::registry::Listener,
}
impl PipewireConnection {
pub fn new(graphview: Rc<RefCell<crate::view::GraphView>>) -> Result<Self, String> {
pw::init();
let mainloop = pw::MainLoop::new().map_err(|_| "Failed to create pipewire mainloop!")?;
let context =
pw::Context::new(&mainloop).map_err(|_| "Failed to create pipewire context")?;
let core = context
.connect()
.map_err(|_| "Failed to connect to pipewire core")?;
let registry = core.get_registry();
let reg_listeners = registry
.add_listener_local()
.global(clone!(@weak graphview => @default-panic, move |global| {
PipewireConnection::handle_global(graphview, global)
}))
.global_remove(|_| { /* TODO */ })
.register();
Ok(Self {
mainloop,
_context: context,
core,
_registry: registry,
_reg_listeners: reg_listeners,
})
}
pub fn roundtrip(&self) {
let done = Rc::new(Cell::new(false));
let pending = self.core.sync(0);
let done_clone = done.clone();
let loop_clone = self.mainloop.clone();
let _listener = self
.core
.add_listener_local()
.done(move |id, seq| {
if id == PW_ID_CORE && seq == pending {
done_clone.set(true);
loop_clone.quit();
}
})
.register();
while !done.get() {
self.mainloop.run();
}
}
fn handle_global(
graphview: Rc<RefCell<crate::view::GraphView>>,
global: pw::registry::GlobalObject,
) {
match global.type_ {
ObjectType::Node => {
let node_widget = crate::view::Node::new(&format!(
"{}",
global
.props
.map(|dict| String::from(
dict.get("node.nick")
.or(dict.get("node.description"))
.or(dict.get("node.name"))
.unwrap_or_default()
))
.unwrap_or_default()
));
graphview.borrow_mut().add_node(global.id, node_widget);
}
ObjectType::Port => {
let props = global.props.expect("Port object is missing properties");
let port_label = format!("{}", props.get("port.name").unwrap_or_default());
let node_id: u32 = props
.get("node.id")
.expect("Port has no node.id property!")
.parse()
.expect("Could not parse node.id property");
let port = crate::view::port::Port::new(
global.id,
&port_label,
if matches!(props.get("port.direction"), Some("in")) {
Direction::Input
} else {
Direction::Output
},
);
graphview
.borrow_mut()
.add_port_to_node(node_id, global.id, port);
}
ObjectType::Link => {
let props = global.props.expect("Link object is missing properties");
let input_node: u32 = props
.get("link.input.node")
.expect("Link has no link.input.node property")
.parse()
.expect("Could not parse link.input.node property");
let input_port: u32 = props
.get("link.input.port")
.expect("Link has no link.input.port property")
.parse()
.expect("Could not parse link.input.port property");
let output_node: u32 = props
.get("link.output.node")
.expect("Link has no link.input.node property")
.parse()
.expect("Could not parse link.input.node property");
let output_port: u32 = props
.get("link.output.port")
.expect("Link has no link.output.port property")
.parse()
.expect("Could not parse link.output.port property");
graphview.borrow_mut().add_link(
global.id,
PipewireLink {
node_from: output_node,
port_from: output_port,
node_to: input_node,
port_to: input_port,
},
);
}
_ => {}
}
}
}
/*impl Drop for PipewireConnection {
fn drop(&mut self) {
unsafe { pw::deinit() }
}
}*/

View File

@@ -1,4 +1,4 @@
use super::PipewireNode; use super::Node;
use cairo::Context; use cairo::Context;
use glib::clone; use glib::clone;
use gtk::{prelude::*, LayoutExt}; use gtk::{prelude::*, LayoutExt};
@@ -6,7 +6,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
pub struct GraphView { pub struct GraphView {
pub(crate) widget: gtk::Layout, pub(crate) widget: gtk::Layout,
nodes: Rc<RefCell<HashMap<u32, PipewireNode>>>, nodes: Rc<RefCell<HashMap<u32, Node>>>,
links: Rc<RefCell<HashMap<u32, crate::PipewireLink>>>, links: Rc<RefCell<HashMap<u32, crate::PipewireLink>>>,
} }
@@ -28,16 +28,29 @@ impl GraphView {
result result
} }
pub fn add_node(&mut self, id: u32, node: PipewireNode) { pub fn add_node(&mut self, id: u32, node: Node) {
// TODO: Find a free position to put the widget at. // TODO: Find a free position to put the widget at.
self.widget.put( self.widget.put(
&node.widget, &node.widget,
(self.nodes.borrow().len() % 4 * 400) as i32, (self.nodes.borrow().len() / 4 * 400) as i32,
(self.nodes.borrow().len() / 4 * 100) as i32, (self.nodes.borrow().len() % 4 * 100) as i32,
); );
node.widget.show_all();
self.nodes.borrow_mut().insert(id, node); self.nodes.borrow_mut().insert(id, node);
} }
pub fn add_port_to_node(&mut self, node_id: u32, port_id: u32, port: super::port::Port) {
if let Some(node) = self.nodes.borrow_mut().get_mut(&node_id) {
node.add_port(port_id, port);
} else {
// FIXME: Log this instead
eprintln!(
"Node with id {} not found when trying to add port with id {} to graph",
node_id, port_id
);
}
}
/// Add a link to the graph. /// Add a link to the graph.
/// ///
/// `add_link` takes three arguments: `link_id` is the id of the link as assigned by the pipewire server, /// `add_link` takes three arguments: `link_id` is the id of the link as assigned by the pipewire server,
@@ -49,7 +62,7 @@ impl GraphView {
} }
fn draw( fn draw(
nodes: Rc<RefCell<HashMap<u32, PipewireNode>>>, nodes: Rc<RefCell<HashMap<u32, Node>>>,
links: Rc<RefCell<HashMap<u32, crate::PipewireLink>>>, links: Rc<RefCell<HashMap<u32, crate::PipewireLink>>>,
cr: &Context, cr: &Context,
) { ) {
@@ -58,44 +71,40 @@ fn draw(
cr.paint(); cr.paint();
cr.set_source_rgb(0.0, 0.0, 0.0); cr.set_source_rgb(0.0, 0.0, 0.0);
for link in links.borrow().values() { for link in links.borrow().values() {
let (from_alloc, to_alloc) = get_allocs(nodes.clone(), link); if let Some((from_alloc, to_alloc)) = get_allocs(nodes.clone(), link) {
let from_x: f64 = (from_alloc.x + from_alloc.width).into();
let from_y: f64 = (from_alloc.y + (from_alloc.height / 2)).into();
cr.move_to(from_x, from_y);
let from_x: f64 = (from_alloc.x + from_alloc.width).into(); let to_x: f64 = to_alloc.x.into();
let from_y: f64 = (from_alloc.y + (from_alloc.height / 2)).into(); let to_y: f64 = (to_alloc.y + (to_alloc.height / 2)).into();
cr.move_to( cr.curve_to(from_x + 75.0, from_y, to_x - 75.0, to_y, to_x, to_y);
from_x, from_y
);
let to_x: f64 = to_alloc.x.into(); cr.stroke();
let to_y: f64 = (to_alloc.y + (to_alloc.height / 2)).into(); } else {
cr.curve_to( eprintln!("Could not get allocation of ports of link: {:?}", link);
from_x + 75.0, from_y, }
to_x - 75.0, to_y,
to_x, to_y
);
cr.stroke();
} }
} }
fn get_allocs( fn get_allocs(
nodes: Rc<RefCell<HashMap<u32, PipewireNode>>>, nodes: Rc<RefCell<HashMap<u32, Node>>>,
link: &crate::PipewireLink, link: &crate::PipewireLink,
) -> (gtk::Allocation, gtk::Allocation) { ) -> Option<(gtk::Allocation, gtk::Allocation)> {
println!();
let from_alloc = &nodes let from_alloc = &nodes
.borrow() .borrow()
.get(&link.node_from) .get(&link.node_from)?
.unwrap() .get_port(link.port_from)?
.get_outgoing_port(link.port_from) .widget
.unwrap()
.get_allocation(); .get_allocation();
let to_alloc = &nodes let to_alloc = &nodes
.borrow() .borrow()
.get(&link.node_to) .get(&link.node_to)?
.unwrap() .get_port(link.port_to)?
.get_ingoing_port(link.port_to) .widget
.unwrap()
.get_allocation(); .get_allocation();
(from_alloc.to_owned(), to_alloc.to_owned()) Some((from_alloc.to_owned(), to_alloc.to_owned()))
} }

View File

@@ -1,5 +1,6 @@
mod graph_view; mod graph_view;
mod pipewire_node; mod node;
pub mod port;
pub use graph_view::GraphView; pub use graph_view::GraphView;
pub use pipewire_node::PipewireNode; pub use node::Node;

View File

@@ -1,40 +1,47 @@
use gtk::prelude::*;
use gdk::prelude::*; use gdk::prelude::*;
use gtk::prelude::*;
use std::collections::HashMap; use std::collections::HashMap;
pub struct PipewireNode { use pipewire::port::Direction;
pub struct Node {
pub(super) widget: gtk::Grid, pub(super) widget: gtk::Grid,
label: gtk::Label, label: gtk::Label,
label_box: gtk::EventBox, label_box: gtk::EventBox,
ingoing_ports: HashMap<u32, gtk::Button>, ports: HashMap<u32, super::port::Port>,
outgoing_ports: HashMap<u32, gtk::Button>, num_ports_in: u32,
num_ports_out: u32,
} }
impl PipewireNode { impl Node {
pub fn new(name: &str) -> Self { pub fn new(name: &str) -> Self {
let result = Self { let result = Self {
widget: gtk::Grid::new(), widget: gtk::Grid::new(),
label: gtk::Label::new(Some(name)), label: gtk::Label::new(Some(name)),
label_box: gtk::EventBox::new(), label_box: gtk::EventBox::new(),
ingoing_ports: HashMap::new(), ports: HashMap::new(),
outgoing_ports: HashMap::new(), num_ports_in: 0,
num_ports_out: 0,
}; };
result.label_box.add(&result.label); result.label_box.add(&result.label);
result.widget.attach(&result.label_box, 0, 0, 2, 1); result.widget.attach(&result.label_box, 0, 0, 2, 1);
// Setup needed events for dragging a node.
result result
.label_box .label_box
.add_events(gdk::EventMask::BUTTON1_MOTION_MASK); .add_events(gdk::EventMask::BUTTON1_MOTION_MASK);
// Setup callback for dragging the node.
result result
.label_box .label_box
.connect_motion_notify_event(|label, event| { .connect_motion_notify_event(|label, event| {
let grid = label let node_frame = label
.get_ancestor(gtk::Grid::static_type()) .get_ancestor(gtk::Grid::static_type())
.unwrap() .unwrap()
.dynamic_cast::<gtk::Grid>() .dynamic_cast::<gtk::Grid>()
.unwrap(); .unwrap();
let graphview = grid let graphview = node_frame
.get_ancestor(gtk::Layout::static_type()) .get_ancestor(gtk::Layout::static_type())
.unwrap() .unwrap()
.dynamic_cast::<gtk::Layout>() .dynamic_cast::<gtk::Layout>()
@@ -47,8 +54,8 @@ impl PipewireNode {
// TODO: Calculate proper values to center the mouse on the label // TODO: Calculate proper values to center the mouse on the label
// instead of using hardcoded offsets. // instead of using hardcoded offsets.
graphview.set_child_x(&grid, x as i32 - offset_x - 100); graphview.set_child_x(&node_frame, x as i32 - offset_x - 100);
graphview.set_child_y(&grid, y as i32 - offset_y - 50); graphview.set_child_y(&node_frame, y as i32 - offset_y - 50);
// FIXME: If links become proper widgets, // FIXME: If links become proper widgets,
// we don't need to redraw the full graph everytime. // we don't need to redraw the full graph everytime.
@@ -60,23 +67,25 @@ impl PipewireNode {
result result
} }
pub fn add_ingoing_port(&mut self, id: u32, port: gtk::Button) { pub fn add_port(&mut self, id: u32, port: super::port::Port) {
self.widget match port.direction {
.attach(&port, 0, (self.ingoing_ports.len() + 1) as i32, 1, 1); Direction::Input => {
self.ingoing_ports.insert(id, port); self.widget
.attach(&port.widget, 0, (self.num_ports_in + 1) as i32, 1, 1);
self.num_ports_in += 1;
}
Direction::Output => {
self.widget
.attach(&port.widget, 1, (self.num_ports_out + 1) as i32, 1, 1);
self.num_ports_out += 1;
}
}
port.widget.show_all();
self.ports.insert(id, port);
} }
pub fn add_outgoing_port(&mut self, id: u32, port: gtk::Button) { pub fn get_port(&self, id: u32) -> Option<&super::port::Port> {
self.widget self.ports.get(&id)
.attach(&port, 1, (self.outgoing_ports.len() + 1) as i32, 1, 1);
self.outgoing_ports.insert(id, port);
}
pub fn get_ingoing_port(&self, id: u32) -> Option<&gtk::Button> {
self.ingoing_ports.get(&id)
}
pub fn get_outgoing_port(&self, id: u32) -> Option<&gtk::Button> {
self.outgoing_ports.get(&id)
} }
} }

16
src/view/port.rs Normal file
View File

@@ -0,0 +1,16 @@
/// Graphical representation of a pipewire port.
pub struct Port {
pub(super) widget: gtk::Button,
pub id: u32,
pub direction: pipewire::port::Direction,
}
impl Port {
pub fn new(id: u32, name: &str, direction: pipewire::port::Direction) -> Self {
Self {
widget: gtk::Button::with_label(name),
id,
direction
}
}
}