1
/* gnome-screenshot.c - Take a screenshot of the desktop
3
* Copyright (C) 2001 Jonathan Blandford <jrb@alum.mit.edu>
4
* Copyright (C) 2006 Emmanuele Bassi <ebassi@gnome.org>
5
* Copyright (C) 2008-2012 Cosimo Cecchi <cosimoc@gnome.org>
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License as
9
* published by the Free Software Foundation; either version 2 of the
10
* License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25
#include <gdk/gdkkeysyms.h>
30
#include <glib/gi18n.h>
33
#include "screenshot-application.h"
34
#include "screenshot-area-selection.h"
35
#include "screenshot-config.h"
36
#include "screenshot-filename-builder.h"
37
#include "screenshot-interactive-dialog.h"
38
#include "screenshot-shadow.h"
39
#include "screenshot-utils.h"
40
#include "screenshot-dialog.h"
42
#define SCREENSHOOTER_ICON "applets-screenshooter"
44
#define LAST_SAVE_DIRECTORY_KEY "last-save-directory"
46
G_DEFINE_TYPE (ScreenshotApplication, screenshot_application, GTK_TYPE_APPLICATION);
48
static ScreenshotApplication *_app_singleton = NULL;
50
static void screenshot_save_to_file (ScreenshotApplication *self);
52
struct _ScreenshotApplicationPriv {
53
GDBusConnection *connection;
55
gchar *icc_profile_base64;
56
GdkPixbuf *screenshot;
59
gboolean should_overwrite;
61
ScreenshotDialog *dialog;
65
save_folder_to_settings (ScreenshotApplication *self)
69
folder = screenshot_dialog_get_folder (self->priv->dialog);
70
g_settings_set_string (screenshot_config->settings,
71
LAST_SAVE_DIRECTORY_KEY, folder);
77
set_recent_entry (ScreenshotApplication *self)
79
char *app_exec = NULL;
80
GtkRecentManager *recent;
81
GtkRecentData recent_data;
83
const char *exec_name = NULL;
84
static char * groups[2] = { "Graphics", NULL };
86
app = g_app_info_get_default_for_type ("image/png", TRUE);
89
/* return early, as this would be an useless recent entry anyway. */
93
recent = gtk_recent_manager_get_default ();
95
exec_name = g_app_info_get_executable (app);
96
app_exec = g_strjoin (" ", exec_name, "%u", NULL);
98
recent_data.display_name = NULL;
99
recent_data.description = NULL;
100
recent_data.mime_type = "image/png";
101
recent_data.app_name = "GNOME Screenshot";
102
recent_data.app_exec = app_exec;
103
recent_data.groups = groups;
104
recent_data.is_private = FALSE;
106
gtk_recent_manager_add_full (recent, self->priv->save_uri, &recent_data);
108
g_object_unref (app);
113
save_pixbuf_handle_success (ScreenshotApplication *self)
115
set_recent_entry (self);
117
if (screenshot_config->interactive)
119
ScreenshotDialog *dialog = self->priv->dialog;
121
save_folder_to_settings (self);
122
gtk_widget_destroy (screenshot_dialog_get_toplevel (dialog));
126
g_application_release (G_APPLICATION (self));
131
save_pixbuf_handle_error (ScreenshotApplication *self,
134
if (screenshot_config->interactive)
136
ScreenshotDialog *dialog = self->priv->dialog;
137
GtkWidget *toplevel = screenshot_dialog_get_toplevel (dialog);
139
screenshot_dialog_set_busy (dialog, FALSE);
141
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS) &&
142
!self->priv->should_overwrite)
144
gchar *folder = screenshot_dialog_get_folder (dialog);
145
gchar *folder_name = g_path_get_basename (folder);
146
gchar *file_name = screenshot_dialog_get_filename (dialog);
147
gchar *detail = g_strdup_printf (_("A file named \"%s\" already exists in \"%s\""),
148
file_name, folder_name);
151
response = screenshot_show_dialog (GTK_WINDOW (toplevel),
154
_("Overwrite existing file?"),
158
g_free (folder_name);
162
if (response == GTK_RESPONSE_YES)
164
self->priv->should_overwrite = TRUE;
165
screenshot_save_to_file (self);
172
screenshot_show_dialog (GTK_WINDOW (toplevel),
175
_("Unable to capture a screenshot"),
176
_("Error creating file. Please choose another location and retry."));
179
screenshot_dialog_focus_entry (dialog);
183
screenshot_play_sound_effect ("dialog-error", _("Unable to capture a screenshot"));
184
g_application_release (G_APPLICATION (self));
189
save_pixbuf_ready_cb (GObject *source,
193
GError *error = NULL;
194
ScreenshotApplication *self = user_data;
196
gdk_pixbuf_save_to_stream_finish (res, &error);
200
save_pixbuf_handle_error (self, error);
201
g_error_free (error);
205
save_pixbuf_handle_success (self);
209
save_file_create_ready_cb (GObject *source,
213
ScreenshotApplication *self = user_data;
214
GFileOutputStream *os;
215
GError *error = NULL;
217
if (self->priv->should_overwrite)
218
os = g_file_replace_finish (G_FILE (source), res, &error);
220
os = g_file_create_finish (G_FILE (source), res, &error);
224
save_pixbuf_handle_error (self, error);
225
g_error_free (error);
229
if (self->priv->icc_profile_base64 != NULL)
230
gdk_pixbuf_save_to_stream_async (self->priv->screenshot,
231
G_OUTPUT_STREAM (os),
233
save_pixbuf_ready_cb, self,
234
"icc-profile", self->priv->icc_profile_base64,
235
"tEXt::Software", "gnome-screenshot",
238
gdk_pixbuf_save_to_stream_async (self->priv->screenshot,
239
G_OUTPUT_STREAM (os),
241
save_pixbuf_ready_cb, self,
242
"tEXt::Software", "gnome-screenshot",
249
screenshot_save_to_file (ScreenshotApplication *self)
253
if (self->priv->dialog != NULL)
254
screenshot_dialog_set_busy (self->priv->dialog, TRUE);
256
target_file = g_file_new_for_uri (self->priv->save_uri);
258
if (self->priv->should_overwrite)
260
g_file_replace_async (target_file,
265
save_file_create_ready_cb, self);
269
g_file_create_async (target_file,
273
save_file_create_ready_cb, self);
276
g_object_unref (target_file);
280
screenshot_save_to_clipboard (ScreenshotApplication *self)
282
GtkClipboard *clipboard;
284
clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
285
GDK_SELECTION_CLIPBOARD);
286
gtk_clipboard_set_image (clipboard, self->priv->screenshot);
290
screenshot_dialog_response_cb (GtkDialog *d,
294
ScreenshotApplication *self = user_data;
298
case GTK_RESPONSE_HELP:
299
screenshot_display_help (GTK_WINDOW (d));
301
case GTK_RESPONSE_OK:
302
/* update to the new URI */
303
g_free (self->priv->save_uri);
304
self->priv->save_uri = screenshot_dialog_get_uri (self->priv->dialog);
305
screenshot_save_to_file (self);
307
case SCREENSHOT_RESPONSE_COPY:
308
screenshot_save_to_clipboard (self);
311
gtk_widget_destroy (GTK_WIDGET (d));
317
build_filename_ready_cb (GObject *source,
321
ScreenshotApplication *self = user_data;
323
ScreenshotDialog *dialog;
325
GError *error = NULL;
327
self->priv->save_uri = screenshot_build_filename_finish (res, &error);
329
/* now release the application */
330
g_application_release (G_APPLICATION (self));
334
g_critical ("Impossible to find a valid location to save the screenshot: %s",
336
g_error_free (error);
338
if (screenshot_config->interactive)
339
screenshot_show_dialog (NULL,
342
_("Unable to capture a screenshot"),
343
_("Error creating file"));
345
screenshot_play_sound_effect ("dialog-error", _("Unable to capture a screenshot"));
350
screenshot_play_sound_effect ("screen-capture", _("Screenshot taken"));
352
if (screenshot_config->interactive)
354
self->priv->dialog = screenshot_dialog_new (self->priv->screenshot, self->priv->save_uri);
355
toplevel = screenshot_dialog_get_toplevel (self->priv->dialog);
356
gtk_widget_show (toplevel);
358
gtk_application_add_window (GTK_APPLICATION (self), GTK_WINDOW (toplevel));
360
g_signal_connect (toplevel,
362
G_CALLBACK (screenshot_dialog_response_cb),
367
g_application_hold (G_APPLICATION (self));
368
screenshot_save_to_file (self);
373
finish_prepare_screenshot (ScreenshotApplication *self,
374
GdkRectangle *rectangle)
376
GdkPixbuf *screenshot;
378
screenshot = screenshot_get_pixbuf (rectangle);
380
if (screenshot == NULL)
382
g_critical ("Unable to capture a screenshot of any window");
384
if (screenshot_config->interactive)
385
screenshot_show_dialog (NULL,
388
_("Unable to capture a screenshot"),
389
_("All possible methods failed"));
391
screenshot_play_sound_effect ("dialog-error", _("Unable to capture a screenshot"));
393
g_application_release (G_APPLICATION (self));
398
if (screenshot_config->take_window_shot)
400
switch (screenshot_config->border_effect[0])
402
case 's': /* shadow */
403
screenshot_add_shadow (&screenshot);
405
case 'b': /* border */
406
screenshot_add_border (&screenshot);
414
self->priv->screenshot = screenshot;
416
if (screenshot_config->copy_to_clipboard)
418
screenshot_save_to_clipboard (self);
419
screenshot_play_sound_effect ("screen-capture", _("Screenshot taken"));
421
g_application_release (G_APPLICATION (self));
426
/* FIXME: apply the ICC profile according to the preferences.
427
* org.gnome.ColorManager.GetProfileForWindow() does not exist anymore,
428
* so we probably need to fetch the color profile of the screen where
429
* the area/window was.
431
* screenshot_ensure_icc_profile (window);
433
screenshot_build_filename_async (build_filename_ready_cb, self);
437
rectangle_found_cb (GdkRectangle *rectangle,
440
ScreenshotApplication *self = user_data;
442
if (rectangle != NULL)
443
finish_prepare_screenshot (self, rectangle);
445
/* user dismissed the rectangle with Esc, no error; just quit */
446
g_application_release (G_APPLICATION (self));
450
prepare_screenshot_timeout (gpointer user_data)
452
ScreenshotApplication *self = user_data;
454
if (screenshot_config->take_area_shot)
455
screenshot_select_area_async (rectangle_found_cb, self);
457
finish_prepare_screenshot (self, NULL);
459
screenshot_save_config ();
465
screenshot_start (ScreenshotApplication *self)
467
guint delay = screenshot_config->delay * 1000;
469
/* hold the GApplication while doing the async screenshot op */
470
g_application_hold (G_APPLICATION (self));
472
/* HACK: give time to the dialog to actually disappear.
473
* We don't have any way to tell when the compositor has finished
476
if (delay == 0 && screenshot_config->interactive)
480
g_timeout_add (delay,
481
prepare_screenshot_timeout,
484
g_idle_add (prepare_screenshot_timeout, self);
488
screenshot_application_local_command_line (GApplication *app,
492
gboolean clipboard_arg = FALSE;
493
gboolean window_arg = FALSE;
494
gboolean area_arg = FALSE;
495
gboolean include_border_arg = FALSE;
496
gboolean disable_border_arg = FALSE;
497
gboolean interactive_arg = FALSE;
498
gchar *border_effect_arg = NULL;
500
const GOptionEntry entries[] = {
501
{ "clipboard", 'c', 0, G_OPTION_ARG_NONE, &clipboard_arg, N_("Send the grab directly to the clipboard"), NULL },
502
{ "window", 'w', 0, G_OPTION_ARG_NONE, &window_arg, N_("Grab a window instead of the entire screen"), NULL },
503
{ "area", 'a', 0, G_OPTION_ARG_NONE, &area_arg, N_("Grab an area of the screen instead of the entire screen"), NULL },
504
{ "include-border", 'b', 0, G_OPTION_ARG_NONE, &include_border_arg, N_("Include the window border with the screenshot"), NULL },
505
{ "remove-border", 'B', 0, G_OPTION_ARG_NONE, &disable_border_arg, N_("Remove the window border from the screenshot"), NULL },
506
{ "delay", 'd', 0, G_OPTION_ARG_INT, &delay_arg, N_("Take screenshot after specified delay [in seconds]"), N_("seconds") },
507
{ "border-effect", 'e', 0, G_OPTION_ARG_STRING, &border_effect_arg, N_("Effect to add to the border (shadow, border or none)"), N_("effect") },
508
{ "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive_arg, N_("Interactively set options"), NULL },
512
GOptionContext *context;
513
GError *error = NULL;
518
*exit_status = EXIT_SUCCESS;
520
argc = g_strv_length (argv);
522
context = g_option_context_new (_("Take a picture of the screen"));
523
g_option_context_add_main_entries (context, entries, NULL);
524
g_option_context_add_group (context, gtk_get_option_group (TRUE));
526
if (!g_option_context_parse (context, &argc, &argv, &error))
528
g_critical ("Unable to parse arguments: %s", error->message);
529
g_error_free (error);
531
*exit_status = EXIT_FAILURE;
535
res = screenshot_load_config (clipboard_arg,
546
*exit_status = EXIT_FAILURE;
550
if (!g_application_register (app, NULL, &error))
552
g_printerr ("Could not register the application: %s\n", error->message);
553
g_error_free (error);
555
*exit_status = EXIT_FAILURE;
559
g_option_context_free (context);
565
register_screenshooter_icon (GtkIconFactory * factory)
567
GtkIconSource *source;
568
GtkIconSet *icon_set;
570
source = gtk_icon_source_new ();
571
gtk_icon_source_set_icon_name (source, SCREENSHOOTER_ICON);
573
icon_set = gtk_icon_set_new ();
574
gtk_icon_set_add_source (icon_set, source);
576
gtk_icon_factory_add (factory, SCREENSHOOTER_ICON, icon_set);
577
gtk_icon_set_unref (icon_set);
578
gtk_icon_source_free (source);
582
screenshooter_init_stock_icons (void)
584
GtkIconFactory *factory;
586
factory = gtk_icon_factory_new ();
587
gtk_icon_factory_add_default (factory);
589
register_screenshooter_icon (factory);
590
g_object_unref (factory);
594
interactive_dialog_response_cb (GtkWidget *d,
598
ScreenshotApplication *self = user_data;
600
gtk_widget_destroy (d);
604
case GTK_RESPONSE_DELETE_EVENT:
605
case GTK_RESPONSE_CANCEL:
607
case GTK_RESPONSE_OK:
608
screenshot_start (self);
611
g_assert_not_reached ();
616
static ScreenshotApplication *
619
if (_app_singleton == NULL)
620
_app_singleton = g_object_new (SCREENSHOT_TYPE_APPLICATION,
621
"application-id", "org.gnome.Screenshot",
624
return _app_singleton;
628
screenshot_application_startup (GApplication *app)
630
ScreenshotApplication *self = SCREENSHOT_APPLICATION (app);
631
GError *error = NULL;
633
G_APPLICATION_CLASS (screenshot_application_parent_class)->startup (app);
635
gtk_window_set_default_icon_name (SCREENSHOOTER_ICON);
636
screenshooter_init_stock_icons ();
638
self->priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
642
g_critical ("Unable to connect to the session bus: %s",
644
g_error_free (error);
649
/* interactive mode: trigger the dialog and wait for the response */
650
if (screenshot_config->interactive)
654
dialog = screenshot_interactive_dialog_new ();
655
gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dialog));
656
gtk_widget_show (dialog);
657
g_signal_connect (dialog, "response",
658
G_CALLBACK (interactive_dialog_response_cb), self);
662
screenshot_start (self);
667
screenshot_application_finalize (GObject *object)
669
ScreenshotApplication *self = SCREENSHOT_APPLICATION (object);
671
g_clear_object (&self->priv->connection);
672
g_clear_object (&self->priv->screenshot);
673
g_free (self->priv->icc_profile_base64);
674
g_free (self->priv->save_uri);
676
G_OBJECT_CLASS (screenshot_application_parent_class)->finalize (object);
680
screenshot_application_class_init (ScreenshotApplicationClass *klass)
682
GObjectClass *oclass = G_OBJECT_CLASS (klass);
683
GApplicationClass *aclass = G_APPLICATION_CLASS (klass);
685
oclass->finalize = screenshot_application_finalize;
687
aclass->local_command_line = screenshot_application_local_command_line;
688
aclass->startup = screenshot_application_startup;
690
g_type_class_add_private (klass, sizeof (ScreenshotApplicationPriv));
694
screenshot_application_init (ScreenshotApplication *self)
696
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SCREENSHOT_TYPE_APPLICATION,
697
ScreenshotApplicationPriv);
701
screenshot_application_get_session_bus (void)
703
ScreenshotApplication *self = get_singleton ();
704
return self->priv->connection;
707
ScreenshotApplication *
708
screenshot_application_get (void)
710
return get_singleton ();