<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Apr 16, 2014 at 6:59 PM, Christophe Fergeau <span dir="ltr"><<a href="mailto:cfergeau@redhat.com" target="_blank">cfergeau@redhat.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This class is used to implement the so-called oVirt 'foreign menu'<br>
which is a menu populated with ISO images available on the<br>
oVirt instance that the user can dynamically insert into the<br>
virtual machine he is currently viewing.<br>
---<br>
 <a href="http://configure.ac" target="_blank">configure.ac</a>             |   1 +<br>
 src/Makefile.am          |   4 +<br>
 src/ovirt-foreign-menu.c | 580 +++++++++++++++++++++++++++++++++++++++++++++++<br>
 src/ovirt-foreign-menu.h |  82 +++++++<br>
 4 files changed, 667 insertions(+)<br>
 create mode 100644 src/ovirt-foreign-menu.c<br>
 create mode 100644 src/ovirt-foreign-menu.h<br>
<br>
diff --git a/<a href="http://configure.ac" target="_blank">configure.ac</a> b/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
index f966688..4e0d7b3 100644<br>
--- a/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
+++ b/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
@@ -200,6 +200,7 @@ AS_IF([test "x$have_ovirt" = "xyes"],<br>
              [AC_MSG_ERROR([oVirt support requested but libgovirt not found])<br>
       ])<br>
 ])<br>
+AM_CONDITIONAL([HAVE_OVIRT], [test "x$have_ovirt" = "xyes"])<br>
<br>
 dnl Decide if this platform can support the SSH tunnel feature.<br>
 AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h])<br>
diff --git a/src/Makefile.am b/src/Makefile.am<br>
index b3a9637..ee8f885 100644<br>
--- a/src/Makefile.am<br>
+++ b/src/Makefile.am<br>
@@ -67,6 +67,10 @@ COMMON_SOURCES +=                                            \<br>
        $(NULL)<br>
 endif<br>
<br>
+if HAVE_OVIRT<br>
+COMMON_SOURCES +=                                      \<br>
+       ovirt-foreign-menu.h ovirt-foreign-menu.c<br>
+endif<br>
<br>
 if HAVE_LIBVIRT<br>
 bin_PROGRAMS += virt-viewer<br>
diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c<br>
new file mode 100644<br>
index 0000000..642c0ef<br>
--- /dev/null<br>
+++ b/src/ovirt-foreign-menu.c<br>
@@ -0,0 +1,580 @@<br>
+/*<br>
+ * Virt Viewer: A virtual machine console viewer<br>
+ *<br>
+ * Copyright (C) 2007-2013 Red Hat, Inc.<br>
+ * Copyright (C) 2009-2012 Daniel P. Berrange<br>
+ * Copyright (C) 2010 Marc-André Lureau<br>
+ *<br>
+ * This program is free software; you can redistribute it and/or modify<br>
+ * it under the terms of the GNU General Public License as published by<br>
+ * the Free Software Foundation; either version 2 of the License, or<br>
+ * (at your option) any later version.<br>
+ *<br>
+ * This program is distributed in the hope that it will be useful,<br>
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
+ * GNU General Public License for more details.<br>
+ *<br>
+ * You should have received a copy of the GNU General Public License<br>
+ * along with this program; if not, write to the Free Software<br>
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA<br>
+ *<br>
+ * Author: Daniel P. Berrange <<a href="mailto:berrange@redhat.com">berrange@redhat.com</a>><br>
+ *         Christope Fergeau <<a href="mailto:cfergeau@redhat.com">cfergeau@redhat.com</a>><br>
+ */<br>
+<br>
+#include <config.h><br>
+<br>
+#include "ovirt-foreign-menu.h"<br>
+#include "virt-glib-compat.h"<br>
+<br>
+#if !GLIB_CHECK_VERSION(2, 26, 0)<br>
+#include "gbinding.h"<br>
+#include "gbinding.c"<br>
+#endif<br>
+<br>
+typedef enum {<br>
+    STATE_0,<br>
+    STATE_STORAGE_DOMAIN,<br>
+    STATE_VM_CDROM,<br>
+    STATE_ISOS<br>
+} OvirtForeignMenuState;<br>
+<br>
+static void ovirt_foreign_menu_next_async_step(OvirtForeignMenu *menu, OvirtForeignMenuState state);<br>
+static void ovirt_foreign_menu_fetch_storage_domain_async(OvirtForeignMenu *menu);<br>
+static void ovirt_foreign_menu_fetch_vm_cdrom_async(OvirtForeignMenu *menu);<br>
+static gboolean ovirt_foreign_menu_refresh_iso_list(gpointer user_data);<br>
+<br>
+G_DEFINE_TYPE (OvirtForeignMenu, ovirt_foreign_menu, G_TYPE_OBJECT)<br>
+<br>
+<br>
+struct _OvirtForeignMenuPrivate {<br>
+    OvirtProxy *proxy;<br>
+    OvirtApi *api;<br>
+    OvirtVm *vm;<br>
+<br>
+    OvirtCollection *files;<br>
+    OvirtCdrom *cdrom;<br>
+<br>
+    GList *iso_names;<br>
+};<br>
+<br>
+<br>
+#define OVIRT_FOREIGN_MENU_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenuPrivate))<br>
+<br>
+<br>
+enum {<br>
+    PROP_0,<br>
+    PROP_PROXY,<br>
+    PROP_API,<br>
+    PROP_VM,<br>
+    PROP_FILES,<br>
+};<br>
+<br>
+static void<br>
+ovirt_foreign_menu_get_property(GObject *object, guint property_id,<br>
+                                       GValue *value, GParamSpec *pspec)<br>
+{<br>
+    OvirtForeignMenu *self = OVIRT_FOREIGN_MENU(object);<br>
+    OvirtForeignMenuPrivate *priv = self->priv;<br>
+<br>
+    switch (property_id) {<br>
+    case PROP_PROXY:<br>
+        g_value_set_object(value, priv->proxy);<br>
+        break;<br>
+    case PROP_API:<br>
+        g_value_set_object(value, priv->api);<br>
+        break;<br>
+    case PROP_VM:<br>
+        g_value_set_object(value, priv->vm);<br>
+        break;<br>
+    case PROP_FILES:<br>
+        g_value_set_pointer(value, priv->iso_names);<br>
+<br>
+    default:<br>
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);<br>
+    }<br>
+}<br>
+<br>
+<br>
+static void<br>
+ovirt_foreign_menu_set_property(GObject *object, guint property_id,<br>
+                                       const GValue *value G_GNUC_UNUSED, GParamSpec *pspec)<br>
+{<br>
+    OvirtForeignMenu *self = OVIRT_FOREIGN_MENU(object);<br>
+    OvirtForeignMenuPrivate *priv = self->priv;<br>
+<br>
+    switch (property_id) {<br>
+    case PROP_PROXY:<br>
+        if (priv->proxy != NULL) {<br>
+            g_object_unref(priv->proxy);<br>
+        }<br></blockquote><div><br></div><div>newly written code can really benefit g_clear_object() / g_clear_pointer() - true for all the remaining if { unref ; foo = NULL } all over.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+        priv->proxy = g_value_dup_object(value);<br>
+        break;<br>
+    case PROP_API:<br>
+        if (priv->api != NULL) {<br>
+            g_object_unref(priv->api);<br>
+        }<br>
+        priv->api = g_value_dup_object(value);<br>
+        break;<br>
+    case PROP_VM:<br>
+        if (priv->vm != NULL) {<br>
+            g_object_unref(priv->vm);<br>
+        }<br>
+        priv->vm = g_value_dup_object(value);<br>
+        break;<br>
+    default:<br>
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);<br>
+    }<br>
+}<br>
+<br>
+<br>
+static void<br>
+ovirt_foreign_menu_dispose(GObject *obj)<br>
+{<br>
+    OvirtForeignMenu *self = OVIRT_FOREIGN_MENU(obj);<br>
+<br>
+    g_debug("Disposing of foreign menu");<br>
+    if (self->priv->proxy) {<br>
+        g_object_unref(self->priv->proxy);<br>
+        self->priv->proxy = NULL;<br>
+    }<br>
+<br>
+    if (self->priv->api != NULL) {<br>
+        g_object_unref(self->priv->api);<br>
+        self->priv->api = NULL;<br>
+    }<br>
+<br>
+    if (self->priv->vm) {<br>
+        g_object_unref(self->priv->vm);<br>
+        self->priv->vm = NULL;<br>
+    }<br>
+<br>
+    if (self->priv->files) {<br>
+        g_object_unref(self->priv->files);<br>
+        self->priv->files = NULL;<br>
+    }<br>
+<br>
+    if (self->priv->cdrom) {<br>
+        g_object_unref(self->priv->cdrom);<br>
+        self->priv->cdrom = NULL;<br>
+    }<br>
+<br>
+    if (self->priv->iso_names) {<br>
+        g_list_free_full(self->priv->iso_names, (GDestroyNotify)g_free);<br>
+        self->priv->iso_names = NULL;<br>
+    }<br>
+<br>
+    G_OBJECT_CLASS(ovirt_foreign_menu_parent_class)->dispose(obj);<br>
+}<br>
+<br>
+<br>
+static void<br>
+ovirt_foreign_menu_class_init(OvirtForeignMenuClass *klass)<br>
+{<br>
+    GObjectClass *oclass = G_OBJECT_CLASS(klass);<br>
+<br>
+    oclass->get_property = ovirt_foreign_menu_get_property;<br>
+    oclass->set_property = ovirt_foreign_menu_set_property;<br>
+    oclass->dispose = ovirt_foreign_menu_dispose;<br>
+<br>
+    g_type_class_add_private(klass, sizeof(OvirtForeignMenuPrivate));<br>
+<br>
+    g_object_class_install_property(oclass,<br>
+                                    PROP_PROXY,<br>
+                                    g_param_spec_object("proxy",<br>
+                                                        "OvirtProxy instance",<br>
+                                                        "OvirtProxy instance",<br>
+                                                        OVIRT_TYPE_PROXY,<br>
+                                                        G_PARAM_READWRITE |<br>
+                                                        G_PARAM_CONSTRUCT_ONLY |<br>
+                                                        G_PARAM_STATIC_STRINGS));<br>
+    g_object_class_install_property(oclass,<br>
+                                    PROP_API,<br>
+                                    g_param_spec_object("api",<br>
+                                                        "OvirtApi instance",<br>
+                                                        "Ovirt api root",<br>
+                                                        OVIRT_TYPE_API,<br>
+                                                        G_PARAM_READWRITE |<br>
+                                                        G_PARAM_STATIC_STRINGS));<br>
+    g_object_class_install_property(oclass,<br>
+                                    PROP_VM,<br>
+                                    g_param_spec_object("vm",<br>
+                                                        "OvirtVm instance",<br>
+                                                        "OvirtVm being handled",<br>
+                                                        OVIRT_TYPE_VM,<br>
+                                                        G_PARAM_READWRITE |<br>
+                                                        G_PARAM_STATIC_STRINGS));<br>
+    g_object_class_install_property(oclass,<br>
+                                    PROP_FILES,<br>
+                                    g_param_spec_pointer("files",<br>
+                                                         "ISO names",<br>
+                                                         "GSList of ISO names for this oVirt VM",<br>
+                                                         G_PARAM_READABLE |<br>
+                                                         G_PARAM_STATIC_STRINGS));<br>
+}<br>
+<br>
+<br>
+static void<br>
+ovirt_foreign_menu_init(OvirtForeignMenu *self)<br>
+{<br>
+    self->priv = OVIRT_FOREIGN_MENU_GET_PRIVATE(self);<br>
+}<br>
+<br>
+<br>
+OvirtForeignMenu* ovirt_foreign_menu_new(OvirtProxy *proxy)<br>
+{<br>
+    return g_object_new(OVIRT_TYPE_FOREIGN_MENU,<br>
+                        "proxy", proxy,<br>
+                        NULL);<br>
+}<br>
+<br>
+<br>
+static void<br>
+ovirt_foreign_menu_next_async_step(OvirtForeignMenu *menu,<br>
+                                   OvirtForeignMenuState current_state)<br>
+{<br>
+    current_state++;<br></blockquote><div><br></div><div>I would add a few g_return_if_fail() check about current_state values.<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+<br>
+    if (current_state == STATE_STORAGE_DOMAIN) {<br>
+        if (menu->priv->files == NULL) {<br>
+            ovirt_foreign_menu_fetch_storage_domain_async(menu);<br>
+        } else {<br>
+            current_state++;<br>
+        }<br>
+    }<br>
+<br>
+    if (current_state == STATE_VM_CDROM) {<br>
+        if (menu->priv->cdrom == NULL) {<br>
+            ovirt_foreign_menu_fetch_vm_cdrom_async(menu);<br>
+        } else {<br>
+            current_state++;<br>
+        }<br>
+    }<br>
+<br>
+    if (current_state == STATE_ISOS) {<br>
+        g_warn_if_fail(menu->priv->api != NULL);<br>
+        g_warn_if_fail(menu->priv->vm != NULL);<br>
+        g_warn_if_fail(menu->priv->files != NULL);<br>
+        g_warn_if_fail(menu->priv->cdrom != NULL);<br>
+<br>
+        ovirt_foreign_menu_refresh_iso_list(menu);<br>
+    }<br>
+}<br>
+<br>
+<br>
+void<br>
+ovirt_foreign_menu_start(OvirtForeignMenu *menu)<br>
+{<br>
+    ovirt_foreign_menu_next_async_step(menu, STATE_0);<br></blockquote><div><br></div><div>Why not calling all the async simultaneously? If they need to be chained, isn't it simpler to do it through the normal code flow?<br>
 <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+}<br>
