cheese r672 - in trunk: . data src



Author: dgsiegel
Date: Mon Apr 21 16:37:06 2008
New Revision: 672
URL: http://svn.gnome.org/viewvc/cheese?rev=672&view=rev

Log:
add a preferences dialog with basic resolution changing, partially fixes #522200, courtesy of James Liggett


Added:
   trunk/data/cheese-prefs.glade
   trunk/data/cheese-prefs.ui
   trunk/src/cheese-prefs-dialog-widgets.c
   trunk/src/cheese-prefs-dialog-widgets.h
   trunk/src/cheese-prefs-dialog.c
   trunk/src/cheese-prefs-dialog.h
   trunk/src/cheese-prefs-resolution-combo.c
   trunk/src/cheese-prefs-resolution-combo.h
   trunk/src/cheese-prefs-widget.c
   trunk/src/cheese-prefs-widget.h
Modified:
   trunk/AUTHORS
   trunk/ChangeLog
   trunk/data/Makefile.am
   trunk/data/cheese-ui.xml
   trunk/data/cheese.schemas.in
   trunk/src/Makefile.am
   trunk/src/cheese-gconf.c
   trunk/src/cheese-gconf.h
   trunk/src/cheese-webcam.c
   trunk/src/cheese-webcam.h
   trunk/src/cheese-window.c

Modified: trunk/AUTHORS
==============================================================================
--- trunk/AUTHORS	(original)
+++ trunk/AUTHORS	Mon Apr 21 16:37:06 2008
@@ -1,10 +1,11 @@
 written by daniel g. siegel <dgsiegel gmail com> and Jaap Haitsma <jaap haitsma org>
 
 the following people contributed to cheese:
-  - Cosimo Cecchi <anarki lilik it>
   - Baptiste Mille-Mathias <bmm80 free fr>
+  - Cosimo Cecchi <anarki lilik it>
   - Diego Escalante Urrelo <dieguito gmail com>
   - Gintautas Miliauskas <gintas akl lt>
+  - James Liggett <jrliggett cox net>
   - Luca Ferretti <elle uca libero it>
   - Mirco "MacSlow" MÃller <macslow bangang de>
   - Patryk Zawadzki <patrys pld-linux org>

Modified: trunk/data/Makefile.am
==============================================================================
--- trunk/data/Makefile.am	(original)
+++ trunk/data/Makefile.am	Mon Apr 21 16:37:06 2008
@@ -13,7 +13,8 @@
 
 pkgdata_DATA =						\
 	cheese.ui					\
-	cheese-ui.xml
+	cheese-ui.xml \
+	cheese-prefs.ui
 
 EXTRA_DIST =						\
 	$(desktop_in_files)				\

Added: trunk/data/cheese-prefs.glade
==============================================================================
--- (empty file)
+++ trunk/data/cheese-prefs.glade	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.0 on Sat Apr 12 23:13:46 2008 -->
+<glade-interface>
+  <widget class="GtkDialog" id="cheese_prefs_dialog">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Preferences</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_NONE</property>
+                <child>
+                  <widget class="GtkAlignment" id="alignment6">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <widget class="GtkComboBox" id="resolution_combo_box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Resolution&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/data/cheese-prefs.ui
==============================================================================
--- (empty file)
+++ trunk/data/cheese-prefs.ui	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<!--Generated with glade3 3.4.0 on Sat Apr 12 23:13:46 2008 -->
+<interface>
+  <object class="GtkDialog" id="cheese_prefs_dialog">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Preferences</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <object class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_NONE</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment6">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkComboBox" id="resolution_combo_box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Resolution&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">button1</action-widget>
+    </action-widgets>
+  </object>
+</interface>

Modified: trunk/data/cheese-ui.xml
==============================================================================
--- trunk/data/cheese-ui.xml	(original)
+++ trunk/data/cheese-ui.xml	Mon Apr 21 16:37:06 2008
@@ -1,21 +1,23 @@
 <ui>
-  <menubar name="MainMenu">
-    <menu action="Cheese">
+  <menubar name="MainMenu" name="MainMenu">
+    <menu action="Cheese" name="Cheese">
       <menuitem name="CountdownToggle" action="Countdown" />
       <separator />
       <menuitem action="TakePhoto" />
       <menuitem action="TakeVideo" />
       <separator />
-      <menuitem action="Photo" />
-      <menuitem action="Video" />
+      <menuitem action="Photo" name="Photo" />
+      <menuitem action="Video" name="Video" />
       <separator />
       <menuitem action="Quit" />
     </menu>
-    <menu action="Edit">
+    <menu action="Edit" name="Edit">
       <menuitem action="Effects" />
       <separator />
       <menuitem action="MoveToTrash" />
       <menuitem action="RemoveAll" />
+      <separator />
+      <menuitem action="Preferences" />
     </menu>
     <menu action="Help">
       <menuitem action="HelpContents" />

Modified: trunk/data/cheese.schemas.in
==============================================================================
--- trunk/data/cheese.schemas.in	(original)
+++ trunk/data/cheese.schemas.in	Mon Apr 21 16:37:06 2008
@@ -10,7 +10,7 @@
 				<short>Use a countdown</short>
 				<long>Whether a countdown should be used, when taking a photo</long>
 			</locale>
-    		</schema>
+    	</schema>
 
 		<schema>
 			<key>/schemas/apps/cheese/webcam</key>
@@ -38,6 +38,30 @@
 				Shagadelic, Vertigo, Edge, Dice and Warp</long>
 			</locale>
 		</schema>
+		
+		<schema>
+			<key>/schemas/apps/cheese/x_resolution</key>
+			<applyto>/apps/cheese/x_resolution</applyto>
+			<owner>cheese</owner>
+			<type>int</type>
+			<default>0</default>
+			<locale name="C">
+				<short>X resolution</short>
+				<long>The X resolution of the image captured from the camera</long>
+			</locale>
+    	</schema>
+		
+		<schema>
+			<key>/schemas/apps/cheese/y_resolution</key>
+			<applyto>/apps/cheese/y_resolution</applyto>
+			<owner>cheese</owner>
+			<type>int</type>
+			<default>0</default>
+			<locale name="C">
+				<short>Y resolution</short>
+				<long>The Y resolution of the image captured from the camera</long>
+			</locale>
+    	</schema>
 
 	</schemalist>
 </gconfschemafile>

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Mon Apr 21 16:37:06 2008
@@ -36,7 +36,15 @@
 	gedit-message-area.c \
 	gedit-message-area.h \
 	cheese-no-camera.c \
-	cheese-no-camera.h
+	cheese-no-camera.h \
+	cheese-prefs-widget.h \
+	cheese-prefs-widget.c \
+	cheese-prefs-dialog-widgets.h \
+	cheese-prefs-dialog-widgets.c \
+	cheese-prefs-resolution-combo.h \
+	cheese-prefs-resolution-combo.c \
+	cheese-prefs-dialog.c \
+	cheese-prefs-dialog.h
 
 cheese_LDADD = \
 	$(CHEESE_LIBS)

Modified: trunk/src/cheese-gconf.c
==============================================================================
--- trunk/src/cheese-gconf.c	(original)
+++ trunk/src/cheese-gconf.c	Mon Apr 21 16:37:06 2008
@@ -86,6 +86,16 @@
       g_slist_free (list);
       g_slist_free (tmp);
       break;
+    case GCONF_PROP_X_RESOLUTION:
+      g_value_set_int (value, gconf_client_get_int (priv->client,
+                                                    CHEESE_GCONF_PREFIX "/x_resolution",
+                                                    NULL));
+      break;
+    case GCONF_PROP_Y_RESOLUTION:
+      g_value_set_int (value, gconf_client_get_int (priv->client,
+                                                    CHEESE_GCONF_PREFIX "/y_resolution",
+                                                    NULL));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -139,6 +149,18 @@
       g_slist_free (list);
       g_strfreev (effects);
       break;
+    case GCONF_PROP_X_RESOLUTION:
+      gconf_client_set_int (priv->client,
+                            CHEESE_GCONF_PREFIX "/x_resolution",
+                            g_value_get_int (value),
+                            NULL);
+      break;
+    case GCONF_PROP_Y_RESOLUTION:
+      gconf_client_set_int (priv->client,
+                            CHEESE_GCONF_PREFIX "/y_resolution",
+                            g_value_get_int (value),
+                            NULL);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -183,8 +205,26 @@
                                                         NULL,
                                                         NULL,
                                                         "",
-                                                        G_PARAM_READWRITE));
-
+                                                        G_PARAM_READWRITE)); 
+    
+  g_object_class_install_property (object_class, GCONF_PROP_X_RESOLUTION,
+                                   g_param_spec_int ("gconf_prop_x_resolution",
+                                                     NULL,
+                                                     NULL,
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+    
+  g_object_class_install_property (object_class, GCONF_PROP_Y_RESOLUTION,
+                                   g_param_spec_int ("gconf_prop_y_resolution",
+                                                     NULL,
+                                                     NULL,
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+    
   g_type_class_add_private (klass, sizeof (CheeseGConfPrivate));
 }
 

Modified: trunk/src/cheese-gconf.h
==============================================================================
--- trunk/src/cheese-gconf.h	(original)
+++ trunk/src/cheese-gconf.h	Mon Apr 21 16:37:06 2008
@@ -44,7 +44,9 @@
   GCONF_PROP_0,
   GCONF_PROP_COUNTDOWN,
   GCONF_PROP_WEBCAM,
-  GCONF_PROP_SELECTED_EFFECTS
+  GCONF_PROP_SELECTED_EFFECTS,
+  GCONF_PROP_X_RESOLUTION,
+  GCONF_PROP_Y_RESOLUTION
 };
 
 GType        cheese_gconf_get_type(void);

Added: trunk/src/cheese-prefs-dialog-widgets.c
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-dialog-widgets.c	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,115 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cheese-prefs-dialog-widgets.h"
+
+typedef struct 
+{
+  GList *widgets;
+  CheeseGConf *gconf;
+} CheesePrefsDialogWidgetsPrivate;
+
+#define CHEESE_PREFS_DIALOG_WIDGETS_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_PREFS_DIALOG_WIDGETS, \
+   CheesePrefsDialogWidgetsPrivate))
+
+G_DEFINE_TYPE (CheesePrefsDialogWidgets, cheese_prefs_dialog_widgets, G_TYPE_OBJECT);
+
+static void
+cheese_prefs_dialog_widgets_init (CheesePrefsDialogWidgets *self)
+{
+  CheesePrefsDialogWidgetsPrivate *priv = CHEESE_PREFS_DIALOG_WIDGETS_GET_PRIVATE (self);
+  
+  priv->widgets = NULL;
+  priv->gconf = NULL;
+}
+
+static void
+cheese_prefs_dialog_widgets_finalize (GObject *object)
+{ 
+  CheesePrefsDialogWidgetsPrivate *priv = CHEESE_PREFS_DIALOG_WIDGETS_GET_PRIVATE (object);
+  GList *current_widget;
+  
+  current_widget = priv->widgets;
+  
+  while (current_widget)
+  {
+    g_object_unref (current_widget->data);
+    current_widget = g_list_next (current_widget);
+  }
+  
+  g_list_free (priv->widgets);
+  
+  G_OBJECT_CLASS (cheese_prefs_dialog_widgets_parent_class)->finalize (object);
+}
+
+static void
+cheese_prefs_dialog_widgets_class_init (CheesePrefsDialogWidgetsClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+  
+  g_type_class_add_private (klass, sizeof (CheesePrefsDialogWidgetsPrivate));
+  
+  object_class->finalize = cheese_prefs_dialog_widgets_finalize;
+}
+
+
+CheesePrefsDialogWidgets *
+cheese_prefs_dialog_widgets_new (CheeseGConf *gconf)
+{
+  CheesePrefsDialogWidgets *self;
+  CheesePrefsDialogWidgetsPrivate *priv;
+  
+  self = g_object_new (CHEESE_TYPE_PREFS_DIALOG_WIDGETS, NULL);
+  
+  priv = CHEESE_PREFS_DIALOG_WIDGETS_GET_PRIVATE (self);
+  priv->gconf = gconf;
+  
+  return self;
+}
+
+void
+cheese_prefs_dialog_widgets_add (CheesePrefsDialogWidgets *prefs_widgets, 
+                                 CheesePrefsWidget *widget)
+{
+  CheesePrefsDialogWidgetsPrivate *priv = CHEESE_PREFS_DIALOG_WIDGETS_GET_PRIVATE (prefs_widgets);
+  
+  if (!g_list_find (priv->widgets, widget))
+  {
+    priv->widgets = g_list_append (priv->widgets, widget);
+    widget->gconf = priv->gconf;
+  }
+}
+
+void
+cheese_prefs_dialog_widgets_synchronize (CheesePrefsDialogWidgets *prefs_widgets)
+{
+  CheesePrefsDialogWidgetsPrivate *priv = CHEESE_PREFS_DIALOG_WIDGETS_GET_PRIVATE (prefs_widgets);
+  
+  GList *current_widget;
+  
+  current_widget = priv->widgets;
+  
+  while (current_widget)
+  {
+    cheese_prefs_widget_synchronize (CHEESE_PREFS_WIDGET (current_widget->data));
+    current_widget = g_list_next (current_widget);
+  }
+}

Added: trunk/src/cheese-prefs-dialog-widgets.h
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-dialog-widgets.h	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,57 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CHEESE_PREFS_DIALOG_WIDGETS_H_
+#define _CHEESE_PREFS_DIALOG_WIDGETS_H_
+
+#include <glib-object.h>
+#include "cheese-prefs-widget.h"
+
+G_BEGIN_DECLS
+
+#define CHEESE_TYPE_PREFS_DIALOG_WIDGETS             (cheese_prefs_dialog_widgets_get_type ())
+#define CHEESE_PREFS_DIALOG_WIDGETS(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), CHEESE_TYPE_PREFS_DIALOG_WIDGETS, CheesePrefsDialogWidgets))
+#define CHEESE_PREFS_DIALOG_WIDGETS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), CHEESE_TYPE_PREFS_DIALOG_WIDGETS, CheesePrefsDialogWidgetsClass))
+#define CHEESE_IS_PREFS_DIALOG_WIDGETS(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CHEESE_TYPE_PREFS_DIALOG_WIDGETS))
+#define CHEESE_IS_PREFS_DIALOG_WIDGETS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), CHEESE_TYPE_PREFS_DIALOG_WIDGETS))
+#define CHEESE_PREFS_DIALOG_WIDGETS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), CHEESE_TYPE_PREFS_DIALOG_WIDGETS, CheesePrefsDialogWidgetsClass))
+
+typedef struct _CheesePrefsDialogWidgetsClass CheesePrefsDialogWidgetsClass;
+typedef struct _CheesePrefsDialogWidgets CheesePrefsDialogWidgets;
+
+struct _CheesePrefsDialogWidgetsClass
+{
+  GObjectClass parent_class;
+};
+
+struct _CheesePrefsDialogWidgets
+{
+  GObject parent_instance;
+};
+
+GType cheese_prefs_dialog_widgets_get_type (void) G_GNUC_CONST;
+CheesePrefsDialogWidgets *cheese_prefs_dialog_widgets_new (CheeseGConf *gconf);
+void cheese_prefs_dialog_widgets_add (CheesePrefsDialogWidgets *prefs_widgets, 
+                                      CheesePrefsWidget *widget);
+void cheese_prefs_dialog_widgets_synchronize (CheesePrefsDialogWidgets *prefs_widgets);
+
+G_END_DECLS
+
+#endif /* _CHEESE_PREFS_DIALOG_WIDGETS_H_ */

