I am attaching patches to update helvum and would like to upload to
Experimental.

Jonas, the Salsa repo is a little jumbled. Could you push your
pristine-tar branch? And update debian/latest to include your latest
upload?

Thank you,
Jeremy Bícha
From fd91245564f7b71a9f6e88106b425af56c15b0c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jeremy=20B=C3=ADcha?= <jeremy.bi...@canonical.com>
Date: Sat, 20 Apr 2024 07:14:35 -0400
Subject: [PATCH 3/3] Update Build-Depends

---
 debian/control | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/debian/control b/debian/control
index 5450b7e..0d0f4c2 100644
--- a/debian/control
+++ b/debian/control
@@ -7,13 +7,14 @@ Build-Depends:
  debhelper-compat (= 13),
  desktop-file-utils,
  dh-cargo,
- librust-glib-0.18+default-dev,
- librust-glib-0.18+log-dev,
- librust-libadwaita-0.5+default-dev,
- librust-libadwaita-0.5+v1-3-dev,
+ librust-async-channel+default-dev,
+ 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-log-0.4+default-dev,
  librust-once-cell-1+default-dev,
- librust-pipewire-0.7+default-dev,
+ librust-pipewire-0.8+default-dev,
  libstring-shellquote-perl,
  meson,
 Standards-Version: 4.6.2
-- 
2.43.0

From 189c8a94ab4dba723ae063c1ac43dafdc507f54c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jeremy=20B=C3=ADcha?= <jeremy.bi...@canonical.com>
Date: Fri, 19 Apr 2024 20:03:14 -0400
Subject: [PATCH 1/3] Cherry-pick several patches to switch to latest GNOME
 Rust crates

Closes: #1063026
---
 .../Update-to-latest-gtk-rs-crates.patch      | 401 ++++++++++++++++++
 debian/patches/Use-responsive-design.patch    | 158 +++++++
 ...t-media.category-property-to-manager.patch |  28 ++
 debian/patches/series                         |   6 +
 ...isplay-node-media-name-in-graph-view.patch | 304 +++++++++++++
 ...um-to-track-the-latest-pipewire0.8.0.patch | 300 +++++++++++++
 debian/patches/use-AdwToolbarView.patch       |  87 ++++
 7 files changed, 1284 insertions(+)
 create mode 100644 debian/patches/Update-to-latest-gtk-rs-crates.patch
 create mode 100644 debian/patches/Use-responsive-design.patch
 create mode 100644 debian/patches/pw-Set-media.category-property-to-manager.patch
 create mode 100644 debian/patches/series
 create mode 100644 debian/patches/ui-Display-node-media-name-in-graph-view.patch
 create mode 100644 debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch
 create mode 100644 debian/patches/use-AdwToolbarView.patch