+<br>
+<br>
+static void updated_cdrom_cb(GObject *source_object,<br>
+                            GAsyncResult *result,<br>
+                            G_GNUC_UNUSED gpointer user_data)<br>
+{<br>
+    GError *error = NULL;<br>
+    ovirt_cdrom_update_finish(OVIRT_CDROM(source_object),<br>
+                              result, &error);<br>
+    g_debug("Finished updating cdrom content");<br>
+    if (error != NULL) {<br>
+        g_debug("Failed to update cdrom resource: %s", error->message);<br></blockquote><div><br>doesn't this deserve a warning? (same for similar errors)<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+        g_clear_error(&error);<br>
+    }<br>
+}<br>
+<br>
+<br>
+static void<br>
+ovirt_foreign_menu_activate_item_cb(GtkMenuItem *menuitem, gpointer user_data)<br>
+{<br>
+    GList *children;<br>
+    GList *it;<br>
+    GtkWidget *menu;<br>
+    OvirtForeignMenu *foreign_menu;<br>
+<br>
+    foreign_menu = OVIRT_FOREIGN_MENU(user_data);<br>
+    if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) {<br>
+        return;<br>
+    }<br>
+<br>
+    menu = gtk_widget_get_parent(GTK_WIDGET(menuitem));<br>
+    g_debug("'%s' clicked", gtk_menu_item_get_label(menuitem));<br>
+    g_return_if_fail(GTK_IS_MENU(menu));<br>
+    /* Unselect all other menu items, we want a GtkRadioMenuItem-like<br>
+     * behaviour, but we need to allow to have no item set<br>
+     */<br>
+    children = gtk_container_get_children(GTK_CONTAINER(menu));<br>
+    for (it = children; it != NULL; it = it->next) {<br>
+        if (it->data != menuitem) {<br>
+            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(it->data), FALSE);<br>
+        }<br>
+    }<br>
+    g_list_free(children);<br>
+<br>
+    if (foreign_menu->priv->cdrom != NULL) {<br>
+        const char *iso_name;<br>
+<br>
+        iso_name = gtk_menu_item_get_label(menuitem);<br>
+        g_object_set(G_OBJECT(foreign_menu->priv->cdrom),<br>
+                     "file", iso_name,<br>
+                     NULL);<br>
+        g_debug("Updating VM cdrom image to '%s'", iso_name);<br>
+        ovirt_cdrom_update_async(foreign_menu->priv->cdrom, TRUE,<br>
+                                 foreign_menu->priv->proxy, NULL,<br>
+                                 updated_cdrom_cb, foreign_menu);<br>
+    }<br>
+}<br>
+<br>
+<br>
+static char *<br>
+ovirt_foreign_menu_get_current_iso_name(OvirtForeignMenu *foreign_menu)<br>
+{<br>
+    char *name;<br>
+<br>
+    if (foreign_menu->priv->cdrom == NULL) {<br>
+        return NULL;<br>
+    }<br>
+<br>
+    g_object_get(G_OBJECT(foreign_menu->priv->cdrom), "file", &name, NULL);<br></blockquote><div><br></div><div>g_object_get()/set() don't need explicit cast.<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+    return name;<br>
+}<br>
+<br>
+<br>
+GtkWidget *ovirt_foreign_menu_get_gtk_menu(OvirtForeignMenu *foreign_menu)<br>
+{<br>
+    GtkWidget *gtk_menu;<br>
+    GList *it;<br>
+    char *current_iso;<br>
+<br>
+    g_debug("Creating GtkMenu for foreign menu");<br>
+    current_iso = ovirt_foreign_menu_get_current_iso_name(foreign_menu);<br></blockquote><div><br>Could be NULL,<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+    gtk_menu = gtk_menu_new();<br>
+    for (it = foreign_menu->priv->iso_names; it != NULL; it = it->next) {<br>
+        GtkWidget *menuitem;<br>
+<br>
+        menuitem = gtk_check_menu_item_new_with_label((char *)it->data);<br>
+        if (g_strcmp0((char *)it->data, current_iso) == 0) {<br></blockquote><div><br></div><div>why not use safer and clearer g_str_equal() ? (same all over)<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),<br>
+                                           TRUE);<br>
+        }<br>
+        g_signal_connect(menuitem, "activate",<br>
+                         G_CALLBACK(ovirt_foreign_menu_activate_item_cb),<br>
+                         foreign_menu);<br>
+        gtk_menu_shell_append(GTK_MENU_SHELL(gtk_menu), menuitem);<br>
+    }<br>
+    g_free(current_iso);<br>
+<br>
+    return gtk_menu;<br>
+}<br>
+<br>
+<br>
+static void ovirt_foreign_menu_set_files(OvirtForeignMenu *menu,<br>
+                                         const GList *files)<br>
+{<br>
+    GList *sorted_files = NULL;<br>
+    const GList *it;<br>
+    GList *it2;<br>
+<br>
+    for (it = files; it != NULL; it = it->next) {<br>
+        char *name;<br>
+        g_object_get(G_OBJECT(it->data), "name", &name, NULL);<br>
+        /* The oVirt REST API is supposed to have a 'type' node<br>
+         * associated with file resources , but as of 3.2, this node<br>
+         * is not present, so we do an extension check instead<br>
+         * to differentiate between ISOs and floppy images */<br>
+        if (g_str_has_suffix(name, ".vfd")) {<br>
+            g_free(name);<br>
+            continue;<br>
+        }<br>
+        sorted_files = g_list_insert_sorted(sorted_files, name,<br>
+                                            (GCompareFunc)g_strcmp0);<br>
+    }<br>
+<br>
+    for (it = sorted_files, it2 = menu->priv->iso_names;<br>
+         (it != NULL) && (it2 != NULL);<br></blockquote><div><br></div><div>nitpick those extra parentheses aren't needed<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+         it = it->next, it2 = it2->next) {<br>
+        if (g_strcmp0(it->data, it2->data) != 0) {<br>
+            break;<br>
+        }<br>
+    }<br>
+<br>
+    if ((it == NULL) && (it2 == NULL)) {<br>
+        /* sorted_files and menu->priv->files content was the same */<br>
+        g_list_free_full(sorted_files, (GDestroyNotify)g_free);<br>
+        return;<br>
+    }<br>
+<br>
+    g_list_free_full(menu->priv->iso_names, (GDestroyNotify)g_free);<br>
+    menu->priv->iso_names = sorted_files;<br>
+    g_object_notify(G_OBJECT(menu), "files");<br>
+}<br>
+<br>
+<br>
+static void cdroms_fetched_cb(GObject *source_object,<br>
+                              GAsyncResult *result,<br>
+                              gpointer user_data)<br>
+{<br>
+    GHashTable *cdroms;<br>
+    OvirtCollection *cdrom_collection = OVIRT_COLLECTION(source_object);<br>
+    OvirtForeignMenu *menu = OVIRT_FOREIGN_MENU(user_data);<br>
+    GList *cdrom_list;<br>
+    GError *error = NULL;<br>
+<br>
+    ovirt_collection_fetch_finish(cdrom_collection, result, &error);<br>
+    if (error != NULL) {<br>
+        g_debug("Failed to fetch cdrom collection: %s", error->message);<br>
+        g_clear_error(&error);<br>
+        return;<br>
+    }<br>
+<br>
+    cdroms = ovirt_collection_get_resources(cdrom_collection);<br>
+<br>
+    g_warn_if_fail(g_hash_table_size(cdroms) <= 1);<br>
+<br>
+    cdrom_list = g_hash_table_get_values(cdroms);<br>
+    if (cdrom_list != NULL) {<br>
+        OvirtCdrom *cdrom;<br>
+<br>
+        cdrom = OVIRT_CDROM(cdrom_list->data);<br>
+        if (menu->priv->cdrom != NULL) {<br>
+            g_object_unref(G_OBJECT(menu->priv->cdrom));<br>
+        }<br>
+<br>
+        menu->priv->cdrom = g_object_ref(G_OBJECT(cdrom));<br>
+        g_debug("Set VM cdrom to %p", menu->priv->cdrom);<br>
+    }<br>
+    g_list_free(cdrom_list);<br>
+<br>
+    if (menu->priv->cdrom != NULL) {<br>
+        ovirt_foreign_menu_next_async_step(menu, STATE_VM_CDROM);<br>
+    } else {<br>
+        g_debug("Could not find VM cdrom through oVirt REST API");<br>
+    }<br>
+}<br>
+<br>
+<br>
+static void ovirt_foreign_menu_fetch_vm_cdrom_async(OvirtForeignMenu *menu)<br>
+{<br>
+    OvirtCollection *cdrom_collection;<br>
+<br>
+    cdrom_collection = ovirt_vm_get_cdroms(menu->priv->vm);<br>
+    ovirt_collection_fetch_async(cdrom_collection, menu->priv->proxy, NULL,<br>
+                                 cdroms_fetched_cb, menu);<br>
+    g_object_unref(G_OBJECT(cdrom_collection));<br>
+}<br>
+<br>
+<br>
+static void storage_domains_fetched_cb(GObject *source_object,<br>
+                                       GAsyncResult *result,<br>
+                                       gpointer user_data)<br>
+{<br>
+    GError *error = NULL;<br>
+    OvirtForeignMenu *menu = OVIRT_FOREIGN_MENU(user_data);<br>
+    OvirtCollection *collection = OVIRT_COLLECTION(source_object);<br>
+    GList *storage_domains;<br>
+    GList *it;<br>
+<br>
+    ovirt_collection_fetch_finish(collection, result, &error);<br>
+    if (error != NULL) {<br>
+        g_debug("failed to fetch storage domains: %s", error->message);<br>
+        g_clear_error(&error);<br>
+        return;<br>
+    }<br>
+<br>
+    storage_domains = g_hash_table_get_values(ovirt_collection_get_resources(collection));<br>
+    for (it = storage_domains; it != NULL; it = it->next) {<br>
+        OvirtStorageDomain *domain;<br>
+        OvirtCollection *file_collection;<br>
+        char *name;<br>
+        int type;<br>
+<br>
+        domain = OVIRT_STORAGE_DOMAIN(it->data);<br>
+        g_object_get(G_OBJECT(domain), "type", &type, "name", &name, NULL);<br>
+        g_free(name);<br>
+<br>
+        if (type != OVIRT_STORAGE_DOMAIN_TYPE_ISO) {<br>
+            continue;<br>
+        }<br>
+<br>
+        file_collection = ovirt_storage_domain_get_files(domain);<br>
+        if (file_collection != NULL) {<br>
+            if (menu->priv->files) {<br>
+                g_object_unref(G_OBJECT(menu->priv->files));<br>
+            }<br>
+            menu->priv->files = g_object_ref(G_OBJECT(file_collection));<br>
+            g_debug("Set VM files to %p", menu->priv->files);<br>
+            break;<br>
+        }<br>
+    }<br>
+    g_list_free(storage_domains);<br>
+<br>
+    if (menu->priv->files != NULL) {<br>
+        ovirt_foreign_menu_next_async_step(menu, STATE_STORAGE_DOMAIN);<br>
+    } else {<br>
+        g_debug("Could not find iso file collection");<br>
+    }<br>
+}<br>
+<br>
+<br>
+static void ovirt_foreign_menu_fetch_storage_domain_async(OvirtForeignMenu *menu)<br>
+{<br>
+    OvirtCollection *collection;<br>
+<br>
+    g_debug("Start fetching oVirt REST collection");<br>
+    collection = ovirt_api_get_storage_domains(menu->priv->api);<br>
+    ovirt_collection_fetch_async(collection, menu->priv->proxy, NULL,<br>
+                                 storage_domains_fetched_cb, menu);<br>
+    g_object_unref(G_OBJECT(collection));<br>
+}<br>
+<br>
+<br>
+static void iso_list_fetched_cb(GObject *source_object,<br>
+                                GAsyncResult *result,<br>
+                                gpointer user_data)<br>
+{<br>
+    OvirtCollection *collection = OVIRT_COLLECTION(source_object);<br>
+    GList *files;<br>
+    GError *error = NULL;<br>
+<br>
+    ovirt_collection_fetch_finish(collection, result, &error);<br>
+    files = g_hash_table_get_values(ovirt_collection_get_resources(collection));<br>
+    if (error != NULL) {<br>
+        g_debug("failed to fetch files for ISO storage domain: %s",<br>
+                error->message);<br>
+        g_clear_error(&error);<br>
+        return;<br>
+    } else {<br>
+        ovirt_foreign_menu_set_files(OVIRT_FOREIGN_MENU(user_data), files);<br>
+    }<br>
+    g_list_free(files);<br>
+<br>
+    g_timeout_add_seconds(15, ovirt_foreign_menu_refresh_iso_list, user_data);<br></blockquote><div><br></div><div>Depending on the load of the server, this could be quite heavy. Is this the recommended value by ovirt folks?<br>
<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+}<br>
+<br>
+<br>
+static void ovirt_foreign_menu_fetch_iso_list_async(OvirtForeignMenu *menu)<br>
+{<br>
+    if (menu->priv->files == NULL) {<br>
+        return;<br>
+    }<br>
+<br>
+    ovirt_collection_fetch_async(menu->priv->files, menu->priv->proxy,<br>
+                                 NULL, iso_list_fetched_cb, menu);<br>
+}<br>
+<br>
+<br>
+static gboolean ovirt_foreign_menu_refresh_iso_list(gpointer user_data)<br>
+{<br>
+    OvirtForeignMenu *menu;<br>
+<br>
+    g_debug("Refreshing foreign menu iso list");<br>
+    menu = OVIRT_FOREIGN_MENU(user_data);<br>
+    ovirt_foreign_menu_fetch_iso_list_async(menu);<br>
+<br>
+    /* ovirt_foreign_menu_fetch_iso_list() will program a new call to that<br>
+     * function when it has finished fetching the iso list<br>
+     */<br>
+    return G_SOURCE_REMOVE;<br>
+}<br>
diff --git a/src/ovirt-foreign-menu.h b/src/ovirt-foreign-menu.h<br>
new file mode 100644<br>
index 0000000..ffadd46<br>
--- /dev/null<br>
+++ b/src/ovirt-foreign-menu.h<br>
@@ -0,0 +1,82 @@<br>
+/*<br>
+ * Virt Viewer: A virtual machine console viewer<br>
+ *<br>
+ * Copyright (C) 2007-2013 Red Hat, Inc.<br>
+ * Copyright (C) 2009-2012 Daniel P. Berrange<br>
+ * Copyright (C) 2010 Marc-André Lureau<br>
+ *<br>
+ * This program is free software; you can redistribute it and/or modify<br>
+ * it under the terms of the GNU General Public License as published by<br>
+ * the Free Software Foundation; either version 2 of the License, or<br>
+ * (at your option) any later version.<br>
+ *<br>
+ * This program is distributed in the hope that it will be useful,<br>
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
+ * GNU General Public License for more details.<br>
+ *<br>
+ * You should have received a copy of the GNU General Public License<br>
+ * along with this program; if not, write to the Free Software<br>
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA<br>
+ *<br>
+ * Author: Daniel P. Berrange <<a href="mailto:berrange@redhat.com">berrange@redhat.com</a>><br>
+ *         Christophe Fergeau <<a href="mailto:cfergeau@redhat.com">cfergeau@redhat.com</a>><br>
+ */<br>
+#ifndef _OVIRT_FOREIGN_MENU_H<br>
+#define _OVIRT_FOREIGN_MENU_H<br>
+<br>
+#include <glib-object.h><br>
+#include <govirt/govirt.h><br>
+#include <gtk/gtk.h><br>
+<br>
+<br>
+G_BEGIN_DECLS<br>
+<br>
+#define OVIRT_TYPE_FOREIGN_MENU ovirt_foreign_menu_get_type()<br>
+<br>
+#define OVIRT_FOREIGN_MENU(obj)                                        \<br>
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenu))<br>
+<br>
+#define OVIRT_FOREIGN_MENU_CLASS(klass)                                \<br>
+    (G_TYPE_CHECK_CLASS_CAST ((klass), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenuClass))<br>
+<br>
+#define OVIRT_IS_FOREIGN_MENU(obj)                                \<br>
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OVIRT_TYPE_FOREIGN_MENU))<br>
+<br>
+#define OVIRTIS_FOREIGN_MENU_CLASS(klass)                        \<br>
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), OVIRT_TYPE_FOREIGN_MENU))<br>
+<br>
+#define OVIRT_FOREIGN_MENU_GET_CLASS(obj)                        \<br>
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenuClass))<br>
+<br>
+typedef struct _OvirtForeignMenu OvirtForeignMenu;<br>
+typedef struct _OvirtForeignMenuClass OvirtForeignMenuClass;<br>
+typedef struct _OvirtForeignMenuPrivate OvirtForeignMenuPrivate;<br>
+<br>
+struct _OvirtForeignMenu {<br>
+    GObject parent;<br>
+<br>
+    OvirtForeignMenuPrivate *priv;<br>
+};<br>
+<br>
+struct _OvirtForeignMenuClass {<br>
+    GObjectClass parent_class;<br>
+};<br>
+<br>
+GType ovirt_foreign_menu_get_type(void);<br>
+<br>
+OvirtForeignMenu* ovirt_foreign_menu_new(OvirtProxy *proxy);<br>
+void ovirt_foreign_menu_start(OvirtForeignMenu *menu);<br>
+<br>
+GtkWidget *ovirt_foreign_menu_get_gtk_menu(OvirtForeignMenu *foreign_menu);<br>
+<br>
+G_END_DECLS<br>
+<br>
+#endif /* _OVIRT_FOREIGN_MENU_H */<br>
+/*<br>
+ * Local variables:<br>
+ *  c-indent-level: 4<br>
+ *  c-basic-offset: 4<br>
+ *  indent-tabs-mode: nil<br>
+ * End:<br>
+ */<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.0<br>
<br>
_______________________________________________<br>
virt-tools-list mailing list<br>
<a href="mailto:virt-tools-list@redhat.com">virt-tools-list@redhat.com</a><br>
<a href="https://www.redhat.com/mailman/listinfo/virt-tools-list" target="_blank">https://www.redhat.com/mailman/listinfo/virt-tools-list</a></font></span></blockquote></div><br><br clear="all"><br>-- <br>Marc-André Lureau
</div></div>