2 * empathy-gst-gtk-widget.c - Source for EmpathyVideoWidget
3 * Copyright (C) 2008 Collabora Ltd.
4 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <gst/interfaces/xoverlay.h>
27 #include <gst/farsight/fs-element-added-notifier.h>
29 #include "empathy-video-widget.h"
31 G_DEFINE_TYPE(EmpathyVideoWidget, empathy_video_widget,
32 GTK_TYPE_DRAWING_AREA)
34 static void empathy_video_widget_element_added_cb (
35 FsElementAddedNotifier *notifier, GstBin *bin, GstElement *element,
36 EmpathyVideoWidget *self);
38 static void empathy_video_widget_sync_message_cb (
39 GstBus *bus, GstMessage *message, EmpathyVideoWidget *self);
48 static guint signals[LAST_SIGNAL] = {0};
60 /* private structure */
61 typedef struct _EmpathyVideoWidgetPriv EmpathyVideoWidgetPriv;
63 struct _EmpathyVideoWidgetPriv
65 gboolean dispose_has_run;
67 GstElement *videosink;
70 FsElementAddedNotifier *notifier;
79 #define GET_PRIV(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
80 EMPATHY_TYPE_VIDEO_WIDGET, EmpathyVideoWidgetPriv))
83 empathy_video_widget_init (EmpathyVideoWidget *obj)
85 EmpathyVideoWidgetPriv *priv = GET_PRIV (obj);
88 priv->lock = g_mutex_new ();
90 priv->notifier = fs_element_added_notifier_new ();
91 g_signal_connect (priv->notifier, "element-added",
92 G_CALLBACK (empathy_video_widget_element_added_cb),
95 if (gdk_color_parse ("Black", &black))
96 gtk_widget_modify_bg (GTK_WIDGET (obj), GTK_STATE_NORMAL,
99 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (obj), GTK_DOUBLE_BUFFERED);
103 empathy_video_widget_constructed (GObject *object)
105 EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
107 priv->videosink = gst_element_factory_make ("gconfvideosink", NULL);
108 gst_object_ref (priv->videosink);
109 gst_object_sink (priv->videosink);
111 priv->sink_pad = gst_element_get_static_pad (priv->videosink, "sink");
113 fs_element_added_notifier_add (priv->notifier, GST_BIN (priv->videosink));
114 gst_bus_enable_sync_message_emission (priv->bus);
116 g_signal_connect (priv->bus, "sync-message",
117 G_CALLBACK (empathy_video_widget_sync_message_cb), object);
119 gtk_widget_set_size_request (GTK_WIDGET (object), priv->min_width,
123 static void empathy_video_widget_dispose (GObject *object);
124 static void empathy_video_widget_finalize (GObject *object);
126 static gboolean empathy_video_widget_expose_event (GtkWidget *widget,
127 GdkEventExpose *event);
129 empathy_video_widget_element_set_sink_properties (EmpathyVideoWidget *self);
132 empathy_video_widget_set_property (GObject *object,
133 guint property_id, const GValue *value, GParamSpec *pspec)
135 EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
140 priv->bus = g_value_dup_object (value);
143 priv->min_width = g_value_get_int (value);
145 case PROP_MIN_HEIGHT:
146 priv->min_height = g_value_get_int (value);
149 priv->sync = g_value_get_boolean (value);
150 empathy_video_widget_element_set_sink_properties (
151 EMPATHY_VIDEO_WIDGET (object));
154 priv->async = g_value_get_boolean (value);
155 empathy_video_widget_element_set_sink_properties (
156 EMPATHY_VIDEO_WIDGET (object));
159 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
164 empathy_video_widget_get_property (GObject *object,
165 guint property_id, GValue *value, GParamSpec *pspec)
167 EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
171 case PROP_GST_ELEMENT:
172 g_value_set_object (value, priv->videosink);
175 g_value_set_object (value, priv->bus);
178 g_value_set_int (value, priv->min_width);
180 case PROP_MIN_HEIGHT:
181 g_value_set_int (value, priv->min_height);
184 g_value_set_boolean (value, priv->sync);
187 g_value_set_boolean (value, priv->async);
190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
196 empathy_video_widget_class_init (
197 EmpathyVideoWidgetClass *empathy_video_widget_class)
199 GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_widget_class);
200 GtkWidgetClass *widget_class =
201 GTK_WIDGET_CLASS (empathy_video_widget_class);
202 GParamSpec *param_spec;
204 g_type_class_add_private (empathy_video_widget_class,
205 sizeof (EmpathyVideoWidgetPriv));
207 object_class->dispose = empathy_video_widget_dispose;
208 object_class->finalize = empathy_video_widget_finalize;
209 object_class->constructed = empathy_video_widget_constructed;
211 object_class->set_property = empathy_video_widget_set_property;
212 object_class->get_property = empathy_video_widget_get_property;
214 widget_class->expose_event = empathy_video_widget_expose_event;
216 param_spec = g_param_spec_object ("gst-element",
217 "gst-element", "The underlaying gstreamer element",
219 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
220 g_object_class_install_property (object_class, PROP_GST_ELEMENT, param_spec);
222 param_spec = g_param_spec_object ("gst-bus",
224 "The toplevel bus from the pipeline in which this bin will be added",
226 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
227 g_object_class_install_property (object_class, PROP_GST_BUS, param_spec);
229 param_spec = g_param_spec_int ("min-width",
231 "Minimal width of the widget",
233 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
234 g_object_class_install_property (object_class, PROP_MIN_WIDTH, param_spec);
236 param_spec = g_param_spec_int ("min-height",
238 "Minimal height of the widget",
240 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
241 g_object_class_install_property (object_class, PROP_MIN_HEIGHT, param_spec);
243 param_spec = g_param_spec_boolean ("sync",
245 "Whether the underlying sink should be sync or not",
247 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
248 g_object_class_install_property (object_class, PROP_SYNC, param_spec);
250 param_spec = g_param_spec_boolean ("async",
252 "Whether the underlying sink should be async or not",
254 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
255 g_object_class_install_property (object_class, PROP_ASYNC, param_spec);
259 empathy_video_widget_dispose (GObject *object)
261 EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (object);
262 EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
264 if (priv->dispose_has_run)
267 priv->dispose_has_run = TRUE;
269 if (priv->bus != NULL)
270 g_object_unref (priv->bus);
274 if (priv->videosink != NULL)
275 g_object_unref (priv->videosink);
277 priv->videosink = NULL;
280 /* release any references held by the object here */
282 if (G_OBJECT_CLASS (empathy_video_widget_parent_class)->dispose)
283 G_OBJECT_CLASS (empathy_video_widget_parent_class)->dispose (object);
287 empathy_video_widget_finalize (GObject *object)
289 EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (object);
290 EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
292 /* free any data held directly by the object here */
293 g_mutex_free (priv->lock);
295 G_OBJECT_CLASS (empathy_video_widget_parent_class)->finalize (object);
300 empathy_video_widget_element_set_sink_properties_unlocked (
301 EmpathyVideoWidget *self)
303 EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
305 if (priv->overlay == NULL)
308 if (g_object_class_find_property (G_OBJECT_GET_CLASS (priv->overlay),
309 "force-aspect-ratio"))
310 g_object_set (G_OBJECT (priv->overlay), "force-aspect-ratio", TRUE, NULL);
312 if (g_object_class_find_property (
313 G_OBJECT_GET_CLASS (priv->overlay), "sync"))
314 g_object_set (G_OBJECT (priv->overlay), "sync", priv->sync, NULL);
316 if (g_object_class_find_property (G_OBJECT_GET_CLASS (priv->overlay),
318 g_object_set (G_OBJECT (priv->overlay), "async", priv->async, NULL);
322 empathy_video_widget_element_set_sink_properties (EmpathyVideoWidget *self)
324 EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
326 g_mutex_lock (priv->lock);
327 empathy_video_widget_element_set_sink_properties_unlocked (self);
328 g_mutex_unlock (priv->lock);
332 empathy_video_widget_element_added_cb (FsElementAddedNotifier *notifier,
333 GstBin *bin, GstElement *element, EmpathyVideoWidget *self)
335 EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
337 /* We assume the overlay is the sink */
338 g_mutex_lock (priv->lock);
339 if (priv->overlay == NULL && GST_IS_X_OVERLAY (element))
341 priv->overlay = element;
342 empathy_video_widget_element_set_sink_properties_unlocked (self);
343 gst_x_overlay_expose (GST_X_OVERLAY (priv->overlay));
345 g_mutex_unlock (priv->lock);
349 empathy_video_widget_sync_message_cb (GstBus *bus, GstMessage *message,
350 EmpathyVideoWidget *self)
352 EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
353 const GstStructure *s;
355 if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
358 if (GST_MESSAGE_SRC (message) != (GstObject *) priv->overlay)
361 s = gst_message_get_structure (message);
363 if (gst_structure_has_name (s, "prepare-xwindow-id"))
365 gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay),
366 GDK_WINDOW_XID (GTK_WIDGET (self)->window));
371 empathy_video_widget_expose_event (GtkWidget *widget, GdkEventExpose *event)
373 EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (widget);
374 EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
376 if (event != NULL && event->count > 0)
379 if (priv->overlay == NULL)
382 gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay),
383 GDK_WINDOW_XID (widget->window));
385 gst_x_overlay_expose (GST_X_OVERLAY (priv->overlay));
391 empathy_video_widget_new_with_size (GstBus *bus, gint width, gint height)
393 g_return_val_if_fail (bus != NULL, NULL);
395 return GTK_WIDGET (g_object_new (EMPATHY_TYPE_VIDEO_WIDGET,
398 "min-height", height,
403 empathy_video_widget_new (GstBus *bus)
405 g_return_val_if_fail (bus != NULL, NULL);
407 return GTK_WIDGET (g_object_new (EMPATHY_TYPE_VIDEO_WIDGET,
413 empathy_video_widget_get_sink (EmpathyVideoWidget *widget)
415 EmpathyVideoWidgetPriv *priv = GET_PRIV (widget);
417 return priv->sink_pad;
421 empathy_video_widget_get_element (EmpathyVideoWidget *widget)
423 EmpathyVideoWidgetPriv *priv = GET_PRIV (widget);
425 return priv->videosink;