diff --git a/debian/patches/Update-to-latest-gtk-rs-crates.patch b/debian/patches/Update-to-latest-gtk-rs-crates.patch
new file mode 100644
index 0000000..1be6793
--- /dev/null
+++ b/debian/patches/Update-to-latest-gtk-rs-crates.patch
@@ -0,0 +1,401 @@
+From: Tom Wagner <tom.a.wag...@protonmail.com>
+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<PipewireMessage>,
++        gtk_receiver: async_channel::Receiver<PipewireMessage>,
+         pw_sender: Sender<GtkMessage>,
+     ) -> 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<crate::PipewireMessage>) {
+-            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<crate::PipewireMessage>) {
++            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<imp::GraphManager>);
+ }
+ 
++async fn receive(graph_manager: GraphManager, receiver: async_channel::Receiver<PipewireMessage>) {
++    graph_manager.imp().receive(receiver).await
++}
++
+ impl GraphManager {
+     pub fn new(
+         graph: &GraphView,
+         connection_banner: &adw::Banner,
+         sender: PwSender<GtkMessage>,
+-        receiver: glib::Receiver<PipewireMessage>,
++        receiver: async_channel::Receiver<PipewireMessage>,
+     ) -> 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<dyn std::error::Error>> {
+ 
+     // 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<PipewireMessage>,
++    gtk_sender: async_channel::Sender<PipewireMessage>,
+     mut pw_receiver: pipewire::channel::Receiver<GtkMessage>,
+ ) {
+     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<PipewireMessage>,
++    sender: &async_channel::Sender<PipewireMessage>,
+     registry: &Rc<Registry>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+     state: &Rc<RefCell<State>>,
+@@ -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<PipewireMessage>,
++    sender: &async_channel::Sender<PipewireMessage>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+ ) {
+     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<PipewireMessage>,
++    sender: &async_channel::Sender<PipewireMessage>,
+     registry: &Rc<Registry>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+     state: &Rc<RefCell<State>>,
+@@ -326,7 +326,7 @@ fn handle_port_info(
+     info: &PortInfoRef,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+     state: &Rc<RefCell<State>>,
+-    sender: &glib::Sender<PipewireMessage>,
++    sender: &async_channel::Sender<PipewireMessage>,
+ ) {
+     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<PipewireMessage>,
++    sender: &async_channel::Sender<PipewireMessage>,
+ ) {
+     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<PipewireMessage>,
++    sender: &async_channel::Sender<PipewireMessage>,
+     registry: &Rc<Registry>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+     state: &Rc<RefCell<State>>,
+@@ -428,7 +428,7 @@ fn handle_link(
+ fn handle_link_info(
+     info: &LinkInfoRef,
+     state: &Rc<RefCell<State>>,
+-    sender: &glib::Sender<PipewireMessage>,
++    sender: &async_channel::Sender<PipewireMessage>,
+ ) {
+     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 --git a/debian/patches/Use-responsive-design.patch b/debian/patches/Use-responsive-design.patch
new file mode 100644
index 0000000..5d726aa
--- /dev/null
+++ b/debian/patches/Use-responsive-design.patch
@@ -0,0 +1,158 @@
+From: Angelo Verlain Shema <geoangerc...@gmail.com>
+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 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <interface>
+   <template class="HelvumZoomEntry" parent="GtkBox">
+-    <child>
+-      <object class="GtkButton" id="zoom_out_button">
+-        <property name="icon-name">zoom-out-symbolic</property>
+-        <property name="tooltip-text">Zoom out</property>
+-      </object>
+-    </child>
++    <property name="spacing">12</property>
+     <child>
+       <object class="GtkEntry" id="entry">
+         <property name="secondary-icon-name">go-down-symbolic</property>
+         <property name="input-purpose">digits</property>
++        <property name="max-width-chars">5</property>
++        <style>
++          <class name="osd"/>
++          <class name="rounded"/>
++        </style>
++      </object>
++    </child>
++    <child>
++      <object class="GtkButton" id="zoom_out_button">
++        <property name="icon-name">zoom-out-symbolic</property>
++        <property name="tooltip-text">Zoom out</property>
++        <style>
++          <class name="osd"/>
++          <class name="rounded"/>
++        </style>
+       </object>
+     </child>
+     <child>
+       <object class="GtkButton" id="zoom_in_button">
+         <property name="icon-name">zoom-in-symbolic</property>
+         <property name="tooltip-text">Zoom in</property>
++        <style>
++          <class name="osd"/>
++          <class name="rounded"/>
++        </style>
+       </object>
+     </child>
+-    <style>
+-      <class name="linked"/>
+-    </style>
+   </template>
+-</interface>
+\ No newline at end of file
++</interface>
+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 @@
+         <child>
+           <object class="AdwHeaderBar" id="header_bar">
+             <child type="end">
+-              <object class="GtkBox">
+-                <property name="spacing">6</property>
+-                <child>
+-                  <object class="HelvumZoomEntry">
+-                    <property name="zoomed-widget">graph</property>
+-                  </object>
+-                </child>
+-                <child>
+-                  <object class="GtkMenuButton">
+-                    <property name="icon-name">open-menu-symbolic</property>
+-                    <property name="menu-model">primary_menu</property>
+-                  </object>
+-                </child>
++              <object class="GtkMenuButton">
++                <property name="icon-name">open-menu-symbolic</property>
++                <property name="menu-model">primary_menu</property>
+               </object>
+             </child>
+           </object>
+@@ -44,11 +34,24 @@
+           </object>
+         </child>
+         <child>
+-          <object class="GtkScrolledWindow">
++          <object class="GtkOverlay">
+             <child>
+-              <object class="HelvumGraphView" id="graph">
+-                <property name="hexpand">true</property>
+-                <property name="vexpand">true</property>
++              <object class="GtkScrolledWindow">
++                <child>
++                  <object class="HelvumGraphView" id="graph">
++                    <property name="hexpand">true</property>
++                    <property name="vexpand">true</property>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="overlay">
++              <object class="HelvumZoomEntry">
++                <property name="zoomed-widget">graph</property>
++                <property name="halign">end</property>
++                <property name="valign">end</property>
++                <property name="margin-end">24</property>
++                <property name="margin-bottom">24</property>
+               </object>
+             </child>
+           </object>
diff --git a/debian/patches/pw-Set-media.category-property-to-manager.patch b/debian/patches/pw-Set-media.category-property-to-manager.patch
new file mode 100644
index 0000000..45565d7
--- /dev/null
+++ b/debian/patches/pw-Set-media.category-property-to-manager.patch
@@ -0,0 +1,28 @@
+From: "Tom A. Wagner" <tom.a.wag...@protonmail.com>
+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 --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..a7d1c8d
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,6 @@
+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
diff --git a/debian/patches/ui-Display-node-media-name-in-graph-view.patch b/debian/patches/ui-Display-node-media-name-in-graph-view.patch
new file mode 100644
index 0000000..2ca6f6b
--- /dev/null
+++ b/debian/patches/ui-Display-node-media-name-in-graph-view.patch
@@ -0,0 +1,304 @@
+From: Denis Drakhnia <numa...@gmail.com>
+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::<graph::Node>() 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<NodeType>,
+     },
++    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, &gtk_sender, &state),
++                    ObjectType::Node => handle_node(global, &gtk_sender, &registry, &proxies, &state),
+                     ObjectType::Port => handle_port(global, &gtk_sender, &registry, &proxies, &state),
+                     ObjectType::Link => handle_link(global, &gtk_sender, &registry, &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<ForeignDict>,
+     sender: &glib::Sender<PipewireMessage>,
++    registry: &Rc<Registry>,
++    proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+     state: &Rc<RefCell<State>>,
+ ) {
+     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<PipewireMessage>,
++    proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
++) {
++    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<u32>,
+         #[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<gtk::Label>,
++        pub(super) node_name: TemplateChild<gtk::Label>,
++        #[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<gtk::Label>,
+         #[template_child]
+         pub(super) separator: TemplateChild<gtk::Separator>,
+         #[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 @@
+       <object class="GtkBox">
+         <property name="orientation">vertical</property>
+         <child>
+-          <object class="GtkLabel" id="label">
++          <object class="GtkBox">
+             <style>
+-              <class name="heading"></class>
++              <class name="node-title"></class>
+             </style>
+-            <property name="wrap">true</property>
+-            <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+-            <property name="lines">2</property>
+-            <property name="max-width-chars">20</property>
++            <property name="orientation">vertical</property>
++            <property name="spacing">1</property>
++            <child>
++              <object class="GtkLabel" id="node_name">
++                <style>
++                  <class name="heading"></class>
++                </style>
++                <property name="wrap">true</property>
++                <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
++                <property name="lines">2</property>
++                <property name="max-width-chars">20</property>
++              </object>
++            </child>
++            <child>
++              <object class="GtkLabel" id="media_name">
++                <style>
++                  <class name="dim-label"></class>
++                  <class name="caption"></class>
++                </style>
++                <property name="visible">false</property>
++                <property name="wrap">true</property>
++                <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
++                <property name="lines">2</property>
++                <property name="max-width-chars">20</property>
++              </object>
++            </child>
+           </object>
+         </child>
+         <child>
diff --git a/debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch b/debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch
new file mode 100644
index 0000000..365d12e
--- /dev/null
+++ b/debian/patches/update-Helvum-to-track-the-latest-pipewire0.8.0.patch
@@ -0,0 +1,300 @@
+From: Dorinda Bassey <dbas...@redhat.com>
+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<PipewireMessage>,
+     mut pw_receiver: pipewire::channel::Receiver<GtkMessage>,
+ ) {
+-    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, &registry, &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<ForeignDict>,
++    node: &GlobalObject<&DictRef>,
+     sender: &glib::Sender<PipewireMessage>,
+     registry: &Rc<Registry>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+@@ -258,7 +262,7 @@ fn handle_node(
+ }
+ 
+ fn handle_node_info(
+-    info: &NodeInfo,
++    info: &NodeInfoRef,
+     sender: &glib::Sender<PipewireMessage>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+ ) {
+@@ -287,7 +291,7 @@ fn handle_node_info(
+ 
+ /// Handle a new port being added
+ fn handle_port(
+-    port: &GlobalObject<ForeignDict>,
++    port: &GlobalObject<&DictRef>,
+     sender: &glib::Sender<PipewireMessage>,
+     registry: &Rc<Registry>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+@@ -319,7 +323,7 @@ fn handle_port(
+ }
+ 
+ fn handle_port_info(
+-    info: &PortInfo,
++    info: &PortInfoRef,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+     state: &Rc<RefCell<State>>,
+     sender: &glib::Sender<PipewireMessage>,
+@@ -393,7 +397,7 @@ fn handle_port_enum_format(
+ 
+ /// Handle a new link being added
+ fn handle_link(
+-    link: &GlobalObject<ForeignDict>,
++    link: &GlobalObject<&DictRef>,
+     sender: &glib::Sender<PipewireMessage>,
+     registry: &Rc<Registry>,
+     proxies: &Rc<RefCell<HashMap<u32, ProxyItem>>>,
+@@ -422,7 +426,7 @@ fn handle_link(
+ }
+ 
+ fn handle_link_info(
+-    info: &LinkInfo,
++    info: &LinkInfoRef,
+     state: &Rc<RefCell<State>>,
+     sender: &glib::Sender<PipewireMessage>,
+ ) {
+@@ -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::<Link, _>(
++        if let Err(e) = core.create_object::<Link>(
+             "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 --git a/debian/patches/use-AdwToolbarView.patch b/debian/patches/use-AdwToolbarView.patch
new file mode 100644
index 0000000..c4abed9
--- /dev/null
+++ b/debian/patches/use-AdwToolbarView.patch
@@ -0,0 +1,87 @@
+From: Angelo Verlain <geoangerc...@gmail.com>
+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 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <interface>
+   <requires lib="gtk" version="4.0"/>
+-  <requires lib="Adw" version="1.0"/>
++  <requires lib="Adw" version="1.4"/>
+   <menu id="primary_menu">
+     <section>
+       <item>
+@@ -15,9 +15,8 @@
+     <property name="default-height">720</property>
+     <property name="title">Helvum - Pipewire Patchbay</property>
+     <child>
+-      <object class="GtkBox">
+-        <property name="orientation">vertical</property>
+-        <child>
++      <object class="AdwToolbarView">
++        <child type="top">
+           <object class="AdwHeaderBar" id="header_bar">
+             <child type="end">
+               <object class="GtkMenuButton">
+@@ -27,13 +26,13 @@
+             </child>
+           </object>
+         </child>
+-        <child>
++        <child type="top">
+           <object class="AdwBanner" id="connection_banner">
+             <property name="title" translatable="yes">Disconnected</property>
+             <property name="revealed">false</property>
+           </object>
+         </child>
+-        <child>
++        <property name="content">
+           <object class="GtkOverlay">
+             <child>
+               <object class="GtkScrolledWindow">
+@@ -55,7 +54,7 @@
+               </object>
+             </child>
+           </object>
+-        </child>
++        </property>
+       </object>
+     </child>
+   </template>
-- 
2.43.0

From bdc1a1410074188cebd7634b5d0bc3e99c9eb92c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jeremy=20B=C3=ADcha?= <jeremy.bi...@canonical.com>
Date: Sat, 20 Apr 2024 07:14:06 -0400
Subject: [PATCH 2/3] Add patch to relax rust-async-channel dependency

---
 debian/patches/relax-deps.patch | 22 ++++++++++++++++++++++
 debian/patches/series           |  1 +
 2 files changed, 23 insertions(+)
 create mode 100644 debian/patches/relax-deps.patch

diff --git a/debian/patches/relax-deps.patch b/debian/patches/relax-deps.patch
new file mode 100644
index 0000000..9705fe2
--- /dev/null
+++ b/debian/patches/relax-deps.patch
@@ -0,0 +1,22 @@
+From: =?utf-8?q?Jeremy_B=C3=ADcha?= <jeremy.bi...@canonical.com>
+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 --git a/debian/patches/series b/debian/patches/series
index a7d1c8d..05bacba 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -4,3 +4,4 @@ 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
-- 
2.43.0

Reply via email to