[Libguestfs] [PATCH v2 1/2] p2v: turn Reboot button into a Shutdown popup menu button

Pino Toscano ptoscano at redhat.com
Tue Nov 6 11:51:29 UTC 2018


To ease adding a proper Shutdown action in the conversion dialog, turn
the current Reboot button into a button that pops a menu up, with Reboot
as the only available action.

The menu is implemented using a popover when using "recent" versions of
GLib, and GTK+ 3, because of all the APIs needed.  In older versions, a
simple toggle button with menu is used, which though needs a manual menu
firing when pressing the button itself (and not its side arrow).
---
 p2v/gui.c        | 97 +++++++++++++++++++++++++++++++++++++++++++-----
 p2v/virt-p2v.pod |  2 +-
 2 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/p2v/gui.c b/p2v/gui.c
index 7ec2900a8..10fb2939a 100644
--- a/p2v/gui.c
+++ b/p2v/gui.c
@@ -98,6 +98,10 @@
 #define MAX_SUPPORTED_VCPUS 160
 #define MAX_SUPPORTED_MEMORY_MB (UINT64_C (4000 * 1024))
 
+#if GLIB_CHECK_VERSION(2,32,0) && GTK_CHECK_VERSION(3,12,0)   /* glib >= 2.32 && gtk >= 3.12 */
+#define USE_POPOVERS
+#endif
+
 static void create_connection_dialog (struct config *);
 static void create_conversion_dialog (struct config *);
 static void create_running_dialog (void);
@@ -129,7 +133,7 @@ static GtkWidget *conv_dlg,
 /* The running dialog which is displayed when virt-v2v is running. */
 static GtkWidget *run_dlg,
   *v2v_output_sw, *v2v_output, *log_label, *status_label,
-  *cancel_button, *reboot_button;
+  *cancel_button, *shutdown_button;
 
 /* Colour tags used in the v2v_output GtkTextBuffer. */
 static GtkTextTag *v2v_output_tags[16];
@@ -1606,9 +1610,20 @@ 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_dialog (GtkWidget *w, gpointer data);
+#ifdef USE_POPOVERS
+static void activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data);
+#else
+static void shutdown_button_clicked (GtkToolButton *w, gpointer data);
+#endif
 static void reboot_clicked (GtkWidget *w, gpointer data);
 static gboolean close_running_dialog (GtkWidget *w, GdkEvent *event, gpointer data);
 
+#ifdef USE_POPOVERS
+static const GActionEntry shutdown_actions[] = {
+  { "reboot", activate_action, NULL, NULL, NULL },
+};
+#endif
+
 /**
  * Create the running dialog.
  *
@@ -1623,6 +1638,13 @@ create_running_dialog (void)
     { "black", "maroon", "green", "olive", "navy", "purple", "teal", "silver",
       "gray", "red", "lime", "yellow", "blue", "fuchsia", "cyan", "white" };
   GtkTextBuffer *buf;
+#ifdef USE_POPOVERS
+  GMenu *shutdown_menu;
+  GSimpleActionGroup *shutdown_group;
+#else
+  GtkWidget *shutdown_menu;
+  GtkWidget *reboot_menu_item;
+#endif
 
   run_dlg = gtk_dialog_new ();
   gtk_window_set_title (GTK_WINDOW (run_dlg), getprogname ());
@@ -1686,15 +1708,47 @@ create_running_dialog (void)
     (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (run_dlg))),
      status_label, TRUE, TRUE, 0);
 
+  /* Shutdown popup menu. */
+#ifdef USE_POPOVERS
+  shutdown_menu = g_menu_new ();
+  g_menu_append (shutdown_menu, _("_Reboot"), "shutdown.reboot");
+
+  shutdown_group = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (shutdown_group),
+                                   shutdown_actions,
+                                   G_N_ELEMENTS (shutdown_actions), NULL);
+#else
+  shutdown_menu = gtk_menu_new ();
+  reboot_menu_item = gtk_menu_item_new_with_mnemonic (_("_Reboot"));
+  gtk_menu_shell_append (GTK_MENU_SHELL (shutdown_menu), reboot_menu_item);
+  gtk_widget_show (reboot_menu_item);
+#endif
+
   /* Buttons. */
   gtk_dialog_add_buttons (GTK_DIALOG (run_dlg),
                           _("_Cancel conversion ..."), 1,
-                          _("_Reboot"), 2,
                           NULL);
   cancel_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (run_dlg), 1);
   gtk_widget_set_sensitive (cancel_button, FALSE);
