]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-video-widget.c
Add minimum width and height properties
[empathy.git] / libempathy-gtk / empathy-video-widget.c
1 /*
2  * empathy-gst-gtk-widget.c - Source for EmpathyVideoWidget
3  * Copyright (C) 2008 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
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.
10  *
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.
15  *
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
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <gdk/gdkx.h>
26 #include <gst/interfaces/xoverlay.h>
27 #include <gst/farsight/fs-element-added-notifier.h>
28
29 #include "empathy-video-widget.h"
30
31 G_DEFINE_TYPE(EmpathyVideoWidget, empathy_video_widget,
32   GTK_TYPE_DRAWING_AREA)
33
34 static void empathy_video_widget_element_added_cb (
35   FsElementAddedNotifier *notifier, GstBin *bin, GstElement *element,
36   EmpathyVideoWidget *self);
37
38 static void empathy_video_widget_sync_message_cb (
39   GstBus *bus, GstMessage *message, EmpathyVideoWidget *self);
40
41 /* signal enum */
42 #if 0
43 enum
44 {
45     LAST_SIGNAL
46 };
47
48 static guint signals[LAST_SIGNAL] = {0};
49 #endif
50
51 enum {
52   PROP_GST_ELEMENT = 1,
53   PROP_GST_BUS,
54   PROP_MIN_WIDTH,
55   PROP_MIN_HEIGHT,
56 };
57
58 /* private structure */
59 typedef struct _EmpathyVideoWidgetPriv EmpathyVideoWidgetPriv;
60
61 struct _EmpathyVideoWidgetPriv
62 {
63   gboolean dispose_has_run;
64   GstBus *bus;
65   GstElement *videosink;
66   GstPad *sink_pad;
67   GstElement *overlay;
68   FsElementAddedNotifier *notifier;
69   gint min_width;
70   gint min_height;
71 };
72
73 #define GET_PRIV(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
74   EMPATHY_TYPE_GST_GTK_WIDGET, EmpathyVideoWidgetPriv))
75
76 static void
77 empathy_video_widget_init (EmpathyVideoWidget *obj)
78 {
79   EmpathyVideoWidgetPriv *priv = GET_PRIV (obj);
80   GdkColor black;
81
82   priv->notifier = fs_element_added_notifier_new ();
83   g_signal_connect (priv->notifier, "element-added",
84     G_CALLBACK (empathy_video_widget_element_added_cb),
85     obj);
86
87   if (gdk_color_parse ("Black", &black))
88     gtk_widget_modify_bg (GTK_WIDGET (obj), GTK_STATE_NORMAL,
89       &black);
90
91   GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (obj), GTK_DOUBLE_BUFFERED);
92 }
93
94 static void
95 empathy_video_widget_constructed (GObject *object)
96 {
97   EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
98
99   priv->videosink = gst_element_factory_make ("gconfvideosink", NULL);
100   gst_object_ref (priv->videosink);
101   gst_object_sink (priv->videosink);
102
103   priv->sink_pad = gst_element_get_static_pad (priv->videosink, "sink");
104
105   fs_element_added_notifier_add (priv->notifier, GST_BIN (priv->videosink));
106   gst_bus_enable_sync_message_emission (priv->bus);
107
108   g_signal_connect (priv->bus, "sync-message",
109     G_CALLBACK (empathy_video_widget_sync_message_cb), object);
110
111   gtk_widget_set_size_request (GTK_WIDGET (object), priv->min_width,
112     priv->min_height);
113 }
114
115 static void empathy_video_widget_dispose (GObject *object);
116 static void empathy_video_widget_finalize (GObject *object);
117 static gboolean empathy_video_widget_expose_event (GtkWidget *widget,
118   GdkEventExpose *event);
119
120 static void
121 empathy_video_widget_set_property (GObject *object,
122   guint property_id, const GValue *value, GParamSpec *pspec)
123 {
124   EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
125
126   switch (property_id)
127     {
128       case PROP_GST_BUS:
129         priv->bus = g_value_dup_object (value);
130         break;
131       case PROP_MIN_WIDTH:
132         priv->min_width = g_value_get_int (value);
133         break;
134       case PROP_MIN_HEIGHT:
135         priv->min_height = g_value_get_int (value);
136         break;
137       default:
138         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
139     }
140 }
141
142 static void
143 empathy_video_widget_get_property (GObject *object,
144   guint property_id, GValue *value, GParamSpec *pspec)
145 {
146   EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
147
148   switch (property_id)
149     {
150       case PROP_GST_ELEMENT:
151         g_value_set_object (value, priv->videosink);
152         break;
153       case PROP_GST_BUS:
154         g_value_set_object (value, priv->bus);
155         break;
156       case PROP_MIN_WIDTH:
157         g_value_set_int (value, priv->min_width);
158         break;
159       case PROP_MIN_HEIGHT:
160         g_value_set_int (value, priv->min_height);
161         break;
162       default:
163         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
164     }
165 }
166
167
168 static void
169 empathy_video_widget_class_init (
170   EmpathyVideoWidgetClass *empathy_video_widget_class)
171 {
172   GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_widget_class);
173   GtkWidgetClass *widget_class =
174     GTK_WIDGET_CLASS (empathy_video_widget_class);
175   GParamSpec *param_spec;
176
177   g_type_class_add_private (empathy_video_widget_class,
178     sizeof (EmpathyVideoWidgetPriv));
179
180   object_class->dispose = empathy_video_widget_dispose;
181   object_class->finalize = empathy_video_widget_finalize;
182   object_class->constructed = empathy_video_widget_constructed;
183
184   object_class->set_property = empathy_video_widget_set_property;
185   object_class->get_property = empathy_video_widget_get_property;
186
187   widget_class->expose_event = empathy_video_widget_expose_event;
188
189   param_spec = g_param_spec_object ("gst-element",
190     "gst-element", "The underlaying gstreamer element",
191     GST_TYPE_ELEMENT,
192     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
193   g_object_class_install_property (object_class, PROP_GST_ELEMENT, param_spec);
194
195   param_spec = g_param_spec_object ("gst-bus",
196     "gst-bus",
197     "The toplevel bus from the pipeline in which this bin will be added",
198     GST_TYPE_BUS,
199     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
200   g_object_class_install_property (object_class, PROP_GST_BUS, param_spec);
201
202   param_spec = g_param_spec_int ("min-width",
203     "min-width",
204     "Minimal width of the widget",
205     0, G_MAXINT, 320,
206     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
207   g_object_class_install_property (object_class, PROP_MIN_WIDTH, param_spec);
208
209   param_spec = g_param_spec_int ("min-height",
210     "min-height",
211     "Minimal height of the widget",
212     0, G_MAXINT, 240,
213     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
214   g_object_class_install_property (object_class, PROP_MIN_HEIGHT, param_spec);
215
216 }
217
218 void
219 empathy_video_widget_dispose (GObject *object)
220 {
221   EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (object);
222   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
223
224   if (priv->dispose_has_run)
225     return;
226
227   priv->dispose_has_run = TRUE;
228
229   if (priv->bus != NULL)
230     g_object_unref (priv->bus);
231
232   priv->bus = NULL;
233
234   if (priv->videosink != NULL)
235     g_object_unref (priv->videosink);
236
237   priv->videosink = NULL;
238
239
240   /* release any references held by the object here */
241
242   if (G_OBJECT_CLASS (empathy_video_widget_parent_class)->dispose)
243     G_OBJECT_CLASS (empathy_video_widget_parent_class)->dispose (object);
244 }
245
246 void
247 empathy_video_widget_finalize (GObject *object)
248 {
249   //EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (object);
250   //EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
251
252   /* free any data held directly by the object here */
253
254   G_OBJECT_CLASS (empathy_video_widget_parent_class)->finalize (object);
255 }
256
257 static void
258 empathy_video_widget_element_added_cb (FsElementAddedNotifier *notifier,
259   GstBin *bin, GstElement *element, EmpathyVideoWidget *self)
260 {
261   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
262
263   if (priv->overlay == NULL && GST_IS_X_OVERLAY (element))
264     {
265       priv->overlay = element;
266       gst_x_overlay_expose (GST_X_OVERLAY (priv->overlay));
267     }
268
269   if (g_object_class_find_property (
270       G_OBJECT_GET_CLASS (element), "force-aspect-ratio"))
271     {
272       g_object_set (G_OBJECT (element), "force-aspect-ratio", TRUE, NULL);
273     }
274 }
275
276 static void
277 empathy_video_widget_sync_message_cb (GstBus *bus, GstMessage *message,
278   EmpathyVideoWidget *self)
279 {
280   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
281   const GstStructure *s;
282
283   if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
284     return;
285
286   if (GST_MESSAGE_SRC (message) != (GstObject *) priv->overlay)
287     return;
288
289   s = gst_message_get_structure (message);
290
291   if (gst_structure_has_name (s, "prepare-xwindow-id"))
292     {
293       gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay),
294         GDK_WINDOW_XID (GTK_WIDGET (self)->window));
295     }
296 }
297
298 static gboolean
299 empathy_video_widget_expose_event (GtkWidget *widget, GdkEventExpose *event)
300 {
301   EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (widget);
302   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
303
304   if (event != NULL && event->count > 0)
305     return TRUE;
306
307   if (priv->overlay == NULL)
308     return TRUE;
309
310   gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay),
311     GDK_WINDOW_XID (widget->window));
312
313   gst_x_overlay_expose (GST_X_OVERLAY (priv->overlay));
314
315   return TRUE;
316 }
317
318 GtkWidget *
319 empathy_video_widget_new_with_size (GstBus *bus, gint width, gint height)
320 {
321   g_return_val_if_fail (bus != NULL, NULL);
322
323   return GTK_WIDGET (g_object_new (EMPATHY_TYPE_GST_GTK_WIDGET,
324     "gst-bus", bus,
325     "min-width", width,
326     "min-height", height,
327     NULL));
328 }
329
330 GtkWidget *
331 empathy_video_widget_new (GstBus *bus)
332 {
333   g_return_val_if_fail (bus != NULL, NULL);
334
335   return GTK_WIDGET (g_object_new (EMPATHY_TYPE_GST_GTK_WIDGET,
336     "gst-bus", bus,
337     NULL));
338 }
339
340 GstPad *
341 empathy_video_widget_get_sink (EmpathyVideoWidget *widget)
342 {
343   EmpathyVideoWidgetPriv *priv = GET_PRIV (widget);
344
345   return priv->sink_pad;
346 }
347
348 GstElement *
349 empathy_video_widget_get_element (EmpathyVideoWidget *widget)
350 {
351   EmpathyVideoWidgetPriv *priv = GET_PRIV (widget);
352
353   return priv->videosink;
354 }