Add typed IDs

This commit is contained in:
Naveen Prashanth 2026-05-06 15:57:38 +05:30
parent bde421a6ea
commit 8a75db1987
7 changed files with 225 additions and 124 deletions

View file

@ -25,7 +25,7 @@ mod imp {
use std::{cell::OnceCell, cell::RefCell, collections::HashMap};
use crate::{ui::graph, MediaType, NodeType};
use crate::{ui::graph, LinkId, MediaType, NodeId, NodeType, PortId};
#[derive(Default, glib::Properties)]
#[properties(wrapper_type = super::GraphManager)]
@ -117,26 +117,33 @@ mod imp {
}
/// Add a new node to the view.
fn add_node(&self, id: u32, name: &str, node_type: Option<NodeType>) {
log::info!("Adding node to graph: id {}", id);
fn add_node(&self, id: NodeId, name: &str, node_type: Option<NodeType>) {
log::info!("Adding node to graph: id {}", id.0);
let mut items = self.items.borrow_mut();
if let Some(old_item) = items.get(&id.0) {
if let Ok(old_node) = old_item.clone().dynamic_cast::<graph::Node>() {
self.graph_view().remove_node(&old_node);
}
}
let node = graph::Node::new(name, id);
self.items.borrow_mut().insert(id, node.clone().upcast());
items.insert(id.0, node.clone().upcast());
self.graph_view().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) {
fn node_name_changed(&self, id: NodeId, 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");
let Some(node) = items.get(&id.0) else {
log::warn!("Node (id: {}) for changed name not found in graph manager", id.0);
return;
};
let Some(node) = node.dynamic_cast_ref::<graph::Node>() else {
log::warn!("Graph Manager item under node (id: {id}) is not a node");
log::warn!("Graph Manager item under node (id: {}) is not a node", id.0);
return;
};
@ -145,15 +152,15 @@ mod imp {
}
/// Remove the node with the specified id from the view.
fn remove_node(&self, id: u32) {
log::info!("Removing node from graph: id {}", id);
fn remove_node(&self, id: NodeId) {
log::info!("Removing node from graph: id {}", id.0);
let Some(node) = self.items.borrow_mut().remove(&id) else {
log::warn!("Unknown node (id={id}) removed from graph");
let Some(node) = self.items.borrow_mut().remove(&id.0) else {
log::warn!("Unknown node (id={}) removed from graph", id.0);
return;
};
let Ok(node) = node.dynamic_cast::<graph::Node>() else {
log::warn!("Graph Manager item under node id {id} is not a node");
log::warn!("Graph Manager item under node id {} is not a node", id.0);
return;
};
@ -161,17 +168,35 @@ mod imp {
}
/// Add a new port to the view.
fn add_port(&self, id: u32, name: &str, node_id: u32, direction: libspa::utils::Direction) {
log::info!("Adding port to graph: id {}", id);
fn add_port(
&self,
id: PortId,
name: &str,
node_id: NodeId,
direction: libspa::utils::Direction,
) {
log::info!("Adding port to graph: id {}", id.0);
let mut items = self.items.borrow_mut();
let Some(node) = items.get(&node_id) else {
log::warn!("Node (id: {node_id}) for port (id: {id}) not found in graph manager");
if let Some(old_item) = items.get(&id.0) {
if let Ok(old_port) = old_item.clone().dynamic_cast::<graph::Port>() {
if let Some(old_node_widget) = old_port.parent().and_downcast::<graph::Node>() {
old_node_widget.remove_port(&old_port);
}
}
}
let Some(node) = items.get(&node_id.0) else {
log::warn!(
"Node (id: {}) for port (id: {}) not found in graph manager",
node_id.0,
id.0
);
return;
};
let Ok(node) = node.clone().dynamic_cast::<graph::Node>() else {
log::warn!("Graph Manager item under node id {node_id} is not a node");
log::warn!("Graph Manager item under node id {} is not a node", node_id.0);
return;
};
@ -187,8 +212,8 @@ mod imp {
#[upgrade_or_default]
move |args| {
// Args always look like this: &[widget, id_port_from, id_port_to]
let port_from = args[1].get::<u32>().unwrap();
let port_to = args[2].get::<u32>().unwrap();
let port_from = PortId(args[1].get::<u32>().unwrap());
let port_to = PortId(args[2].get::<u32>().unwrap());
app.toggle_link(port_from, port_to);
@ -197,20 +222,20 @@ mod imp {
),
);
items.insert(id, port.clone().upcast());
items.insert(id.0, port.clone().upcast());
node.add_port(port);
}
fn port_media_type_changed(&self, id: u32, media_type: MediaType) {
fn port_media_type_changed(&self, id: PortId, media_type: MediaType) {
let items = self.items.borrow();
let Some(port) = items.get(&id) else {
log::warn!("Port (id: {id}) for changed media type not found in graph manager");
let Some(port) = items.get(&id.0) else {
log::warn!("Port (id: {}) for changed media type not found in graph manager", id.0);
return;
};
let Some(port) = port.dynamic_cast_ref::<graph::Port>() else {
log::warn!("Graph Manager item under port id {id} is not a port");
log::warn!("Graph Manager item under port id {} is not a port", id.0);
return;
};
@ -219,25 +244,25 @@ mod imp {
/// Remove the port with the id `id` from the node with the id `node_id`
/// from the view.
fn remove_port(&self, id: u32, node_id: u32) {
log::info!("Removing port from graph: id {}, node_id: {}", id, node_id);
fn remove_port(&self, id: PortId, node_id: NodeId) {
log::info!("Removing port from graph: id {}, node_id: {}", id.0, node_id.0);
let mut items = self.items.borrow_mut();
let Some(node) = items.get(&node_id) else {
log::warn!("Node (id: {node_id}) for port (id: {id}) not found in graph manager");
let Some(node) = items.get(&node_id.0) else {
log::warn!("Node (id: {}) for port (id: {}) not found in graph manager", node_id.0, id.0);
return;
};
let Ok(node) = node.clone().dynamic_cast::<graph::Node>() else {
log::warn!("Graph Manager item under node id {node_id} is not a node");
log::warn!("Graph Manager item under node id {} is not a node", node_id.0);
return;
};
let Some(port) = items.remove(&id) else {
log::warn!("Unknown Port (id: {id}) removed from graph");
let Some(port) = items.remove(&id.0) else {
log::warn!("Unknown Port (id: {}) removed from graph", id.0);
return;
};
let Ok(port) = port.dynamic_cast::<graph::Port>() else {
log::warn!("Graph Manager item under port id {id} is not a port");
log::warn!("Graph Manager item under port id {} is not a port", id.0);
return;
};
@ -247,30 +272,40 @@ mod imp {
/// Add a new link to the view.
fn add_link(
&self,
id: u32,
output_port_id: u32,
input_port_id: u32,
id: LinkId,
output_port_id: PortId,
input_port_id: PortId,
active: bool,
media_type: MediaType,
) {
log::info!("Adding link to graph: id {}", id);
log::info!("Adding link to graph: id {}", id.0);
let mut items = self.items.borrow_mut();
let Some(output_port) = items.get(&output_port_id) else {
log::warn!("Output port (id: {output_port_id}) for link (id: {id}) not found in graph manager");
if let Some(old_item) = items.get(&id.0) {
if let Ok(old_link) = old_item.clone().dynamic_cast::<graph::Link>() {
self.graph
.borrow()
.as_ref()
.expect("graph should be set")
.remove_link(&old_link);
}
}
let Some(output_port) = items.get(&output_port_id.0) else {
log::warn!("Output port (id: {}) for link (id: {}) not found in graph manager", output_port_id.0, id.0);
return;
};
let Ok(output_port) = output_port.clone().dynamic_cast::<graph::Port>() else {
log::warn!("Graph Manager item under port id {output_port_id} is not a port");
log::warn!("Graph Manager item under port id {} is not a port", output_port_id.0);
return;
};
let Some(input_port) = items.get(&input_port_id) else {
log::warn!("Output port (id: {input_port_id}) for link (id: {id}) not found in graph manager");
let Some(input_port) = items.get(&input_port_id.0) else {
log::warn!("Output port (id: {}) for link (id: {}) not found in graph manager", input_port_id.0, id.0);
return;
};
let Ok(input_port) = input_port.clone().dynamic_cast::<graph::Port>() else {
log::warn!("Graph Manager item under port id {input_port_id} is not a port");
log::warn!("Graph Manager item under port id {} is not a port", input_port_id.0);
return;
};
@ -280,7 +315,7 @@ mod imp {
link.set_active(active);
link.set_media_type(media_type);
items.insert(id, link.clone().upcast());
items.insert(id.0, link.clone().upcast());
// Update graph to contain the new link.
self.graph
@ -290,42 +325,43 @@ mod imp {
.add_link(link);
}
fn link_state_changed(&self, id: u32, active: bool) {
fn link_state_changed(&self, id: LinkId, active: bool) {
log::info!(
"Link state changed: Link (id={id}) is now {}",
"Link state changed: Link (id={}) is now {}",
id.0,
if active { "active" } else { "inactive" }
);
let items = self.items.borrow();
let Some(link) = items.get(&id) else {
log::warn!("Link state changed on unknown link (id={id})");
let Some(link) = items.get(&id.0) else {
log::warn!("Link state changed on unknown link (id={})", id.0);
return;
};
let Some(link) = link.dynamic_cast_ref::<graph::Link>() else {
log::warn!("Graph Manager item under link id {id} is not a link");
log::warn!("Graph Manager item under link id {} is not a link", id.0);
return;
};
link.set_active(active);
}
fn link_format_changed(&self, id: u32, media_type: libspa::param::format::MediaType) {
fn link_format_changed(&self, id: LinkId, media_type: libspa::param::format::MediaType) {
let items = self.items.borrow();
let Some(link) = items.get(&id) else {
log::warn!("Link (id: {id}) for changed media type not found in graph manager");
let Some(link) = items.get(&id.0) else {
log::warn!("Link (id: {}) for changed media type not found in graph manager", id.0);
return;
};
let Some(link) = link.dynamic_cast_ref::<graph::Link>() else {
log::warn!("Graph Manager item under link id {id} is not a link");
log::warn!("Graph Manager item under link id {} is not a link", id.0);
return;
};
link.set_media_type(media_type);
}
// Toggle a link between the two specified ports on the remote pipewire server.
fn toggle_link(&self, port_from: u32, port_to: u32) {
fn toggle_link(&self, port_from: PortId, port_to: PortId) {
let sender = self.pw_sender.get().expect("pw_sender shoud be set");
sender
.send(crate::GtkMessage::ToggleLink { port_from, port_to })
@ -333,15 +369,15 @@ mod imp {
}
/// Remove the link with the specified id from the view.
fn remove_link(&self, id: u32) {
log::info!("Removing link from graph: id {}", id);
fn remove_link(&self, id: LinkId) {
log::info!("Removing link from graph: id {}", id.0);
let Some(link) = self.items.borrow_mut().remove(&id) else {
log::warn!("Unknown Link (id={id}) removed from graph");
let Some(link) = self.items.borrow_mut().remove(&id.0) else {
log::warn!("Unknown Link (id={}) removed from graph", id.0);
return;
};
let Ok(link) = link.dynamic_cast::<graph::Link>() else {
log::warn!("Graph Manager item under link id {id} is not a link");
log::warn!("Graph Manager item under link id {} is not a link", id.0);
return;
};

View file

@ -22,11 +22,41 @@ mod ui;
use adw::{gtk, prelude::*};
use libspa::{param::format::MediaType, utils::Direction};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NodeId(pub u32);
impl std::fmt::Display for NodeId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PortId(pub u32);
impl std::fmt::Display for PortId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct LinkId(pub u32);
impl std::fmt::Display for LinkId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
/// 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 },
ToggleLink {
port_from: PortId,
port_to: PortId,
},
/// Quit the event loop and let the thread finish.
Terminate,
}
@ -35,49 +65,49 @@ pub enum GtkMessage {
#[derive(Debug, Clone)]
pub enum PipewireMessage {
NodeAdded {
id: u32,
id: NodeId,
name: String,
node_type: Option<NodeType>,
},
NodeNameChanged {
id: u32,
id: NodeId,
name: String,
media_name: String,
},
PortAdded {
id: u32,
node_id: u32,
id: PortId,
node_id: NodeId,
name: String,
direction: Direction,
},
PortFormatChanged {
id: u32,
id: PortId,
media_type: MediaType,
},
LinkAdded {
id: u32,
port_from: u32,
port_to: u32,
id: LinkId,
port_from: PortId,
port_to: PortId,
active: bool,
media_type: MediaType,
},
LinkStateChanged {
id: u32,
id: LinkId,
active: bool,
},
LinkFormatChanged {
id: u32,
id: LinkId,
media_type: MediaType,
},
NodeRemoved {
id: u32,
id: NodeId,
},
PortRemoved {
id: u32,
node_id: u32,
id: PortId,
node_id: NodeId,
},
LinkRemoved {
id: u32,
id: LinkId,
},
Connecting,
Connected,
@ -92,10 +122,10 @@ pub enum NodeType {
#[derive(Debug, Clone)]
pub struct PipewireLink {
pub node_from: u32,
pub port_from: u32,
pub node_to: u32,
pub port_to: u32,
pub node_from: NodeId,
pub port_from: PortId,
pub node_to: NodeId,
pub port_to: PortId,
}
static GLIB_LOGGER: glib::GlibLogger = glib::GlibLogger::new(

View file

@ -40,7 +40,7 @@ use pipewire::{
types::ObjectType,
};
use crate::{GtkMessage, MediaType, NodeType, PipewireMessage};
use crate::{GtkMessage, LinkId, MediaType, NodeId, NodeType, PipewireMessage, PortId};
use state::{Item, State};
enum ProxyItem {
@ -179,9 +179,11 @@ pub(super) fn thread_main(
if let Some(item) = state_remove.borrow_mut().remove(id) {
gtk_sender4
.send_blocking(match item {
Item::Node => PipewireMessage::NodeRemoved { id },
Item::Port { node_id } => PipewireMessage::PortRemoved { id, node_id },
Item::Link { .. } => PipewireMessage::LinkRemoved { id },
Item::Node => PipewireMessage::NodeRemoved { id: NodeId(id) },
Item::Port { node_id } => {
PipewireMessage::PortRemoved { id: PortId(id), node_id }
}
Item::Link { .. } => PipewireMessage::LinkRemoved { id: LinkId(id) },
})
.expect("Failed to send message");
} else {
@ -247,7 +249,7 @@ fn handle_node(
sender
.send_blocking(PipewireMessage::NodeAdded {
id: node.id,
id: NodeId(node.id),
name,
node_type,
})
@ -292,7 +294,7 @@ fn handle_node_info(
sender
.send_blocking(PipewireMessage::NodeNameChanged {
id,
id: NodeId(id),
name,
media_name: media_name.to_string(),
})
@ -362,11 +364,13 @@ fn handle_port_info(
// First time we get info. We can now notify the gtk thread of a new port.
let props = info.props().expect("Port object is missing properties");
let name = props.get("port.name").unwrap_or_default().to_string();
let node_id: u32 = props
.get("node.id")
.expect("Port has no node.id property!")
.parse()
.expect("Could not parse node.id property");
let node_id = NodeId(
props
.get("node.id")
.expect("Port has no node.id property!")
.parse()
.expect("Could not parse node.id property"),
);
state.insert(id, Item::Port { node_id });
@ -382,7 +386,7 @@ fn handle_port_info(
sender
.send_blocking(PipewireMessage::PortAdded {
id,
id: PortId(id),
node_id,
name,
direction: info.direction(),
@ -403,7 +407,7 @@ fn handle_port_enum_format(
sender
.send_blocking(PipewireMessage::PortFormatChanged {
id: port_id,
id: PortId(port_id),
media_type,
})
.expect("Failed to send message")
@ -455,7 +459,7 @@ fn handle_link_info(
if info.change_mask().contains(LinkChangeMask::STATE) {
sender
.send_blocking(PipewireMessage::LinkStateChanged {
id,
id: LinkId(id),
active: matches!(info.state(), LinkState::Active),
})
.expect("Failed to send message");
@ -463,20 +467,20 @@ fn handle_link_info(
if info.change_mask().contains(LinkChangeMask::FORMAT) {
sender
.send_blocking(PipewireMessage::LinkFormatChanged {
id,
id: LinkId(id),
media_type: get_link_media_type(info),
})
.expect("Failed to send message");
}
} else {
let port_from = info.output_port_id();
let port_to = info.input_port_id();
let port_from = PortId(info.output_port_id());
let port_to = PortId(info.input_port_id());
state.insert(id, Item::Link { port_from, port_to });
sender
.send_blocking(PipewireMessage::LinkAdded {
id,
id: LinkId(id),
port_from,
port_to,
active: matches!(info.state(), LinkState::Active),
@ -488,20 +492,20 @@ fn handle_link_info(
/// Toggle a link between the two specified ports.
fn toggle_link(
port_from: u32,
port_to: u32,
port_from: PortId,
port_to: PortId,
core: &CoreRc,
registry: &RegistryRc,
state: &Rc<RefCell<State>>,
) {
let state = state.borrow();
if let Some(id) = state.get_link_id(port_from, port_to) {
info!("Requesting removal of link with id {}", id);
registry.destroy_global(id);
info!("Requesting removal of link with id {}", id.0);
registry.destroy_global(id.0);
} else {
info!(
"Requesting creation of link from port id:{} to port id:{}",
port_from, port_to
port_from.0, port_to.0
);
let node_from = state

View file

@ -14,6 +14,7 @@
//
// SPDX-License-Identifier: GPL-3.0-only
use crate::{LinkId, NodeId, PortId};
use std::collections::HashMap;
/// Any pipewire item we need to keep track of.
@ -23,11 +24,11 @@ pub(super) enum Item {
Port {
// Save the id of the node this is on so we can remove the port from it
// when it is deleted.
node_id: u32,
node_id: NodeId,
},
Link {
port_from: u32,
port_to: u32,
port_from: PortId,
port_to: PortId,
},
}
@ -39,7 +40,7 @@ pub(super) struct State {
/// Map pipewire ids to items.
items: HashMap<u32, Item>,
/// Map `(output port id, input port id)` tuples to the id of the link that connects them.
links: HashMap<(u32, u32), u32>,
links: HashMap<(PortId, PortId), LinkId>,
}
impl State {
@ -51,10 +52,12 @@ impl State {
/// Add a new item under the specified id.
pub fn insert(&mut self, id: u32, item: Item) {
if let Item::Link {
port_from, port_to, ..
port_from,
port_to,
..
} = item
{
self.links.insert((port_from, port_to), id);
self.links.insert((port_from, port_to), LinkId(id));
}
self.items.insert(id, item);
@ -66,7 +69,7 @@ impl State {
}
/// Get the id of the link that links the two specified ports.
pub fn get_link_id(&self, output_port: u32, input_port: u32) -> Option<u32> {
pub fn get_link_id(&self, output_port: PortId, input_port: PortId) -> Option<LinkId> {
self.links.get(&(output_port, input_port)).copied()
}
@ -82,8 +85,8 @@ impl State {
}
/// Convenience function: Get the id of the node a port is on
pub fn get_node_of_port(&self, port: u32) -> Option<u32> {
if let Some(Item::Port { node_id }) = self.get(port) {
pub fn get_node_of_port(&self, port: PortId) -> Option<NodeId> {
if let Some(Item::Port { node_id }) = self.get(port.0) {
Some(*node_id)
} else {
None

View file

@ -556,6 +556,8 @@ mod imp {
let input_x = input_anchor.x();
let input_y = input_anchor.y();
let zoom = self.zoom_factor.get() as f32;
let builder = gsk::PathBuilder::new();
builder.move_to(output_x, output_y);
@ -563,7 +565,7 @@ mod imp {
// a similar y coordinate, apply a y offset to the control points
// so that the curve sticks out a bit.
let y_control_offset = if output_x > input_x {
f32::max(0.0, 25.0 - (output_y - input_y).abs())
f32::max(0.0, (25.0 * zoom) - (output_y - input_y).abs())
} else {
0.0
};
@ -582,11 +584,12 @@ mod imp {
);
let path = builder.to_path();
let stroke = gsk::Stroke::new(2.0 * self.zoom_factor.get() as f32);
let stroke_width = f32::max(1.0, 2.0 * zoom);
let stroke = gsk::Stroke::new(stroke_width);
// Use dashed line for inactive links, full line otherwise.
if !active {
stroke.set_dash(&[10.0, 5.0]);
stroke.set_dash(&[10.0 * zoom, 5.0 * zoom]);
}
snapshot.append_stroke(&path, &stroke, color);
@ -620,7 +623,12 @@ mod imp {
_ => unreachable!(),
};
let color = &colors.color_for_media_type(MediaType::from_raw(port.media_type()));
let mut media_type = MediaType::from_raw(port.media_type());
if media_type == MediaType::Unknown {
media_type = MediaType::Unknown;
}
let color = &colors.color_for_media_type(media_type);
self.draw_link(snapshot, output_anchor, input_anchor, false, color);
}
@ -634,9 +642,19 @@ mod imp {
};
for link in self.links.borrow().iter() {
let color = &colors.color_for_media_type(link.media_type());
let mut media_type = link.media_type();
// If link media type is unknown, try to fall back to port media types.
if media_type == MediaType::Unknown {
if let Some(output_port) = link.output_port() {
media_type = MediaType::from_raw(output_port.media_type());
} else if let Some(input_port) = link.input_port() {
media_type = MediaType::from_raw(input_port.media_type());
}
}
let color = &colors.color_for_media_type(media_type);
// TODO: Do not draw links when they are outside the view
let Some((output_anchor, input_anchor)) = self.get_link_coordinates(link) else {
warn!("Could not get allocation of ports of link: {:?}", link);
continue;
@ -852,7 +870,7 @@ impl GraphView {
self.queue_draw();
}
pub fn clear(&mut self) {
pub fn clear(&self) {
self.imp().links.borrow_mut().clear();
for (node, _) in self.imp().nodes.borrow_mut().drain() {
node.unparent();

View file

@ -17,6 +17,7 @@
use adw::{glib, gtk, prelude::*, subclass::prelude::*};
use libspa::utils::Direction;
use crate::NodeId;
use super::Port;
mod imp {
@ -153,13 +154,17 @@ glib::wrapper! {
}
impl Node {
pub fn new(name: &str, pipewire_id: u32) -> Self {
pub fn new(name: &str, pipewire_id: NodeId) -> Self {
glib::Object::builder()
.property("node-name", name)
.property("pipewire-id", pipewire_id)
.property("pipewire-id", pipewire_id.0)
.build()
}
pub fn pw_id(&self) -> NodeId {
NodeId(self.property("pipewire-id"))
}
pub fn add_port(&self, port: Port) {
let imp = self.imp();
imp.ports.borrow_mut().insert(port);

View file

@ -21,6 +21,7 @@ use adw::{
prelude::*,
subclass::prelude::*,
};
use crate::PortId;
use libspa::utils::Direction;
use super::PortHandle;
@ -222,7 +223,7 @@ mod imp {
.dynamic_cast::<super::Port>()
.expect("Widget should be a Port");
log::trace!("Drag started from port {}", port.pipewire_id());
log::trace!("Drag started from port {}", port.pw_id());
});
drag_src.connect_drag_cancel(|drag_source, _, _| {
let port = drag_source
@ -231,7 +232,7 @@ mod imp {
.dynamic_cast::<super::Port>()
.expect("Widget should be a Port");
log::trace!("Drag from port {} was cancelled", port.pipewire_id());
log::trace!("Drag from port {} was cancelled", port.pw_id());
false
});
@ -284,7 +285,7 @@ mod imp {
port.emit_by_name::<()>(
"port-toggled",
&[&output_port.pipewire_id(), &input_port.pipewire_id()],
&[&output_port.pw_id().0, &input_port.pw_id().0],
);
true
@ -336,14 +337,18 @@ glib::wrapper! {
}
impl Port {
pub fn new(id: u32, name: &str, direction: Direction) -> Self {
pub fn new(id: PortId, name: &str, direction: Direction) -> Self {
glib::Object::builder()
.property("pipewire-id", id)
.property("pipewire-id", id.0)
.property("direction", direction.as_raw())
.property("name", name)
.build()
}
pub fn pw_id(&self) -> PortId {
PortId(self.property("pipewire-id"))
}
pub fn link_anchor(&self) -> graphene::Point {
let imp = self.imp();
let handle = &imp.handle;