prefs: call on_change when setting resolution on sync
[gstreamer-omap:cheese.git] / src / cheese-prefs-resolution-combo.c
1 /*
2  * Copyright © 2008 James Liggett <jrliggett@cox.net>
3  *
4  * Licensed under the GNU General Public License Version 2
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <string.h>
21 #include "cheese-prefs-resolution-combo.h"
22
23 typedef struct
24 {
25   gchar *x_resolution_key;
26   gchar *y_resolution_key;
27   unsigned int max_x_resolution;
28   unsigned int max_y_resolution;
29   GtkListStore *list_store;
30   CheeseCamera *camera;
31   CheeseVideoFormat *selected_format;
32   gboolean has_been_synchronized;  /* Make sure we don't synchronize if client
33                                     * sets camera on construction. */
34 } CheesePrefsResolutionComboPrivate;
35
36 #define CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE(o)                     \
37   (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_PREFS_RESOLUTION_COMBO, \
38                                 CheesePrefsResolutionComboPrivate))
39
40 enum
41 {
42   PROP_0,
43
44   PROP_X_RESOLUTION_KEY,
45   PROP_Y_RESOLUTION_KEY,
46   PROP_MAX_X_RESOLUTION,
47   PROP_MAX_Y_RESOLUTION,
48   PROP_CAMERA
49 };
50
51 enum
52 {
53   COL_NAME,
54   COL_FORMAT,
55   NUM_COLS
56 };
57
58 G_DEFINE_TYPE (CheesePrefsResolutionCombo, cheese_prefs_resolution_combo, CHEESE_TYPE_PREFS_WIDGET);
59
60 static void
61 cheese_prefs_resolution_combo_init (CheesePrefsResolutionCombo *self)
62 {
63   CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
64
65   priv->x_resolution_key      = NULL;
66   priv->y_resolution_key      = NULL;
67   priv->max_x_resolution      = G_MAXUINT;
68   priv->max_y_resolution      = G_MAXUINT;
69   priv->list_store            = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
70   priv->camera                = NULL;
71   priv->selected_format       = NULL;
72   priv->has_been_synchronized = FALSE;
73 }
74
75 static void
76 cheese_prefs_resolution_combo_finalize (GObject *object)
77 {
78   CheesePrefsResolutionCombo        *self = CHEESE_PREFS_RESOLUTION_COMBO (object);
79   CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
80
81   g_free (priv->x_resolution_key);
82   g_free (priv->y_resolution_key);
83   g_object_unref (priv->list_store);
84
85   G_OBJECT_CLASS (cheese_prefs_resolution_combo_parent_class)->finalize (object);
86 }
87
88 static void
89 combo_selection_changed (GtkComboBox                *combo_box,
90                          CheesePrefsResolutionCombo *self)
91 {
92   CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
93
94   GtkTreeIter        iter;
95   CheeseVideoFormat *format;
96
97   gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
98   gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), &iter, COL_FORMAT,
99                       &format, -1);
100
101   g_object_set (CHEESE_PREFS_WIDGET (self)->gconf, priv->x_resolution_key,
102                 format->width, priv->y_resolution_key, format->height, NULL);
103
104   priv->selected_format = format;
105
106   cheese_prefs_widget_notify_changed (CHEESE_PREFS_WIDGET (self));
107 }
108
109 static void
110 cheese_prefs_resolution_combo_synchronize (CheesePrefsWidget *prefs_widget)
111 {
112   CheesePrefsResolutionCombo        *self = CHEESE_PREFS_RESOLUTION_COMBO (prefs_widget);
113   CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
114
115   GtkWidget               *combo_box;
116   const CheeseVideoFormat *current_format;
117   GList                   *formats;
118   GList                   *l;
119   CheeseVideoFormat       *format;
120   gchar                   *format_name;
121   GtkTreeIter              iter;
122   GtkTreeIter              active_iter;
123   gboolean                 found_resolution;
124
125   priv->has_been_synchronized = TRUE;
126   found_resolution            = FALSE;
127
128   /* Don't generate spurious changed events when we set the active resolution */
129   g_object_get (prefs_widget, "widget", &combo_box, NULL);
130   g_signal_handlers_disconnect_by_func (combo_box, combo_selection_changed,
131                                         prefs_widget);
132
133   g_object_ref (priv->list_store);
134   gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), NULL);
135
136   gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), NULL);
137   current_format = g_slice_new (CheeseVideoFormat);
138   g_object_get (CHEESE_PREFS_WIDGET (self)->gconf,
139                 priv->x_resolution_key, &(current_format->width),
140                 priv->y_resolution_key, &(current_format->height), NULL);
141
142   gtk_list_store_clear (priv->list_store);
143   if (strstr (priv->x_resolution_key, "video"))
144     formats = cheese_camera_get_video_formats (priv->camera);
145   else
146     formats = cheese_camera_get_photo_formats (priv->camera);
147
148   for (l = formats; l != NULL; l = l->next)
149   {
150     format      = l->data;
151     format_name = g_strdup_printf ("%i x %i", format->width, format->height);
152
153     if (format->width <= priv->max_x_resolution &&
154         format->height <= priv->max_y_resolution)
155     {
156       gtk_list_store_append (priv->list_store, &iter);
157       gtk_list_store_set (priv->list_store, &iter,
158                           COL_NAME, format_name,
159                           COL_FORMAT, format,
160                           -1);
161
162       g_free (format_name);
163
164       if ((format->width == current_format->width) &&
165           (format->height == current_format->height))
166       {
167         active_iter      = iter;
168         found_resolution = TRUE;
169       }
170     }
171   }
172
173   gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box),
174                            GTK_TREE_MODEL (priv->list_store));
175   g_object_unref (priv->list_store);
176
177   g_signal_connect (G_OBJECT (combo_box), "changed",
178                     G_CALLBACK (combo_selection_changed),
179                     self);
180
181   if (found_resolution)
182     gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &active_iter);
183   else
184     gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
185
186   gtk_widget_set_sensitive (combo_box, formats != NULL);
187   g_list_free (formats);
188   g_list_free (l);
189 }
190
191 static void
192 cheese_prefs_resolution_combo_set_property (GObject *object, guint prop_id,
193                                             const GValue *value,
194                                             GParamSpec *pspec)
195 {
196   CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (object);
197
198   g_return_if_fail (CHEESE_IS_PREFS_RESOLUTION_COMBO (object));
199
200   switch (prop_id)
201   {
202     case PROP_X_RESOLUTION_KEY:
203       priv->x_resolution_key = g_value_dup_string (value);
204       break;
205     case PROP_Y_RESOLUTION_KEY:
206       priv->y_resolution_key = g_value_dup_string (value);
207       break;
208     case PROP_MAX_X_RESOLUTION:
209       priv->max_x_resolution = g_value_get_uint (value);
210       break;
211     case PROP_MAX_Y_RESOLUTION:
212       priv->max_y_resolution = g_value_get_uint (value);
213       break;
214     case PROP_CAMERA:
215       priv->camera = CHEESE_CAMERA (g_value_get_object (value));
216
217       /* If the camera changes the resolutions change too. But only change the
218        * data if we've been synchronized once already. If this property is set
219        * on construction, we would synchronize twice--once when the property is
220        * set, and again when the dialog syncs when it's created. */
221       if (priv->has_been_synchronized)
222         cheese_prefs_resolution_combo_synchronize (CHEESE_PREFS_WIDGET (object));
223
224       break;
225     default:
226       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
227       break;
228   }
229 }
230
231 static void
232 cheese_prefs_resolution_combo_get_property (GObject *object, guint prop_id,
233                                             GValue *value, GParamSpec *pspec)
234 {
235   CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (object);
236
237   g_return_if_fail (CHEESE_IS_PREFS_RESOLUTION_COMBO (object));
238
239   switch (prop_id)
240   {
241     case PROP_X_RESOLUTION_KEY:
242       g_value_set_string (value, priv->x_resolution_key);
243       break;
244     case PROP_Y_RESOLUTION_KEY:
245       g_value_set_string (value, priv->y_resolution_key);
246       break;
247     case PROP_MAX_X_RESOLUTION:
248       g_value_set_uint (value, priv->max_x_resolution);
249       break;
250     case PROP_MAX_Y_RESOLUTION:
251       g_value_set_uint (value, priv->max_y_resolution);
252       break;
253     case PROP_CAMERA:
254       g_value_set_object (value, priv->camera);
255       break;
256     default:
257       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
258       break;
259   }
260 }
261
262 static void
263 cheese_prefs_resolution_combo_class_init (CheesePrefsResolutionComboClass *klass)
264 {
265   GObjectClass           *object_class = G_OBJECT_CLASS (klass);
266   CheesePrefsWidgetClass *parent_class = CHEESE_PREFS_WIDGET_CLASS (klass);
267
268   g_type_class_add_private (klass, sizeof (CheesePrefsResolutionComboPrivate));
269
270   object_class->finalize     = cheese_prefs_resolution_combo_finalize;
271   object_class->set_property = cheese_prefs_resolution_combo_set_property;
272   object_class->get_property = cheese_prefs_resolution_combo_get_property;
273   parent_class->synchronize  = cheese_prefs_resolution_combo_synchronize;
274
275   g_object_class_install_property (object_class,
276                                    PROP_X_RESOLUTION_KEY,
277                                    g_param_spec_string ("x_resolution_key",
278                                                         "",
279                                                         "GConf key for X resolution",
280                                                         "",
281                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
282
283   g_object_class_install_property (object_class,
284                                    PROP_Y_RESOLUTION_KEY,
285                                    g_param_spec_string ("y_resolution_key",
286                                                         "",
287                                                         "GConf key for Y resolution",
288                                                         "",
289                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
290
291   g_object_class_install_property (object_class,
292                                    PROP_MAX_X_RESOLUTION,
293                                    g_param_spec_uint ("max_x_resolution",
294                                                       "",
295                                                       "Maximum supported X resolution",
296                                                       0,
297                                                       G_MAXUINT,
298                                                       G_MAXUINT,
299                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
300
301   g_object_class_install_property (object_class,
302                                    PROP_MAX_Y_RESOLUTION,
303                                    g_param_spec_uint ("max_y_resolution",
304                                                       "",
305                                                       "Maximum supported Y resolution",
306                                                       0,
307                                                       G_MAXUINT,
308                                                       G_MAXUINT,
309                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
310
311   g_object_class_install_property (object_class,
312                                    PROP_CAMERA,
313                                    g_param_spec_object ("camera",
314                                                         "",
315                                                         "Camera object",
316                                                         CHEESE_TYPE_CAMERA,
317                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
318 }
319
320 CheesePrefsResolutionCombo *
321 cheese_prefs_resolution_combo_new (GtkWidget *combo_box, CheeseCamera *camera,
322                                    const gchar *x_resolution_key,
323                                    const gchar *y_resolution_key,
324                                    unsigned int max_x_resolution,
325                                    unsigned int max_y_resolution)
326 {
327   CheesePrefsResolutionCombo        *self;
328   GtkCellRenderer                   *renderer;
329   CheesePrefsResolutionComboPrivate *priv;
330
331   self = g_object_new (CHEESE_TYPE_PREFS_RESOLUTION_COMBO,
332                        "widget", combo_box,
333                        "camera", camera,
334                        "x_resolution_key", x_resolution_key,
335                        "y_resolution_key", y_resolution_key,
336                        NULL);
337
338   if (max_x_resolution > 0 &&
339       max_y_resolution > 0)
340   {
341     g_object_set (self,
342                   "max_x_resolution", max_x_resolution,
343                   "max_y_resolution", max_y_resolution,
344                   NULL);
345   }
346
347   priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
348
349   renderer = gtk_cell_renderer_text_new ();
350   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
351   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), renderer, "text",
352                                  COL_NAME);
353   gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box),
354                            GTK_TREE_MODEL (priv->list_store));
355
356   return self;
357 }
358
359 CheeseVideoFormat *
360 cheese_prefs_resolution_combo_get_selected_format (CheesePrefsResolutionCombo *resolution_combo)
361 {
362   CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (resolution_combo);
363
364   return priv->selected_format;
365 }