diff -Nru helvum-0.5.1/.gitlab-ci.yml helvum-0.5.1+20240328/.gitlab-ci.yml --- helvum-0.5.1/.gitlab-ci.yml 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/.gitlab-ci.yml 2024-03-28 12:29:11.000000000 +0000 @@ -3,7 +3,7 @@ - lint .flatpak: - image: 'quay.io/gnome_infrastructure/gnome-runtime-images:gnome-45' + image: 'quay.io/gnome_infrastructure/gnome-runtime-images:gnome-46' variables: FLATPAK_BUILD_DIR: _build MANIFEST_PATH: build-aux/org.pipewire.Helvum.json diff -Nru helvum-0.5.1/Cargo.lock helvum-0.5.1+20240328/Cargo.lock --- helvum-0.5.1/Cargo.lock 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/Cargo.lock 2024-03-28 12:29:11.000000000 +0000 @@ -12,12 +12,35 @@ ] [[package]] +name = "annotate-snippets" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +dependencies = [ + "unicode-width", + "yansi-term", +] + +[[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] +name = "async-channel" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +dependencies = [ + "concurrent-queue", + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -25,16 +48,17 @@ [[package]] name = "bindgen" -version = "0.66.1" +version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags 2.4.0", + "annotate-snippets", + "bitflags", "cexpr", "clang-sys", + "itertools", "lazy_static", "lazycell", - "peeking_take_while", "proc-macro2", "quote", "regex", @@ -45,35 +69,28 @@ [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "cairo-rs" -version = "0.18.2" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c0466dfa8c0ee78deef390c274ad756801e0a6dbb86c5ef0924a298c5761c4d" +checksum = "2650f66005301bd33cc486dec076e1293c4cecf768bc7ba9bf5d2b1be339b99c" dependencies = [ - "bitflags 2.4.0", + "bitflags", "cairo-sys-rs", "glib", "libc", - "once_cell", "thiserror", ] [[package]] name = "cairo-sys-rs" -version = "0.18.2" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +checksum = "fd3bb3119664efbd78b5e6c93957447944f16bdbced84c17a9f41c7829b81e64" dependencies = [ "glib-sys", "libc", @@ -126,6 +143,15 @@ ] [[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] name = "convert_case" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -141,18 +167,51 @@ checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" [[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] +name = "event-listener" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset 0.9.0", + "memoffset", "rustc_version", ] @@ -221,22 +280,21 @@ [[package]] name = "gdk-pixbuf" -version = "0.18.0" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc9c2ed73a81d556b65d08879ba4ee58808a6b1927ce915262185d6d547c6f3" +checksum = "f6a23f8a0b5090494fd04924662d463f8386cc678dd3915015a838c1a3679b92" dependencies = [ "gdk-pixbuf-sys", "gio", "glib", "libc", - "once_cell", ] [[package]] name = "gdk-pixbuf-sys" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +checksum = "3dcbd04c1b2c4834cc008b4828bc917d062483b88d26effde6342e5622028f96" dependencies = [ "gio-sys", "glib-sys", @@ -247,9 +305,9 @@ [[package]] name = "gdk4" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edb019ad581f8ecf8ea8e4baa6df7c483a95b5a59be3140be6a9c3b0c632af6" +checksum = "9100b25604183f2fd97f55ef087fae96ab4934d7215118a35303e422688e6e4b" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -262,9 +320,9 @@ [[package]] name = "gdk4-sys" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbab43f332a3cf1df9974da690b5bb0e26720ed09a228178ce52175372dcfef0" +checksum = "d0b76874c40bb8d1c7d03a7231e23ac75fa577a456cd53af32ec17ec8f121626" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -279,9 +337,9 @@ [[package]] name = "gio" -version = "0.18.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57052f84e8e5999b258e8adf8f5f2af0ac69033864936b8b6838321db2f759b1" +checksum = "c64947d08d7fbb03bf8ad1f25a8ac6cf4329bc772c9b7e5abe7bf9493c81194f" dependencies = [ "futures-channel", "futures-core", @@ -290,7 +348,6 @@ "gio-sys", "glib", "libc", - "once_cell", "pin-project-lite", "smallvec", "thiserror", @@ -298,24 +355,24 @@ [[package]] name = "gio-sys" -version = "0.18.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +checksum = "bcf8e1d9219bb294636753d307b030c1e8a032062cba74f493c431a5c8b81ce4" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", - "winapi", + "windows-sys", ] [[package]] name = "glib" -version = "0.18.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c316afb01ce8067c5eaab1fc4f2cd47dc21ce7b6296358605e2ffab23ccbd19" +checksum = "01e191cc1af1f35b9699213107068cd3fe05d9816275ac118dc785a0dd8faebf" dependencies = [ - "bitflags 2.4.0", + "bitflags", "futures-channel", "futures-core", "futures-executor", @@ -328,20 +385,18 @@ "libc", "log", "memchr", - "once_cell", "smallvec", "thiserror", ] [[package]] name = "glib-macros" -version = "0.18.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8da903822b136d42360518653fcf154455defc437d3e7a81475bf9a95ff1e47" +checksum = "9972bb91643d589c889654693a4f1d07697fdcb5d104b5c44fb68649ba1bf68d" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro-crate", - "proc-macro-error", "proc-macro2", "quote", "syn 2.0.37", @@ -349,9 +404,9 @@ [[package]] name = "glib-sys" -version = "0.18.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +checksum = "630f097773d7c7a0bb3258df4e8157b47dc98bbfa0e60ad9ab56174813feced4" dependencies = [ "libc", "system-deps", @@ -365,9 +420,9 @@ [[package]] name = "gobject-sys" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +checksum = "c85e2b1080b9418dd0c58b498da3a5c826030343e0ef07bde6a955d28de54979" dependencies = [ "glib-sys", "libc", @@ -376,9 +431,9 @@ [[package]] name = "graphene-rs" -version = "0.18.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2228cda1505613a7a956cca69076892cfbda84fc2b7a62b94a41a272c0c401" +checksum = "99e4d388e96c5f29e2b2f67045d229ddf826d0a8d6d282f94ed3b34452222c91" dependencies = [ "glib", "graphene-sys", @@ -387,9 +442,9 @@ [[package]] name = "graphene-sys" -version = "0.18.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4144cee8fc8788f2a9b73dc5f1d4e1189d1f95305c4cb7bd9c1af1cfa31f59" +checksum = "236ed66cc9b18d8adf233716f75de803d0bf6fc806f60d14d948974a12e240d0" dependencies = [ "glib-sys", "libc", @@ -399,9 +454,9 @@ [[package]] name = "gsk4" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d958e351d2f210309b32d081c832d7de0aca0b077aa10d88336c6379bd01f7e" +checksum = "c65036fc8f99579e8cb37b12487969b707ab23ec8ab953682ff347cbd15d396e" dependencies = [ "cairo-rs", "gdk4", @@ -414,9 +469,9 @@ [[package]] name = "gsk4-sys" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bd9e3effea989f020e8f1ff3fa3b8c63ba93d43b899c11a118868853a56d55" +checksum = "bd24c814379f9c3199dc53e52253ee8d0f657eae389ab282c330505289d24738" dependencies = [ "cairo-sys-rs", "gdk4-sys", @@ -430,9 +485,9 @@ [[package]] name = "gtk4" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb51aa3e9728575a053e1f43543cd9992ac2477e1b186ad824fd4adfb70842" +checksum = "aa82753b8c26277e4af1446c70e35b19aad4fb794a7b143859e7eeb9a4025d83" dependencies = [ "cairo-rs", "field-offset", @@ -451,9 +506,9 @@ [[package]] name = "gtk4-macros" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d57ec49cf9b657f69a05bca8027cff0a8dfd0c49e812be026fc7311f2163832f" +checksum = "40300bf071d2fcd4c94eacc09e84ec6fe73129d2ceb635cf7e55b026b5443567" dependencies = [ "anyhow", "proc-macro-crate", @@ -465,9 +520,9 @@ [[package]] name = "gtk4-sys" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54d8c4aa23638ce9faa2caf7e2a27d4a1295af2155c8e8d28c4d4eeca7a65eb8" +checksum = "0db1b104138f087ccdc81d2c332de5dd049b89de3d384437cc1093b17cd2da18" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -495,9 +550,16 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] name = "helvum" version = "0.5.1" dependencies = [ + "async-channel", "glib", "libadwaita", "libc", @@ -517,6 +579,15 @@ ] [[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -530,9 +601,9 @@ [[package]] name = "libadwaita" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe7e70c06507ed10a16cda707f358fbe60fe0dc237498f78c686ade92fd979c" +checksum = "91b4990248b9e1ec5e72094a2ccaea70ec3809f88f6fd52192f2af306b87c5d9" dependencies = [ "gdk-pixbuf", "gdk4", @@ -546,9 +617,9 @@ [[package]] name = "libadwaita-sys" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e10aaa38de1d53374f90deeb4535209adc40cc5dba37f9704724169bceec69a" +checksum = "23a748e4e92be1265cd9e93d569c0b5dfc7814107985aa6743d670ab281ea1a8" dependencies = [ "gdk4-sys", "gio-sys", @@ -578,11 +649,11 @@ [[package]] name = "libspa" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434617020ddca18b86067912970c55410ca654cdafd775480322f50b857a8c4" +checksum = "65f3a4b81b2a2d8c7f300643676202debd1b7c929dbf5c9bb89402ea11d19810" dependencies = [ - "bitflags 2.4.0", + "bitflags", "cc", "convert_case", "cookie-factory", @@ -595,9 +666,9 @@ [[package]] name = "libspa-sys" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e70ca3f3e70f858ef363046d06178c427b4e0b63d210c95fd87d752679d345" +checksum = "bf0d9716420364790e85cbb9d3ac2c950bde16a7dd36f3209b7dfdfc4a24d01f" dependencies = [ "bindgen", "cc", @@ -612,18 +683,9 @@ [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memoffset" @@ -642,15 +704,13 @@ [[package]] name = "nix" -version = "0.26.4" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if", "libc", - "memoffset 0.7.1", - "pin-utils", ] [[package]] @@ -665,28 +725,27 @@ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "pango" -version = "0.18.0" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a9e54b831d033206160096b825f2070cf5fda7e35167b1c01e9e774f9202d1" +checksum = "b1264d13deb823cc652f26cfe59afb1ec4b9db2a5bd27c41b738c879cc1bfaa1" dependencies = [ "gio", "glib", "libc", - "once_cell", "pango-sys", ] [[package]] name = "pango-sys" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +checksum = "f52ef6a881c19fbfe3b1484df5cad411acaaba29dbec843941c3110d19f340ea" dependencies = [ "glib-sys", "gobject-sys", @@ -695,10 +754,10 @@ ] [[package]] -name = "peeking_take_while" -version = "0.1.2" +name = "parking" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "pin-project-lite" @@ -714,12 +773,12 @@ [[package]] name = "pipewire" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d009c8dd65e890b515a71950f7e4c801523b8894ff33863a40830bf762e9e9" +checksum = "08e645ba5c45109106d56610b3ee60eb13a6f2beb8b74f8dc8186cf261788dda" dependencies = [ "anyhow", - "bitflags 2.4.0", + "bitflags", "libc", "libspa", "libspa-sys", @@ -731,9 +790,9 @@ [[package]] name = "pipewire-sys" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "890c084e7b737246cb4799c86b71a0e4da536031ff7473dd639eba9f95039f64" +checksum = "849e188f90b1dda88fe2bfe1ad31fe5f158af2c98f80fb5d13726c44f3f01112" dependencies = [ "bindgen", "libspa-sys", @@ -742,18 +801,17 @@ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "once_cell", - "toml_edit", + "toml_edit 0.21.1", ] [[package]] @@ -894,9 +952,9 @@ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" @@ -927,7 +985,7 @@ checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" dependencies = [ "cfg-expr", - "heck", + "heck 0.4.1", "pkg-config", "toml", "version-compare", @@ -968,14 +1026,14 @@ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -994,6 +1052,17 @@ ] [[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1006,6 +1075,12 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] name = "version-compare" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1040,6 +1115,72 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] name = "winnow" version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1047,3 +1188,12 @@ dependencies = [ "memchr", ] + +[[package]] +name = "yansi-term" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" +dependencies = [ + "winapi", +] diff -Nru helvum-0.5.1/Cargo.toml helvum-0.5.1+20240328/Cargo.toml --- helvum-0.5.1/Cargo.toml 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/Cargo.toml 2024-03-28 12:29:11.000000000 +0000 @@ -14,12 +14,13 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -pipewire = "0.7.1" -adw = { version = "0.5", package = "libadwaita", features = ["v1_3"] } -glib = { version = "0.18", features = ["log"] } +pipewire = "0.8.0" +adw = { version = "0.6", package = "libadwaita", features = ["v1_4"] } +glib = { version = "0.19", features = ["log"] } +async-channel = "2.2" log = "0.4.11" -once_cell = "1.7.2" +once_cell = "1.19" libc = "0.2" diff -Nru helvum-0.5.1/README.md helvum-0.5.1+20240328/README.md --- helvum-0.5.1/README.md 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/README.md 2024-03-28 12:29:11.000000000 +0000 @@ -23,7 +23,7 @@ Then install the required flatpak platform and SDK, if you dont have them already: ```shell -$ flatpak install org.gnome.{Platform,Sdk}//45 org.freedesktop.Sdk.Extension.rust-stable//23.08 org.freedesktop.Sdk.Extension.llvm16//23.08 +$ flatpak install org.gnome.{Platform,Sdk}//46 org.freedesktop.Sdk.Extension.rust-stable//23.08 org.freedesktop.Sdk.Extension.llvm16//23.08 ``` To compile and install as a flatpak, clone the project, change to the project directory, and run: diff -Nru helvum-0.5.1/build-aux/org.pipewire.Helvum.json helvum-0.5.1+20240328/build-aux/org.pipewire.Helvum.json --- helvum-0.5.1/build-aux/org.pipewire.Helvum.json 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/build-aux/org.pipewire.Helvum.json 2024-03-28 12:29:11.000000000 +0000 @@ -1,7 +1,7 @@ { "id": "org.pipewire.Helvum", "runtime": "org.gnome.Platform", - "runtime-version": "45", + "runtime-version": "46", "sdk": "org.gnome.Sdk", "sdk-extensions": [ "org.freedesktop.Sdk.Extension.rust-stable", diff -Nru helvum-0.5.1/debian/changelog helvum-0.5.1+20240328/debian/changelog --- helvum-0.5.1/debian/changelog 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/changelog 2024-04-20 15:26:09.000000000 +0000 @@ -1,10 +1,23 @@ -helvum (0.5.1-1ubuntu1) noble; urgency=medium +helvum (0.5.1+20240328-1) experimental; urgency=medium - * Cherry-pick several patches to switch to latest GNOME Rust crates - * Add patch to relax rust-async-channel dependency - * Update Build-Depends + [ upstream ] + * development snapshot; + closes: bug#1063026, thanks to Matthias Geiger and Jeremy Bícha - -- Jeremy Bícha Sat, 20 Apr 2024 07:15:40 -0400 + [ Jonas Smedegaard ] + * update watch file to track git commits (not release tags) + * tighten build-dependencies; + build-depend on package for crates async-channel libc + * fix declare Static-Built-Using + (not Build-Using nor XB-X-Cargo-Built-Using) + * declare compliance with Debian Policy 4.7.0 + * add patch 2001 to accept older branch of crate async-channel + * update dh-cargo fork + * update copyright info: update coverage + * build-depend on libgtk-4-bin + * let debhelper snippets invoke meson + + -- Jonas Smedegaard Sat, 20 Apr 2024 17:26:09 +0200 helvum (0.5.1-1) unstable; urgency=medium diff -Nru helvum-0.5.1/debian/control helvum-0.5.1+20240328/debian/control --- helvum-0.5.1/debian/control 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/control 2024-04-20 15:26:09.000000000 +0000 @@ -1,24 +1,25 @@ Source: helvum Section: sound Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Jonas Smedegaard +Maintainer: Jonas Smedegaard Build-Depends: appstream-util, debhelper-compat (= 13), desktop-file-utils, dh-cargo, - librust-async-channel+default-dev, + libgtk-4-bin, + librust-async-channel-dev (<< 3), librust-glib-0.19+default-dev, librust-glib-0.19+log-dev, librust-libadwaita-0.6+default-dev, - librust-libadwaita-0.6+v1-3-dev, + librust-libadwaita-0.6+v1-4-dev, + librust-libc-0.2+default-dev, librust-log-0.4+default-dev, librust-once-cell-1+default-dev, librust-pipewire-0.8+default-dev, libstring-shellquote-perl, meson, -Standards-Version: 4.6.2 +Standards-Version: 4.7.0 Homepage: https://gitlab.freedesktop.org/ryuukyu/helvum Vcs-Git: https://salsa.debian.org/debian/helvum.git Vcs-Browser: https://salsa.debian.org/debian/helvum @@ -36,10 +37,8 @@ ${cargo:Suggests}, Provides: ${cargo:Provides}, -Built-Using: - ${cargo:Built-Using}, -XB-X-Cargo-Built-Using: - ${cargo:X-Cargo-Built-Using}, +Static-Built-Using: + ${cargo:Static-Built-Using}, Description: GTK patchbay for pipewire Helvum is a GTK-based patchbay for pipewire, inspired by the JACK tool catia. diff -Nru helvum-0.5.1/debian/copyright helvum-0.5.1+20240328/debian/copyright --- helvum-0.5.1/debian/copyright 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/copyright 2024-04-20 15:26:09.000000000 +0000 @@ -35,7 +35,7 @@ Reference: debian/copyright Files: - debian/debcargo/bin/cargo + debian/dh-cargo/bin/cargo Copyright: 2022 Jonas Smedegaard 2015-2016 Luca Bruno @@ -44,11 +44,13 @@ License: Apache-2.0 or Expat Files: - debian/debcargo/lib/* + debian/dh-cargo/bin/dh-cargo-built-using + debian/dh-cargo/lib/* Copyright: 2022-2023 Jonas Smedegaard 2016 Josh Triplett - 2018 Ximin Luo + 2019-2021 Sylvestre Ledru + 2018-2021 Ximin Luo License: Expat License: Apache-2.0 diff -Nru helvum-0.5.1/debian/copyright_hints helvum-0.5.1+20240328/debian/copyright_hints --- helvum-0.5.1/debian/copyright_hints 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/copyright_hints 2024-04-20 15:26:09.000000000 +0000 @@ -19,6 +19,9 @@ debian/copyright-check debian/dh-cargo/README.md debian/gbp.conf + debian/patches/2001_async-channel.patch + debian/patches/README + debian/patches/series debian/rules debian/source/format debian/source/lintian-overrides @@ -58,16 +61,25 @@ Copyright: 2015-2016, Luca Bruno 2016-2019, Ximin Luo 2017-2019, Vasudeva Kamath + 2022, Jonas Smedegaard License: Apache-2.0 FIXME Files: debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm Copyright: 2016, Josh Triplett - 2018, Ximin Luo + 2018-2021, Ximin Luo + 2019-2021, Sylvestre Ledru 2022-2023, Jonas Smedegaard License: Expat FIXME +Files: debian/dh-cargo/bin/dh-cargo-built-using +Copyright: 2018-2021, Ximin Luo + 2023, Jonas Smedegaard + file +License: Expat + FIXME + Files: README.md Copyright: NONE License: Expat and/or GPL-3 diff -Nru helvum-0.5.1/debian/dh-cargo/README.md helvum-0.5.1+20240328/debian/dh-cargo/README.md --- helvum-0.5.1/debian/dh-cargo/README.md 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/dh-cargo/README.md 2024-04-20 15:26:09.000000000 +0000 @@ -1,25 +1,23 @@ # dh-cargo fork This is a fork of the debhelper script [dh-cargo], -based on git commit e07347b -(included with version 30 released 2022-11-25), +based on git commit e0317c5 +(included with version 31 released 2023-12-22), with these functional changes: * support workspace (i.e. multi-crate project), * resolve crate name and version from Cargo.toml, using X-Cargo-Crates hint or library package name only as key - * support debhelper option --sourcedirectory + * support debhelper options --sourcedirectory --builddirectory * support debhelper option --no-package * validate package names against Cargo.toml entries, failing early (not after test) on crate vs. package mismatch * generate cargo-checksum during install * pass cargo --remap-path-prefix option sets in RUSTFLAGS * allow overriding CARGO_HOME - * omit installing crate metadata in binary library packages: - * use "cargo package" to install crate contents - * omit license files - * omit debian/patches - (see bug#880689) + * install crate contents using "cargo package" + * omit license files, Cargo.toml.orig, and debian/patches + (see bug#880689) * use debian/Cargo.lock or Cargo.lock (in that order) during build, if Cargo.lock exists * use crates below debian/vendorlibs when available @@ -27,16 +25,18 @@ (not confusingly only dh_auto_test) Also included is a slight fork of related [cargo] wrapper script, -based on git commit e4072cb -(included with version 0.63.1-1 released 2022-11-16), +based on git commit bac0ad2d +(included with version 0.66.0+ds2-1 released 2023-12-03), with these functional changes: + * support CARGO_MANIFEST_DIR=${debhelper_sourcedirectory} * support --remap-path-prefix option sets in RUSTFLAGS by omitting that (not fail) when DEB_CARGO_CRATE is not set * support documented shorter CARGO_HOME path * support cargo option --path * fix only inject path for "cargo install" when not passed as option * support DEB_BUILD_OPTIONS=terse + * warn when cargo wrapper bails due to mismatching CARGO_HOME * enable optimization flags by default also for tests, and support DEB_BUILD_OPTIONS=noopt @@ -64,4 +64,4 @@ ``` - -- Jonas Smedegaard Sat, Sat, 29 Jul 2023 20:14:19 +0200 + -- Jonas Smedegaard Sat, 30 Dec 2023 16:19:18 +0100 diff -Nru helvum-0.5.1/debian/dh-cargo/bin/cargo helvum-0.5.1+20240328/debian/dh-cargo/bin/cargo --- helvum-0.5.1/debian/dh-cargo/bin/cargo 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/dh-cargo/bin/cargo 2024-04-20 15:26:09.000000000 +0000 @@ -2,9 +2,10 @@ """ Wrapper around cargo to have it build using Debian settings. +SPDX-FileCopyrightText: 2022 Jonas Smedegaard SPDX-FileCopyrightText: 2015-2016 Luca Bruno -SPDX-FileCopyrightText: 2016-2019 Ximin Luo SPDX-FileCopyrightText: 2017-2019 Vasudeva Kamath +SPDX-FileCopyrightText: 2016-2019 Ximin Luo SPDX-License-Identifier: Apache-2.0 or MIT @@ -138,13 +139,14 @@ def install(destdir, cratespec, host_rust_type, crate_in_registry, install_prefix, *args): crate, version = cratespec.rsplit("_", 1) + builddir = os.getenv("DEB_BUILDDIR", "target") log("installing into destdir '%s' prefix '%s'" % (destdir, install_prefix)) install_target = destdir + install_prefix path_args = [] if "--path" in args else ["--path", sourcepath()] logrun(["env", "RUST_BACKTRACE=1", # set CARGO_TARGET_DIR so build products are saved in target/ # normally `cargo install` deletes them when it exits - "CARGO_TARGET_DIR=" + sourcepath("target"), + "CARGO_TARGET_DIR=" + sourcepath(builddir), "/usr/bin/cargo"] + list(args) + ([crate, "--vers", version] if crate_in_registry else path_args) + ["--root", install_target], check=True) @@ -153,8 +155,8 @@ # if there was a custom build output, symlink it to debian/cargo_out_dir # hopefully cargo will provide a better solution in future https://github.com/rust-lang/cargo/issues/5457 - r = logrun('''ls -td "target/%s/release/build/%s"-*/out 2>/dev/null | head -n1''' - % (host_rust_type, crate), shell=True, stdout=subprocess.PIPE).stdout + r = logrun('''ls -td "%s/%s/release/build/%s"-*/out 2>/dev/null | head -n1''' + % (builddir, host_rust_type, crate), shell=True, stdout=subprocess.PIPE).stdout r = r.decode("utf-8").rstrip() if r: logrun(["ln", "-sfT", "../%s" % r, "debian/cargo_out_dir"], check=True) @@ -163,6 +165,7 @@ def main(*args): cargo_home = os.getenv("CARGO_HOME", "") if not cargo_home.endswith("debian/cargo_home"): + log(f"WARNING: falling back to simply calling upstream cargo, because CARGO_HOME does not end with debian/cargo_home: ", cargo_home) os.execv("/usr/bin/cargo", ["cargo"] + list(args)) if any(f not in os.environ for f in FLAGS.split()): @@ -175,9 +178,20 @@ build_profiles = os.getenv("DEB_BUILD_PROFILES", "").split() parallel = [] + lto = 0 for o in build_options: if o.startswith("parallel="): parallel = ["-j" + o[9:]] + elif o.startswith("optimize="): + opt_arg = o[9:] + for arg in opt_arg.split(","): + if opt_arg == "-lto": + lto = -1 + elif opt_arg == "+lto": + lto = 1 + else: + log(f"WARNING: unhandled optimization flag: {opt_arg}") + nodoc = "nodoc" in build_options or "nodoc" in build_profiles nocheck = "nocheck" in build_options or "nocheck" in build_profiles noopt = "noopt" in build_options @@ -190,7 +204,7 @@ host_rust_type = os.getenv("DEB_HOST_RUST_TYPE", "") host_gnu_type = os.getenv("DEB_HOST_GNU_TYPE", "") - log("options, profiles, parallel:", build_options, build_profiles, parallel) + log("options, profiles, parallel, lto:", build_options, build_profiles, parallel, lto) log("rust_type, gnu_type:", ", ".join([host_rust_type, host_gnu_type])) if "RUSTFLAGS" in os.environ: @@ -222,11 +236,14 @@ newargs.append("--release") elif noopt and subcmd == "install": newargs.append("--debug") - elif (subcmd is None) and (a in ("check", "clean", "run")): + elif (subcmd is None) and (a in ("check", "run")): subcmd = a newargs.extend([a] + verbose) if not noopt: newargs.append("--release") + elif (subcmd is None) and (a == "clean"): + subcmd = a + newargs.extend([a] + verbose) else: newargs.append(a) @@ -238,6 +255,11 @@ if nocheck and subcmd in ("test", "bench"): return 0 + if lto == 1: + newargs.append("--config profile.release.lto = \"thin\"") + elif lto == -1: + newargs.append("--config profile.release.lto = false") + if subcmd == "clean": logrun(["env", "RUST_BACKTRACE=1", "/usr/bin/cargo"] + list(newargs), check=True) if os.path.exists(cargo_home): diff -Nru helvum-0.5.1/debian/dh-cargo/bin/dh-cargo-built-using helvum-0.5.1+20240328/debian/dh-cargo/bin/dh-cargo-built-using --- helvum-0.5.1/debian/dh-cargo/bin/dh-cargo-built-using 1970-01-01 00:00:00.000000000 +0000 +++ helvum-0.5.1+20240328/debian/dh-cargo/bin/dh-cargo-built-using 2024-04-20 15:26:09.000000000 +0000 @@ -0,0 +1,180 @@ +#!/bin/sh +# Generates Built-Using after a successful cargo build. +# Run this in the package top-level directory where debian/ is. +# +# SPDX-FileCopyrightText: 2023 Jonas Smedegaard +# SPDX-FileCopyrightText: 2018-2021 Ximin Luo +# +# SPDX-License-Identifier: MIT + +set -e + +DEB_BUILDDIR="${DEB_BUILD_DIR:-target}" +DEB_HOST_RUST_TYPE="${DEB_HOST_RUST_TYPE:-$(printf "include /usr/share/rustc/architecture.mk\nall:\n\techo \$(DEB_HOST_RUST_TYPE)\n" | make --no-print-directory -sf -)}" +CARGO_REGISTRY="${CARGO_REGISTRY:-debian/cargo_registry}" +CARGO_CHANNEL="${CARGO_CHANNEL:-release}" +# useful for testing: +# CARGO_REGISTRY="$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823" DEB_HOST_RUST_TYPE="." CARGO_CHANNEL=debug + +CARGO_TARGET_DIR="$DEB_BUILDDIR/$DEB_HOST_RUST_TYPE/$CARGO_CHANNEL" +CARGO_TARGET_DIR_ABS="$(readlink -f "$CARGO_TARGET_DIR")" + +CPRIGHT_FORMAT="https://www.debian.org/doc/packaging-manuals/copyright-format/1.0" +SRCLEFT_LICENSES="$(echo GPL LGPL AGPL GFDL MPL CDDL CPL Artistic Perl QPL | tr ' ' '\n')" +pkg_has_srcleft_license() { + local pkg="$1" + local ver="$2" + local f="/usr/share/doc/$pkg/copyright" + if ! sed -nre 's ^Format: (.*) \1 gp' "$f" | grep -qiw "$CPRIGHT_FORMAT"; then + echo >&2 "$0: abort: Not in machine-readable format: $f" + echo 2 + elif sed -nre 's ^X-Binary-Requires-Source: (.*) \1 gp' "$f" | grep -qiw yes; then + echo 1 + elif sed -nre 's ^License: (.*) \1 gp' "$f" | grep -qiwF "$SRCLEFT_LICENSES"; then + echo 1 + else + echo 0 + fi +} + +dep_files_to_pkgs() { + xargs -r dpkg -S \ + | sed -nre 's (.*): .* \1 gp' \ + | xargs -r dpkg-query --show \ + | while read pkg ver; do echo "$pkg $ver $(pkg_has_srcleft_license "${pkg%:*}" "$ver")"; done + # pkg_has_srcleft_license should be accurate for all rust crates, no need to give a $containing_crate + # this is due to nature of crate copyright info, and the debian rust packaging policy +} + +rust_dep_files() { + cat "$CARGO_TARGET_DIR/deps"/*.d \ + | sed -nre 's ^\S*/('"$CARGO_REGISTRY"'/[^/]*)/.* '"$(readlink -f "$PWD")/"'\1 gp' \ + | sort -u \ + | xargs -r readlink -f +} + +rust_libs() { + { which rustc; rust_dep_files; } | dep_files_to_pkgs +} + +gcc_default_searchdirs() { + gcc -print-search-dirs \ + | sed -nre 's ^libraries: (.*) \1 gp' \ + | tr ':' '\n' \ + | sed -e 's ^= '"$(gcc -print-sysroot)"' g' \ + | xargs readlink -m 2>/dev/null # suppress errors caused by early pipe closure +} + +rust_search_lib() { + local lib="$1" + { + cat + # rust does not actually search normal paths when linking static libs + # - see https://github.com/rust-lang/rust/issues/43118 + # - see also `fn link_rlib` in back/link.rs which calls + # `pub fn find_library` in back/archive.rs which generates the error message + #gcc_default_searchdirs + } | while read searchdir; do + #echo >&2 "searching $searchdir for static lib $lib" + local f="$(readlink -m "$searchdir/lib${lib}.a")" + if test -f "$f"; then + printf "%s\n" "$f" + break + fi + done +} + +native_libs() { + ls -1d "$CARGO_TARGET_DIR/build"/*/output 2>/dev/null | while read output; do + sed -nre 's ^cargo:rustc-link-lib=static=(.*) \1 '"$output"' gp' "$output" + done | while read lib output; do + local containing_crate="$(basename "$(dirname "$output")")" + test -n "$lib" || continue + local libfile="$(sed -nre 's ^cargo:rustc-link-search=native=(.*) \1 gp' "$output" | rust_search_lib "$lib")" + local srcleft="" + test -n "$libfile" || { echo >&2 "$0: abort: could not find static lib '$lib'; rustc should have failed already?"; exit 1; } + echo >&2 "$0: found static lib $lib at $libfile" + if [ "${libfile#$CARGO_TARGET_DIR_ABS/}" != "$libfile" ]; then + # static library source code embedded in crate + local srcstat="$(sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=([01]=.*) \1 gp' "$output")" + case "$srcstat" in + 0=*|1=*) + srcleft="${srcstat%%=*}" + libfile="${srcstat#*=}" + if [ "$(readlink -f "$libfile")" = "$(readlink -f "$PWD")" ]; then + # Note that this exception only applies in the case that where you are building + # the Debian package for $containing_crate itself. In the case where you are + # building a Debian package for crate X depending on $containing_crate, the + # latter still has to output the dh-cargo:deb-built-using in their build.rs so + # that the Debian package for crate X can correctly set Built-Using themselves. + echo >&2 "$0: static library derived from $libfile which is the top-level crate being built, no need to add Built-Using" + continue + fi + ;; + *) + echo >&2 "$0: abort: could not determine source-distribution conditions of ${libfile#$CARGO_TARGET_DIR_ABS/}." + echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'println!(\"dh-cargo:deb-built-using=$lib=\$s={}\", env::var(\"CARGO_MANIFEST_DIR\").unwrap());' where:" + echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0" + exit 1 + ;; + esac + fi + local wpkg="$(dpkg -S "$(readlink -f "$libfile")")" + test -n "$wpkg" || { echo >&2 "$0: abort: could not find Debian package for file $libfile"; exit 1; } + local pkgstat="$(echo "$wpkg" | sed -nre 's (.*): .* \1 gp' | xargs -r dpkg-query --show)" + local pkg="$(echo "$pkgstat" | cut -f1)" + local ver="$(echo "$pkgstat" | cut -f2)" + # static library source code embedded in crate (from earlier) + if [ -n "$srcleft" ]; then + echo "$pkg $ver $srcleft" + # static libraries from another Debian package + elif sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=0~=(.*) \1 gp' "$output" | { echo "${pkg%:*} $ver" | grep -qExf /dev/fd/3; } 3<&0; then + echo "$pkg $ver 0" + elif sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=1~=(.*) \1 gp' "$output" | { echo "${pkg%:*} $ver" | grep -qExf /dev/fd/3; } 3<&0; then + echo "$pkg $ver 1" + else + # guess the conditions based on the whole d/copyright file + # this loses granularity, e.g. gcc is mostly distributed as GPL-3 but the libbacktrace portion is BSD-3 + # to retain granularity the crate package maintainer should patch build.rs as suggested + echo >&2 "$0: warning: guessing source-distribution conditions of $libfile, this may be inaccurate." + echo >&2 "$0: warning: patch build.rs to suppress the above warning" + srcleft="$(pkg_has_srcleft_license "${pkg%:*}" "$ver")" + if [ "$srcleft" -gt 1 ]; then + echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'dh-cargo:deb-built-using=$lib=\$s~=\$PAT' where:" + echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0" + echo >&2 "- \$PAT is an egrep pattern matching the \"\$pkg \$ver\" combinations that satisfy \$s" + echo >&2 " for example '$pkg .*' matches the currently-relevant package, $pkg $ver" + exit 1 + fi + echo "$pkg $ver $srcleft" + fi + done +} + +output() { + local binpkg="$1" + if [ -z "$binpkg" ]; then + cat + else + local built_using="" + local built_using_x="" + while read pkg ver srcleft; do + local src="$(dpkg-query -f '${source:Package}' --show "$pkg")" + local srcver="$(dpkg-query -f '${source:Version}' --show "$pkg")" + case "$srcleft" in + 2) exit 1;; + 1) built_using="${built_using}$src (= $srcver), ";; + esac + built_using_x="${built_using_x}$src (= $srcver), " + done + echo "cargo:Built-Using=${built_using%, }" >> "debian/$binpkg.substvars" + echo "cargo:X-Cargo-Built-Using=${built_using_x%, }" >> "debian/$binpkg.substvars" + echo "cargo:Static-Built-Using=${built_using_x%, }" >> "debian/$binpkg.substvars" + fi +} + +native_libs="$(native_libs)" # capture output outside of pipe so set -e works +{ +rust_libs +test -z "$native_libs" || echo "$native_libs" +} | LC_ALL=C.utf-8 sort -u | output "$@" diff -Nru helvum-0.5.1/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm helvum-0.5.1+20240328/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm --- helvum-0.5.1/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm 2024-04-20 15:26:09.000000000 +0000 @@ -1,8 +1,9 @@ # debhelper buildsystem for Rust crates using Cargo # -# SPDX-FileCopyrightText: 2016 Josh Triplett -# SPDX-FileCopyrightText: 2018 Ximin Luo # SPDX-FileCopyrightText: 2022-2023 Jonas Smedegaard +# SPDX-FileCopyrightText: 2016 Josh Triplett +# SPDX-FileCopyrightText: 2019-2021 Sylvestre Ledru +# SPDX-FileCopyrightText: 2018-2021 Ximin Luo # # SPDX-License-Identifier: MIT # @@ -37,12 +38,16 @@ use String::ShellQuote qw( shell_quote ); use base 'Debian::Debhelper::Buildsystem'; -use constant CARGO_SYSTEM_REGISTRY => '/usr/share/cargo/registry/'; +use constant CARGO_SYSTEM_REGISTRY => '/usr/share/cargo/registry'; sub DESCRIPTION { "Rust Cargo" } +sub DEFAULT_BUILD_DIRECTORY { + "target" +} + sub cargo_crates { my ( $root, $src, $default ) = @_; open(F, "cargo metadata --manifest-path $src --no-deps --format-version 1 |"); @@ -54,6 +59,7 @@ my %object = ( cratename => join( '-', $key->{name}, $key->{version} ), cratespec => join( '_', $key->{name}, $key->{version} ), + pkgid => join( '@', $key->{name}, $key->{version} ), ); $object{sourcepath} = File::Spec->abs2rel( $key->{manifest_path} =~ s{/Cargo\.toml$}{}r, @@ -74,6 +80,11 @@ $crates{_default} //= \%object if $key->{name} eq $default; } + # resolve amount of local dependencies + # TODO: use Graph to compute an always reliable order instead + for my $key ( @{ $manifest->{packages} } ) { + $crates{ $key->{name} =~ tr/_/-/r }{depcount} = grep { exists $crates{ $_->{name} =~ tr/_/-/r } } @{ $key->{dependencies} }; + } return \%crates; } @@ -247,7 +258,7 @@ "--remap-path-prefix", "$_->{cratespec}=$_->{systempath}", )} map { @{ $this->{libpkg}{$_}{crates} } } sort keys %{ $this->{libpkg} }; - push @rustflags, "--remap-path-prefix", "$registry_path=" . CARGO_SYSTEM_REGISTRY; + push @rustflags, "--remap-path-prefix", "$registry_path=" . CARGO_SYSTEM_REGISTRY . '/'; my $rustflags = shell_quote(@rustflags); $rustflags .= " $ENV{RUSTFLAGS}" if $ENV{RUSTFLAGS}; @@ -259,8 +270,9 @@ if ( -d 'debian/vendorlibs' ) { complex_doit( qw(find debian/cargo_registry -lname '../vendorlibs/*' -delete)); + # force to favor this crate over a dependency pulled from system complex_doit( - qw(ln --symbolic --relative --target-directory=debian/cargo_registry debian/vendorlibs/*)); + qw(ln --symbolic --force --relative --target-directory=debian/cargo_registry debian/vendorlibs/*)); } $this->doit_in_sourcedir(qw(cargo update)) if -f $cargo_lock; } @@ -279,25 +291,30 @@ # which might fail if e.g. the package # requires non-rust system dependencies and the maintainer didn't provide # this additional information to debcargo. - $this->doit_in_sourcedir($this->{cargo_command}, "test", @_); + $this->doit_in_sourcedir("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + $this->{cargo_command}, "test", @_); # test generating Built-Using fields my $channel = get_buildoption("noopt") ? 'debug' : 'release'; - doit("env", "CARGO_CHANNEL=$channel", "/usr/share/cargo/bin/dh-cargo-built-using"); + doit("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + "CARGO_CHANNEL=$channel", + "debian/dh-cargo/bin/dh-cargo-built-using"); } sub install { my $this=shift; my $destdir=shift; - foreach my $crate ( map { @{ $_->{crates} } } sort values %{ $this->{libpkg} } ) { + foreach my $crate ( sort { $a->{depcount} cmp $b->{depcount} } map { @{ $_->{crates} } } sort values %{ $this->{libpkg} } ) { my $target = tmpdir( $crate->{libpkg}{name} ) . $crate->{systempath}; install_dir($target); $this->doit_in_somedir( $crate->{sourcepath}, - "env", "DEB_CARGO_CRATE=$crate->{cratespec}", - qw(cargo package --offline --allow-dirty --no-verify)); + qw(cargo package --offline --allow-dirty --no-verify), + '--target-dir', cwd . '/target', '--package', $crate->{pkgid} ); $this->doit_in_somedir( "$target/..", - qw(tar --exclude debian/* --exclude debian --exclude Cargo.lock --exclude COPYING* --exclude LICENSE* -xvf), + 'tar', map( { ( '--exclude', $_ ) } qw(debian/* debian Cargo.toml.orig Cargo.lock COPYING* LICENSE*) ), '-xvf', $this->_rel2rel( $crate->{packagepath}, "$target/.." ), $crate->{cratename} ); complex_doit( @@ -307,7 +324,12 @@ ">", "$target/.cargo-checksum.json"); # prevent an ftpmaster auto-reject regarding files with old dates. doit("touch", "-d@" . $ENV{SOURCE_DATE_EPOCH}, "$target/Cargo.toml"); - } + # add crate to local registry, needed by some multi-crate workspaces + # maybe related: + # force to favor this crate over a dependency pulled from system + complex_doit( + qw(ln --symbolic --force --relative --target-directory=debian/cargo_registry), $target ); + } foreach my $featurepkg (@{$this->{featurepkg}}) { my $target = tmpdir( $featurepkg->{name} ) . "/usr/share/doc"; install_dir($target); @@ -317,17 +339,24 @@ # Do the install my $destdir = $ENV{'DESTDIR'} || tmpdir( $crate->{binpkg}{name} ); my @path_opts = $crate->{sourcepath} ne '.' ? ('--path', $crate->{sourcepath}) : (); - $this->doit_in_sourcedir("env", "DESTDIR=$destdir", "DEB_CARGO_CRATE=$crate->{cratespec}", - $this->{cargo_command}, "install", @path_opts, @_); + $this->doit_in_sourcedir("env", + "DEB_CARGO_CRATE=$crate->{cratespec}", + "DEB_BUILDDIR=" . $this->get_builddir(), + "DESTDIR=$destdir", + $this->{cargo_command}, "install", @path_opts, @_); # generate Built-Using fields - doit("env", "/usr/share/cargo/bin/dh-cargo-built-using", $crate->{binpkg}{name}); + doit("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + "debian/dh-cargo/bin/dh-cargo-built-using", $crate->{binpkg}{name}); } } sub clean { my $this=shift; doit("touch", "--no-create", "-d@" . $ENV{SOURCE_DATE_EPOCH}, ".cargo_vcs_info.json"); - $this->doit_in_sourcedir($this->{cargo_command}, "clean", @_); + $this->doit_in_sourcedir("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + $this->{cargo_command}, "clean", @_); doit("rm", "-rf", "debian/cargo_registry"); } diff -Nru helvum-0.5.1/debian/patches/2001_async-channel.patch helvum-0.5.1+20240328/debian/patches/2001_async-channel.patch --- helvum-0.5.1/debian/patches/2001_async-channel.patch 1970-01-01 00:00:00.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/2001_async-channel.patch 2024-04-20 15:26:09.000000000 +0000 @@ -0,0 +1,17 @@ +Description: accept older branch of crate async-channel +Author: Jonas Smedegaard +Forwarded: not-needed +Last-Update: 2024-04-20 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -17,7 +17,7 @@ + pipewire = "0.8.0" + adw = { version = "0.6", package = "libadwaita", features = ["v1_4"] } + glib = { version = "0.19", features = ["log"] } +-async-channel = "2.2" ++async-channel = ">= 1.9.0, <= 2" + + log = "0.4.11" + diff -Nru helvum-0.5.1/debian/patches/README helvum-0.5.1+20240328/debian/patches/README --- helvum-0.5.1/debian/patches/README 1970-01-01 00:00:00.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/README 2024-04-20 15:26:09.000000000 +0000 @@ -0,0 +1,3 @@ +0xxx: Grabbed from upstream development. +1xxx: Possibly relevant for upstream adoption. +2xxx: Only relevant for official Debian release. \ No newline at end of file diff -Nru helvum-0.5.1/debian/patches/Update-to-latest-gtk-rs-crates.patch helvum-0.5.1+20240328/debian/patches/Update-to-latest-gtk-rs-crates.patch --- helvum-0.5.1/debian/patches/Update-to-latest-gtk-rs-crates.patch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/Update-to-latest-gtk-rs-crates.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,401 +0,0 @@ -From: Tom Wagner -Date: Sat, 23 Mar 2024 11:51:04 +0100 -Subject: Update to latest gtk-rs crates - -(cherry picked from commit f32559511d5e950bf5fde965de47c9caec6eabba) ---- - Cargo.toml | 7 ++-- - src/application.rs | 7 ++-- - src/graph_manager.rs | 94 ++++++++++++++++++++++++++---------------- - src/main.rs | 2 +- - src/pipewire_connection/mod.rs | 38 ++++++++--------- - src/ui/graph/port.rs | 4 +- - 6 files changed, 89 insertions(+), 63 deletions(-) - -diff --git a/Cargo.toml b/Cargo.toml -index a9a220c..f839bfc 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -15,11 +15,12 @@ categories = ["gui", "multimedia"] - - [dependencies] - pipewire = "0.8.0" --adw = { version = "0.5", package = "libadwaita", features = ["v1_4"] } --glib = { version = "0.18", features = ["log"] } -+adw = { version = "0.6", package = "libadwaita", features = ["v1_4"] } -+glib = { version = "0.19", features = ["log"] } -+async-channel = "2.2" - - log = "0.4.11" - --once_cell = "1.7.2" -+once_cell = "1.19" - - libc = "0.2" -diff --git a/src/application.rs b/src/application.rs -index 97aa21b..a40ac30 100644 ---- a/src/application.rs -+++ b/src/application.rs -@@ -16,7 +16,7 @@ - - use adw::{ - gio, -- glib::{self, clone, Receiver}, -+ glib::{self, clone}, - gtk, - prelude::*, - subclass::prelude::*, -@@ -33,8 +33,9 @@ static AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); - mod imp { - use super::*; - -+ use std::cell::OnceCell; -+ - use adw::subclass::prelude::AdwApplicationImpl; -- use once_cell::unsync::OnceCell; - - #[derive(Default)] - pub struct Application { -@@ -140,7 +141,7 @@ impl Application { - /// Create the view. - /// This will set up the entire user interface and prepare it for being run. - pub(super) fn new( -- gtk_receiver: Receiver, -+ gtk_receiver: async_channel::Receiver, - pw_sender: Sender, - ) -> Self { - let app: Application = glib::Object::builder() -diff --git a/src/graph_manager.rs b/src/graph_manager.rs -index 4b00cba..b80f0d3 100644 ---- a/src/graph_manager.rs -+++ b/src/graph_manager.rs -@@ -23,9 +23,7 @@ use crate::{ui::graph::GraphView, GtkMessage, PipewireMessage}; - mod imp { - use super::*; - -- use std::{cell::RefCell, collections::HashMap}; -- -- use once_cell::unsync::OnceCell; -+ use std::{cell::OnceCell, cell::RefCell, collections::HashMap}; - - use crate::{ui::graph, MediaType, NodeType}; - -@@ -53,36 +51,58 @@ mod imp { - impl ObjectImpl for GraphManager {} - - impl GraphManager { -- pub fn attach_receiver(&self, receiver: glib::Receiver) { -- receiver.attach(None, glib::clone!( -- @weak self as imp => @default-return glib::ControlFlow::Continue, -- move |msg| { -- match msg { -- PipewireMessage::NodeAdded { id, name, node_type } => imp.add_node(id, name.as_str(), node_type), -- PipewireMessage::NodeNameChanged { id, name, media_name } => imp.node_name_changed(id, &name, &media_name), -- PipewireMessage::PortAdded { id, node_id, name, direction } => imp.add_port(id, name.as_str(), node_id, direction), -- PipewireMessage::PortFormatChanged { id, media_type } => imp.port_media_type_changed(id, media_type), -- PipewireMessage::LinkAdded { -- id, port_from, port_to, active, media_type -- } => imp.add_link(id, port_from, port_to, active, media_type), -- PipewireMessage::LinkStateChanged { id, active } => imp.link_state_changed(id, active), -- PipewireMessage::LinkFormatChanged { id, media_type } => imp.link_format_changed(id, media_type), -- PipewireMessage::NodeRemoved { id } => imp.remove_node(id), -- PipewireMessage::PortRemoved { id, node_id } => imp.remove_port(id, node_id), -- PipewireMessage::LinkRemoved { id } => imp.remove_link(id), -- PipewireMessage::Connecting => { -- imp.obj().connection_banner().set_revealed(true); -- } -- PipewireMessage::Connected => { -- imp.obj().connection_banner().set_revealed(false); -- }, -- PipewireMessage::Disconnected => { -- imp.clear(); -- }, -- }; -- glib::ControlFlow::Continue -- } -- )); -+ pub async fn receive(&self, receiver: async_channel::Receiver) { -+ loop { -+ let Ok(msg) = receiver.recv().await else { -+ continue; -+ }; -+ match msg { -+ PipewireMessage::NodeAdded { -+ id, -+ name, -+ node_type, -+ } => self.add_node(id, name.as_str(), node_type), -+ PipewireMessage::NodeNameChanged { -+ id, -+ name, -+ media_name, -+ } => self.node_name_changed(id, &name, &media_name), -+ PipewireMessage::PortAdded { -+ id, -+ node_id, -+ name, -+ direction, -+ } => self.add_port(id, name.as_str(), node_id, direction), -+ PipewireMessage::PortFormatChanged { id, media_type } => { -+ self.port_media_type_changed(id, media_type) -+ } -+ PipewireMessage::LinkAdded { -+ id, -+ port_from, -+ port_to, -+ active, -+ media_type, -+ } => self.add_link(id, port_from, port_to, active, media_type), -+ PipewireMessage::LinkStateChanged { id, active } => { -+ self.link_state_changed(id, active) -+ } -+ PipewireMessage::LinkFormatChanged { id, media_type } => { -+ self.link_format_changed(id, media_type) -+ } -+ PipewireMessage::NodeRemoved { id } => self.remove_node(id), -+ PipewireMessage::PortRemoved { id, node_id } => self.remove_port(id, node_id), -+ PipewireMessage::LinkRemoved { id } => self.remove_link(id), -+ PipewireMessage::Connecting => { -+ self.obj().connection_banner().set_revealed(true); -+ } -+ PipewireMessage::Connected => { -+ self.obj().connection_banner().set_revealed(false); -+ } -+ PipewireMessage::Disconnected => { -+ self.clear(); -+ } -+ }; -+ } - } - - /// Add a new node to the view. -@@ -332,19 +352,23 @@ glib::wrapper! { - pub struct GraphManager(ObjectSubclass); - } - -+async fn receive(graph_manager: GraphManager, receiver: async_channel::Receiver) { -+ graph_manager.imp().receive(receiver).await -+} -+ - impl GraphManager { - pub fn new( - graph: &GraphView, - connection_banner: &adw::Banner, - sender: PwSender, -- receiver: glib::Receiver, -+ receiver: async_channel::Receiver, - ) -> Self { - let res: Self = glib::Object::builder() - .property("graph", graph) - .property("connection-banner", connection_banner) - .build(); - -- res.imp().attach_receiver(receiver); -+ glib::MainContext::default().spawn_local(receive(res.clone(), receiver)); - assert!( - res.imp().pw_sender.set(sender).is_ok(), - "Should be able to set pw_sender)" -diff --git a/src/main.rs b/src/main.rs -index 467c544..1f3b1b7 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -120,7 +120,7 @@ fn main() -> Result<(), Box> { - - // Start the pipewire thread with channels in both directions. - -- let (gtk_sender, gtk_receiver) = glib::MainContext::channel(glib::Priority::DEFAULT); -+ let (gtk_sender, gtk_receiver) = async_channel::unbounded(); - let (pw_sender, pw_receiver) = pipewire::channel::channel(); - let pw_thread = - std::thread::spawn(move || pipewire_connection::thread_main(gtk_sender, pw_receiver)); -diff --git a/src/pipewire_connection/mod.rs b/src/pipewire_connection/mod.rs -index c554d67..ba2d77f 100644 ---- a/src/pipewire_connection/mod.rs -+++ b/src/pipewire_connection/mod.rs -@@ -63,7 +63,7 @@ enum ProxyItem { - - /// The "main" function of the pipewire thread. - pub(super) fn thread_main( -- gtk_sender: glib::Sender, -+ gtk_sender: async_channel::Sender, - mut pw_receiver: pipewire::channel::Receiver, - ) { - let mainloop = MainLoop::new(None).expect("Failed to create mainloop"); -@@ -81,7 +81,7 @@ pub(super) fn thread_main( - if !is_connecting { - is_connecting = true; - gtk_sender -- .send(PipewireMessage::Connecting) -+ .send_blocking(PipewireMessage::Connecting) - .expect("Failed to send message"); - } - -@@ -116,7 +116,7 @@ pub(super) fn thread_main( - if is_connecting { - is_connecting = false; - gtk_sender -- .send(PipewireMessage::Connected) -+ .send_blocking(PipewireMessage::Connected) - .expect("Failed to send message"); - } - -@@ -145,7 +145,7 @@ pub(super) fn thread_main( - } - - if res == -libc::EPIPE { -- gtk_sender.send(PipewireMessage::Disconnected) -+ gtk_sender.send_blocking(PipewireMessage::Disconnected) - .expect("Failed to send message"); - mainloop.quit(); - } else { -@@ -169,7 +169,7 @@ pub(super) fn thread_main( - )) - .global_remove(clone!(@strong proxies, @strong state => move |id| { - if let Some(item) = state.borrow_mut().remove(id) { -- gtk_sender.send(match item { -+ gtk_sender.send_blocking(match item { - Item::Node { .. } => PipewireMessage::NodeRemoved {id}, - Item::Port { node_id } => PipewireMessage::PortRemoved {id, node_id}, - Item::Link { .. } => PipewireMessage::LinkRemoved {id}, -@@ -202,7 +202,7 @@ fn get_node_name(props: &DictRef) -> &str { - /// Handle a new node being added - fn handle_node( - node: &GlobalObject<&DictRef>, -- sender: &glib::Sender, -+ sender: &async_channel::Sender, - registry: &Rc, - proxies: &Rc>>, - state: &Rc>, -@@ -237,7 +237,7 @@ fn handle_node( - state.borrow_mut().insert(node.id, Item::Node); - - sender -- .send(PipewireMessage::NodeAdded { -+ .send_blocking(PipewireMessage::NodeAdded { - id: node.id, - name, - node_type, -@@ -263,7 +263,7 @@ fn handle_node( - - fn handle_node_info( - info: &NodeInfoRef, -- sender: &glib::Sender, -+ sender: &async_channel::Sender, - proxies: &Rc>>, - ) { - debug!("Received node info: {:?}", info); -@@ -280,7 +280,7 @@ fn handle_node_info( - let name = get_node_name(props).to_string(); - - sender -- .send(PipewireMessage::NodeNameChanged { -+ .send_blocking(PipewireMessage::NodeNameChanged { - id, - name, - media_name: media_name.to_string(), -@@ -292,7 +292,7 @@ fn handle_node_info( - /// Handle a new port being added - fn handle_port( - port: &GlobalObject<&DictRef>, -- sender: &glib::Sender, -+ sender: &async_channel::Sender, - registry: &Rc, - proxies: &Rc>>, - state: &Rc>, -@@ -326,7 +326,7 @@ fn handle_port_info( - info: &PortInfoRef, - proxies: &Rc>>, - state: &Rc>, -- sender: &glib::Sender, -+ sender: &async_channel::Sender, - ) { - debug!("Received port info: {:?}", info); - -@@ -367,7 +367,7 @@ fn handle_port_info( - } - - sender -- .send(PipewireMessage::PortAdded { -+ .send_blocking(PipewireMessage::PortAdded { - id, - node_id, - name, -@@ -380,7 +380,7 @@ fn handle_port_info( - fn handle_port_enum_format( - port_id: u32, - param: Option<&pipewire::spa::pod::Pod>, -- sender: &glib::Sender, -+ sender: &async_channel::Sender, - ) { - let media_type = param - .and_then(|param| pipewire::spa::param::format_utils::parse_format(param).ok()) -@@ -388,7 +388,7 @@ fn handle_port_enum_format( - .unwrap_or(MediaType::Unknown); - - sender -- .send(PipewireMessage::PortFormatChanged { -+ .send_blocking(PipewireMessage::PortFormatChanged { - id: port_id, - media_type, - }) -@@ -398,7 +398,7 @@ fn handle_port_enum_format( - /// Handle a new link being added - fn handle_link( - link: &GlobalObject<&DictRef>, -- sender: &glib::Sender, -+ sender: &async_channel::Sender, - registry: &Rc, - proxies: &Rc>>, - state: &Rc>, -@@ -428,7 +428,7 @@ fn handle_link( - fn handle_link_info( - info: &LinkInfoRef, - state: &Rc>, -- sender: &glib::Sender, -+ sender: &async_channel::Sender, - ) { - debug!("Received link info: {:?}", info); - -@@ -439,7 +439,7 @@ fn handle_link_info( - // Info was an update - figure out if we should notify the gtk thread - if info.change_mask().contains(LinkChangeMask::STATE) { - sender -- .send(PipewireMessage::LinkStateChanged { -+ .send_blocking(PipewireMessage::LinkStateChanged { - id, - active: matches!(info.state(), LinkState::Active), - }) -@@ -447,7 +447,7 @@ fn handle_link_info( - } - if info.change_mask().contains(LinkChangeMask::FORMAT) { - sender -- .send(PipewireMessage::LinkFormatChanged { -+ .send_blocking(PipewireMessage::LinkFormatChanged { - id, - media_type: get_link_media_type(info), - }) -@@ -461,7 +461,7 @@ fn handle_link_info( - state.insert(id, Item::Link { port_from, port_to }); - - sender -- .send(PipewireMessage::LinkAdded { -+ .send_blocking(PipewireMessage::LinkAdded { - id, - port_from, - port_to, -diff --git a/src/ui/graph/port.rs b/src/ui/graph/port.rs -index 4189cd9..5826e3a 100644 ---- a/src/ui/graph/port.rs -+++ b/src/ui/graph/port.rs -@@ -28,9 +28,9 @@ use super::PortHandle; - mod imp { - use super::*; - -- use std::cell::Cell; -+ use std::cell::{Cell, OnceCell}; - -- use once_cell::{sync::Lazy, unsync::OnceCell}; -+ use once_cell::sync::Lazy; - use pipewire::spa::{param::format::MediaType, utils::Direction}; - - /// Graphical representation of a pipewire port. diff -Nru helvum-0.5.1/debian/patches/Use-responsive-design.patch helvum-0.5.1+20240328/debian/patches/Use-responsive-design.patch --- helvum-0.5.1/debian/patches/Use-responsive-design.patch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/Use-responsive-design.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -From: Angelo Verlain Shema -Date: Tue, 10 Oct 2023 18:16:23 +0000 -Subject: Use responsive design - -(cherry picked from commit e1f63ddd28c216b955a624b215e0d367f513db51) ---- - src/style.css | 17 +++++++++++++++++ - src/ui/graph/zoomentry.rs | 1 + - src/ui/graph/zoomentry.ui | 31 +++++++++++++++++++++---------- - src/ui/window.ui | 37 ++++++++++++++++++++----------------- - 4 files changed, 59 insertions(+), 27 deletions(-) - -diff --git a/src/style.css b/src/style.css -index fb8e8a3..f8fa650 100644 ---- a/src/style.css -+++ b/src/style.css -@@ -53,3 +53,20 @@ port-handle { - border-radius: 50%; - background-color: @media-type-unknown; - } -+ -+button.rounded { -+ padding: 6px; -+ border-radius: 9999px; -+} -+ -+entry.rounded { -+ border-radius: 9999px; -+} -+ -+entry.rounded > :first-child { -+ padding-left: 12px; -+} -+ -+entry.rounded > :nth-child(2) { -+ padding-right: 12px; -+} -diff --git a/src/ui/graph/zoomentry.rs b/src/ui/graph/zoomentry.rs -index 6c6a951..667236b 100644 ---- a/src/ui/graph/zoomentry.rs -+++ b/src/ui/graph/zoomentry.rs -@@ -34,6 +34,7 @@ mod imp { - menu.append(Some("200%"), Some("win.set-zoom(2.0)")); - menu.append(Some("300%"), Some("win.set-zoom(3.0)")); - let popover = gtk::PopoverMenu::from_model(Some(&menu)); -+ popover.set_position(gtk::PositionType::Top); - - ZoomEntry { - graphview: Default::default(), -diff --git a/src/ui/graph/zoomentry.ui b/src/ui/graph/zoomentry.ui -index 975e971..def1a6a 100644 ---- a/src/ui/graph/zoomentry.ui -+++ b/src/ui/graph/zoomentry.ui -@@ -1,26 +1,37 @@ - - - -- -\ No newline at end of file -+ -diff --git a/src/ui/window.ui b/src/ui/window.ui -index ef2b72b..22d72f1 100644 ---- a/src/ui/window.ui -+++ b/src/ui/window.ui -@@ -20,19 +20,9 @@ - - - -- -- 6 -- -- -- graph -- -- -- -- -- open-menu-symbolic -- primary_menu -- -- -+ -+ open-menu-symbolic -+ primary_menu - - - -@@ -44,11 +34,24 @@ - - - -- -+ - -- -- true -- true -+ -+ -+ -+ true -+ true -+ -+ -+ -+ -+ -+ -+ graph -+ end -+ end -+ 24 -+ 24 - - - diff -Nru helvum-0.5.1/debian/patches/pw-Set-media.category-property-to-manager.patch helvum-0.5.1+20240328/debian/patches/pw-Set-media.category-property-to-manager.patch --- helvum-0.5.1/debian/patches/pw-Set-media.category-property-to-manager.patch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/pw-Set-media.category-property-to-manager.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -From: "Tom A. Wagner" -Date: Thu, 12 Oct 2023 10:29:42 +0200 -Subject: pw: Set media.category property to manager - -This will make the session manager give Helvum full permissions even when -used from flatpak or otherwise restricted, so that we can always change -the graph even if permissions become more restricted in the future. - -(cherry picked from commit 5d4931b4184634788663498564bdc3a73c564c30) ---- - src/pipewire_connection/mod.rs | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/pipewire_connection/mod.rs b/src/pipewire_connection/mod.rs -index f7ba1a0..a0cf429 100644 ---- a/src/pipewire_connection/mod.rs -+++ b/src/pipewire_connection/mod.rs -@@ -65,7 +65,9 @@ pub(super) fn thread_main( - - while !is_stopped.get() { - // Try to connect -- let core = match context.connect(None) { -+ let core = match context.connect(Some(properties! { -+ "media.category" => "Manager" -+ })) { - Ok(core) => Rc::new(core), - Err(_) => { - if !is_connecting { diff -Nru helvum-0.5.1/debian/patches/relax-deps.patch helvum-0.5.1+20240328/debian/patches/relax-deps.patch --- helvum-0.5.1/debian/patches/relax-deps.patch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/relax-deps.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -From: =?utf-8?q?Jeremy_B=C3=ADcha?= -Date: Sat, 20 Apr 2024 07:07:47 -0400 -Subject: Relax deps - -Forwarded: not-needed ---- - Cargo.toml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Cargo.toml b/Cargo.toml -index f839bfc..d584c14 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -17,7 +17,7 @@ categories = ["gui", "multimedia"] - pipewire = "0.8.0" - adw = { version = "0.6", package = "libadwaita", features = ["v1_4"] } - glib = { version = "0.19", features = ["log"] } --async-channel = "2.2" -+async-channel = "1.9" - - log = "0.4.11" - diff -Nru helvum-0.5.1/debian/patches/series helvum-0.5.1+20240328/debian/patches/series --- helvum-0.5.1/debian/patches/series 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/series 2024-04-20 15:26:09.000000000 +0000 @@ -1,7 +1 @@ -Use-responsive-design.patch -use-AdwToolbarView.patch -pw-Set-media.category-property-to-manager.patch -ui-Display-node-media-name-in-graph-view.patch -update-Helvum-to-track-the-latest-pipewire0.8.0.patch -Update-to-latest-gtk-rs-crates.patch -relax-deps.patch +2001_async-channel.patch diff -Nru helvum-0.5.1/debian/patches/ui-Display-node-media-name-in-graph-view.patch helvum-0.5.1+20240328/debian/patches/ui-Display-node-media-name-in-graph-view.patch --- helvum-0.5.1/debian/patches/ui-Display-node-media-name-in-graph-view.patch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/ui-Display-node-media-name-in-graph-view.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,304 +0,0 @@ -From: Denis Drakhnia -Date: Wed, 11 Oct 2023 11:17:30 +0300 -Subject: ui: Display node media name in graph view - -(cherry picked from commit 96c079d29e26f85207eb31252013b4b571a7c774) ---- - src/graph_manager.rs | 18 +++++++++++ - src/main.rs | 5 +++ - src/pipewire_connection/mod.rs | 73 ++++++++++++++++++++++++++++++++++++------ - src/style.css | 2 +- - src/ui/graph/node.rs | 25 +++++++++++---- - src/ui/graph/node.ui | 34 ++++++++++++++++---- - 6 files changed, 133 insertions(+), 24 deletions(-) - -diff --git a/src/graph_manager.rs b/src/graph_manager.rs -index e438552..34b2868 100644 ---- a/src/graph_manager.rs -+++ b/src/graph_manager.rs -@@ -59,6 +59,7 @@ mod imp { - move |msg| { - match msg { - PipewireMessage::NodeAdded { id, name, node_type } => imp.add_node(id, name.as_str(), node_type), -+ PipewireMessage::NodeNameChanged { id, name, media_name } => imp.node_name_changed(id, &name, &media_name), - PipewireMessage::PortAdded { id, node_id, name, direction } => imp.add_port(id, name.as_str(), node_id, direction), - PipewireMessage::PortFormatChanged { id, media_type } => imp.port_media_type_changed(id, media_type), - PipewireMessage::LinkAdded { -@@ -95,6 +96,23 @@ mod imp { - self.obj().graph().add_node(node, node_type); - } - -+ /// Update a node tooltip to the view. -+ fn node_name_changed(&self, id: u32, node_name: &str, media_name: &str) { -+ let items = self.items.borrow(); -+ -+ let Some(node) = items.get(&id) else { -+ log::warn!("Node (id: {id}) for changed name not found in graph manager"); -+ return; -+ }; -+ let Some(node) = node.dynamic_cast_ref::() else { -+ log::warn!("Graph Manager item under node (id: {id}) is not a node"); -+ return; -+ }; -+ -+ node.set_node_name(node_name); -+ node.set_media_name(media_name); -+ } -+ - /// Remove the node with the specified id from the view. - fn remove_node(&self, id: u32) { - log::info!("Removing node from graph: id {}", id); -diff --git a/src/main.rs b/src/main.rs -index b147c96..610c175 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -39,6 +39,11 @@ pub enum PipewireMessage { - name: String, - node_type: Option, - }, -+ NodeNameChanged { -+ id: u32, -+ name: String, -+ media_name: String, -+ }, - PortAdded { - id: u32, - node_id: u32, -diff --git a/src/pipewire_connection/mod.rs b/src/pipewire_connection/mod.rs -index a0cf429..768f737 100644 ---- a/src/pipewire_connection/mod.rs -+++ b/src/pipewire_connection/mod.rs -@@ -26,7 +26,9 @@ use std::{ - use adw::glib::{self, clone}; - use log::{debug, error, info, warn}; - use pipewire::{ -+ keys, - link::{Link, LinkChangeMask, LinkInfo, LinkListener, LinkState}, -+ node::{Node, NodeInfo, NodeListener}, - port::{Port, PortChangeMask, PortInfo, PortListener}, - prelude::*, - properties, -@@ -43,6 +45,10 @@ use crate::{GtkMessage, MediaType, NodeType, PipewireMessage}; - use state::{Item, State}; - - enum ProxyItem { -+ Node { -+ _proxy: Node, -+ _listener: NodeListener, -+ }, - Port { - proxy: Port, - _listener: PortListener, -@@ -149,7 +155,7 @@ pub(super) fn thread_main( - .add_listener_local() - .global(clone!(@strong gtk_sender, @weak registry, @strong proxies, @strong state => - move |global| match global.type_ { -- ObjectType::Node => handle_node(global, >k_sender, &state), -+ ObjectType::Node => handle_node(global, >k_sender, ®istry, &proxies, &state), - ObjectType::Port => handle_port(global, >k_sender, ®istry, &proxies, &state), - ObjectType::Link => handle_link(global, >k_sender, ®istry, &proxies, &state), - _ => { -@@ -180,10 +186,21 @@ pub(super) fn thread_main( - } - } - -+/// Get the nicest possible name for the node, using a fallback chain of possible name attributes -+fn get_node_name(props: &ForeignDict) -> &str { -+ props -+ .get(&keys::NODE_DESCRIPTION) -+ .or_else(|| props.get(&keys::NODE_NICK)) -+ .or_else(|| props.get(&keys::NODE_NAME)) -+ .unwrap_or_default() -+} -+ - /// Handle a new node being added - fn handle_node( - node: &GlobalObject, - sender: &glib::Sender, -+ registry: &Rc, -+ proxies: &Rc>>, - state: &Rc>, - ) { - let props = node -@@ -191,15 +208,7 @@ fn handle_node( - .as_ref() - .expect("Node object is missing properties"); - -- // Get the nicest possible name for the node, using a fallback chain of possible name attributes. -- let name = String::from( -- props -- .get("node.description") -- .or_else(|| props.get("node.nick")) -- .or_else(|| props.get("node.name")) -- .unwrap_or_default(), -- ); -- -+ let name = get_node_name(props).to_string(); - let media_class = |class: &str| { - if class.contains("Sink") || class.contains("Input") { - Some(NodeType::Input) -@@ -230,6 +239,50 @@ fn handle_node( - node_type, - }) - .expect("Failed to send message"); -+ -+ let proxy: Node = registry.bind(node).expect("Failed to bind to node proxy"); -+ let listener = proxy -+ .add_listener_local() -+ .info(clone!(@strong sender, @strong proxies => move |info| { -+ handle_node_info(info, &sender, &proxies); -+ })) -+ .register(); -+ -+ proxies.borrow_mut().insert( -+ node.id, -+ ProxyItem::Node { -+ _proxy: proxy, -+ _listener: listener, -+ }, -+ ); -+} -+ -+fn handle_node_info( -+ info: &NodeInfo, -+ sender: &glib::Sender, -+ proxies: &Rc>>, -+) { -+ debug!("Received node info: {:?}", info); -+ -+ let id = info.id(); -+ let proxies = proxies.borrow(); -+ let Some(ProxyItem::Node { .. }) = proxies.get(&id) else { -+ error!("Received info on unknown node with id {id}"); -+ return; -+ }; -+ -+ let props = info.props().expect("NodeInfo object is missing properties"); -+ if let Some(media_name) = props.get(&keys::MEDIA_NAME) { -+ let name = get_node_name(props).to_string(); -+ -+ sender -+ .send(PipewireMessage::NodeNameChanged { -+ id, -+ name, -+ media_name: media_name.to_string(), -+ }) -+ .expect("Failed to send message"); -+ } - } - - /// Handle a new port being added -diff --git a/src/style.css b/src/style.css -index f8fa650..397fedb 100644 ---- a/src/style.css -+++ b/src/style.css -@@ -41,7 +41,7 @@ node { - background-color: @headerbar_bg_color; - } - --node label.heading { -+node .node-title { - padding: 4px 7px; - } - -diff --git a/src/ui/graph/node.rs b/src/ui/graph/node.rs -index bb41ba8..54d71c6 100644 ---- a/src/ui/graph/node.rs -+++ b/src/ui/graph/node.rs -@@ -34,15 +34,26 @@ mod imp { - #[property(get, set, construct_only)] - pub(super) pipewire_id: Cell, - #[property( -- name = "name", type = String, -- get = |this: &Self| this.label.text().to_string(), -+ name = "node-name", type = String, -+ get = |this: &Self| this.node_name.text().to_string(), - set = |this: &Self, val| { -- this.label.set_text(val); -- this.label.set_tooltip_text(Some(val)); -+ this.node_name.set_text(val); -+ this.node_name.set_tooltip_text(Some(val)); - } - )] - #[template_child] -- pub(super) label: TemplateChild, -+ pub(super) node_name: TemplateChild, -+ #[property( -+ name = "media-name", type = String, -+ get = |this: &Self| this.media_name.text().to_string(), -+ set = |this: &Self, val| { -+ this.media_name.set_text(val); -+ this.media_name.set_tooltip_text(Some(val)); -+ this.media_name.set_visible(!val.is_empty()); -+ } -+ )] -+ #[template_child] -+ pub(super) media_name: TemplateChild, - #[template_child] - pub(super) separator: TemplateChild, - #[template_child] -@@ -75,7 +86,7 @@ mod imp { - self.parent_constructed(); - - // Display a grab cursor when the mouse is over the label so the user knows the node can be dragged. -- self.label -+ self.node_name - .set_cursor(gtk::gdk::Cursor::from_name("grab", None).as_ref()); - } - -@@ -141,7 +152,7 @@ glib::wrapper! { - impl Node { - pub fn new(name: &str, pipewire_id: u32) -> Self { - glib::Object::builder() -- .property("name", name) -+ .property("node-name", name) - .property("pipewire-id", pipewire_id) - .build() - } -diff --git a/src/ui/graph/node.ui b/src/ui/graph/node.ui -index 8c53ada..9a80c56 100644 ---- a/src/ui/graph/node.ui -+++ b/src/ui/graph/node.ui -@@ -9,14 +9,36 @@ - - vertical - -- -+ - -- true -- PANGO_ELLIPSIZE_END -- 2 -- 20 -+ vertical -+ 1 -+ -+ -+ -+ true -+ PANGO_ELLIPSIZE_END -+ 2 -+ 20 -+ -+ -+ -+ -+ -+ false -+ true -+ PANGO_ELLIPSIZE_END -+ 2 -+ 20 -+ -+ - - - diff -Nru helvum-0.5.1/debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch helvum-0.5.1+20240328/debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch --- helvum-0.5.1/debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,300 +0,0 @@ -From: Dorinda Bassey -Date: Tue, 19 Mar 2024 14:06:57 +0100 -Subject: update Helvum to track the latest pipewire0.8.0 - -update Helvum to track the latest pipewire0.8.0 - -(cherry picked from commit d1b9b0f11f3f9d86f74b643c3aca024489165d7c) ---- - Cargo.toml | 2 +- - src/graph_manager.rs | 14 ++++++++++-- - src/main.rs | 2 +- - src/pipewire_connection/mod.rs | 50 +++++++++++++++++++++++------------------- - src/ui/graph/graph_view.rs | 4 ++-- - src/ui/graph/link.rs | 2 +- - src/ui/graph/node.rs | 2 +- - src/ui/graph/port.rs | 4 ++-- - 8 files changed, 47 insertions(+), 33 deletions(-) - -diff --git a/Cargo.toml b/Cargo.toml -index e72f4fd..a9a220c 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -14,7 +14,7 @@ categories = ["gui", "multimedia"] - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - - [dependencies] --pipewire = "0.7.1" -+pipewire = "0.8.0" - adw = { version = "0.5", package = "libadwaita", features = ["v1_4"] } - glib = { version = "0.18", features = ["log"] } - -diff --git a/src/graph_manager.rs b/src/graph_manager.rs -index 34b2868..4b00cba 100644 ---- a/src/graph_manager.rs -+++ b/src/graph_manager.rs -@@ -130,7 +130,13 @@ mod imp { - } - - /// Add a new port to the view. -- fn add_port(&self, id: u32, name: &str, node_id: u32, direction: pipewire::spa::Direction) { -+ fn add_port( -+ &self, -+ id: u32, -+ name: &str, -+ node_id: u32, -+ direction: pipewire::spa::utils::Direction, -+ ) { - log::info!("Adding port to graph: id {}", id); - - let mut items = self.items.borrow_mut(); -@@ -273,7 +279,11 @@ mod imp { - link.set_active(active); - } - -- fn link_format_changed(&self, id: u32, media_type: pipewire::spa::format::MediaType) { -+ fn link_format_changed( -+ &self, -+ id: u32, -+ media_type: pipewire::spa::param::format::MediaType, -+ ) { - let items = self.items.borrow(); - - let Some(link) = items.get(&id) else { -diff --git a/src/main.rs b/src/main.rs -index 610c175..467c544 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -20,7 +20,7 @@ mod pipewire_connection; - mod ui; - - use adw::{gtk, prelude::*}; --use pipewire::spa::{format::MediaType, Direction}; -+use pipewire::spa::{param::format::MediaType, utils::Direction}; - - /// Messages sent by the GTK thread to notify the pipewire thread. - #[derive(Debug, Clone)] -diff --git a/src/pipewire_connection/mod.rs b/src/pipewire_connection/mod.rs -index 768f737..c554d67 100644 ---- a/src/pipewire_connection/mod.rs -+++ b/src/pipewire_connection/mod.rs -@@ -26,19 +26,21 @@ use std::{ - use adw::glib::{self, clone}; - use log::{debug, error, info, warn}; - use pipewire::{ -+ context::Context, -+ core::{Core, PW_ID_CORE}, - keys, -- link::{Link, LinkChangeMask, LinkInfo, LinkListener, LinkState}, -- node::{Node, NodeInfo, NodeListener}, -- port::{Port, PortChangeMask, PortInfo, PortListener}, -- prelude::*, -- properties, -+ link::{Link, LinkChangeMask, LinkInfoRef, LinkListener, LinkState}, -+ main_loop::MainLoop, -+ node::{Node, NodeInfoRef, NodeListener}, -+ port::{Port, PortChangeMask, PortInfoRef, PortListener}, -+ properties::properties, - registry::{GlobalObject, Registry}, - spa::{ - param::{ParamInfoFlags, ParamType}, -- ForeignDict, SpaResult, -+ utils::dict::DictRef, -+ utils::result::SpaResult, - }, - types::ObjectType, -- Context, Core, MainLoop, - }; - - use crate::{GtkMessage, MediaType, NodeType, PipewireMessage}; -@@ -64,7 +66,7 @@ pub(super) fn thread_main( - gtk_sender: glib::Sender, - mut pw_receiver: pipewire::channel::Receiver, - ) { -- let mainloop = MainLoop::new().expect("Failed to create mainloop"); -+ let mainloop = MainLoop::new(None).expect("Failed to create mainloop"); - let context = Rc::new(Context::new(&mainloop).expect("Failed to create context")); - let is_stopped = Rc::new(Cell::new(false)); - let mut is_connecting = false; -@@ -86,13 +88,15 @@ pub(super) fn thread_main( - // If connection is failed, try to connect again in 200ms - let interval = Some(Duration::from_millis(200)); - -- let timer = mainloop.add_timer(clone!(@strong mainloop => move |_| { -- mainloop.quit(); -- })); -+ let timer = mainloop -+ .loop_() -+ .add_timer(clone!(@strong mainloop => move |_| { -+ mainloop.quit(); -+ })); - - timer.update_timer(interval, None).into_result().unwrap(); - -- let receiver = pw_receiver.attach(&mainloop, { -+ let receiver = pw_receiver.attach(mainloop.loop_(), { - clone!(@strong mainloop, @strong is_stopped => move |msg| - if let GtkMessage::Terminate = msg { - // main thread requested stop -@@ -122,7 +126,7 @@ pub(super) fn thread_main( - let proxies = Rc::new(RefCell::new(HashMap::new())); - let state = Rc::new(RefCell::new(State::new())); - -- let receiver = pw_receiver.attach(&mainloop, { -+ let receiver = pw_receiver.attach(mainloop.loop_(), { - clone!(@strong mainloop, @weak core, @weak registry, @strong state, @strong is_stopped => move |msg| match msg { - GtkMessage::ToggleLink { port_from, port_to } => toggle_link(port_from, port_to, &core, ®istry, &state), - GtkMessage::Terminate => { -@@ -136,7 +140,7 @@ pub(super) fn thread_main( - let gtk_sender = gtk_sender.clone(); - let _listener = core.add_listener_local() - .error(clone!(@strong mainloop, @strong gtk_sender, @strong is_stopped => move |id, _seq, res, message| { -- if id != pipewire::PW_ID_CORE { -+ if id != PW_ID_CORE { - return; - } - -@@ -187,7 +191,7 @@ pub(super) fn thread_main( - } - - /// Get the nicest possible name for the node, using a fallback chain of possible name attributes --fn get_node_name(props: &ForeignDict) -> &str { -+fn get_node_name(props: &DictRef) -> &str { - props - .get(&keys::NODE_DESCRIPTION) - .or_else(|| props.get(&keys::NODE_NICK)) -@@ -197,7 +201,7 @@ fn get_node_name(props: &ForeignDict) -> &str { - - /// Handle a new node being added - fn handle_node( -- node: &GlobalObject, -+ node: &GlobalObject<&DictRef>, - sender: &glib::Sender, - registry: &Rc, - proxies: &Rc>>, -@@ -258,7 +262,7 @@ fn handle_node( - } - - fn handle_node_info( -- info: &NodeInfo, -+ info: &NodeInfoRef, - sender: &glib::Sender, - proxies: &Rc>>, - ) { -@@ -287,7 +291,7 @@ fn handle_node_info( - - /// Handle a new port being added - fn handle_port( -- port: &GlobalObject, -+ port: &GlobalObject<&DictRef>, - sender: &glib::Sender, - registry: &Rc, - proxies: &Rc>>, -@@ -319,7 +323,7 @@ fn handle_port( - } - - fn handle_port_info( -- info: &PortInfo, -+ info: &PortInfoRef, - proxies: &Rc>>, - state: &Rc>, - sender: &glib::Sender, -@@ -393,7 +397,7 @@ fn handle_port_enum_format( - - /// Handle a new link being added - fn handle_link( -- link: &GlobalObject, -+ link: &GlobalObject<&DictRef>, - sender: &glib::Sender, - registry: &Rc, - proxies: &Rc>>, -@@ -422,7 +426,7 @@ fn handle_link( - } - - fn handle_link_info( -- info: &LinkInfo, -+ info: &LinkInfoRef, - state: &Rc>, - sender: &glib::Sender, - ) { -@@ -495,7 +499,7 @@ fn toggle_link( - .get_node_of_port(port_to) - .expect("Requested port not in state"); - -- if let Err(e) = core.create_object::( -+ if let Err(e) = core.create_object::( - "link-factory", - &properties! { - "link.output.node" => node_from.to_string(), -@@ -510,7 +514,7 @@ fn toggle_link( - } - } - --fn get_link_media_type(link_info: &LinkInfo) -> MediaType { -+fn get_link_media_type(link_info: &LinkInfoRef) -> MediaType { - let media_type = link_info - .format() - .and_then(|format| pipewire::spa::param::format_utils::parse_format(format).ok()) -diff --git a/src/ui/graph/graph_view.rs b/src/ui/graph/graph_view.rs -index 549a4c5..d1ec5da 100644 ---- a/src/ui/graph/graph_view.rs -+++ b/src/ui/graph/graph_view.rs -@@ -42,8 +42,8 @@ mod imp { - use adw::gtk::gdk::{self}; - use log::warn; - use once_cell::sync::Lazy; -- use pipewire::spa::format::MediaType; -- use pipewire::spa::Direction; -+ use pipewire::spa::param::format::MediaType; -+ use pipewire::spa::utils::Direction; - - pub struct Colors { - audio: gdk::RGBA, -diff --git a/src/ui/graph/link.rs b/src/ui/graph/link.rs -index 140c74c..eb1343b 100644 ---- a/src/ui/graph/link.rs -+++ b/src/ui/graph/link.rs -@@ -15,7 +15,7 @@ - // SPDX-License-Identifier: GPL-3.0-only - - use adw::{glib, prelude::*, subclass::prelude::*}; --use pipewire::spa::format::MediaType; -+use pipewire::spa::param::format::MediaType; - - use super::Port; - -diff --git a/src/ui/graph/node.rs b/src/ui/graph/node.rs -index 54d71c6..8233e62 100644 ---- a/src/ui/graph/node.rs -+++ b/src/ui/graph/node.rs -@@ -15,7 +15,7 @@ - // SPDX-License-Identifier: GPL-3.0-only - - use adw::{glib, gtk, prelude::*, subclass::prelude::*}; --use pipewire::spa::Direction; -+use pipewire::spa::utils::Direction; - - use super::Port; - -diff --git a/src/ui/graph/port.rs b/src/ui/graph/port.rs -index b79e4d7..4189cd9 100644 ---- a/src/ui/graph/port.rs -+++ b/src/ui/graph/port.rs -@@ -21,7 +21,7 @@ use adw::{ - prelude::*, - subclass::prelude::*, - }; --use pipewire::spa::Direction; -+use pipewire::spa::utils::Direction; - - use super::PortHandle; - -@@ -31,7 +31,7 @@ mod imp { - use std::cell::Cell; - - use once_cell::{sync::Lazy, unsync::OnceCell}; -- use pipewire::spa::{format::MediaType, Direction}; -+ use pipewire::spa::{param::format::MediaType, utils::Direction}; - - /// Graphical representation of a pipewire port. - #[derive(gtk::CompositeTemplate, glib::Properties)] diff -Nru helvum-0.5.1/debian/patches/use-AdwToolbarView.patch helvum-0.5.1+20240328/debian/patches/use-AdwToolbarView.patch --- helvum-0.5.1/debian/patches/use-AdwToolbarView.patch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/patches/use-AdwToolbarView.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -From: Angelo Verlain -Date: Fri, 6 Oct 2023 18:02:01 +0200 -Subject: use AdwToolbarView - -(cherry picked from commit 94d5e956952a071818dff6a7ef18996552b8363d) ---- - Cargo.toml | 2 +- - meson.build | 2 +- - src/ui/window.ui | 13 ++++++------- - 3 files changed, 8 insertions(+), 9 deletions(-) - -diff --git a/Cargo.toml b/Cargo.toml -index b10c546..e72f4fd 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -15,7 +15,7 @@ categories = ["gui", "multimedia"] - - [dependencies] - pipewire = "0.7.1" --adw = { version = "0.5", package = "libadwaita", features = ["v1_3"] } -+adw = { version = "0.5", package = "libadwaita", features = ["v1_4"] } - glib = { version = "0.18", features = ["log"] } - - log = "0.4.11" -diff --git a/meson.build b/meson.build -index 2ecbebc..34bf0fa 100644 ---- a/meson.build -+++ b/meson.build -@@ -12,7 +12,7 @@ base_id = 'org.pipewire.Helvum' - - dependency('glib-2.0', version: '>= 2.66') - dependency('gtk4', version: '>= 4.4.0') --dependency('libadwaita-1', version: '>= 1.3') -+dependency('libadwaita-1', version: '>= 1.4') - dependency('libpipewire-0.3') - - desktop_file_validate = find_program('desktop-file-validate', required: false) -diff --git a/src/ui/window.ui b/src/ui/window.ui -index 22d72f1..f40432a 100644 ---- a/src/ui/window.ui -+++ b/src/ui/window.ui -@@ -1,7 +1,7 @@ - - - -- -+ - -
- -@@ -15,9 +15,8 @@ - 720 - Helvum - Pipewire Patchbay - -- -- vertical -- -+ -+ - - - -@@ -27,13 +26,13 @@ - - - -- -+ - - Disconnected - false - - -- -+ - - - -@@ -55,7 +54,7 @@ - - - -- -+ - - - diff -Nru helvum-0.5.1/debian/rules helvum-0.5.1+20240328/debian/rules --- helvum-0.5.1/debian/rules 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/rules 2024-04-20 15:26:09.000000000 +0000 @@ -15,13 +15,13 @@ execute_after_dh_auto_configure: mkdir -p debian/build ln --symbolic --force ../cargo_home debian/build/cargo-home - cd debian/build && meson --prefix=/usr ../.. + dh_auto_configure --buildsystem=meson+ninja --builddirectory=debian/build override_dh_auto_build: - cd debian/build && ninja -v + dh_auto_build --buildsystem=meson+ninja --builddirectory=debian/build override_dh_auto_test: - cd debian/build && ninja test + dh_auto_test --buildsystem=meson+ninja --builddirectory=debian/build override_dh_auto_install: - cd debian/build && DESTDIR=${CURDIR}/debian/helvum ninja install + dh_auto_install --buildsystem=meson+ninja --builddirectory=debian/build diff -Nru helvum-0.5.1/debian/watch helvum-0.5.1+20240328/debian/watch --- helvum-0.5.1/debian/watch 2024-04-20 11:15:40.000000000 +0000 +++ helvum-0.5.1+20240328/debian/watch 2024-04-20 15:26:09.000000000 +0000 @@ -3,7 +3,7 @@ # update: gbp import-orig --upstream-vcs-tag=vX.Y.Z --uscan opts=\ -filenamemangle=s/.*?(@ANY_VERSION@@ARCHIVE_EXT@)/@PACKAGE@-$1/,\ +mode=git,pgpmode=none,pretty=0.5.1+%cd,\ dversionmangle=auto \ -https://gitlab.freedesktop.org/ryuukyu/helvum/-/tags \ -.*?@ANY_VERSION@@ARCHIVE_EXT@ +https://gitlab.freedesktop.org/ryuukyu/helvum.git \ +HEAD diff -Nru helvum-0.5.1/meson.build helvum-0.5.1+20240328/meson.build --- helvum-0.5.1/meson.build 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/meson.build 2024-03-28 12:29:11.000000000 +0000 @@ -12,7 +12,7 @@ dependency('glib-2.0', version: '>= 2.66') dependency('gtk4', version: '>= 4.4.0') -dependency('libadwaita-1', version: '>= 1.3') +dependency('libadwaita-1', version: '>= 1.4') dependency('libpipewire-0.3') desktop_file_validate = find_program('desktop-file-validate', required: false) diff -Nru helvum-0.5.1/src/application.rs helvum-0.5.1+20240328/src/application.rs --- helvum-0.5.1/src/application.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/application.rs 2024-03-28 12:29:11.000000000 +0000 @@ -16,11 +16,12 @@ use adw::{ gio, - glib::{self, clone, Receiver}, + glib::{self, clone}, gtk, prelude::*, subclass::prelude::*, }; +use log::error; use pipewire::channel::Sender; use crate::{graph_manager::GraphManager, ui, GtkMessage, PipewireMessage}; @@ -30,11 +31,14 @@ static VERSION: &str = env!("CARGO_PKG_VERSION"); static AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); +const DEFAULT_REMOTE_NAME: &str = "Default Remote"; + mod imp { use super::*; + use std::cell::OnceCell; + use adw::subclass::prelude::AdwApplicationImpl; - use once_cell::unsync::OnceCell; #[derive(Default)] pub struct Application { @@ -112,9 +116,12 @@ } fn show_about_dialog(&self) { + let obj = &*self.obj(); + let window = obj.active_window().unwrap(); let authors: Vec<&str> = AUTHORS.split(':').collect(); let about_window = adw::AboutWindow::builder() + .transient_for(&window) .application_icon(APP_ID) .application_name("Helvum") .developer_name("Tom Wagner") @@ -127,6 +134,31 @@ about_window.present(); } + + pub(super) fn setup_options(&self, pw_sender: Sender) { + let obj = &*self.obj(); + + obj.add_main_option( + "socket", + glib::char::Char::from(b's'), + glib::OptionFlags::NONE, + glib::OptionArg::String, + "PipeWire socket to connect", + Some("PATH"), + ); + + let current_remote_label = obj.imp().window.current_remote_label(); + obj.connect_handle_local_options(clone!(@strong pw_sender => move |_, opts| { + match opts.lookup::("socket") { + Ok(p) => { + current_remote_label.set_label(p.as_deref().unwrap_or(DEFAULT_REMOTE_NAME)); + pw_sender.send(GtkMessage::Connect(p)).unwrap(); + }, + Err(e) => error!("Invalid socket path: {e}"), + } + -1 + })); + } } } @@ -140,7 +172,7 @@ /// Create the view. /// This will set up the entire user interface and prepare it for being run. pub(super) fn new( - gtk_receiver: Receiver, + gtk_receiver: async_channel::Receiver, pw_sender: Sender, ) -> Self { let app: Application = glib::Object::builder() @@ -149,6 +181,8 @@ let imp = app.imp(); + imp.setup_options(pw_sender.clone()); + imp.graph_manager .set(GraphManager::new( &imp.window.graph(), diff -Nru helvum-0.5.1/src/graph_manager.rs helvum-0.5.1+20240328/src/graph_manager.rs --- helvum-0.5.1/src/graph_manager.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/graph_manager.rs 2024-03-28 12:29:11.000000000 +0000 @@ -23,9 +23,7 @@ mod imp { use super::*; - use std::{cell::RefCell, collections::HashMap}; - - use once_cell::unsync::OnceCell; + use std::{cell::OnceCell, cell::RefCell, collections::HashMap}; use crate::{ui::graph, MediaType, NodeType}; @@ -53,35 +51,58 @@ impl ObjectImpl for GraphManager {} impl GraphManager { - pub fn attach_receiver(&self, receiver: glib::Receiver) { - receiver.attach(None, glib::clone!( - @weak self as imp => @default-return glib::ControlFlow::Continue, - move |msg| { - match msg { - PipewireMessage::NodeAdded { id, name, node_type } => imp.add_node(id, name.as_str(), node_type), - PipewireMessage::PortAdded { id, node_id, name, direction } => imp.add_port(id, name.as_str(), node_id, direction), - PipewireMessage::PortFormatChanged { id, media_type } => imp.port_media_type_changed(id, media_type), - PipewireMessage::LinkAdded { - id, port_from, port_to, active, media_type - } => imp.add_link(id, port_from, port_to, active, media_type), - PipewireMessage::LinkStateChanged { id, active } => imp.link_state_changed(id, active), - PipewireMessage::LinkFormatChanged { id, media_type } => imp.link_format_changed(id, media_type), - PipewireMessage::NodeRemoved { id } => imp.remove_node(id), - PipewireMessage::PortRemoved { id, node_id } => imp.remove_port(id, node_id), - PipewireMessage::LinkRemoved { id } => imp.remove_link(id), - PipewireMessage::Connecting => { - imp.obj().connection_banner().set_revealed(true); - } - PipewireMessage::Connected => { - imp.obj().connection_banner().set_revealed(false); - }, - PipewireMessage::Disconnected => { - imp.clear(); - }, - }; - glib::ControlFlow::Continue - } - )); + pub async fn receive(&self, receiver: async_channel::Receiver) { + loop { + let Ok(msg) = receiver.recv().await else { + continue; + }; + match msg { + PipewireMessage::NodeAdded { + id, + name, + node_type, + } => self.add_node(id, name.as_str(), node_type), + PipewireMessage::NodeNameChanged { + id, + name, + media_name, + } => self.node_name_changed(id, &name, &media_name), + PipewireMessage::PortAdded { + id, + node_id, + name, + direction, + } => self.add_port(id, name.as_str(), node_id, direction), + PipewireMessage::PortFormatChanged { id, media_type } => { + self.port_media_type_changed(id, media_type) + } + PipewireMessage::LinkAdded { + id, + port_from, + port_to, + active, + media_type, + } => self.add_link(id, port_from, port_to, active, media_type), + PipewireMessage::LinkStateChanged { id, active } => { + self.link_state_changed(id, active) + } + PipewireMessage::LinkFormatChanged { id, media_type } => { + self.link_format_changed(id, media_type) + } + PipewireMessage::NodeRemoved { id } => self.remove_node(id), + PipewireMessage::PortRemoved { id, node_id } => self.remove_port(id, node_id), + PipewireMessage::LinkRemoved { id } => self.remove_link(id), + PipewireMessage::Connecting => { + self.obj().connection_banner().set_revealed(true); + } + PipewireMessage::Connected => { + self.obj().connection_banner().set_revealed(false); + } + PipewireMessage::Disconnected => { + self.clear(); + } + }; + } } /// Add a new node to the view. @@ -95,6 +116,23 @@ self.obj().graph().add_node(node, node_type); } + /// Update a node tooltip to the view. + fn node_name_changed(&self, id: u32, node_name: &str, media_name: &str) { + let items = self.items.borrow(); + + let Some(node) = items.get(&id) else { + log::warn!("Node (id: {id}) for changed name not found in graph manager"); + return; + }; + let Some(node) = node.dynamic_cast_ref::() else { + log::warn!("Graph Manager item under node (id: {id}) is not a node"); + return; + }; + + node.set_node_name(node_name); + node.set_media_name(media_name); + } + /// Remove the node with the specified id from the view. fn remove_node(&self, id: u32) { log::info!("Removing node from graph: id {}", id); @@ -112,7 +150,13 @@ } /// Add a new port to the view. - fn add_port(&self, id: u32, name: &str, node_id: u32, direction: pipewire::spa::Direction) { + fn add_port( + &self, + id: u32, + name: &str, + node_id: u32, + direction: pipewire::spa::utils::Direction, + ) { log::info!("Adding port to graph: id {}", id); let mut items = self.items.borrow_mut(); @@ -255,7 +299,11 @@ link.set_active(active); } - fn link_format_changed(&self, id: u32, media_type: pipewire::spa::format::MediaType) { + fn link_format_changed( + &self, + id: u32, + media_type: pipewire::spa::param::format::MediaType, + ) { let items = self.items.borrow(); let Some(link) = items.get(&id) else { @@ -304,19 +352,23 @@ pub struct GraphManager(ObjectSubclass); } +async fn receive(graph_manager: GraphManager, receiver: async_channel::Receiver) { + graph_manager.imp().receive(receiver).await +} + impl GraphManager { pub fn new( graph: &GraphView, connection_banner: &adw::Banner, sender: PwSender, - receiver: glib::Receiver, + receiver: async_channel::Receiver, ) -> Self { let res: Self = glib::Object::builder() .property("graph", graph) .property("connection-banner", connection_banner) .build(); - res.imp().attach_receiver(receiver); + glib::MainContext::default().spawn_local(receive(res.clone(), receiver)); assert!( res.imp().pw_sender.set(sender).is_ok(), "Should be able to set pw_sender)" diff -Nru helvum-0.5.1/src/main.rs helvum-0.5.1+20240328/src/main.rs --- helvum-0.5.1/src/main.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/main.rs 2024-03-28 12:29:11.000000000 +0000 @@ -20,13 +20,15 @@ mod ui; use adw::{gtk, prelude::*}; -use pipewire::spa::{format::MediaType, Direction}; +use pipewire::spa::{param::format::MediaType, utils::Direction}; /// Messages sent by the GTK thread to notify the pipewire thread. #[derive(Debug, Clone)] pub enum GtkMessage { /// Toggle a link between the two specified ports. ToggleLink { port_from: u32, port_to: u32 }, + /// Connect to PipeWire service. + Connect(Option), /// Quit the event loop and let the thread finish. Terminate, } @@ -39,6 +41,11 @@ name: String, node_type: Option, }, + NodeNameChanged { + id: u32, + name: String, + media_name: String, + }, PortAdded { id: u32, node_id: u32, @@ -115,7 +122,7 @@ // Start the pipewire thread with channels in both directions. - let (gtk_sender, gtk_receiver) = glib::MainContext::channel(glib::Priority::DEFAULT); + let (gtk_sender, gtk_receiver) = async_channel::unbounded(); let (pw_sender, pw_receiver) = pipewire::channel::channel(); let pw_thread = std::thread::spawn(move || pipewire_connection::thread_main(gtk_sender, pw_receiver)); diff -Nru helvum-0.5.1/src/pipewire_connection/mod.rs helvum-0.5.1+20240328/src/pipewire_connection/mod.rs --- helvum-0.5.1/src/pipewire_connection/mod.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/pipewire_connection/mod.rs 2024-03-28 12:29:11.000000000 +0000 @@ -16,33 +16,36 @@ mod state; -use std::{ - cell::{Cell, RefCell}, - collections::HashMap, - rc::Rc, - time::Duration, -}; +use std::{cell::RefCell, collections::HashMap, rc::Rc, time::Duration}; use adw::glib::{self, clone}; use log::{debug, error, info, warn}; use pipewire::{ - link::{Link, LinkChangeMask, LinkInfo, LinkListener, LinkState}, - port::{Port, PortChangeMask, PortInfo, PortListener}, - prelude::*, - properties, + context::Context, + core::{Core, PW_ID_CORE}, + keys, + link::{Link, LinkChangeMask, LinkInfoRef, LinkListener, LinkState}, + main_loop::MainLoop, + node::{Node, NodeInfoRef, NodeListener}, + port::{Port, PortChangeMask, PortInfoRef, PortListener}, + properties::{properties, Properties}, registry::{GlobalObject, Registry}, spa::{ param::{ParamInfoFlags, ParamType}, - ForeignDict, SpaResult, + utils::dict::DictRef, + utils::result::SpaResult, }, types::ObjectType, - Context, Core, MainLoop, }; use crate::{GtkMessage, MediaType, NodeType, PipewireMessage}; use state::{Item, State}; enum ProxyItem { + Node { + _proxy: Node, + _listener: NodeListener, + }, Port { proxy: Port, _listener: PortListener, @@ -53,42 +56,78 @@ }, } +struct LoopState { + is_stopped: bool, + props: Properties, +} + +impl LoopState { + fn handle_message(&mut self, msg: GtkMessage) -> bool { + match msg { + GtkMessage::Terminate => self.is_stopped = true, + GtkMessage::Connect(remote) => match remote { + Some(s) => self.props.insert(*keys::REMOTE_NAME, s), + None => self.props.remove(*keys::REMOTE_NAME), + }, + _ => return false, + } + true + } +} + /// The "main" function of the pipewire thread. pub(super) fn thread_main( - gtk_sender: glib::Sender, + gtk_sender: async_channel::Sender, mut pw_receiver: pipewire::channel::Receiver, ) { - let mainloop = MainLoop::new().expect("Failed to create mainloop"); + let mainloop = MainLoop::new(None).expect("Failed to create mainloop"); let context = Rc::new(Context::new(&mainloop).expect("Failed to create context")); - let is_stopped = Rc::new(Cell::new(false)); + let loop_state = Rc::new(RefCell::new(LoopState { + is_stopped: false, + props: properties! { + "media.category" => "Manager", + }, + })); let mut is_connecting = false; - while !is_stopped.get() { + // Wait PipeWire service to connect from command line arguments. + let receiver = pw_receiver.attach(mainloop.loop_(), { + clone!(@strong mainloop, @strong loop_state => move |msg| + if loop_state.borrow_mut().handle_message(msg) { + mainloop.quit(); + } + ) + }); + mainloop.run(); + pw_receiver = receiver.deattach(); + + while !loop_state.borrow().is_stopped { // Try to connect - let core = match context.connect(None) { + let props = loop_state.borrow().props.clone(); + let core = match context.connect(Some(props)) { Ok(core) => Rc::new(core), Err(_) => { if !is_connecting { is_connecting = true; gtk_sender - .send(PipewireMessage::Connecting) + .send_blocking(PipewireMessage::Connecting) .expect("Failed to send message"); } // If connection is failed, try to connect again in 200ms let interval = Some(Duration::from_millis(200)); - let timer = mainloop.add_timer(clone!(@strong mainloop => move |_| { - mainloop.quit(); - })); + let timer = mainloop + .loop_() + .add_timer(clone!(@strong mainloop => move |_| { + mainloop.quit(); + })); timer.update_timer(interval, None).into_result().unwrap(); - let receiver = pw_receiver.attach(&mainloop, { - clone!(@strong mainloop, @strong is_stopped => move |msg| - if let GtkMessage::Terminate = msg { - // main thread requested stop - is_stopped.set(true); + let receiver = pw_receiver.attach(mainloop.loop_(), { + clone!(@strong mainloop, @strong loop_state => move |msg| + if loop_state.borrow_mut().handle_message(msg) { mainloop.quit(); } ) @@ -104,7 +143,7 @@ if is_connecting { is_connecting = false; gtk_sender - .send(PipewireMessage::Connected) + .send_blocking(PipewireMessage::Connected) .expect("Failed to send message"); } @@ -114,40 +153,41 @@ let proxies = Rc::new(RefCell::new(HashMap::new())); let state = Rc::new(RefCell::new(State::new())); - let receiver = pw_receiver.attach(&mainloop, { - clone!(@strong mainloop, @weak core, @weak registry, @strong state, @strong is_stopped => move |msg| match msg { + let receiver = pw_receiver.attach(mainloop.loop_(), { + clone!(@strong mainloop, @weak core, @weak registry, @strong state, @strong loop_state => move |msg| match msg { GtkMessage::ToggleLink { port_from, port_to } => toggle_link(port_from, port_to, &core, ®istry, &state), - GtkMessage::Terminate => { - // main thread requested stop - is_stopped.set(true); + GtkMessage::Terminate | GtkMessage::Connect(_) => { + loop_state.borrow_mut().handle_message(msg); mainloop.quit(); } }) }); - let gtk_sender = gtk_sender.clone(); - let _listener = core.add_listener_local() - .error(clone!(@strong mainloop, @strong gtk_sender, @strong is_stopped => move |id, _seq, res, message| { - if id != pipewire::PW_ID_CORE { - return; - } + let _listener = core + .add_listener_local() + .error( + clone!(@strong mainloop, @strong gtk_sender => move |id, _seq, res, message| { + if id != PW_ID_CORE { + return; + } - if res == -libc::EPIPE { - gtk_sender.send(PipewireMessage::Disconnected) - .expect("Failed to send message"); - mainloop.quit(); - } else { - let serr = SpaResult::from_c(res).into_result().unwrap_err(); - error!("Pipewire Core received error {serr}: {message}"); - } - })) + if res == -libc::EPIPE { + gtk_sender.send_blocking(PipewireMessage::Disconnected) + .expect("Failed to send message"); + mainloop.quit(); + } else { + let serr = SpaResult::from_c(res).into_result().unwrap_err(); + error!("Pipewire Core received error {serr}: {message}"); + } + }), + ) .register(); let _listener = registry .add_listener_local() .global(clone!(@strong gtk_sender, @weak registry, @strong proxies, @strong state => move |global| match global.type_ { - ObjectType::Node => handle_node(global, >k_sender, &state), + ObjectType::Node => handle_node(global, >k_sender, ®istry, &proxies, &state), ObjectType::Port => handle_port(global, >k_sender, ®istry, &proxies, &state), ObjectType::Link => handle_link(global, >k_sender, ®istry, &proxies, &state), _ => { @@ -155,9 +195,9 @@ } } )) - .global_remove(clone!(@strong proxies, @strong state => move |id| { + .global_remove(clone!(@strong gtk_sender, @strong proxies, @strong state => move |id| { if let Some(item) = state.borrow_mut().remove(id) { - gtk_sender.send(match item { + gtk_sender.send_blocking(match item { Item::Node { .. } => PipewireMessage::NodeRemoved {id}, Item::Port { node_id } => PipewireMessage::PortRemoved {id, node_id}, Item::Link { .. } => PipewireMessage::LinkRemoved {id}, @@ -175,13 +215,28 @@ mainloop.run(); pw_receiver = receiver.deattach(); + + gtk_sender + .send_blocking(PipewireMessage::Disconnected) + .expect("Failed to send message"); } } +/// Get the nicest possible name for the node, using a fallback chain of possible name attributes +fn get_node_name(props: &DictRef) -> &str { + props + .get(&keys::NODE_DESCRIPTION) + .or_else(|| props.get(&keys::NODE_NICK)) + .or_else(|| props.get(&keys::NODE_NAME)) + .unwrap_or_default() +} + /// Handle a new node being added fn handle_node( - node: &GlobalObject, - sender: &glib::Sender, + node: &GlobalObject<&DictRef>, + sender: &async_channel::Sender, + registry: &Rc, + proxies: &Rc>>, state: &Rc>, ) { let props = node @@ -189,15 +244,7 @@ .as_ref() .expect("Node object is missing properties"); - // Get the nicest possible name for the node, using a fallback chain of possible name attributes. - let name = String::from( - props - .get("node.description") - .or_else(|| props.get("node.nick")) - .or_else(|| props.get("node.name")) - .unwrap_or_default(), - ); - + let name = get_node_name(props).to_string(); let media_class = |class: &str| { if class.contains("Sink") || class.contains("Input") { Some(NodeType::Input) @@ -222,18 +269,62 @@ state.borrow_mut().insert(node.id, Item::Node); sender - .send(PipewireMessage::NodeAdded { + .send_blocking(PipewireMessage::NodeAdded { id: node.id, name, node_type, }) .expect("Failed to send message"); + + let proxy: Node = registry.bind(node).expect("Failed to bind to node proxy"); + let listener = proxy + .add_listener_local() + .info(clone!(@strong sender, @strong proxies => move |info| { + handle_node_info(info, &sender, &proxies); + })) + .register(); + + proxies.borrow_mut().insert( + node.id, + ProxyItem::Node { + _proxy: proxy, + _listener: listener, + }, + ); +} + +fn handle_node_info( + info: &NodeInfoRef, + sender: &async_channel::Sender, + proxies: &Rc>>, +) { + debug!("Received node info: {:?}", info); + + let id = info.id(); + let proxies = proxies.borrow(); + let Some(ProxyItem::Node { .. }) = proxies.get(&id) else { + error!("Received info on unknown node with id {id}"); + return; + }; + + let props = info.props().expect("NodeInfo object is missing properties"); + if let Some(media_name) = props.get(&keys::MEDIA_NAME) { + let name = get_node_name(props).to_string(); + + sender + .send_blocking(PipewireMessage::NodeNameChanged { + id, + name, + media_name: media_name.to_string(), + }) + .expect("Failed to send message"); + } } /// Handle a new port being added fn handle_port( - port: &GlobalObject, - sender: &glib::Sender, + port: &GlobalObject<&DictRef>, + sender: &async_channel::Sender, registry: &Rc, proxies: &Rc>>, state: &Rc>, @@ -264,10 +355,10 @@ } fn handle_port_info( - info: &PortInfo, + info: &PortInfoRef, proxies: &Rc>>, state: &Rc>, - sender: &glib::Sender, + sender: &async_channel::Sender, ) { debug!("Received port info: {:?}", info); @@ -308,7 +399,7 @@ } sender - .send(PipewireMessage::PortAdded { + .send_blocking(PipewireMessage::PortAdded { id, node_id, name, @@ -321,7 +412,7 @@ fn handle_port_enum_format( port_id: u32, param: Option<&pipewire::spa::pod::Pod>, - sender: &glib::Sender, + sender: &async_channel::Sender, ) { let media_type = param .and_then(|param| pipewire::spa::param::format_utils::parse_format(param).ok()) @@ -329,7 +420,7 @@ .unwrap_or(MediaType::Unknown); sender - .send(PipewireMessage::PortFormatChanged { + .send_blocking(PipewireMessage::PortFormatChanged { id: port_id, media_type, }) @@ -338,8 +429,8 @@ /// Handle a new link being added fn handle_link( - link: &GlobalObject, - sender: &glib::Sender, + link: &GlobalObject<&DictRef>, + sender: &async_channel::Sender, registry: &Rc, proxies: &Rc>>, state: &Rc>, @@ -367,9 +458,9 @@ } fn handle_link_info( - info: &LinkInfo, + info: &LinkInfoRef, state: &Rc>, - sender: &glib::Sender, + sender: &async_channel::Sender, ) { debug!("Received link info: {:?}", info); @@ -380,7 +471,7 @@ // Info was an update - figure out if we should notify the gtk thread if info.change_mask().contains(LinkChangeMask::STATE) { sender - .send(PipewireMessage::LinkStateChanged { + .send_blocking(PipewireMessage::LinkStateChanged { id, active: matches!(info.state(), LinkState::Active), }) @@ -388,7 +479,7 @@ } if info.change_mask().contains(LinkChangeMask::FORMAT) { sender - .send(PipewireMessage::LinkFormatChanged { + .send_blocking(PipewireMessage::LinkFormatChanged { id, media_type: get_link_media_type(info), }) @@ -402,7 +493,7 @@ state.insert(id, Item::Link { port_from, port_to }); sender - .send(PipewireMessage::LinkAdded { + .send_blocking(PipewireMessage::LinkAdded { id, port_from, port_to, @@ -440,7 +531,7 @@ .get_node_of_port(port_to) .expect("Requested port not in state"); - if let Err(e) = core.create_object::( + if let Err(e) = core.create_object::( "link-factory", &properties! { "link.output.node" => node_from.to_string(), @@ -455,7 +546,7 @@ } } -fn get_link_media_type(link_info: &LinkInfo) -> MediaType { +fn get_link_media_type(link_info: &LinkInfoRef) -> MediaType { let media_type = link_info .format() .and_then(|format| pipewire::spa::param::format_utils::parse_format(format).ok()) diff -Nru helvum-0.5.1/src/style.css helvum-0.5.1+20240328/src/style.css --- helvum-0.5.1/src/style.css 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/style.css 2024-03-28 12:29:11.000000000 +0000 @@ -41,7 +41,7 @@ background-color: @headerbar_bg_color; } -node label.heading { +node .node-title { padding: 4px 7px; } @@ -53,3 +53,20 @@ border-radius: 50%; background-color: @media-type-unknown; } + +button.rounded { + padding: 6px; + border-radius: 9999px; +} + +entry.rounded { + border-radius: 9999px; +} + +entry.rounded > :first-child { + padding-left: 12px; +} + +entry.rounded > :nth-child(2) { + padding-right: 12px; +} diff -Nru helvum-0.5.1/src/ui/graph/graph_view.rs helvum-0.5.1+20240328/src/ui/graph/graph_view.rs --- helvum-0.5.1/src/ui/graph/graph_view.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/graph/graph_view.rs 2024-03-28 12:29:11.000000000 +0000 @@ -42,8 +42,8 @@ use adw::gtk::gdk::{self}; use log::warn; use once_cell::sync::Lazy; - use pipewire::spa::format::MediaType; - use pipewire::spa::Direction; + use pipewire::spa::param::format::MediaType; + use pipewire::spa::utils::Direction; pub struct Colors { audio: gdk::RGBA, @@ -93,6 +93,9 @@ // Memorized data for an in-progress zoom gesture pub zoom_gesture_initial_zoom: Cell>, pub zoom_gesture_anchor: Cell>, + + // This keeps track of an ongoing move view gesture. + pub move_view_state: Cell<(f64, f64)>, } impl Default for GraphView { @@ -108,6 +111,7 @@ port_drag_cursor: Cell::new(Point::new(0.0, 0.0)), zoom_gesture_initial_zoom: Default::default(), zoom_gesture_anchor: Default::default(), + move_view_state: Default::default(), } } } @@ -136,6 +140,7 @@ self.setup_port_drag_and_drop(); self.setup_scroll_zooming(); self.setup_zoom_gesture(); + self.setup_move_view(); } fn dispose(&self) { @@ -465,6 +470,48 @@ self.obj().add_controller(zoom_gesture); } + fn setup_move_view(&self) { + let drag_controller = gtk::GestureDrag::new(); + + drag_controller.set_button(gtk::gdk::BUTTON_MIDDLE); + + // TODO: set `all-scroll` cursor while dragging view + + drag_controller.connect_drag_begin(|drag_controller, _, _| { + let widget = drag_controller + .widget() + .downcast::() + .unwrap(); + + widget.imp().move_view_state.set((0.0, 0.0)); + }); + + drag_controller.connect_drag_update(|drag_controller, x, y| { + let widget = drag_controller + .widget() + .downcast::() + .unwrap(); + + let imp = widget.imp(); + let state = imp.move_view_state.replace((x, y)); + let delta_x = state.0 - x; + let delta_y = state.1 - y; + + let hadjustment_ref = imp.hadjustment.borrow(); + let vadjustment_ref = imp.vadjustment.borrow(); + let hadjustment = hadjustment_ref.as_ref().unwrap(); + let vadjustment = vadjustment_ref.as_ref().unwrap(); + + let new_hadjustment = hadjustment.value() + delta_x; + let new_vadjustment = vadjustment.value() + delta_y; + + hadjustment.set_value(new_hadjustment); + vadjustment.set_value(new_vadjustment); + }); + + self.obj().add_controller(drag_controller); + } + fn draw_link( &self, link_cr: &cairo::Context, diff -Nru helvum-0.5.1/src/ui/graph/link.rs helvum-0.5.1+20240328/src/ui/graph/link.rs --- helvum-0.5.1/src/ui/graph/link.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/graph/link.rs 2024-03-28 12:29:11.000000000 +0000 @@ -15,7 +15,7 @@ // SPDX-License-Identifier: GPL-3.0-only use adw::{glib, prelude::*, subclass::prelude::*}; -use pipewire::spa::format::MediaType; +use pipewire::spa::param::format::MediaType; use super::Port; diff -Nru helvum-0.5.1/src/ui/graph/node.rs helvum-0.5.1+20240328/src/ui/graph/node.rs --- helvum-0.5.1/src/ui/graph/node.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/graph/node.rs 2024-03-28 12:29:11.000000000 +0000 @@ -15,7 +15,7 @@ // SPDX-License-Identifier: GPL-3.0-only use adw::{glib, gtk, prelude::*, subclass::prelude::*}; -use pipewire::spa::Direction; +use pipewire::spa::utils::Direction; use super::Port; @@ -34,15 +34,26 @@ #[property(get, set, construct_only)] pub(super) pipewire_id: Cell, #[property( - name = "name", type = String, - get = |this: &Self| this.label.text().to_string(), + name = "node-name", type = String, + get = |this: &Self| this.node_name.text().to_string(), set = |this: &Self, val| { - this.label.set_text(val); - this.label.set_tooltip_text(Some(val)); + this.node_name.set_text(val); + this.node_name.set_tooltip_text(Some(val)); } )] #[template_child] - pub(super) label: TemplateChild, + pub(super) node_name: TemplateChild, + #[property( + name = "media-name", type = String, + get = |this: &Self| this.media_name.text().to_string(), + set = |this: &Self, val| { + this.media_name.set_text(val); + this.media_name.set_tooltip_text(Some(val)); + this.media_name.set_visible(!val.is_empty()); + } + )] + #[template_child] + pub(super) media_name: TemplateChild, #[template_child] pub(super) separator: TemplateChild, #[template_child] @@ -74,8 +85,11 @@ fn constructed(&self) { self.parent_constructed(); + // Force left-to-right direction for the ports grid to avoid messed up UI when defaulting to right-to-left + self.port_grid.set_direction(gtk::TextDirection::Ltr); + // Display a grab cursor when the mouse is over the label so the user knows the node can be dragged. - self.label + self.node_name .set_cursor(gtk::gdk::Cursor::from_name("grab", None).as_ref()); } @@ -141,7 +155,7 @@ impl Node { pub fn new(name: &str, pipewire_id: u32) -> Self { glib::Object::builder() - .property("name", name) + .property("node-name", name) .property("pipewire-id", pipewire_id) .build() } diff -Nru helvum-0.5.1/src/ui/graph/node.ui helvum-0.5.1+20240328/src/ui/graph/node.ui --- helvum-0.5.1/src/ui/graph/node.ui 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/graph/node.ui 2024-03-28 12:29:11.000000000 +0000 @@ -9,14 +9,36 @@ vertical - + - true - PANGO_ELLIPSIZE_END - 2 - 20 + vertical + 1 + + + + true + PANGO_ELLIPSIZE_END + 2 + 20 + + + + + + false + true + PANGO_ELLIPSIZE_END + 2 + 20 + + diff -Nru helvum-0.5.1/src/ui/graph/port.rs helvum-0.5.1+20240328/src/ui/graph/port.rs --- helvum-0.5.1/src/ui/graph/port.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/graph/port.rs 2024-03-28 12:29:11.000000000 +0000 @@ -21,17 +21,17 @@ prelude::*, subclass::prelude::*, }; -use pipewire::spa::Direction; +use pipewire::spa::utils::Direction; use super::PortHandle; mod imp { use super::*; - use std::cell::Cell; + use std::cell::{Cell, OnceCell}; - use once_cell::{sync::Lazy, unsync::OnceCell}; - use pipewire::spa::{format::MediaType, Direction}; + use once_cell::sync::Lazy; + use pipewire::spa::{param::format::MediaType, utils::Direction}; /// Graphical representation of a pipewire port. #[derive(gtk::CompositeTemplate, glib::Properties)] @@ -101,6 +101,9 @@ fn constructed(&self) { self.parent_constructed(); + // Force left-to-right direction for the ports grid to avoid messed up UI when defaulting to right-to-left + self.obj().set_direction(gtk::TextDirection::Ltr); + // Display a grab cursor when the mouse is over the port so the user knows it can be dragged to another port. self.obj() .set_cursor(gtk::gdk::Cursor::from_name("grab", None).as_ref()); diff -Nru helvum-0.5.1/src/ui/graph/zoomentry.rs helvum-0.5.1+20240328/src/ui/graph/zoomentry.rs --- helvum-0.5.1/src/ui/graph/zoomentry.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/graph/zoomentry.rs 2024-03-28 12:29:11.000000000 +0000 @@ -34,6 +34,7 @@ menu.append(Some("200%"), Some("win.set-zoom(2.0)")); menu.append(Some("300%"), Some("win.set-zoom(3.0)")); let popover = gtk::PopoverMenu::from_model(Some(&menu)); + popover.set_position(gtk::PositionType::Top); ZoomEntry { graphview: Default::default(), diff -Nru helvum-0.5.1/src/ui/graph/zoomentry.ui helvum-0.5.1+20240328/src/ui/graph/zoomentry.ui --- helvum-0.5.1/src/ui/graph/zoomentry.ui 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/graph/zoomentry.ui 2024-03-28 12:29:11.000000000 +0000 @@ -1,26 +1,37 @@ - \ No newline at end of file + diff -Nru helvum-0.5.1/src/ui/window.rs helvum-0.5.1+20240328/src/ui/window.rs --- helvum-0.5.1/src/ui/window.rs 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/window.rs 2024-03-28 12:29:11.000000000 +0000 @@ -15,6 +15,9 @@ #[property(type = adw::Banner, get = |_| self.connection_banner.clone())] pub connection_banner: TemplateChild, #[template_child] + #[property(type = gtk::Label, get = |_| self.current_remote_label.clone())] + pub current_remote_label: TemplateChild, + #[template_child] #[property(type = graph::GraphView, get = |_| self.graph.clone())] pub graph: TemplateChild, } diff -Nru helvum-0.5.1/src/ui/window.ui helvum-0.5.1+20240328/src/ui/window.ui --- helvum-0.5.1/src/ui/window.ui 2023-09-28 12:13:00.000000000 +0000 +++ helvum-0.5.1+20240328/src/ui/window.ui 2024-03-28 12:29:11.000000000 +0000 @@ -1,7 +1,7 @@ - +
@@ -13,46 +13,82 @@