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
This commit is contained in:
Thibault Saunier 2015-09-24 10:51:31 +02:00
parent 9764e22a5c
commit 5ad5f5c369

View file

@ -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)