diff options
author | monsta <[email protected]> | 2015-09-09 12:35:05 +0300 |
---|---|---|
committer | monsta <[email protected]> | 2015-09-09 12:35:05 +0300 |
commit | aa3a853c9d06d0321e8924cbfbc42c8411f571f5 (patch) | |
tree | 7bca363d0bb67fddadbe6fd53e92c3b3db71db8d /mate-screenshot/mate-screenshot.c | |
parent | 0d36d61761a1d68839d61f521889dba3db7f514f (diff) | |
download | mate-utils-aa3a853c9d06d0321e8924cbfbc42c8411f571f5.tar.bz2 mate-utils-aa3a853c9d06d0321e8924cbfbc42c8411f571f5.tar.xz |
mate-screenshot: move stuff to data/ and src/ subdirs
Diffstat (limited to 'mate-screenshot/mate-screenshot.c')
-rw-r--r-- | mate-screenshot/mate-screenshot.c | 1372 |
1 files changed, 0 insertions, 1372 deletions
diff --git a/mate-screenshot/mate-screenshot.c b/mate-screenshot/mate-screenshot.c deleted file mode 100644 index 3e121f00..00000000 --- a/mate-screenshot/mate-screenshot.c +++ /dev/null @@ -1,1372 +0,0 @@ -/* mate-screenshot.c - Take a screenshot of the desktop - * - * Copyright (C) 2001 Jonathan Blandford <[email protected]> - * Copyright (C) 2006 Emmanuele Bassi <[email protected]> - * Copyright (C) 2008 Cosimo Cecchi <[email protected]> - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -/* THERE ARE NO FEATURE REQUESTS ALLOWED */ -/* IF YOU WANT YOUR OWN FEATURE -- WRITE THE DAMN THING YOURSELF (-: */ -/* 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 <canberra-gtk.h> - -#include "screenshot-shadow.h" -#include "screenshot-utils.h" -#include "screenshot-save.h" -#include "screenshot-dialog.h" -#include "screenshot-xfer.h" - -#define SCREENSHOOTER_ICON "applets-screenshooter" - -#define MATE_SCREENSHOT_SCHEMA "org.mate.screenshot" -#define INCLUDE_BORDER_KEY "include-border" -#define INCLUDE_POINTER_KEY "include-pointer" -#define LAST_SAVE_DIRECTORY_KEY "last-save-directory" -#define BORDER_EFFECT_KEY "border-effect" -#define DELAY_KEY "delay" -#define CAJA_PREFERENCES_SCHEMA "org.mate.caja.preferences" - -enum -{ - COLUMN_NICK, - COLUMN_LABEL, - COLUMN_ID, - - N_COLUMNS -}; - -typedef enum { - SCREENSHOT_EFFECT_NONE, - SCREENSHOT_EFFECT_SHADOW, - SCREENSHOT_EFFECT_BORDER -} ScreenshotEffectType; - -typedef enum -{ - TEST_LAST_DIR = 0, - TEST_DESKTOP = 1, - TEST_TMP = 2, -} TestType; - -typedef struct -{ - char *base_uris[3]; - char *retval; - int iteration; - TestType type; - GdkWindow *window; - GdkRectangle *rectangle; -} AsyncExistenceJob; - -static GdkPixbuf *screenshot = NULL; - -/* Global variables*/ -static char *last_save_dir = NULL; -static char *window_title = NULL; -static char *temporary_file = NULL; -static gboolean save_immediately = FALSE; -static GSettings *settings = NULL; - -/* Options */ -static gboolean take_window_shot = FALSE; -static gboolean take_area_shot = FALSE; -static gboolean include_border = FALSE; -static gboolean include_pointer = TRUE; -static char *border_effect = NULL; -static guint delay = 0; - -/* some local prototypes */ -static void display_help (GtkWindow *parent); -static void save_done_notification (gpointer data); -static char *get_desktop_dir (void); -static void save_options (void); - -static GtkWidget *border_check = NULL; -static GtkWidget *effect_combo = NULL; -static GtkWidget *effect_label = NULL; -static GtkWidget *effects_vbox = NULL; -static GtkWidget *delay_hbox = NULL; - -static void -display_help (GtkWindow *parent) -{ - GError *error = NULL; - - gtk_show_uri (gtk_window_get_screen (parent), - "help:mate-user-guide/goseditmainmenu-53", - gtk_get_current_event_time (), &error); - - if (error) - { - screenshot_show_gerror_dialog (parent, - _("Error loading the help page"), - error); - g_error_free (error); - } -} - -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"); - 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 - -static void -target_toggled_cb (GtkToggleButton *button, - gpointer data) -{ - int target_toggle = GPOINTER_TO_INT (data); - - if (gtk_toggle_button_get_active (button)) - { - take_window_shot = (target_toggle == TARGET_TOGGLE_WINDOW); - take_area_shot = (target_toggle == TARGET_TOGGLE_AREA); - - gtk_widget_set_sensitive (border_check, take_window_shot); - gtk_widget_set_sensitive (effect_combo, take_window_shot); - gtk_widget_set_sensitive (effect_label, take_window_shot); - - gtk_widget_set_sensitive (delay_hbox, !take_area_shot); - gtk_widget_set_sensitive (effects_vbox, !take_area_shot); - } -} - -static void -delay_spin_value_changed_cb (GtkSpinButton *button) -{ - delay = gtk_spin_button_get_value_as_int (button); -} - -static void -include_border_toggled_cb (GtkToggleButton *button, - gpointer data) -{ - include_border = gtk_toggle_button_get_active (button); -} - -static void -include_pointer_toggled_cb (GtkToggleButton *button, - gpointer data) -{ - include_pointer = gtk_toggle_button_get_active (button); -} - -static void -effect_combo_changed_cb (GtkComboBox *combo, - gpointer user_data) -{ - GtkTreeIter iter; - - if (gtk_combo_box_get_active_iter (combo, &iter)) - { - GtkTreeModel *model; - gchar *effect; - - model = gtk_combo_box_get_model (combo); - gtk_tree_model_get (model, &iter, COLUMN_NICK, &effect, -1); - - g_assert (effect != NULL); - - g_free (border_effect); - border_effect = effect; /* gets free'd later */ - } -} - -static gint -key_press_cb (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - if (event->keyval == GDK_KEY_F1) - { - display_help (GTK_WINDOW (widget)); - return TRUE; - } - - return FALSE; -} - -typedef struct { - ScreenshotEffectType id; - const gchar *label; - const gchar *nick; -} ScreenshotEffect; - -/* Translators: - * these are the names of the effects available which will be - * displayed inside a combo box in interactive mode for the user - * to chooser. - */ -static const ScreenshotEffect effects[] = { - { SCREENSHOT_EFFECT_NONE, N_("None"), "none" }, - { SCREENSHOT_EFFECT_SHADOW, N_("Drop shadow"), "shadow" }, - { SCREENSHOT_EFFECT_BORDER, N_("Border"), "border" } -}; - -static guint n_effects = G_N_ELEMENTS (effects); - -static GtkWidget * -create_effects_combo (void) -{ - GtkWidget *retval; - GtkListStore *model; - GtkCellRenderer *renderer; - gint i; - - model = gtk_list_store_new (N_COLUMNS, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_UINT); - - for (i = 0; i < n_effects; i++) - { - GtkTreeIter iter; - - gtk_list_store_insert (model, &iter, i); - gtk_list_store_set (model, &iter, - COLUMN_ID, effects[i].id, - COLUMN_LABEL, gettext (effects[i].label), - COLUMN_NICK, effects[i].nick, - -1); - } - - retval = gtk_combo_box_new (); - gtk_combo_box_set_model (GTK_COMBO_BOX (retval), - GTK_TREE_MODEL (model)); - g_object_unref (model); - - switch (border_effect[0]) - { - case 's': /* shadow */ - gtk_combo_box_set_active (GTK_COMBO_BOX (retval), - SCREENSHOT_EFFECT_SHADOW); - break; - case 'b': /* border */ - gtk_combo_box_set_active (GTK_COMBO_BOX (retval), - SCREENSHOT_EFFECT_BORDER); - break; - case 'n': /* none */ - gtk_combo_box_set_active (GTK_COMBO_BOX (retval), - SCREENSHOT_EFFECT_NONE); - break; - default: - break; - } - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (retval), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (retval), renderer, - "text", COLUMN_LABEL, - NULL); - - g_signal_connect (retval, "changed", - G_CALLBACK (effect_combo_changed_cb), - NULL); - - return retval; -} - -static void -create_effects_frame (GtkWidget *outer_vbox, - const gchar *frame_title) -{ - GtkWidget *main_vbox, *vbox, *hbox; - GtkWidget *align; - GtkWidget *label; - GtkWidget *check; - GtkWidget *combo; - gchar *title; - - main_vbox = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (outer_vbox), main_vbox, FALSE, FALSE, 0); - gtk_widget_show (main_vbox); - effects_vbox = main_vbox; - - title = g_strconcat ("<b>", frame_title, "</b>", NULL); - label = gtk_label_new (title); - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - g_free (title); - - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); - - align = gtk_alignment_new (0.0, 0.0, 0.0, 0.0); - gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0); - gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0); - gtk_widget_show (align); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_container_add (GTK_CONTAINER (align), vbox); - gtk_widget_show (vbox); - - /** Include pointer **/ - check = gtk_check_button_new_with_mnemonic (_("Include _pointer")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), include_pointer); - g_signal_connect (check, "toggled", - G_CALLBACK (include_pointer_toggled_cb), - NULL); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_widget_show (check); - - /** Include window border **/ - check = gtk_check_button_new_with_mnemonic (_("Include the window _border")); - gtk_widget_set_sensitive (check, take_window_shot); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), include_border); - g_signal_connect (check, "toggled", - G_CALLBACK (include_border_toggled_cb), - NULL); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_widget_show (check); - border_check = check; - - /** Effects **/ - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); - - label = gtk_label_new_with_mnemonic (_("Apply _effect:")); - gtk_widget_set_sensitive (label, take_window_shot); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - effect_label = label; - - combo = create_effects_combo (); - gtk_widget_set_sensitive (combo, take_window_shot); - gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo); - gtk_widget_show (combo); - effect_combo = combo; -} - -static void -create_screenshot_frame (GtkWidget *outer_vbox, - const gchar *frame_title) -{ - GtkWidget *main_vbox, *vbox, *hbox; - GtkWidget *align; - GtkWidget *radio; - GtkWidget *image; - GtkWidget *spin; - GtkWidget *label; - GtkAdjustment *adjust; - GSList *group; - gchar *title; - - main_vbox = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (outer_vbox), main_vbox, FALSE, FALSE, 0); - gtk_widget_show (main_vbox); - - title = g_strconcat ("<b>", frame_title, "</b>", NULL); - label = gtk_label_new (title); - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - g_free (title); - - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); - - align = gtk_alignment_new (0.0, 0.0, 0.0, 0.0); - gtk_widget_set_size_request (align, 48, -1); - gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0); - gtk_widget_show (align); - - image = gtk_image_new_from_stock (SCREENSHOOTER_ICON, - GTK_ICON_SIZE_DIALOG); - gtk_container_add (GTK_CONTAINER (align), image); - gtk_widget_show (image); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - gtk_widget_show (vbox); - - /** Grab whole desktop **/ - group = NULL; - radio = gtk_radio_button_new_with_mnemonic (group, - _("Grab the whole _desktop")); - if (take_window_shot || take_area_shot) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), FALSE); - g_signal_connect (radio, "toggled", - G_CALLBACK (target_toggled_cb), - GINT_TO_POINTER (TARGET_TOGGLE_DESKTOP)); - gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0); - group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)); - gtk_widget_show (radio); - - /** Grab current window **/ - radio = gtk_radio_button_new_with_mnemonic (group, - _("Grab the current _window")); - if (take_window_shot) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE); - g_signal_connect (radio, "toggled", - G_CALLBACK (target_toggled_cb), - GINT_TO_POINTER (TARGET_TOGGLE_WINDOW)); - gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0); - group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)); - gtk_widget_show (radio); - - /** Grab area of the desktop **/ - radio = gtk_radio_button_new_with_mnemonic (group, - _("Select _area to grab")); - if (take_area_shot) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE); - g_signal_connect (radio, "toggled", - G_CALLBACK (target_toggled_cb), - GINT_TO_POINTER (TARGET_TOGGLE_AREA)); - gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0); - gtk_widget_show (radio); - - /** Grab after delay **/ - delay_hbox = gtk_hbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (vbox), delay_hbox, FALSE, FALSE, 0); - gtk_widget_show (delay_hbox); - - /* translators: this is the first part of the "grab after a - * delay of <spin button> seconds". - */ - label = gtk_label_new_with_mnemonic (_("Grab _after a delay of")); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (delay_hbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); - - adjust = GTK_ADJUSTMENT (gtk_adjustment_new ((gdouble) delay, - 0.0, 99.0, - 1.0, 1.0, - 0.0)); - spin = gtk_spin_button_new (adjust, 1.0, 0); - g_signal_connect (spin, "value-changed", - G_CALLBACK (delay_spin_value_changed_cb), - NULL); - gtk_box_pack_start (GTK_BOX (delay_hbox), spin, FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin); - gtk_widget_show (spin); - - /* translators: this is the last part of the "grab after a - * delay of <spin button> seconds". - */ - label = gtk_label_new (_("seconds")); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_end (GTK_BOX (delay_hbox), label, FALSE, FALSE, 0); - gtk_widget_show (label); -} - -static GtkWidget * -create_interactive_dialog (void) -{ - GtkWidget *retval; - 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)); - gtk_box_set_spacing (GTK_BOX (content_area), 2); - gtk_window_set_title (GTK_WINDOW (retval), _("Take Screenshot")); - - /* main container */ - main_vbox = gtk_vbox_new (FALSE, 18); - gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 5); - gtk_box_pack_start (GTK_BOX (content_area), main_vbox, TRUE, TRUE, 0); - gtk_widget_show (main_vbox); - - 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_set_default_response (GTK_DIALOG (retval), GTK_RESPONSE_OK); - - /* 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); - - g_signal_connect (G_OBJECT (retval), "key-press-event", - G_CALLBACK(key_press_cb), - NULL); - - return retval; -} - -static void -save_folder_to_settings (ScreenshotDialog *dialog) -{ - char *folder; - - folder = screenshot_dialog_get_folder (dialog); - g_settings_set_string (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 = "MATE 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_callback (TransferResult result, - char *error_message, - gpointer data) -{ - ScreenshotDialog *dialog = data; - GtkWidget *toplevel; - - toplevel = screenshot_dialog_get_toplevel (dialog); - screenshot_dialog_set_busy (dialog, FALSE); - - if (result == TRANSFER_OK) - { - save_folder_to_settings (dialog); - set_recent_entry (dialog); - gtk_widget_destroy (toplevel); - - /* we're done, stop the mainloop now */ - gtk_main_quit (); - } - else if (result == TRANSFER_OVERWRITE || - result == TRANSFER_CANCELLED) - { - /* user has canceled the overwrite dialog or the transfer itself, let him - * choose another name. - */ - screenshot_dialog_focus_entry (dialog); - } - else /* result == TRANSFER_ERROR */ - { - /* we had an error, display a dialog to the user and let him choose - * another name/location to save the screenshot. - */ - GtkWidget *error_dialog; - char *uri; - - uri = screenshot_dialog_get_uri (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 file path, 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."), uri, error_message); - gtk_widget_show (error_dialog); - g_signal_connect (error_dialog, - "response", - G_CALLBACK (error_dialog_response_cb), - dialog); - - g_free (uri); - } - -} - -static void -try_to_save (ScreenshotDialog *dialog, - const char *target) -{ - GFile *source_file, *target_file; - - g_assert (temporary_file); - - screenshot_dialog_set_busy (dialog, TRUE); - - source_file = g_file_new_for_path (temporary_file); - target_file = g_file_new_for_uri (target); - - screenshot_xfer_uri (source_file, - target_file, - screenshot_dialog_get_toplevel (dialog), - save_callback, dialog); - - /* screenshot_xfer_uri () holds a ref, so we can unref now */ - g_object_unref (source_file); - g_object_unref (target_file); -} - -static void -save_done_notification (gpointer data) -{ - ScreenshotDialog *dialog = data; - - temporary_file = g_strdup (screenshot_save_get_filename ()); - screenshot_dialog_enable_dnd (dialog); - - if (save_immediately) - { - GtkWidget *toplevel; - - toplevel = screenshot_dialog_get_toplevel (dialog); - gtk_dialog_response (GTK_DIALOG (toplevel), GTK_RESPONSE_OK); - } -} - -static void -screenshot_dialog_response_cb (GtkDialog *d, - gint response_id, - ScreenshotDialog *dialog) -{ - char *uri; - - if (response_id == GTK_RESPONSE_HELP) - { - display_help (GTK_WINDOW (d)); - } - else if (response_id == GTK_RESPONSE_OK) - { - uri = screenshot_dialog_get_uri (dialog); - if (temporary_file == NULL) - { - save_immediately = TRUE; - screenshot_dialog_set_busy (dialog, TRUE); - } - else - { - /* we've saved the temporary file, lets try to copy it to the - * correct location. - */ - try_to_save (dialog, uri); - } - g_free (uri); - } - else if (response_id == SCREENSHOT_RESPONSE_COPY) - { - GtkClipboard *clipboard; - GdkPixbuf *screenshot; - - clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (d)), - GDK_SELECTION_CLIPBOARD); - screenshot = screenshot_dialog_get_screenshot (dialog); - gtk_clipboard_set_image (clipboard, screenshot); - } - else /* dialog was canceled */ - { - gtk_widget_destroy (GTK_WIDGET (d)); - gtk_main_quit (); - } -} - - -static void -run_dialog (ScreenshotDialog *dialog) -{ - GtkWidget *toplevel; - - toplevel = screenshot_dialog_get_toplevel (dialog); - - gtk_widget_show (toplevel); - - g_signal_connect (toplevel, - "response", - G_CALLBACK (screenshot_dialog_response_cb), - dialog); -} - -static void -play_sound_effect (GdkWindow *window) -{ - ca_context *c; - ca_proplist *p = NULL; - int res; - - c = ca_gtk_context_get (); - - res = ca_proplist_create (&p); - if (res < 0) - goto done; - - res = ca_proplist_sets (p, CA_PROP_EVENT_ID, "screen-capture"); - if (res < 0) - goto done; - - res = ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, _("Screenshot taken")); - if (res < 0) - goto done; - - if (window != NULL) - { - res = ca_proplist_setf (p, - CA_PROP_WINDOW_X11_XID, - "%lu", - (unsigned long) GDK_WINDOW_XID (window)); - if (res < 0) - goto done; - } - - ca_context_play_full (c, 0, p, NULL, NULL); - - done: - if (p != NULL) - ca_proplist_destroy (p); - -} - -static void -finish_prepare_screenshot (char *initial_uri, GdkWindow *window, GdkRectangle *rectangle) -{ - ScreenshotDialog *dialog; - gboolean include_mask = (!take_window_shot && !take_area_shot); - - /* always disable window border for full-desktop or selected-area screenshots */ - if (!take_window_shot) - screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, FALSE, include_mask); - else - { - screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, include_border, include_mask); - - switch (border_effect[0]) - { - case 's': /* shadow */ - screenshot_add_shadow (&screenshot); - break; - case 'b': /* border */ - screenshot_add_border (&screenshot); - break; - case 'n': /* none */ - default: - break; - } - } - - /* release now the lock, it was acquired when we were finding the window */ - screenshot_release_lock (); - - if (screenshot == NULL) - { - screenshot_show_error_dialog (NULL, - _("Unable to take a screenshot of the current window"), - NULL); - exit (1); - } - - play_sound_effect (window); - - dialog = screenshot_dialog_new (screenshot, initial_uri, take_window_shot); - g_free (initial_uri); - - screenshot_save_start (screenshot, save_done_notification, dialog); - - run_dialog (dialog); -} - -static void -async_existence_job_free (AsyncExistenceJob *job) -{ - if (!job) - return; - - g_free (job->base_uris[1]); - g_free (job->base_uris[2]); - - if (job->rectangle != NULL) - g_slice_free (GdkRectangle, job->rectangle); - - g_slice_free (AsyncExistenceJob, job); -} - -static gboolean -check_file_done (gpointer user_data) -{ - AsyncExistenceJob *job = user_data; - - finish_prepare_screenshot (job->retval, job->window, job->rectangle); - - async_existence_job_free (job); - - return FALSE; -} - -static char * -build_uri (AsyncExistenceJob *job) -{ - char *retval, *file_name; - char *timestamp; - GDateTime *d; - - d = g_date_time_new_now_local (); - /* Translators: This is a strftime format string. - * It is used to display the time in 24-hours format (eg, like - * in France: 20:10). */ - timestamp = g_date_time_format (d, _("%Y-%m-%d %H:%M:%S")); - g_date_time_unref (d); - - if (job->iteration == 0) - { - /* translators: this is the name of the file that gets made up - * with the screenshot if the entire screen is taken */ - file_name = g_strdup_printf (_("Screenshot at %s.png"), timestamp); - } - else - { - /* translators: this is the name of the file that gets - * made up with the screenshot if the entire screen is - * taken */ - file_name = g_strdup_printf (_("Screenshot at %s - %d.png"), timestamp, job->iteration); - } - - retval = g_build_filename (job->base_uris[job->type], file_name, NULL); - g_free (file_name); - g_free (timestamp); - - return retval; -} - -static gboolean -try_check_file (GIOSchedulerJob *io_job, - GCancellable *cancellable, - gpointer data) -{ - AsyncExistenceJob *job = data; - GFile *file; - GFileInfo *info; - GError *error; - char *uri; - -retry: - error = NULL; - uri = build_uri (job); - file = g_file_new_for_uri (uri); - - info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, - G_FILE_QUERY_INFO_NONE, cancellable, &error); - if (info != NULL) - { - /* file already exists, iterate again */ - g_object_unref (info); - g_object_unref (file); - g_free (uri); - - (job->iteration)++; - - goto retry; - } - else - { - /* see the error to check whether the location is not accessible - * or the file does not exist. - */ - if (error->code == G_IO_ERROR_NOT_FOUND) - { - GFile *parent; - - /* if the parent directory doesn't exist as well, forget the saved - * directory and treat this as a generic error. - */ - - parent = g_file_get_parent (file); - - if (!g_file_query_exists (parent, NULL)) - { - (job->type)++; - job->iteration = 0; - - g_object_unref (file); - g_object_unref (parent); - goto retry; - } - else - { - job->retval = uri; - - g_object_unref (parent); - goto out; - } - } - else - { - /* another kind of error, assume this location is not - * accessible. - */ - g_free (uri); - if (job->type == TEST_TMP) - { - job->retval = NULL; - goto out; - } - else - { - (job->type)++; - job->iteration = 0; - - g_error_free (error); - g_object_unref (file); - goto retry; - } - } - } - -out: - g_error_free (error); - g_object_unref (file); - - g_io_scheduler_job_send_to_mainloop_async (io_job, - check_file_done, - job, - NULL); - return FALSE; -} - -static GdkWindow * -find_current_window (char **window_title) -{ - GdkWindow *window; - - if (!screenshot_grab_lock ()) - exit (0); - - if (take_window_shot) - { - window = screenshot_find_current_window (); - if (!window) - { - take_window_shot = FALSE; - window = gdk_get_default_root_window (); - } - else - { - gchar *tmp, *sanitized; - - tmp = screenshot_get_window_title (window); - sanitized = screenshot_sanitize_filename (tmp); - g_free (tmp); - *window_title = sanitized; - } - } - else - { - window = gdk_get_default_root_window (); - } - - return window; -} - -static void -push_check_file_job (GdkRectangle *rectangle) -{ - AsyncExistenceJob *job; - - job = g_slice_new0 (AsyncExistenceJob); - job->base_uris[0] = last_save_dir; - /* we'll have to free these two */ - job->base_uris[1] = get_desktop_dir (); - job->base_uris[2] = g_strconcat ("file://", g_get_tmp_dir (), NULL); - job->iteration = 0; - job->type = TEST_LAST_DIR; - job->window = find_current_window (&window_title); - - if (rectangle != NULL) - { - job->rectangle = g_slice_new0 (GdkRectangle); - job->rectangle->x = rectangle->x; - job->rectangle->y = rectangle->y; - job->rectangle->width = rectangle->width; - job->rectangle->height = rectangle->height; - } - - /* Check if the area selection was cancelled */ - if (job->rectangle && - (job->rectangle->width == 0 || job->rectangle->height == 0)) - { - async_existence_job_free (job); - gtk_main_quit (); - return; - } - - g_io_scheduler_push_job (try_check_file, - job, - NULL, - 0, NULL); - -} - -static void -rectangle_found_cb (GdkRectangle *rectangle) -{ - push_check_file_job (rectangle); -} - -static void -prepare_screenshot (void) -{ - if (take_area_shot) - screenshot_select_area_async (rectangle_found_cb); - else - push_check_file_job (NULL); -} - -static gboolean -prepare_screenshot_timeout (gpointer data) -{ - prepare_screenshot (); - save_options (); - - return FALSE; -} - - -static gchar * -get_desktop_dir (void) -{ - gboolean desktop_is_home_dir = FALSE; - gchar *desktop_dir; - gboolean schema_exists = FALSE; - - /* Check if caja schema is installed before trying to read settings */ - GSettingsSchema *schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (), - CAJA_PREFERENCES_SCHEMA, - FALSE); - - if (schema != NULL) { - GSettings *caja_prefs; - - caja_prefs = g_settings_new (CAJA_PREFERENCES_SCHEMA); - desktop_is_home_dir = g_settings_get_boolean (caja_prefs, "desktop-is-home-dir"); - - g_object_unref (caja_prefs); - g_settings_schema_unref (schema); - } - - if (desktop_is_home_dir) - desktop_dir = g_strconcat ("file://", g_get_home_dir (), NULL); - else - desktop_dir = g_strconcat ("file://", g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP), NULL); - - return desktop_dir; -} - -/* Taken from mate-vfs-utils.c */ -static char * -expand_initial_tilde (const char *path) -{ - char *slash_after_user_name, *user_name; - struct passwd *passwd_file_entry; - - if (path[1] == '/' || path[1] == '\0') { - return g_strconcat (g_get_home_dir (), &path[1], NULL); - } - - slash_after_user_name = strchr (&path[1], '/'); - if (slash_after_user_name == NULL) { - user_name = g_strdup (&path[1]); - } else { - user_name = g_strndup (&path[1], - slash_after_user_name - &path[1]); - } - passwd_file_entry = getpwnam (user_name); - g_free (user_name); - - if (passwd_file_entry == NULL || passwd_file_entry->pw_dir == NULL) { - return g_strdup (path); - } - - return g_strconcat (passwd_file_entry->pw_dir, - slash_after_user_name, - NULL); -} - -/* Load options */ -static void -load_options (void) -{ - /* Find various dirs */ - last_save_dir = g_settings_get_string (settings, - LAST_SAVE_DIRECTORY_KEY); - if (!last_save_dir || !last_save_dir[0]) - { - last_save_dir = get_desktop_dir (); - } - else if (last_save_dir[0] == '~') - { - char *tmp = expand_initial_tilde (last_save_dir); - g_free (last_save_dir); - last_save_dir = tmp; - } - - include_border = g_settings_get_boolean (settings, - INCLUDE_BORDER_KEY); - - include_pointer = g_settings_get_boolean (settings, - INCLUDE_POINTER_KEY); - - border_effect = g_settings_get_string (settings, - BORDER_EFFECT_KEY); - if (!border_effect) - border_effect = g_strdup ("none"); - - delay = g_settings_get_int (settings, DELAY_KEY); -} - -static void -save_options (void) -{ - g_settings_set_boolean (settings, - INCLUDE_BORDER_KEY, include_border); - g_settings_set_boolean (settings, - INCLUDE_POINTER_KEY, include_pointer); - g_settings_set_int (settings, DELAY_KEY, delay); - g_settings_set_string (settings, - BORDER_EFFECT_KEY, border_effect); -} - - -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); -} - -/* main */ -int -main (int argc, char *argv[]) -{ - GOptionContext *context; - 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; - - const GOptionEntry entries[] = { - { "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 }, - }; - - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); - 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); - - if (window_arg && area_arg) { - g_printerr (_("Conflicting options: --window and --area should not be " - "used at the same time.\n")); - exit (1); - } - - gtk_window_set_default_icon_name (SCREENSHOOTER_ICON); - screenshooter_init_stock_icons (); - - settings = g_settings_new (MATE_SCREENSHOT_SCHEMA); - load_options (); - /* allow the command line to override options */ - if (window_arg) - take_window_shot = TRUE; - - if (area_arg) - take_area_shot = TRUE; - - if (include_border_arg) - include_border = TRUE; - - if (disable_border_arg) - include_border = FALSE; - - if (border_effect_arg) - { - g_free (border_effect); - border_effect = border_effect_arg; - } - - if (delay_arg > 0) - delay = delay_arg; - - /* interactive mode overrides everything */ - if (interactive_arg) - { - GtkWidget *dialog; - gint response; - - dialog = create_interactive_dialog (); - response = gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - - switch (response) - { - case GTK_RESPONSE_DELETE_EVENT: - case GTK_RESPONSE_CANCEL: - return EXIT_SUCCESS; - case GTK_RESPONSE_OK: - break; - default: - g_assert_not_reached (); - break; - } - } - - if (((delay > 0 && interactive_arg) || delay_arg > 0) && - !take_area_shot) - { - g_timeout_add (delay * 1000, - prepare_screenshot_timeout, - NULL); - } - else - { - if (interactive_arg) - { - /* HACK: give time to the dialog to actually disappear. - * We don't have any way to tell when the compositor has finished - * re-drawing. - */ - g_timeout_add (200, - prepare_screenshot_timeout, NULL); - } - else - g_idle_add (prepare_screenshot_timeout, NULL); - } - - gtk_main (); - - return EXIT_SUCCESS; -} |