Commit c3f72729 authored by Thibault Saunier's avatar Thibault Saunier 🌵

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
parent afdea505
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment