From 0741304538cc50b1003392ec9c3005df2e2c6ab4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?=
 <rafael.carre@savoirfairelinux.com>
Date: Thu, 30 Jun 2011 16:10:03 -0400
Subject: [PATCH] * #6226 : dynamically probe cameras using udev

---
 sflphone-client-gnome/src/config/videoconf.c  | 135 +++++++++---------
 sflphone-client-gnome/src/config/videoconf.h  |   2 +-
 .../dbus/configurationmanager-introspec.xml   |   3 +
 sflphone-client-gnome/src/dbus/dbus.c         |   5 +
 .../dbus/configurationmanager-introspec.xml   |   3 +
 sflphone-common/src/managerimpl.cpp           |   4 +
 sflphone-common/src/managerimpl.h             |   2 +
 sflphone-common/src/video/video_v4l2_list.cpp |   6 +-
 8 files changed, 93 insertions(+), 67 deletions(-)

diff --git a/sflphone-client-gnome/src/config/videoconf.c b/sflphone-client-gnome/src/config/videoconf.c
index 328588475a..9949f83212 100644
--- a/sflphone-client-gnome/src/config/videoconf.c
+++ b/sflphone-client-gnome/src/config/videoconf.c
@@ -50,6 +50,9 @@ static GtkListStore *v4l2ChannelList;
 static GtkListStore *v4l2SizeList;
 static GtkListStore *v4l2RateList;
 
+static GtkWidget *v4l2_hbox;
+static GtkWidget *v4l2_nodev;
+
 static GtkWidget *codecTreeView;		// View used instead of store to get access to selection
 static GtkWidget *codecMoveUpButton;
 static GtkWidget *codecMoveDownButton;
@@ -165,46 +168,6 @@ preview_button_clicked(GtkButton *button, gpointer data UNUSED)
     }
 }
 
-GtkWidget* create_video_configuration()
-{
-    // Main widget
-    GtkWidget *ret;
-    // Sub boxes
-    GtkWidget *frame;
-
-    ret = gtk_vbox_new (FALSE, 10);
-    gtk_container_set_border_width (GTK_CONTAINER (ret), 10);
-
-    GtkWidget *table;
-
-    gnome_main_section_new_with_table (_ ("Video Manager"), &frame, &table, 1, 5);
-    gtk_box_pack_start (GTK_BOX (ret), frame, FALSE, FALSE, 0);
-
-    gnome_main_section_new_with_table (_ ("Preview"), &frame, &table, 1, 2);
-    gtk_box_pack_start (GTK_BOX (ret), frame, FALSE, FALSE, 0);
-
-    preview_button = gtk_button_new_with_mnemonic(_("_Start preview"));
-    gtk_table_attach(GTK_TABLE(table), preview_button, 0, 1, 0, 1, 0, 0, 0, 6);
-    g_signal_connect(G_OBJECT(preview_button), "clicked", G_CALLBACK(preview_button_clicked), NULL);
-    gtk_widget_show(GTK_WIDGET(preview_button));
-
-    using_clutter = clutter_init(NULL, NULL) == CLUTTER_INIT_SUCCESS;
-    drawarea = using_clutter ? gtk_clutter_embed_new() : gtk_drawing_area_new();
-    gtk_widget_set_size_request (drawarea, drawWidth, drawHeight);
-    gtk_table_attach(GTK_TABLE(table), drawarea, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 6);
-    gtk_widget_show(GTK_WIDGET(drawarea));
-
-    gnome_main_section_new_with_table (_ ("Video4Linux2"), &frame, &table, 1, 4);
-    gtk_box_pack_start (GTK_BOX (ret), frame, FALSE, FALSE, 0);
-    GtkWidget *v4l2box = v4l2_box();
-    gtk_table_attach(GTK_TABLE(table), v4l2box, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 6);
-    gtk_widget_show(GTK_WIDGET(v4l2box));
-
-    gtk_widget_show_all (ret);
-
-    return ret;
-}
-
 /**
  * Fills the tree list with supported codecs
  */
@@ -713,19 +676,39 @@ select_video_input_device (GtkComboBox* comboBox, gpointer data UNUSED)
     }
 }
 
-GtkWidget* v4l2_box ()
+static void fill_devices(void)
+{
+    if (!preferences_dialog_fill_video_input_device_list()) {
+        gtk_widget_show_all(v4l2_hbox);
+        gtk_widget_hide(v4l2_nodev);
+    } else {
+        gtk_widget_hide_all(v4l2_hbox);
+        gtk_widget_show(v4l2_nodev);
+    }
+}
+
+void video_device_event_cb(DBusGProxy *proxy UNUSED, void * foo  UNUSED)
+{
+    fill_devices();
+}
+
+static GtkWidget* v4l2_box ()
 {
-    GtkWidget *ret;
     GtkWidget *item;
     GtkWidget *table;
     GtkCellRenderer *renderer;
 
-    ret = gtk_hbox_new (FALSE, 4);
+    GtkWidget *ret = gtk_vbox_new(FALSE, 0);
+
+    v4l2_nodev = gtk_label_new (_ ("No devices found"));
+    v4l2_hbox = gtk_hbox_new (FALSE, 4);
+
+    gtk_box_pack_start (GTK_BOX (ret) , v4l2_hbox , TRUE , TRUE , 0);
+    gtk_box_pack_start (GTK_BOX (ret) , v4l2_nodev, TRUE , TRUE , 0);
 
     table = gtk_table_new (6, 3, FALSE);
     gtk_table_set_col_spacing (GTK_TABLE (table), 0, 40);
-    gtk_box_pack_start (GTK_BOX (ret) , table , TRUE , TRUE , 1);
-    gtk_widget_show (table);
+    gtk_box_pack_start (GTK_BOX (v4l2_hbox) , table , TRUE , TRUE , 1);
 
     // Set choices of input devices
     item = gtk_label_new (_ ("Device"));
@@ -733,9 +716,6 @@ GtkWidget* v4l2_box ()
     v4l2Device = gtk_combo_box_new_with_model (GTK_TREE_MODEL (v4l2DeviceList));
     gtk_label_set_mnemonic_widget (GTK_LABEL (item), v4l2Device);
 
-    if (preferences_dialog_fill_video_input_device_list())
-        goto fail;
-
     g_signal_connect (G_OBJECT (v4l2Device), "changed", G_CALLBACK (select_video_input_device), v4l2Device);
     gtk_table_attach (GTK_TABLE (table), item, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
 
@@ -744,7 +724,6 @@ GtkWidget* v4l2_box ()
     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (v4l2Device), renderer, TRUE);
     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (v4l2Device), renderer, "text", 0, NULL);
     gtk_table_attach (GTK_TABLE (table), v4l2Device, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-    gtk_widget_show (v4l2Device);
 
 
     // Set choices of input
@@ -755,15 +734,11 @@ GtkWidget* v4l2_box ()
     g_signal_connect (G_OBJECT (v4l2Channel), "changed", G_CALLBACK (select_video_input_device_channel), v4l2Channel);
     gtk_table_attach (GTK_TABLE (table), item, 0, 1, 1, 2, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
 
-    preferences_dialog_fill_video_input_device_channel_list();
-
     // Set rendering
     renderer = gtk_cell_renderer_text_new();
     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (v4l2Channel), renderer, TRUE);
     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (v4l2Channel), renderer, "text", 0, NULL);
     gtk_table_attach (GTK_TABLE (table), v4l2Channel, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-    gtk_widget_show (v4l2Channel);
-
 
     // Set choices of sizes
     item = gtk_label_new (_ ("Size"));
@@ -773,15 +748,11 @@ GtkWidget* v4l2_box ()
     g_signal_connect (G_OBJECT (v4l2Size), "changed", G_CALLBACK (select_video_input_device_size), v4l2Size);
     gtk_table_attach (GTK_TABLE (table), item, 0, 1, 2, 3, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
 
-    preferences_dialog_fill_video_input_device_size_list();
-
     // Set rendering
     renderer = gtk_cell_renderer_text_new();
     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (v4l2Size), renderer, TRUE);
     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (v4l2Size), renderer, "text", 0, NULL);
     gtk_table_attach (GTK_TABLE (table), v4l2Size, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-    gtk_widget_show (v4l2Size);
-
 
     // Set choices of rates
     item = gtk_label_new (_ ("Rate"));
@@ -791,19 +762,55 @@ GtkWidget* v4l2_box ()
     g_signal_connect (G_OBJECT (v4l2Rate), "changed", G_CALLBACK (select_video_input_device_rate), v4l2Rate);
     gtk_table_attach (GTK_TABLE (table), item, 0, 1, 3, 4, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
 
-    preferences_dialog_fill_video_input_device_rate_list();
-
     // Set rendering
     renderer = gtk_cell_renderer_text_new();
     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (v4l2Rate), renderer, TRUE);
     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (v4l2Rate), renderer, "text", 0, NULL);
     gtk_table_attach (GTK_TABLE (table), v4l2Rate, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-    gtk_widget_show (v4l2Rate);
-
-    gtk_widget_show_all(ret);
 
     return ret;
+}
+
+GtkWidget* create_video_configuration()
+{
+    // Main widget
+    GtkWidget *ret;
+    // Sub boxes
+    GtkWidget *frame;
+
+    ret = gtk_vbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (ret), 10);
+
+    GtkWidget *table;
+
+    gnome_main_section_new_with_table (_ ("Video Manager"), &frame, &table, 1, 5);
+    gtk_box_pack_start (GTK_BOX (ret), frame, FALSE, FALSE, 0);
 
-fail:
-    return gtk_label_new (_ ("No devices found"));
+    gnome_main_section_new_with_table (_ ("Preview"), &frame, &table, 1, 2);
+    gtk_box_pack_start (GTK_BOX (ret), frame, FALSE, FALSE, 0);
+
+    preview_button = gtk_button_new_with_mnemonic(_("_Start preview"));
+    gtk_table_attach(GTK_TABLE(table), preview_button, 0, 1, 0, 1, 0, 0, 0, 6);
+    g_signal_connect(G_OBJECT(preview_button), "clicked", G_CALLBACK(preview_button_clicked), NULL);
+    gtk_widget_show(GTK_WIDGET(preview_button));
+
+    using_clutter = clutter_init(NULL, NULL) == CLUTTER_INIT_SUCCESS;
+    drawarea = using_clutter ? gtk_clutter_embed_new() : gtk_drawing_area_new();
+    gtk_widget_set_size_request (drawarea, drawWidth, drawHeight);
+    gtk_table_attach(GTK_TABLE(table), drawarea, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 6);
+    gtk_widget_show(GTK_WIDGET(drawarea));
+
+    gnome_main_section_new_with_table (_ ("Video4Linux2"), &frame, &table, 1, 4);
+    gtk_box_pack_start (GTK_BOX (ret), frame, FALSE, FALSE, 0);
+
+    GtkWidget *v4l2box = v4l2_box();
+    gtk_table_attach(GTK_TABLE(table), v4l2box, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 6);
+
+    gtk_widget_show_all (ret);
+
+    // get devices list from daemon *after* showing all widgets
+    // that way we can show either the list, either the "no devices found" label
+    fill_devices();
+
+    return ret;
 }
diff --git a/sflphone-client-gnome/src/config/videoconf.h b/sflphone-client-gnome/src/config/videoconf.h
index 0771229a27..9efdae1856 100644
--- a/sflphone-client-gnome/src/config/videoconf.h
+++ b/sflphone-client-gnome/src/config/videoconf.h
@@ -36,8 +36,8 @@
 
 GtkWidget* create_video_configuration();
 GtkWidget* videocodecs_box();
-GtkWidget* v4l2_box();
 void video_started_cb(DBusGProxy *proxy, gint OUT_shmId, gint OUT_semId, gint OUT_videoBufferSize, GError *error, gpointer userdata);
 void video_stopped_cb();
+void video_device_event_cb(DBusGProxy *proxy UNUSED, void * foo  UNUSED);
 
 #endif // __VIDEO_CONF_H__
diff --git a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml
index 2b85864c4a..a5f0c81b81 100755
--- a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml
+++ b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml
@@ -1076,5 +1076,8 @@
        <signal name="videoStopped" tp:name-for-bindings="videoStopped">
 	   </signal>
 
