diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 6321bdaae3..41bb7f23ca 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -77,6 +77,54 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, "gtkbasesink", 0, "Gtk Video Sink base class")); +struct invoke_context +{ + GThreadFunc func; + gpointer data; + GMutex lock; + GCond cond; + gboolean fired; + + gpointer res; +}; + +static gboolean +_invoke_func (struct invoke_context *info) +{ + g_mutex_lock (&info->lock); + info->res = info->func (info->data); + info->fired = TRUE; + g_cond_signal (&info->cond); + g_mutex_unlock (&info->lock); + + return G_SOURCE_REMOVE; +} + +static gpointer +_invoke_on_main (GThreadFunc func, gpointer data) +{ + GMainContext *main_context = g_main_context_default (); + struct invoke_context info; + + g_mutex_init (&info.lock); + g_cond_init (&info.cond); + info.fired = FALSE; + info.func = func; + info.data = data; + + g_main_context_invoke (main_context, (GSourceFunc) _invoke_func, &info); + + g_mutex_lock (&info.lock); + while (!info.fired) + g_cond_wait (&info.cond, &info.lock); + g_mutex_unlock (&info.lock); + + g_mutex_clear (&info.lock); + g_cond_clear (&info.cond); + + return info.res; +} + static void gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) { @@ -207,8 +255,21 @@ gst_gtk_base_sink_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_WIDGET: - g_value_set_object (value, gst_gtk_base_sink_get_widget (gtk_sink)); + { + GObject *widget = NULL; + + GST_OBJECT_LOCK (gtk_sink); + if (gtk_sink->widget != NULL) + widget = G_OBJECT (gtk_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); + + if (!widget) + widget = _invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget, + gtk_sink); + + g_value_set_object (value, widget); break; + } case PROP_FORCE_ASPECT_RATIO: g_value_set_boolean (value, gtk_sink->force_aspect_ratio); break; @@ -273,7 +334,7 @@ gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface) } static gboolean -gst_gtk_base_sink_start (GstBaseSink * bsink) +gst_gtk_base_sink_start_on_main (GstBaseSink * bsink) { GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); GstGtkBaseSinkClass *klass = GST_GTK_BASE_SINK_GET_CLASS (bsink); @@ -303,7 +364,14 @@ gst_gtk_base_sink_start (GstBaseSink * bsink) } static gboolean -gst_gtk_base_sink_stop (GstBaseSink * bsink) +gst_gtk_base_sink_start (GstBaseSink * bsink) +{ + return ! !_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_start_on_main, + bsink); +} + +static gboolean +gst_gtk_base_sink_stop_on_main (GstBaseSink * bsink) { GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); @@ -317,11 +385,17 @@ gst_gtk_base_sink_stop (GstBaseSink * bsink) } static gboolean -_show_window_cb (GstGtkBaseSink * gtk_sink) +gst_gtk_base_sink_stop (GstBaseSink * bsink) { - gtk_widget_show_all (gtk_sink->window); + return ! !_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_stop_on_main, + bsink); +} - return FALSE; +static void +gst_gtk_widget_show_all_and_unref (GtkWidget * widget) +{ + gtk_widget_show_all (widget); + g_object_unref (widget); } static GstStateChangeReturn @@ -340,11 +414,20 @@ gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: + { + GtkWindow *window = NULL; + GST_OBJECT_LOCK (gtk_sink); if (gtk_sink->window) - g_idle_add ((GSourceFunc) _show_window_cb, gtk_sink); + window = g_object_ref (gtk_sink->window); GST_OBJECT_UNLOCK (gtk_sink); + + if (window) + _invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref, + window); + break; + } case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (gtk_sink); if (gtk_sink->widget)