Added mechanism that should prevent undo corruption by broken plug-ins and

2006-10-25  Michael Natterer  <mitch@gimp.org>

	Added mechanism that should prevent undo corruption by
	broken plug-ins and scripts. Work in progress.

	* app/plug-in/Makefile.am
	* app/plug-in/gimpplugin-cleanup.[ch]: new files that (for now)
	keep track of the undo groups plug-in procedures open and close,
	and can fix an image's undo group state after a plug-in messed.

	* app/plug-in/gimppluginprocframe.h (struct GimpPlugInProcFrame):
	keep a list of plug-in cleanup structs.

	* app/plug-in/gimppluginprocframe.c
	(gimp_plug_in_proc_frame_dispose): call gimp_plug_in_cleanup() if
	the list is not empty.

	* tools/pdbgen/pdb/undo.pdb: keep track of undo groups using
	the new gimp_plug_in_cleanup_undo_group_start() and _end()
	functions. Fail if any of the functions returns FALSE.

	* app/pdb/undo_cmds.c: regenerated.
This commit is contained in:
Michael Natterer 2006-10-25 09:41:05 +00:00 committed by Michael Natterer
parent a1c0603228
commit b6f9bf5d57
8 changed files with 387 additions and 21 deletions

View File

@ -1,3 +1,26 @@
2006-10-25 Michael Natterer <mitch@gimp.org>
Added mechanism that should prevent undo corruption by
broken plug-ins and scripts. Work in progress.
* app/plug-in/Makefile.am
* app/plug-in/gimpplugin-cleanup.[ch]: new files that (for now)
keep track of the undo groups plug-in procedures open and close,
and can fix an image's undo group state after a plug-in messed.
* app/plug-in/gimppluginprocframe.h (struct GimpPlugInProcFrame):
keep a list of plug-in cleanup structs.
* app/plug-in/gimppluginprocframe.c
(gimp_plug_in_proc_frame_dispose): call gimp_plug_in_cleanup() if
the list is not empty.
* tools/pdbgen/pdb/undo.pdb: keep track of undo groups using
the new gimp_plug_in_cleanup_undo_group_start() and _end()
functions. Fail if any of the functions returns FALSE.
* app/pdb/undo_cmds.c: regenerated.
2006-10-25 Sven Neumann <sven@gimp.org>
* app/core/gimpimage.[ch]: added signals "parasite-attached" and

View File

