Commit 884e34e9 authored by Patricia Santana Cruz's avatar Patricia Santana Cruz Committed by David King

Add hotplug support to preferences dialog

Adding and removing camera devices in the CheeseCamera is now propagated
to the preferences dialog UI. Partially fixes bug 603612.
parent 680d3f68
......@@ -101,7 +101,7 @@ struct _CheeseCameraPrivate
gboolean pipeline_is_playing;
gchar *photo_filename;
gint num_camera_devices;
guint num_camera_devices;
gchar *device_name;
/* an array of CheeseCameraDevices */
......@@ -122,6 +122,8 @@ enum
PROP_VIDEO_TEXTURE,
PROP_DEVICE_NAME,
PROP_FORMAT,
PROP_NUM_CAMERA_DEVICES,
PROP_LAST
};
enum
......@@ -134,6 +136,7 @@ enum
};
static guint camera_signals[LAST_SIGNAL];
static GParamSpec *properties[PROP_LAST];
GST_DEBUG_CATEGORY (cheese_camera_cat);
#define GST_CAT_DEFAULT cheese_camera_cat
......@@ -275,6 +278,8 @@ cheese_camera_add_device (CheeseCameraDeviceMonitor *monitor,
g_ptr_array_add (priv->camera_devices, device);
priv->num_camera_devices++;
g_object_notify_by_pspec (G_OBJECT (camera), properties[PROP_NUM_CAMERA_DEVICES]);
}
/*
......@@ -305,6 +310,7 @@ cheese_camera_remove_device (CheeseCameraDeviceMonitor *monitor,
{
g_ptr_array_remove (priv->camera_devices, (gpointer) indexDevice);
priv->num_camera_devices--;
g_object_notify_by_pspec (G_OBJECT (camera), properties[PROP_NUM_CAMERA_DEVICES]);
break;
}
}
......@@ -1097,6 +1103,9 @@ cheese_camera_get_property (GObject *object, guint prop_id, GValue *value,
case PROP_FORMAT:
g_value_set_boxed (value, priv->current_format);
break;
case PROP_NUM_CAMERA_DEVICES:
g_value_set_uint (value, priv->num_camera_devices);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -1218,7 +1227,7 @@ cheese_camera_class_init (CheeseCameraClass *klass)
g_object_class_install_property (object_class, PROP_DEVICE_NAME,
g_param_spec_string ("device-name",
"Device name",
"The path to the device node for the video capture device.",
"The path to the device node for the video capture device",
"",
G_PARAM_READWRITE));
......@@ -1234,6 +1243,22 @@ cheese_camera_class_init (CheeseCameraClass *klass)
CHEESE_TYPE_VIDEO_FORMAT,
G_PARAM_READWRITE));
/**
* CheeseCamera:num-camera-devices:
*
* The currently number of camera devices available for being used.
*/
properties[PROP_NUM_CAMERA_DEVICES] = g_param_spec_uint ("num-camera-devices",
"Number of camera devices",
"The currently number of camera devices available on the system",
0,
G_MAXUINT8,
0,
G_PARAM_READABLE);
g_object_class_install_property (object_class, PROP_NUM_CAMERA_DEVICES, properties[PROP_NUM_CAMERA_DEVICES]);
g_type_class_add_private (klass, sizeof (CheeseCameraPrivate));
}
......
......@@ -33,6 +33,8 @@ public class Cheese.PreferencesDialog : GLib.Object
private Gtk.ComboBox video_resolution_combo;
private Gtk.ComboBox source_combo;
private Gtk.ListStore camera_model;
private Gtk.Adjustment brightness_adjustment;
private Gtk.Adjustment contrast_adjustment;
private Gtk.Adjustment hue_adjustment;
......@@ -54,6 +56,7 @@ public class Cheese.PreferencesDialog : GLib.Object
public PreferencesDialog (Cheese.Camera camera, GLib.Settings settings)
{
this.camera = camera;
this.settings = settings;
Gtk.Builder builder = new Gtk.Builder ();
......@@ -104,6 +107,7 @@ public class Cheese.PreferencesDialog : GLib.Object
* Stops a bunch of unnecessary signals from being fired
*/
builder.connect_signals (this);
camera.notify["num-camera-devices"].connect(this.on_camera_update_num_camera_devices);
}
private void setup_combo_box_models ()
......@@ -122,27 +126,14 @@ public class Cheese.PreferencesDialog : GLib.Object
private void initialize_camera_devices ()
{
Cheese.CameraDevice dev;
unowned GLib.PtrArray devices = camera.get_camera_devices ();
ListStore camera_model = new ListStore (2, typeof (string), typeof (Cheese.CameraDevice));
unowned GLib.PtrArray devices = camera.get_camera_devices ();
camera_model = new ListStore (2, typeof (string), typeof (Cheese.CameraDevice));
source_combo.model = camera_model;
if (devices.len <= 1)
source_combo.sensitive = false;
for (int i = 0; i < devices.len; i++)
{
TreeIter iter;
dev = (Cheese.CameraDevice) devices.index (i);
camera_model.append (out iter);
camera_model.set (iter,
0, dev.get_name () + " (" + dev.get_device_file () + " )",
1, dev);
if (camera.get_selected_device ().get_device_file () == dev.get_device_file ())
{
source_combo.set_active_iter (iter);
}
}
devices.foreach(add_camera_device);
settings.set_string ("camera", camera.get_selected_device ().get_device_file ());
setup_resolutions_for_device (camera.get_selected_device ());
......@@ -209,8 +200,10 @@ public class Cheese.PreferencesDialog : GLib.Object
[CCode (instance_pos = -1)]
public void on_source_change (Gtk.ComboBox combo)
{
TreeIter iter;
// TODO: Handle going from 1 to 0 devices, cleanly!
return_if_fail (camera.num_camera_devices > 0);
TreeIter iter;
Cheese.CameraDevice dev;
combo.get_active_iter (out iter);
......@@ -333,6 +326,105 @@ public class Cheese.PreferencesDialog : GLib.Object
settings.set_double ("saturation", adjustment.value);
}
// A camera device was added/removed.
public void on_camera_update_num_camera_devices ()
{
unowned GLib.PtrArray devices = camera.get_camera_devices ();
Cheese.CameraDevice dev;
// Add (if) / Remove (else) a camera device.
if (devices.len > camera_model.iter_n_children (null))
{
dev = (Cheese.CameraDevice) devices.index (devices.len - 1);
add_camera_device(dev);
}
else
{
// First camera device in the combobox.
TreeIter iter;
camera_model.get_iter_first (out iter);
// Combobox active element.
TreeIter active_iter;
Cheese.CameraDevice active_device;
source_combo.get_active_iter (out active_iter);
camera_model.get (active_iter, 1, out active_device, -1);
// Find which device was removed.
bool device_removed = false;
devices.foreach ((device) =>
{
var old_device = (Cheese.CameraDevice) device;
Cheese.CameraDevice new_device;
camera_model.get (iter, 1, out new_device, -1);
// Found the device that was removed.
if (strcmp (old_device.device_file, new_device.device_file) != 0)
{
remove_camera_device (iter, new_device, active_device);
device_removed = true;
// Remember, this is from the anonymous function!
return;
}
camera_model.iter_next (ref iter);
});
// Special case: the last device on the list was removed.
if (!device_removed)
{
Cheese.CameraDevice old_device;
camera_model.get (iter, 1, out old_device, -1);
remove_camera_device (iter, old_device, active_device);
}
}
settings.set_string ("camera", camera.get_selected_device ().get_device_file ());
setup_resolutions_for_device (camera.get_selected_device ());
}
private void add_camera_device (void *device)
{
TreeIter iter;
Cheese.CameraDevice dev = (Cheese.CameraDevice) device;
camera_model.append (out iter);
camera_model.set (iter,
0, dev.get_name () + " (" + dev.get_device_file () + ")",
1, dev);
if (camera.get_selected_device ().get_device_file () == dev.get_device_file ())
source_combo.set_active_iter (iter);
}
private void remove_camera_device (TreeIter iter, Cheese.CameraDevice device_node,
Cheese.CameraDevice active_device_node)
{
unowned GLib.PtrArray devices = camera.get_camera_devices ();
// Check if the camera that we want to remove, is the active one
if (strcmp (device_node.device_file, active_device_node.device_file) == 0)
{
if (devices.len > 0)
set_new_available_camera_device (iter);
else
this.dialog.hide();
}
camera_model.remove (iter);
}
// Look for an available device and activate it.
private void set_new_available_camera_device (TreeIter iter)
{
TreeIter new_iter = iter;
if (!camera_model.iter_next (ref new_iter))
{
new_iter = iter;
camera_model.iter_previous (ref new_iter);
}
source_combo.set_active_iter (new_iter);
}
public void show ()
{
this.dialog.show_all ();
......
......@@ -56,6 +56,8 @@ namespace Cheese
public Cheese.VideoFormat format {owned get; set;}
[NoAccessorMethod]
public void *video_texture {get; set;}
[NoAccessorMethod]
public uint num_camera_devices {get;}
public virtual signal void photo_saved ();
public virtual signal void photo_taken (Gdk.Pixbuf pixbuf);
public virtual signal void video_saved ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment