mirror of
https://gitlab.freedesktop.org/pipewire/helvum.git
synced 2026-05-19 18:18:11 +02:00
Add typed IDs
This commit is contained in:
parent
bde421a6ea
commit
8a75db1987
7 changed files with 225 additions and 124 deletions
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
68
src/main.rs
68
src/main.rs
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue