show context menu even when there is no video

This fixes the bug that resulted in the context menu (right click)
not showing during a call if there was no outgoing video.

This also fixes a memory leak which happened because a new menu
was being built each time, but the old one was never destroyed.

Change-Id: Ie72fbae05703c708dc91d0ec968aa57c5b8a509f
Tuleap: #1080
diff --git a/src/video/video_widget.cpp b/src/video/video_widget.cpp
index 1f7b62a..406e270 100644
--- a/src/video/video_widget.cpp
+++ b/src/video/video_widget.cpp
@@ -80,6 +80,8 @@
      */
     guint                    renderer_timeout_source;
     GAsyncQueue             *new_renderer_queue;
+
+    GtkWidget               *popup_menu;
 };
 
 struct _VideoWidgetRenderer {
@@ -152,6 +154,8 @@
         priv->new_renderer_queue = NULL;
     }
 
+    gtk_widget_destroy(priv->popup_menu);
+
     G_OBJECT_CLASS(video_widget_parent_class)->dispose(object);
 }
 
@@ -364,6 +368,8 @@
     /* drag & drop files as video sources */
     gtk_drag_dest_set(GTK_WIDGET(self), GTK_DEST_DEFAULT_ALL, NULL, 0, (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_PRIVATE));
     gtk_drag_dest_add_uri_targets(GTK_WIDGET(self));
+
+    priv->popup_menu = gtk_menu_new();
 }
 
 /*
@@ -476,23 +482,25 @@
  * Handle button event in the video screen.
  */
 gboolean
-video_widget_on_button_press_in_screen_event(GtkWidget *parent,  GdkEventButton *event, Call* call)
+video_widget_on_button_press_in_screen_event(VideoWidget *self,  GdkEventButton *event, Call* call)
 {
     /* check for right click */
     if (event->button != BUTTON_RIGHT_CLICK || event->type != GDK_BUTTON_PRESS)
         return FALSE;
 
-    /* create menu with available video sources */
-    GtkWidget *menu = gtk_menu_new();
+    /* update menu with available video sources */
+    auto priv = VIDEO_WIDGET_GET_PRIVATE(self);
+    auto menu = priv->popup_menu;
+
+    gtk_container_forall(GTK_CONTAINER(menu), (GtkCallback)gtk_widget_destroy, nullptr);
 
     Video::SourceModel *sourcemodel = nullptr;
-    if (auto out_media = call->firstMedia<Media::Video>(Media::Media::Direction::OUT))
+    int active = -1;
+    if (auto out_media = call->firstMedia<Media::Video>(Media::Media::Direction::OUT)) {
         sourcemodel = out_media->sourceModel();
-
-    if(!sourcemodel)
-        return FALSE;
-
-    auto active = sourcemodel->activeIndex();
+        active = sourcemodel->activeIndex();
+    }
+    /* if sourcemodel is null then we have no outgoing video */
 
     /* list available devices and check off the active device */
     auto device_list = Video::DeviceModel::instance().devices();
@@ -500,10 +508,14 @@
     for( auto device: device_list) {
         GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(device->name().toLocal8Bit().constData());
         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-        auto device_idx = sourcemodel->getDeviceIndex(device);
-        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), device_idx == active);
-        g_object_set_data(G_OBJECT(item), JOIN_CALL_KEY,call);
-        g_signal_connect(item, "activate", G_CALLBACK(switch_video_input), device);
+        if (sourcemodel) {
+            auto device_idx = sourcemodel->getDeviceIndex(device);
+            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), device_idx == active);
+            g_object_set_data(G_OBJECT(item), JOIN_CALL_KEY,call);
+            g_signal_connect(item, "activate", G_CALLBACK(switch_video_input), device);
+        } else {
+            gtk_widget_set_sensitive(item, FALSE);
+        }
     }
 
     /* add separator */
@@ -512,15 +524,23 @@
     /* add screen area as an input */
     GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(_("Share screen area"));
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), Video::SourceModel::ExtendedDeviceList::SCREEN == active);
-    g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_screen), call);
+    if (sourcemodel) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), Video::SourceModel::ExtendedDeviceList::SCREEN == active);
+        g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_screen), call);
+    } else {
+        gtk_widget_set_sensitive(item, FALSE);
+    }
 
     /* add file as an input */
     item = gtk_check_menu_item_new_with_mnemonic(_("Share file"));
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), Video::SourceModel::ExtendedDeviceList::FILE == active);
-    g_object_set_data(G_OBJECT(item), JOIN_CALL_KEY, call);
-    g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_file), parent);
+    if (sourcemodel) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), Video::SourceModel::ExtendedDeviceList::FILE == active);
+        g_object_set_data(G_OBJECT(item), JOIN_CALL_KEY, call);
+        g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_file), self);
+    } else {
+        gtk_widget_set_sensitive(item, FALSE);
+    }
 
     /* add separator */
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
diff --git a/src/video/video_widget.h b/src/video/video_widget.h
index a100d2f..1847f6b 100644
--- a/src/video/video_widget.h
+++ b/src/video/video_widget.h
@@ -55,7 +55,7 @@
                                                     guint info,
                                                     guint32 time,
                                                     Call* call);
-gboolean        video_widget_on_button_press_in_screen_event (GtkWidget *parent,
+gboolean        video_widget_on_button_press_in_screen_event (VideoWidget *self,
                                                               GdkEventButton *event,
                                                               Call* call);
 void            video_widget_take_snapshot (VideoWidget *self);