[virt-tools-list] [virt-viewer v2 2/6] ovirt: Add OvirtForeignMenu class
Jonathon Jongsma
jjongsma at redhat.com
Fri Jun 27 21:42:35 UTC 2014
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 at redhat.com>
> + * Christope Fergeau <cfergeau at redhat.com>
> + */
> +
> +#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 at redhat.com>
> + * Christophe Fergeau <cfergeau at redhat.com>
> + */
> +#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:
> + */
More information about the virt-tools-list
mailing list