Hi, some comments below On Thu, 2014-06-26 at 22:01 +0200, Christophe Fergeau wrote: > This class is used to implement the so-called oVirt 'foreign menu' > which is a menu populated with ISO images available on the > oVirt instance that the user can dynamically insert into the > virtual machine he is currently viewing. > --- > configure.ac | 1 + > src/Makefile.am | 4 + > src/ovirt-foreign-menu.c | 681 +++++++++++++++++++++++++++++++++++++++++++++++ > src/ovirt-foreign-menu.h | 82 ++++++ > 4 files changed, 768 insertions(+) > create mode 100644 src/ovirt-foreign-menu.c > create mode 100644 src/ovirt-foreign-menu.h > > diff --git a/configure.ac b/configure.ac > index f1b0d1c..8e07c14 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -200,6 +200,7 @@ AS_IF([test "x$have_ovirt" = "xyes"], > [AC_MSG_ERROR([oVirt support requested but libgovirt not found]) > ]) > ]) > +AM_CONDITIONAL([HAVE_OVIRT], [test "x$have_ovirt" = "xyes"]) > > dnl Decide if this platform can support the SSH tunnel feature. > AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h]) > diff --git a/src/Makefile.am b/src/Makefile.am > index b3a9637..ee8f885 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -67,6 +67,10 @@ COMMON_SOURCES += \ > $(NULL) > endif > > +if HAVE_OVIRT > +COMMON_SOURCES += \ > + ovirt-foreign-menu.h ovirt-foreign-menu.c > +endif > > if HAVE_LIBVIRT > bin_PROGRAMS += virt-viewer > diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c > new file mode 100644 > index 0000000..ab88040 > --- /dev/null > +++ b/src/ovirt-foreign-menu.c > @@ -0,0 +1,681 @@ > +/* > + * Virt Viewer: A virtual machine console viewer > + * > + * Copyright (C) 2007-2014 Red Hat, Inc. > + * Copyright (C) 2009-2012 Daniel P. Berrange > + * Copyright (C) 2010 Marc-André Lureau > + * > + * 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, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + * > + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> > + * Christope Fergeau <cfergeau@xxxxxxxxxx> > + */ > + > +#include <config.h> > + > +#include "ovirt-foreign-menu.h" > +#include "virt-glib-compat.h" > +#include "virt-viewer-util.h" > + > +typedef enum { > + STATE_0, > + STATE_STORAGE_DOMAIN, > + STATE_VM_CDROM, > + STATE_CDROM_FILE, > + STATE_ISOS > +} OvirtForeignMenuState; > + > +static void ovirt_foreign_menu_next_async_step(OvirtForeignMenu *menu, OvirtForeignMenuState state); > +static void ovirt_foreign_menu_fetch_storage_domain_async(OvirtForeignMenu *menu); > +static void ovirt_foreign_menu_fetch_vm_cdrom_async(OvirtForeignMenu *menu); > +static void ovirt_foreign_menu_refresh_cdrom_file_async(OvirtForeignMenu *menu); > +static gboolean ovirt_foreign_menu_refresh_iso_list(gpointer user_data); > + > +G_DEFINE_TYPE (OvirtForeignMenu, ovirt_foreign_menu, G_TYPE_OBJECT) > + > + > +struct _OvirtForeignMenuPrivate { > + OvirtProxy *proxy; > + OvirtApi *api; > + OvirtVm *vm; > + > + OvirtCollection *files; > + OvirtCdrom *cdrom; > + /* The next 2 members are used when changing the ISO image shown in > + * * a VM */ > + /* Menu item for the ISO which is currently used by the VM OvirtCdrom */ > + GtkMenuItem *current_iso_menuitem; > + /* Menu item for the ISO we are trying to insert in the VM OvirtCdrom */ > + GtkMenuItem *next_iso_menuitem; Something seems wrong about storing GtkMenuItem objects here. OvirtForeignMenu is owned by the application, so there's a single OvirtForeignMenu object for the entire application. However, each display window has its own GtkMenu representing this foreign menu. So 'current_iso_menuitem' is a pointer to a single menu item from a single window. The intent of storing these two values seems to be so that we can keep the check-mark on the old menu item until we get notified that ovirt has changed the CD. However, if the 'current_iso_menuitem' refers to a menu item in a different window than new menuitem you just clicked, it won't work as expected. In addition, it appears that we re-create and replace these GtkMenus any time the foreign menu 'file' or 'files' properties change. At first I was concerned that this would lead to us holding weak references to a destroyed GtkMenuItem, but luckily we avoid this issue because: - The act of creating the GtkMenu also updates the 'current_iso_menuitem' variable. So a stale 'current_iso_menuitem' automatically gets overwritten with a valid one when we create the new GtkMenu. - The next_iso_menuitem variable does not get updated by creating a new GtkMenu, so it could theoretically become invalid. But when updated_cdrom_cb() is called, we copy this value to current_iso_menuitem just before notifying the 'file' property. This notification causes us to re-create the GtkMenu, which overwrites this (invalid) current_iso_menuitem value that we just wrote. (note that as it is currently implemented, current_iso_menuitem will almost always hold the menuitem from the last window, which may not even be displayed). The rest of the patch looks OK. > + > + > + GList *iso_names; > +}; > + > + > +#define OVIRT_FOREIGN_MENU_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenuPrivate)) > + > + > +enum { > + PROP_0, > + PROP_PROXY, > + PROP_API, > + PROP_VM, > + PROP_FILE, > + PROP_FILES, > +}; > + > + > +static char * > +ovirt_foreign_menu_get_current_iso_name(OvirtForeignMenu *foreign_menu) > +{ > + char *name; > + > + if (foreign_menu->priv->cdrom == NULL) { > + return NULL; > + } > + > + g_object_get(foreign_menu->priv->cdrom, "file", &name, NULL); > + > + return name; > +} > + > + > +static void > +ovirt_foreign_menu_get_property(GObject *object, guint property_id, > + GValue *value, GParamSpec *pspec) > +{ > + OvirtForeignMenu *self = OVIRT_FOREIGN_MENU(object); > + OvirtForeignMenuPrivate *priv = self->priv; > + > + switch (property_id) { > + case PROP_PROXY: > + g_value_set_object(value, priv->proxy); > + break; > + case PROP_API: > + g_value_set_object(value, priv->api); > + break; > + case PROP_VM: > + g_value_set_object(value, priv->vm); > + break; > + case PROP_FILE: > + g_value_take_string(value, > + ovirt_foreign_menu_get_current_iso_name(self)); > + break; > + case PROP_FILES: > + g_value_set_pointer(value, priv->iso_names); > + break; > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); > + } > +} > + > + > +static void > +ovirt_foreign_menu_set_property(GObject *object, guint property_id, > + const GValue *value G_GNUC_UNUSED, GParamSpec *pspec) > +{ > + OvirtForeignMenu *self = OVIRT_FOREIGN_MENU(object); > + OvirtForeignMenuPrivate *priv = self->priv; > + > + switch (property_id) { > + case PROP_PROXY: > + if (priv->proxy != NULL) { > + g_object_unref(priv->proxy); > + } > + priv->proxy = g_value_dup_object(value); > + break; > + case PROP_API: > + if (priv->api != NULL) { > + g_object_unref(priv->api); > + } > + priv->api = g_value_dup_object(value); > + break; > + case PROP_VM: > + if (priv->vm != NULL) { > + g_object_unref(priv->vm); > + } > + priv->vm = g_value_dup_object(value); > + break; > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); > + } > +} > + > + > +static void > +ovirt_foreign_menu_dispose(GObject *obj) > +{ > + OvirtForeignMenu *self = OVIRT_FOREIGN_MENU(obj); > + > + if (self->priv->proxy) { > + g_object_unref(self->priv->proxy); > + self->priv->proxy = NULL; > + } > + > + if (self->priv->api != NULL) { > + g_object_unref(self->priv->api); > + self->priv->api = NULL; > + } > + > + if (self->priv->vm) { > + g_object_unref(self->priv->vm); > + self->priv->vm = NULL; > + } > + > + if (self->priv->files) { > + g_object_unref(self->priv->files); > + self->priv->files = NULL; > + } > + > + if (self->priv->cdrom) { > + g_object_unref(self->priv->cdrom); > + self->priv->cdrom = NULL; > + } > + > + if (self->priv->iso_names) { > + g_list_free_full(self->priv->iso_names, (GDestroyNotify)g_free); > + self->priv->iso_names = NULL; > + } > + > + G_OBJECT_CLASS(ovirt_foreign_menu_parent_class)->dispose(obj); > +} > + > + > +static void > +ovirt_foreign_menu_class_init(OvirtForeignMenuClass *klass) > +{ > + GObjectClass *oclass = G_OBJECT_CLASS(klass); > + > + oclass->get_property = ovirt_foreign_menu_get_property; > + oclass->set_property = ovirt_foreign_menu_set_property; > + oclass->dispose = ovirt_foreign_menu_dispose; > + > + g_type_class_add_private(klass, sizeof(OvirtForeignMenuPrivate)); > + > + g_object_class_install_property(oclass, > + PROP_PROXY, > + g_param_spec_object("proxy", > + "OvirtProxy instance", > + "OvirtProxy instance", > + OVIRT_TYPE_PROXY, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT_ONLY | > + G_PARAM_STATIC_STRINGS)); > + g_object_class_install_property(oclass, > + PROP_API, > + g_param_spec_object("api", > + "OvirtApi instance", > + "Ovirt api root", > + OVIRT_TYPE_API, > + G_PARAM_READWRITE | > + G_PARAM_STATIC_STRINGS)); > + g_object_class_install_property(oclass, > + PROP_VM, > + g_param_spec_object("vm", > + "OvirtVm instance", > + "OvirtVm being handled", > + OVIRT_TYPE_VM, > + G_PARAM_READWRITE | > + G_PARAM_STATIC_STRINGS)); > + g_object_class_install_property(oclass, > + PROP_FILE, > + g_param_spec_string("file", > + "File", > + "Name of the image currently inserted in the virtual CDROM", > + NULL, > + G_PARAM_READABLE | > + G_PARAM_STATIC_STRINGS)); > + g_object_class_install_property(oclass, > + PROP_FILES, > + g_param_spec_pointer("files", > + "ISO names", > + "GSList of ISO names for this oVirt VM", > + G_PARAM_READABLE | > + G_PARAM_STATIC_STRINGS)); > +} > + > + > +static void > +ovirt_foreign_menu_init(OvirtForeignMenu *self) > +{ > + self->priv = OVIRT_FOREIGN_MENU_GET_PRIVATE(self); > +} > + > + > +OvirtForeignMenu* ovirt_foreign_menu_new(OvirtProxy *proxy) > +{ > + return g_object_new(OVIRT_TYPE_FOREIGN_MENU, > + "proxy", proxy, > + NULL); > +} > + > + > +static void > +ovirt_foreign_menu_next_async_step(OvirtForeignMenu *menu, > + OvirtForeignMenuState current_state) > +{ > + g_return_if_fail(current_state >= STATE_0); > + g_return_if_fail(current_state < STATE_ISOS); > + > + current_state++; > + > + if (current_state == STATE_STORAGE_DOMAIN) { > + if (menu->priv->files == NULL) { > + ovirt_foreign_menu_fetch_storage_domain_async(menu); > + } else { > + current_state++; > + } > + } > + > + if (current_state == STATE_VM_CDROM) { > + if (menu->priv->cdrom == NULL) { > + ovirt_foreign_menu_fetch_vm_cdrom_async(menu); > + } else { > + current_state++; > + } > + } > + > + if (current_state == STATE_CDROM_FILE) { > + ovirt_foreign_menu_refresh_cdrom_file_async(menu); > + } > + > + if (current_state == STATE_ISOS) { > + g_warn_if_fail(menu->priv->api != NULL); > + g_warn_if_fail(menu->priv->vm != NULL); > + g_warn_if_fail(menu->priv->files != NULL); > + g_warn_if_fail(menu->priv->cdrom != NULL); > + > + ovirt_foreign_menu_refresh_iso_list(menu); > + } > +} > + > + > +void > +ovirt_foreign_menu_start(OvirtForeignMenu *menu) > +{ > + ovirt_foreign_menu_next_async_step(menu, STATE_0); > +} > + > + > +static void > +ovirt_foreign_menu_activate_item_cb(GtkMenuItem *menuitem, gpointer user_data); > + > + > +static void > +menu_item_set_active_no_signal(GtkMenuItem *menuitem, > + gboolean active, > + GCallback callback, > + gpointer user_data) > +{ > + g_signal_handlers_block_by_func(menuitem, callback, user_data); > + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active); > + g_signal_handlers_unblock_by_func(menuitem, callback, user_data); > +} > + > + > +static void updated_cdrom_cb(GObject *source_object, > + GAsyncResult *result, > + G_GNUC_UNUSED gpointer user_data) > +{ > + GError *error = NULL; > + OvirtForeignMenu *foreign_menu; > + gboolean updated; > + > + foreign_menu = OVIRT_FOREIGN_MENU(user_data); > + updated = ovirt_cdrom_update_finish(OVIRT_CDROM(source_object), > + result, &error); > + g_debug("Finished updating cdrom content"); > + if (updated) { > + foreign_menu->priv->current_iso_menuitem = foreign_menu->priv->next_iso_menuitem; > + g_object_notify(G_OBJECT(foreign_menu), "file"); > + } else { > + /* Reset old state back as we were not successful in switching to > + * the new ISO */ > + GtkMenuItem *current = foreign_menu->priv->current_iso_menuitem; > + const char *current_file; > + > + if (error != NULL) { > + g_warning("failed to update cdrom resource: %s", error->message); > + g_clear_error(&error); > + } > + if (current != NULL) { > + current_file = gtk_menu_item_get_label(current); > + } else { > + current_file = NULL; > + } > + g_debug("setting OvirtCdrom:file back to '%s'", > + current_file?current_file:NULL); > + g_object_set(foreign_menu->priv->cdrom, "file", current_file, NULL); > + } > + foreign_menu->priv->next_iso_menuitem = NULL; > +} > + > + > +static void > +ovirt_foreign_menu_activate_item_cb(GtkMenuItem *menuitem, gpointer user_data) > +{ > + OvirtForeignMenu *foreign_menu; > + const char *iso_name; > + gboolean checked; > + > + checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)); > + foreign_menu = OVIRT_FOREIGN_MENU(user_data); > + g_return_if_fail(foreign_menu->priv->cdrom != NULL); > + g_return_if_fail(foreign_menu->priv->next_iso_menuitem == NULL); > + > + g_debug("'%s' clicked", gtk_menu_item_get_label(menuitem)); > + > + /* We only want to move the check mark for the currently selected ISO > + * when ovirt_cdrom_update_async() is successful, so for now we move > + * the check mark back to where it was before > + */ > +/* > + menu_item_set_active_no_signal(foreign_menu->priv->current_iso_menuitem, > + !checked, > + ovirt_foreign_menu_activate_item_cb, > + foreign_menu); > +*/ What is the purpose of this commented-out bit? > + menu_item_set_active_no_signal(menuitem, !checked, > + (GCallback)ovirt_foreign_menu_activate_item_cb, > + foreign_menu); > + > + if (checked) { > + g_debug("Updating VM cdrom image to '%s'", iso_name); > + iso_name = gtk_menu_item_get_label(menuitem); > + foreign_menu->priv->next_iso_menuitem = menuitem; > + } else { > + g_debug("Removing current cdrom image"); > + iso_name = NULL; > + foreign_menu->priv->next_iso_menuitem = NULL; > + /* FIXME: No idea how to remove a CDRom from a VM through ovirt REST > + * API for now, so return early. > + */ > + return; > + } > + g_object_set(foreign_menu->priv->cdrom, > + "file", iso_name, > + NULL); > + ovirt_cdrom_update_async(foreign_menu->priv->cdrom, TRUE, > + foreign_menu->priv->proxy, NULL, > + updated_cdrom_cb, foreign_menu); > +} > + > + > +GtkWidget *ovirt_foreign_menu_get_gtk_menu(OvirtForeignMenu *foreign_menu) > +{ > + GtkWidget *gtk_menu; > + GList *it; > + char *current_iso; > + > + g_debug("Creating GtkMenu for foreign menu"); > + current_iso = ovirt_foreign_menu_get_current_iso_name(foreign_menu); > + gtk_menu = gtk_menu_new(); > + for (it = foreign_menu->priv->iso_names; it != NULL; it = it->next) { > + GtkWidget *menuitem; > + > + menuitem = gtk_check_menu_item_new_with_label((char *)it->data); > + if (g_strcmp0((char *)it->data, current_iso) == 0) { > + foreign_menu->priv->current_iso_menuitem = GTK_MENU_ITEM(menuitem); > + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), > + TRUE); > + } > + g_signal_connect(menuitem, "activate", > + G_CALLBACK(ovirt_foreign_menu_activate_item_cb), > + foreign_menu); > + gtk_menu_shell_append(GTK_MENU_SHELL(gtk_menu), menuitem); > + } > + g_free(current_iso); > + > + return gtk_menu; > +} > + > + > +static void ovirt_foreign_menu_set_files(OvirtForeignMenu *menu, > + const GList *files) > +{ > + GList *sorted_files = NULL; > + const GList *it; > + GList *it2; > + > + for (it = files; it != NULL; it = it->next) { > + char *name; > + g_object_get(it->data, "name", &name, NULL); > + /* The oVirt REST API is supposed to have a 'type' node > + * associated with file resources , but as of 3.2, this node > + * is not present, so we do an extension check instead > + * to differentiate between ISOs and floppy images */ > + if (g_str_has_suffix(name, ".vfd")) { > + g_free(name); > + continue; > + } > + sorted_files = g_list_insert_sorted(sorted_files, name, > + (GCompareFunc)g_strcmp0); > + } > + > + for (it = sorted_files, it2 = menu->priv->iso_names; > + (it != NULL) && (it2 != NULL); > + it = it->next, it2 = it2->next) { > + if (g_strcmp0(it->data, it2->data) != 0) { > + break; > + } > + } > + > + if ((it == NULL) && (it2 == NULL)) { > + /* sorted_files and menu->priv->files content was the same */ > + g_list_free_full(sorted_files, (GDestroyNotify)g_free); > + return; > + } > + > + g_list_free_full(menu->priv->iso_names, (GDestroyNotify)g_free); > + menu->priv->iso_names = sorted_files; > + g_object_notify(G_OBJECT(menu), "files"); > +} > + > + > +static void cdrom_file_refreshed_cb(GObject *source_object, > + GAsyncResult *result, > + gpointer user_data) > +{ > + OvirtResource *cdrom = OVIRT_RESOURCE(source_object); > + OvirtForeignMenu *menu = OVIRT_FOREIGN_MENU(user_data); > + GError *error = NULL; > + > + ovirt_resource_refresh_finish(cdrom, result, &error); > + if (error != NULL) { > + g_warning("failed to refresh cdrom content: %s", error->message); > + g_clear_error(&error); > + return; > + } > + > + /* Content of OvirtCdrom is now current */ > + g_object_notify(G_OBJECT(menu), "file"); > + if (menu->priv->cdrom != NULL) { > + ovirt_foreign_menu_next_async_step(menu, STATE_CDROM_FILE); > + } else { > + g_debug("Could not find VM cdrom through oVirt REST API"); > + } > +} > + > + > +static void ovirt_foreign_menu_refresh_cdrom_file_async(OvirtForeignMenu *menu) > +{ > + g_return_if_fail(OVIRT_IS_RESOURCE(menu->priv->cdrom)); > + > + ovirt_resource_refresh_async(OVIRT_RESOURCE(menu->priv->cdrom), > + menu->priv->proxy, NULL, > + cdrom_file_refreshed_cb, menu); > +} > + > + > +static void cdroms_fetched_cb(GObject *source_object, > + GAsyncResult *result, > + gpointer user_data) > +{ > + GHashTable *cdroms; > + OvirtCollection *cdrom_collection = OVIRT_COLLECTION(source_object); > + OvirtForeignMenu *menu = OVIRT_FOREIGN_MENU(user_data); > + GHashTableIter iter; > + OvirtCdrom *cdrom; > + GError *error = NULL; > + > + ovirt_collection_fetch_finish(cdrom_collection, result, &error); > + if (error != NULL) { > + g_warning("failed to fetch cdrom collection: %s", error->message); > + g_clear_error(&error); > + return; > + } > + > + cdroms = ovirt_collection_get_resources(cdrom_collection); > + > + g_warn_if_fail(g_hash_table_size(cdroms) <= 1); > + > + g_hash_table_iter_init(&iter, cdroms); > + /* Set CDROM drive. If we have multiple ones, only the first > + * one will be kept, but currently oVirt only adds one CDROM > + * device per-VM > + */ > + if (g_hash_table_iter_next(&iter, NULL, (gpointer *)&cdrom)) { > + if (menu->priv->cdrom != NULL) { > + g_object_unref(G_OBJECT(menu->priv->cdrom)); > + } > + menu->priv->cdrom = g_object_ref(G_OBJECT(cdrom)); > + g_debug("Set VM cdrom to %p", menu->priv->cdrom); > + } > + > + if (menu->priv->cdrom != NULL) { > + ovirt_foreign_menu_next_async_step(menu, STATE_VM_CDROM); > + } else { > + g_debug("Could not find VM cdrom through oVirt REST API"); > + } > +} > + > + > +static void ovirt_foreign_menu_fetch_vm_cdrom_async(OvirtForeignMenu *menu) > +{ > + OvirtCollection *cdrom_collection; > + > + cdrom_collection = ovirt_vm_get_cdroms(menu->priv->vm); > + ovirt_collection_fetch_async(cdrom_collection, menu->priv->proxy, NULL, > + cdroms_fetched_cb, menu); > +} > + > + > +static void storage_domains_fetched_cb(GObject *source_object, > + GAsyncResult *result, > + gpointer user_data) > +{ > + GError *error = NULL; > + OvirtForeignMenu *menu = OVIRT_FOREIGN_MENU(user_data); > + OvirtCollection *collection = OVIRT_COLLECTION(source_object); > + GHashTableIter iter; > + OvirtStorageDomain *domain; > + > + ovirt_collection_fetch_finish(collection, result, &error); > + if (error != NULL) { > + g_warning("failed to fetch storage domains: %s", error->message); > + g_clear_error(&error); > + return; > + } > + > + g_hash_table_iter_init(&iter, ovirt_collection_get_resources(collection)); > + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&domain)) { > + OvirtCollection *file_collection; > + int type; > + > + g_object_get(domain, "type", &type, NULL); > + if (type != OVIRT_STORAGE_DOMAIN_TYPE_ISO) { > + continue; > + } > + > + file_collection = ovirt_storage_domain_get_files(domain); > + if (file_collection != NULL) { > + if (menu->priv->files) { > + g_object_unref(G_OBJECT(menu->priv->files)); > + } > + menu->priv->files = g_object_ref(G_OBJECT(file_collection)); > + g_debug("Set VM files to %p", menu->priv->files); > + break; > + } > + } > + > + if (menu->priv->files != NULL) { > + ovirt_foreign_menu_next_async_step(menu, STATE_STORAGE_DOMAIN); > + } else { > + g_debug("Could not find iso file collection"); > + } > +} > + > + > +static void ovirt_foreign_menu_fetch_storage_domain_async(OvirtForeignMenu *menu) > +{ > + OvirtCollection *collection; > + > + g_debug("Start fetching oVirt REST collection"); > + collection = ovirt_api_get_storage_domains(menu->priv->api); > + ovirt_collection_fetch_async(collection, menu->priv->proxy, NULL, > + storage_domains_fetched_cb, menu); > +} > + > + > +static void iso_list_fetched_cb(GObject *source_object, > + GAsyncResult *result, > + gpointer user_data) > +{ > + OvirtCollection *collection = OVIRT_COLLECTION(source_object); > + GError *error = NULL; > + GList *files; > + > + ovirt_collection_fetch_finish(collection, result, &error); > + if (error != NULL) { > + g_warning("failed to fetch files for ISO storage domain: %s", > + error->message); > + g_clear_error(&error); > + return; > + } > + > + files = g_hash_table_get_values(ovirt_collection_get_resources(collection)); > + ovirt_foreign_menu_set_files(OVIRT_FOREIGN_MENU(user_data), files); > + g_list_free(files); > + > + g_timeout_add_seconds(15, ovirt_foreign_menu_refresh_iso_list, user_data); > +} > + > + > +static void ovirt_foreign_menu_fetch_iso_list_async(OvirtForeignMenu *menu) > +{ > + if (menu->priv->files == NULL) { > + return; > + } > + > + ovirt_collection_fetch_async(menu->priv->files, menu->priv->proxy, > + NULL, iso_list_fetched_cb, menu); > +} > + > + > +static gboolean ovirt_foreign_menu_refresh_iso_list(gpointer user_data) > +{ > + OvirtForeignMenu *menu; > + > + g_debug("Refreshing foreign menu iso list"); > + menu = OVIRT_FOREIGN_MENU(user_data); > + ovirt_foreign_menu_fetch_iso_list_async(menu); > + > + /* ovirt_foreign_menu_fetch_iso_list_async() will schedule a new call to > + * that function through iso_list_fetched_cb() when it has finished > + * fetching the iso list > + */ > + return G_SOURCE_REMOVE; > +} > diff --git a/src/ovirt-foreign-menu.h b/src/ovirt-foreign-menu.h > new file mode 100644 > index 0000000..7d28f0b > --- /dev/null > +++ b/src/ovirt-foreign-menu.h > @@ -0,0 +1,82 @@ > +/* > + * Virt Viewer: A virtual machine console viewer > + * > + * Copyright (C) 2007-2014 Red Hat, Inc. > + * Copyright (C) 2009-2012 Daniel P. Berrange > + * Copyright (C) 2010 Marc-André Lureau > + * > + * 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, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + * > + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> > + * Christophe Fergeau <cfergeau@xxxxxxxxxx> > + */ > +#ifndef _OVIRT_FOREIGN_MENU_H > +#define _OVIRT_FOREIGN_MENU_H > + > +#include <glib-object.h> > +#include <govirt/govirt.h> > +#include <gtk/gtk.h> > + > + > +G_BEGIN_DECLS > + > +#define OVIRT_TYPE_FOREIGN_MENU ovirt_foreign_menu_get_type() > + > +#define OVIRT_FOREIGN_MENU(obj) \ > + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenu)) > + > +#define OVIRT_FOREIGN_MENU_CLASS(klass) \ > + (G_TYPE_CHECK_CLASS_CAST ((klass), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenuClass)) > + > +#define OVIRT_IS_FOREIGN_MENU(obj) \ > + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OVIRT_TYPE_FOREIGN_MENU)) > + > +#define OVIRTIS_FOREIGN_MENU_CLASS(klass) \ > + (G_TYPE_CHECK_CLASS_TYPE ((klass), OVIRT_TYPE_FOREIGN_MENU)) > + > +#define OVIRT_FOREIGN_MENU_GET_CLASS(obj) \ > + (G_TYPE_INSTANCE_GET_CLASS ((obj), OVIRT_TYPE_FOREIGN_MENU, OvirtForeignMenuClass)) > + > +typedef struct _OvirtForeignMenu OvirtForeignMenu; > +typedef struct _OvirtForeignMenuClass OvirtForeignMenuClass; > +typedef struct _OvirtForeignMenuPrivate OvirtForeignMenuPrivate; > + > +struct _OvirtForeignMenu { > + GObject parent; > + > + OvirtForeignMenuPrivate *priv; > +}; > + > +struct _OvirtForeignMenuClass { > + GObjectClass parent_class; > +}; > + > +GType ovirt_foreign_menu_get_type(void); > + > +OvirtForeignMenu* ovirt_foreign_menu_new(OvirtProxy *proxy); > +void ovirt_foreign_menu_start(OvirtForeignMenu *menu); > + > +GtkWidget *ovirt_foreign_menu_get_gtk_menu(OvirtForeignMenu *foreign_menu); > + > +G_END_DECLS > + > +#endif /* _OVIRT_FOREIGN_MENU_H */ > +/* > + * Local variables: > + * c-indent-level: 4 > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ _______________________________________________ virt-tools-list mailing list virt-tools-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/virt-tools-list