@ -31,6 +31,7 @@
#include "core/gimp.h"
#include "core/gimpimage-undo.h"
#include "core/gimpimage.h"
#include "plug-in/gimpplugin-cleanup.h"
#include "plug-in/gimpplugin.h"
#include "plug-in/gimppluginmanager.h"
@ -49,13 +50,19 @@ image_undo_group_start_invoker (GimpProcedure *procedure,
if (success)
{
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
gchar *undo_desc = NULL;
if (plug_in)
undo_desc = gimp_plug_in_get_undo_desc (plug_in);
{
success = gimp_plug_in_cleanup_undo_group_start (plug_in, image);
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_MISC, undo_desc);
if (success)
undo_desc = gimp_plug_in_get_undo_desc (plug_in);
}
if (success)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_MISC, undo_desc);
if (undo_desc)
g_free (undo_desc);
@ -78,7 +85,13 @@ image_undo_group_end_invoker (GimpProcedure *procedure,
if (success)
{
gimp_image_undo_group_end (image);
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_group_end (plug_in, image);
if (success)
gimp_image_undo_group_end (image);
}
return gimp_procedure_get_return_values (procedure, success);
@ -127,7 +140,15 @@ image_undo_disable_invoker (GimpProcedure *procedure,
if (success)
{
disabled = gimp_image_undo_disable (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_disable (plug_in, image);
#endif
if (success)
disabled = gimp_image_undo_disable (image);
}
return_vals = gimp_procedure_get_return_values (procedure, success);
@ -154,7 +175,15 @@ image_undo_enable_invoker (GimpProcedure *procedure,
if (success)
{
enabled = gimp_image_undo_enable (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_enable (plug_in, image);
#endif
if (success)
enabled = gimp_image_undo_enable (image);
}
return_vals = gimp_procedure_get_return_values (procedure, success);
@ -181,7 +210,15 @@ image_undo_freeze_invoker (GimpProcedure *procedure,
if (success)
{
frozen = gimp_image_undo_freeze (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_freeze (plug_in, image);
#endif
if (success)
frozen = gimp_image_undo_freeze (image);
}
return_vals = gimp_procedure_get_return_values (procedure, success);
@ -208,7 +245,15 @@ image_undo_thaw_invoker (GimpProcedure *procedure,
if (success)
{
thawed = gimp_image_undo_thaw (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_thaw (plug_in, image);
#endif
if (success)
thawed = gimp_image_undo_thaw (image);
}
return_vals = gimp_procedure_get_return_values (procedure, success);

View File

@ -27,6 +27,8 @@ libappplug_in_a_SOURCES = \
gimpplugindebug.h \
gimpplugin.c \
gimpplugin.h \
gimpplugin-cleanup.c \
gimpplugin-cleanup.h \
gimpplugin-context.c \
gimpplugin-context.h \
gimpplugin-message.c \

View File

@ -0,0 +1,209 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpplugin-cleanup.c
*
* 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 "glib-object.h"
#include "plug-in-types.h"
#include "core/gimp.h"
#include "core/gimpcontainer.h"
#include "core/gimpimage.h"
#include "core/gimpimage-undo.h"
#include "core/gimpdrawable.h"
#include "core/gimpundostack.h"
#include "gimpplugin.h"
#include "gimpplugin-cleanup.h"
#include "gimppluginmanager.h"
#include "gimppluginmanager-locale-domain.h"
#include "gimppluginprocedure.h"
typedef struct _GimpPlugInCleanupImage GimpPlugInCleanupImage;
struct _GimpPlugInCleanupImage
{
GimpImage *image;
gint undo_group_count;
};
/* local function prototypes */
static GimpPlugInCleanupImage *
gimp_plug_in_cleanup_get_image (GimpPlugInProcFrame *proc_frame,
GimpImage *image);
/* public functions */
gboolean
gimp_plug_in_cleanup_undo_group_start (GimpPlugIn *plug_in,
GimpImage *image)
{
GimpPlugInProcFrame *proc_frame;
GimpPlugInCleanupImage *cleanup;
g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
proc_frame = gimp_plug_in_get_proc_frame (plug_in);
cleanup = gimp_plug_in_cleanup_get_image (proc_frame, image);
g_printerr ("\n%s: procedure %s starts undo group on\n"
"image with group count %d\n",
G_STRFUNC, GIMP_OBJECT (proc_frame->procedure)->name,
image->group_count);
if (! cleanup)
{
g_printerr ("%s: creating new cleanup entry => SUCCESS\n", G_STRFUNC);
cleanup = g_new0 (GimpPlugInCleanupImage, 1);
cleanup->image = image;
cleanup->undo_group_count = image->group_count;
proc_frame->cleanups = g_list_prepend (proc_frame->cleanups, cleanup);
}
else
{
g_printerr ("%s: using existing cleanup entry => SUCCESS\n", G_STRFUNC);
}
return TRUE;
}
gboolean
gimp_plug_in_cleanup_undo_group_end (GimpPlugIn *plug_in,
GimpImage *image)
{
GimpPlugInProcFrame *proc_frame;
GimpPlugInCleanupImage *cleanup;
g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE);
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
proc_frame = gimp_plug_in_get_proc_frame (plug_in);
cleanup = gimp_plug_in_cleanup_get_image (proc_frame, image);
g_printerr ("\n%s: procedure %s ends undo group on\n"
"image with group count %d\n",
G_STRFUNC, GIMP_OBJECT (proc_frame->procedure)->name,
image->group_count);
if (! cleanup)
{
g_printerr ("%s: no cleanup entry found => FAILURE\n", G_STRFUNC);
return FALSE;
}
if (cleanup->undo_group_count == image->group_count - 1)
{
g_printerr ("%s: group count balanced, deleting cleanup entry => SUCCESS\n",
G_STRFUNC);
proc_frame->cleanups = g_list_remove (proc_frame->cleanups, cleanup);
g_free (cleanup);
}
else
{
g_printerr ("%s: undo groups still open, keeping cleanup entry => SUCCESS\n",
G_STRFUNC);
}
return TRUE;
}
void
gimp_plug_in_cleanup (GimpPlugIn *plug_in,
GimpPlugInProcFrame *proc_frame)
{
GList *list;
g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
g_return_if_fail (proc_frame != NULL);
for (list = proc_frame->cleanups; list; list = g_list_next (list))
{
GimpPlugInCleanupImage *cleanup = list->data;
GimpImage *image = cleanup->image;
if (! gimp_container_have (plug_in->manager->gimp->images,
(GimpObject *) image))
continue;
if (image->pushing_undo_group == GIMP_UNDO_GROUP_NONE)
continue;
g_printerr ("\n%s: checking image with group count %d\n",
G_STRFUNC, image->group_count);
if (cleanup->undo_group_count != image->group_count)
{
const gchar *domain;
gchar *label;
domain = gimp_plug_in_manager_get_locale_domain (plug_in->manager,
plug_in->prog, NULL);
label = gimp_plug_in_procedure_get_label (GIMP_PLUG_IN_PROCEDURE (proc_frame->procedure),
domain);
g_message ("Plug-In '%s' left image undo in inconsistent state, "
"closing open undo groups.", label);
g_free (label);
while (image->pushing_undo_group != GIMP_UNDO_GROUP_NONE &&
cleanup->undo_group_count < image->group_count)
{
if (! gimp_image_undo_group_end (image))
break;
}
}
g_free (cleanup);
}
g_list_free (proc_frame->cleanups);
proc_frame->cleanups = NULL;
}
/* private functions */
static GimpPlugInCleanupImage *
gimp_plug_in_cleanup_get_image (GimpPlugInProcFrame *proc_frame,
GimpImage *image)
{
GList *list;
for (list = proc_frame->cleanups; list; list = g_list_next (list))
{
GimpPlugInCleanupImage *cleanup = list->data;
if (cleanup->image == image)
return cleanup;
}
return NULL;
}

View File

@ -0,0 +1,34 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpplugin-cleanup.h
*
* 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 __GIMP_PLUG_IN_CLEANUP_H__
#define __GIMP_PLUG_IN_CLEANUP_H__
gboolean gimp_plug_in_cleanup_undo_group_start (GimpPlugIn *plug_in,
GimpImage *image);
gboolean gimp_plug_in_cleanup_undo_group_end (GimpPlugIn *plug_in,
GimpImage *image);
void gimp_plug_in_cleanup (GimpPlugIn *plug_in,
GimpPlugInProcFrame *proc_frame);
#endif /* __GIMP_PLUG_IN_CLEANUP_H__ */

View File

@ -30,11 +30,12 @@
#include "core/gimpprogress.h"
#include "gimpplugin.h"
#include "gimpplugin-cleanup.h"
#include "gimpplugin-progress.h"
#include "gimppluginprocedure.h"
/* publuc functions */
/* public functions */
GimpPlugInProcFrame *
gimp_plug_in_proc_frame_new (GimpContext *context,
@ -120,6 +121,9 @@ gimp_plug_in_proc_frame_dispose (GimpPlugInProcFrame *proc_frame,
g_main_loop_unref (proc_frame->main_loop);
proc_frame->main_loop = NULL;
}
if (proc_frame->cleanups)
gimp_plug_in_cleanup (plug_in, proc_frame);
}
GimpPlugInProcFrame *

View File

@ -37,6 +37,9 @@ struct _GimpPlugInProcFrame
GimpProgress *progress;
gboolean progress_created;
gulong progress_cancel_id;
/* lists of things to clean up on dispose */
GList *cleanups;
};

View File

@ -35,17 +35,21 @@ HELP
);
%invoke = (
headers => [ qw("core/gimp.h" "plug-in/gimppluginmanager.h"
"plug-in/gimpplugin.h") ],
code => <<'CODE'
code => <<'CODE'
{
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
gchar *undo_desc = NULL;
if (plug_in)
undo_desc = gimp_plug_in_get_undo_desc (plug_in);
{
success = gimp_plug_in_cleanup_undo_group_start (plug_in, image);
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_MISC, undo_desc);
if (success)
undo_desc = gimp_plug_in_get_undo_desc (plug_in);
}
if (success)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_MISC, undo_desc);
if (undo_desc)
g_free (undo_desc);
@ -73,7 +77,13 @@ HELP
%invoke = (
code => <<'CODE'
{
gimp_image_undo_group_end (image);
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_group_end (plug_in, image);
if (success)
gimp_image_undo_group_end (image);
}
CODE
);
@ -135,7 +145,15 @@ HELP
%invoke = (
code => <<'CODE'
{
disabled = gimp_image_undo_disable (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_disable (plug_in, image);
#endif
if (success)
disabled = gimp_image_undo_disable (image);
}
CODE
);
@ -165,7 +183,15 @@ HELP
%invoke = (
code => <<'CODE'
{
enabled = gimp_image_undo_enable (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_enable (plug_in, image);
#endif
if (success)
enabled = gimp_image_undo_enable (image);
}
CODE
);
@ -203,7 +229,15 @@ HELP
%invoke = (
code => <<'CODE'
{
frozen = gimp_image_undo_freeze (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_freeze (plug_in, image);
#endif
if (success)
frozen = gimp_image_undo_freeze (image);
}
CODE
);
@ -240,14 +274,26 @@ HELP
%invoke = (
code => <<'CODE'
{
thawed = gimp_image_undo_thaw (image);
#if 0
GimpPlugIn *plug_in = gimp->plug_in_manager->current_plug_in;
if (plug_in)
success = gimp_plug_in_cleanup_undo_thaw (plug_in, image);
#endif
if (success)
thawed = gimp_image_undo_thaw (image);
}
CODE
);
}
@headers = qw("core/gimpimage-undo.h");
@headers = qw("core/gimp.h"
"core/gimpimage-undo.h"
"plug-in/gimpplugin.h"
"plug-in/gimpplugin-cleanup.h"
"plug-in/gimppluginmanager.h");
@procs = qw(image_undo_group_start image_undo_group_end
image_undo_is_enabled