[gnome-screenshot] screenshot: add an application menu for the interactive window



commit fca6036f4642612fe649b04ebe839766c644fdbf
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Tue May 8 14:23:44 2012 -0400

    screenshot: add an application menu for the interactive window
    
    When started in interactive mode, the tool should behave as a real
    GNOME app, and use an application menu.
    This also allows us to remove the Help button from there, and move it to
    the application menu.
    Finally, the toplevel window is now a regular GtkApplicationWindow (not
    a GtkDialog), so it gained a real "Close" button we can use instead of
    the "Cancel" one we had before.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=674947

 src/gnome-screenshot.ui             |   16 -----
 src/screenshot-application.c        |  108 +++++++++++++++++++++++++++++-----
 src/screenshot-dialog.c             |   73 +++++++++++-------------
 src/screenshot-dialog.h             |   16 ++++-
 src/screenshot-interactive-dialog.c |   81 ++++++++++++++------------
 5 files changed, 182 insertions(+), 112 deletions(-)
---
diff --git a/src/gnome-screenshot.ui b/src/gnome-screenshot.ui
index 62f1265..7560e8b 100644
--- a/src/gnome-screenshot.ui
+++ b/src/gnome-screenshot.ui
@@ -3,17 +3,13 @@
 <interface>
   <object class="GtkDialog" id="toplevel">
     <property name="border_width">5</property>
-    <property name="title" translatable="yes">Save Screenshot</property>
     <property name="type">GTK_WINDOW_TOPLEVEL</property>
-    <property name="window_position">GTK_WIN_POS_NONE</property>
     <property name="modal">False</property>
-    <property name="resizable">False</property>
     <property name="destroy_with_parent">False</property>
     <property name="decorated">True</property>
     <property name="skip_taskbar_hint">False</property>
     <property name="skip_pager_hint">False</property>
     <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
-    <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
@@ -42,17 +38,6 @@
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="cancel_button">
-                <property name="visible">True</property>
-                <property name="can_default">True</property>
-                <property name="can_focus">True</property>
-                <property name="label">gtk-cancel</property>
-                <property name="use_stock">True</property>
-                <property name="relief">GTK_RELIEF_NORMAL</property>
-                <property name="focus_on_click">True</property>
-              </object>
-            </child>
-            <child>
               <object class="GtkButton" id="ok_button">
                 <property name="visible">True</property>
                 <property name="can_default">True</property>
@@ -238,7 +223,6 @@
       </object>
     </child>
     <action-widgets>
-      <action-widget response="-6">cancel_button</action-widget>
       <action-widget response="-5">ok_button</action-widget>
       <action-widget response="1">copy_button</action-widget>
     </action-widgets>
diff --git a/src/screenshot-application.c b/src/screenshot-application.c
index 3ddedb7..da438da 100644
--- a/src/screenshot-application.c
+++ b/src/screenshot-application.c
@@ -45,6 +45,26 @@
 
 G_DEFINE_TYPE (ScreenshotApplication, screenshot_application, GTK_TYPE_APPLICATION);
 
