mirror of
https://gitlab.freedesktop.org/pipewire/helvum
synced 2026-03-15 03:26:10 +08:00
Emit "link-toggled" signal when two ports widgets are connected
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
use gtk::{
|
||||
gdk,
|
||||
glib::{self, subclass::Signal},
|
||||
prelude::*,
|
||||
subclass::prelude::*,
|
||||
};
|
||||
use log::warn;
|
||||
use pipewire::spa::Direction;
|
||||
|
||||
use crate::controller::MediaType;
|
||||
|
||||
mod imp {
|
||||
use once_cell::unsync::OnceCell;
|
||||
use once_cell::{sync::Lazy, unsync::OnceCell};
|
||||
use pipewire::spa::Direction;
|
||||
|
||||
use super::*;
|
||||
@@ -23,7 +29,22 @@ mod imp {
|
||||
type ParentType = gtk::Button;
|
||||
}
|
||||
|
||||
impl ObjectImpl for Port {}
|
||||
impl ObjectImpl for Port {
|
||||
fn signals() -> &'static [Signal] {
|
||||
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||
vec![Signal::builder(
|
||||
"port-toggled",
|
||||
// Provide id of output port and input port to signal handler.
|
||||
&[<u32>::static_type().into(), <u32>::static_type().into()],
|
||||
// signal handler sends back nothing.
|
||||
<()>::static_type().into(),
|
||||
)
|
||||
.build()]
|
||||
});
|
||||
|
||||
SIGNALS.as_ref()
|
||||
}
|
||||
}
|
||||
impl WidgetImpl for Port {}
|
||||
impl ButtonImpl for Port {}
|
||||
}
|
||||
@@ -46,6 +67,44 @@ impl Port {
|
||||
|
||||
res.set_child(Some(>k::Label::new(Some(name))));
|
||||
|
||||
// Add either a drag source or drop target controller depending on direction,
|
||||
// they will be responsible for link creation by dragging an output port onto an input port.
|
||||
//
|
||||
// FIXME: The type used for dragging is simply a u32.
|
||||
// This means that anything that provides a u32 could be dragged onto a input port,
|
||||
// leading to that port trying to create a link to an invalid output port.
|
||||
// We should use a newtype instead of a plain u32.
|
||||
// Additionally, this does not protect against e.g. dropping an outgoing audio port on an ingoing video port.
|
||||
match direction {
|
||||
Direction::Input => {
|
||||
let drop_target = gtk::DropTarget::new(u32::static_type(), gdk::DragAction::COPY);
|
||||
let this = res.clone();
|
||||
drop_target.connect_drop(move |drop_target, val, _, _| {
|
||||
if let Some(source_id) = val.downcast_ref::<u32>() {
|
||||
// Get the callback registered in the widget and call it
|
||||
let source_id = source_id.get_some();
|
||||
drop_target
|
||||
.get_widget()
|
||||
.expect("Drop target has no widget")
|
||||
.emit_by_name("port-toggled", &[&source_id, &this.id()])
|
||||
.expect("Failed to send signal");
|
||||
} else {
|
||||
warn!("Invalid type dropped on ingoing port");
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
res.add_controller(&drop_target);
|
||||
}
|
||||
Direction::Output => {
|
||||
// The port will simply provide its pipewire id to the drag target.
|
||||
let drag_src = gtk::DragSourceBuilder::new()
|
||||
.content(&gdk::ContentProvider::new_for_value(&(id.to_value())))
|
||||
.build();
|
||||
res.add_controller(&drag_src);
|
||||
}
|
||||
}
|
||||
|
||||
// Color the port according to its media type.
|
||||
match media_type {
|
||||
Some(MediaType::Video) => res.add_css_class("video"),
|
||||
@@ -57,6 +116,11 @@ impl Port {
|
||||
res
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u32 {
|
||||
let private = imp::Port::from_instance(self);
|
||||
private.id.get().copied().expect("Port id is not set")
|
||||
}
|
||||
|
||||
pub fn direction(&self) -> &Direction {
|
||||
let private = imp::Port::from_instance(self);
|
||||
private.direction.get().expect("Port direction is not set")
|
||||
|
||||
Reference in New Issue
Block a user