Added: trunk/src/cheese-prefs-dialog.c
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-dialog.c	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,122 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cheese-prefs-dialog.h"
+
+typedef struct
+{
+  GtkWidget *cheese_prefs_dialog;
+  GtkWidget *resolution_combo_box;
+  
+  GtkWidget *parent;
+  CheeseWebcam *webcam;
+  
+  CheesePrefsDialogWidgets *widgets;
+} CheesePrefsDialog;
+
+static void
+cheese_prefs_dialog_create_dialog (CheesePrefsDialog *prefs_dialog)
+{
+  GtkBuilder *builder;
+  GError *error;
+  
+  error = NULL;
+  builder = gtk_builder_new ();
+  gtk_builder_add_from_file (builder, PACKAGE_DATADIR"/cheese-prefs.ui", &error);
+
+  if (error)
+  {
+    g_error ("building ui from %s failed: %s", PACKAGE_DATADIR"/cheese-prefs.ui", error->message);
+    g_clear_error (&error);
+  }
+  
+  prefs_dialog->cheese_prefs_dialog = GTK_WIDGET (gtk_builder_get_object (builder, 
+                                                                          "cheese_prefs_dialog"));
+  prefs_dialog->resolution_combo_box = GTK_WIDGET (gtk_builder_get_object (builder, 
+                                                                           "resolution_combo_box"));
+  
+  gtk_window_set_transient_for (GTK_WINDOW (prefs_dialog->cheese_prefs_dialog),
+                                GTK_WINDOW (prefs_dialog->parent));
+}
+
+static void
+on_resolution_changed (CheesePrefsWidget *widget, gpointer user_data)
+{
+  CheeseWebcam *webcam;
+  CheeseVideoFormat *current_format;
+  CheeseVideoFormat *new_format;
+  
+  g_object_get (widget, "webcam", &webcam, NULL);
+  
+  current_format = cheese_webcam_get_current_video_format (webcam);
+  new_format = cheese_prefs_resolution_combo_get_selected_format (CHEESE_PREFS_RESOLUTION_COMBO (widget));
+  
+  if (new_format != current_format)
+    cheese_webcam_set_video_format (webcam, new_format);
+}
+
+static void
+cheese_prefs_dialog_setup_widgets (CheesePrefsDialog *prefs_dialog)
+{
+  CheesePrefsWidget *widget;
+  
+  widget = CHEESE_PREFS_WIDGET (cheese_prefs_resolution_combo_new (prefs_dialog->resolution_combo_box,
+                                                                   prefs_dialog->webcam,
+                                                                   "gconf_prop_x_resolution",
+                                                                   "gconf_prop_y_resolution",
+                                                                   0, 0));
+  g_signal_connect (G_OBJECT (widget), "changed",
+                    G_CALLBACK (on_resolution_changed),
+                    NULL);
+  
+  cheese_prefs_dialog_widgets_add (prefs_dialog->widgets, widget);
+  
+  cheese_prefs_dialog_widgets_synchronize (prefs_dialog->widgets);
+}
+
+static void
+cheese_prefs_dialog_destroy_dialog (CheesePrefsDialog *prefs_dialog)
+{
+  gtk_widget_destroy (prefs_dialog->cheese_prefs_dialog);
+  
+  g_object_unref (prefs_dialog->widgets);
+  
+  g_free (prefs_dialog);
+}
+
+void
+cheese_prefs_dialog_run (GtkWidget *parent, CheeseGConf *gconf, 
+                         CheeseWebcam *webcam)
+{
+  CheesePrefsDialog *prefs_dialog;
+  
+  prefs_dialog = g_new0 (CheesePrefsDialog, 1);
+  
+  prefs_dialog->parent = parent;
+  prefs_dialog->webcam = webcam;
+  prefs_dialog->widgets = cheese_prefs_dialog_widgets_new (gconf);
+  
+  cheese_prefs_dialog_create_dialog (prefs_dialog);
+  cheese_prefs_dialog_setup_widgets (prefs_dialog);
+  
+  gtk_dialog_run (GTK_DIALOG (prefs_dialog->cheese_prefs_dialog));
+  
+  cheese_prefs_dialog_destroy_dialog (prefs_dialog);
+}

Added: trunk/src/cheese-prefs-dialog.h
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-dialog.h	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,35 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CHEESE_PREFS_DIALOG_H_
+#define _CHEESE_PREFS_DIALOG_H_
+
+#ifdef HAVE_CONFIG_H
+#include "cheese-config.h"
+#endif
+
+#include "cheese-webcam.h"
+#include "cheese-prefs-dialog-widgets.h"
+#include "cheese-prefs-resolution-combo.h"
+
+void cheese_prefs_dialog_run (GtkWidget *parent, CheeseGConf *gconf, 
+                              CheeseWebcam *webcam);
+
+#endif /* _CHEESE_PREFS_DIALOG_H_ */