+static const gchar *app_menu =
+    "<interface>"
+    "  <menu id=\"app-menu\">"
+    "    <section>"
+    "      <item>"
+    "        <attribute name=\"action\">app.about</attribute>"
+    "	     <attribute name=\"label\" translatable=\"yes\">About Screenshot</attribute>"
+    "      </item>"
+    "      <item>"
+    "        <attribute name=\"action\">app.help</attribute>"
+    "	     <attribute name=\"label\" translatable=\"yes\">Help</attribute>"
+    "      </item>"
+    "      <item>"
+    "       <attribute name=\"action\">app.quit</attribute>"
+    "	    <attribute name=\"label\" translatable=\"yes\">Quit</attribute>"
+    "      </item>"
+    "    </section>"
+    "  <menu>"
+    "</interface>";
+
 static void screenshot_save_to_file (ScreenshotApplication *self);
 
 struct _ScreenshotApplicationPriv {
@@ -115,7 +135,7 @@ save_pixbuf_handle_success (ScreenshotApplication *self)
       ScreenshotDialog *dialog = self->priv->dialog;
 
       save_folder_to_settings (self);
-      gtk_widget_destroy (screenshot_dialog_get_toplevel (dialog));
+      gtk_widget_destroy (dialog->window);
     }
   else
     {
@@ -130,7 +150,6 @@ save_pixbuf_handle_error (ScreenshotApplication *self,
   if (screenshot_config->interactive)
     {
       ScreenshotDialog *dialog = self->priv->dialog;
-      GtkWidget *toplevel = screenshot_dialog_get_toplevel (dialog);
 
       screenshot_dialog_set_busy (dialog, FALSE);
 
@@ -144,7 +163,7 @@ save_pixbuf_handle_error (ScreenshotApplication *self,
                                            file_name, folder_name);
           gint response;
                                              
-          response = screenshot_show_dialog (GTK_WINDOW (toplevel),
+          response = screenshot_show_dialog (GTK_WINDOW (dialog->window),
                                              GTK_MESSAGE_WARNING,
                                              GTK_BUTTONS_YES_NO,
                                              _("Overwrite existing file?"),
@@ -165,14 +184,14 @@ save_pixbuf_handle_error (ScreenshotApplication *self,
         }
       else
         {
-          screenshot_show_dialog (GTK_WINDOW (toplevel),
+          screenshot_show_dialog (GTK_WINDOW (dialog->window),
                                   GTK_MESSAGE_ERROR,
                                   GTK_BUTTONS_OK,
                                   _("Unable to capture a screenshot"),
                                   _("Error creating file. Please choose another location and retry."));
         }
 
-      screenshot_dialog_focus_entry (dialog);
+      gtk_widget_grab_focus (dialog->filename_entry);
     }
   else
     {
@@ -315,7 +334,6 @@ build_filename_ready_cb (GObject *source,
                          gpointer user_data)
 {
   ScreenshotApplication *self = user_data;
-  GtkWidget *toplevel;
   GError *error = NULL;
 
   self->priv->save_uri = screenshot_build_filename_finish (res, &error);
@@ -346,12 +364,7 @@ build_filename_ready_cb (GObject *source,
   if (screenshot_config->interactive)
     {
       self->priv->dialog = screenshot_dialog_new (self->priv->screenshot, self->priv->save_uri);
-      toplevel = screenshot_dialog_get_toplevel (self->priv->dialog);
-      gtk_widget_show (toplevel);
-
-      gtk_application_add_window (GTK_APPLICATION (self), GTK_WINDOW (toplevel));
-  
-      g_signal_connect (toplevel,
+      g_signal_connect (self->priv->dialog->dialog,
                         "response",
                         G_CALLBACK (screenshot_dialog_response_cb),
                         self);
@@ -594,16 +607,19 @@ interactive_dialog_response_cb (GtkWidget *d,
 {
   ScreenshotApplication *self = user_data;
 
-  gtk_widget_destroy (d);
+  if (response != GTK_RESPONSE_HELP)
+    gtk_widget_destroy (d);
 
   switch (response)
     {
     case GTK_RESPONSE_DELETE_EVENT:
-    case GTK_RESPONSE_CANCEL:
       break;
     case GTK_RESPONSE_OK:
       screenshot_start (self);
       break;
+    case GTK_RESPONSE_HELP:
+      screenshot_display_help (GTK_WINDOW (d));
+      break;
     default:
       g_assert_not_reached ();
       break;
@@ -611,6 +627,55 @@ interactive_dialog_response_cb (GtkWidget *d,
 }
 
 static void
+action_quit (GSimpleAction *action,
+             GVariant *parameter,
+             gpointer user_data)
+{
+  GList *windows = gtk_application_get_windows (GTK_APPLICATION (user_data));
+  gtk_widget_destroy (g_list_nth_data (windows, 0));
+}
+
+static void
+action_help (GSimpleAction *action,
+             GVariant *parameter,
+             gpointer user_data)
+{
+  GList *windows = gtk_application_get_windows (GTK_APPLICATION (user_data));
+  screenshot_display_help (g_list_nth_data (windows, 0));
+}
+
+static void
+action_about (GSimpleAction *action,
+              GVariant *parameter,
+              gpointer user_data)
+{
+  const gchar *authors[] = {
+    "Emmanuele Bassi",
+    "Jonathan Blandford",
+    "Cosimo Cecchi",
+    NULL
+  };
+
+  GList *windows = gtk_application_get_windows (GTK_APPLICATION (user_data));
+  gtk_show_about_dialog (GTK_WINDOW (g_list_nth_data (windows, 0)),
+                         "version", VERSION,
+                         "authors", authors,
+                         "program-name", _("Screenshot"),
+                         "comments", _("Save images of your screen or individual windows"),
+                         "logo-icon-name", "applets-screenshooter",
+                         "translator-credits", _("translator-credits"),
+                         "license-type", GTK_LICENSE_GPL_2_0,
+                         "wrap-license", TRUE,
+                         NULL);
+}
+
+static GActionEntry action_entries[] = {
+  { "about", action_about, NULL, NULL, NULL },
+  { "help", action_help, NULL, NULL, NULL },
+  { "quit", action_quit, NULL, NULL, NULL }
+};
+
+static void
 screenshot_application_startup (GApplication *app)
 {
   ScreenshotApplication *self = SCREENSHOT_APPLICATION (app);
@@ -624,10 +689,21 @@ screenshot_application_startup (GApplication *app)
   if (screenshot_config->interactive)
     {
       GtkWidget *dialog;
+      GtkBuilder *builder;
+      GMenuModel *menu;
+
+      g_action_map_add_action_entries (G_ACTION_MAP (self), action_entries,
+                                       G_N_ELEMENTS (action_entries), self);
+
+      builder = gtk_builder_new ();
+      gtk_builder_add_from_string (builder, app_menu, -1, NULL);
+      menu = G_MENU_MODEL (gtk_builder_get_object (builder, "app-menu"));
+      gtk_application_set_app_menu (GTK_APPLICATION (self), menu);
+
+      g_object_unref (builder);
+      g_object_unref (menu);
 
       dialog = screenshot_interactive_dialog_new ();
-      gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dialog));
-      gtk_widget_show (dialog);
       g_signal_connect (dialog, "response",
                         G_CALLBACK (interactive_dialog_response_cb), self);
     }
diff --git a/src/screenshot-dialog.c b/src/screenshot-dialog.c
index b988c83..6501735 100644
--- a/src/screenshot-dialog.c
+++ b/src/screenshot-dialog.c
@@ -36,17 +36,6 @@ static GtkTargetEntry drag_types[] =
   { "image/png", 0, TYPE_IMAGE_PNG },
 };
 
-struct ScreenshotDialog
-{
-  GtkBuilder *ui;
-  GdkPixbuf *screenshot;
-  GdkPixbuf *preview_image;
-  GtkWidget *save_widget;
-  GtkWidget *filename_entry;
-  gint drag_x;
-  gint drag_y;
-};
-
 static void
 on_preview_draw (GtkWidget      *drawing_area,
                  cairo_t        *cr,
@@ -129,13 +118,20 @@ drag_begin (GtkWidget        *widget,
 			    dialog->drag_x, dialog->drag_y);
 }
 
+static void
+dialog_destroy_cb (GtkWidget *widget,
+                   gpointer user_data)
+{
+  ScreenshotDialog *dialog = user_data;
+  gtk_widget_destroy (dialog->window);
+}
 
 ScreenshotDialog *
 screenshot_dialog_new (GdkPixbuf *screenshot,
 		       char      *initial_uri)
 {
   ScreenshotDialog *dialog;
-  GtkWidget *toplevel;
+  GtkBuilder *ui;
   GtkWidget *preview_darea;
   GtkWidget *aspect_frame;
   GtkWidget *file_chooser_box;
@@ -157,11 +153,12 @@ screenshot_dialog_new (GdkPixbuf *screenshot,
   g_object_unref (parent_file);
 
   dialog = g_new0 (ScreenshotDialog, 1);
-
-  dialog-> ui = gtk_builder_new ();
-  res = gtk_builder_add_from_file (dialog->ui, UIDIR "/gnome-screenshot.ui", NULL);
   dialog->screenshot = screenshot;
 
+  ui = gtk_builder_new ();
+  gtk_builder_set_translation_domain (ui, GETTEXT_PACKAGE);
+  res = gtk_builder_add_from_file (ui, UIDIR "/gnome-screenshot.ui", NULL);
+
   if (res == 0)
     {
       GtkWidget *dialog;
@@ -175,19 +172,31 @@ screenshot_dialog_new (GdkPixbuf *screenshot,
       exit (1);
     }
 
-  gtk_builder_set_translation_domain (dialog->ui, GETTEXT_PACKAGE);
-
   width = gdk_pixbuf_get_width (screenshot);
   height = gdk_pixbuf_get_height (screenshot);
 
   width /= 5;
   height /= 5;
 
-  toplevel = GTK_WIDGET (gtk_builder_get_object (dialog->ui, "toplevel"));
-  aspect_frame = GTK_WIDGET (gtk_builder_get_object (dialog->ui, "aspect_frame"));
-  preview_darea = GTK_WIDGET (gtk_builder_get_object (dialog->ui, "preview_darea"));
-  dialog->filename_entry = GTK_WIDGET (gtk_builder_get_object (dialog->ui, "filename_entry"));
-  file_chooser_box = GTK_WIDGET (gtk_builder_get_object (dialog->ui, "file_chooser_box"));
+  dialog->window =
+    gtk_application_window_new (GTK_APPLICATION (g_application_get_default ()));
+  gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (dialog->window), FALSE);
+  gtk_window_set_resizable (GTK_WINDOW (dialog->window), FALSE);
+  gtk_window_set_title (GTK_WINDOW (dialog->window), _("Save Screenshot"));
+  gtk_window_set_position (GTK_WINDOW (dialog->window), GTK_WIN_POS_CENTER);
+  gtk_widget_realize (dialog->window);
+
+  dialog->dialog = GTK_WIDGET (gtk_builder_get_object (ui, "toplevel"));
+  gtk_widget_set_parent_window (dialog->dialog, gtk_widget_get_window (dialog->window));
+  gtk_container_add (GTK_CONTAINER (dialog->window), dialog->dialog);
+  g_signal_connect (dialog->dialog, "destroy",
+                    G_CALLBACK (dialog_destroy_cb), dialog);
+
+  aspect_frame = GTK_WIDGET (gtk_builder_get_object (ui, "aspect_frame"));
+  preview_darea = GTK_WIDGET (gtk_builder_get_object (ui, "preview_darea"));
+  dialog->filename_entry = GTK_WIDGET (gtk_builder_get_object (ui, "filename_entry"));
+  file_chooser_box = GTK_WIDGET (gtk_builder_get_object (ui, "file_chooser_box"));
+  g_object_unref (ui);
 
   dialog->save_widget = gtk_file_chooser_button_new (_("Select a folder"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
   gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog->save_widget), FALSE);
@@ -223,7 +232,7 @@ screenshot_dialog_new (GdkPixbuf *screenshot,
   g_signal_connect (G_OBJECT (preview_darea), "drag_data_get",
 		    G_CALLBACK (drag_data_get), dialog);
 
-  gtk_widget_show_all (toplevel);
+  gtk_widget_show_all (dialog->window);
 
   /* select the name of the file but leave out the extension if there's any;
    * the dialog must be realized for select_region to work
@@ -243,18 +252,6 @@ screenshot_dialog_new (GdkPixbuf *screenshot,
   return dialog;
 }
 
-void
-screenshot_dialog_focus_entry (ScreenshotDialog *dialog)
-{
-  gtk_widget_grab_focus (dialog->filename_entry);
-}
-
-GtkWidget *
-screenshot_dialog_get_toplevel (ScreenshotDialog *dialog)
-{
-  return GTK_WIDGET (gtk_builder_get_object (dialog->ui, "toplevel"));
-}
-
 char *
 screenshot_dialog_get_uri (ScreenshotDialog *dialog)
 {
@@ -308,11 +305,9 @@ void
 screenshot_dialog_set_busy (ScreenshotDialog *dialog,
 			    gboolean          busy)
 {
-  GtkWidget *toplevel;
   GdkWindow *window;
 
-  toplevel = screenshot_dialog_get_toplevel (dialog);
-  window = gtk_widget_get_window (toplevel);
+  window = gtk_widget_get_window (dialog->window);
 
   if (busy)
     {
@@ -327,7 +322,7 @@ screenshot_dialog_set_busy (ScreenshotDialog *dialog,
       gdk_window_set_cursor (window, NULL);
     }
 
-  gtk_widget_set_sensitive (toplevel, ! busy);
+  gtk_widget_set_sensitive (dialog->window, ! busy);
 
   gdk_flush ();
 }
diff --git a/src/screenshot-dialog.h b/src/screenshot-dialog.h
index 7741198..c47453b 100644
--- a/src/screenshot-dialog.h
+++ b/src/screenshot-dialog.h
@@ -22,19 +22,29 @@
 
 #include <gtk/gtk.h>
 
-typedef struct ScreenshotDialog ScreenshotDialog;
+typedef struct {
+  GdkPixbuf *screenshot;
+  GdkPixbuf *preview_image;
+
+  GtkWidget *window;
+  GtkWidget *dialog;
+  GtkWidget *save_widget;
+  GtkWidget *filename_entry;
+
+  gint drag_x;
+  gint drag_y;
+}  ScreenshotDialog;
 
 /* Keep in sync with the value defined in the UI file */
 #define SCREENSHOT_RESPONSE_COPY 1
 
 ScreenshotDialog *screenshot_dialog_new          (GdkPixbuf        *screenshot,
 						  char             *initial_uri);
-GtkWidget        *screenshot_dialog_get_toplevel (ScreenshotDialog *dialog);
+
 char             *screenshot_dialog_get_uri      (ScreenshotDialog *dialog);
 char             *screenshot_dialog_get_folder   (ScreenshotDialog *dialog);
 char             *screenshot_dialog_get_filename (ScreenshotDialog *dialog);
 void              screenshot_dialog_set_busy     (ScreenshotDialog *dialog,
 						  gboolean          busy);
-void              screenshot_dialog_focus_entry  (ScreenshotDialog *dialog);
 
 #endif /* __SCREENSHOT_DIALOG_H__ */
diff --git a/src/screenshot-interactive-dialog.c b/src/screenshot-interactive-dialog.c
index cb1c7fb..bd96504 100644
--- a/src/screenshot-interactive-dialog.c
+++ b/src/screenshot-interactive-dialog.c
@@ -50,23 +50,6 @@ typedef enum {
   SCREENSHOT_EFFECT_BORDER
 } ScreenshotEffectType;
 
-static void
-interactive_dialog_response_cb (GtkDialog *dialog,
-                                gint       response,
-                                gpointer   user_data)
-{
-  switch (response)
-    {
-    case GTK_RESPONSE_HELP:
-      g_signal_stop_emission_by_name (dialog, "response");
-      screenshot_display_help (GTK_WINDOW (dialog));
-      break;
-    default:
-      gtk_widget_hide (GTK_WIDGET (dialog));
-      break;
-    }
-}
-
 #define TARGET_TOGGLE_DESKTOP 0
 #define TARGET_TOGGLE_WINDOW  1
 #define TARGET_TOGGLE_AREA    2
@@ -429,19 +412,37 @@ create_screenshot_frame (GtkWidget   *outer_vbox,
   gtk_widget_show (label);
 }
 
+static void
+interactive_dialog_destroy_cb (GtkWidget *widget,
+                               gpointer user_data)
+{
+  GtkWidget *window = user_data;
+  gtk_widget_destroy (window);
+}
+
 GtkWidget *
 screenshot_interactive_dialog_new (void)
 {
-  GtkWidget *retval;
+  GtkWidget *window, *dialog;
   GtkWidget *main_vbox;
   GtkWidget *content_area;
-
-  retval = gtk_dialog_new ();
-  gtk_window_set_resizable (GTK_WINDOW (retval), FALSE);
-  gtk_container_set_border_width (GTK_CONTAINER (retval), 5);
-  content_area = gtk_dialog_get_content_area (GTK_DIALOG (retval));
+  gboolean shows_app_menu;
+  GtkSettings *settings;
+
+  window = gtk_application_window_new (GTK_APPLICATION (g_application_get_default ()));
+  gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (window), FALSE);
+  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+  gtk_window_set_title (GTK_WINDOW (window), _("Take Screenshot"));
+  gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
+  gtk_widget_realize (window);
+
+  dialog = gtk_dialog_new ();
+  gtk_widget_set_parent_window (dialog, gtk_widget_get_window (window));
+  gtk_container_add (GTK_CONTAINER (window), dialog);
+
+  gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
   gtk_box_set_spacing (GTK_BOX (content_area), 2);
-  gtk_window_set_title (GTK_WINDOW (retval), _("Take Screenshot"));
 
   /* main container */
   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
@@ -452,24 +453,28 @@ screenshot_interactive_dialog_new (void)
   create_screenshot_frame (main_vbox, _("Take Screenshot"));
   create_effects_frame (main_vbox, _("Effects"));
 
-  gtk_dialog_add_buttons (GTK_DIALOG (retval),
-                          GTK_STOCK_HELP, GTK_RESPONSE_HELP,
-                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                          _("Take _Screenshot"), GTK_RESPONSE_OK,
-                          NULL);
+  gtk_dialog_add_button (GTK_DIALOG (dialog),
+                         _("Take _Screenshot"), GTK_RESPONSE_OK);
 
-  gtk_dialog_set_default_response (GTK_DIALOG (retval), GTK_RESPONSE_OK);
+  /* add help as a dialog button if we're not showing the application menu */
+  settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
+  g_object_get (settings,
+                "gtk-shell-shows-app-menu", &shows_app_menu,
+                NULL);
+  if (!shows_app_menu)
+    gtk_dialog_add_button (GTK_DIALOG (dialog),
+                           GTK_STOCK_HELP, GTK_RESPONSE_HELP);
 
-  /* we need to block on "response" and keep showing the interactive
-   * dialog in case the user did choose "help"
-   */
-  g_signal_connect (retval, "response",
-                    G_CALLBACK (interactive_dialog_response_cb),
-                    NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
 
-  g_signal_connect (retval, "key-press-event",
+  g_signal_connect (dialog, "key-press-event",
                     G_CALLBACK (interactive_dialog_key_press_cb), 
                     NULL);
+  g_signal_connect (dialog, "destroy",
+                    G_CALLBACK (interactive_dialog_destroy_cb),
+                    window);
 
-  return retval;
+  gtk_widget_show_all (window);
+
+  return dialog;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]