-  reboot_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (run_dlg), 2);
-  gtk_widget_set_sensitive (reboot_button, FALSE);
+#ifdef USE_POPOVERS
+  shutdown_button = gtk_menu_button_new ();
+  gtk_button_set_use_underline (GTK_BUTTON (shutdown_button), TRUE);
+  gtk_button_set_label (GTK_BUTTON (shutdown_button), _("_Shutdown ..."));
+  gtk_button_set_always_show_image (GTK_BUTTON (shutdown_button), TRUE);
+  gtk_widget_insert_action_group (shutdown_button, "shutdown",
+                                  G_ACTION_GROUP (shutdown_group));
+  gtk_menu_button_set_use_popover (GTK_MENU_BUTTON (shutdown_button), TRUE);
+  gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (shutdown_button),
+                                  G_MENU_MODEL (shutdown_menu));
+#else
+  shutdown_button = GTK_WIDGET (gtk_menu_tool_button_new (NULL,
+                                                          _("_Shutdown ...")));
+  gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (shutdown_button), TRUE);
+  gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (shutdown_button),
+                                 shutdown_menu);
+#endif
+  gtk_widget_set_sensitive (shutdown_button, FALSE);
+  gtk_dialog_add_action_widget (GTK_DIALOG (run_dlg), shutdown_button, 2);
 
   /* Signals. */
   g_signal_connect_swapped (G_OBJECT (run_dlg), "delete_event",
@@ -1703,8 +1757,12 @@ create_running_dialog (void)
                             G_CALLBACK (gtk_main_quit), NULL);
   g_signal_connect (G_OBJECT (cancel_button), "clicked",
                     G_CALLBACK (cancel_conversion_dialog), NULL);
-  g_signal_connect (G_OBJECT (reboot_button), "clicked",
+#ifndef USE_POPOVERS
+  g_signal_connect (G_OBJECT (shutdown_button), "clicked",
+                    G_CALLBACK (shutdown_button_clicked), shutdown_menu);
+  g_signal_connect (G_OBJECT (reboot_menu_item), "activate",
                     G_CALLBACK (reboot_clicked), NULL);
+#endif
 }
 
 /**
@@ -1721,7 +1779,7 @@ show_running_dialog (void)
   gtk_widget_show_all (run_dlg);
   gtk_widget_set_sensitive (cancel_button, TRUE);
   if (is_iso_environment)
-    gtk_widget_set_sensitive (reboot_button, FALSE);
+    gtk_widget_set_sensitive (shutdown_button, FALSE);
 }
 
 /**
@@ -2077,9 +2135,9 @@ conversion_error (gpointer user_data)
   /* Disable the cancel button. */
   gtk_widget_set_sensitive (cancel_button, FALSE);
 
-  /* Enable the reboot button. */
+  /* Enable the shutdown button. */
   if (is_iso_environment)
-    gtk_widget_set_sensitive (reboot_button, TRUE);
+    gtk_widget_set_sensitive (shutdown_button, TRUE);
 
   return FALSE;
 }
@@ -2105,9 +2163,9 @@ conversion_finished (gpointer user_data)
   /* Disable the cancel button. */
   gtk_widget_set_sensitive (cancel_button, FALSE);
 
-  /* Enable the reboot button. */
+  /* Enable the shutdown button. */
   if (is_iso_environment)
-    gtk_widget_set_sensitive (reboot_button, TRUE);
+    gtk_widget_set_sensitive (shutdown_button, TRUE);
 
   return FALSE;
 }
@@ -2192,6 +2250,25 @@ cancel_conversion_dialog (GtkWidget *w, gpointer data)
   gtk_widget_destroy (dlg);
 }
 
+#ifdef USE_POPOVERS
+static void
+activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
+{
+  const char *action_name = g_action_get_name (G_ACTION (action));
+  if (STREQ (action_name, "reboot"))
+    reboot_clicked (NULL, user_data);
+}
+#else
+static void
+shutdown_button_clicked (GtkToolButton *w, gpointer data)
+{
+  GtkMenu *menu = data;
+
+  gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 1,
+                  gtk_get_current_event_time ());
+}
+#endif
+
 static void
 reboot_clicked (GtkWidget *w, gpointer data)
 {
diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod
index 48548f8c6..6535e8d7b 100644
--- a/p2v/virt-p2v.pod
+++ b/p2v/virt-p2v.pod
@@ -504,7 +504,7 @@ option.
 This flag is passed to virt-p2v when it is launched inside the
 virt-p2v ISO environment, ie. when it is running on a real physical
 machine (and thus not when testing).  It enables various dangerous
-features such as the Reboot button.
+features such as the Shutdown popup button.
 
 =item B<--nbd=server[,server...]>
 
-- 
2.17.2




More information about the Libguestfs mailing list