[gnome-screenshot] screenshot: port to GApplication



commit 07b354c2df075fc3e56ce0296873edbdaddc05e6
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Wed Jan 25 17:52:54 2012 -0500

    screenshot: port to GApplication
    
    This further cleans up the screenshot setup code, and will allow us to
    use GApplication facilities for unique application instead of using a X
    selection.

 src/Makefile.am                 |    3 +-
 src/gnome-screenshot.c          |  536 +--------------------------------
 src/gnome-screenshot.h          |   29 --
 src/screenshot-application.c    |  646 +++++++++++++++++++++++++++++++++++++++
 src/screenshot-application.h    |   55 ++++
 src/screenshot-area-selection.c |    9 +-
 src/screenshot-area-selection.h |    6 +-
 src/screenshot-utils.c          |    4 +-
 8 files changed, 724 insertions(+), 564 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 04d9d75..8f2b4ad 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,9 +13,10 @@ bin_PROGRAMS = \
 
 gnome_screenshot_SOURCES = \
 	gnome-screenshot.c		\
-	gnome-screenshot.h		\
 	cheese-flash.c			\
 	cheese-flash.h			\
+	screenshot-application.c	\
+	screenshot-application.h	\
 	screenshot-area-selection.c	\
 	screenshot-area-selection.h	\
 	screenshot-config.c		\
diff --git a/src/gnome-screenshot.c b/src/gnome-screenshot.c
index 3814070..76732d0 100644
--- a/src/gnome-screenshot.c
+++ b/src/gnome-screenshot.c
@@ -25,547 +25,27 @@
 /* MAYBE I LIED... -jrb */
 
 #include <config.h>
-#include <gdk/gdkx.h>
-#include <gdk/gdkkeysyms.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
 #include <locale.h>
-#include <glib/gi18n.h>
-#include <gio/gio.h>
-#include <pwd.h>
-#include <X11/Xutil.h>
 