Added: trunk/src/cheese-prefs-resolution-combo.c
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-resolution-combo.c	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,358 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cheese-prefs-resolution-combo.h"
+
+typedef struct
+{
+  gchar *x_resolution_key;
+  gchar *y_resolution_key;
+  unsigned int max_x_resolution;
+  unsigned int max_y_resolution;
+  GtkListStore *list_store;
+  CheeseWebcam *webcam;
+  CheeseVideoFormat *selected_format;
+  gboolean has_been_synchronized;  /* Make sure we don't synchronize if client
+                                    * sets webcam on construction. */
+} CheesePrefsResolutionComboPrivate;
+
+#define CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_PREFS_RESOLUTION_COMBO, \
+   CheesePrefsResolutionComboPrivate))
+
+enum
+{
+  PROP_0,
+  
+  PROP_X_RESOLUTION_KEY,
+  PROP_Y_RESOLUTION_KEY,
+  PROP_MAX_X_RESOLUTION,
+  PROP_MAX_Y_RESOLUTION,
+  PROP_WEBCAM
+};
+
+enum
+{
+  COL_NAME,
+  COL_FORMAT,
+  NUM_COLS
+};
+
+G_DEFINE_TYPE (CheesePrefsResolutionCombo, cheese_prefs_resolution_combo, CHEESE_TYPE_PREFS_WIDGET);
+
+static void
+cheese_prefs_resolution_combo_init (CheesePrefsResolutionCombo *self)
+{
+  CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
+  
+  priv->x_resolution_key = NULL;
+  priv->y_resolution_key = NULL;
+  priv->max_x_resolution = G_MAXUINT;
+  priv->max_y_resolution = G_MAXUINT;
+  priv->list_store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
+  priv->webcam = NULL;
+  priv->selected_format = NULL;
+  priv->has_been_synchronized = FALSE;
+}
+
+static void
+cheese_prefs_resolution_combo_finalize (GObject *object)
+{
+  CheesePrefsResolutionCombo *self = CHEESE_PREFS_RESOLUTION_COMBO (object);
+  CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
+  
+  g_free (priv->x_resolution_key);
+  g_free (priv->y_resolution_key);
+  g_object_unref (priv->list_store);
+  
+  G_OBJECT_CLASS (cheese_prefs_resolution_combo_parent_class)->finalize (object);
+}
+
+static void
+combo_selection_changed (GtkComboBox *combo_box, 
+                         CheesePrefsResolutionCombo *self)
+{
+  CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self); 
+  GtkTreeIter iter;
+  CheeseVideoFormat *format;
+  
+  gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
+  gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), &iter, COL_FORMAT, 
+                      &format, -1);
+  
+  g_object_set (CHEESE_PREFS_WIDGET (self)->gconf, priv->x_resolution_key,
+                format->width, priv->y_resolution_key, format->height, NULL);
+  
+  priv->selected_format = format;
+  
+  cheese_prefs_widget_notify_changed (CHEESE_PREFS_WIDGET (self));
+}
+
+static void
+cheese_prefs_resolution_combo_synchronize (CheesePrefsWidget *prefs_widget)
+{
+  CheesePrefsResolutionCombo *self = CHEESE_PREFS_RESOLUTION_COMBO (prefs_widget);
+  CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self); 
+  GtkWidget *combo_box;
+  CheeseVideoFormat *current_format;
+  GArray *formats;
+  int i;
+  CheeseVideoFormat *format;
+  gchar *format_name;
+  GtkTreeIter iter;
+  GtkTreeIter active_iter;
+  gboolean found_resolution;
+  
+  priv->has_been_synchronized = TRUE;
+  found_resolution = FALSE;
+  
+  /* Don't generate spurious changed events when we set the active resolution */
+  g_object_get (prefs_widget, "widget", &combo_box, NULL);
+  g_signal_handlers_disconnect_by_func (combo_box, combo_selection_changed, 
+                                        prefs_widget);
+  
+  g_object_ref (priv->list_store);
+  gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), NULL);
+  
+  gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), NULL);
+  current_format = cheese_webcam_get_current_video_format (priv->webcam);
+  
+  gtk_list_store_clear (priv->list_store);
+  formats = cheese_webcam_get_video_formats (priv->webcam);
+  
+  for (i = 0; i < formats->len; i++)
+  {
+    format = &g_array_index (formats, CheeseVideoFormat, i);
+    format_name = g_strdup_printf ("%i x %i", format->width, format->height);
+    
+    
+    if (format->width <= priv->max_x_resolution && 
+        format->height <= priv->max_y_resolution)
+    {
+      gtk_list_store_append (priv->list_store, &iter);
+      gtk_list_store_set (priv->list_store, &iter, 
+                          COL_NAME, format_name,
+                          COL_FORMAT, format, 
+                          -1);
+      
+      g_free (format_name);
+      
+      if (format == current_format)
+      {
+        active_iter = iter;
+        found_resolution = TRUE;
+      }
+
+    }
+  }
+  
+  gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), 
+                           GTK_TREE_MODEL (priv->list_store));
+  g_object_unref (priv->list_store);
+  
+  if (found_resolution)
+    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &active_iter);
+  else
+    gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
+  
+  g_signal_connect (G_OBJECT (combo_box), "changed",
+                    G_CALLBACK (combo_selection_changed),
+                    self);
+  
+}
+
+static void
+cheese_prefs_resolution_combo_set_property (GObject *object, guint prop_id, 
+                                            const GValue *value, 
+                                            GParamSpec *pspec)
+{
+  CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (object);
+  
+  g_return_if_fail (CHEESE_IS_PREFS_RESOLUTION_COMBO (object));
+  
+  switch (prop_id)
+  {
+    case PROP_X_RESOLUTION_KEY:
+      priv->x_resolution_key = g_value_dup_string (value);
+      break;
+    case PROP_Y_RESOLUTION_KEY:
+      priv->y_resolution_key = g_value_dup_string (value);
+      break;
+    case PROP_MAX_X_RESOLUTION:
+      priv->max_x_resolution = g_value_get_uint (value);
+      break;
+    case PROP_MAX_Y_RESOLUTION:
+      priv->max_y_resolution = g_value_get_uint (value);
+      break;
+    case PROP_WEBCAM:
+      priv->webcam = CHEESE_WEBCAM (g_value_get_object (value));
+      
+      /* If the webcam changes the resolutions change too. But only change the
+       * data if we've been synchronized once already. If this property is set
+       * on construction, we would synchronize twice--once when the property is
+       * set, and again when the dialog syncs when it's created. */
+      if (priv->has_been_synchronized)
+        cheese_prefs_resolution_combo_synchronize (CHEESE_PREFS_WIDGET (object));
+      
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+cheese_prefs_resolution_combo_get_property (GObject *object, guint prop_id, 
+                                            GValue *value, GParamSpec *pspec)
+{
+  CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (object);
+  
+  g_return_if_fail (CHEESE_IS_PREFS_RESOLUTION_COMBO (object));
+  
+  switch (prop_id)
+  {
+    case PROP_X_RESOLUTION_KEY:
+      g_value_set_string (value, priv->x_resolution_key);
+      break;
+    case PROP_Y_RESOLUTION_KEY:
+      g_value_set_string (value, priv->y_resolution_key);
+      break;
+    case PROP_MAX_X_RESOLUTION:
+      g_value_set_uint (value, priv->max_x_resolution);
+      break;
+    case PROP_MAX_Y_RESOLUTION:
+      g_value_set_uint (value, priv->max_y_resolution);
+      break;
+    case PROP_WEBCAM:
+      g_value_set_object (value, priv->webcam);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+cheese_prefs_resolution_combo_class_init (CheesePrefsResolutionComboClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+  CheesePrefsWidgetClass* parent_class = CHEESE_PREFS_WIDGET_CLASS (klass);
+  
+  g_type_class_add_private (klass, sizeof (CheesePrefsResolutionComboPrivate));
+  
+  object_class->finalize = cheese_prefs_resolution_combo_finalize;
+  object_class->set_property = cheese_prefs_resolution_combo_set_property;
+  object_class->get_property = cheese_prefs_resolution_combo_get_property;
+  parent_class->synchronize = cheese_prefs_resolution_combo_synchronize;
+  
+  g_object_class_install_property (object_class,
+                                   PROP_X_RESOLUTION_KEY,
+                                   g_param_spec_string ("x_resolution_key",
+                                                        "",
+                                                        "GConf key for X resolution",
+                                                        "",
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+  
+  g_object_class_install_property (object_class,
+                                   PROP_Y_RESOLUTION_KEY,
+                                   g_param_spec_string ("y_resolution_key",
+                                                        "",
+                                                        "GConf key for Y resolution",
+                                                        "",
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+  
+  g_object_class_install_property (object_class,
+                                   PROP_MAX_X_RESOLUTION,
+                                   g_param_spec_uint ("max_x_resolution",
+                                                      "",
+                                                      "Maximum supported X resolution",
+                                                      0, 
+                                                      G_MAXUINT, 
+                                                      G_MAXUINT,
+                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
+  
+  g_object_class_install_property (object_class,
+                                   PROP_MAX_Y_RESOLUTION,
+                                   g_param_spec_uint ("max_y_resolution",
+                                                      "",
+                                                      "Maximum supported Y resolution",
+                                                      0, 
+                                                      G_MAXUINT, 
+                                                      G_MAXUINT,
+                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
+  
+  g_object_class_install_property (object_class, 
+                                   PROP_WEBCAM,
+                                   g_param_spec_object ("webcam",
+                                                        "",
+                                                        "Webcam object",
+                                                        CHEESE_TYPE_WEBCAM,
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
+}
+
+CheesePrefsResolutionCombo *
+cheese_prefs_resolution_combo_new (GtkWidget *combo_box, CheeseWebcam *webcam, 
+                                   const gchar *x_resolution_key, 
+                                   const gchar *y_resolution_key,
+                                   unsigned int max_x_resolution,
+                                   unsigned int max_y_resolution)
+{
+  CheesePrefsResolutionCombo *self;
+  GtkCellRenderer *renderer;
+  CheesePrefsResolutionComboPrivate *priv; 
+  
+  self = g_object_new (CHEESE_TYPE_PREFS_RESOLUTION_COMBO, 
+                       "widget", combo_box, 
+                       "webcam", webcam,
+                       "x_resolution_key", x_resolution_key,
+                       "y_resolution_key", y_resolution_key,
+                       NULL);
+  
+  if (max_x_resolution > 0 &&
+      max_y_resolution > 0)
+  {
+    g_object_set (self, 
+                  "max_x_resolution", max_x_resolution, 
+                  "max_y_resolution", max_y_resolution, 
+                  NULL);
+  }
+  
+  priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (self);
+  
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
+  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), renderer, "text",
+                                 COL_NAME);
+  gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), 
+                           GTK_TREE_MODEL (priv->list_store));
+  
+  return self;
+  
+}
+
+CheeseVideoFormat *
+cheese_prefs_resolution_combo_get_selected_format (CheesePrefsResolutionCombo *resolution_combo)
+{
+  CheesePrefsResolutionComboPrivate *priv = CHEESE_PREFS_RESOLUTION_COMBO_GET_PRIVATE (resolution_combo); 
+  
+  return priv->selected_format;
+}
+
+

Added: trunk/src/cheese-prefs-resolution-combo.h
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-resolution-combo.h	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,62 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CHEESE_PREFS_RESOLUTION_COMBO_H_
+#define _CHEESE_PREFS_RESOLUTION_COMBO_H_
+
+#include <glib-object.h>
+#include "cheese-prefs-widget.h"
+#include "cheese-webcam.h"
+
+G_BEGIN_DECLS
+
+#define CHEESE_TYPE_PREFS_RESOLUTION_COMBO             (cheese_prefs_resolution_combo_get_type ())
+#define CHEESE_PREFS_RESOLUTION_COMBO(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), CHEESE_TYPE_PREFS_RESOLUTION_COMBO, CheesePrefsResolutionCombo))
+#define CHEESE_PREFS_RESOLUTION_COMBO_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), CHEESE_TYPE_PREFS_RESOLUTION_COMBO, CheesePrefsResolutionComboClass))
+#define CHEESE_IS_PREFS_RESOLUTION_COMBO(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CHEESE_TYPE_PREFS_RESOLUTION_COMBO))
+#define CHEESE_IS_PREFS_RESOLUTION_COMBO_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), CHEESE_TYPE_PREFS_RESOLUTION_COMBO))
+#define CHEESE_PREFS_RESOLUTION_COMBO_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), CHEESE_TYPE_PREFS_RESOLUTION_COMBO, CheesePrefsResolutionComboClass))
+
+typedef struct _CheesePrefsResolutionComboClass CheesePrefsResolutionComboClass;
+typedef struct _CheesePrefsResolutionCombo CheesePrefsResolutionCombo;
+
+struct _CheesePrefsResolutionComboClass
+{
+	CheesePrefsWidgetClass parent_class;
+};
+
+struct _CheesePrefsResolutionCombo
+{
+	CheesePrefsWidget parent_instance;
+};
+
+GType cheese_prefs_resolution_combo_get_type (void) G_GNUC_CONST;
+
+CheesePrefsResolutionCombo *cheese_prefs_resolution_combo_new (GtkWidget *combo_box,
+                                                               CheeseWebcam *webcam,
+                                                               const gchar *x_resolution_key,
+                                                               const gchar *y_resolution_key,
+                                                               unsigned int max_x_resolution,
+                                                               unsigned int max_y_resolution);
+CheeseVideoFormat *cheese_prefs_resolution_combo_get_selected_format (CheesePrefsResolutionCombo *resolution_combo);
+
+G_END_DECLS
+
+#endif /* _CHEESE_PREFS_RESOLUTION_COMBO_H_ */

Added: trunk/src/cheese-prefs-widget.c
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-widget.c	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,153 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cheese-prefs-widget.h"
+
+enum
+{
+  CHANGED,
+  
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  
+  PROP_WIDGET
+};
+
+
+static guint prefs_widget_signals[LAST_SIGNAL] = { 0 };
+
+typedef struct
+{
+  GtkWidget *widget;
+} CheesePrefsWidgetPrivate;
+
+#define CHEESE_PREFS_WIDGET_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_PREFS_WIDGET, \
+   CheesePrefsWidgetPrivate))
+
+G_DEFINE_TYPE (CheesePrefsWidget, cheese_prefs_widget, G_TYPE_OBJECT);
+
+static void
+cheese_prefs_widget_init (CheesePrefsWidget *prefs_widget)
+{
+  CheesePrefsWidgetPrivate *priv = CHEESE_PREFS_WIDGET_GET_PRIVATE (prefs_widget);
+  
+  prefs_widget->gconf = NULL;
+  priv->widget = NULL;
+}
+
+static void
+cheese_prefs_widget_finalize (GObject *object)
+{ 
+  G_OBJECT_CLASS (cheese_prefs_widget_parent_class)->finalize (object);
+}
+
+static void
+cheese_prefs_widget_set_property (GObject *object, guint prop_id, 
+                                  const GValue *value, 
+                                  GParamSpec *pspec)
+{
+  CheesePrefsWidgetPrivate *priv = CHEESE_PREFS_WIDGET_GET_PRIVATE (object);
+  
+  g_return_if_fail (CHEESE_IS_PREFS_WIDGET (object));
+  
+  switch (prop_id)
+  {
+    case PROP_WIDGET:
+      priv->widget = GTK_WIDGET (g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+cheese_prefs_widget_get_property (GObject *object, guint prop_id, 
+                                  GValue *value, GParamSpec *pspec)
+{
+  CheesePrefsWidgetPrivate *priv = CHEESE_PREFS_WIDGET_GET_PRIVATE (object);
+  
+  g_return_if_fail (CHEESE_IS_PREFS_WIDGET (object));
+  
+  switch (prop_id)
+  {
+    case PROP_WIDGET:
+      g_value_set_object (value, priv->widget);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+cheese_prefs_widget_changed (CheesePrefsWidget *self)
+{
+
+}
+
+static void
+cheese_prefs_widget_class_init (CheesePrefsWidgetClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+  
+  object_class->finalize = cheese_prefs_widget_finalize;
+  object_class->set_property = cheese_prefs_widget_set_property;
+  object_class->get_property = cheese_prefs_widget_get_property;
+  
+  klass->changed = cheese_prefs_widget_changed;
+  klass->synchronize = NULL;
+  
+  g_type_class_add_private (klass, sizeof (CheesePrefsWidgetPrivate));
+  
+  prefs_widget_signals[CHANGED] =
+    g_signal_new ("changed",
+                  G_OBJECT_CLASS_TYPE (klass),
+                  0,
+                  G_STRUCT_OFFSET (CheesePrefsWidgetClass, changed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  
+  g_object_class_install_property (object_class, PROP_WIDGET,
+                                   g_param_spec_object ("widget",
+                                                        "",
+                                                        "The widget that this object wraps",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+
+void
+cheese_prefs_widget_synchronize (CheesePrefsWidget *prefs_widget)
+{
+  CHEESE_PREFS_WIDGET_GET_CLASS (prefs_widget)->synchronize (prefs_widget);
+}
+
+void
+cheese_prefs_widget_notify_changed (CheesePrefsWidget *prefs_widget)
+{
+  g_signal_emit_by_name (prefs_widget, "changed");
+}

Added: trunk/src/cheese-prefs-widget.h
==============================================================================
--- (empty file)
+++ trunk/src/cheese-prefs-widget.h	Mon Apr 21 16:37:06 2008
@@ -0,0 +1,64 @@
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * Copyright (C) 2008 James Liggett <jrliggett cox net>
+ * 
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CHEESE_PREFS_WIDGET_H_
+#define _CHEESE_PREFS_WIDGET_H_
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "cheese-gconf.h"
+
+G_BEGIN_DECLS
+
+#define CHEESE_TYPE_PREFS_WIDGET             (cheese_prefs_widget_get_type ())
+#define CHEESE_PREFS_WIDGET(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), CHEESE_TYPE_PREFS_WIDGET, CheesePrefsWidget))
+#define CHEESE_PREFS_WIDGET_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), CHEESE_TYPE_PREFS_WIDGET, CheesePrefsWidgetClass))
+#define CHEESE_IS_PREFS_WIDGET(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CHEESE_TYPE_PREFS_WIDGET))
+#define CHEESE_IS_PREFS_WIDGET_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), CHEESE_TYPE_PREFS_WIDGET))
+#define CHEESE_PREFS_WIDGET_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), CHEESE_TYPE_PREFS_WIDGET, CheesePrefsWidgetClass))
+
+typedef struct _CheesePrefsWidgetClass CheesePrefsWidgetClass;
+typedef struct _CheesePrefsWidget CheesePrefsWidget;
+
+struct _CheesePrefsWidgetClass
+{
+  GObjectClass parent_class;
+  
+  /* Signals */
+  void (*changed) (CheesePrefsWidget *self);
+  
+  /* Virtual methods */
+  void (*synchronize) (CheesePrefsWidget *self);
+};
+
+struct _CheesePrefsWidget
+{
+  GObject parent_instance;
+  
+  CheeseGConf *gconf;
+};
+
+GType cheese_prefs_widget_get_type (void) G_GNUC_CONST;
+void cheese_prefs_widget_synchronize (CheesePrefsWidget *prefs_widget);
+void cheese_prefs_widget_notify_changed (CheesePrefsWidget *prefs_widget);
+
+G_END_DECLS
+
+#endif /* _CHEESE_PREFS_WIDGET_H_ */

Modified: trunk/src/cheese-webcam.c
==============================================================================
--- trunk/src/cheese-webcam.c	(original)
+++ trunk/src/cheese-webcam.c	Mon Apr 21 16:37:06 2008
@@ -39,21 +39,6 @@
 
 #define CHEESE_WEBCAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_WEBCAM, CheeseWebcamPrivate))
 
-typedef struct 
-{
-  int numerator;
-  int denominator;
-} CheeseFramerate;
-
-typedef struct 
-{
-  char *mimetype;
-  int width;
-  int height;
-  int num_framerates;
-  CheeseFramerate *framerates; 
-} CheeseVideoFormat;
-
 typedef struct
 {
   char *video_device; 
@@ -78,6 +63,7 @@
   GstElement *video_save_bin;
 
   GstElement *video_source;
+  GstElement *capsfilter;
   GstElement *video_file_sink;
   GstElement *photo_sink;
   GstElement *audio_source;
@@ -98,13 +84,20 @@
   int num_webcam_devices;
   char *device_name;
   CheeseWebcamDevice *webcam_devices;
+  int x_resolution;
+  int y_resolution;
+  int selected_device;
+  CheeseVideoFormat *current_format;
+  GHashTable *supported_resolutions;
 } CheeseWebcamPrivate;
 
 enum 
 {
   PROP_0,
   PROP_VIDEO_WINDOW,
-  PROP_DEVICE_NAME
+  PROP_DEVICE_NAME,
+  PROP_X_RESOLUTION,
+  PROP_Y_RESOLUTION
 };
 
 enum 
@@ -240,6 +233,10 @@
   CheeseWebcamPrivate* priv = CHEESE_WEBCAM_GET_PRIVATE (webcam);
   int i;
   int num_udis;
+  int num_devices;  /* Devices we actually create formats for; can either be the
+                     * number of webcams detected, or 1 if none were. The one
+                     * refers to a fake device so that resolution changing still
+                     * works even if the computer doesn't have a webcam. */
   char **udis;
   DBusError error;
   LibHalContext *hal_ctx;
@@ -283,9 +280,19 @@
   }
 
   /* Initialize webcam structures */
-  priv->num_webcam_devices = num_udis;
-  priv->webcam_devices = g_new0 (CheeseWebcamDevice, priv->num_webcam_devices);
-  for (i = 0; i < priv->num_webcam_devices; i++)
+    
+  if (num_udis > 0)
+        priv->num_webcam_devices = num_devices = num_udis;
+  else
+  {
+    num_devices = 1;
+    priv->num_webcam_devices = num_udis;  /* We don't have any real cameras-- 
+                                           * this is important when we create 
+                                           * the pipeline. */
+  }
+  
+  priv->webcam_devices = g_new0 (CheeseWebcamDevice, num_devices);
+  for (i = 0; i < num_devices; i++)
   {
     priv->webcam_devices[i].num_video_formats = 0;
     priv->webcam_devices[i].video_formats = g_array_new (FALSE, FALSE, sizeof (CheeseVideoFormat));
@@ -456,8 +463,10 @@
 }
 
 static void
-cheese_webcam_get_webcam_device_data (CheeseWebcamDevice *webcam_device)
+cheese_webcam_get_webcam_device_data (CheeseWebcam *webcam, 
+                                      CheeseWebcamDevice *webcam_device)
 {
+  CheeseWebcamPrivate* priv = CHEESE_WEBCAM_GET_PRIVATE (webcam);
   char *pipeline_desc;
   GstElement *pipeline;
   GError *err;
@@ -532,6 +541,12 @@
     CheeseVideoFormat video_format;
    
     video_format = g_array_index (webcam_device->video_formats, CheeseVideoFormat, i);
+    g_hash_table_insert (priv->supported_resolutions, 
+                         g_strdup_printf ("%ix%i", video_format.width,
+                                          video_format.height), 
+                                          &g_array_index (webcam_device->video_formats, 
+                                                          CheeseVideoFormat, 
+                                                          i));
     g_print ("%s %d x %d num_framerates %d\n", video_format.mimetype, video_format.width, 
              video_format.height, video_format.num_framerates);
     for (j = 0; j < video_format.num_framerates; j++)
@@ -544,6 +559,26 @@
 }
 
 static void
+cheese_webcam_create_fake_format (CheeseWebcam *webcam)
+{
+  CheeseWebcamPrivate *priv = CHEESE_WEBCAM_GET_PRIVATE (webcam);
+  CheeseVideoFormat format;
+    
+  /* Right now just emulate one format: video/x-raw-yuv, 320x240 @ 30 Hz */
+    
+  format.mimetype = g_strdup ("video/x-raw-yuv");
+  format.width = 320;
+  format.height = 240;
+  format.num_framerates = 1;
+  format.framerates = g_new0 (CheeseFramerate, 1);
+  format.framerates[0].numerator = 30;
+  format.framerates[0].denominator = 1;
+    
+  g_array_append_val (priv->webcam_devices[0].video_formats, format);
+  priv->current_format = &format;
+}
+
+static void
 cheese_webcam_detect_webcam_devices (CheeseWebcam *webcam)
 {
   CheeseWebcamPrivate* priv = CHEESE_WEBCAM_GET_PRIVATE (webcam);
@@ -552,8 +587,37 @@
   cheese_webcam_get_video_devices_from_hal (webcam);
   for (i = 0; i < priv->num_webcam_devices; i++) 
   {
-    cheese_webcam_get_webcam_device_data (&(priv->webcam_devices[i]));
+    cheese_webcam_get_webcam_device_data (webcam, &(priv->webcam_devices[i]));
   }
+    
+  if (priv->num_webcam_devices == 0)
+   cheese_webcam_create_fake_format (webcam);
+}
+
+static void
+find_highest_framerate (CheeseVideoFormat *format, int *numerator, 
+                        int *denominator)
+{
+  int framerate_numerator;
+  int framerate_denominator;
+  int i;
+    
+  /* Select the highest framerate up to 30 Hz*/
+  framerate_numerator = 1;
+  framerate_denominator = 1;
+  for (i = 0; i < format->num_framerates; i++)
+  {
+    float framerate = format->framerates[i].numerator / format->framerates[i].denominator;
+    if (framerate > ((float)framerate_numerator / framerate_denominator)
+        && framerate <= 30)
+    {
+      framerate_numerator = format->framerates[i].numerator;
+      framerate_denominator = format->framerates[i].denominator;        
+    }
+  }
+    
+  *numerator = framerate_numerator;
+  *denominator = framerate_denominator;
 }
 
 static gboolean 
@@ -565,53 +629,60 @@
 
   if (priv->num_webcam_devices == 0)
   {
-    goto fallback;
+    priv->webcam_source_bin = gst_parse_bin_from_description ("videotestsrc name=video_source ! capsfilter name=capsfilter ! identity",
+                                                              TRUE, &err);
   }
   else
   {
     CheeseVideoFormat *format; 
     int i;
-    int selected_device;
     int framerate_numerator, framerate_denominator;
+    gchar *resolution;
 
     /* If we have a matching video device use that one, otherwise use the first */
-    selected_device = 0;
+    priv->selected_device = 0;
+    format = NULL;
     for (i = 1; i < priv->num_webcam_devices ; i++)
     {
 	    if (g_strcmp0 (priv->webcam_devices[i].video_device, priv->device_name) == 0)
-          selected_device = i;
+          priv->selected_device = i;
     }
-    CheeseWebcamDevice *selected_webcam = &(priv->webcam_devices[selected_device]);
+    CheeseWebcamDevice *selected_webcam = &(priv->webcam_devices[priv->selected_device]);
 
-    /* Select the highest resolution */
-    format = &(g_array_index (selected_webcam->video_formats, CheeseVideoFormat, 0));
-    for (i = 1; i < selected_webcam->num_video_formats; i++)
-    {
+    resolution = g_strdup_printf ("%ix%i", priv->x_resolution, 
+                                  priv->y_resolution);
 
-      if (g_array_index (selected_webcam->video_formats, CheeseVideoFormat, i).width >  format->width)
+    /* Use the previously set resolution from gconf if it is set and the 
+     * camera supports it. */
+    if (priv->x_resolution != 0 && priv->y_resolution != 0)
+      format = g_hash_table_lookup (priv->supported_resolutions, resolution);
+      
+    if (!format)
+    {  
+      /* Select the highest resolution */
+      format = &(g_array_index (selected_webcam->video_formats, 
+                                CheeseVideoFormat, 0));
+      for (i = 1; i < selected_webcam->num_video_formats; i++)
       {
-        format = &(g_array_index (selected_webcam->video_formats, CheeseVideoFormat, i));
+        if (g_array_index (selected_webcam->video_formats, 
+                           CheeseVideoFormat, i).width >  format->width)
+        {
+          format = &(g_array_index (selected_webcam->video_formats, 
+                                    CheeseVideoFormat, i));
+        }
       }
     }
-
+      
+    priv->current_format = format;
+    g_free (resolution);
+    
+    find_highest_framerate (format, &framerate_numerator, 
+                            &framerate_denominator);
+    
     if (format == NULL)
       goto fallback;
 
-    /* Select the highest framerate up to 30 Hz*/
-    framerate_numerator = 1;
-    framerate_denominator = 1;
-    for (i = 0; i < format->num_framerates; i++)
-    {
-      float framerate = format->framerates[i].numerator / format->framerates[i].denominator;
-      if (framerate > ((float)framerate_numerator / framerate_denominator)
-          && framerate <= 30)
-      {
-        framerate_numerator = format->framerates[i].numerator;
-        framerate_denominator = format->framerates[i].denominator;        
-      }
-    }
-
-    webcam_input = g_strdup_printf ("%s name=video_source device=%s ! %s,width=%d,height=%d,framerate=%d/%d ! identity",
+    webcam_input = g_strdup_printf ("%s name=video_source device=%s ! capsfilter name=capsfilter caps=%s,width=%d,height=%d,framerate=%d/%d ! identity",
                                     selected_webcam->gstreamer_src,
                                     selected_webcam->video_device,
                                     format->mimetype,
@@ -625,11 +696,13 @@
                                                               TRUE, &err);
     g_free (webcam_input);
 
-    if ( priv->webcam_source_bin == NULL)
+    if (priv->webcam_source_bin == NULL)
       goto fallback;
   }
 
   priv->video_source = gst_bin_get_by_name (GST_BIN (priv->webcam_source_bin), "video_source");
+  priv->capsfilter = gst_bin_get_by_name (GST_BIN (priv->webcam_source_bin), 
+                                          "capsfilter");
   return TRUE;
 
 fallback:
@@ -647,6 +720,8 @@
     g_error_free (err);
     return FALSE;
   }
+  priv->capsfilter = gst_bin_get_by_name (GST_BIN (priv->webcam_source_bin), 
+                                          "capsfilter");
   return TRUE;
 }
 
@@ -749,7 +824,6 @@
   GstElement *mux;
   GstPad *pad;
   gboolean ok;
-  GstCaps *caps;
 
   priv->video_save_bin = gst_bin_new ("video_save_bin");
 
@@ -781,15 +855,8 @@
   ok = gst_element_link_many (priv->audio_source, audio_queue, audio_convert, 
                               audio_enc, mux, priv->video_file_sink, NULL);
 
-  /* Record videos always in 320x240 */
-  ok &= gst_element_link (video_save_csp ,video_save_scale);
-  caps = gst_caps_new_simple ("video/x-raw-yuv",
-                              "width", G_TYPE_INT, 320,
-                              "height", G_TYPE_INT, 240,
-                              NULL);
-  ok &= gst_element_link_filtered (video_save_scale, video_enc, caps);
-  gst_caps_unref (caps);
-
+  ok &= gst_element_link_many (video_save_csp, video_save_scale, video_enc,
+                               NULL);
   ok &= gst_element_link (video_enc, mux);
 
   if (!ok)
@@ -1004,6 +1071,8 @@
     g_array_free (priv->webcam_devices[i].video_formats, TRUE);
   }
   g_free (priv->webcam_devices);
+    
+  g_hash_table_destroy (priv->supported_resolutions);
 
   G_OBJECT_CLASS (cheese_webcam_parent_class)->finalize (object);
 }
@@ -1024,6 +1093,12 @@
     case PROP_DEVICE_NAME:
       g_value_set_string (value, priv->device_name);
       break;
+    case PROP_X_RESOLUTION:
+      g_value_set_int (value, priv->x_resolution);
+      break;
+    case PROP_Y_RESOLUTION:
+      g_value_set_int (value, priv->y_resolution);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1049,6 +1124,12 @@
       g_free (priv->device_name);
       priv->device_name = g_value_dup_string (value);
       break;
+    case PROP_X_RESOLUTION:
+      priv->x_resolution = g_value_get_int (value);
+      break;
+    case PROP_Y_RESOLUTION:
+      priv->y_resolution = g_value_get_int (value);
+      break; 
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1090,6 +1171,26 @@
                                                          NULL,
 							 "",
                                                          G_PARAM_READWRITE));
+    
+   g_object_class_install_property (object_class, PROP_X_RESOLUTION,
+                                   g_param_spec_int ("x-resolution",
+                                                     NULL,
+                                                     NULL,
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT_ONLY));
+    
+    g_object_class_install_property (object_class, PROP_Y_RESOLUTION,
+                                   g_param_spec_int ("y-resolution",
+                                                     NULL,
+                                                     NULL,
+                                                     0,
+                                                     G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT_ONLY));
 
 
   g_type_class_add_private (klass, sizeof (CheeseWebcamPrivate));
@@ -1105,6 +1206,33 @@
   priv->photo_filename = NULL;
   priv->webcam_devices = NULL;
   priv->device_name = NULL;
+    
+  priv->supported_resolutions = g_hash_table_new_full (g_str_hash, 
+                                                       g_str_equal,
+                                                       g_free, NULL);
+}
+
+CheeseWebcam*
+cheese_webcam_new (GtkWidget* video_window, char *webcam_device_name, 
+                   int x_resolution, int y_resolution)
+{
+  CheeseWebcam *webcam;
+    
+  if (webcam_device_name)
+  {
+    webcam = g_object_new (CHEESE_TYPE_WEBCAM, "video-window", video_window, 
+                           "device_name", webcam_device_name, 
+                           "x-resolution", x_resolution, 
+                           "y-resolution", y_resolution, NULL);
+  }
+  else
+  {
+    webcam = g_object_new (CHEESE_TYPE_WEBCAM, "video-window", video_window, 
+                           "x-resolution", x_resolution, 
+                           "y-resolution", y_resolution, NULL);
+  }
+	
+  return webcam;
 }
 
 void
@@ -1139,20 +1267,46 @@
   gdk_threads_leave();
 }
 
+GArray *
+cheese_webcam_get_video_formats (CheeseWebcam *webcam)
+{
+  CheeseWebcamPrivate *priv = CHEESE_WEBCAM_GET_PRIVATE (webcam); 
+    
+  return priv->webcam_devices[priv->selected_device].video_formats;
+}
+
+void
+cheese_webcam_set_video_format (CheeseWebcam *webcam, CheeseVideoFormat *format)
+{
+  CheeseWebcamPrivate *priv = CHEESE_WEBCAM_GET_PRIVATE (webcam);
+  GstCaps *new_caps;
+  int framerate_numerator;
+  int framerate_denominator;
+    
+  find_highest_framerate (format, &framerate_numerator, &framerate_denominator);
+    
+  new_caps = gst_caps_new_simple (format->mimetype,
+                                  "width", G_TYPE_INT, 
+                                  format->width,
+                                  "height", G_TYPE_INT, 
+                                  format->height,
+                                  "framerate", GST_TYPE_FRACTION, 
+                                  framerate_numerator,
+                                  framerate_denominator,
+                                  NULL);
+    
+  priv->current_format = format;
+    
+  cheese_webcam_stop (webcam);
+  g_object_set (priv->capsfilter, "caps", new_caps, NULL);
+  cheese_webcam_play (webcam);
+}
 
-CheeseWebcam*
-cheese_webcam_new (GtkWidget* video_window, char *webcam_device_name)
+CheeseVideoFormat *
+cheese_webcam_get_current_video_format (CheeseWebcam *webcam)
 {
-  CheeseWebcam *webcam;
-  if (webcam_device_name)
-  {
-    webcam = g_object_new (CHEESE_TYPE_WEBCAM, "video-window", video_window, 
-                           "device-name", webcam_device_name, NULL);
-  }
-  else
-  {
-    webcam = g_object_new (CHEESE_TYPE_WEBCAM, "video-window", video_window, NULL);
-  }
-  return webcam;
+  CheeseWebcamPrivate *priv = CHEESE_WEBCAM_GET_PRIVATE (webcam);
+    
+  return priv->current_format;
 }
 

Modified: trunk/src/cheese-webcam.h
==============================================================================
--- trunk/src/cheese-webcam.h	(original)
+++ trunk/src/cheese-webcam.h	Mon Apr 21 16:37:06 2008
@@ -35,6 +35,21 @@
 #define CHEESE_IS_WEBCAM_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), CHEESE_TYPE_WEBCAM))
 #define CHEESE_WEBCAM_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), CHEESE_TYPE_WEBCAM, CheeseWebcamClass))
 
+typedef struct 
+{
+  int numerator;
+  int denominator;
+} CheeseFramerate;
+
+typedef struct 
+{
+  char *mimetype;
+  int width;
+  int height;
+  int num_framerates;
+  CheeseFramerate *framerates; 
+} CheeseVideoFormat;
+
 typedef enum
 {
   CHEESE_WEBCAM_EFFECT_NO_EFFECT       = (0),
@@ -66,7 +81,10 @@
 
 
 GType		 cheese_webcam_get_type			(void);
-CheeseWebcam 	*cheese_webcam_new 			(GtkWidget *video_window, char *webcam_device_name);
+CheeseWebcam 	*cheese_webcam_new 			(GtkWidget *video_window, 
+                                       char *webcam_device_name, 
+                                       int x_resolution,
+                                       int y_resolution);
 void 		 cheese_webcam_setup 			(CheeseWebcam *webcam);
 void 		 cheese_webcam_play 			(CheeseWebcam *webcam);
 void 		 cheese_webcam_stop 			(CheeseWebcam *webcam);
@@ -76,6 +94,10 @@
 void 		 cheese_webcam_take_photo 		(CheeseWebcam *webcam, char *filename);
 gboolean	 cheese_webcam_has_webcam 		(CheeseWebcam *webcam);
 int            	 cheese_webcam_get_num_webcam_devices	(CheeseWebcam *webcam);
+GArray *cheese_webcam_get_video_formats (CheeseWebcam *webcam);
+void cheese_webcam_set_video_format (CheeseWebcam *webcam,
+                                     CheeseVideoFormat *format);
+CheeseVideoFormat *cheese_webcam_get_current_video_format (CheeseWebcam *webcam);
 G_END_DECLS
 
 #endif /* __CHEESE_WEBCAM_H__ */

Modified: trunk/src/cheese-window.c
==============================================================================
--- trunk/src/cheese-window.c	(original)
+++ trunk/src/cheese-window.c	Mon Apr 21 16:37:06 2008
@@ -49,6 +49,7 @@
 #include "gst-audio-play.h"
 #include "gedit-message-area.h"
 #include "cheese-no-camera.h"
+#include "cheese-prefs-dialog.h"
 
 #define SHUTTER_SOUNDS 5
 
@@ -58,7 +59,6 @@
   WEBCAM_MODE_VIDEO
 } WebcamMode;
 
-
 typedef struct 
 {
   gboolean recording;
@@ -114,6 +114,7 @@
   GtkActionGroup *actions_account_photo;
   GtkActionGroup *actions_countdown;
   GtkActionGroup *actions_effects;
+  GtkActionGroup *actions_preferences;
   GtkActionGroup *actions_file;
   GtkActionGroup *actions_flickr;
   GtkActionGroup *actions_fspot;
@@ -234,6 +235,9 @@
   g_object_unref (cheese_window->actions_mail);
   g_object_unref (cheese_window->actions_photo);
   g_object_unref (cheese_window->actions_toggle);
+  g_object_unref (cheese_window->actions_effects);
+  g_object_unref (cheese_window->actions_preferences);
+  g_object_unref (cheese_window->actions_file);
   g_object_unref (cheese_window->actions_video);
   g_object_unref (cheese_window->ui_manager);
   g_object_unref (cheese_window->gconf);
@@ -941,6 +945,13 @@
   }
 }
 
+static void 
+cheese_window_preferences_cb (GtkAction *action, CheeseWindow *cheese_window)
+{
+  cheese_prefs_dialog_run (cheese_window->window, cheese_window->gconf,
+                           cheese_window->webcam);
+}
+
 static const GtkActionEntry action_entries_main[] = {
   {"Cheese", NULL, N_("_Cheese")},
 
@@ -963,6 +974,10 @@
   {"Effects", NULL, N_("_Effects"), NULL, NULL, G_CALLBACK (cheese_window_effect_button_pressed_cb), FALSE},
 };
 
+static const GtkActionEntry action_entries_preferences[] = {
+  {"Preferences", GTK_STOCK_PREFERENCES, N_("Preferences"), NULL, NULL, G_CALLBACK (cheese_window_preferences_cb)},
+};
+
 static const GtkRadioActionEntry action_entries_toggle[] = {
   {"Photo", NULL, N_("_Photo"), NULL, NULL, 0},
   {"Video", NULL, N_("_Video"), NULL, NULL, 1},
@@ -1194,6 +1209,10 @@
                                                                           "ActionsEffects", 
                                                                           action_entries_effects, 
                                                                           G_N_ELEMENTS (action_entries_effects));
+  cheese_window->actions_preferences = cheese_window_action_group_new (cheese_window, 
+                                                                       "ActionsPreferences", 
+                                                                       action_entries_preferences, 
+                                                                       G_N_ELEMENTS (action_entries_preferences));
   cheese_window->actions_file = cheese_window_action_group_new (cheese_window, 
                                                                 "ActionsFile", 
                                                                 action_entries_file, 
@@ -1306,11 +1325,16 @@
 setup_camera (CheeseWindow *cheese_window)
 {
   char *webcam_device = NULL;
+  int x_resolution;
+  int y_resolution;
   GtkWidget *message_area;
+  
+  g_object_get (cheese_window->gconf, "gconf_prop_x_resolution", &x_resolution,
+                "gconf_prop_y_resolution", &y_resolution, NULL);
 
-  g_object_get (cheese_window->gconf, "gconf_prop_webcam", &webcam_device, NULL);
-
-  cheese_window->webcam = cheese_webcam_new (cheese_window->screen, webcam_device);
+  cheese_window->webcam = cheese_webcam_new (cheese_window->screen, 
+                                             webcam_device, x_resolution,
+                                             y_resolution);
   g_free (webcam_device);
 
   cheese_webcam_setup (cheese_window->webcam);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]