+	   <signal name="videoDeviceEvent" tp:name-for-bindings="videoDeviceEvent">
+	   </signal>  
+
    </interface>
 	   </node>
diff --git a/sflphone-client-gnome/src/dbus/dbus.c b/sflphone-client-gnome/src/dbus/dbus.c
index 959c365a4e..13d4c0641d 100644
--- a/sflphone-client-gnome/src/dbus/dbus.c
+++ b/sflphone-client-gnome/src/dbus/dbus.c
@@ -905,6 +905,11 @@ dbus_connect (GError **error)
     dbus_g_proxy_connect_signal (configurationManagerProxy, "errorAlert",
                                  G_CALLBACK (error_alert), NULL, NULL);
 
+    /* Video related signals */
+    dbus_g_proxy_add_signal (configurationManagerProxy, "videoDeviceEvent", G_TYPE_INVALID);
+    dbus_g_proxy_connect_signal(configurationManagerProxy, "videoDeviceEvent",
+                                G_CALLBACK (video_device_event_cb), NULL, NULL);
+
     /* Defines a default timeout for the proxies */
 #if HAVE_DBUS_G_PROXY_SET_DEFAULT_TIMEOUT
     dbus_g_proxy_set_default_timeout (callManagerProxy, DEFAULT_DBUS_TIMEOUT);
diff --git a/sflphone-common/src/dbus/configurationmanager-introspec.xml b/sflphone-common/src/dbus/configurationmanager-introspec.xml
index 2b85864c4a..1ba990854b 100755
--- a/sflphone-common/src/dbus/configurationmanager-introspec.xml
+++ b/sflphone-common/src/dbus/configurationmanager-introspec.xml
@@ -1076,5 +1076,8 @@
        <signal name="videoStopped" tp:name-for-bindings="videoStopped">
 	   </signal>
 
+       <signal name="videoDeviceEvent" tp:name-for-bindings="videoDeviceEvent">
+       </signal>
+
    </interface>
 	   </node>
diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp
index 0d82d324eb..3cbfea491f 100644
--- a/sflphone-common/src/managerimpl.cpp
+++ b/sflphone-common/src/managerimpl.cpp
@@ -4790,3 +4790,7 @@ std::vector<std::string> ManagerImpl::getParticipantList (
 }
 
 
+void ManagerImpl::notifyVideoDeviceEvent()
+{
+	_dbus->getConfigurationManager()->videoDeviceEvent();
+}
diff --git a/sflphone-common/src/managerimpl.h b/sflphone-common/src/managerimpl.h
index 8eb7d229a8..a54b5e6bee 100644
--- a/sflphone-common/src/managerimpl.h
+++ b/sflphone-common/src/managerimpl.h
@@ -1549,6 +1549,8 @@ class ManagerImpl
         // Map containing conference pointers
         ConferenceMap _conferencemap;
 
+        void notifyVideoDeviceEvent();
+
     private:
         // Copy Constructor
         ManagerImpl (const ManagerImpl& rh);
diff --git a/sflphone-common/src/video/video_v4l2_list.cpp b/sflphone-common/src/video/video_v4l2_list.cpp
index a087bd0167..2cb2a7e5e4 100644
--- a/sflphone-common/src/video/video_v4l2_list.cpp
+++ b/sflphone-common/src/video/video_v4l2_list.cpp
@@ -56,6 +56,8 @@ extern "C" {
 
 #include "video_v4l2_list.h"
 
+#include "manager.h"
+
 namespace sfl_video {
 
 static int is_v4l2(struct udev_device *dev)
@@ -226,7 +228,7 @@ void VideoV4l2List::run()
 				_debug("udev: adding %s", node);
                 try {
                     addDevice(node);
-    				//FIXME : notify preferences change
+    				Manager::instance().notifyVideoDeviceEvent();
                 } catch (const std::runtime_error &e) {
                     _error(e.what());
                 }
@@ -265,7 +267,7 @@ void VideoV4l2List::delDevice(const std::string &node)
     for (i = 0 ; i < n ; i++) {
         if (devices[i].device == node) {
         	devices.erase(devices.begin() + i);
-			//FIXME : notify preferences change
+			Manager::instance().notifyVideoDeviceEvent();
         	return;
         }
     }
-- 
GitLab