-#include "gnome-screenshot.h"
-#include "screenshot-area-selection.h"
-#include "screenshot-config.h"
-#include "screenshot-filename-builder.h"
-#include "screenshot-interactive-dialog.h"
-#include "screenshot-shadow.h"
-#include "screenshot-utils.h"
-#include "screenshot-dialog.h"
-
-#define SCREENSHOOTER_ICON "applets-screenshooter"
-
-#define LAST_SAVE_DIRECTORY_KEY "last-save-directory"
-
-static GdkPixbuf *screenshot = NULL;
-
-/* Global variables*/
-static gchar *icc_profile_base64 = NULL;
-
-static void
-save_folder_to_settings (ScreenshotDialog *dialog)
-{
-  char *folder;
-
-  folder = screenshot_dialog_get_folder (dialog);
-  g_settings_set_string (screenshot_config->settings,
-                         LAST_SAVE_DIRECTORY_KEY, folder);
-
-  g_free (folder);
-}
-
-static void
-set_recent_entry (ScreenshotDialog *dialog)
-{
-  char *uri, *app_exec = NULL;
-  GtkRecentManager *recent;
-  GtkRecentData recent_data;
-  GAppInfo *app;
-  const char *exec_name = NULL;
-  static char * groups[2] = { "Graphics", NULL };
-
-  app = g_app_info_get_default_for_type ("image/png", TRUE);
-
-  if (!app) {
-    /* return early, as this would be an useless recent entry anyway. */
-    return;
-  }
-
-  uri = screenshot_dialog_get_uri (dialog);
-  recent = gtk_recent_manager_get_default ();
-  
-  exec_name = g_app_info_get_executable (app);
-  app_exec = g_strjoin (" ", exec_name, "%u", NULL);
-
-  recent_data.display_name = NULL;
-  recent_data.description = NULL;
-  recent_data.mime_type = "image/png";
-  recent_data.app_name = "GNOME Screenshot";
-  recent_data.app_exec = app_exec;
-  recent_data.groups = groups;
-  recent_data.is_private = FALSE;
-
-  gtk_recent_manager_add_full (recent, uri, &recent_data);
-
-  g_object_unref (app);
-  g_free (app_exec);
-  g_free (uri);
-}
-
-static void
-error_dialog_response_cb (GtkDialog *d,
-                          gint response,
-                          ScreenshotDialog *dialog)
-{
-  gtk_widget_destroy (GTK_WIDGET (d));
-
-  screenshot_dialog_focus_entry (dialog);
-}
-
-static void
-save_file_failed_error (ScreenshotDialog *dialog,
-                        GError *error)
-{
-  GtkWidget *toplevel;
-  GtkWidget *error_dialog;
-  char *folder;
-
-  toplevel = screenshot_dialog_get_toplevel (dialog);
-  screenshot_dialog_set_busy (dialog, FALSE);
-
-  /* we had an error, display a dialog to the user and let him choose
-   * another name/location to save the screenshot.
-   */      
-  folder = screenshot_dialog_get_folder (dialog);
-  error_dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel),
-                                         GTK_DIALOG_DESTROY_WITH_PARENT,
-                                         GTK_MESSAGE_ERROR,
-                                         GTK_BUTTONS_OK,
-                                         _("Error while saving screenshot"));
-
-  /* translators: first %s is the folder URI, second %s is the VFS error */
-  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog),
-                                            _("Impossible to save the screenshot "
-                                              "to %s.\n Error was %s.\n Please choose another "
-                                              "location and retry."), folder, error->message);
-  gtk_widget_show (error_dialog);
-  g_signal_connect (error_dialog,
-                    "response",
-                    G_CALLBACK (error_dialog_response_cb),
-                    dialog);
-
-  g_free (folder);
-}
-
-static void
-save_file_completed (ScreenshotDialog *dialog)
-{
-  GtkWidget *toplevel;
-
-  toplevel = screenshot_dialog_get_toplevel (dialog);
-
-  save_folder_to_settings (dialog);
-  set_recent_entry (dialog);
-  gtk_widget_destroy (toplevel);
-
-  /* we're done, stop the mainloop now */
-  gtk_main_quit ();
-}
-
-static void
-save_pixbuf_ready_cb (GObject *source,
-                      GAsyncResult *res,
-                      gpointer user_data)
-{
-  GError *error = NULL;
-  ScreenshotDialog *dialog = user_data;
-
-  gdk_pixbuf_save_to_stream_finish (res, &error);
-
-  if (error != NULL)
-    {
-      save_file_failed_error (dialog, error);
-      g_error_free (error);
-      return;
-    }
-
-  save_file_completed (dialog);
-}
-
-static void
-save_file_create_ready_cb (GObject *source,
-                           GAsyncResult *res,
-                           gpointer user_data)
-{
-  GFileOutputStream *os;
-  GError *error = NULL;
-  ScreenshotDialog *dialog = user_data;
-
-  os = g_file_create_finish (G_FILE (source), res, &error);
-
-  if (error != NULL)
-    {
-      save_file_failed_error (dialog, error);
-      g_error_free (error);
-      return;
-    }
-
-  if (icc_profile_base64 != NULL)
-    gdk_pixbuf_save_to_stream_async (screenshot,
-                                     G_OUTPUT_STREAM (os),
-                                     "png", NULL,
-                                     save_pixbuf_ready_cb, dialog,
-                                     "icc-profile", icc_profile_base64,
-                                     "tEXt::Software", "gnome-screenshot",
-                                     NULL);
-  else
-    gdk_pixbuf_save_to_stream_async (screenshot,
-                                     G_OUTPUT_STREAM (os),
-                                     "png", NULL,
-                                     save_pixbuf_ready_cb, dialog,
-                                     "tEXt::Software", "gnome-screenshot",
-                                     NULL);
-
-  g_object_unref (os);
-}
-
-static void
-try_to_save (ScreenshotDialog *dialog)
-{
-  gchar *target_uri;
-  GFile *target_file;
-
-  screenshot_dialog_set_busy (dialog, TRUE);
-
-  target_uri = screenshot_dialog_get_uri (dialog);
-  target_file = g_file_new_for_uri (target_uri);
-
-  g_file_create_async (target_file,
-                       G_FILE_CREATE_NONE,
-                       G_PRIORITY_DEFAULT,
-                       NULL,
-                       save_file_create_ready_cb, dialog);
-
-  g_object_unref (target_file);
-  g_free (target_uri);
-}
-
-static void
-screenshot_save_to_clipboard (void)
-{
-  GtkClipboard *clipboard;
-
-  clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
-                                             GDK_SELECTION_CLIPBOARD);
-  gtk_clipboard_set_image (clipboard, screenshot);
-}
-
-static void
-screenshot_dialog_response_cb (GtkDialog *d,
-                               gint response_id,
-                               ScreenshotDialog *dialog)
-{
-  switch (response_id)
-    {
-    case GTK_RESPONSE_HELP:
-      screenshot_display_help (GTK_WINDOW (d));
-      break;
-    case GTK_RESPONSE_OK:
-      try_to_save (dialog);
-      break;
-    case SCREENSHOT_RESPONSE_COPY:
-      screenshot_save_to_clipboard ();
-      break;
-    default:
-      gtk_widget_destroy (GTK_WIDGET (d));
-      gtk_main_quit ();
-      break;
-    }
-}
-                               
-static void
-build_filename_ready_cb (GObject *source,
-                         GAsyncResult *res,
-                         gpointer user_data)
-{
-  GtkWidget *toplevel;
-  ScreenshotDialog *dialog;
-  GdkPixbuf *screenshot = user_data;
-  gchar *save_uri;
-  GError *error = NULL;
-
-  save_uri = screenshot_build_filename_finish (res, &error);
-
-  if (error != NULL)
-    {
-      g_critical ("Impossible to find a valid location to save the screenshot: %s",
-                  error->message);
-      g_error_free (error);
-
-      exit(1);
-    }
-
-  dialog = screenshot_dialog_new (screenshot, save_uri);
-  toplevel = screenshot_dialog_get_toplevel (dialog);
-  gtk_widget_show (toplevel);
-  
-  g_signal_connect (toplevel,
-                    "response",
-                    G_CALLBACK (screenshot_dialog_response_cb),
-                    dialog);
-
-  g_free (save_uri);
-}
-
-static void
-finish_prepare_screenshot (GdkRectangle *rectangle)
-{
-  screenshot = screenshot_get_pixbuf (rectangle);
-
-  if (screenshot == NULL)
-    {
-      screenshot_show_error_dialog (NULL,
-                                    _("Unable to take a screenshot of the current window"),
-                                    NULL);
-      exit (1);
-    }
-
-  if (screenshot_config->take_window_shot)
-    {
-      switch (screenshot_config->border_effect[0])
-        {
-        case 's': /* shadow */
-          screenshot_add_shadow (&screenshot);
-          break;
-        case 'b': /* border */
-          screenshot_add_border (&screenshot);
-          break;
-        case 'n': /* none */
-        default:
-          break;
-        }
-    }
-
-  if (screenshot_config->copy_to_clipboard)
-    {
-      screenshot_save_to_clipboard ();
-      gtk_main_quit ();
-
-      return;
-    }
-
-  /* FIXME: apply the ICC profile according to the preferences.
-   * org.gnome.ColorManager.GetProfileForWindow() does not exist anymore,
-   * so we probably need to fetch the color profile of the screen where
-   * the area/window was.
-   *
-   * screenshot_ensure_icc_profile (window);
-   */
-  screenshot_build_filename_async (screenshot_config->last_save_dir,
-                                   build_filename_ready_cb, screenshot);
-}
-
-static void
-rectangle_found_cb (GdkRectangle *rectangle)
-{
-  if (rectangle != NULL)
-    finish_prepare_screenshot (rectangle);
-  else
-    /* just quit here; user dismissed the rectangle with Esc */
-    gtk_main_quit ();
-}
-
-static gboolean
-prepare_screenshot_timeout (gpointer data)
-{
-  if (screenshot_config->take_area_shot)
-    screenshot_select_area_async (rectangle_found_cb);
-  else
-    finish_prepare_screenshot (NULL);
-
-  screenshot_save_config ();
-
-  return FALSE;
-}
-
-static void
-screenshot_start ()
-{
-  guint delay = screenshot_config->delay * 1000;
-
-  /* HACK: give time to the dialog to actually disappear.
-   * We don't have any way to tell when the compositor has finished 
-   * re-drawing.
-   */
-  if (delay == 0 && screenshot_config->interactive)
-    delay = 200;
-
-  if (delay > 0)
-    g_timeout_add (delay,
-                   prepare_screenshot_timeout,
-                   NULL);
-  else
-    g_idle_add (prepare_screenshot_timeout, NULL);
-}
-
-static void
-interactive_dialog_response_cb (GtkWidget *d,
-                                gint response,
-                                gpointer _user_data)
-{
-  gtk_widget_destroy (d);
-
-  switch (response)
-    {
-    case GTK_RESPONSE_DELETE_EVENT:
-    case GTK_RESPONSE_CANCEL:
-      gtk_main_quit ();
-      break;
-    case GTK_RESPONSE_OK:
-      screenshot_start ();
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-}
-
-static void
-register_screenshooter_icon (GtkIconFactory * factory)
-{
-  GtkIconSource *source;
-  GtkIconSet *icon_set;
-
-  source = gtk_icon_source_new ();
-  gtk_icon_source_set_icon_name (source, SCREENSHOOTER_ICON);
-
-  icon_set = gtk_icon_set_new ();
-  gtk_icon_set_add_source (icon_set, source);
-
-  gtk_icon_factory_add (factory, SCREENSHOOTER_ICON, icon_set);
-  gtk_icon_set_unref (icon_set);
-  gtk_icon_source_free (source);
-}
-
-static void
-screenshooter_init_stock_icons (void)
-{
-  GtkIconFactory *factory;
-
-  factory = gtk_icon_factory_new ();
-  gtk_icon_factory_add_default (factory);
-
-  register_screenshooter_icon (factory);
-  g_object_unref (factory);
-}
-
-static gboolean
-init_dbus_session (void)
-{
-  GError *error = NULL;
-  gboolean retval = TRUE;
-
-  g_assert (connection == NULL);
-
-  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-
-  if (error != NULL)
-    {
-      g_critical ("Unable to connect to the session bus: %s",
-                  error->message);
-      g_error_free (error);
-      retval = FALSE;
-    }
-
-  return retval;
-}
-
-static gboolean
-screenshot_app_init (void)
-{
-  gtk_window_set_default_icon_name (SCREENSHOOTER_ICON);
-  screenshooter_init_stock_icons ();
-
-  return init_dbus_session ();
-}
+#include "screenshot-application.h"
 
 /* main */
 int
 main (int argc, char *argv[])
 {
-  GOptionContext *context;
-  gboolean clipboard_arg = FALSE;
-  gboolean window_arg = FALSE;
-  gboolean area_arg = FALSE;
-  gboolean include_border_arg = FALSE;
-  gboolean disable_border_arg = FALSE;
-  gboolean interactive_arg = FALSE;
-  gchar *border_effect_arg = NULL;
-  guint delay_arg = 0;
-  GError *error = NULL;
-  gboolean res;
+  gint result;
+  ScreenshotApplication *app;
 
-  const GOptionEntry entries[] = {
-    { "clipboard", 'c', 0, G_OPTION_ARG_NONE, &clipboard_arg, N_("Send the grab directly to the clipboard"), NULL },
-    { "window", 'w', 0, G_OPTION_ARG_NONE, &window_arg, N_("Grab a window instead of the entire screen"), NULL },
-    { "area", 'a', 0, G_OPTION_ARG_NONE, &area_arg, N_("Grab an area of the screen instead of the entire screen"), NULL },
-    { "include-border", 'b', 0, G_OPTION_ARG_NONE, &include_border_arg, N_("Include the window border with the screenshot"), NULL },
-    { "remove-border", 'B', 0, G_OPTION_ARG_NONE, &disable_border_arg, N_("Remove the window border from the screenshot"), NULL },
-    { "delay", 'd', 0, G_OPTION_ARG_INT, &delay_arg, N_("Take screenshot after specified delay [in seconds]"), N_("seconds") },
-    { "border-effect", 'e', 0, G_OPTION_ARG_STRING, &border_effect_arg, N_("Effect to add to the border (shadow, border or none)"), N_("effect") },
-    { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive_arg, N_("Interactively set options"), NULL },
-    { NULL },
-  };
+  g_type_init ();
 
   setlocale (LC_ALL, "");
   bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
   textdomain (GETTEXT_PACKAGE);
 
-  context = g_option_context_new (_("Take a picture of the screen"));
-  g_option_context_set_ignore_unknown_options (context, FALSE);
-  g_option_context_set_help_enabled (context, TRUE);
-  g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
-  g_option_context_add_group (context, gtk_get_option_group (TRUE));
-
-  g_option_context_parse (context, &argc, &argv, &error);
-
-  if (error)
-    {
-      g_critical ("Unable to parse arguments: %s", error->message);
-      g_error_free (error);
-      g_option_context_free (context);
-      exit (1);
-    }
-
-  g_option_context_free (context);
-
-  res = screenshot_load_config (clipboard_arg,
-                                window_arg,
-                                area_arg,
-                                include_border_arg,
-                                disable_border_arg,
-                                border_effect_arg,
-                                delay_arg,
-                                interactive_arg);
-
-  if (!res || !screenshot_app_init ())
-    exit (1);
-
-  /* interactive mode: trigger the dialog and wait for the response */
-  if (interactive_arg)
-    {
-      GtkWidget *dialog;
-
-      dialog = screenshot_interactive_dialog_new ();
-      gtk_widget_show (dialog);
-      g_signal_connect (dialog, "response",
-                        G_CALLBACK (interactive_dialog_response_cb), NULL);
-    }
-  else
-    {
-      screenshot_start ();
-    }
-
-  gtk_main ();
-
-  g_clear_object (&connection);
+  app = screenshot_application_get ();
+  result = g_application_run (G_APPLICATION (app), argc, argv);
+  g_object_unref (app);
 
-  return EXIT_SUCCESS;
+  return result;
 }
diff --git a/src/screenshot-application.c b/src/screenshot-application.c
new file mode 100644
index 0000000..e946d8a
--- /dev/null
+++ b/src/screenshot-application.c
@@ -0,0 +1,646 @@
+/* gnome-screenshot.c - Take a screenshot of the desktop
+ *
+ * Copyright (C) 2001 Jonathan Blandford <jrb alum mit edu>
+ * Copyright (C) 2006 Emmanuele Bassi <ebassi gnome org>
+ * Copyright (C) 2008-2012 Cosimo Cecchi <cosimoc gnome org>
+ *
+ * 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
+ */
+
+#include <config.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "screenshot-application.h"
+#include "screenshot-area-selection.h"
+#include "screenshot-config.h"
+#include "screenshot-filename-builder.h"
+#include "screenshot-interactive-dialog.h"
+#include "screenshot-shadow.h"
+#include "screenshot-utils.h"
+#include "screenshot-dialog.h"
+
+#define SCREENSHOOTER_ICON "applets-screenshooter"
+
+#define LAST_SAVE_DIRECTORY_KEY "last-save-directory"
+
+G_DEFINE_TYPE (ScreenshotApplication, screenshot_application, GTK_TYPE_APPLICATION);
+
+static ScreenshotApplication *_app_singleton = NULL;
+
+struct _ScreenshotApplicationPriv {
+  GDBusConnection *connection;
+
+  gchar *icc_profile_base64;
+  GdkPixbuf *screenshot;
+
+  ScreenshotDialog *dialog;
+};
+
+static void
+save_folder_to_settings (ScreenshotDialog *dialog)
+{
+  char *folder;
+
+  folder = screenshot_dialog_get_folder (dialog);
+  g_settings_set_string (screenshot_config->settings,
+                         LAST_SAVE_DIRECTORY_KEY, folder);
+
+  g_free (folder);
+}
+
+static void
+set_recent_entry (ScreenshotDialog *dialog)
+{
+  char *uri, *app_exec = NULL;
+  GtkRecentManager *recent;
+  GtkRecentData recent_data;
+  GAppInfo *app;
+  const char *exec_name = NULL;
+  static char * groups[2] = { "Graphics", NULL };
+
+  app = g_app_info_get_default_for_type ("image/png", TRUE);
+
+  if (!app) {
+    /* return early, as this would be an useless recent entry anyway. */
+    return;
+  }
+
+  uri = screenshot_dialog_get_uri (dialog);
+  recent = gtk_recent_manager_get_default ();
+  
+  exec_name = g_app_info_get_executable (app);
+  app_exec = g_strjoin (" ", exec_name, "%u", NULL);
+
+  recent_data.display_name = NULL;
+  recent_data.description = NULL;
+  recent_data.mime_type = "image/png";
+  recent_data.app_name = "GNOME Screenshot";
+  recent_data.app_exec = app_exec;
+  recent_data.groups = groups;
+  recent_data.is_private = FALSE;
+
+  gtk_recent_manager_add_full (recent, uri, &recent_data);
+
+  g_object_unref (app);
+  g_free (app_exec);
+  g_free (uri);
+}
+
+static void
+error_dialog_response_cb (GtkDialog *d,
+                          gint response,
+                          ScreenshotDialog *dialog)
+{
+  gtk_widget_destroy (GTK_WIDGET (d));
+
+  screenshot_dialog_focus_entry (dialog);
+}
+
+static void
+save_file_failed_error (ScreenshotDialog *dialog,
+                        GError *error)
+{
+  GtkWidget *toplevel;
+  GtkWidget *error_dialog;
+  char *folder;
+
+  toplevel = screenshot_dialog_get_toplevel (dialog);
+  screenshot_dialog_set_busy (dialog, FALSE);
+
+  /* we had an error, display a dialog to the user and let him choose
+   * another name/location to save the screenshot.
+   */      
+  folder = screenshot_dialog_get_folder (dialog);
+  error_dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel),
+                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                         GTK_MESSAGE_ERROR,
+                                         GTK_BUTTONS_OK,
+                                         _("Error while saving screenshot"));
+
+  /* translators: first %s is the folder URI, second %s is the VFS error */
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog),
+                                            _("Impossible to save the screenshot "
+                                              "to %s.\n Error was %s.\n Please choose another "
+                                              "location and retry."), folder, error->message);
+  gtk_widget_show (error_dialog);
+  g_signal_connect (error_dialog,
+                    "response",
+                    G_CALLBACK (error_dialog_response_cb),
+                    dialog);
+
+  g_free (folder);
+}
+
+static void
+save_file_completed (ScreenshotDialog *dialog)
+{
+  GtkWidget *toplevel;
+
+  toplevel = screenshot_dialog_get_toplevel (dialog);
+
+  save_folder_to_settings (dialog);
+  set_recent_entry (dialog);
+  gtk_widget_destroy (toplevel);
+}
+
+static void
+save_pixbuf_ready_cb (GObject *source,
+                      GAsyncResult *res,
+                      gpointer user_data)
+{
+  GError *error = NULL;
+  ScreenshotDialog *dialog = user_data;
+
+  gdk_pixbuf_save_to_stream_finish (res, &error);
+
+  if (error != NULL)
+    {
+      save_file_failed_error (dialog, error);
+      g_error_free (error);
+      return;
+    }
+
+  save_file_completed (dialog);
+}
+
+static void
+save_file_create_ready_cb (GObject *source,
+                           GAsyncResult *res,
+                           gpointer user_data)
+{
+  ScreenshotApplication *self = user_data;
+  ScreenshotDialog *dialog = self->priv->dialog;
+  GFileOutputStream *os;
+  GError *error = NULL;
+
+  os = g_file_create_finish (G_FILE (source), res, &error);
+
+  if (error != NULL)
+    {
+      save_file_failed_error (dialog, error);
+      g_error_free (error);
+      return;
+    }
+
+  if (self->priv->icc_profile_base64 != NULL)
+    gdk_pixbuf_save_to_stream_async (self->priv->screenshot,
+                                     G_OUTPUT_STREAM (os),
+                                     "png", NULL,
+                                     save_pixbuf_ready_cb, dialog,
+                                     "icc-profile", self->priv->icc_profile_base64,
+                                     "tEXt::Software", "gnome-screenshot",
+                                     NULL);
+  else
+    gdk_pixbuf_save_to_stream_async (self->priv->screenshot,
+                                     G_OUTPUT_STREAM (os),
+                                     "png", NULL,
+                                     save_pixbuf_ready_cb, dialog,
+                                     "tEXt::Software", "gnome-screenshot",
+                                     NULL);
+
+  g_object_unref (os);
+}
+
+static void
+try_to_save (ScreenshotApplication *self)
+{
+  ScreenshotDialog *dialog = self->priv->dialog;
+  gchar *target_uri;
+  GFile *target_file;
+
+  screenshot_dialog_set_busy (dialog, TRUE);
+
+  target_uri = screenshot_dialog_get_uri (dialog);
+  target_file = g_file_new_for_uri (target_uri);
+
+  g_file_create_async (target_file,
+                       G_FILE_CREATE_NONE,
+                       G_PRIORITY_DEFAULT,
+                       NULL,
+                       save_file_create_ready_cb, self);
+
+  g_object_unref (target_file);
+  g_free (target_uri);
+}
+
+static void
+screenshot_save_to_clipboard (ScreenshotApplication *self)
+{
+  GtkClipboard *clipboard;
+
+  clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
+                                             GDK_SELECTION_CLIPBOARD);
+  gtk_clipboard_set_image (clipboard, self->priv->screenshot);
+}
+
+static void
+screenshot_dialog_response_cb (GtkDialog *d,
+                               gint response_id,
+                               gpointer user_data)
+{
+  ScreenshotApplication *self = user_data;
+
+  switch (response_id)
+    {
+    case GTK_RESPONSE_HELP:
+      screenshot_display_help (GTK_WINDOW (d));
+      break;
+    case GTK_RESPONSE_OK:
+      try_to_save (self);
+      break;
+    case SCREENSHOT_RESPONSE_COPY:
+      screenshot_save_to_clipboard (self);
+      break;
+    default:
+      gtk_widget_destroy (GTK_WIDGET (d));
+      break;
+    }
+}
+
+static void
+build_filename_ready_cb (GObject *source,
+                         GAsyncResult *res,
+                         gpointer user_data)
+{
+  ScreenshotApplication *self = user_data;
+  GtkWidget *toplevel;
+  ScreenshotDialog *dialog;
+  gchar *save_uri;
+  GError *error = NULL;
+
+  save_uri = screenshot_build_filename_finish (res, &error);
+
+  if (error != NULL)
+    {
+      g_critical ("Impossible to find a valid location to save the screenshot: %s",
+                  error->message);
+      g_error_free (error);
+
+      exit(1);
+    }
+
+  /* now release the application */
+  g_application_release (G_APPLICATION (self));
+
+  self->priv->dialog = screenshot_dialog_new (self->priv->screenshot, 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,
+                    "response",
+                    G_CALLBACK (screenshot_dialog_response_cb),
+                    self);
+
+  g_free (save_uri);
+}
+
+static void
+finish_prepare_screenshot (ScreenshotApplication *self,
+                           GdkRectangle *rectangle)
+{
+  GdkPixbuf *screenshot;
+
+  screenshot = screenshot_get_pixbuf (rectangle);
+
+  if (screenshot == NULL)
+    {
+      screenshot_show_error_dialog (NULL,
+                                    _("Unable to take a screenshot of the current window"),
+                                    NULL);
+      exit (1);
+    }
+
+  if (screenshot_config->take_window_shot)
+    {
+      switch (screenshot_config->border_effect[0])
+        {
+        case 's': /* shadow */
+          screenshot_add_shadow (&screenshot);
+          break;
+        case 'b': /* border */
+          screenshot_add_border (&screenshot);
+          break;
+        case 'n': /* none */
+        default:
+          break;
+        }
+    }
+
+  self->priv->screenshot = screenshot;
+
+  if (screenshot_config->copy_to_clipboard)
+    {
+      screenshot_save_to_clipboard (self);
+      g_application_release (G_APPLICATION (self));
+
+      return;
+    }
+
+  /* FIXME: apply the ICC profile according to the preferences.
+   * org.gnome.ColorManager.GetProfileForWindow() does not exist anymore,
+   * so we probably need to fetch the color profile of the screen where
+   * the area/window was.
+   *
+   * screenshot_ensure_icc_profile (window);
+   */
+  screenshot_build_filename_async (screenshot_config->last_save_dir,
+                                   build_filename_ready_cb, self);
+}
+
+static void
+rectangle_found_cb (GdkRectangle *rectangle,
+                    gpointer user_data)
+{
+  ScreenshotApplication *self = user_data;
+
+  if (rectangle != NULL)
+    finish_prepare_screenshot (self, rectangle);
+  else
+    /* user dismissed the rectangle with Esc, no error; just quit */
+    g_application_release (G_APPLICATION (self));
+}
+
+static gboolean
+prepare_screenshot_timeout (gpointer user_data)
+{
+  ScreenshotApplication *self = user_data;
+
+  if (screenshot_config->take_area_shot)
+    screenshot_select_area_async (rectangle_found_cb, self);
+  else
+    finish_prepare_screenshot (self, NULL);
+
+  screenshot_save_config ();
+
+  return FALSE;
+}
+
+static void
+screenshot_start (ScreenshotApplication *self)
+{
+  guint delay = screenshot_config->delay * 1000;
+
+  /* hold the GApplication while doing the async screenshot op */
+  g_application_hold (G_APPLICATION (self));
+
+  /* HACK: give time to the dialog to actually disappear.
+   * We don't have any way to tell when the compositor has finished 
+   * re-drawing.
+   */
+  if (delay == 0 && screenshot_config->interactive)
+    delay = 200;
+
+  if (delay > 0)
+    g_timeout_add (delay,
+                   prepare_screenshot_timeout,
+                   self);
+  else
+    g_idle_add (prepare_screenshot_timeout, self);
+}
+
+static gboolean
+screenshot_application_local_command_line (GApplication *app,
+                                           gchar ***arguments,
+                                           gint *exit_status)
+{
+  gboolean clipboard_arg = FALSE;
+  gboolean window_arg = FALSE;
+  gboolean area_arg = FALSE;
+  gboolean include_border_arg = FALSE;
+  gboolean disable_border_arg = FALSE;
+  gboolean interactive_arg = FALSE;
+  gchar *border_effect_arg = NULL;
+  guint delay_arg = 0;
+  const GOptionEntry entries[] = {
+    { "clipboard", 'c', 0, G_OPTION_ARG_NONE, &clipboard_arg, N_("Send the grab directly to the clipboard"), NULL },
+    { "window", 'w', 0, G_OPTION_ARG_NONE, &window_arg, N_("Grab a window instead of the entire screen"), NULL },
+    { "area", 'a', 0, G_OPTION_ARG_NONE, &area_arg, N_("Grab an area of the screen instead of the entire screen"), NULL },
+    { "include-border", 'b', 0, G_OPTION_ARG_NONE, &include_border_arg, N_("Include the window border with the screenshot"), NULL },
+    { "remove-border", 'B', 0, G_OPTION_ARG_NONE, &disable_border_arg, N_("Remove the window border from the screenshot"), NULL },
+    { "delay", 'd', 0, G_OPTION_ARG_INT, &delay_arg, N_("Take screenshot after specified delay [in seconds]"), N_("seconds") },
+    { "border-effect", 'e', 0, G_OPTION_ARG_STRING, &border_effect_arg, N_("Effect to add to the border (shadow, border or none)"), N_("effect") },
+    { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive_arg, N_("Interactively set options"), NULL },
+    { NULL },
+  };
+
+  GOptionContext *context;
+  GError *error = NULL;
+  gint argc = 0;
+  gchar **argv = NULL;
+  gboolean res;
+
+  *exit_status = EXIT_SUCCESS;
+  argv = *arguments;
+  argc = g_strv_length (argv);
+
+  context = g_option_context_new (_("Take a picture of the screen"));
+  g_option_context_add_main_entries (context, entries, NULL);
+  g_option_context_add_group (context, gtk_get_option_group (TRUE));
+
+  if (!g_option_context_parse (context, &argc, &argv, &error))
+    {
+      g_critical ("Unable to parse arguments: %s", error->message);
+      g_error_free (error);
+
+      *exit_status = EXIT_FAILURE;
+      goto out;
+    }
+
+  res = screenshot_load_config (clipboard_arg,
+                                window_arg,
+                                area_arg,
+                                include_border_arg,
+                                disable_border_arg,
+                                border_effect_arg,
+                                delay_arg,
+                                interactive_arg);
+
+  if (!res)
+    {
+      *exit_status = EXIT_FAILURE;
+      goto out;
+    }
+
+  if (!g_application_register (app, NULL, &error)) 
+    {
+      g_printerr ("Could not register the application: %s\n", error->message);
+      g_error_free (error);
+
+      *exit_status = EXIT_FAILURE;
+    }
+
+ out:
+  g_option_context_free (context);
+
+  return TRUE;	
+}
+
+static void
+register_screenshooter_icon (GtkIconFactory * factory)
+{
+  GtkIconSource *source;
+  GtkIconSet *icon_set;
+
+  source = gtk_icon_source_new ();
+  gtk_icon_source_set_icon_name (source, SCREENSHOOTER_ICON);
+
+  icon_set = gtk_icon_set_new ();
+  gtk_icon_set_add_source (icon_set, source);
+
+  gtk_icon_factory_add (factory, SCREENSHOOTER_ICON, icon_set);
+  gtk_icon_set_unref (icon_set);
+  gtk_icon_source_free (source);
+}
+
+static void
+screenshooter_init_stock_icons (void)
+{
+  GtkIconFactory *factory;
+
+  factory = gtk_icon_factory_new ();
+  gtk_icon_factory_add_default (factory);
+
+  register_screenshooter_icon (factory);
+  g_object_unref (factory);
+}
+
+static void
+interactive_dialog_response_cb (GtkWidget *d,
+                                gint response,
+                                gpointer user_data)
+{
+  ScreenshotApplication *self = user_data;
+
+  gtk_widget_destroy (d);
+
+  switch (response)
+    {
+    case GTK_RESPONSE_DELETE_EVENT:
+    case GTK_RESPONSE_CANCEL:
+      break;
+    case GTK_RESPONSE_OK:
+      screenshot_start (self);
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+}
+
+static ScreenshotApplication *
+get_singleton (void)
+{
+  if (_app_singleton == NULL)
+    _app_singleton = g_object_new (SCREENSHOT_TYPE_APPLICATION, 
+                                   "application-id", "org.gnome.Screenshot",
+                                   NULL);
+
+  return _app_singleton;
+}
+
+static void
+screenshot_application_startup (GApplication *app)
+{
+  ScreenshotApplication *self = SCREENSHOT_APPLICATION (app);
+  GError *error = NULL;
+
+  G_APPLICATION_CLASS (screenshot_application_parent_class)->startup (app);
+
+  gtk_window_set_default_icon_name (SCREENSHOOTER_ICON);
+  screenshooter_init_stock_icons ();
+
+  self->priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+
+  if (error != NULL)
+    {
+      g_critical ("Unable to connect to the session bus: %s",
+                  error->message);
+      g_error_free (error);
+
+      return;
+    }
+
+  /* interactive mode: trigger the dialog and wait for the response */
+  if (screenshot_config->interactive)
+    {
+      GtkWidget *dialog;
+
+      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);
+    }
+  else
+    {
+      screenshot_start (self);
+    }
+}
+
+static void
+screenshot_application_finalize (GObject *object)
+{
+  ScreenshotApplication *self = SCREENSHOT_APPLICATION (object);
+
+  g_clear_object (&self->priv->connection);
+  g_clear_object (&self->priv->screenshot);
+  g_free (self->priv->icc_profile_base64);
+
+  G_OBJECT_CLASS (screenshot_application_parent_class)->finalize (object);
+}
+
+static void
+screenshot_application_class_init (ScreenshotApplicationClass *klass)
+{
+  GObjectClass *oclass = G_OBJECT_CLASS (klass);
+  GApplicationClass *aclass = G_APPLICATION_CLASS (klass);
+
+  oclass->finalize = screenshot_application_finalize;
+
+  aclass->local_command_line = screenshot_application_local_command_line;
+  aclass->startup = screenshot_application_startup;
+
+  g_type_class_add_private (klass, sizeof (ScreenshotApplicationPriv));
+}
+
+static void
+screenshot_application_init (ScreenshotApplication *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SCREENSHOT_TYPE_APPLICATION,
+                                            ScreenshotApplicationPriv);
+}
+
+GDBusConnection *
+screenshot_application_get_session_bus (void)
+{
+  ScreenshotApplication *self = get_singleton ();
+  return self->priv->connection;
+}
+
+ScreenshotApplication *
+screenshot_application_get (void)
+{
+  return get_singleton ();
+}
diff --git a/src/screenshot-application.h b/src/screenshot-application.h
new file mode 100644
index 0000000..96624f4
--- /dev/null
+++ b/src/screenshot-application.h
@@ -0,0 +1,55 @@
+/* gnome-screenshot.c - Take screenshots
+ *
+ * Copyright (C) 2001 Jonathan Blandford <jrb alum mit edu>
+ * Copyright (C) 2006 Emmanuele Bassi <ebassi gnome org>
+ * Copyright (C) 2008-2011 Cosimo Cecchi <cosimoc gnome org>
+ *
+ * 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
+ */
+
+#ifndef __SCREENSHOT_APPLICATION_H__
+#define __SCREENSHOT_APPLICATION_H__
+
+#include <gtk/gtk.h>
+
+#define SCREENSHOT_TYPE_APPLICATION screenshot_application_get_type()
+#define SCREENSHOT_APPLICATION(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), SCREENSHOT_TYPE_APPLICATION, ScreenshotApplication))
+#define SCREENSHOT_APPLICATION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), SCREENSHOT_TYPE_APPLICATION, ScreenshotApplicationClass))
+#define SCREENSHOT_IS_APPLICATION(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SCREENSHOT_TYPE_APPLICATION))
+#define SCREENSHOT_IS_APPLICATION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), SCREENSHOT_TYPE_APPLICATION))
+#define SCREENSHOT_APPLICATION_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), SCREENSHOT_TYPE_APPLICATION, ScreenshotApplicationClass))
+
+typedef struct _ScreenshotApplicationPriv ScreenshotApplicationPriv;
+
+typedef struct {
+	GtkApplication parent;
+	ScreenshotApplicationPriv *priv;
+} ScreenshotApplication;
+
+typedef struct {
+	GtkApplicationClass parent_class;
+} ScreenshotApplicationClass;
+
+GType screenshot_application_get_type (void);
+ScreenshotApplication * screenshot_application_get (void);
+GDBusConnection * screenshot_application_get_session_bus (void);
+
+#endif /* __SCREENSHOT_APPLICATION_H__ */
diff --git a/src/screenshot-area-selection.c b/src/screenshot-area-selection.c
index 9179815..fc01f86 100644
--- a/src/screenshot-area-selection.c
+++ b/src/screenshot-area-selection.c
@@ -205,6 +205,7 @@ create_select_window (void)
 typedef struct {
   GdkRectangle rectangle;
   SelectAreaCallback callback;
+  gpointer callback_data;
   gboolean aborted;
 } CallbackData;
 
