mirror of
https://gitlab.gnome.org/GNOME/gimp
synced 2024-10-21 12:02:32 +00:00
9252db5865
2003-05-17 Michael Natterer <mitch@gimp.org> Fixed File->Revert, which was completely broken before: * app/gui/file-commands.c (file_revert_confirm_callback): set the new image on all GimpContexts which had the old image set. Unref the new image after the displays are reconnected. Added some paranoia code for similar future situations (the functions below were not broken, but affected by the above bug): * app/display/gimpdisplay-handlers.c (gimp_display_disconnect): set gdisp->gimage to NULL before unrefing the image. * app/widgets/gimpimagedock.c (gimp_image_dock_image_changed): unref the gimage pointer returned by g_object_get() only if it is non-NULL. Cleanup.
486 lines
12 KiB
C
486 lines
12 KiB
C
/* The GIMP -- an image manipulation program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* 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 <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
#include "gui-types.h"
|
|
|
|
#include "config/gimpguiconfig.h"
|
|
|
|
#include "core/gimp.h"
|
|
#include "core/gimpcontainer.h"
|
|
#include "core/gimpcontext.h"
|
|
#include "core/gimplist.h"
|
|
#include "core/gimpimage.h"
|
|
#include "core/gimpimage-undo.h"
|
|
#include "core/gimptemplate.h"
|
|
|
|
#include "file/file-open.h"
|
|
#include "file/file-save.h"
|
|
#include "file/file-utils.h"
|
|
|
|
#include "widgets/gimpdialogfactory.h"
|
|
|
|
#include "display/gimpdisplay.h"
|
|
#include "display/gimpdisplay-foreach.h"
|
|
#include "display/gimpdisplayshell.h"
|
|
|
|
#include "dialogs.h"
|
|
#include "file-commands.h"
|
|
#include "file-new-dialog.h"
|
|
#include "file-open-dialog.h"
|
|
#include "file-save-dialog.h"
|
|
#include "menus.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
#define REVERT_DATA_KEY "revert-confirm-dialog"
|
|
|
|
|
|
#define return_if_no_gimp(gimp,data) \
|
|
if (GIMP_IS_DISPLAY (data)) \
|
|
gimp = ((GimpDisplay *) data)->gimage->gimp; \
|
|
else if (GIMP_IS_GIMP (data)) \
|
|
gimp = data; \
|
|
else \
|
|
gimp = NULL; \
|
|
if (! gimp) \
|
|
return
|
|
|
|
|
|
#define return_if_no_display(gdisp,data) \
|
|
if (GIMP_IS_DISPLAY (data)) \
|
|
gdisp = data; \
|
|
else if (GIMP_IS_GIMP (data)) \
|
|
gdisp = gimp_context_get_display (gimp_get_user_context (GIMP (data))); \
|
|
else \
|
|
gdisp = NULL; \
|
|
if (! gdisp) \
|
|
return
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
static void file_new_template_callback (GtkWidget *widget,
|
|
gchar *name,
|
|
gpointer data);
|
|
static void file_revert_confirm_callback (GtkWidget *widget,
|
|
gboolean revert,
|
|
gpointer data);
|
|
|
|
|
|
/* public functions */
|
|
|
|
void
|
|
file_new_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
Gimp *gimp;
|
|
GimpImage *gimage;
|
|
GtkWidget *dialog;
|
|
return_if_no_gimp (gimp, data);
|
|
|
|
/* if called from the image menu */
|
|
if (action)
|
|
gimage = gimp_context_get_image (gimp_get_user_context (gimp));
|
|
else
|
|
gimage = NULL;
|
|
|
|
dialog = gimp_dialog_factory_dialog_new (global_dialog_factory,
|
|
"gimp-file-new-dialog", -1);
|
|
|
|
if (dialog)
|
|
file_new_dialog_set (dialog, gimage, NULL);
|
|
}
|
|
|
|
void
|
|
file_open_by_extension_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
file_open_dialog_set_type (NULL);
|
|
}
|
|
|
|
void
|
|
file_open_type_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
file_open_dialog_set_type ((PlugInProcDef *) data);
|
|
}
|
|
|
|
void
|
|
file_open_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
Gimp *gimp;
|
|
GimpImage *gimage;
|
|
return_if_no_gimp (gimp, data);
|
|
|
|
/* if called from the image menu */
|
|
if (action)
|
|
gimage = gimp_context_get_image (gimp_get_user_context (gimp));
|
|
else
|
|
gimage = NULL;
|
|
|
|
file_open_dialog_show (gimp, gimage, NULL, global_menu_factory);
|
|
}
|
|
|
|
void
|
|
file_last_opened_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
Gimp *gimp;
|
|
GimpImagefile *imagefile;
|
|
guint num_entries;
|
|
return_if_no_gimp (gimp, data);
|
|
|
|
num_entries = gimp_container_num_children (gimp->documents);
|
|
|
|
if (action >= num_entries)
|
|
return;
|
|
|
|
imagefile = (GimpImagefile *)
|
|
gimp_container_get_child_by_index (gimp->documents, action);
|
|
|
|
if (imagefile)
|
|
{
|
|
GimpImage *gimage;
|
|
GimpPDBStatusType status;
|
|
GError *error = NULL;
|
|
|
|
gimage = file_open_with_display (gimp, GIMP_OBJECT (imagefile)->name,
|
|
&status, &error);
|
|
|
|
if (! gimage && status != GIMP_PDB_CANCEL)
|
|
{
|
|
gchar *filename;
|
|
|
|
filename =
|
|
file_utils_uri_to_utf8_filename (GIMP_OBJECT (imagefile)->name);
|
|
|
|
g_message (_("Opening '%s' failed:\n\n%s"),
|
|
filename, error->message);
|
|
g_clear_error (&error);
|
|
|
|
g_free (filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
file_save_by_extension_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
file_save_dialog_set_type (NULL);
|
|
}
|
|
|
|
void
|
|
file_save_type_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
file_save_dialog_set_type ((PlugInProcDef *) data);
|
|
}
|
|
|
|
void
|
|
file_save_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
GimpDisplay *gdisp;
|
|
return_if_no_display (gdisp, data);
|
|
|
|
if (! gimp_image_active_drawable (gdisp->gimage))
|
|
return;
|
|
|
|
/* Only save if the gimage has been modified */
|
|
if (gdisp->gimage->dirty ||
|
|
! GIMP_GUI_CONFIG (gdisp->gimage->gimp->config)->trust_dirty_flag)
|
|
{
|
|
const gchar *uri;
|
|
|
|
uri = gimp_object_get_name (GIMP_OBJECT (gdisp->gimage));
|
|
|
|
if (! uri)
|
|
{
|
|
file_save_as_cmd_callback (widget, data, action);
|
|
}
|
|
else
|
|
{
|
|
GimpPDBStatusType status;
|
|
GError *error = NULL;
|
|
|
|
status = file_save (gdisp->gimage, GIMP_RUN_WITH_LAST_VALS, &error);
|
|
|
|
if (status != GIMP_PDB_SUCCESS &&
|
|
status != GIMP_PDB_CANCEL)
|
|
{
|
|
gchar *filename;
|
|
|
|
filename = file_utils_uri_to_utf8_filename (uri);
|
|
|
|
g_message (_("Saving '%s' failed:\n\n%s"),
|
|
filename, error->message);
|
|
g_clear_error (&error);
|
|
|
|
g_free (filename);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
file_save_as_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
GimpDisplay *gdisp;
|
|
return_if_no_display (gdisp, data);
|
|
|
|
file_save_dialog_show (gdisp->gimage, global_menu_factory);
|
|
}
|
|
|
|
void
|
|
file_save_a_copy_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
GimpDisplay *gdisp;
|
|
return_if_no_display (gdisp, data);
|
|
|
|
file_save_a_copy_dialog_show (gdisp->gimage, global_menu_factory);
|
|
}
|
|
|
|
void
|
|
file_save_template_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
GimpDisplay *gdisp;
|
|
GtkWidget *qbox;
|
|
return_if_no_display (gdisp, data);
|
|
|
|
qbox = gimp_query_string_box (_("Create New Template"),
|
|
gimp_standard_help_func,
|
|
"dialogs/new_template.html",
|
|
_("Enter a name for this template"),
|
|
NULL,
|
|
G_OBJECT (gdisp->gimage), "disconnect",
|
|
file_new_template_callback, gdisp->gimage);
|
|
gtk_widget_show (qbox);
|
|
}
|
|
|
|
void
|
|
file_revert_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
GimpDisplay *gdisp;
|
|
GtkWidget *query_box;
|
|
const gchar *uri;
|
|
return_if_no_display (gdisp, data);
|
|
|
|
uri = gimp_object_get_name (GIMP_OBJECT (gdisp->gimage));
|
|
|
|
query_box = g_object_get_data (G_OBJECT (gdisp->gimage), REVERT_DATA_KEY);
|
|
|
|
if (! uri)
|
|
{
|
|
g_message (_("Revert failed.\n"
|
|
"No file name associated with this image."));
|
|
}
|
|
else if (query_box)
|
|
{
|
|
gtk_window_present (GTK_WINDOW (query_box->window));
|
|
}
|
|
else
|
|
{
|
|
gchar *basename;
|
|
gchar *text;
|
|
|
|
basename = g_path_get_basename (uri);
|
|
|
|
text = g_strdup_printf (_("Revert '%s' to\n"
|
|
"'%s'?\n\n"
|
|
"You will lose all your changes, "
|
|
"including all undo information."),
|
|
basename, uri);
|
|
|
|
g_free (basename);
|
|
|
|
query_box = gimp_query_boolean_box (_("Revert Image"),
|
|
gimp_standard_help_func,
|
|
"file/revert.html",
|
|
GIMP_STOCK_QUESTION,
|
|
text,
|
|
GTK_STOCK_YES, GTK_STOCK_NO,
|
|
G_OBJECT (gdisp->gimage),
|
|
"disconnect",
|
|
file_revert_confirm_callback,
|
|
gdisp->gimage);
|
|
|
|
g_free (text);
|
|
|
|
g_object_set_data (G_OBJECT (gdisp->gimage), REVERT_DATA_KEY,
|
|
query_box);
|
|
|
|
gtk_window_set_transient_for (GTK_WINDOW (query_box),
|
|
GTK_WINDOW (gdisp->shell));
|
|
|
|
gtk_widget_show (query_box);
|
|
}
|
|
}
|
|
|
|
void
|
|
file_close_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
GimpDisplay *gdisp;
|
|
return_if_no_display (gdisp, data);
|
|
|
|
gimp_display_shell_close (GIMP_DISPLAY_SHELL (gdisp->shell), FALSE);
|
|
}
|
|
|
|
void
|
|
file_quit_cmd_callback (GtkWidget *widget,
|
|
gpointer data,
|
|
guint action)
|
|
{
|
|
Gimp *gimp;
|
|
return_if_no_gimp (gimp, data);
|
|
|
|
gimp_exit (gimp, FALSE);
|
|
}
|
|
|
|
void
|
|
file_file_open_dialog (Gimp *gimp,
|
|
const gchar *uri)
|
|
{
|
|
file_open_dialog_show (gimp, NULL, uri, global_menu_factory);
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static void
|
|
file_new_template_callback (GtkWidget *widget,
|
|
gchar *name,
|
|
gpointer data)
|
|
{
|
|
GimpTemplate *template;
|
|
GimpImage *gimage;
|
|
|
|
gimage = (GimpImage *) data;
|
|
|
|
if (! (name && strlen (name)))
|
|
name = _("(Unnamed Template)");
|
|
|
|
template = gimp_template_new (name);
|
|
gimp_template_set_from_image (template, gimage);
|
|
|
|
gimp_list_uniquefy_name (GIMP_LIST (gimage->gimp->templates),
|
|
GIMP_OBJECT (template), TRUE);
|
|
gimp_container_add (gimage->gimp->templates,
|
|
GIMP_OBJECT (template));
|
|
g_object_unref (template);
|
|
}
|
|
|
|
static void
|
|
file_revert_confirm_callback (GtkWidget *widget,
|
|
gboolean revert,
|
|
gpointer data)
|
|
{
|
|
GimpImage *old_gimage;
|
|
|
|
old_gimage = (GimpImage *) data;
|
|
|
|
g_object_set_data (G_OBJECT (old_gimage), REVERT_DATA_KEY, NULL);
|
|
|
|
if (revert)
|
|
{
|
|
Gimp *gimp;
|
|
GimpImage *new_gimage;
|
|
const gchar *uri;
|
|
GimpPDBStatusType status;
|
|
GError *error = NULL;
|
|
|
|
gimp = old_gimage->gimp;
|
|
|
|
uri = gimp_object_get_name (GIMP_OBJECT (old_gimage));
|
|
|
|
new_gimage = file_open_image (gimp, uri, uri, NULL,
|
|
GIMP_RUN_INTERACTIVE,
|
|
&status, &error);
|
|
|
|
if (new_gimage)
|
|
{
|
|
GList *contexts = NULL;
|
|
GList *list;
|
|
|
|
/* remember which contexts refer to old_gimage */
|
|
for (list = gimp->context_list; list; list = g_list_next (list))
|
|
{
|
|
GimpContext *context = list->data;
|
|
|
|
if (gimp_context_get_image (context) == old_gimage)
|
|
contexts = g_list_prepend (contexts, list->data);
|
|
}
|
|
|
|
gimp_image_undo_free (new_gimage);
|
|
gimp_displays_reconnect (gimp, old_gimage, new_gimage);
|
|
gimp_image_clean_all (new_gimage);
|
|
gimp_image_flush (new_gimage);
|
|
|
|
/* set the new_gimage on the remembered contexts (in reverse
|
|
* order, since older contexts are usually the parents of
|
|
* newer ones)
|
|
*/
|
|
g_list_foreach (contexts, (GFunc) gimp_context_set_image, new_gimage);
|
|
g_list_free (contexts);
|
|
|
|
/* the displays own the image now */
|
|
g_object_unref (new_gimage);
|
|
}
|
|
else if (status != GIMP_PDB_CANCEL)
|
|
{
|
|
gchar *filename;
|
|
|
|
filename = file_utils_uri_to_utf8_filename (uri);
|
|
|
|
g_message (_("Reverting to '%s' failed:\n\n%s"),
|
|
filename, error->message);
|
|
g_clear_error (&error);
|
|
|
|
g_free (filename);
|
|
}
|
|
}
|
|
}
|