mirror of
https://gitlab.freedesktop.org/pipewire/helvum
synced 2026-03-16 03:56:12 +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 pipewire::spa::Direction;
|
||||||
|
|
||||||
use crate::controller::MediaType;
|
use crate::controller::MediaType;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use once_cell::unsync::OnceCell;
|
use once_cell::{sync::Lazy, unsync::OnceCell};
|
||||||
use pipewire::spa::Direction;
|
use pipewire::spa::Direction;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -23,7 +29,22 @@ mod imp {
|
|||||||
type ParentType = gtk::Button;
|
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 WidgetImpl for Port {}
|
||||||
impl ButtonImpl for Port {}
|
impl ButtonImpl for Port {}
|
||||||
}
|
}
|
||||||
@@ -46,6 +67,44 @@ impl Port {
|
|||||||
|
|
||||||
res.set_child(Some(>k::Label::new(Some(name))));
|
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.
|
// Color the port according to its media type.
|
||||||
match media_type {
|
match media_type {
|
||||||
Some(MediaType::Video) => res.add_css_class("video"),
|
Some(MediaType::Video) => res.add_css_class("video"),
|
||||||
@@ -57,6 +116,11 @@ impl Port {
|
|||||||
res
|
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 {
|
pub fn direction(&self) -> &Direction {
|
||||||
let private = imp::Port::from_instance(self);
|
let private = imp::Port::from_instance(self);
|
||||||
private.direction.get().expect("Port direction is not set")
|
private.direction.get().expect("Port direction is not set")
|
||||||
|
|||||||
Reference in New Issue
Block a user