[Spice-devel] [spice-gtk v3 07/16] file-xfer: call user callback once per operation
Victor Toso
victortoso at redhat.com
Mon May 30 09:55:03 UTC 2016
SpiceFileTransferTask has a callback to be called when operation
ended. Til this patch, we were setting the user callback which means
that in multiple file-transfers, we were calling the user callback
several times.
Following the same logic pointed from 113093dd00a1cf10f6d3c3589b7 this
is a SpiceMainChannel operation and it should only call the user
callback when this operation is over (FileTransferOperation now).
---
src/channel-main.c | 72 ++-
src/tmp-introspect325cwcm0/SpiceClientGtk-3.0.c | 628 ++++++++++++++++++++++++
2 files changed, 694 insertions(+), 6 deletions(-)
create mode 100644 src/tmp-introspect325cwcm0/SpiceClientGtk-3.0.c
diff --git a/src/channel-main.c b/src/channel-main.c
index f36326d..e204a1e 100644
--- a/src/channel-main.c
+++ b/src/channel-main.c
@@ -157,6 +157,10 @@ typedef struct {
SpiceMainChannel *channel;
GFileProgressCallback progress_callback;
gpointer progress_callback_data;
+ GAsyncReadyCallback end_callback;
+ gpointer end_callback_data;
+ GError *error;
+ GCancellable *cancellable;
goffset total_sent;
goffset transfer_size;
} FileTransferOperation;
@@ -1838,9 +1842,7 @@ static void file_xfer_close_cb(GObject *object,
}
}
- /* Notify to user that files have been transferred or something error
- happened. */
- task = g_task_new(self->channel,
+ task = g_task_new(self,
self->cancellable,
self->callback,
self->user_data);
@@ -1919,6 +1921,42 @@ static void file_xfer_flush_callback(SpiceFileTransferTask *xfer_task,
file_xfer_flush_async(main_channel, cancellable, file_xfer_data_flushed_cb, xfer_task);
}
+static void file_xfer_end_callback(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ FileTransferOperation *xfer_op;
+
+ task = G_TASK(res);
+ if (!g_task_had_error(task))
+ /* SpiceFileTransferTask and FileTransferOperation are freed on
+ * file_transfer_operation_task_finished */
+ return;
+
+ xfer_op = user_data;
+
+ if (xfer_op->error != NULL)
+ return;
+
+ /* Get the GError from SpiceFileTransferTask so we can properly return to
+ * the application when the FileTransferOperation ends */
+ g_task_propagate_boolean(task, &xfer_op->error);
+
+ /* User can cancel a FileTransfer without cancelling the whole
+ * operation. For that, spice_main_file_copy_async must be called
+ * without GCancellabe */
+ if (g_error_matches(xfer_op->error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ xfer_op->cancellable == NULL) {
+ SpiceFileTransferTask *xfer_task;
+
+ xfer_task = SPICE_FILE_TRANSFER_TASK(source_object);
+ spice_debug("file-transfer %u was cancelled",
+ spice_file_transfer_task_get_id(xfer_task));
+ g_clear_error(&xfer_op->error);
+ }
+}
+
/* main context */
static void file_xfer_read_cb(GObject *source_object,
GAsyncResult *res,
@@ -3108,10 +3146,24 @@ static void file_transfer_operation_end(FileTransferOperation *xfer_op)
g_return_if_fail(xfer_op != NULL);
spice_debug("Freeing file-transfer-operation %p", xfer_op);
+ if (xfer_op->end_callback) {
+ GTask *task = g_task_new(xfer_op->channel,
+ xfer_op->cancellable,
+ xfer_op->end_callback,
+ xfer_op->end_callback_data);
+
+ if (xfer_op->error != NULL) {
+ g_task_return_error(task, xfer_op->error);
+ } else {
+ g_task_return_boolean(task, TRUE);
+ }
+ }
+
/* SpiceFileTransferTask itself is freed after it emits "finish" */
if (xfer_op->tasks != NULL)
g_list_free(xfer_op->tasks);
+ g_clear_object (&xfer_op->cancellable);
g_free(xfer_op);
}
@@ -3225,7 +3277,11 @@ static void task_finished(SpiceFileTransferTask *task,
* files, please connect to the #SpiceMainChannel::new-file-transfer signal.
*
* When the operation is finished, callback will be called. You can then call
- * spice_main_file_copy_finish() to get the result of the operation.
+ * spice_main_file_copy_finish() to get the result of the operation. Note that
+ * before release 0.32 the callback was called for each file in multiple file
+ * transfer. This behavior was changed for the same reason as the
+ * progress_callback (above). If you need to monitor the ending of individual
+ * files, you can connect to "finished" signal from each SpiceFileTransferTask.
*
**/
void spice_main_file_copy_async(SpiceMainChannel *channel,
@@ -3259,15 +3315,19 @@ void spice_main_file_copy_async(SpiceMainChannel *channel,
xfer_op = g_new0(FileTransferOperation, 1);
xfer_op->progress_callback = progress_callback;
xfer_op->progress_callback_data = progress_callback_data;
+ xfer_op->end_callback = callback;
+ xfer_op->end_callback_data = user_data;
xfer_op->channel = channel;
+ xfer_op->error = NULL;
+ xfer_op->cancellable = (cancellable != NULL) ? g_object_ref(cancellable) : NULL;
xfer_op->tasks = spice_file_transfer_task_create_tasks(channel,
sources,
flags,
cancellable,
file_xfer_flush_callback,
xfer_op,
- callback,
- user_data);
+ file_xfer_end_callback,
+ xfer_op);
spice_debug("New file-transfer-operation %p", xfer_op);
for (it = xfer_op->tasks; it != NULL; it = it->next) {
SpiceFileTransferTask *task = SPICE_FILE_TRANSFER_TASK(it->data);
diff --git a/src/tmp-introspect325cwcm0/SpiceClientGtk-3.0.c b/src/tmp-introspect325cwcm0/SpiceClientGtk-3.0.c
new file mode 100644
index 0000000..765abbf
--- /dev/null
+++ b/src/tmp-introspect325cwcm0/SpiceClientGtk-3.0.c
@@ -0,0 +1,628 @@
+/* This file is generated, do not edit */
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ * GObject introspection: Dump introspection data
+ *
+ * Copyright (C) 2008 Colin Walters <walters at verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+/* This file is both compiled into libgirepository.so, and installed
+ * on the filesystem. But for the dumper, we want to avoid linking
+ * to libgirepository; see
+ * https://bugzilla.gnome.org/show_bug.cgi?id=630342
+ */
+#ifdef G_IREPOSITORY_COMPILATION
+#include "config.h"
+#include "girepository.h"
+#endif
+
+#include <string.h>
+
+static void
+escaped_printf (GOutputStream *out, const char *fmt, ...) G_GNUC_PRINTF (2, 3);
+
+static void
+escaped_printf (GOutputStream *out, const char *fmt, ...)
+{
+ char *str;
+ va_list args;
+ gsize written;
+ GError *error = NULL;
+
+ va_start (args, fmt);
+
+ str = g_markup_vprintf_escaped (fmt, args);
+ if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL, &error))
+ {
+ g_critical ("failed to write to iochannel: %s", error->message);
+ g_clear_error (&error);
+ }
+ g_free (str);
+
+ va_end (args);
+}
+
+static void
+goutput_write (GOutputStream *out, const char *str)
+{
+ gsize written;
+ GError *error = NULL;
+ if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL, &error))
+ {
+ g_critical ("failed to write to iochannel: %s", error->message);
+ g_clear_error (&error);
+ }
+}
+
+typedef GType (*GetTypeFunc)(void);
+typedef GQuark (*ErrorQuarkFunc)(void);
+
+static GType
+invoke_get_type (GModule *self, const char *symbol, GError **error)
+{
+ GetTypeFunc sym;
+ GType ret;
+
+ if (!g_module_symbol (self, symbol, (void**)&sym))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed to find symbol '%s'", symbol);
+ return G_TYPE_INVALID;
+ }
+
+ ret = sym ();
+ if (ret == G_TYPE_INVALID)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Function '%s' returned G_TYPE_INVALID", symbol);
+ }
+ return ret;
+}
+
+static GQuark
+invoke_error_quark (GModule *self, const char *symbol, GError **error)
+{
+ ErrorQuarkFunc sym;
+
+ if (!g_module_symbol (self, symbol, (void**)&sym))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed to find symbol '%s'", symbol);
+ return G_TYPE_INVALID;
+ }
+
+ return sym ();
+}
+
+static void
+dump_properties (GType type, GOutputStream *out)
+{
+ guint i;
+ guint n_properties;
+ GParamSpec **props;
+
+ if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT)
+ {
+ GObjectClass *klass;
+ klass = g_type_class_ref (type);
+ props = g_object_class_list_properties (klass, &n_properties);
+ }
+ else
+ {
+ void *klass;
+ klass = g_type_default_interface_ref (type);
+ props = g_object_interface_list_properties (klass, &n_properties);
+ }
+
+ for (i = 0; i < n_properties; i++)
+ {
+ GParamSpec *prop;
+
+ prop = props[i];
+ if (prop->owner_type != type)
+ continue;
+
+ escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\"/>\n",
+ prop->name, g_type_name (prop->value_type), prop->flags);
+ }
+ g_free (props);
+}
+
+static void
+dump_signals (GType type, GOutputStream *out)
+{
+ guint i;
+ guint n_sigs;
+ guint *sig_ids;
+
+ sig_ids = g_signal_list_ids (type, &n_sigs);
+ for (i = 0; i < n_sigs; i++)
+ {
+ guint sigid;
+ GSignalQuery query;
+ guint j;
+
+ sigid = sig_ids[i];
+ g_signal_query (sigid, &query);
+
+ escaped_printf (out, " <signal name=\"%s\" return=\"%s\"",
+ query.signal_name, g_type_name (query.return_type));
+
+ if (query.signal_flags & G_SIGNAL_RUN_FIRST)
+ escaped_printf (out, " when=\"first\"");
+ else if (query.signal_flags & G_SIGNAL_RUN_LAST)
+ escaped_printf (out, " when=\"last\"");
+ else if (query.signal_flags & G_SIGNAL_RUN_CLEANUP)
+ escaped_printf (out, " when=\"cleanup\"");
+#if GLIB_CHECK_VERSION(2, 29, 15)
+ else if (query.signal_flags & G_SIGNAL_MUST_COLLECT)
+ escaped_printf (out, " when=\"must-collect\"");
+#endif
+ if (query.signal_flags & G_SIGNAL_NO_RECURSE)
+ escaped_printf (out, " no-recurse=\"1\"");
+
+ if (query.signal_flags & G_SIGNAL_DETAILED)
+ escaped_printf (out, " detailed=\"1\"");
+
+ if (query.signal_flags & G_SIGNAL_ACTION)
+ escaped_printf (out, " action=\"1\"");
+
+ if (query.signal_flags & G_SIGNAL_NO_HOOKS)
+ escaped_printf (out, " no-hooks=\"1\"");
+
+ goutput_write (out, ">\n");
+
+ for (j = 0; j < query.n_params; j++)
+ {
+ escaped_printf (out, " <param type=\"%s\"/>\n",
+ g_type_name (query.param_types[j]));
+ }
+ goutput_write (out, " </signal>\n");
+ }
+ g_free (sig_ids);
+}
+
+static void
+dump_object_type (GType type, const char *symbol, GOutputStream *out)
+{
+ guint n_interfaces;
+ guint i;
+ GType *interfaces;
+
+ escaped_printf (out, " <class name=\"%s\" get-type=\"%s\"",
+ g_type_name (type), symbol);
+ if (type != G_TYPE_OBJECT)
+ {
+ GString *parent_str;
+ GType parent;
+ gboolean first = TRUE;
+
+ parent = g_type_parent (type);
+ parent_str = g_string_new ("");
+ while (parent != G_TYPE_INVALID)
+ {
+ if (first)
+ first = FALSE;
+ else
+ g_string_append_c (parent_str, ',');
+ g_string_append (parent_str, g_type_name (parent));
+ parent = g_type_parent (parent);
+ }
+
+ escaped_printf (out, " parents=\"%s\"", parent_str->str);
+
+ g_string_free (parent_str, TRUE);
+ }
+
+ if (G_TYPE_IS_ABSTRACT (type))
+ escaped_printf (out, " abstract=\"1\"");
+ goutput_write (out, ">\n");
+
+ interfaces = g_type_interfaces (type, &n_interfaces);
+ for (i = 0; i < n_interfaces; i++)
+ {
+ GType itype = interfaces[i];
+ escaped_printf (out, " <implements name=\"%s\"/>\n",
+ g_type_name (itype));
+ }
+ g_free (interfaces);
+
+ dump_properties (type, out);
+ dump_signals (type, out);
+ goutput_write (out, " </class>\n");
+}
+
+static void
+dump_interface_type (GType type, const char *symbol, GOutputStream *out)
+{
+ guint n_interfaces;
+ guint i;
+ GType *interfaces;
+
+ escaped_printf (out, " <interface name=\"%s\" get-type=\"%s\">\n",
+ g_type_name (type), symbol);
+
+ interfaces = g_type_interface_prerequisites (type, &n_interfaces);
+ for (i = 0; i < n_interfaces; i++)
+ {
+ GType itype = interfaces[i];
+ if (itype == G_TYPE_OBJECT)
+ {
+ /* Treat this as implicit for now; in theory GInterfaces are
+ * supported on things like GstMiniObject, but right now
+ * the introspection system only supports GObject.
+ * http://bugzilla.gnome.org/show_bug.cgi?id=559706
+ */
+ continue;
+ }
+ escaped_printf (out, " <prerequisite name=\"%s\"/>\n",
+ g_type_name (itype));
+ }
+ g_free (interfaces);
+
+ dump_properties (type, out);
+ dump_signals (type, out);
+ goutput_write (out, " </interface>\n");
+}
+
+static void
+dump_boxed_type (GType type, const char *symbol, GOutputStream *out)
+{
+ escaped_printf (out, " <boxed name=\"%s\" get-type=\"%s\"/>\n",
+ g_type_name (type), symbol);
+}
+
+static void
+dump_flags_type (GType type, const char *symbol, GOutputStream *out)
+{
+ guint i;
+ GFlagsClass *klass;
+
+ klass = g_type_class_ref (type);
+ escaped_printf (out, " <flags name=\"%s\" get-type=\"%s\">\n",
+ g_type_name (type), symbol);
+
+ for (i = 0; i < klass->n_values; i++)
+ {
+ GFlagsValue *value = &(klass->values[i]);
+
+ escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%d\"/>\n",
+ value->value_name, value->value_nick, value->value);
+ }
+ goutput_write (out, " </flags>\n");
+}
+
+static void
+dump_enum_type (GType type, const char *symbol, GOutputStream *out)
+{
+ guint i;
+ GEnumClass *klass;
+
+ klass = g_type_class_ref (type);
+ escaped_printf (out, " <enum name=\"%s\" get-type=\"%s\">\n",
+ g_type_name (type), symbol);
+
+ for (i = 0; i < klass->n_values; i++)
+ {
+ GEnumValue *value = &(klass->values[i]);
+
+ escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%d\"/>\n",
+ value->value_name, value->value_nick, value->value);
+ }
+ goutput_write (out, " </enum>");
+}
+
+static void
+dump_fundamental_type (GType type, const char *symbol, GOutputStream *out)
+{
+ guint n_interfaces;
+ guint i;
+ GType *interfaces;
+ GString *parent_str;
+ GType parent;
+ gboolean first = TRUE;
+
+
+ escaped_printf (out, " <fundamental name=\"%s\" get-type=\"%s\"",
+ g_type_name (type), symbol);
+
+ if (G_TYPE_IS_ABSTRACT (type))
+ escaped_printf (out, " abstract=\"1\"");
+
+ if (G_TYPE_IS_INSTANTIATABLE (type))
+ escaped_printf (out, " instantiatable=\"1\"");
+
+ parent = g_type_parent (type);
+ parent_str = g_string_new ("");
+ while (parent != G_TYPE_INVALID)
+ {
+ if (first)
+ first = FALSE;
+ else
+ g_string_append_c (parent_str, ',');
+ if (!g_type_name (parent))
+ break;
+ g_string_append (parent_str, g_type_name (parent));
+ parent = g_type_parent (parent);
+ }
+
+ if (parent_str->len > 0)
+ escaped_printf (out, " parents=\"%s\"", parent_str->str);
+ g_string_free (parent_str, TRUE);
+
+ goutput_write (out, ">\n");
+
+ interfaces = g_type_interfaces (type, &n_interfaces);
+ for (i = 0; i < n_interfaces; i++)
+ {
+ GType itype = interfaces[i];
+ escaped_printf (out, " <implements name=\"%s\"/>\n",
+ g_type_name (itype));
+ }
+ g_free (interfaces);
+ goutput_write (out, " </fundamental>\n");
+}
+
+static void
+dump_type (GType type, const char *symbol, GOutputStream *out)
+{
+ switch (g_type_fundamental (type))
+ {
+ case G_TYPE_OBJECT:
+ dump_object_type (type, symbol, out);
+ break;
+ case G_TYPE_INTERFACE:
+ dump_interface_type (type, symbol, out);
+ break;
+ case G_TYPE_BOXED:
+ dump_boxed_type (type, symbol, out);
+ break;
+ case G_TYPE_FLAGS:
+ dump_flags_type (type, symbol, out);
+ break;
+ case G_TYPE_ENUM:
+ dump_enum_type (type, symbol, out);
+ break;
+ case G_TYPE_POINTER:
+ /* GValue, etc. Just skip them. */
+ break;
+ default:
+ dump_fundamental_type (type, symbol, out);
+ break;
+ }
+}
+
+static void
+dump_error_quark (GQuark quark, const char *symbol, GOutputStream *out)
+{
+ escaped_printf (out, " <error-quark function=\"%s\" domain=\"%s\"/>\n",
+ symbol, g_quark_to_string (quark));
+}
+
+/**
+ * g_irepository_dump:
+ * @arg: Comma-separated pair of input and output filenames
+ * @error: a %GError
+ *
+ * Argument specified is a comma-separated pair of filenames; i.e. of
+ * the form "input.txt,output.xml". The input file should be a
+ * UTF-8 Unix-line-ending text file, with each line containing either
+ * "get-type:" followed by the name of a GType _get_type function, or
+ * "error-quark:" followed by the name of an error quark function. No
+ * extra whitespace is allowed.
+ *
+ * The output file should already exist, but be empty. This function will
+ * overwrite its contents.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ */
+#ifndef G_IREPOSITORY_COMPILATION
+static gboolean
+dump_irepository (const char *arg, GError **error) G_GNUC_UNUSED;
+static gboolean
+dump_irepository (const char *arg, GError **error)
+#else
+gboolean
+g_irepository_dump (const char *arg, GError **error)
+#endif
+{
+ GHashTable *output_types;
+ char **args;
+ GFile *input_file;
+ GFile *output_file;
+ GFileInputStream *input;
+ GFileOutputStream *output;
+ GDataInputStream *in;
+ GModule *self;
+ gboolean caught_error = FALSE;
+
+ self = g_module_open (NULL, 0);
+ if (!self)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "failed to open self: %s",
+ g_module_error ());
+ return FALSE;
+ }
+
+ args = g_strsplit (arg, ",", 2);
+
+ input_file = g_file_new_for_path (args[0]);
+ output_file = g_file_new_for_path (args[1]);
+
+ g_strfreev (args);
+
+ input = g_file_read (input_file, NULL, error);
+ g_object_unref (input_file);
+
+ if (input == NULL)
+ {
+ g_object_unref (output_file);
+ return FALSE;
+ }
+
+ output = g_file_replace (output_file, NULL, FALSE, 0, NULL, error);
+ g_object_unref (output_file);
+
+ if (output == NULL)
+ {
+ g_input_stream_close (G_INPUT_STREAM (input), NULL, NULL);
+ return FALSE;
+ }
+
+ goutput_write (G_OUTPUT_STREAM (output), "<?xml version=\"1.0\"?>\n");
+ goutput_write (G_OUTPUT_STREAM (output), "<dump>\n");
+
+ output_types = g_hash_table_new (NULL, NULL);
+
+ in = g_data_input_stream_new (G_INPUT_STREAM (input));
+ g_object_unref (input);
+
+ while (TRUE)
+ {
+ gsize len;
+ char *line = g_data_input_stream_read_line (in, &len, NULL, NULL);
+ const char *function;
+
+ if (line == NULL || *line == '\0')
+ {
+ g_free (line);
+ break;
+ }
+
+ g_strchomp (line);
+
+ if (strncmp (line, "get-type:", strlen ("get-type:")) == 0)
+ {
+ GType type;
+
+ function = line + strlen ("get-type:");
+
+ type = invoke_get_type (self, function, error);
+
+ if (type == G_TYPE_INVALID)
+ {
+ g_printerr ("Invalid GType function: '%s'\n", function);
+ caught_error = TRUE;
+ g_free (line);
+ break;
+ }
+
+ if (g_hash_table_lookup (output_types, (gpointer) type))
+ goto next;
+ g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
+
+ dump_type (type, function, G_OUTPUT_STREAM (output));
+ }
+ else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0)
+ {
+ GQuark quark;
+ function = line + strlen ("error-quark:");
+ quark = invoke_error_quark (self, function, error);
+
+ if (quark == 0)
+ {
+ g_printerr ("Invalid error quark function: '%s'\n", function);
+ caught_error = TRUE;
+ g_free (line);
+ break;
+ }
+
+ dump_error_quark (quark, function, G_OUTPUT_STREAM (output));
+ }
+
+
+ next:
+ g_free (line);
+ }
+
+ g_hash_table_destroy (output_types);
+
+ goutput_write (G_OUTPUT_STREAM (output), "</dump>\n");
+
+ {
+ GError **ioerror;
+ /* Avoid overwriting an earlier set error */
+ if (caught_error)
+ ioerror = NULL;
+ else
+ ioerror = error;
+ if (!g_input_stream_close (G_INPUT_STREAM (in), NULL, ioerror))
+ return FALSE;
+ if (!g_output_stream_close (G_OUTPUT_STREAM (output), NULL, ioerror))
+ return FALSE;
+ }
+
+ return !caught_error;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ GError *error = NULL;
+ const char *introspect_dump_prefix = "--introspect-dump=";
+
+#if !GLIB_CHECK_VERSION(2,35,0)
+ g_type_init ();
+#endif
+
+
+
+ if (argc != 2 || !g_str_has_prefix (argv[1], introspect_dump_prefix))
+ {
+ g_printerr ("Usage: %s --introspect-dump=input,output", argv[0]);
+ exit (1);
+ }
+
+ if (!dump_irepository (argv[1] + strlen(introspect_dump_prefix), &error))
+ {
+ g_printerr ("%s\n", error->message);
+ exit (1);
+ }
+ exit (0);
+}
+extern GType spice_grab_sequence_get_type(void);
+extern GType spice_gtk_session_get_type(void);
+extern GType spice_display_key_event_get_type(void);
+extern GType spice_display_get_type(void);
+extern GType spice_usb_device_widget_get_type(void);
+GType (*GI_GET_TYPE_FUNCS_[])(void) = {
+ spice_grab_sequence_get_type,
+ spice_gtk_session_get_type,
+ spice_display_key_event_get_type,
+ spice_display_get_type,
+ spice_usb_device_widget_get_type
+};
--
2.5.5
More information about the Spice-devel
mailing list