Currently virt-p2v requires Gtk 2. This commit changes virt-p2v so it
can be built with either Gtk 2 or 3.
By careful use of macros, this code should compile on both recent
Gtk 2 and Gtk 3.
With no other options, ./configure will now prefer Gtk 3 if it finds
it, or fall back to Gtk 2. But you can control this by setting
'./configure --with-gtk=2|3|check|no' where the options mean:
* --with-gtk=2 - Only test for Gtk 2
* --with-gtk=3 - Only test for Gtk 3
* --with-gtk=check - Check for Gtk 3 then Gtk 2 (default)
* --with-gtk=no - Don't build virt-p2v
In the ./configure output you will see something like this:
checking for --with-gtk option... 2
checking for GTK... yes
checking if we can build virt-p2v... yes, with Gtk 2
---
docs/guestfs-building.pod | 10 +-
m4/guestfs_misc_libraries.m4 | 43 ++-
p2v/Makefile.am | 6 +-
p2v/dependencies.m4 | 8 +-
p2v/gui.c | 619 +++++++++++++++++++++++++++++--------------
p2v/main.c | 2 -
6 files changed, 470 insertions(+), 218 deletions(-)
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index f42d25f..faaa626 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -272,9 +272,15 @@ Optional. Used by virt-builder for checking digital signatures.
Optional. If available, virt-builder will use this library
for fast, parallel uncompression of templates.
-=item gtk2 E<ge> 2.24
+=item Gtk E<ge> 2.24, or 3
-Optional. Used by the virt-p2v user interface.
+Optional.
+
+Used by the virt-p2v graphical user interface.
+
+Either Gtk 2 or Gtk 3 can be used. If you want to select a specific
+version of Gtk, use S<C<./configure --with-gtk=2>> or
+S<C<./configure --with-gtk=3>>.
=item zip
diff --git a/m4/guestfs_misc_libraries.m4 b/m4/guestfs_misc_libraries.m4
index 9b22670..4ae0576 100644
--- a/m4/guestfs_misc_libraries.m4
+++ b/m4/guestfs_misc_libraries.m4
@@ -74,12 +74,41 @@ PKG_CHECK_MODULES([LIBCONFIG], [libconfig],[
[AC_MSG_WARN([libconfig not found, some features will be disabled])])
AM_CONDITIONAL([HAVE_LIBCONFIG],[test "x$LIBCONFIG_LIBS" != "x"])
-dnl Check for gtk2 library, used by virt-p2v.
-PKG_CHECK_MODULES([GTK2], [gtk+-2.0], [
- AC_SUBST([GTK2_CFLAGS])
- AC_SUBST([GTK2_LIBS])
-],
- [AC_MSG_WARN([gtk2 not found, virt-p2v will be disabled])])
+dnl Check for Gtk 2 or 3 library, used by virt-p2v.
+AC_MSG_CHECKING([for --with-gtk option])
+AC_ARG_WITH([gtk],
+ [AS_HELP_STRING([--with-gtk=2|3|check|no],
+ [prefer Gtk version 2 or 3. @<:@default=check@:>@])],
+ [with_gtk="$withval"
+ AC_MSG_RESULT([$withval])],
+ [with_gtk="check"
+ AC_MSG_RESULT([not set, will check for installed Gtk])]
+)
+
+if test "x$GTK_LIBS" = "x" && \
+ ( test "x$with_gtk" = "x3" || test "x$with_gtk" =
"xcheck" ) ; then
+ PKG_CHECK_MODULES([GTK], [gtk+-3.0], [
+ AC_SUBST([GTK_CFLAGS])
+ AC_SUBST([GTK_LIBS])
+ GTK_VERSION=3
+ AC_SUBST([GTK_VERSION])
+ ], [])
+fi
+if test "x$GTK_LIBS" = "x" && \
+ ( test "x$with_gtk" = "x2" || test "x$with_gtk" =
"xcheck" ) ; then
+ PKG_CHECK_MODULES([GTK], [gtk+-2.0], [
+ AC_SUBST([GTK_CFLAGS])
+ AC_SUBST([GTK_LIBS])
+ GTK_VERSION=2
+ AC_SUBST([GTK_VERSION])
+ ], [])
+fi
dnl Can we build virt-p2v?
-AM_CONDITIONAL([HAVE_P2V], [test "x$GTK2_LIBS" != "x"])
+AC_MSG_CHECKING([if we can build virt-p2v])
+if test "x$GTK_LIBS" != "x"; then
+ AC_MSG_RESULT([yes, with Gtk $GTK_VERSION])
+else
+ AC_MSG_RESULT([no])
+fi
+AM_CONDITIONAL([HAVE_P2V], [test "x$GTK_LIBS" != "x"])
diff --git a/p2v/Makefile.am b/p2v/Makefile.am
index 3342563..53d7198 100644
--- a/p2v/Makefile.am
+++ b/p2v/Makefile.am
@@ -84,13 +84,13 @@ virt_p2v_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
$(PCRE_CFLAGS) \
$(LIBXML2_CFLAGS) \
- $(GTK2_CFLAGS)
+ $(GTK_CFLAGS)
virt_p2v_LDADD = \
$(top_builddir)/src/libutils.la \
$(PCRE_LIBS) \
$(LIBXML2_LIBS) \
- $(GTK2_LIBS) \
+ $(GTK_LIBS) \
../gnulib/lib/libgnu.la
# Scripts to build the disk image, USB key, or kickstart.
@@ -104,7 +104,7 @@ dependencies_files = \
$(dependencies_files): dependencies.m4
define=`echo $@ | $(SED)
's/dependencies.//;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
- m4 -D$$define=1 $< > $@-t
+ m4 -D$$define=1 -DGTK_VERSION=$(GTK_VERSION) $< > $@-t
mv $@-t $@
# Support files needed by the virt-p2v-make-* scripts.
diff --git a/p2v/dependencies.m4 b/p2v/dependencies.m4
index ab25a49..b5d4d6e 100644
--- a/p2v/dependencies.m4
+++ b/p2v/dependencies.m4
@@ -23,7 +23,7 @@ ifelse(REDHAT,1,
dnl Used by the virt-p2v binary.
pcre
libxml2
- gtk2
+ gtk`'GTK_VERSION
dnl Run as external programs by the p2v binary.
/usr/bin/ssh
@@ -55,7 +55,7 @@ ifelse(REDHAT,1,
ifelse(DEBIAN,1,
libpcre3
libxml2
- libgtk2.0-0
+ libgtk`'GTK_VERSION`'.0-0
openssh-client
qemu-utils
curl
@@ -73,7 +73,7 @@ ifelse(DEBIAN,1,
ifelse(ARCHLINUX,1,
pcre
libxml2
- gtk2
+ gtk`'GTK_VERSION
openssh
qemu
curl
@@ -92,7 +92,7 @@ ifelse(ARCHLINUX,1,
ifelse(SUSE,1,
pcre
libxml2
- gtk2
+ gtk`'GTK_VERSION
/usr/bin/ssh
/usr/bin/qemu-nbd
curl
diff --git a/p2v/gui.c b/p2v/gui.c
index f3e448f..147cadd 100644
--- a/p2v/gui.c
+++ b/p2v/gui.c
@@ -80,6 +80,104 @@
#define MAX_SUPPORTED_VCPUS 160
#define MAX_SUPPORTED_MEMORY_MB (UINT64_C (4000 * 1024))
+/* Backwards compatibility for some deprecated functions in Gtk 3. */
+#if GTK_CHECK_VERSION(3,2,0) /* gtk >= 3.2 */
+#define hbox_new(box, homogeneous, spacing) \
+ do { \
+ (box) = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, spacing); \
+ if (homogeneous) \
+ gtk_box_set_homogeneous (GTK_BOX (box), TRUE); \
+ } while (0)
+#define vbox_new(box, homogeneous, spacing) \
+ do { \
+ (box) = gtk_box_new (GTK_ORIENTATION_VERTICAL, spacing); \
+ if (homogeneous) \
+ gtk_box_set_homogeneous (GTK_BOX (box), TRUE); \
+ } while (0)
+#else /* gtk < 3.2 */
+#define hbox_new(box, homogeneous, spacing) \
+ (box) = gtk_hbox_new ((homogeneous), (spacing))
+#define vbox_new(box, homogeneous, spacing) \
+ (box) = gtk_vbox_new ((homogeneous), (spacing))
+#endif
+
+#if GTK_CHECK_VERSION(3,4,0) /* gtk >= 3.4 */
+/* GtkGrid is sufficiently similar to GtkTable that we can just
+ * redefine these functions.
+ */
+#define table_new(grid, rows, columns) \
+ (grid) = gtk_grid_new ()
+#define table_attach(grid, child, left, right, top, bottom, xoptions, yoptions, xpadding,
ypadding) \
+ do { \
+ gtk_grid_attach (GTK_GRID (grid), (child), \
+ (left), (top), (right)-(left), (bottom)-(top)); \
+ if ((xoptions) == GTK_EXPAND) \
+ gtk_widget_set_hexpand ((grid), TRUE); \
+ else if ((xoptions) == GTK_FILL) \
+ gtk_widget_set_halign ((grid), GTK_ALIGN_FILL); \
+ if ((yoptions) == GTK_EXPAND) \
+ gtk_widget_set_vexpand ((grid), TRUE); \
+ else if ((yoptions) == GTK_FILL) \
+ gtk_widget_set_valign ((grid), GTK_ALIGN_FILL); \
+ set_padding ((grid), (xpadding), (ypadding)); \
+ } while (0)
+#else
+#define table_new(table, rows, columns) \
+ (table) = gtk_table_new ((rows), (columns), FALSE)
+#define table_attach(table, child, left, right,top, bottom, xoptions, yoptions, xpadding,
ypadding) \
+ gtk_table_attach (GTK_TABLE (table), (child), \
+ (left), (right), (top), (bottom), \
+ (xoptions), (yoptions), (xpadding), (ypadding))
+#endif
+
+#if GTK_CHECK_VERSION(3,8,0) /* gtk >= 3.8 */
+#define scrolled_window_add_with_viewport(container, child) \
+ gtk_container_add (GTK_CONTAINER (container), child)
+#else
+#define scrolled_window_add_with_viewport(container, child) \
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (container), child)
+#endif
+
+#if GTK_CHECK_VERSION(3,10,0) /* gtk >= 3.10 */
+#undef GTK_STOCK_DIALOG_WARNING
+#define GTK_STOCK_DIALOG_WARNING "dialog-warning"
+#define gtk_image_new_from_stock gtk_image_new_from_icon_name
+#endif
+
+#if GTK_CHECK_VERSION(3,14,0) /* gtk >= 3.14 */
+#define set_padding(widget, xpad, ypad) \
+ do { \
+ if ((xpad) != 0) { \
+ gtk_widget_set_margin_start ((widget), (xpad)); \
+ gtk_widget_set_margin_end ((widget), (xpad)); \
+ } \
+ if ((ypad) != 0) { \
+ gtk_widget_set_margin_top ((widget), (ypad)); \
+ gtk_widget_set_margin_bottom ((widget), (ypad)); \
+ } \
+ } while (0)
+#define set_alignment(widget, xalign, yalign) \
+ do { \
+ if ((xalign) == 0.) \
+ gtk_widget_set_halign ((widget), GTK_ALIGN_START); \
+ else if ((xalign) == 1.) \
+ gtk_widget_set_halign ((widget), GTK_ALIGN_END); \
+ else \
+ gtk_widget_set_halign ((widget), GTK_ALIGN_CENTER); \
+ if ((yalign) == 0.) \
+ gtk_widget_set_valign ((widget), GTK_ALIGN_START); \
+ else if ((xalign) == 1.) \
+ gtk_widget_set_valign ((widget), GTK_ALIGN_END); \
+ else \
+ gtk_widget_set_valign ((widget), GTK_ALIGN_CENTER); \
+ } while (0)
+#else /* gtk < 3.14 */
+#define set_padding(widget, xpad, ypad) \
+ gtk_misc_set_padding(GTK_MISC(widget),(xpad),(ypad))
+#define set_alignment(widget, xalign, yalign) \
+ gtk_misc_set_padding(GTK_MISC(widget),(xalign),(yalign))
+#endif
+
static void create_connection_dialog (struct config *);
static void create_conversion_dialog (struct config *);
static void create_running_dialog (void);
@@ -127,7 +225,6 @@ gui_conversion (struct config *config)
show_connection_dialog ();
gtk_main ();
- gdk_threads_leave ();
}
/*----------------------------------------------------------------------*/
@@ -135,6 +232,10 @@ gui_conversion (struct config *config)
static void test_connection_clicked (GtkWidget *w, gpointer data);
static void *test_connection_thread (void *data);
+static gboolean start_spinner (gpointer user_data);
+static gboolean stop_spinner (gpointer user_data);
+static gboolean test_connection_error (gpointer user_data);
+static gboolean test_connection_ok (gpointer user_data);
static void configure_network_button_clicked (GtkWidget *w, gpointer data);
static void about_button_clicked (GtkWidget *w, gpointer data);
static void connection_next_clicked (GtkWidget *w, gpointer data);
@@ -168,46 +269,46 @@ create_connection_dialog (struct config *config)
/* The main dialog area. */
intro = gtk_label_new (_("Connect to a virt-v2v conversion server over
SSH:"));
gtk_label_set_line_wrap (GTK_LABEL (intro), TRUE);
- gtk_misc_set_padding (GTK_MISC (intro), 10, 10);
+ set_padding (intro, 10, 10);
- table = gtk_table_new (7, 2, FALSE);
+ table_new (table, 7, 2);
server_label = gtk_label_new (_("Conversion server:"));
- gtk_misc_set_alignment (GTK_MISC (server_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (table), server_label,
- 0, 1, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
+ set_alignment (server_label, 1., 0.5);
+ table_attach (table, server_label,
+ 0, 1, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
server_entry = gtk_entry_new ();
if (config->server != NULL)
gtk_entry_set_text (GTK_ENTRY (server_entry), config->server);
- gtk_table_attach (GTK_TABLE (table), server_entry,
- 1, 2, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
+ table_attach (table, server_entry,
+ 1, 2, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
port_label = gtk_label_new (_("SSH port:"));
- gtk_misc_set_alignment (GTK_MISC (port_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (table), port_label,
- 0, 1, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
+ set_alignment (port_label, 1., 0.5);
+ table_attach (table, port_label,
+ 0, 1, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
port_entry = gtk_entry_new ();
gtk_entry_set_width_chars (GTK_ENTRY (port_entry), 6);
snprintf (port_str, sizeof port_str, "%d", config->port);
gtk_entry_set_text (GTK_ENTRY (port_entry), port_str);
- gtk_table_attach (GTK_TABLE (table), port_entry,
- 1, 2, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
+ table_attach (table, port_entry,
+ 1, 2, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
username_label = gtk_label_new (_("User name:"));
- gtk_misc_set_alignment (GTK_MISC (username_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (table), username_label,
- 0, 1, 2, 3, GTK_FILL, GTK_FILL, 4, 4);
+ set_alignment (username_label, 1., 0.5);
+ table_attach (table, username_label,
+ 0, 1, 2, 3, GTK_FILL, GTK_FILL, 4, 4);
username_entry = gtk_entry_new ();
if (config->username != NULL)
gtk_entry_set_text (GTK_ENTRY (username_entry), config->username);
else
gtk_entry_set_text (GTK_ENTRY (username_entry), "root");
- gtk_table_attach (GTK_TABLE (table), username_entry,
- 1, 2, 2, 3, GTK_FILL, GTK_FILL, 4, 4);
+ table_attach (table, username_entry,
+ 1, 2, 2, 3, GTK_FILL, GTK_FILL, 4, 4);
password_label = gtk_label_new (_("Password:"));
- gtk_misc_set_alignment (GTK_MISC (password_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (table), password_label,
- 0, 1, 3, 4, GTK_FILL, GTK_FILL, 4, 4);
+ set_alignment (password_label, 1., 0.5);
+ table_attach (table, password_label,
+ 0, 1, 3, 4, GTK_FILL, GTK_FILL, 4, 4);
password_entry = gtk_entry_new ();
gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
#ifdef GTK_INPUT_PURPOSE_PASSWORD
@@ -216,53 +317,57 @@ create_connection_dialog (struct config *config)
#endif
if (config->password != NULL)
gtk_entry_set_text (GTK_ENTRY (password_entry), config->password);
- gtk_table_attach (GTK_TABLE (table), password_entry,
- 1, 2, 3, 4, GTK_FILL, GTK_FILL, 4, 4);
+ table_attach (table, password_entry,
+ 1, 2, 3, 4, GTK_FILL, GTK_FILL, 4, 4);
identity_label = gtk_label_new (_("SSH Identity URL:"));
- gtk_misc_set_alignment (GTK_MISC (identity_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (table), identity_label,
- 0, 1, 4, 5, GTK_FILL, GTK_FILL, 4, 4);
+ set_alignment (identity_label, 1., 0.5);
+ table_attach (table, identity_label,
+ 0, 1, 4, 5, GTK_FILL, GTK_FILL, 4, 4);
identity_entry = gtk_entry_new ();
if (config->identity_url != NULL)
gtk_entry_set_text (GTK_ENTRY (identity_entry), config->identity_url);
- gtk_table_attach (GTK_TABLE (table), identity_entry,
- 1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4);
+ table_attach (table, identity_entry,
+ 1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4);
identity_tip_label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (identity_tip_label),
_("<i>If using password authentication, leave the SSH
Identity URL blank</i>"));
gtk_label_set_line_wrap (GTK_LABEL (identity_tip_label), TRUE);
- gtk_table_attach (GTK_TABLE (table), identity_tip_label,
- 1, 2, 5, 6, GTK_FILL, GTK_FILL, 4, 4);
+ table_attach (table, identity_tip_label,
+ 1, 2, 5, 6, GTK_FILL, GTK_FILL, 4, 4);
sudo_button =
gtk_check_button_new_with_label (_("Use sudo when running virt-v2v"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sudo_button),
config->sudo);
- gtk_table_attach (GTK_TABLE (table), sudo_button,
- 1, 2, 6, 7, GTK_FILL, GTK_FILL, 4, 4);
+ table_attach (table, sudo_button,
+ 1, 2, 6, 7, GTK_FILL, GTK_FILL, 4, 4);
- test_hbox = gtk_hbox_new (FALSE, 0);
+ hbox_new (test_hbox, FALSE, 0);
test = gtk_button_new_with_label (_("Test connection"));
gtk_box_pack_start (GTK_BOX (test_hbox), test, TRUE, FALSE, 0);
- spinner_hbox = gtk_hbox_new (FALSE, 10);
+ hbox_new (spinner_hbox, FALSE, 10);
spinner = gtk_spinner_new ();
gtk_box_pack_start (GTK_BOX (spinner_hbox), spinner, FALSE, FALSE, 0);
spinner_message = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (spinner_message), TRUE);
- gtk_misc_set_padding (GTK_MISC (spinner_message), 10, 10);
+ set_padding (spinner_message, 10, 10);
gtk_box_pack_start (GTK_BOX (spinner_hbox), spinner_message, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (conn_dlg)->vbox),
- intro, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (conn_dlg)->vbox),
- table, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (conn_dlg)->vbox),
- test_hbox, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (conn_dlg)->vbox),
- spinner_hbox, TRUE, TRUE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (conn_dlg))),
+ intro, TRUE, TRUE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (conn_dlg))),
+ table, TRUE, TRUE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (conn_dlg))),
+ test_hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (conn_dlg))),
+ spinner_hbox, TRUE, TRUE, 0);
/* Buttons. */
gtk_dialog_add_buttons (GTK_DIALOG (conn_dlg),
@@ -303,7 +408,7 @@ show_connection_dialog (void)
/* Show everything except the spinner. */
gtk_widget_show_all (conn_dlg);
- gtk_widget_hide_all (spinner_hbox);
+ gtk_widget_hide (spinner_hbox);
}
/**
@@ -396,43 +501,84 @@ test_connection_thread (void *data)
struct config *copy = data;
int r;
- gdk_threads_enter ();
+ g_idle_add (start_spinner, NULL);
+
+ wait_network_online (copy);
+ r = test_connection (copy);
+ free_config (copy);
+
+ g_idle_add (stop_spinner, NULL);
+
+ if (r == -1)
+ g_idle_add (test_connection_error, NULL);
+ else
+ g_idle_add (test_connection_ok, NULL);
+
+ /* Thread is detached anyway, so no one is waiting for the status. */
+ return NULL;
+}
+
+/**
+ * Idle task called from C<test_connection_thread> (but run on the
+ * main thread) to start the spinner in the connection dialog.
+ */
+static gboolean
+start_spinner (gpointer user_data)
+{
gtk_label_set_text (GTK_LABEL (spinner_message),
_("Testing the connection to the conversion server
..."));
gtk_spinner_start (GTK_SPINNER (spinner));
- gdk_threads_leave ();
+ return FALSE;
+}
- wait_network_online (copy);
- r = test_connection (copy);
- free_config (copy);
-
- gdk_threads_enter ();
+/**
+ * Idle task called from C<test_connection_thread> (but run on the
+ * main thread) to stop the spinner in the connection dialog.
+ */
+static gboolean
+stop_spinner (gpointer user_data)
+{
gtk_spinner_stop (GTK_SPINNER (spinner));
+ return FALSE;
+}
- if (r == -1) {
- /* Error testing the connection. */
- const char *err = get_ssh_error ();
+/**
+ * Idle task called from C<test_connection_thread> (but run on the
+ * main thread) when there is an error. Display the error message and
+ * disable the C<Next> button so the user is forced to correct it.
+ */
+static gboolean
+test_connection_error (gpointer user_data)
+{
+ const char *err = get_ssh_error ();
- gtk_label_set_text (GTK_LABEL (spinner_message), err);
- /* Disable the Next button. */
- gtk_widget_set_sensitive (next_button, FALSE);
- }
- else {
- /* Connection is good. */
- gtk_label_set_text (GTK_LABEL (spinner_message),
- _("Connected to the conversion server.\n"
- "Press the \"Next\" button to configure the
conversion process."));
- /* Enable the Next button. */
- gtk_widget_set_sensitive (next_button, TRUE);
- gtk_widget_grab_focus (next_button);
+ gtk_label_set_text (GTK_LABEL (spinner_message), err);
+ /* Disable the Next button. */
+ gtk_widget_set_sensitive (next_button, FALSE);
- /* Update the information in the conversion dialog. */
- set_info_label ();
- }
- gdk_threads_leave ();
+ return FALSE;
+}
- /* Thread is detached anyway, so no one is waiting for the status. */
- return NULL;
+/**
+ * Idle task called from C<test_connection_thread> (but run on the
+ * main thread) when the connection test was successful.
+ */
+static gboolean
+test_connection_ok (gpointer user_data)
+{
+ gtk_label_set_text
+ (GTK_LABEL (spinner_message),
+ _("Connected to the conversion server.\n"
+ "Press the \"Next\" button to configure the conversion
process."));
+
+ /* Enable the Next button. */
+ gtk_widget_set_sensitive (next_button, TRUE);
+ gtk_widget_grab_focus (next_button);
+
+ /* Update the information in the conversion dialog. */
+ set_info_label ();
+
+ return FALSE;
}
/**
@@ -548,55 +694,55 @@ create_conversion_dialog (struct config *config)
gtk_widget_set_size_request (conv_dlg, 900, 560);
/* The main dialog area. */
- hbox = gtk_hbox_new (TRUE, 1);
- left_vbox = gtk_vbox_new (FALSE, 1);
- right_vbox = gtk_vbox_new (TRUE, 1);
+ hbox_new (hbox, TRUE, 1);
+ vbox_new (left_vbox, FALSE, 1);
+ vbox_new (right_vbox, TRUE, 1);
/* The left column: target properties and output options. */
target_frame = gtk_frame_new (_("Target properties"));
gtk_container_set_border_width (GTK_CONTAINER (target_frame), 4);
- target_vbox = gtk_vbox_new (FALSE, 1);
+ vbox_new (target_vbox, FALSE, 1);
- target_tbl = gtk_table_new (3, 3, FALSE);
+ table_new (target_tbl, 3, 3);
guestname_label = gtk_label_new (_("Name:"));
- gtk_misc_set_alignment (GTK_MISC (guestname_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (target_tbl), guestname_label,
- 0, 1, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (guestname_label, 1., 0.5);
+ table_attach (target_tbl, guestname_label,
+ 0, 1, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
guestname_entry = gtk_entry_new ();
if (config->guestname != NULL)
gtk_entry_set_text (GTK_ENTRY (guestname_entry), config->guestname);
- gtk_table_attach (GTK_TABLE (target_tbl), guestname_entry,
- 1, 2, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (target_tbl, guestname_entry,
+ 1, 2, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
vcpus_label = gtk_label_new (_("# vCPUs:"));
- gtk_misc_set_alignment (GTK_MISC (vcpus_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (target_tbl), vcpus_label,
- 0, 1, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (vcpus_label, 1., 0.5);
+ table_attach (target_tbl, vcpus_label,
+ 0, 1, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
vcpus_entry = gtk_entry_new ();
snprintf (vcpus_str, sizeof vcpus_str, "%d", config->vcpus);
gtk_entry_set_text (GTK_ENTRY (vcpus_entry), vcpus_str);
- gtk_table_attach (GTK_TABLE (target_tbl), vcpus_entry,
- 1, 2, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (target_tbl, vcpus_entry,
+ 1, 2, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
vcpus_warning = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
GTK_ICON_SIZE_BUTTON);
- gtk_table_attach (GTK_TABLE (target_tbl), vcpus_warning,
- 2, 3, 1, 2, 0, 0, 1, 1);
+ table_attach (target_tbl, vcpus_warning,
+ 2, 3, 1, 2, 0, 0, 1, 1);
memory_label = gtk_label_new (_("Memory (MB):"));
- gtk_misc_set_alignment (GTK_MISC (memory_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (target_tbl), memory_label,
- 0, 1, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (memory_label, 1., 0.5);
+ table_attach (target_tbl, memory_label,
+ 0, 1, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
memory_entry = gtk_entry_new ();
snprintf (memory_str, sizeof memory_str, "%" PRIu64,
config->memory / 1024 / 1024);
gtk_entry_set_text (GTK_ENTRY (memory_entry), memory_str);
- gtk_table_attach (GTK_TABLE (target_tbl), memory_entry,
- 1, 2, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (target_tbl, memory_entry,
+ 1, 2, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
memory_warning = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
GTK_ICON_SIZE_BUTTON);
- gtk_table_attach (GTK_TABLE (target_tbl), memory_warning,
- 2, 3, 2, 3, 0, 0, 1, 1);
+ table_attach (target_tbl, memory_warning,
+ 2, 3, 2, 3, 0, 0, 1, 1);
gtk_box_pack_start (GTK_BOX (target_vbox), target_tbl, TRUE, TRUE, 0);
@@ -612,56 +758,56 @@ create_conversion_dialog (struct config *config)
output_frame = gtk_frame_new (_("Virt-v2v output options"));
gtk_container_set_border_width (GTK_CONTAINER (output_frame), 4);
- output_vbox = gtk_vbox_new (FALSE, 1);
+ vbox_new (output_vbox, FALSE, 1);
- output_tbl = gtk_table_new (5, 2, FALSE);
+ table_new (output_tbl, 5, 2);
o_label = gtk_label_new (_("Output to (-o):"));
- gtk_misc_set_alignment (GTK_MISC (o_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (output_tbl), o_label,
- 0, 1, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (o_label, 1., 0.5);
+ table_attach (output_tbl, o_label,
+ 0, 1, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
o_combo = gtk_combo_box_text_new ();
gtk_widget_set_tooltip_markup (o_combo, _("<b>libvirt</b> means send
the converted guest to libvirt-managed KVM on the conversion server.
<b>local</b> means put it in a directory on the conversion server.
<b>rhev</b> means write it to RHEV-M/oVirt. <b>glance</b> means
write it to OpenStack Glance. See the virt-v2v(1) manual page for more information about
output options."));
repopulate_output_combo (config);
- gtk_table_attach (GTK_TABLE (output_tbl), o_combo,
- 1, 2, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (output_tbl, o_combo,
+ 1, 2, 0, 1, GTK_FILL, GTK_FILL, 1, 1);
oc_label = gtk_label_new (_("Output conn. (-oc):"));
- gtk_misc_set_alignment (GTK_MISC (oc_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (output_tbl), oc_label,
- 0, 1, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (oc_label, 1., 0.5);
+ table_attach (output_tbl, oc_label,
+ 0, 1, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
oc_entry = gtk_entry_new ();
gtk_widget_set_tooltip_markup (oc_entry, _("For <b>libvirt</b> only,
the libvirt connection URI, or leave blank to add the guest to the default libvirt
instance on the conversion server. For others, leave this field blank."));
if (config->output_connection != NULL)
gtk_entry_set_text (GTK_ENTRY (oc_entry), config->output_connection);
- gtk_table_attach (GTK_TABLE (output_tbl), oc_entry,
- 1, 2, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (output_tbl, oc_entry,
+ 1, 2, 1, 2, GTK_FILL, GTK_FILL, 1, 1);
os_label = gtk_label_new (_("Output storage (-os):"));
- gtk_misc_set_alignment (GTK_MISC (os_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (output_tbl), os_label,
- 0, 1, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (os_label, 1., 0.5);
+ table_attach (output_tbl, os_label,
+ 0, 1, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
os_entry = gtk_entry_new ();
gtk_widget_set_tooltip_markup (os_entry, _("For <b>local</b>, put the
directory name on the conversion server. For <b>rhev</b>, put the Export
Storage Domain (server:/mountpoint). For others, leave this field blank."));
if (config->output_storage != NULL)
gtk_entry_set_text (GTK_ENTRY (os_entry), config->output_storage);
- gtk_table_attach (GTK_TABLE (output_tbl), os_entry,
- 1, 2, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (output_tbl, os_entry,
+ 1, 2, 2, 3, GTK_FILL, GTK_FILL, 1, 1);
of_label = gtk_label_new (_("Output format (-of):"));
- gtk_misc_set_alignment (GTK_MISC (of_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (output_tbl), of_label,
- 0, 1, 3, 4, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (of_label, 1., 0.5);
+ table_attach (output_tbl, of_label,
+ 0, 1, 3, 4, GTK_FILL, GTK_FILL, 1, 1);
of_entry = gtk_entry_new ();
gtk_widget_set_tooltip_markup (of_entry, _("The output disk format, typically
<b>raw</b> or <b>qcow2</b>. If blank, defaults to
<b>raw</b>."));
if (config->output_format != NULL)
gtk_entry_set_text (GTK_ENTRY (of_entry), config->output_format);
- gtk_table_attach (GTK_TABLE (output_tbl), of_entry,
- 1, 2, 3, 4, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (output_tbl, of_entry,
+ 1, 2, 3, 4, GTK_FILL, GTK_FILL, 1, 1);
oa_label = gtk_label_new (_("Output allocation (-oa):"));
- gtk_misc_set_alignment (GTK_MISC (oa_label), 1., 0.5);
- gtk_table_attach (GTK_TABLE (output_tbl), oa_label,
- 0, 1, 4, 5, GTK_FILL, GTK_FILL, 1, 1);
+ set_alignment (oa_label, 1., 0.5);
+ table_attach (output_tbl, oa_label,
+ 0, 1, 4, 5, GTK_FILL, GTK_FILL, 1, 1);
oa_combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (oa_combo),
"sparse");
@@ -675,8 +821,8 @@ create_conversion_dialog (struct config *config)
gtk_combo_box_set_active (GTK_COMBO_BOX (oa_combo), 0);
break;
}
- gtk_table_attach (GTK_TABLE (output_tbl), oa_combo,
- 1, 2, 4, 5, GTK_FILL, GTK_FILL, 1, 1);
+ table_attach (output_tbl, oa_combo,
+ 1, 2, 4, 5, GTK_FILL, GTK_FILL, 1, 1);
debug_button =
gtk_check_button_new_with_label (_("Enable server-side debugging\n"
@@ -691,7 +837,7 @@ create_conversion_dialog (struct config *config)
info_frame = gtk_frame_new (_("Information"));
gtk_container_set_border_width (GTK_CONTAINER (info_frame), 4);
info_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (info_label), 0.1, 0.5);
+ set_alignment (info_label, 0.1, 0.5);
set_info_label ();
gtk_container_add (GTK_CONTAINER (info_frame), info_label);
@@ -704,8 +850,7 @@ create_conversion_dialog (struct config *config)
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
disks_list = gtk_tree_view_new ();
populate_disks (GTK_TREE_VIEW (disks_list));
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (disks_sw),
- disks_list);
+ scrolled_window_add_with_viewport (disks_sw, disks_list);
gtk_container_add (GTK_CONTAINER (disks_frame), disks_sw);
removable_frame = gtk_frame_new (_("Removable media"));
@@ -716,8 +861,7 @@ create_conversion_dialog (struct config *config)
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
removable_list = gtk_tree_view_new ();
populate_removable (GTK_TREE_VIEW (removable_list));
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (removable_sw),
- removable_list);
+ scrolled_window_add_with_viewport (removable_sw, removable_list);
gtk_container_add (GTK_CONTAINER (removable_frame), removable_sw);
interfaces_frame = gtk_frame_new (_("Network interfaces"));
@@ -732,8 +876,7 @@ create_conversion_dialog (struct config *config)
G_CALLBACK (maybe_identify_click), NULL);
gtk_widget_set_tooltip_markup (interfaces_list, _("Left click on an interface name
to flash the light on the physical interface."));
populate_interfaces (GTK_TREE_VIEW (interfaces_list));
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (interfaces_sw),
- interfaces_list);
+ scrolled_window_add_with_viewport (interfaces_sw, interfaces_list);
gtk_container_add (GTK_CONTAINER (interfaces_frame), interfaces_sw);
/* Pack the top level dialog. */
@@ -747,8 +890,9 @@ create_conversion_dialog (struct config *config)
gtk_box_pack_start (GTK_BOX (hbox), left_vbox, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), right_vbox, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (conv_dlg)->vbox),
- hbox, TRUE, TRUE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (conv_dlg))),
+ hbox, TRUE, TRUE, 0);
/* Buttons. */
gtk_dialog_add_buttons (GTK_DIALOG (conv_dlg),
@@ -1415,11 +1559,12 @@ get_memory_from_conv_dlg (void)
/*----------------------------------------------------------------------*/
/* Running dialog. */
-static void set_log_dir (const char *remote_dir);
-static void set_status (const char *msg);
-static void add_v2v_output (const char *msg);
-static void add_v2v_output_2 (const char *msg, size_t len);
+static gboolean set_log_dir (gpointer remote_dir);
+static gboolean set_status (gpointer msg);
+static gboolean add_v2v_output (gpointer msg);
static void *start_conversion_thread (void *data);
+static gboolean conversion_error (gpointer user_data);
+static gboolean conversion_finished (gpointer user_data);
static void cancel_conversion_clicked (GtkWidget *w, gpointer data);
static void reboot_clicked (GtkWidget *w, gpointer data);
static gboolean close_running_dialog (GtkWidget *w, GdkEvent *event, gpointer data);
@@ -1444,23 +1589,27 @@ create_running_dialog (void)
v2v_output = gtk_text_view_new ();
gtk_text_view_set_editable (GTK_TEXT_VIEW (v2v_output), FALSE);
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (v2v_output), GTK_WRAP_CHAR);
+ /* XXX Gtk3 ignores this, why? */
gtk_widget_set_size_request (v2v_output, 700, 400);
log_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (log_label), 0., 0.5);
- gtk_misc_set_padding (GTK_MISC (log_label), 10, 10);
+ set_alignment (log_label, 0., 0.5);
+ set_padding (log_label, 10, 10);
set_log_dir (NULL);
status_label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (status_label), 0., 0.5);
- gtk_misc_set_padding (GTK_MISC (status_label), 10, 10);
+ set_alignment (status_label, 0., 0.5);
+ set_padding (status_label, 10, 10);
gtk_container_add (GTK_CONTAINER (v2v_output_sw), v2v_output);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (run_dlg)->vbox),
- v2v_output_sw, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (run_dlg)->vbox),
- log_label, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (run_dlg)->vbox),
- status_label, TRUE, TRUE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (run_dlg))),
+ v2v_output_sw, TRUE, TRUE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (run_dlg))),
+ log_label, TRUE, TRUE, 0);
+ gtk_box_pack_start
+ (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (run_dlg))),
+ status_label, TRUE, TRUE, 0);
/* Buttons. */
gtk_dialog_add_buttons (GTK_DIALOG (run_dlg),
@@ -1499,9 +1648,19 @@ show_running_dialog (void)
gtk_widget_set_sensitive (reboot_button, FALSE);
}
-static void
-set_log_dir (const char *remote_dir)
+/**
+ * Display the remote log directory in the running dialog.
+ *
+ * If this isn't called from the main thread, then you must only
+ * call it via an idle task (C<g_idle_add>).
+ *
+ * B<NB:> This frees the remote_dir (C<user_data> pointer) which was
+ * strdup'd in C<notify_ui_callback>.
+ */
+static gboolean
+set_log_dir (gpointer user_data)
{
+ CLEANUP_FREE const char *remote_dir = user_data;
CLEANUP_FREE char *msg;
if (asprintf (&msg,
@@ -1513,45 +1672,70 @@ set_log_dir (const char *remote_dir)
error (EXIT_FAILURE, errno, "asprintf");
gtk_label_set_text (GTK_LABEL (log_label), msg);
+
+ return FALSE;
}
-static void
-set_status (const char *msg)
+/**
+ * Display the conversion status in the running dialog.
+ *
+ * If this isn't called from the main thread, then you must only
+ * call it via an idle task (C<g_idle_add>).
+ *
+ * B<NB:> This frees the message (C<user_data> pointer) which was
+ * strdup'd in C<notify_ui_callback>.
+ */
+static gboolean
+set_status (gpointer user_data)
{
+ CLEANUP_FREE const char *msg = user_data;
+
gtk_label_set_text (GTK_LABEL (status_label), msg);
+
+ return FALSE;
}
+static void add_v2v_output_helper (const char *msg, size_t len);
+
/**
* Append output from the virt-v2v process to the buffer, and scroll
* to ensure it is visible.
+ *
+ * If this isn't called from the main thread, then you must only
+ * call it via an idle task (C<g_idle_add>).
+ *
+ * B<NB:> This frees the message (C<user_data> pointer) which was
+ * strdup'd in C<notify_ui_callback>.
*/
-static void
-add_v2v_output (const char *msg)
+static gboolean
+add_v2v_output (gpointer user_data)
{
+ CLEANUP_FREE const char *msg = user_data;
static size_t linelen = 0;
const char *p0, *p;
- /* Gtk2 (in ~ Fedora 23) has a regression where it takes much
- * longer to display long lines, to the point where the virt-p2v
- * UI would still be slowly display kernel modules while the
- * conversion had finished. For this reason, arbitrarily break
- * long lines.
+ /* Gtk2 (in ~ Fedora 23) has a regression where it takes much longer
+ * to display long lines, to the point where the virt-p2v UI would
+ * still be slowly displaying kernel modules while the conversion
+ * had finished. For this reason, arbitrarily break long lines.
*/
for (p0 = p = msg; *p; ++p) {
linelen++;
if (*p == '\n' || linelen > 1024) {
- add_v2v_output_2 (p0, p-p0+1);
+ add_v2v_output_helper (p0, p-p0+1);
if (*p != '\n')
- add_v2v_output_2 ("\n", 1);
+ add_v2v_output_helper ("\n", 1);
linelen = 0;
p0 = p+1;
}
}
- add_v2v_output_2 (p0, p-p0);
+ add_v2v_output_helper (p0, p-p0);
+
+ return FALSE;
}
static void
-add_v2v_output_2 (const char *msg, size_t len)
+add_v2v_output_helper (const char *msg, size_t len)
{
GtkTextBuffer *buf;
GtkTextIter iter;
@@ -1689,73 +1873,108 @@ start_conversion_thread (void *data)
{
struct config *copy = data;
int r;
- GtkWidget *dlg;
r = start_conversion (copy, notify_ui_callback);
free_config (copy);
- gdk_threads_enter ();
-
- if (r == -1) {
- const char *err = get_conversion_error ();
-
- dlg = gtk_message_dialog_new (GTK_WINDOW (run_dlg),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- _("Conversion failed: %s"), err);
- gtk_window_set_title (GTK_WINDOW (dlg), _("Conversion failed"));
- gtk_dialog_run (GTK_DIALOG (dlg));
- gtk_widget_destroy (dlg);
- }
- else {
- dlg = gtk_message_dialog_new (GTK_WINDOW (run_dlg),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_INFO,
- GTK_BUTTONS_OK,
- _("The conversion was successful."));
- gtk_window_set_title (GTK_WINDOW (dlg), _("Conversion was successful"));
- gtk_dialog_run (GTK_DIALOG (dlg));
- gtk_widget_destroy (dlg);
- }
-
- /* Disable the cancel button. */
- gtk_widget_set_sensitive (cancel_button, FALSE);
-
- /* Enable the reboot button. */
- gtk_widget_set_sensitive (reboot_button, TRUE);
-
- gdk_threads_leave ();
+ if (r == -1)
+ g_idle_add (conversion_error, NULL);
+ else
+ g_idle_add (conversion_finished, NULL);
/* Thread is detached anyway, so no one is waiting for the status. */
return NULL;
}
+/**
+ * Idle task called from C<start_conversion_thread> (but run on the
+ * main thread) when there was an error during the conversion.
+ */
+static gboolean
+conversion_error (gpointer user_data)
+{
+ const char *err = get_conversion_error ();
+ GtkWidget *dlg;
+
+ dlg = gtk_message_dialog_new (GTK_WINDOW (run_dlg),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Conversion failed: %s"), err);
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Conversion failed"));
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+
+ /* Disable the cancel button. */
+ gtk_widget_set_sensitive (cancel_button, FALSE);
+
+ /* Enable the reboot button. */
+ gtk_widget_set_sensitive (reboot_button, TRUE);
+
+ return FALSE;
+}
+
+/**
+ * Idle task called from C<start_conversion_thread> (but run on the
+ * main thread) when the conversion completed without errors.
+ */
+static gboolean
+conversion_finished (gpointer user_data)
+{
+ GtkWidget *dlg;
+
+ dlg = gtk_message_dialog_new (GTK_WINDOW (run_dlg),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ _("The conversion was successful."));
+ gtk_window_set_title (GTK_WINDOW (dlg), _("Conversion was successful"));
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+
+ /* Disable the cancel button. */
+ gtk_widget_set_sensitive (cancel_button, FALSE);
+
+ /* Enable the reboot button. */
+ gtk_widget_set_sensitive (reboot_button, TRUE);
+
+ return FALSE;
+}
+
+/**
+ * This is called from F<conversion.c>:C<start_conversion>
+ * when there is a status change or a log message.
+ */
static void
notify_ui_callback (int type, const char *data)
{
- gdk_threads_enter ();
+ /* Because we call the functions as idle callbacks which run
+ * in the main thread some time later, we must duplicate the
+ * 'data' parameter (which is always a \0-terminated string).
+ *
+ * This is freed by the idle task function.
+ */
+ char *copy = strdup (data);
switch (type) {
case NOTIFY_LOG_DIR:
- set_log_dir (data);
+ g_idle_add (set_log_dir, (gpointer) copy);
break;
case NOTIFY_REMOTE_MESSAGE:
- add_v2v_output (data);
+ g_idle_add (add_v2v_output, (gpointer) copy);
break;
case NOTIFY_STATUS:
- set_status (data);
+ g_idle_add (set_status, (gpointer) copy);
break;
default:
fprintf (stderr,
"%s: unknown message during conversion: type=%d data=%s\n",
guestfs_int_program_name, type, data);
+ free (copy);
}
-
- gdk_threads_leave ();
}
static gboolean
diff --git a/p2v/main.c b/p2v/main.c
index e1be311..ba371fc 100644
--- a/p2v/main.c
+++ b/p2v/main.c
@@ -138,8 +138,6 @@ main (int argc, char *argv[])
if (glib_check_version (2, 32, 0) != NULL) /* This checks < 2.32 */
g_thread_init (NULL);
#endif
- gdk_threads_init ();
- gdk_threads_enter ();
gui_possible = gtk_init_check (&argc, &argv);
for (;;) {
--
2.7.4