From 0dcf9c2be75827c89d30e3f7b23ccfda89f6b593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 4 Aug 2017 17:41:21 +0300 Subject: [PATCH] Move gtksink example to GtkApplication And have an example for using GTK objects from closures that require Send --- Cargo.lock | 1 + examples/Cargo.toml | 3 +- examples/src/bin/gtksink.rs | 74 ++++++++++++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3f374b50..ed8da9195 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,7 @@ name = "examples" version = "0.1.0" dependencies = [ "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "gio 0.1.3 (git+https://github.com/gtk-rs/gio)", "glib 0.1.3 (git+https://github.com/gtk-rs/glib)", "gstreamer 0.1.0", "gstreamer-app 0.1.0", diff --git a/examples/Cargo.toml b/examples/Cargo.toml index e0e76afce..3cc195e9b 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -7,7 +7,8 @@ authors = ["Sebastian Dröge "] glib = { version = "0.1.3", git = "https://github.com/gtk-rs/glib" } gstreamer = { path = "../gstreamer" } gstreamer-app = { path = "../gstreamer-app" } -gtk = { version = "0.1.3", git = "https://github.com/gtk-rs/gtk" } +gtk = { version = "0.1.3", git = "https://github.com/gtk-rs/gtk", features = ["v3_6"] } +gio = { version = "0.1.3", git = "https://github.com/gtk-rs/gio" } futures = "0.1" tokio-core = "0.1" diff --git a/examples/src/bin/gtksink.rs b/examples/src/bin/gtksink.rs index 258c41975..8590d80de 100644 --- a/examples/src/bin/gtksink.rs +++ b/examples/src/bin/gtksink.rs @@ -4,14 +4,48 @@ use gst::*; extern crate glib; use glib::*; +extern crate gio; +use gio::ApplicationExt; + extern crate gtk; use gtk::prelude::*; use gtk::{Window, WindowType}; +use gtk::ApplicationExt as GtkApplicationExt; -fn main() { - gst::init().unwrap(); - gtk::init().unwrap(); +use std::env; +// Workaround for GTK objects not implementing Send (nor Sync) +// but us having to use them in a closure that requires Send +use std::thread; +use std::ops::Deref; + +#[derive(Clone, Debug)] +pub struct SendCell { + data: T, + thread_id: thread::ThreadId, +} + +impl SendCell { + pub fn new(data: T) -> Self { + SendCell { + data: data, + thread_id: thread::current().id(), + } + } +} + +impl Deref for SendCell { + type Target = T; + + fn deref(&self) -> &T { + assert_eq!(thread::current().id(), self.thread_id); + &self.data + } +} + +unsafe impl Send for SendCell {} + +fn create_ui(app: >k::Application) { let pipeline = Pipeline::new(None); let src = ElementFactory::make("videotestsrc", None).unwrap(); let (sink, widget) = if let Some(gtkglsink) = ElementFactory::make("gtkglsink", None) { @@ -40,6 +74,8 @@ fn main() { window.add(&vbox); window.show_all(); + app.add_window(&window); + let pipeline_clone = pipeline.clone(); gtk::timeout_add(500, move || { let pipeline = &pipeline_clone; @@ -66,8 +102,10 @@ fn main() { glib::Continue(true) }); - window.connect_delete_event(|_, _| { - gtk::main_quit(); + let app_clone = app.clone(); + window.connect_delete_event(move |_, _| { + let app = &app_clone; + app.quit(); Inhibit(false) }); @@ -76,7 +114,9 @@ fn main() { let ret = pipeline.set_state(gst::State::Playing); assert_ne!(ret, gst::StateChangeReturn::Failure); + let app_clone = SendCell::new(app.clone()); bus.add_watch(move |_, msg| { + let app = &app_clone; match msg.view() { MessageView::Eos(..) => gtk::main_quit(), MessageView::Error(err) => { @@ -86,7 +126,7 @@ fn main() { err.get_error(), err.get_debug() ); - gtk::main_quit(); + app.quit(); } _ => (), }; @@ -94,8 +134,22 @@ fn main() { glib::Continue(true) }); - gtk::main(); - - let ret = pipeline.set_state(gst::State::Null); - assert_ne!(ret, gst::StateChangeReturn::Failure); + let pipeline_clone = pipeline.clone(); + app.connect_shutdown(move |_| { + let pipeline = &pipeline_clone; + let ret = pipeline.set_state(gst::State::Null); + assert_ne!(ret, gst::StateChangeReturn::Failure); + }); +} + +fn main() { + gst::init().unwrap(); + gtk::init().unwrap(); + + let app = gtk::Application::new(None, gio::APPLICATION_FLAGS_NONE).unwrap(); + + app.connect_activate(create_ui); + let args = env::args().collect::>(); + let args_ref = args.iter().map(|a| a.as_str()).collect::>(); + app.run(&args_ref); }