summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Saunier <tsaunier@gnome.org>2015-09-24 10:51:31 +0200
committerThibault Saunier <tsaunier@gnome.org>2015-09-24 12:03:01 +0200
commit5ad5f5c369a4a7384850930fe837433a422ffdd0 (patch)
treed2ca567f8b91678ad966ff0167de11e98fad96bf
parent9764e22a5c150238fe5e5368c3816bcacc8dc0a4 (diff)
downloadgstreamer-plugins-bad-5ad5f5c369a4a7384850930fe837433a422ffdd0.tar.gz
gtk: Marshall state changes in the main thread
Gtk is not MT safe thus we need to make sure that everything is done in the main thread when working with it. https://bugzilla.gnome.org/show_bug.cgi?id=755251
-rw-r--r--ext/gtk/gstgtkbasesink.c97
1 files changed, 90 insertions, 7 deletions
diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c
index 6321bdaae..41bb7f23c 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)