]> git.0d.be Git - empathy.git/blob - libempathy/empathy-camera-monitor.c
1e603e9890c94fdbab1cdb5399d9a5e5ab6337de
[empathy.git] / libempathy / empathy-camera-monitor.c
1 /*
2  * Copyright (C) 2011 Collabora Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
19  */
20
21 #include "config.h"
22
23 #include "empathy-camera-monitor.h"
24 #include "cheese-camera-device-monitor.h"
25
26 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
27 #include "empathy-debug.h"
28
29 struct _EmpathyCameraMonitorPrivate
30 {
31   EmpathyCameraDeviceMonitor *empathy_monitor;
32   GQueue *cameras;
33   gint num_cameras;
34 };
35
36 enum
37 {
38   PROP_0,
39   PROP_AVAILABLE,
40 };
41
42 enum
43 {
44   CAMERA_ADDED,
45   CAMERA_REMOVED,
46   LAST_SIGNAL
47 };
48
49 static guint signals[LAST_SIGNAL];
50
51 G_DEFINE_TYPE (EmpathyCameraMonitor, empathy_camera_monitor, G_TYPE_OBJECT);
52
53 static EmpathyCameraMonitor *manager_singleton = NULL;
54
55 static EmpathyCamera *
56 empathy_camera_new (const gchar *id,
57     const gchar *device,
58     const gchar *name)
59 {
60   EmpathyCamera *camera = g_slice_new (EmpathyCamera);
61
62   camera->id = g_strdup (id);
63   camera->device = g_strdup (device);
64   camera->name = g_strdup (name);
65
66   return camera;
67 }
68
69 static EmpathyCamera *
70 empathy_camera_copy (EmpathyCamera *camera)
71 {
72   return empathy_camera_new (camera->id, camera->device, camera->name);
73 }
74
75 static void
76 empathy_camera_free (EmpathyCamera *camera)
77 {
78   g_free (camera->id);
79   g_free (camera->device);
80   g_free (camera->name);
81
82   g_slice_free (EmpathyCamera, camera);
83 }
84
85 G_DEFINE_BOXED_TYPE (EmpathyCamera, empathy_camera,
86     empathy_camera_copy, empathy_camera_free)
87
88 static gint
89 empathy_camera_find (gconstpointer a,
90     gconstpointer b)
91 {
92   const EmpathyCamera *camera = a;
93   const gchar *id = b;
94
95   return g_strcmp0 (camera->id, id);
96 }
97
98 static void
99 empathy_camera_monitor_free_camera_foreach (gpointer data,
100     gpointer user_data)
101 {
102   empathy_camera_free (data);
103 }
104
105 static void
106 on_camera_added (EmpathyCameraDeviceMonitor *device,
107     gchar *id,
108     gchar *filename,
109     gchar *product_name,
110     gint api_version,
111     EmpathyCameraMonitor *self)
112 {
113   EmpathyCamera *camera;
114
115   if (self->priv->cameras == NULL)
116     return;
117
118   camera = empathy_camera_new (id, filename, product_name);
119
120   g_queue_push_tail (self->priv->cameras, camera);
121
122   self->priv->num_cameras++;
123
124   if (self->priv->num_cameras == 1)
125     g_object_notify (G_OBJECT (self), "available");
126
127   g_signal_emit (self, signals[CAMERA_ADDED], 0, camera);
128 }
129
130 static void
131 on_camera_removed (EmpathyCameraDeviceMonitor *device,
132     gchar *id,
133     EmpathyCameraMonitor *self)
134 {
135   EmpathyCamera *camera;
136   GList *l;
137
138   if (self->priv->cameras == NULL)
139     return;
140
141   l = g_queue_find_custom (self->priv->cameras, id, empathy_camera_find);
142
143   g_return_if_fail (l != NULL);
144
145   camera = l->data;
146
147   g_queue_delete_link (self->priv->cameras, l);
148
149   self->priv->num_cameras--;
150
151   if (self->priv->num_cameras == 0)
152     g_object_notify (G_OBJECT (self), "available");
153
154   g_signal_emit (self, signals[CAMERA_REMOVED], 0, camera);
155
156   empathy_camera_free (camera);
157 }
158
159 const GList *
160 empathy_camera_monitor_get_cameras (EmpathyCameraMonitor *self)
161 {
162   if (self->priv->cameras != NULL)
163     return self->priv->cameras->head;
164   else
165     return NULL;
166 }
167
168 static void
169 empathy_camera_monitor_get_property (GObject *object,
170     guint prop_id,
171     GValue *value,
172     GParamSpec *pspec)
173 {
174   EmpathyCameraMonitor *self = (EmpathyCameraMonitor *) object;
175
176   switch (prop_id)
177     {
178     case PROP_AVAILABLE:
179       g_value_set_boolean (value, self->priv->num_cameras > 0);
180       break;
181     default:
182       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
183       break;
184   }
185 }
186
187 static void
188 empathy_camera_monitor_dispose (GObject *object)
189 {
190   EmpathyCameraMonitor *self = EMPATHY_CAMERA_MONITOR (object);
191
192   tp_clear_object (&self->priv->empathy_monitor);
193
194   g_queue_foreach (self->priv->cameras,
195       empathy_camera_monitor_free_camera_foreach, NULL);
196   tp_clear_pointer (&self->priv->cameras, g_queue_free);
197
198   G_OBJECT_CLASS (empathy_camera_monitor_parent_class)->dispose (object);
199 }
200
201 static void
202 empathy_camera_monitor_constructed (GObject *object)
203 {
204   EmpathyCameraMonitor *self = (EmpathyCameraMonitor *) object;
205
206   G_OBJECT_CLASS (empathy_camera_monitor_parent_class)->constructed (object);
207
208   empathy_camera_device_monitor_coldplug (self->priv->empathy_monitor);
209 }
210
211 static void
212 empathy_camera_monitor_class_init (EmpathyCameraMonitorClass *klass)
213 {
214   GObjectClass *object_class = G_OBJECT_CLASS (klass);
215
216   object_class->dispose = empathy_camera_monitor_dispose;
217   object_class->constructed = empathy_camera_monitor_constructed;
218   object_class->get_property = empathy_camera_monitor_get_property;
219
220   g_object_class_install_property (object_class, PROP_AVAILABLE,
221       g_param_spec_boolean ("available", "Available",
222       "Camera available", TRUE, G_PARAM_READABLE));
223
224   signals[CAMERA_ADDED] =
225       g_signal_new ("added", G_OBJECT_CLASS_TYPE (klass),
226           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
227           0, NULL, NULL,
228           g_cclosure_marshal_generic,
229           G_TYPE_NONE, 1, EMPATHY_TYPE_CAMERA);
230
231   signals[CAMERA_REMOVED] =
232       g_signal_new ("removed", G_OBJECT_CLASS_TYPE (klass),
233           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
234           0, NULL, NULL,
235           g_cclosure_marshal_generic,
236           G_TYPE_NONE, 1, EMPATHY_TYPE_CAMERA);
237
238   g_type_class_add_private (object_class,
239       sizeof (EmpathyCameraMonitorPrivate));
240 }
241
242 static void
243 empathy_camera_monitor_init (EmpathyCameraMonitor *self)
244 {
245   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
246       EMPATHY_TYPE_CAMERA_MONITOR, EmpathyCameraMonitorPrivate);
247
248   self->priv->cameras = g_queue_new ();
249
250   self->priv->empathy_monitor = empathy_camera_device_monitor_new ();
251
252   g_signal_connect (self->priv->empathy_monitor, "added",
253       G_CALLBACK (on_camera_added), self);
254   g_signal_connect (self->priv->empathy_monitor, "removed",
255       G_CALLBACK (on_camera_removed), self);
256
257 #ifndef HAVE_UDEV
258   /* No udev, assume there are cameras present */
259   self->priv->num_cameras = 1;
260 #endif
261 }
262
263 EmpathyCameraMonitor *
264 empathy_camera_monitor_dup_singleton (void)
265 {
266   GObject *retval;
267
268   if (manager_singleton)
269     {
270       retval = g_object_ref (manager_singleton);
271     }
272   else
273     {
274       retval = g_object_new (EMPATHY_TYPE_CAMERA_MONITOR, NULL);
275
276       manager_singleton = EMPATHY_CAMERA_MONITOR (retval);
277       g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
278     }
279
280   return EMPATHY_CAMERA_MONITOR (retval);
281 }
282
283 EmpathyCameraMonitor *
284 empathy_camera_monitor_new (void)
285 {
286   return EMPATHY_CAMERA_MONITOR (
287       g_object_new (EMPATHY_TYPE_CAMERA_MONITOR, NULL));
288 }
289
290 gboolean empathy_camera_monitor_get_available (EmpathyCameraMonitor *self)
291 {
292   g_return_val_if_fail (EMPATHY_IS_CAMERA_MONITOR (self), FALSE);
293
294   return self->priv->num_cameras > 0;
295 }