@@ -214,9 +215,9 @@ emit_select_callback_in_idle (gpointer user_data)
   CallbackData *data = user_data;
 
   if (!data->aborted)
-    data->callback (&data->rectangle);
+    data->callback (&data->rectangle, data->callback_data);
   else
-    data->callback (NULL);
+    data->callback (NULL, data->callback_data);
 
   g_slice_free (CallbackData, data);
 
@@ -224,7 +225,8 @@ emit_select_callback_in_idle (gpointer user_data)
 }
 
 void
-screenshot_select_area_async (SelectAreaCallback callback)
+screenshot_select_area_async (SelectAreaCallback callback,
+                              gpointer callback_data)
 {
   GdkCursor *cursor;
   select_area_filter_data  data;
@@ -243,6 +245,7 @@ screenshot_select_area_async (SelectAreaCallback callback)
 
   cb_data = g_slice_new0 (CallbackData);
   cb_data->callback = callback;
+  cb_data->callback_data = callback_data;
 
   g_signal_connect (data.window, "key-press-event", G_CALLBACK (select_area_key_press), &data);
   g_signal_connect (data.window, "button-press-event", G_CALLBACK (select_area_button_press), &data);
diff --git a/src/screenshot-area-selection.h b/src/screenshot-area-selection.h
index c2f556a..b29fbfe 100644
--- a/src/screenshot-area-selection.h
+++ b/src/screenshot-area-selection.h
@@ -25,9 +25,11 @@
 
 G_BEGIN_DECLS
 
-typedef void (* SelectAreaCallback) (GdkRectangle *rectangle);
+typedef void (* SelectAreaCallback) (GdkRectangle *rectangle,
+                                     gpointer user_data);
 
-void       screenshot_select_area_async   (SelectAreaCallback callback);
+void       screenshot_select_area_async   (SelectAreaCallback callback,
+                                           gpointer callback_data);
 
 G_END_DECLS
 
diff --git a/src/screenshot-utils.c b/src/screenshot-utils.c
index 7fe6d28..a8b0854 100644
--- a/src/screenshot-utils.c
+++ b/src/screenshot-utils.c
@@ -32,7 +32,7 @@
 #endif
 
 #include "cheese-flash.h"
-#include "gnome-screenshot.h"
+#include "screenshot-application.h"
 #include "screenshot-config.h"
 #include "screenshot-utils.h"
 
@@ -643,6 +643,7 @@ screenshot_get_pixbuf (GdkRectangle *rectangle)
   const gchar *method_name;
   GVariant *method_params;
   GError *error = NULL;
+  GDBusConnection *connection;
 
   if (!screenshot_grab_lock ())
     exit (0);
@@ -676,6 +677,7 @@ screenshot_get_pixbuf (GdkRectangle *rectangle)
       method_params = g_variant_new ("(bs)", TRUE, filename);
     }
 
+  connection = screenshot_application_get_session_bus ();
   g_dbus_connection_call_sync (connection,
                                "org.gnome.Shell",
                                "/org/gnome/Shell",



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