diff --git a/ChangeLog b/ChangeLog index 6c0f11588e..d44deedf38 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,75 @@ +2003-02-20 Michael Natterer + + Reimplemented the undo history: + + * app/Makefile.am + * app/undo_history.[ch]: removed. + + Changes/cleanups to the undo system to enable/simplify the new + undo history implementation: + + * app/core/core-types.h: removed enum undo_event_t. Removed the + GimpImage parameter from GimpUndoPopFunc and GimpUndoFreeFunc + because GimpUndo has a GimpImage pointer now (see below). + + * app/core/core-enums.[ch]: added enum GimpUndoEvent. Added an + enum value for REDO_EXPIRED. + + * app/core/gimpimage.[ch]: added a GimpUndo pointer to the + "undo_event" signal which needs to be passed for all events except + UNDO_FREE. + + * app/display/gimpdisplayshell-handlers.c: changed accordingly. + + * app/core/gimpundo.[ch]: added a GimpImage pointer to the + GimpUndo struct. Removed GimpImage parameters all over the + place. Added preview stuff. The preview creation needs to be + triggered explicitly using gimp_undo_create_preview() because the + GimpUndo can't know when it's possible to create the preview. + + * app/core/gimpimage-undo-push.c + * app/paint/gimppaintcore-undo.c + * app/tools/gimptransformtool-undo.c: changed accordingly, cleanup. + + * app/core/gimpundostack.[ch]: ditto. Return the freed undo from + gimp_undo_stack_free_bottom(). Removed unused container signal + handlers. + + * app/core/gimpimage-undo.c: free the redo stack the same way old + undos are freed (from bottom up). Emit "undo_event" with event == + REDO_EXPIRED for each removed redo. + + * app/core/gimpmarshal.list: added new marshallers. + + New undo history implementation: + + * app/widgets/Makefile.am + * app/widgets/widgets-types.h + * app/widgets/gimpundoeditor.[ch] + * app/widgets/gimpundopreview.[ch]: new widgets for the undo + step previews and the history itself. + + * app/widgets/gimppreview-utils.c: added GimpUndoPreview to the + list of possible preview types. + + * app/gui/dialogs-constructors.[ch] + * app/gui/dialogs-menu.c + * app/gui/dialogs.c + * app/gui/image-menu.c + * app/gui/toolbox-menu.c: removed the old and added the new undo + history to the dialog factory and the various dialog menus. + + * app/widgets/gimpdnd.[ch]: don't warn if a GType has no + corresponding DND type. Instead, return FALSE from the function + that failed. + + * app/widgets/gimppreview.c: check the return value of gimpdnd + functions. Not only add drag sources but also remove them when no + longer needed. + + * app/widgets/gimpselectioneditor.h: removed unneeded inclusion of + "gui/gui-types.h". + 2003-02-19 Tor Lillqvist * libgimpbase/gimpbase.def: Add gimp_utf8_strtrim. Sort. Remove diff --git a/app/Makefile.am b/app/Makefile.am index b2d9935dbf..14431075d1 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -35,13 +35,6 @@ scriptdata = bin_PROGRAMS = gimp-1.3 -## -## gui stuff for gui/, display/ or widgets/ -## -gui_sources = \ - undo_history.c \ - undo_history.h - ## ## stuff which is about to be replaced by new subsystems ## @@ -69,7 +62,6 @@ stuff_sources = \ libgimp_glue.h gimp_1_3_SOURCES = \ - $(gui_sources) \ $(bye_sources) \ $(stuff_sources) diff --git a/app/core/core-enums.c b/app/core/core-enums.c index abfd545191..260bd0e192 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -381,6 +381,29 @@ gimp_undo_mode_get_type (void) } +static const GEnumValue gimp_undo_event_enum_values[] = +{ + { GIMP_UNDO_EVENT_UNDO_PUSHED, "GIMP_UNDO_EVENT_UNDO_PUSHED", "undo-pushed" }, + { GIMP_UNDO_EVENT_UNDO_EXPIRED, "GIMP_UNDO_EVENT_UNDO_EXPIRED", "undo-expired" }, + { GIMP_UNDO_EVENT_REDO_EXPIRED, "GIMP_UNDO_EVENT_REDO_EXPIRED", "redo-expired" }, + { GIMP_UNDO_EVENT_UNDO, "GIMP_UNDO_EVENT_UNDO", "undo" }, + { GIMP_UNDO_EVENT_REDO, "GIMP_UNDO_EVENT_REDO", "redo" }, + { GIMP_UNDO_EVENT_UNDO_FREE, "GIMP_UNDO_EVENT_UNDO_FREE", "undo-free" }, + { 0, NULL, NULL } +}; + +GType +gimp_undo_event_get_type (void) +{ + static GType enum_type = 0; + + if (!enum_type) + enum_type = g_enum_register_static ("GimpUndoEvent", gimp_undo_event_enum_values); + + return enum_type; +} + + static const GEnumValue gimp_undo_type_enum_values[] = { { GIMP_UNDO_GROUP_NONE, N_("<>"), "group-none" }, diff --git a/app/core/core-enums.h b/app/core/core-enums.h index 31818daa31..41ee8dd9bc 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -280,6 +280,21 @@ typedef enum /*< pdb-skip >*/ } GimpUndoMode; +#define GIMP_TYPE_UNDO_EVENT (gimp_undo_event_get_type ()) + +GType gimp_undo_event_get_type (void) G_GNUC_CONST; + +typedef enum /*< pdb-skip >*/ +{ + GIMP_UNDO_EVENT_UNDO_PUSHED, /* a new undo has been added to the undo stack */ + GIMP_UNDO_EVENT_UNDO_EXPIRED, /* an undo has been freed from the undo stack */ + GIMP_UNDO_EVENT_REDO_EXPIRED, /* a redo has been freed from the redo stack */ + GIMP_UNDO_EVENT_UNDO, /* an undo has been executed */ + GIMP_UNDO_EVENT_REDO, /* a redo has been executed */ + GIMP_UNDO_EVENT_UNDO_FREE /* all undo and redo info has been cleared */ +} GimpUndoEvent; + + #define GIMP_TYPE_UNDO_TYPE (gimp_undo_type_get_type ()) GType gimp_undo_type_get_type (void) G_GNUC_CONST; diff --git a/app/core/core-types.h b/app/core/core-types.h index d0a904de62..b927dbd615 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -44,18 +44,6 @@ typedef enum GIMP_POINTS } SizeType; -/* Argument to undo_event signal emitted by images */ - -typedef enum /*< pdb-skip >*/ /*< skip >*/ -{ - UNDO_PUSHED, /* a new undo has been added to the undo stack */ - UNDO_EXPIRED, /* an undo has been freed from the undo stack */ - UNDO_POPPED, /* an undo has been executed and moved to redo stack */ - UNDO_REDO, /* a redo has been executed and moved to undo stack */ - UNDO_FREE /* all undo and redo info has been cleared */ -} undo_event_t; - - /* base objects */ @@ -160,11 +148,9 @@ typedef void (* GimpInitStatusFunc) (const gchar *text1, typedef GimpData * (* GimpDataObjectLoaderFunc) (const gchar *filename); typedef gboolean (* GimpUndoPopFunc) (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); typedef void (* GimpUndoFreeFunc) (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index 923c03461c..2cc2a5d8f3 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -76,11 +76,9 @@ struct _ImageUndo }; static gboolean undo_pop_image (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_image (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -203,7 +201,6 @@ gimp_image_undo_push_image_mod (GimpImage *gimage, static gboolean undo_pop_image (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -277,7 +274,6 @@ undo_pop_image (GimpUndo *undo, static void undo_free_image (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { ImageUndo *image_undo; @@ -301,11 +297,9 @@ struct _ImageTypeUndo }; static gboolean undo_pop_image_type (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_image_type (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -338,7 +332,6 @@ gimp_image_undo_push_image_type (GimpImage *gimage, static gboolean undo_pop_image_type (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -348,14 +341,13 @@ undo_pop_image_type (GimpUndo *undo, itu = (ImageTypeUndo *) undo->data; tmp = itu->base_type; - itu->base_type = gimage->base_type; - gimage->base_type = tmp; + itu->base_type = undo->gimage->base_type; + undo->gimage->base_type = tmp; - gimp_image_projection_allocate (gimage); + gimp_image_projection_allocate (undo->gimage); + gimp_image_colormap_changed (undo->gimage, -1); - gimp_image_colormap_changed (gimage, -1); - - if (itu->base_type != gimage->base_type) + if (itu->base_type != undo->gimage->base_type) accum->mode_changed = TRUE; return TRUE; @@ -363,7 +355,6 @@ undo_pop_image_type (GimpUndo *undo, static void undo_free_image_type (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { g_free (undo->data); @@ -383,11 +374,9 @@ struct _ImageSizeUndo }; static gboolean undo_pop_image_size (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_image_size (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -410,8 +399,6 @@ gimp_image_undo_push_image_size (GimpImage *gimage, isu = new->data; - new->data = isu; - isu->width = gimage->width; isu->height = gimage->height; @@ -423,7 +410,6 @@ gimp_image_undo_push_image_size (GimpImage *gimage, static gboolean undo_pop_image_size (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -436,17 +422,17 @@ undo_pop_image_size (GimpUndo *undo, width = isu->width; height = isu->height; - isu->width = gimage->width; - isu->height = gimage->height; + isu->width = undo->gimage->width; + isu->height = undo->gimage->height; - gimage->width = width; - gimage->height = height; + undo->gimage->width = width; + undo->gimage->height = height; - gimp_image_projection_allocate (gimage); - gimp_image_mask_invalidate (gimage); + gimp_image_projection_allocate (undo->gimage); + gimp_image_mask_invalidate (undo->gimage); - if (gimage->width != isu->width || - gimage->height != isu->height) + if (undo->gimage->width != isu->width || + undo->gimage->height != isu->height) accum->size_changed = TRUE; return TRUE; @@ -454,7 +440,6 @@ undo_pop_image_size (GimpUndo *undo, static void undo_free_image_size (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { g_free (undo->data); @@ -475,11 +460,9 @@ struct _ResolutionUndo }; static gboolean undo_pop_image_resolution (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_image_resolution (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -514,7 +497,6 @@ gimp_image_undo_push_image_resolution (GimpImage *gimage, static gboolean undo_pop_image_resolution (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -522,17 +504,17 @@ undo_pop_image_resolution (GimpUndo *undo, ru = (ResolutionUndo *) undo->data; - if (ABS (ru->xres - gimage->xresolution) >= 1e-5 || - ABS (ru->yres - gimage->yresolution) >= 1e-5) + if (ABS (ru->xres - undo->gimage->xresolution) >= 1e-5 || + ABS (ru->yres - undo->gimage->yresolution) >= 1e-5) { gdouble xres; gdouble yres; - xres = gimage->xresolution; - yres = gimage->yresolution; + xres = undo->gimage->xresolution; + yres = undo->gimage->yresolution; - gimage->xresolution = ru->xres; - gimage->yresolution = ru->yres; + undo->gimage->xresolution = ru->xres; + undo->gimage->yresolution = ru->yres; ru->xres = xres; ru->yres = yres; @@ -540,12 +522,12 @@ undo_pop_image_resolution (GimpUndo *undo, accum->resolution_changed = TRUE; } - if (ru->unit != gimage->unit) + if (ru->unit != undo->gimage->unit) { GimpUnit unit; - unit = gimage->unit; - gimage->unit = ru->unit; + unit = undo->gimage->unit; + undo->gimage->unit = ru->unit; ru->unit = unit; accum->unit_changed = TRUE; @@ -556,7 +538,6 @@ undo_pop_image_resolution (GimpUndo *undo, static void undo_free_image_resolution (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { g_free (undo->data); @@ -571,16 +552,13 @@ typedef struct _QmaskUndo QmaskUndo; struct _QmaskUndo { - GimpImage *gimage; - gboolean qmask; + gboolean qmask_state; }; static gboolean undo_pop_image_qmask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_image_qmask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -603,8 +581,7 @@ gimp_image_undo_push_image_qmask (GimpImage *gimage, qu = new->data; - qu->gimage = gimage; - qu->qmask = gimage->qmask_state; + qu->qmask_state = gimage->qmask_state; return TRUE; } @@ -614,18 +591,17 @@ gimp_image_undo_push_image_qmask (GimpImage *gimage, static gboolean undo_pop_image_qmask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { - QmaskUndo *data; + QmaskUndo *qu; gboolean tmp; - data = (QmaskUndo *) undo->data; - - tmp = gimage->qmask_state; - gimage->qmask_state = data->qmask; - data->qmask = tmp; + qu = (QmaskUndo *) undo->data; + + tmp = undo->gimage->qmask_state; + undo->gimage->qmask_state = qu->qmask_state; + qu->qmask_state = tmp; accum->qmask_changed = TRUE; @@ -633,9 +609,8 @@ undo_pop_image_qmask (GimpUndo *undo, } static void -undo_free_image_qmask (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode) +undo_free_image_qmask (GimpUndo *undo, + GimpUndoMode undo_mode) { g_free (undo->data); } @@ -649,17 +624,14 @@ typedef struct _GuideUndo GuideUndo; struct _GuideUndo { - GimpImage *gimage; GimpGuide *guide; GimpGuide orig; }; static gboolean undo_pop_image_guide (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_image_guide (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -686,9 +658,8 @@ gimp_image_undo_push_image_guide (GimpImage *gimage, guide->ref_count++; - gu->gimage = gimage; - gu->guide = guide; - gu->orig = *guide; + gu->guide = guide; + gu->orig = *guide; return TRUE; } @@ -698,47 +669,45 @@ gimp_image_undo_push_image_guide (GimpImage *gimage, static gboolean undo_pop_image_guide (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { - GuideUndo *data; + GuideUndo *gu; GimpGuide tmp_guide; gint tmp_ref; - data = (GuideUndo *) undo->data; + gu = (GuideUndo *) undo->data; - gimp_image_update_guide (gimage, data->guide); + gimp_image_update_guide (undo->gimage, gu->guide); - tmp_ref = data->guide->ref_count; - tmp_guide = *(data->guide); + tmp_ref = gu->guide->ref_count; + tmp_guide = *(gu->guide); - *(data->guide) = data->orig; + *(gu->guide) = gu->orig; - data->guide->ref_count = tmp_ref; - data->orig = tmp_guide; + gu->guide->ref_count = tmp_ref; + gu->orig = tmp_guide; - gimp_image_update_guide (gimage, data->guide); + gimp_image_update_guide (undo->gimage, gu->guide); return TRUE; } static void -undo_free_image_guide (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode) +undo_free_image_guide (GimpUndo *undo, + GimpUndoMode undo_mode) { - GuideUndo *data; + GuideUndo *gu; - data = (GuideUndo *) undo->data; + gu = (GuideUndo *) undo->data; - data->guide->ref_count--; - if (data->guide->position < 0 && data->guide->ref_count <= 0) + gu->guide->ref_count--; + if (gu->guide->position < 0 && gu->guide->ref_count <= 0) { - gimp_image_remove_guide (gimage, data->guide); - g_free (data->guide); + gimp_image_remove_guide (undo->gimage, gu->guide); + g_free (gu->guide); } - g_free (data); + g_free (gu); } @@ -756,11 +725,9 @@ struct _MaskUndo }; static gboolean undo_pop_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -804,14 +771,14 @@ gimp_image_undo_push_mask (GimpImage *gimage, undo_pop_mask, undo_free_mask))) { - MaskUndo *mask_undo; + MaskUndo *mu; - mask_undo = new->data; + mu = new->data; - mask_undo->channel = mask; - mask_undo->tiles = undo_tiles; - mask_undo->x = x1; - mask_undo->y = y1; + mu->channel = mask; + mu->tiles = undo_tiles; + mu->x = x1; + mu->y = y1; return TRUE; } @@ -824,11 +791,10 @@ gimp_image_undo_push_mask (GimpImage *gimage, static gboolean undo_pop_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { - MaskUndo *mask_undo; + MaskUndo *mu; TileManager *new_tiles; PixelRegion srcPR, destPR; gint x1, y1, x2, y2; @@ -837,20 +803,20 @@ undo_pop_mask (GimpUndo *undo, width = height = 0; - mask_undo = (MaskUndo *) undo->data; + mu = (MaskUndo *) undo->data; - if (gimp_channel_bounds (mask_undo->channel, &x1, &y1, &x2, &y2)) + if (gimp_channel_bounds (mu->channel, &x1, &y1, &x2, &y2)) { new_tiles = tile_manager_new ((x2 - x1), (y2 - y1), 1); - pixel_region_init (&srcPR, GIMP_DRAWABLE (mask_undo->channel)->tiles, + pixel_region_init (&srcPR, GIMP_DRAWABLE (mu->channel)->tiles, x1, y1, (x2 - x1), (y2 - y1), FALSE); pixel_region_init (&destPR, new_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE); copy_region (&srcPR, &destPR); - pixel_region_init (&srcPR, GIMP_DRAWABLE (mask_undo->channel)->tiles, + pixel_region_init (&srcPR, GIMP_DRAWABLE (mu->channel)->tiles, x1, y1, (x2 - x1), (y2 - y1), TRUE); color_region (&srcPR, &empty); @@ -858,67 +824,67 @@ undo_pop_mask (GimpUndo *undo, else new_tiles = NULL; - if (mask_undo->tiles) + if (mu->tiles) { - width = tile_manager_width (mask_undo->tiles); - height = tile_manager_height (mask_undo->tiles); + width = tile_manager_width (mu->tiles); + height = tile_manager_height (mu->tiles); - pixel_region_init (&srcPR, mask_undo->tiles, + pixel_region_init (&srcPR, mu->tiles, 0, 0, width, height, FALSE); - pixel_region_init (&destPR, GIMP_DRAWABLE (mask_undo->channel)->tiles, - mask_undo->x, mask_undo->y, width, height, TRUE); + pixel_region_init (&destPR, GIMP_DRAWABLE (mu->channel)->tiles, + mu->x, mu->y, width, height, TRUE); copy_region (&srcPR, &destPR); - tile_manager_destroy (mask_undo->tiles); + tile_manager_destroy (mu->tiles); } - if (mask_undo->channel == gimp_image_get_mask (gimage)) + if (mu->channel == gimp_image_get_mask (undo->gimage)) { /* invalidate the current bounds and boundary of the mask */ - gimp_image_mask_invalidate (gimage); + gimp_image_mask_invalidate (undo->gimage); } else { - mask_undo->channel->boundary_known = FALSE; - GIMP_DRAWABLE (mask_undo->channel)->preview_valid = FALSE; + mu->channel->boundary_known = FALSE; + GIMP_DRAWABLE (mu->channel)->preview_valid = FALSE; } - if (mask_undo->tiles) + if (mu->tiles) { - mask_undo->channel->empty = FALSE; - mask_undo->channel->x1 = mask_undo->x; - mask_undo->channel->y1 = mask_undo->y; - mask_undo->channel->x2 = mask_undo->x + width; - mask_undo->channel->y2 = mask_undo->y + height; + mu->channel->empty = FALSE; + mu->channel->x1 = mu->x; + mu->channel->y1 = mu->y; + mu->channel->x2 = mu->x + width; + mu->channel->y2 = mu->y + height; } else { - mask_undo->channel->empty = TRUE; - mask_undo->channel->x1 = 0; - mask_undo->channel->y1 = 0; - mask_undo->channel->x2 = GIMP_DRAWABLE (mask_undo->channel)->width; - mask_undo->channel->y2 = GIMP_DRAWABLE (mask_undo->channel)->height; + mu->channel->empty = TRUE; + mu->channel->x1 = 0; + mu->channel->y1 = 0; + mu->channel->x2 = GIMP_DRAWABLE (mu->channel)->width; + mu->channel->y2 = GIMP_DRAWABLE (mu->channel)->height; } /* we know the bounds */ - mask_undo->channel->bounds_known = TRUE; + mu->channel->bounds_known = TRUE; /* set the new mask undo parameters */ - mask_undo->tiles = new_tiles; - mask_undo->x = x1; - mask_undo->y = y1; + mu->tiles = new_tiles; + mu->x = x1; + mu->y = y1; - if (mask_undo->channel == gimp_image_get_mask (gimage)) + if (mu->channel == gimp_image_get_mask (undo->gimage)) { accum->mask_changed = TRUE; } else { - gimp_drawable_update (GIMP_DRAWABLE (mask_undo->channel), + gimp_drawable_update (GIMP_DRAWABLE (mu->channel), 0, 0, - GIMP_DRAWABLE (mask_undo->channel)->width, - GIMP_DRAWABLE (mask_undo->channel)->height); + GIMP_DRAWABLE (mu->channel)->width, + GIMP_DRAWABLE (mu->channel)->height); } return TRUE; @@ -926,16 +892,16 @@ undo_pop_mask (GimpUndo *undo, static void undo_free_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { - MaskUndo *mask_undo; + MaskUndo *mu; - mask_undo = (MaskUndo *) undo->data; + mu = (MaskUndo *) undo->data; - if (mask_undo->tiles) - tile_manager_destroy (mask_undo->tiles); - g_free (mask_undo); + if (mu->tiles) + tile_manager_destroy (mu->tiles); + + g_free (mu); } @@ -952,11 +918,9 @@ struct _ItemRenameUndo }; static gboolean undo_pop_item_rename (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_item_rename (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -981,8 +945,6 @@ gimp_image_undo_push_item_rename (GimpImage *gimage, iru = new->data; - new->data = iru; - iru->item = item; iru->old_name = g_strdup (gimp_object_get_name (GIMP_OBJECT (item))); @@ -994,7 +956,6 @@ gimp_image_undo_push_item_rename (GimpImage *gimage, static gboolean undo_pop_item_rename (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1013,7 +974,6 @@ undo_pop_item_rename (GimpUndo *undo, static void undo_free_item_rename (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { ItemRenameUndo *iru; @@ -1045,11 +1005,9 @@ static gboolean undo_push_layer (GimpImage *gimage, gint prev_position, GimpLayer *prev_layer); static gboolean undo_pop_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -1117,7 +1075,6 @@ undo_push_layer (GimpImage *gimage, static gboolean undo_pop_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1133,24 +1090,25 @@ undo_pop_layer (GimpUndo *undo, /* remove layer */ /* record the current position */ - lu->prev_position = gimp_image_get_layer_index (gimage, lu->layer); + lu->prev_position = gimp_image_get_layer_index (undo->gimage, lu->layer); /* if exists, set the previous layer */ if (lu->prev_layer) - gimp_image_set_active_layer (gimage, lu->prev_layer); + gimp_image_set_active_layer (undo->gimage, lu->prev_layer); /* remove the layer */ - gimp_container_remove (gimage->layers, GIMP_OBJECT (lu->layer)); - gimage->layer_stack = g_slist_remove (gimage->layer_stack, lu->layer); + gimp_container_remove (undo->gimage->layers, GIMP_OBJECT (lu->layer)); + undo->gimage->layer_stack = g_slist_remove (undo->gimage->layer_stack, + lu->layer); /* reset the gimage values */ if (gimp_layer_is_floating_sel (lu->layer)) { - gimage->floating_sel = NULL; + undo->gimage->floating_sel = NULL; /* reset the old drawable */ floating_sel_reset (lu->layer); - gimp_image_floating_selection_changed (gimage); + gimp_image_floating_selection_changed (undo->gimage); } gimp_drawable_update (GIMP_DRAWABLE (lu->layer), @@ -1158,8 +1116,8 @@ undo_pop_layer (GimpUndo *undo, GIMP_DRAWABLE (lu->layer)->width, GIMP_DRAWABLE (lu->layer)->height); - if (gimp_container_num_children (gimage->layers) == 1 && - ! gimp_drawable_has_alpha (GIMP_LIST (gimage->layers)->list->data)) + if (gimp_container_num_children (undo->gimage->layers) == 1 && + ! gimp_drawable_has_alpha (GIMP_LIST (undo->gimage->layers)->list->data)) { accum->alpha_changed = TRUE; } @@ -1169,29 +1127,29 @@ undo_pop_layer (GimpUndo *undo, /* restore layer */ /* record the active layer */ - lu->prev_layer = gimp_image_get_active_layer (gimage); + lu->prev_layer = gimp_image_get_active_layer (undo->gimage); /* hide the current selection--for all views */ - if (gimp_image_get_active_layer (gimage)) - gimp_layer_invalidate_boundary (gimp_image_get_active_layer (gimage)); + if (gimp_image_get_active_layer (undo->gimage)) + gimp_layer_invalidate_boundary (gimp_image_get_active_layer (undo->gimage)); /* if this is a floating selection, set the fs pointer */ if (gimp_layer_is_floating_sel (lu->layer)) - gimage->floating_sel = lu->layer; + undo->gimage->floating_sel = lu->layer; - if (gimp_container_num_children (gimage->layers) == 1 && - ! gimp_drawable_has_alpha (GIMP_LIST (gimage->layers)->list->data)) + if (gimp_container_num_children (undo->gimage->layers) == 1 && + ! gimp_drawable_has_alpha (GIMP_LIST (undo->gimage->layers)->list->data)) { accum->alpha_changed = TRUE; } /* add the new layer */ - gimp_container_insert (gimage->layers, + gimp_container_insert (undo->gimage->layers, GIMP_OBJECT (lu->layer), lu->prev_position); - gimp_image_set_active_layer (gimage, lu->layer); + gimp_image_set_active_layer (undo->gimage, lu->layer); if (gimp_layer_is_floating_sel (lu->layer)) - gimp_image_floating_selection_changed (gimage); + gimp_image_floating_selection_changed (undo->gimage); gimp_drawable_update (GIMP_DRAWABLE (lu->layer), 0, 0, @@ -1204,7 +1162,6 @@ undo_pop_layer (GimpUndo *undo, static void undo_free_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { LayerUndo *lu; @@ -1233,11 +1190,9 @@ struct _LayerModUndo }; static gboolean undo_pop_layer_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_layer_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -1283,7 +1238,6 @@ gimp_image_undo_push_layer_mod (GimpImage *gimage, static gboolean undo_pop_layer_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1298,7 +1252,7 @@ undo_pop_layer_mod (GimpUndo *undo, layer = lmu->layer; /* Issue the first update */ - gimp_image_update (gimage, + gimp_image_update (undo->gimage, GIMP_DRAWABLE (layer)->offset_x, GIMP_DRAWABLE (layer)->offset_y, GIMP_DRAWABLE (layer)->width, @@ -1331,9 +1285,9 @@ undo_pop_layer_mod (GimpUndo *undo, if (GIMP_IMAGE_TYPE_HAS_ALPHA (GIMP_DRAWABLE (layer)->type) != GIMP_IMAGE_TYPE_HAS_ALPHA (lmu->type) && - GIMP_ITEM (layer)->gimage->layers->num_children == 1) + undo->gimage->layers->num_children == 1) { - gimp_image_alpha_changed (GIMP_ITEM (layer)->gimage); + gimp_image_alpha_changed (undo->gimage); } if (GIMP_DRAWABLE (layer)->width != tile_manager_width (lmu->tiles) || @@ -1353,7 +1307,6 @@ undo_pop_layer_mod (GimpUndo *undo, static void undo_free_layer_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { LayerModUndo *lmu; @@ -1383,11 +1336,9 @@ static gboolean undo_push_layer_mask (GimpImage *gimage, GimpLayer *layer, GimpLayerMask *mask); static gboolean undo_pop_layer_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_layer_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -1451,7 +1402,6 @@ undo_push_layer_mask (GimpImage *gimage, static gboolean undo_pop_layer_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1480,7 +1430,6 @@ undo_pop_layer_mask (GimpUndo *undo, static void undo_free_layer_mask (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { LayerMaskUndo *lmu; @@ -1506,11 +1455,9 @@ struct _LayerRepositionUndo }; static gboolean undo_pop_layer_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_layer_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -1546,7 +1493,6 @@ gimp_image_undo_push_layer_reposition (GimpImage *gimage, static gboolean undo_pop_layer_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1556,8 +1502,8 @@ undo_pop_layer_reposition (GimpUndo *undo, lru = (LayerRepositionUndo *) undo->data; /* what's the layer's current index? */ - pos = gimp_image_get_layer_index (gimage, lru->layer); - gimp_image_position_layer (gimage, lru->layer, lru->old_position, + pos = gimp_image_get_layer_index (undo->gimage, lru->layer); + gimp_image_position_layer (undo->gimage, lru->layer, lru->old_position, FALSE, NULL); lru->old_position = pos; @@ -1567,7 +1513,6 @@ undo_pop_layer_reposition (GimpUndo *undo, static void undo_free_layer_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { g_free (undo->data); @@ -1589,11 +1534,9 @@ struct _LayerDisplaceUndo }; static gboolean undo_pop_layer_displace (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_layer_displace (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -1631,7 +1574,6 @@ gimp_image_undo_push_layer_displace (GimpImage *gimage, static gboolean undo_pop_layer_displace (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1676,14 +1618,13 @@ undo_pop_layer_displace (GimpUndo *undo, /* Now undo paths bits */ if (ldu->path_undo) - path_transform_do_undo (gimage, ldu->path_undo); + path_transform_do_undo (undo->gimage, ldu->path_undo); return TRUE; } static void undo_free_layer_displace (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { LayerDisplaceUndo *ldu; @@ -1719,11 +1660,9 @@ static gboolean undo_push_channel (GimpImage *gimage, gint prev_position, GimpChannel *prev_channel); static gboolean undo_pop_channel (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_channel (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -1792,7 +1731,6 @@ undo_push_channel (GimpImage *gimage, static gboolean undo_pop_channel (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1808,14 +1746,15 @@ undo_pop_channel (GimpUndo *undo, /* remove channel */ /* record the current position */ - cu->prev_position = gimp_image_get_channel_index (gimage, cu->channel); + cu->prev_position = gimp_image_get_channel_index (undo->gimage, + cu->channel); /* remove the channel */ - gimp_container_remove (gimage->channels, GIMP_OBJECT (cu->channel)); + gimp_container_remove (undo->gimage->channels, GIMP_OBJECT (cu->channel)); /* if exists, set the previous channel */ if (cu->prev_channel) - gimp_image_set_active_channel (gimage, cu->prev_channel); + gimp_image_set_active_channel (undo->gimage, cu->prev_channel); /* update the area */ gimp_drawable_update (GIMP_DRAWABLE (cu->channel), @@ -1828,14 +1767,14 @@ undo_pop_channel (GimpUndo *undo, /* restore channel */ /* record the active channel */ - cu->prev_channel = gimp_image_get_active_channel (gimage); + cu->prev_channel = gimp_image_get_active_channel (undo->gimage); /* add the new channel */ - gimp_container_insert (gimage->channels, + gimp_container_insert (undo->gimage->channels, GIMP_OBJECT (cu->channel), cu->prev_position); /* set the new channel */ - gimp_image_set_active_channel (gimage, cu->channel); + gimp_image_set_active_channel (undo->gimage, cu->channel); /* update the area */ gimp_drawable_update (GIMP_DRAWABLE (cu->channel), @@ -1849,7 +1788,6 @@ undo_pop_channel (GimpUndo *undo, static void undo_free_channel (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { ChannelUndo *cu; @@ -1875,11 +1813,9 @@ struct _ChannelModUndo }; static gboolean undo_pop_channel_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_channel_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -1923,7 +1859,6 @@ gimp_image_undo_push_channel_mod (GimpImage *gimage, static gboolean undo_pop_channel_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -1967,7 +1902,6 @@ undo_pop_channel_mod (GimpUndo *undo, static void undo_free_channel_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { ChannelModUndo *cmu; @@ -1993,11 +1927,9 @@ struct _ChannelRepositionUndo }; static gboolean undo_pop_channel_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_channel_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2033,7 +1965,6 @@ gimp_image_undo_push_channel_reposition (GimpImage *gimage, static gboolean undo_pop_channel_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2043,8 +1974,8 @@ undo_pop_channel_reposition (GimpUndo *undo, cru = (ChannelRepositionUndo *) undo->data; /* what's the channel's current index? */ - pos = gimp_image_get_channel_index (gimage, cru->channel); - gimp_image_position_channel (gimage, cru->channel, cru->old_position, + pos = gimp_image_get_channel_index (undo->gimage, cru->channel); + gimp_image_position_channel (undo->gimage, cru->channel, cru->old_position, FALSE, NULL); cru->old_position = pos; @@ -2054,7 +1985,6 @@ undo_pop_channel_reposition (GimpUndo *undo, static void undo_free_channel_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { g_free (undo->data); @@ -2081,11 +2011,9 @@ static gboolean undo_push_vectors (GimpImage *gimage, gint prev_position, GimpVectors *prev_vectors); static gboolean undo_pop_vectors (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_vectors (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2154,7 +2082,6 @@ undo_push_vectors (GimpImage *gimage, static gboolean undo_pop_vectors (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2170,28 +2097,29 @@ undo_pop_vectors (GimpUndo *undo, /* remove vectors */ /* record the current position */ - vu->prev_position = gimp_image_get_vectors_index (gimage, vu->vectors); + vu->prev_position = gimp_image_get_vectors_index (undo->gimage, + vu->vectors); /* remove the vectors */ - gimp_container_remove (gimage->vectors, GIMP_OBJECT (vu->vectors)); + gimp_container_remove (undo->gimage->vectors, GIMP_OBJECT (vu->vectors)); /* if exists, set the previous vectors */ if (vu->prev_vectors) - gimp_image_set_active_vectors (gimage, vu->prev_vectors); + gimp_image_set_active_vectors (undo->gimage, vu->prev_vectors); } else { /* restore vectors */ /* record the active vectors */ - vu->prev_vectors = gimp_image_get_active_vectors (gimage); + vu->prev_vectors = gimp_image_get_active_vectors (undo->gimage); /* add the new vectors */ - gimp_container_insert (gimage->vectors, + gimp_container_insert (undo->gimage->vectors, GIMP_OBJECT (vu->vectors), vu->prev_position); /* set the new vectors */ - gimp_image_set_active_vectors (gimage, vu->vectors); + gimp_image_set_active_vectors (undo->gimage, vu->vectors); } return TRUE; @@ -2199,7 +2127,6 @@ undo_pop_vectors (GimpUndo *undo, static void undo_free_vectors (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { VectorsUndo *vu; @@ -2225,11 +2152,9 @@ struct _VectorsModUndo }; static gboolean undo_pop_vectors_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_vectors_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2271,7 +2196,6 @@ gimp_image_undo_push_vectors_mod (GimpImage *gimage, static gboolean undo_pop_vectors_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2296,7 +2220,6 @@ undo_pop_vectors_mod (GimpUndo *undo, static void undo_free_vectors_mod (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { VectorsModUndo *vmu; @@ -2322,11 +2245,9 @@ struct _VectorsRepositionUndo }; static gboolean undo_pop_vectors_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_vectors_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2362,7 +2283,6 @@ gimp_image_undo_push_vectors_reposition (GimpImage *gimage, static gboolean undo_pop_vectors_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2372,8 +2292,8 @@ undo_pop_vectors_reposition (GimpUndo *undo, vru = (VectorsRepositionUndo *) undo->data; /* what's the vectors's current index? */ - pos = gimp_image_get_vectors_index (gimage, vru->vectors); - gimp_image_position_vectors (gimage, vru->vectors, vru->old_position, + pos = gimp_image_get_vectors_index (undo->gimage, vru->vectors); + gimp_image_position_vectors (undo->gimage, vru->vectors, vru->old_position, FALSE, NULL); vru->old_position = pos; @@ -2383,7 +2303,6 @@ undo_pop_vectors_reposition (GimpUndo *undo, static void undo_free_vectors_reposition (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { g_free (undo->data); @@ -2403,11 +2322,9 @@ struct _FStoLayerUndo }; static gboolean undo_pop_fs_to_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_fs_to_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2448,7 +2365,6 @@ gimp_image_undo_push_fs_to_layer (GimpImage *gimage, static gboolean undo_pop_fs_to_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2463,8 +2379,8 @@ undo_pop_fs_to_layer (GimpUndo *undo, gimp_viewable_invalidate_preview (GIMP_VIEWABLE (fsu->floating_layer)); fsu->floating_layer->fs.drawable = fsu->drawable; - gimp_image_set_active_layer (gimage, fsu->floating_layer); - gimage->floating_sel = fsu->floating_layer; + gimp_image_set_active_layer (undo->gimage, fsu->floating_layer); + undo->gimage->floating_sel = fsu->floating_layer; /* restore the contents of the drawable */ floating_sel_store (fsu->floating_layer, @@ -2497,21 +2413,20 @@ undo_pop_fs_to_layer (GimpUndo *undo, /* update the pointers */ fsu->floating_layer->fs.drawable = NULL; - gimage->floating_sel = NULL; + undo->gimage->floating_sel = NULL; /* Update the fs drawable */ gimp_viewable_invalidate_preview (GIMP_VIEWABLE (fsu->floating_layer)); break; } - gimp_image_floating_selection_changed (gimage); + gimp_image_floating_selection_changed (undo->gimage); return TRUE; } static void undo_free_fs_to_layer (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { FStoLayerUndo *fsu; @@ -2540,11 +2455,9 @@ struct _FSRigorUndo }; static gboolean undo_pop_fs_rigor (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_fs_rigor (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2579,7 +2492,6 @@ gimp_image_undo_push_fs_rigor (GimpImage *gimage, static gboolean undo_pop_fs_rigor (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2606,7 +2518,6 @@ undo_pop_fs_rigor (GimpUndo *undo, static void undo_free_fs_rigor (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { FSRigorUndo *fsu; @@ -2631,11 +2542,9 @@ struct _FSRelaxUndo }; static gboolean undo_pop_fs_relax (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_fs_relax (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2670,7 +2579,6 @@ gimp_image_undo_push_fs_relax (GimpImage *gimage, static gboolean undo_pop_fs_relax (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2697,7 +2605,6 @@ undo_pop_fs_relax (GimpUndo *undo, static void undo_free_fs_relax (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { FSRelaxUndo *fsu; @@ -2725,11 +2632,9 @@ struct _ParasiteUndo }; static gboolean undo_pop_parasite (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_parasite (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -2866,7 +2771,6 @@ gimp_image_undo_push_item_parasite_remove (GimpImage *gimage, static gboolean undo_pop_parasite (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -2879,7 +2783,7 @@ undo_pop_parasite (GimpUndo *undo, if (pu->gimage) { - pu->parasite = gimp_parasite_copy (gimp_image_parasite_find (gimage, + pu->parasite = gimp_parasite_copy (gimp_image_parasite_find (undo->gimage, pu->name)); if (tmp) gimp_parasite_list_add (pu->gimage->parasites, tmp); @@ -2897,12 +2801,12 @@ undo_pop_parasite (GimpUndo *undo, } else { - pu->parasite = gimp_parasite_copy (gimp_parasite_find (gimage->gimp, + pu->parasite = gimp_parasite_copy (gimp_parasite_find (undo->gimage->gimp, pu->name)); if (tmp) - gimp_parasite_attach (gimage->gimp, tmp); + gimp_parasite_attach (undo->gimage->gimp, tmp); else - gimp_parasite_detach (gimage->gimp, pu->name); + gimp_parasite_detach (undo->gimage->gimp, pu->name); } if (tmp) @@ -2913,7 +2817,6 @@ undo_pop_parasite (GimpUndo *undo, static void undo_free_parasite (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { ParasiteUndo *pu; @@ -2934,7 +2837,6 @@ undo_free_parasite (GimpUndo *undo, /******************************************************************************/ static gboolean undo_pop_cantundo (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); @@ -2966,7 +2868,6 @@ gimp_image_undo_push_cantundo (GimpImage *gimage, static gboolean undo_pop_cantundo (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { diff --git a/app/core/gimpimage-undo.c b/app/core/gimpimage-undo.c index ecbf6b7ba6..b6895079a9 100644 --- a/app/core/gimpimage-undo.c +++ b/app/core/gimpimage-undo.c @@ -38,6 +38,7 @@ static void gimp_image_undo_pop_stack (GimpImage *gimage, GimpUndoStack *redo_stack, GimpUndoMode undo_mode); static void gimp_image_undo_free_space (GimpImage *gimage); +static void gimp_image_undo_free_redo (GimpImage *gimage); static const gchar * gimp_image_undo_type_to_name (GimpUndoType type); @@ -78,8 +79,13 @@ gimp_image_undo_free (GimpImage *gimage) { g_return_if_fail (GIMP_IS_IMAGE (gimage)); - gimp_undo_free (GIMP_UNDO (gimage->undo_stack), gimage, GIMP_UNDO_MODE_UNDO); - gimp_undo_free (GIMP_UNDO (gimage->redo_stack), gimage, GIMP_UNDO_MODE_REDO); + /* Emit the UNDO_FREE event before actually freeing everything + * so the views can properly detach from the undo items + */ + gimp_image_undo_event (gimage, GIMP_UNDO_EVENT_UNDO_FREE, NULL); + + gimp_undo_free (GIMP_UNDO (gimage->undo_stack), GIMP_UNDO_MODE_UNDO); + gimp_undo_free (GIMP_UNDO (gimage->redo_stack), GIMP_UNDO_MODE_REDO); /* If the image was dirty, but could become clean by redo-ing * some actions, then it should now become 'infinitely' dirty. @@ -94,7 +100,6 @@ gimp_image_undo_free (GimpImage *gimage) * due to undo actions, but since user can't undo without an undo * stack, that's not so much a problem. */ - gimp_image_undo_event (gimage, UNDO_FREE); } gboolean @@ -124,8 +129,7 @@ gimp_image_undo_group_start (GimpImage *gimage, return TRUE; /* nuke the redo stack */ - gimp_undo_free (GIMP_UNDO (gimage->redo_stack), gimage, - GIMP_UNDO_MODE_REDO); + gimp_image_undo_free_redo (gimage); /* If the image was dirty, but could become clean by redo-ing * some actions, then it should now become 'infinitely' dirty. @@ -170,7 +174,8 @@ gimp_image_undo_group_end (GimpImage *gimage) /* Do it here, since undo_push doesn't emit this event while in * the middle of a group */ - gimp_image_undo_event (gimage, UNDO_PUSHED); + gimp_image_undo_event (gimage, GIMP_UNDO_EVENT_UNDO_PUSHED, + gimp_undo_stack_peek (gimage->undo_stack)); } return TRUE; @@ -205,8 +210,7 @@ gimp_image_undo_push (GimpImage *gimage, return NULL; /* nuke the redo stack */ - gimp_undo_free (GIMP_UNDO (gimage->redo_stack), gimage, - GIMP_UNDO_MODE_REDO); + gimp_image_undo_free_redo (gimage); /* If the image was dirty, but could become clean by redo-ing * some actions, then it should now become 'infinitely' dirty. @@ -220,7 +224,8 @@ gimp_image_undo_push (GimpImage *gimage, if (struct_size > 0) undo_struct = g_malloc0 (struct_size); - new = gimp_undo_new (type, + new = gimp_undo_new (gimage, + type, name, undo_struct, size, dirties_image, @@ -232,7 +237,7 @@ gimp_image_undo_push (GimpImage *gimage, gimp_image_undo_free_space (gimage); - gimp_image_undo_event (gimage, UNDO_PUSHED); + gimp_image_undo_event (gimage, GIMP_UNDO_EVENT_UNDO_PUSHED, new); } else { @@ -292,7 +297,8 @@ gimp_image_undo_pop_stack (GimpImage *gimage, /* let others know that we just popped an action */ gimp_image_undo_event (gimage, (undo_mode == GIMP_UNDO_MODE_UNDO) ? - UNDO_POPPED : UNDO_REDO); + GIMP_UNDO_EVENT_UNDO : GIMP_UNDO_EVENT_REDO, + undo); } static void @@ -322,7 +328,10 @@ gimp_image_undo_free_space (GimpImage *gimage) while ((gimp_object_get_memsize (GIMP_OBJECT (container)) > undo_size) || (gimp_container_num_children (container) > max_undo_levels)) { - gimp_undo_stack_free_bottom (gimage->undo_stack, GIMP_UNDO_MODE_UNDO); + GimpUndo *freed; + + freed = gimp_undo_stack_free_bottom (gimage->undo_stack, + GIMP_UNDO_MODE_UNDO); #if 0 g_print ("freed one step: undo_steps: %d undo_bytes: %d\n", @@ -330,13 +339,47 @@ gimp_image_undo_free_space (GimpImage *gimage) gimp_object_get_memsize (GIMP_OBJECT (container))); #endif - gimp_image_undo_event (gimage, UNDO_EXPIRED); + gimp_image_undo_event (gimage, GIMP_UNDO_EVENT_UNDO_EXPIRED, freed); + + g_object_unref (freed); if (gimp_container_num_children (container) <= min_undo_levels) return; } } +static void +gimp_image_undo_free_redo (GimpImage *gimage) +{ + GimpContainer *container; + + container = gimage->redo_stack->undos; + +#if 0 + g_print ("redo_steps: %d redo_bytes: %d\n", + gimp_container_num_children (container), + gimp_object_get_memsize (GIMP_OBJECT (container))); +#endif + + while (gimp_container_num_children (container) > 0) + { + GimpUndo *freed; + + freed = gimp_undo_stack_free_bottom (gimage->redo_stack, + GIMP_UNDO_MODE_REDO); + +#if 0 + g_print ("freed one step: redo_steps: %d redo_bytes: %d\n", + gimp_container_num_children (container), + gimp_object_get_memsize (GIMP_OBJECT (container))); +#endif + + gimp_image_undo_event (gimage, GIMP_UNDO_EVENT_REDO_EXPIRED, freed); + + g_object_unref (freed); + } +} + static const gchar * gimp_image_undo_type_to_name (GimpUndoType type) { diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index 1000a8d2b5..c683555a41 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -371,9 +371,10 @@ gimp_image_class_init (GimpImageClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpImageClass, undo_event), NULL, NULL, - gimp_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); + gimp_marshal_VOID__ENUM_OBJECT, + G_TYPE_NONE, 2, + GIMP_TYPE_UNDO_EVENT, + GIMP_TYPE_UNDO); gimp_image_signals[FLUSH] = g_signal_new ("flush", @@ -1574,10 +1575,14 @@ gimp_image_undo_start (GimpImage *gimage) } void -gimp_image_undo_event (GimpImage *gimage, - gint event) +gimp_image_undo_event (GimpImage *gimage, + GimpUndoEvent event, + GimpUndo *undo) { - g_signal_emit (gimage, gimp_image_signals[UNDO_EVENT], 0, event); + g_return_if_fail (GIMP_IS_IMAGE (gimage)); + g_return_if_fail (event == GIMP_UNDO_EVENT_UNDO_FREE || GIMP_IS_UNDO (undo)); + + g_signal_emit (gimage, gimp_image_signals[UNDO_EVENT], 0, event, undo); } diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h index 445b3cf251..433c1b1e3a 100644 --- a/app/core/gimpimage.h +++ b/app/core/gimpimage.h @@ -198,7 +198,8 @@ struct _GimpImageClass gint color_index); void (* undo_start) (GimpImage *gimage); void (* undo_event) (GimpImage *gimage, - gint event); + GimpUndoEvent event, + GimpUndo *undo); void (* flush) (GimpImage *gimage); }; @@ -299,7 +300,8 @@ gboolean gimp_image_undo_freeze (GimpImage *gimage); gboolean gimp_image_undo_thaw (GimpImage *gimage); void gimp_image_undo_start (GimpImage *gimage); void gimp_image_undo_event (GimpImage *gimage, - gint event); + GimpUndoEvent event, + GimpUndo *undo); gint gimp_image_dirty (GimpImage *gimage); gint gimp_image_clean (GimpImage *gimage); void gimp_image_clean_all (GimpImage *gimage); diff --git a/app/core/gimpmarshal.list b/app/core/gimpmarshal.list index fcf3b62932..2b560beb50 100644 --- a/app/core/gimpmarshal.list +++ b/app/core/gimpmarshal.list @@ -46,6 +46,8 @@ POINTER: VOID VOID: BOXED VOID: DOUBLE VOID: ENUM +VOID: ENUM, OBJECT +VOID: ENUM, POINTER VOID: INT VOID: INT, BOOLEAN, INT, OBJECT VOID: INT, INT diff --git a/app/core/gimpundo.c b/app/core/gimpundo.c index 8863e43a0e..11728dc527 100644 --- a/app/core/gimpundo.c +++ b/app/core/gimpundo.c @@ -27,6 +27,7 @@ #include "gimpimage.h" #include "gimpmarshal.h" #include "gimpundo.h" +#include "gimpundostack.h" enum @@ -37,24 +38,25 @@ enum }; -static void gimp_undo_class_init (GimpUndoClass *klass); -static void gimp_undo_init (GimpUndo *undo); +static void gimp_undo_class_init (GimpUndoClass *klass); +static void gimp_undo_init (GimpUndo *undo); -static void gimp_undo_finalize (GObject *object); +static void gimp_undo_finalize (GObject *object); -static gsize gimp_undo_get_memsize (GimpObject *object); +static gsize gimp_undo_get_memsize (GimpObject *object); -static TempBuf * gimp_undo_get_preview (GimpViewable *viewable, - gint width, - gint height); +static TempBuf * gimp_undo_get_preview (GimpViewable *viewable, + gint width, + gint height); -static void gimp_undo_real_pop (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode, - GimpUndoAccumulator *accum); -static void gimp_undo_real_free (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode); +static void gimp_undo_real_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void gimp_undo_real_free (GimpUndo *undo, + GimpUndoMode undo_mode); + +static gboolean gimp_undo_create_preview_idle (gpointer data); +static void gimp_undo_create_preview_private (GimpUndo *undo); static guint undo_signals[LAST_SIGNAL] = { 0 }; @@ -109,9 +111,8 @@ gimp_undo_class_init (GimpUndoClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpUndoClass, pop), NULL, NULL, - gimp_marshal_VOID__OBJECT_ENUM_POINTER, - G_TYPE_NONE, 3, - GIMP_TYPE_IMAGE, + gimp_marshal_VOID__ENUM_POINTER, + G_TYPE_NONE, 2, GIMP_TYPE_UNDO_MODE, G_TYPE_POINTER); @@ -121,9 +122,8 @@ gimp_undo_class_init (GimpUndoClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpUndoClass, free), NULL, NULL, - gimp_marshal_VOID__OBJECT_ENUM, - G_TYPE_NONE, 2, - GIMP_TYPE_IMAGE, + gimp_marshal_VOID__ENUM, + G_TYPE_NONE, 1, GIMP_TYPE_UNDO_MODE); object_class->finalize = gimp_undo_finalize; @@ -139,6 +139,8 @@ gimp_undo_class_init (GimpUndoClass *klass) static void gimp_undo_init (GimpUndo *undo) { + undo->gimage = NULL; + undo->undo_type = 0; undo->data = NULL; undo->dirties_image = FALSE; undo->pop_func = NULL; @@ -153,6 +155,12 @@ gimp_undo_finalize (GObject *object) undo = GIMP_UNDO (object); + if (undo->preview_idle_id) + { + g_source_remove (undo->preview_idle_id); + undo->preview_idle_id = 0; + } + if (undo->preview) { temp_buf_free (undo->preview); @@ -183,11 +191,29 @@ gimp_undo_get_preview (GimpViewable *viewable, gint width, gint height) { - return (GIMP_UNDO (viewable)->preview); + return GIMP_UNDO (viewable)->preview; +} + +static void +gimp_undo_real_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + if (undo->pop_func) + undo->pop_func (undo, undo_mode, accum); +} + +static void +gimp_undo_real_free (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + if (undo->free_func) + undo->free_func (undo, undo_mode); } GimpUndo * -gimp_undo_new (GimpUndoType undo_type, +gimp_undo_new (GimpImage *gimage, + GimpUndoType undo_type, const gchar *name, gpointer data, gsize size, @@ -197,13 +223,15 @@ gimp_undo_new (GimpUndoType undo_type, { GimpUndo *undo; + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); g_return_val_if_fail (name != NULL, NULL); - //g_return_val_if_fail (size == 0 || data != NULL, NULL); + g_return_val_if_fail (size == 0 || data != NULL, NULL); undo = g_object_new (GIMP_TYPE_UNDO, "name", name, NULL); - + + undo->gimage = gimage; undo->undo_type = undo_type; undo->data = data; undo->size = size; @@ -216,26 +244,24 @@ gimp_undo_new (GimpUndoType undo_type, void gimp_undo_pop (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { g_return_if_fail (GIMP_IS_UNDO (undo)); - g_return_if_fail (GIMP_IS_IMAGE (gimage)); g_return_if_fail (accum != NULL); - g_signal_emit (undo, undo_signals[POP], 0, gimage, undo_mode, accum); + g_signal_emit (undo, undo_signals[POP], 0, undo_mode, accum); if (undo->dirties_image) { switch (undo_mode) { case GIMP_UNDO_MODE_UNDO: - gimp_image_clean (gimage); + gimp_image_clean (undo->gimage); break; case GIMP_UNDO_MODE_REDO: - gimp_image_dirty (gimage); + gimp_image_dirty (undo->gimage); break; } } @@ -243,30 +269,86 @@ gimp_undo_pop (GimpUndo *undo, void gimp_undo_free (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { g_return_if_fail (GIMP_IS_UNDO (undo)); - g_return_if_fail (GIMP_IS_IMAGE (gimage)); - g_signal_emit (undo, undo_signals[FREE], 0, gimage, undo_mode); + g_signal_emit (undo, undo_signals[FREE], 0, undo_mode); } -static void -gimp_undo_real_pop (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode, - GimpUndoAccumulator *accum) +void +gimp_undo_create_preview (GimpUndo *undo, + gboolean create_now) { - if (undo->pop_func) - undo->pop_func (undo, gimage, undo_mode, accum); + g_return_if_fail (GIMP_IS_UNDO (undo)); + + if (undo->preview || undo->preview_idle_id) + return; + + if (create_now) + gimp_undo_create_preview_private (undo); + else + undo->preview_idle_id = g_idle_add (gimp_undo_create_preview_idle, undo); } -static void -gimp_undo_real_free (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode) +static gboolean +gimp_undo_create_preview_idle (gpointer data) { - if (undo->free_func) - undo->free_func (undo, gimage, undo_mode); + GimpUndo *undo; + + undo = GIMP_UNDO (data); + + if (undo == gimp_undo_stack_peek (undo->gimage->undo_stack)) + { + gimp_undo_create_preview_private (undo); + } + + undo->preview_idle_id = 0; + + return FALSE; +} + +void +gimp_undo_create_preview_private (GimpUndo *undo) +{ + GimpViewable *preview_viewable; + gint width; + gint height; + + switch (undo->undo_type) + { + case GIMP_UNDO_GROUP_IMAGE_QMASK: + case GIMP_UNDO_IMAGE_QMASK: + case GIMP_UNDO_MASK: + preview_viewable = GIMP_VIEWABLE (gimp_image_get_mask (undo->gimage)); + break; + + default: + preview_viewable = GIMP_VIEWABLE (undo->gimage); + break; + } + + if (undo->gimage->width <= 64 && undo->gimage->height <= 64) + { + width = undo->gimage->width; + height = undo->gimage->height; + } + else + { + if (undo->gimage->width > undo->gimage->height) + { + width = 64; + height = MAX (1, undo->gimage->height * 64 / undo->gimage->width); + } + else + { + height = 64; + width = MAX (1, undo->gimage->width * 64 / undo->gimage->height); + } + } + + undo->preview = gimp_viewable_get_new_preview (preview_viewable, + width, height); + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (undo)); } diff --git a/app/core/gimpundo.h b/app/core/gimpundo.h index d759c6fa80..6fe5ff83c8 100644 --- a/app/core/gimpundo.h +++ b/app/core/gimpundo.h @@ -49,6 +49,8 @@ struct _GimpUndo { GimpViewable parent_instance; + GimpImage *gimage; /* the image this undo is part of */ + GimpUndoType undo_type; /* undo type */ gpointer data; /* data to implement the undo */ gsize size; /* size of undo item */ @@ -58,6 +60,7 @@ struct _GimpUndo GimpUndoFreeFunc free_func; /* function pointer to free undo data */ TempBuf *preview; + guint preview_idle_id; }; struct _GimpUndoClass @@ -65,32 +68,32 @@ struct _GimpUndoClass GimpViewableClass parent_class; void (* pop) (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); void (* free) (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); }; -GType gimp_undo_get_type (void) G_GNUC_CONST; +GType gimp_undo_get_type (void) G_GNUC_CONST; -GimpUndo * gimp_undo_new (GimpUndoType undo_type, - const gchar *name, - gpointer data, - gsize size, - gboolean dirties_image, - GimpUndoPopFunc pop_func, - GimpUndoFreeFunc free_func); +GimpUndo * gimp_undo_new (GimpImage *gimage, + GimpUndoType undo_type, + const gchar *name, + gpointer data, + gsize size, + gboolean dirties_image, + GimpUndoPopFunc pop_func, + GimpUndoFreeFunc free_func); -void gimp_undo_pop (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode, - GimpUndoAccumulator *accum); -void gimp_undo_free (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode); +void gimp_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +void gimp_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode); + +void gimp_undo_create_preview (GimpUndo *undo, + gboolean create_now); #endif /* __GIMP_UNDO_H__ */ diff --git a/app/core/gimpundostack.c b/app/core/gimpundostack.c index a5ce731cf8..308c0dc0f4 100644 --- a/app/core/gimpundostack.c +++ b/app/core/gimpundostack.c @@ -28,27 +28,18 @@ #include "gimpundostack.h" -static void gimp_undo_stack_class_init (GimpUndoStackClass *klass); -static void gimp_undo_stack_init (GimpUndoStack *stack); +static void gimp_undo_stack_class_init (GimpUndoStackClass *klass); +static void gimp_undo_stack_init (GimpUndoStack *stack); -static void gimp_undo_stack_finalize (GObject *object); +static void gimp_undo_stack_finalize (GObject *object); -static gsize gimp_undo_stack_get_memsize (GimpObject *object); +static gsize gimp_undo_stack_get_memsize (GimpObject *object); -static void gimp_undo_stack_pop (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode, - GimpUndoAccumulator *accum); -static void gimp_undo_stack_free (GimpUndo *undo, - GimpImage *gimage, - GimpUndoMode undo_mode); - -static void gimp_undo_stack_add_callback (GimpContainer *container, - GimpObject *object, - gpointer data); -static void gimp_undo_stack_remove_callback (GimpContainer *container, - GimpObject *object, - gpointer data); +static void gimp_undo_stack_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void gimp_undo_stack_free (GimpUndo *undo, + GimpUndoMode undo_mode); static GimpUndoClass *parent_class = NULL; @@ -106,21 +97,8 @@ gimp_undo_stack_class_init (GimpUndoStackClass *klass) static void gimp_undo_stack_init (GimpUndoStack *stack) { - GimpContainer *undos; - - undos = gimp_list_new (GIMP_TYPE_UNDO, - GIMP_CONTAINER_POLICY_STRONG); - - stack->undos = undos; - - g_signal_connect (undos, "add", - G_CALLBACK (gimp_undo_stack_add_callback), - stack); - g_signal_connect (undos, "remove", - G_CALLBACK (gimp_undo_stack_remove_callback), - stack); - - stack->gimage = NULL; + stack->undos = gimp_list_new (GIMP_TYPE_UNDO, + GIMP_CONTAINER_POLICY_STRONG); } static void @@ -155,7 +133,6 @@ gimp_undo_stack_get_memsize (GimpObject *object) static void gimp_undo_stack_pop (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -172,13 +149,12 @@ gimp_undo_stack_pop (GimpUndo *undo, child = GIMP_UNDO (list->data); - gimp_undo_pop (child, gimage, undo_mode, accum); + gimp_undo_pop (child, undo_mode, accum); } } static void gimp_undo_stack_free (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { GimpUndoStack *stack; @@ -194,7 +170,7 @@ gimp_undo_stack_free (GimpUndo *undo, child = GIMP_UNDO (list->data); - gimp_undo_free (child, gimage, undo_mode); + gimp_undo_free (child, undo_mode); g_object_unref (child); } @@ -212,7 +188,7 @@ gimp_undo_stack_new (GimpImage *gimage) stack = GIMP_UNDO_STACK (g_object_new (GIMP_TYPE_UNDO_STACK, NULL)); - stack->gimage = gimage; + GIMP_UNDO (stack)->gimage = gimage; return stack; } @@ -232,45 +208,49 @@ gimp_undo_stack_pop_undo (GimpUndoStack *stack, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { - GimpObject *object; + GimpUndo *undo; g_return_val_if_fail (GIMP_IS_UNDO_STACK (stack), NULL); g_return_val_if_fail (accum != NULL, NULL); - - object = gimp_container_get_child_by_index (GIMP_CONTAINER (stack->undos),0); - if (object) + undo = (GimpUndo *) + gimp_container_get_child_by_index (GIMP_CONTAINER (stack->undos), 0); + + if (undo) { - gimp_container_remove (GIMP_CONTAINER (stack->undos), object); - gimp_undo_pop (GIMP_UNDO (object), stack->gimage, undo_mode, accum); + gimp_container_remove (GIMP_CONTAINER (stack->undos), GIMP_OBJECT (undo)); + gimp_undo_pop (undo, undo_mode, accum); - return GIMP_UNDO (object); + return undo; } return NULL; } -void +GimpUndo * gimp_undo_stack_free_bottom (GimpUndoStack *stack, GimpUndoMode undo_mode) { - GimpObject *object; - gint n_children; + GimpUndo *undo; + gint n_children; - g_return_if_fail (GIMP_IS_UNDO_STACK (stack)); + g_return_val_if_fail (GIMP_IS_UNDO_STACK (stack), NULL); n_children = gimp_container_num_children (GIMP_CONTAINER (stack->undos)); - object = gimp_container_get_child_by_index (GIMP_CONTAINER (stack->undos), - n_children - 1); + undo = (GimpUndo *) + gimp_container_get_child_by_index (GIMP_CONTAINER (stack->undos), + n_children - 1); - if (object) + if (undo) { - gimp_container_remove (GIMP_CONTAINER (stack->undos), object); - gimp_undo_free (GIMP_UNDO (object), stack->gimage, undo_mode); + gimp_container_remove (GIMP_CONTAINER (stack->undos), GIMP_OBJECT (undo)); + gimp_undo_free (undo, undo_mode); - g_object_unref (object); + return undo; } + + return NULL; } GimpUndo * @@ -284,27 +264,3 @@ gimp_undo_stack_peek (GimpUndoStack *stack) return (object ? GIMP_UNDO (object) : NULL); } - -static void -gimp_undo_stack_add_callback (GimpContainer *container, - GimpObject *object, - gpointer data) -{ - GimpUndo *undo; - GimpUndo *stack; - - undo = GIMP_UNDO (object); - stack = GIMP_UNDO (data); -} - -static void -gimp_undo_stack_remove_callback (GimpContainer *container, - GimpObject *object, - gpointer data) -{ - GimpUndo *undo; - GimpUndo *stack; - - undo = GIMP_UNDO (object); - stack = GIMP_UNDO (data); -} diff --git a/app/core/gimpundostack.h b/app/core/gimpundostack.h index 6217222995..a0213b12ac 100644 --- a/app/core/gimpundostack.h +++ b/app/core/gimpundostack.h @@ -37,7 +37,6 @@ struct _GimpUndoStack { GimpUndo parent_instance; - GimpImage *gimage; GimpContainer *undos; }; @@ -57,7 +56,7 @@ GimpUndo * gimp_undo_stack_pop_undo (GimpUndoStack *stack, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); -void gimp_undo_stack_free_bottom (GimpUndoStack *stack, +GimpUndo * gimp_undo_stack_free_bottom (GimpUndoStack *stack, GimpUndoMode undo_mode); GimpUndo * gimp_undo_stack_peek (GimpUndoStack *stack); diff --git a/app/dialogs/dialogs-constructors.c b/app/dialogs/dialogs-constructors.c index de6f4a7989..d55535352e 100644 --- a/app/dialogs/dialogs-constructors.c +++ b/app/dialogs/dialogs-constructors.c @@ -60,6 +60,7 @@ #include "widgets/gimpselectioneditor.h" #include "widgets/gimptoolbox.h" #include "widgets/gimptoolbox-color-area.h" +#include "widgets/gimpundoeditor.h" #include "widgets/gimpvectorslistview.h" #include "display/gimpdisplay.h" @@ -82,8 +83,6 @@ #include "tool-options-dialog.h" #include "vectors-commands.h" -#include "undo_history.h" - #include "libgimp/gimpintl.h" @@ -128,6 +127,8 @@ static void dialogs_set_indexed_palette_context_func (GimpDockable *dockable, GimpContext *context); static void dialogs_set_selection_editor_context_func (GimpDockable *dockable, GimpContext *context); +static void dialogs_set_undo_history_context_func (GimpDockable *dockable, + GimpContext *context); static void dialogs_set_navigation_context_func (GimpDockable *dockable, GimpContext *context); @@ -150,6 +151,9 @@ static void dialogs_indexed_palette_image_changed (GimpContext *context static void dialogs_selection_editor_image_changed (GimpContext *context, GimpImage *gimage, GimpSelectionEditor *editor); +static void dialogs_undo_history_image_changed (GimpContext *context, + GimpImage *gimage, + GimpUndoEditor *editor); static void dialogs_navigation_display_changed (GimpContext *context, GimpDisplay *gdisp, GimpNavigationView *view); @@ -183,31 +187,6 @@ dialogs_module_browser_get (GimpDialogFactory *factory, return module_browser_new (context->gimp); } -GtkWidget * -dialogs_undo_history_get (GimpDialogFactory *factory, - GimpContext *context, - gint preview_size) -{ - GimpImage *gimage; - GtkWidget *undo_history; - - gimage = gimp_context_get_image (context); - - if (! gimage) - return NULL; - - undo_history = g_object_get_data (G_OBJECT (gimage), "gimp-undo-history"); - - if (! undo_history) - { - undo_history = undo_history_new (gimage); - - g_object_set_data (G_OBJECT (gimage), "gimp-undo-history", undo_history); - } - - return undo_history; -} - GtkWidget * dialogs_display_filters_get (GimpDialogFactory *factory, GimpContext *context, @@ -795,6 +774,30 @@ dialogs_selection_editor_new (GimpDialogFactory *factory, return dockable; } +GtkWidget * +dialogs_undo_history_new (GimpDialogFactory *factory, + GimpContext *context, + gint preview_size) +{ + GimpImage *gimage; + GtkWidget *view; + GtkWidget *dockable; + + gimage = gimp_context_get_image (context); + + view = gimp_undo_editor_new (gimage); + + dockable = dialogs_dockable_new (view, + _("Undo History"), _("Undo"), + GTK_STOCK_UNDO, + dialogs_stock_text_tab_func, + dialogs_set_undo_history_context_func); + + gimp_dockable_set_context (GIMP_DOCKABLE (dockable), context); + + return dockable; +} + /***** misc dockables *****/ @@ -1380,6 +1383,41 @@ dialogs_set_selection_editor_context_func (GimpDockable *dockable, } } +static void +dialogs_set_undo_history_context_func (GimpDockable *dockable, + GimpContext *context) +{ + GimpUndoEditor *view; + + view = (GimpUndoEditor *) g_object_get_data (G_OBJECT (dockable), + "gimp-dialogs-view"); + + if (view) + { + if (dockable->context) + { + g_signal_handlers_disconnect_by_func (dockable->context, + dialogs_undo_history_image_changed, + view); + } + + if (context) + { + g_signal_connect (context, "image_changed", + G_CALLBACK (dialogs_undo_history_image_changed), + view); + + dialogs_undo_history_image_changed (context, + gimp_context_get_image (context), + view); + } + else + { + dialogs_undo_history_image_changed (NULL, NULL, view); + } + } +} + static void dialogs_set_navigation_context_func (GimpDockable *dockable, GimpContext *context) @@ -1470,6 +1508,14 @@ dialogs_selection_editor_image_changed (GimpContext *context, gimp_selection_editor_set_image (editor, gimage); } +static void +dialogs_undo_history_image_changed (GimpContext *context, + GimpImage *gimage, + GimpUndoEditor *editor) +{ + gimp_undo_editor_set_image (editor, gimage); +} + static void dialogs_navigation_display_changed (GimpContext *context, GimpDisplay *gdisp, diff --git a/app/dialogs/dialogs-constructors.h b/app/dialogs/dialogs-constructors.h index bdd45e4549..2497c5d600 100644 --- a/app/dialogs/dialogs-constructors.h +++ b/app/dialogs/dialogs-constructors.h @@ -31,9 +31,6 @@ GtkWidget * dialogs_preferences_get (GimpDialogFactory *factory, GtkWidget * dialogs_module_browser_get (GimpDialogFactory *factory, GimpContext *context, gint preview_size); -GtkWidget * dialogs_undo_history_get (GimpDialogFactory *factory, - GimpContext *context, - gint preview_size); GtkWidget * dialogs_display_filters_get (GimpDialogFactory *factory, GimpContext *context, gint preview_size); @@ -126,6 +123,9 @@ GtkWidget * dialogs_indexed_palette_new (GimpDialogFactory *factory, GtkWidget * dialogs_selection_editor_new (GimpDialogFactory *factory, GimpContext *context, gint preview_size); +GtkWidget * dialogs_undo_history_new (GimpDialogFactory *factory, + GimpContext *context, + gint preview_size); GtkWidget * dialogs_color_editor_new (GimpDialogFactory *factory, GimpContext *context, diff --git a/app/dialogs/dialogs.c b/app/dialogs/dialogs.c index 6e903070c9..aecf8113cb 100644 --- a/app/dialogs/dialogs.c +++ b/app/dialogs/dialogs.c @@ -43,7 +43,6 @@ static const GimpDialogFactoryEntry toplevel_entries[] = { "gimp-device-status-dialog", dialogs_device_status_get, 32, TRUE, TRUE, FALSE, TRUE }, { "gimp-preferences-dialog", dialogs_preferences_get, 32, TRUE, FALSE, FALSE, TRUE }, { "gimp-module-browser-dialog", dialogs_module_browser_get, 32, TRUE, FALSE, FALSE, TRUE }, - { "gimp-undo-history-dialog", dialogs_undo_history_get, 32, FALSE, FALSE, FALSE, TRUE }, { "gimp-display-filters-dialog", dialogs_display_filters_get, 32, FALSE, FALSE, FALSE, TRUE }, { "gimp-tips-dialog", dialogs_tips_get, 32, TRUE, FALSE, FALSE, TRUE }, { "gimp-about-dialog", dialogs_about_get, 32, TRUE, FALSE, FALSE, TRUE } @@ -76,6 +75,7 @@ static const GimpDialogFactoryEntry dock_entries[] = { "gimp-path-list", dialogs_path_list_view_new, 32, TRUE, FALSE, FALSE, TRUE }, { "gimp-indexed-palette", dialogs_indexed_palette_new, 32, FALSE, FALSE, FALSE, TRUE }, { "gimp-selection-editor", dialogs_selection_editor_new, 0, FALSE, FALSE, FALSE, TRUE }, + { "gimp-undo-history", dialogs_undo_history_new, 0, FALSE, FALSE, FALSE, TRUE }, { "gimp-color-editor", dialogs_color_editor_new, 0, FALSE, FALSE, FALSE, TRUE }, diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c index 708f075685..30341cfae6 100644 --- a/app/display/gimpdisplayshell-handlers.c +++ b/app/display/gimpdisplayshell-handlers.c @@ -44,7 +44,8 @@ static void gimp_display_shell_clean_dirty_handler (GimpImage *gimage, GimpDisplayShell *shell); static void gimp_display_shell_undo_event_handler (GimpImage *gimage, - gint event, + GimpUndoEvent event, + GimpUndo *undo, GimpDisplayShell *shell); static void gimp_display_shell_name_changed_handler (GimpImage *gimage, GimpDisplayShell *shell); @@ -267,7 +268,8 @@ gimp_display_shell_clean_dirty_handler (GimpImage *gimage, static void gimp_display_shell_undo_event_handler (GimpImage *gimage, - gint event, + GimpUndoEvent event, + GimpUndo *undo, GimpDisplayShell *shell) { shell->title_dirty = TRUE; diff --git a/app/gui/dialogs-constructors.c b/app/gui/dialogs-constructors.c index de6f4a7989..d55535352e 100644 --- a/app/gui/dialogs-constructors.c +++ b/app/gui/dialogs-constructors.c @@ -60,6 +60,7 @@ #include "widgets/gimpselectioneditor.h" #include "widgets/gimptoolbox.h" #include "widgets/gimptoolbox-color-area.h" +#include "widgets/gimpundoeditor.h" #include "widgets/gimpvectorslistview.h" #include "display/gimpdisplay.h" @@ -82,8 +83,6 @@ #include "tool-options-dialog.h" #include "vectors-commands.h" -#include "undo_history.h" - #include "libgimp/gimpintl.h" @@ -128,6 +127,8 @@ static void dialogs_set_indexed_palette_context_func (GimpDockable *dockable, GimpContext *context); static void dialogs_set_selection_editor_context_func (GimpDockable *dockable, GimpContext *context); +static void dialogs_set_undo_history_context_func (GimpDockable *dockable, + GimpContext *context); static void dialogs_set_navigation_context_func (GimpDockable *dockable, GimpContext *context); @@ -150,6 +151,9 @@ static void dialogs_indexed_palette_image_changed (GimpContext *context static void dialogs_selection_editor_image_changed (GimpContext *context, GimpImage *gimage, GimpSelectionEditor *editor); +static void dialogs_undo_history_image_changed (GimpContext *context, + GimpImage *gimage, + GimpUndoEditor *editor); static void dialogs_navigation_display_changed (GimpContext *context, GimpDisplay *gdisp, GimpNavigationView *view); @@ -183,31 +187,6 @@ dialogs_module_browser_get (GimpDialogFactory *factory, return module_browser_new (context->gimp); } -GtkWidget * -dialogs_undo_history_get (GimpDialogFactory *factory, - GimpContext *context, - gint preview_size) -{ - GimpImage *gimage; - GtkWidget *undo_history; - - gimage = gimp_context_get_image (context); - - if (! gimage) - return NULL; - - undo_history = g_object_get_data (G_OBJECT (gimage), "gimp-undo-history"); - - if (! undo_history) - { - undo_history = undo_history_new (gimage); - - g_object_set_data (G_OBJECT (gimage), "gimp-undo-history", undo_history); - } - - return undo_history; -} - GtkWidget * dialogs_display_filters_get (GimpDialogFactory *factory, GimpContext *context, @@ -795,6 +774,30 @@ dialogs_selection_editor_new (GimpDialogFactory *factory, return dockable; } +GtkWidget * +dialogs_undo_history_new (GimpDialogFactory *factory, + GimpContext *context, + gint preview_size) +{ + GimpImage *gimage; + GtkWidget *view; + GtkWidget *dockable; + + gimage = gimp_context_get_image (context); + + view = gimp_undo_editor_new (gimage); + + dockable = dialogs_dockable_new (view, + _("Undo History"), _("Undo"), + GTK_STOCK_UNDO, + dialogs_stock_text_tab_func, + dialogs_set_undo_history_context_func); + + gimp_dockable_set_context (GIMP_DOCKABLE (dockable), context); + + return dockable; +} + /***** misc dockables *****/ @@ -1380,6 +1383,41 @@ dialogs_set_selection_editor_context_func (GimpDockable *dockable, } } +static void +dialogs_set_undo_history_context_func (GimpDockable *dockable, + GimpContext *context) +{ + GimpUndoEditor *view; + + view = (GimpUndoEditor *) g_object_get_data (G_OBJECT (dockable), + "gimp-dialogs-view"); + + if (view) + { + if (dockable->context) + { + g_signal_handlers_disconnect_by_func (dockable->context, + dialogs_undo_history_image_changed, + view); + } + + if (context) + { + g_signal_connect (context, "image_changed", + G_CALLBACK (dialogs_undo_history_image_changed), + view); + + dialogs_undo_history_image_changed (context, + gimp_context_get_image (context), + view); + } + else + { + dialogs_undo_history_image_changed (NULL, NULL, view); + } + } +} + static void dialogs_set_navigation_context_func (GimpDockable *dockable, GimpContext *context) @@ -1470,6 +1508,14 @@ dialogs_selection_editor_image_changed (GimpContext *context, gimp_selection_editor_set_image (editor, gimage); } +static void +dialogs_undo_history_image_changed (GimpContext *context, + GimpImage *gimage, + GimpUndoEditor *editor) +{ + gimp_undo_editor_set_image (editor, gimage); +} + static void dialogs_navigation_display_changed (GimpContext *context, GimpDisplay *gdisp, diff --git a/app/gui/dialogs-constructors.h b/app/gui/dialogs-constructors.h index bdd45e4549..2497c5d600 100644 --- a/app/gui/dialogs-constructors.h +++ b/app/gui/dialogs-constructors.h @@ -31,9 +31,6 @@ GtkWidget * dialogs_preferences_get (GimpDialogFactory *factory, GtkWidget * dialogs_module_browser_get (GimpDialogFactory *factory, GimpContext *context, gint preview_size); -GtkWidget * dialogs_undo_history_get (GimpDialogFactory *factory, - GimpContext *context, - gint preview_size); GtkWidget * dialogs_display_filters_get (GimpDialogFactory *factory, GimpContext *context, gint preview_size); @@ -126,6 +123,9 @@ GtkWidget * dialogs_indexed_palette_new (GimpDialogFactory *factory, GtkWidget * dialogs_selection_editor_new (GimpDialogFactory *factory, GimpContext *context, gint preview_size); +GtkWidget * dialogs_undo_history_new (GimpDialogFactory *factory, + GimpContext *context, + gint preview_size); GtkWidget * dialogs_color_editor_new (GimpDialogFactory *factory, GimpContext *context, diff --git a/app/gui/dialogs-menu.c b/app/gui/dialogs-menu.c index 3a651e04de..80d367ae16 100644 --- a/app/gui/dialogs-menu.c +++ b/app/gui/dialogs-menu.c @@ -67,6 +67,8 @@ GimpItemFactoryEntry dialogs_menu_entries[] = "", GIMP_STOCK_TOOL_RECT_SELECT), ADD_TAB (N_("/Add Tab/Navigation..."), "gimp-navigation-view", "", GIMP_STOCK_NAVIGATION), + ADD_TAB (N_("/Add Tab/Undo History..."), "gimp-undo-history", + "", GTK_STOCK_UNDO), MENU_SEPARATOR ("/Add Tab/---"), diff --git a/app/gui/dialogs.c b/app/gui/dialogs.c index 6e903070c9..aecf8113cb 100644 --- a/app/gui/dialogs.c +++ b/app/gui/dialogs.c @@ -43,7 +43,6 @@ static const GimpDialogFactoryEntry toplevel_entries[] = { "gimp-device-status-dialog", dialogs_device_status_get, 32, TRUE, TRUE, FALSE, TRUE }, { "gimp-preferences-dialog", dialogs_preferences_get, 32, TRUE, FALSE, FALSE, TRUE }, { "gimp-module-browser-dialog", dialogs_module_browser_get, 32, TRUE, FALSE, FALSE, TRUE }, - { "gimp-undo-history-dialog", dialogs_undo_history_get, 32, FALSE, FALSE, FALSE, TRUE }, { "gimp-display-filters-dialog", dialogs_display_filters_get, 32, FALSE, FALSE, FALSE, TRUE }, { "gimp-tips-dialog", dialogs_tips_get, 32, TRUE, FALSE, FALSE, TRUE }, { "gimp-about-dialog", dialogs_about_get, 32, TRUE, FALSE, FALSE, TRUE } @@ -76,6 +75,7 @@ static const GimpDialogFactoryEntry dock_entries[] = { "gimp-path-list", dialogs_path_list_view_new, 32, TRUE, FALSE, FALSE, TRUE }, { "gimp-indexed-palette", dialogs_indexed_palette_new, 32, FALSE, FALSE, FALSE, TRUE }, { "gimp-selection-editor", dialogs_selection_editor_new, 0, FALSE, FALSE, FALSE, TRUE }, + { "gimp-undo-history", dialogs_undo_history_new, 0, FALSE, FALSE, FALSE, TRUE }, { "gimp-color-editor", dialogs_color_editor_new, 0, FALSE, FALSE, FALSE, TRUE }, diff --git a/app/gui/image-menu.c b/app/gui/image-menu.c index 9ca2a3407c..928949f6fc 100644 --- a/app/gui/image-menu.c +++ b/app/gui/image-menu.c @@ -466,13 +466,6 @@ GimpItemFactoryEntry image_menu_entries[] = NULL, "layers/flatten_image.html", NULL }, - MENU_SEPARATOR ("/Image/---"), - - { { N_("/Image/Undo History..."), NULL, - dialogs_create_toplevel_cmd_callback, 0 }, - "gimp-undo-history-dialog", - "dialogs/undo_history.html", NULL }, - /* /Layer */ /* /Layer/Stack */ @@ -707,6 +700,11 @@ GimpItemFactoryEntry image_menu_entries[] = "", GIMP_STOCK_NAVIGATION }, "gimp-navigation-view", NULL, NULL }, + { { N_("/Dialogs/Undo History..."), NULL, + dialogs_create_dockable_cmd_callback, 0, + "", GTK_STOCK_UNDO }, + "gimp-undo-history", + NULL, NULL }, MENU_SEPARATOR ("/Dialogs/---"), @@ -1277,7 +1275,6 @@ image_menu_update (GtkItemFactory *item_factory, SET_SENSITIVE ("/Image/Duplicate", gdisp); SET_SENSITIVE ("/Image/Merge Visible Layers...", gdisp && !fs && !aux && lp); SET_SENSITIVE ("/Image/Flatten Image", gdisp && !fs && !aux && lp); - SET_SENSITIVE ("/Image/Undo History...", gdisp); /* Layer */ diff --git a/app/gui/toolbox-menu.c b/app/gui/toolbox-menu.c index 1012ba4d44..cae8bfdfaf 100644 --- a/app/gui/toolbox-menu.c +++ b/app/gui/toolbox-menu.c @@ -125,6 +125,11 @@ GimpItemFactoryEntry toolbox_menu_entries[] = "", GIMP_STOCK_NAVIGATION }, "gimp-navigation-view", NULL, NULL }, + { { N_("/File/Dialogs/Undo History..."), NULL, + dialogs_create_dockable_cmd_callback, 0, + "", GTK_STOCK_UNDO }, + "gimp-undo-history", + NULL, NULL }, MENU_SEPARATOR ("/File/Dialogs/---"), diff --git a/app/menus/image-menu.c b/app/menus/image-menu.c index 9ca2a3407c..928949f6fc 100644 --- a/app/menus/image-menu.c +++ b/app/menus/image-menu.c @@ -466,13 +466,6 @@ GimpItemFactoryEntry image_menu_entries[] = NULL, "layers/flatten_image.html", NULL }, - MENU_SEPARATOR ("/Image/---"), - - { { N_("/Image/Undo History..."), NULL, - dialogs_create_toplevel_cmd_callback, 0 }, - "gimp-undo-history-dialog", - "dialogs/undo_history.html", NULL }, - /* /Layer */ /* /Layer/Stack */ @@ -707,6 +700,11 @@ GimpItemFactoryEntry image_menu_entries[] = "", GIMP_STOCK_NAVIGATION }, "gimp-navigation-view", NULL, NULL }, + { { N_("/Dialogs/Undo History..."), NULL, + dialogs_create_dockable_cmd_callback, 0, + "", GTK_STOCK_UNDO }, + "gimp-undo-history", + NULL, NULL }, MENU_SEPARATOR ("/Dialogs/---"), @@ -1277,7 +1275,6 @@ image_menu_update (GtkItemFactory *item_factory, SET_SENSITIVE ("/Image/Duplicate", gdisp); SET_SENSITIVE ("/Image/Merge Visible Layers...", gdisp && !fs && !aux && lp); SET_SENSITIVE ("/Image/Flatten Image", gdisp && !fs && !aux && lp); - SET_SENSITIVE ("/Image/Undo History...", gdisp); /* Layer */ diff --git a/app/menus/toolbox-menu.c b/app/menus/toolbox-menu.c index 1012ba4d44..cae8bfdfaf 100644 --- a/app/menus/toolbox-menu.c +++ b/app/menus/toolbox-menu.c @@ -125,6 +125,11 @@ GimpItemFactoryEntry toolbox_menu_entries[] = "", GIMP_STOCK_NAVIGATION }, "gimp-navigation-view", NULL, NULL }, + { { N_("/File/Dialogs/Undo History..."), NULL, + dialogs_create_dockable_cmd_callback, 0, + "", GTK_STOCK_UNDO }, + "gimp-undo-history", + NULL, NULL }, MENU_SEPARATOR ("/File/Dialogs/---"), diff --git a/app/paint/gimppaintcore-undo.c b/app/paint/gimppaintcore-undo.c index 2d5aaf43a5..77097c12f4 100644 --- a/app/paint/gimppaintcore-undo.c +++ b/app/paint/gimppaintcore-undo.c @@ -44,11 +44,9 @@ struct _PaintUndo }; static gboolean undo_pop_paint (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_paint (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -86,7 +84,6 @@ gimp_paint_core_push_undo (GimpImage *gimage, static gboolean undo_pop_paint (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { @@ -109,7 +106,6 @@ undo_pop_paint (GimpUndo *undo, static void undo_free_paint (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { PaintUndo *pu; diff --git a/app/tools/gimptransformtool-undo.c b/app/tools/gimptransformtool-undo.c index 5d9955d88e..2c5b962c83 100644 --- a/app/tools/gimptransformtool-undo.c +++ b/app/tools/gimptransformtool-undo.c @@ -54,11 +54,9 @@ struct _TransformUndo }; static gboolean undo_pop_transform (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum); static void undo_free_transform (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode); gboolean @@ -102,13 +100,12 @@ gimp_transform_tool_push_undo (GimpImage *gimage, static gboolean undo_pop_transform (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpTool *active_tool; - active_tool = tool_manager_get_active (gimage->gimp); + active_tool = tool_manager_get_active (undo->gimage->gimp); if (GIMP_IS_TRANSFORM_TOOL (active_tool)) { @@ -118,7 +115,7 @@ undo_pop_transform (GimpUndo *undo, tt = GIMP_TRANSFORM_TOOL (active_tool); tu = (TransformUndo *) undo->data; - path_transform_do_undo (gimage, tu->path_undo); + path_transform_do_undo (undo->gimage, tu->path_undo); /* only pop if the active tool is the tool that pushed this undo */ if (tu->tool_ID == active_tool->ID) @@ -156,7 +153,6 @@ undo_pop_transform (GimpUndo *undo, static void undo_free_transform (GimpUndo *undo, - GimpImage *gimage, GimpUndoMode undo_mode) { TransformUndo * tu; @@ -165,6 +161,8 @@ undo_free_transform (GimpUndo *undo, if (tu->original) tile_manager_destroy (tu->original); + path_transform_free_undo (tu->path_undo); + g_free (tu); } diff --git a/app/undo_history.c b/app/undo_history.c deleted file mode 100644 index 423cc07ce7..0000000000 --- a/app/undo_history.c +++ /dev/null @@ -1,917 +0,0 @@ -/* The GIMP -- an image manipulation program - * Copyright (C) 1995-1999 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. - * - * Undo history browser by Austin Donnelly - */ - - -/* TODO: - * - * - reuse the L&C previews? - * Currently we use gimp_image_construct_composite_preview () - * which makes use of the preview_cache on a per layer basis. - * - * - work out which (if any) is the clean image, and mark it as such. - * Currently, it's on the wrong line. - * - * - undo names are less than useful. This isn't a problem with - * undo_history.c itself, more with the rather chaotic way - * people have of picking an undo type when pushing undos, and - * inconsistent use of undo groups. Maybe rather than - * specifying an (enum) type, it should be a const char * ? - * - * BUGS: - * - clean pixmap in wrong place - * - * Initial rev 0.01, (c) 19 Sept 1999 Austin Donnelly - * - */ - -#include "config.h" - -#ifdef __GNUC__ -#warning GTK_DISABLE_DEPRECATED -#endif -#undef GTK_DISABLE_DEPRECATED - -#include - -#include "libgimpbase/gimpbase.h" -#include "libgimpwidgets/gimpwidgets.h" - -#include "display/display-types.h" - -#include "config/gimpcoreconfig.h" - -#include "base/pixel-region.h" -#include "base/temp-buf.h" - -#include "paint-funcs/paint-funcs.h" - -#include "core/gimp.h" -#include "core/gimpcontainer.h" -#include "core/gimpdrawable.h" -#include "core/gimpimage.h" -#include "core/gimpimage-mask.h" -#include "core/gimpimage-undo.h" -#include "core/gimpundostack.h" - -#include "file/file-utils.h" - -#include "widgets/gimpviewabledialog.h" - -#include "libgimp/gimpintl.h" - -#include "pixmaps/yes.xpm" -#include "pixmaps/question.xpm" - - -typedef struct -{ - GimpImage *gimage; /* image we're tracking undo info for */ - GtkWidget *shell; /* dialog window */ - GtkWidget *clist; /* list of undo actions */ - GtkWidget *undo_button; /* button to undo an operation */ - GtkWidget *redo_button; /* button to redo an operation */ - int old_selection; /* previous selection in the clist */ - int preview_size; /* size of the previews (from preferences) */ -} undo_history_st; - -typedef struct -{ - GtkCList *clist; - gint row; - gint size; - GimpImage *gimage; -} idle_preview_args; - -/* - * Theory of operation. - * - * Keep a clist. Each row of the clist corresponds to an image as it - * was at some time in the past, present or future. The selected row - * is the present image. Rows below the selected one are in the - * future - as redo operations are performed, they become the current - * image. Rows above the selected one are in the past - undo - * operations move the highlight up. - * - * The slight fly in the ointment is that if rows are images, then how - * should they be labelled? An undo or redo operation goes _between_ - * two image states - it isn't an image state. It's a pretty - * arbitrary decision, but I've chosen to label a row with the name of - * the action that brought the image into the state represented by - * that row. Thus, there is a special first row without a meaningful - * label, which represents the image state before the first action has - * been done to it. The choice is between a special first row or a - * special last row. Since people mostly work near the leading edge, - * not often going all the way back, I've chosen to put the special - * case out of common sight. - * - * So, the undo stack contents appear above the selected row, and the - * redo stack below it. - * - * The clist is initialised by mapping over the undo and redo stack. - * - * Once initialised, the dialog listens to undo_event signals from the - * gimage. These undo events allow us to track changes to the undo - * and redo stacks. We follow the events, making parallel changes to - * the clist. If we ever get out of sync, there is no mechanism to - * notice or re-sync. A few g_return_if_fails should catch some of - * these cases. - * - * User clicks changing the selected row in the clist turn into - * multiple calls to undo_pop or undo_redo, with appropriate signals - * blocked so we don't get our own events back. - * - * The "Close" button hides the dialog, rather than destroying it. - * This may well need to be changed, since the dialog will continue to - * track updates, and if it's generating previews this might take too - * long for large images. - * - * The dialog is destroyed when the gimage it is tracking is - * destroyed. Note that a File/Revert destroys the current gimage and - * so blows the undo/redo stacks. - * - * --austin, 19/9/1999 - */ - -/**************************************************************/ -/* Static Data */ - -static GdkPixmap *clean_pixmap = NULL; -static GdkBitmap *clean_mask = NULL; - -static GdkPixmap *clear_pixmap = NULL; -static GdkBitmap *clear_mask = NULL; - - -static void undo_history_undo_event (GtkWidget *widget, - gint ev, - gpointer data); -static void undo_history_clean_callback (GtkWidget *widget, - gpointer data); - -static void undo_history_select_row_callback (GtkWidget *widget, - gint row, - gint column, - gpointer event, - gpointer data); - - -/**************************************************************/ -/* Local functions */ - - -static MaskBuf * -mask_render_preview (GimpImage *gimage, - gint *pwidth, - gint *pheight) -{ - GimpChannel *mask; - MaskBuf *scaled_buf = NULL; - PixelRegion srcPR, destPR; - gint subsample; - gint width, height; - gint scale; - - mask = gimp_image_get_mask (gimage); - if ((gimp_drawable_width (GIMP_DRAWABLE(mask)) > *pwidth) || - (gimp_drawable_height (GIMP_DRAWABLE(mask)) > *pheight)) - { - if (((gfloat) gimp_drawable_width (GIMP_DRAWABLE (mask)) / (gfloat) *pwidth) > - ((gfloat) gimp_drawable_height (GIMP_DRAWABLE (mask)) / (gfloat) *pheight)) - { - width = *pwidth; - height = (gimp_drawable_height (GIMP_DRAWABLE (mask)) * (*pwidth)) / gimp_drawable_width (GIMP_DRAWABLE (mask)); - } - else - { - width = (gimp_drawable_width (GIMP_DRAWABLE (mask)) * (*pheight)) / gimp_drawable_height (GIMP_DRAWABLE (mask)); - height = *pheight; - } - - scale = TRUE; - } - else - { - width = gimp_drawable_width (GIMP_DRAWABLE (mask)); - height = gimp_drawable_height (GIMP_DRAWABLE (mask)); - - scale = FALSE; - } - - /* if the mask is empty, no need to scale and update again */ - if (gimp_image_mask_is_empty (gimage)) - return NULL; - - if (scale) - { - /* calculate 'acceptable' subsample */ - subsample = 1; - while ((width * (subsample + 1) * 2 < gimp_drawable_width (GIMP_DRAWABLE (mask))) && - (height * (subsample + 1) * 2 < gimp_drawable_height (GIMP_DRAWABLE (mask)))) - subsample = subsample + 1; - - pixel_region_init (&srcPR, gimp_drawable_data (GIMP_DRAWABLE (mask)), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (mask)), - gimp_drawable_height (GIMP_DRAWABLE (mask)), FALSE); - - scaled_buf = mask_buf_new (width, height); - destPR.bytes = 1; - destPR.x = 0; - destPR.y = 0; - destPR.w = width; - destPR.h = height; - destPR.rowstride = srcPR.bytes * width; - destPR.data = mask_buf_data (scaled_buf); - destPR.tiles = NULL; - - subsample_region (&srcPR, &destPR, subsample); - } - else - { - pixel_region_init (&srcPR, gimp_drawable_data (GIMP_DRAWABLE (mask)), - 0, 0, - gimp_drawable_width (GIMP_DRAWABLE (mask)), - gimp_drawable_height (GIMP_DRAWABLE (mask)), FALSE); - - scaled_buf = mask_buf_new (width, height); - destPR.bytes = 1; - destPR.x = 0; - destPR.y = 0; - destPR.w = width; - destPR.h = height; - destPR.rowstride = srcPR.bytes * width; - destPR.data = mask_buf_data (scaled_buf); - destPR.tiles = NULL; - - copy_region (&srcPR, &destPR); - } - - *pheight = height; - *pwidth = width; - return scaled_buf; -} - - -static gint -undo_history_set_pixmap_idle (gpointer data) -{ - idle_preview_args *idle = data; - static GdkGC *gc = NULL; - TempBuf *buf = NULL; - GdkPixmap *pixmap; - GimpUndoType utype; - MaskBuf *mbuf = NULL; - guchar *src; - gdouble r, g, b, a; - gdouble c0, c1; - guchar *p0, *p1, *even, *odd; - gint width, height, bpp; - gint x, y; - - if (!gc) - gc = gdk_gc_new (GTK_WIDGET (idle->clist)->window); - - width = idle->gimage->width; - height = idle->gimage->height; - - /* Get right aspect ratio */ - if (width > height) - { - height = (gint)(((gdouble)idle->size * (gdouble)height) / (gdouble)width + 0.5); - width = (gint)(((gdouble)width * (gdouble)height)/ (gdouble)idle->gimage->height + 0.5); - } - else - { - width = (gint)(((gdouble)idle->size * (gdouble)width) / (gdouble)height + 0.5); - height = (gint)(((gdouble)height * (gdouble)width ) /(gdouble) idle->gimage->width + 0.5); - } - - utype = gimp_undo_stack_peek (idle->gimage->undo_stack)->undo_type; - - if ((utype != GIMP_UNDO_MASK && utype != GIMP_UNDO_IMAGE_QMASK) || - (mbuf = mask_render_preview (idle->gimage, &width, &height)) == NULL) - { - buf = gimp_viewable_get_new_preview (GIMP_VIEWABLE (idle->gimage), - width, - height); - bpp = buf->bytes; - src = temp_buf_data (buf); - } - else - { - src = mask_buf_data (mbuf); - bpp = 1; /* Always the case for masks */ - } - - pixmap = gdk_pixmap_new (GTK_WIDGET (idle->clist)->window, - width + 2, height + 2, - -1); - - gdk_draw_rectangle (pixmap, - GTK_WIDGET (idle->clist)->style->black_gc, - TRUE, - 0, 0, - width + 2, height + 2); - - even = g_malloc (width * 3); - odd = g_malloc (width * 3); - - for (y = 0; y < height; y++) - { - p0 = even; - p1 = odd; - - for (x = 0; x < width; x++) - { - if (bpp == 4) - { - r = ((gdouble) src[x*4+0]) / 255.0; - g = ((gdouble) src[x*4+1]) / 255.0; - b = ((gdouble) src[x*4+2]) / 255.0; - a = ((gdouble) src[x*4+3]) / 255.0; - } - else if (bpp == 3) - { - r = ((gdouble) src[x*3+0]) / 255.0; - g = ((gdouble) src[x*3+1]) / 255.0; - b = ((gdouble) src[x*3+2]) / 255.0; - a = 1.0; - } - else - { - r = ((gdouble) src[x*bpp+0]) / 255.0; - g = b = r; - if (bpp == 2) - a = ((gdouble) src[x*bpp+1]) / 255.0; - else - a = 1.0; - } - - if ((x / GIMP_CHECK_SIZE_SM) & 1) - { - c0 = GIMP_CHECK_LIGHT; - c1 = GIMP_CHECK_DARK; - } - else - { - c0 = GIMP_CHECK_DARK; - c1 = GIMP_CHECK_LIGHT; - } - - *p0++ = (c0 + (r - c0) * a) * 255.0; - *p0++ = (c0 + (g - c0) * a) * 255.0; - *p0++ = (c0 + (b - c0) * a) * 255.0; - - *p1++ = (c1 + (r - c1) * a) * 255.0; - *p1++ = (c1 + (g - c1) * a) * 255.0; - *p1++ = (c1 + (b - c1) * a) * 255.0; - - } - - if ((y / GIMP_CHECK_SIZE_SM) & 1) - { - gdk_draw_rgb_image (pixmap, gc, - 1, y + 1, - width, 1, - GDK_RGB_DITHER_NORMAL, - (guchar *) odd, 3); - } - else - { - gdk_draw_rgb_image (pixmap, gc, - 1, y + 1, - width, 1, - GDK_RGB_DITHER_NORMAL, - (guchar *) even, 3); - } - src += width * bpp; - } - - g_free (even); - g_free (odd); - - if (buf) - temp_buf_free (buf); - if (mbuf) - mask_buf_free (mbuf); - - gtk_clist_set_row_data (idle->clist, idle->row, (gpointer)2); - gtk_clist_set_pixmap (idle->clist, idle->row, 0, pixmap, NULL); - g_object_unref (pixmap); - - return (FALSE); -} - -/* check if a preview is already made, otherwise g_idle_add the pixmap func */ -static void -undo_history_set_pixmap (GtkCList *clist, - gint row, - gint size, - GimpImage *gimage) -{ - static idle_preview_args idle; - - if (!size || (GPOINTER_TO_INT (gtk_clist_get_row_data (clist, row))) == 2) - return; - - idle.clist = clist; - idle.row = row; - idle.size = size; - idle.gimage = gimage; - - g_idle_add (undo_history_set_pixmap_idle, &idle); -} - - -/* close button clicked */ -static void -undo_history_close_callback (GtkWidget *widget, - gpointer data) -{ - undo_history_st *st = data; - gtk_widget_hide (GTK_WIDGET (st->shell)); -} - -/* The gimage and shell destroy callbacks are split so we can: - * a) blow the shell when the image dissappears - * b) disconnect from the image if the shell dissappears (we don't - * want signals from the image to carry on using "st" once it's - * been freed. - */ - -/* gimage renamed */ -static void -undo_history_gimage_rename_callback (GimpImage *gimage, - gpointer data) -{ - undo_history_st *st = data; - gchar *basename; - gchar *title; - - basename = g_path_get_basename (gimp_image_get_uri (gimage)); - - title = g_strdup_printf (_("Undo History: %s"), basename); - - g_free (basename); - - gtk_window_set_title (GTK_WINDOW (st->shell), title); - - g_free (title); -} - -static void -undo_history_shell_destroy_callback (GtkWidget *widget, - gpointer data) -{ - undo_history_st *st = data; - - if (st->gimage) - { - g_signal_handlers_disconnect_by_func (st->gimage, - undo_history_undo_event, - st); - g_signal_handlers_disconnect_by_func (st->gimage, - undo_history_gimage_rename_callback, - st); - g_signal_handlers_disconnect_by_func (st->gimage, - undo_history_clean_callback, - st); - g_object_unref (st->gimage); - - } - - g_free (st); -} - -/* undo button clicked */ -static void -undo_history_undo_callback (GtkWidget *widget, - gpointer data) -{ - undo_history_st *st = data; - - if (gimp_image_undo (st->gimage)) - gimp_image_flush (st->gimage); -} - -/* redo button clicked */ -static void -undo_history_redo_callback (GtkWidget *widget, - gpointer data) -{ - undo_history_st *st = data; - - if (gimp_image_redo (st->gimage)) - gimp_image_flush (st->gimage); -} - - -/* Always start clist with dummy entry for image state before - * the first action on the undo stack */ -static void -undo_history_prepend_special (GtkCList *clist) -{ - gchar *name = _("[ base image ]"); - gchar *namelist[3]; - gint row; - - namelist[0] = NULL; - namelist[1] = NULL; - namelist[2] = name; - - row = gtk_clist_prepend (clist, namelist); -} - - -/* Recalculate which of the undo and redo buttons are meant to be sensitive */ -static void -undo_history_set_sensitive (undo_history_st *st, - gint rows) -{ - gtk_widget_set_sensitive (st->undo_button, (st->old_selection != 0)); - gtk_widget_set_sensitive (st->redo_button, (st->old_selection != rows-1)); -} - - -/* Track undo_event signals, telling us of changes to the undo and - * redo stacks. */ -static void -undo_history_undo_event (GtkWidget *widget, - gint ev, - gpointer data) -{ - undo_history_st *st = data; - undo_event_t event = ev; - const gchar *name; - gchar *namelist[3]; - GList *list; - gint cur_selection; - GtkCList *clist; - gint row; - GdkPixmap *pixmap; - GdkBitmap *mask; - - list = GTK_CLIST (st->clist)->selection; - g_return_if_fail (list != NULL); - cur_selection = GPOINTER_TO_INT (list->data); - - clist = GTK_CLIST (st->clist); - - /* block select events */ - g_signal_handlers_block_by_func (st->clist, - undo_history_select_row_callback, - st); - - switch (event) - { - case UNDO_PUSHED: - /* clip everything after the current selection (ie, the - * actions that are from the redo stack) */ - gtk_clist_freeze (clist); - while (clist->rows > cur_selection + 1) - gtk_clist_remove (clist, cur_selection + 1); - - /* find out what's new */ - name = gimp_object_get_name (GIMP_OBJECT (gimp_undo_stack_peek (st->gimage->undo_stack))); - namelist[0] = NULL; - namelist[1] = NULL; - namelist[2] = (char *) name; - row = gtk_clist_append (clist, namelist); - g_assert (clist->rows == cur_selection + 2); - - undo_history_set_pixmap (clist, row, st->preview_size, st->gimage); - - /* always force selection to bottom, and scroll to it */ - gtk_clist_select_row (clist, clist->rows - 1, -1); - gtk_clist_thaw (clist); - gtk_clist_moveto (clist, clist->rows - 1, 0, 1.0, 0.0); - cur_selection = clist->rows - 1; - break; - - case UNDO_EXPIRED: - /* remove earliest row, but not our special first one */ - if (gtk_clist_get_pixmap (clist, 1, 0, &pixmap, &mask)) - gtk_clist_set_pixmap (clist, 0, 0, pixmap, mask); - gtk_clist_remove (clist, 1); - break; - - case UNDO_POPPED: - /* move hilight up one */ - g_return_if_fail (cur_selection >= 1); - gtk_clist_select_row (clist, cur_selection - 1, -1); - cur_selection--; - undo_history_set_pixmap (clist, cur_selection, st->preview_size, st->gimage); - if ( !(gtk_clist_row_is_visible (clist, cur_selection) & GTK_VISIBILITY_FULL)) - gtk_clist_moveto (clist, cur_selection, 0, 0.0, 0.0); - break; - - case UNDO_REDO: - /* move hilight down one */ - g_return_if_fail (cur_selection+1 < clist->rows); - gtk_clist_select_row (clist, cur_selection+1, -1); - cur_selection++; - undo_history_set_pixmap (clist, cur_selection, st->preview_size, st->gimage); - if ( !(gtk_clist_row_is_visible (clist, cur_selection) & GTK_VISIBILITY_FULL)) - gtk_clist_moveto (clist, cur_selection, 0, 1.0, 0.0); - break; - - case UNDO_FREE: - /* clear all info other that the special first line */ - gtk_clist_freeze (clist); - gtk_clist_clear (clist); - undo_history_prepend_special (clist); - gtk_clist_thaw (clist); - cur_selection = 0; - break; - } - - /* if the image is clean, set the clean pixmap */ - if (st->gimage->dirty == 0) - gtk_clist_set_pixmap (clist, cur_selection, 1, clean_pixmap, clean_mask); - - g_signal_handlers_unblock_by_func (st->clist, - undo_history_select_row_callback, - st); - - st->old_selection = cur_selection; - undo_history_set_sensitive (st, clist->rows); -} - - -static void -undo_history_select_row_callback (GtkWidget *widget, - gint row, - gint column, - gpointer event, - gpointer data) -{ - undo_history_st *st = data; - gint cur_selection; - - cur_selection = row; - - if (cur_selection == st->old_selection) - return; - - /* Disable undo_event signals while we do these multiple undo or - * redo actions. */ - g_signal_handlers_block_by_func (st->gimage, - undo_history_undo_event, st); - - while (cur_selection < st->old_selection) - { - gimp_image_undo (st->gimage); - st->old_selection--; - } - while (cur_selection > st->old_selection) - { - gimp_image_redo (st->gimage); - st->old_selection++; - } - - gimp_image_flush (st->gimage); - - undo_history_set_pixmap (GTK_CLIST (widget), - cur_selection, st->preview_size, st->gimage); - - /* if the image is clean, set the clean pixmap */ - if (st->gimage->dirty == 0) - gtk_clist_set_pixmap (GTK_CLIST (widget), - cur_selection, 1, clean_pixmap, clean_mask); - - g_signal_handlers_unblock_by_func (st->gimage, - undo_history_undo_event, st); - - undo_history_set_sensitive (st, GTK_CLIST(st->clist)->rows); -} - - -static void -undo_history_clean_callback (GtkWidget *widget, - gpointer data) -{ - undo_history_st *st = data; - gint i; - gint nrows; - GtkCList *clist; - - if (st->gimage->dirty != 0) - return; - - /* - * The image has become clean. Remove the clean_pixmap from - * all entries. It will be set in the undo_event or select_row - * callbacks. - * Ugly, but works better than before. The actual problem is - * that the "clean" signal is emitted before UNDO_POPPED event, - * so we can not simply set the clean pixmap here. - */ - - clist = GTK_CLIST (st->clist); - nrows = clist->rows; - - gtk_clist_freeze (clist); - for (i=0; i < nrows; i++) - gtk_clist_set_text (clist, i, 1, NULL); - gtk_clist_thaw (clist); -} - - -/* Used to build up initial contents of clist */ -static void -undo_history_init_undo (gpointer undo, - gpointer data) -{ - undo_history_st *st = data; - gchar *namelist[3]; - gint row; - - namelist[0] = NULL; - namelist[1] = NULL; - namelist[2] = (gchar *) gimp_object_get_name (GIMP_OBJECT (undo)); - row = gtk_clist_prepend (GTK_CLIST (st->clist), namelist); - gtk_clist_set_pixmap (GTK_CLIST (st->clist), row, 0, - clear_pixmap, clear_mask); -} - -static void -undo_history_init_redo (gpointer undo, - gpointer data) -{ - undo_history_st *st = data; - gchar *namelist[3]; - gint row; - - namelist[0] = NULL; namelist[1] = NULL; - namelist[1] = NULL; - namelist[2] = (gchar *) gimp_object_get_name (GIMP_OBJECT (undo)); - row = gtk_clist_append (GTK_CLIST (st->clist), namelist); - gtk_clist_set_pixmap (GTK_CLIST (st->clist), row, 0, - clear_pixmap, clear_mask); -} - - -/*************************************************************/ -/* Publicly exported function */ - -GtkWidget * -undo_history_new (GimpImage *gimage) -{ - undo_history_st *st; - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *button; - GtkWidget *scrolled_win; - - st = g_new0 (undo_history_st, 1); - st->gimage = gimage; - g_object_ref (gimage); - st->preview_size = gimage->gimp->config->preview_size; - - /* gimage signals */ - g_signal_connect (gimage, "undo_event", - G_CALLBACK (undo_history_undo_event), - st); - g_signal_connect (gimage, "name_changed", - G_CALLBACK (undo_history_gimage_rename_callback), - st); - g_signal_connect (gimage, "clean", - G_CALLBACK (undo_history_clean_callback), - st); - - /* The shell and main vbox */ - st->shell = - gimp_viewable_dialog_new (GIMP_VIEWABLE (gimage), - _("Undo History"), "undo_history", - GTK_STOCK_UNDO, - _("Image Undo History"), - gimp_standard_help_func, - "dialogs/undo_history.html", - - GTK_STOCK_CLOSE, undo_history_close_callback, - st, NULL, NULL, TRUE, TRUE, - - NULL); - - vbox = gtk_vbox_new (FALSE, 2); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (st->shell)->vbox), vbox); - gtk_widget_show (vbox); - - g_signal_connect (st->shell, "destroy", - G_CALLBACK (undo_history_shell_destroy_callback), - st); - - scrolled_win = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_set_usize (GTK_WIDGET (scrolled_win), - 160 + st->preview_size, - 4 * (MAX (st->preview_size, 16) + 6)); - - /* clist of undo actions */ - st->clist = gtk_clist_new (3); - gtk_clist_set_selection_mode (GTK_CLIST (st->clist), GTK_SELECTION_BROWSE); - gtk_clist_set_reorderable (GTK_CLIST (st->clist), FALSE); - gtk_clist_set_row_height (GTK_CLIST (st->clist), MAX (st->preview_size, 16) + 4); - gtk_clist_set_column_width (GTK_CLIST (st->clist), 0, st->preview_size + 2); - gtk_clist_set_column_width (GTK_CLIST (st->clist), 1, 18); - gtk_clist_set_column_min_width (GTK_CLIST (st->clist), 2, 64); - - /* allocate the pixmaps if not already done */ - if (!clean_pixmap) - { - GtkStyle *style; - - gtk_widget_realize (st->shell); - style = gtk_widget_get_style (st->shell); - - clean_pixmap = - gdk_pixmap_create_from_xpm_d (st->shell->window, - &clean_mask, - &style->bg[GTK_STATE_NORMAL], - yes_xpm); - - clear_pixmap = - gdk_pixmap_create_from_xpm_d (st->shell->window, - &clear_mask, - &style->bg[GTK_STATE_NORMAL], - question_xpm); - } - - /* work out the initial contents */ - gimp_container_foreach (GIMP_CONTAINER (st->gimage->undo_stack->undos), - undo_history_init_undo, st); - - /* force selection to bottom */ - gtk_clist_select_row (GTK_CLIST (st->clist), - GTK_CLIST (st->clist)->rows - 1, -1); - - gimp_container_foreach (GIMP_CONTAINER (st->gimage->redo_stack->undos), - undo_history_init_redo, st); - - undo_history_prepend_special (GTK_CLIST (st->clist)); - st->old_selection = GPOINTER_TO_INT(GTK_CLIST(st->clist)->selection->data); - - /* draw the preview of the current state */ - undo_history_set_pixmap (GTK_CLIST (st->clist), - st->old_selection, st->preview_size, st->gimage); - - g_signal_connect (st->clist, "select_row", - G_CALLBACK (undo_history_select_row_callback), - st); - - /* if the image is clean, set the clean pixmap */ - if (st->gimage->dirty == 0) - gtk_clist_set_pixmap (GTK_CLIST (st->clist), st->old_selection, 1, clean_pixmap, clean_mask); - - gtk_widget_show (GTK_WIDGET (st->clist)); - - gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0); - gtk_widget_show (GTK_WIDGET (scrolled_win)); - gtk_container_add (GTK_CONTAINER (scrolled_win), st->clist); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), - GTK_POLICY_NEVER, - GTK_POLICY_ALWAYS); - - hbox = gtk_hbox_new (FALSE, 6); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 2); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); - - st->undo_button = button = gtk_button_new_from_stock (GTK_STOCK_UNDO); - gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); - g_signal_connect (button, "clicked", - G_CALLBACK (undo_history_undo_callback), - st); - gtk_widget_show (GTK_WIDGET (button)); - - st->redo_button = button = gtk_button_new_from_stock (GTK_STOCK_REDO); - gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); - g_signal_connect (button, "clicked", - G_CALLBACK (undo_history_redo_callback), - st); - gtk_widget_show (GTK_WIDGET (button)); - - undo_history_set_sensitive (st, GTK_CLIST (st->clist)->rows); - - gtk_widget_show (GTK_WIDGET (st->shell)); - gtk_clist_moveto (GTK_CLIST (st->clist), st->old_selection, 0, 0.5, 0.0); - - return st->shell; -} diff --git a/app/undo_history.h b/app/undo_history.h deleted file mode 100644 index ac82b0aaeb..0000000000 --- a/app/undo_history.h +++ /dev/null @@ -1,26 +0,0 @@ -/* 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. - */ - -#ifndef __UNDO_HISTORY_H__ -#define __UNDO_HISTORY_H__ - - -GtkWidget * undo_history_new (GimpImage *gimage); - - -#endif /* __UNDO_HISTORY_H__ */ diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am index 1518f05d22..da0cf531c4 100644 --- a/app/widgets/Makefile.am +++ b/app/widgets/Makefile.am @@ -151,6 +151,10 @@ libappwidgets_a_sources = \ gimptoolbox-indicator-area.h \ gimptoolinfopreview.c \ gimptoolinfopreview.h \ + gimpundoeditor.c \ + gimpundoeditor.h \ + gimpundopreview.c \ + gimpundopreview.h \ gimpvectorslistview.c \ gimpvectorslistview.h \ gimpviewabledialog.c \ diff --git a/app/widgets/gimpdnd.c b/app/widgets/gimpdnd.c index f04d265dc9..ba62014043 100644 --- a/app/widgets/gimpdnd.c +++ b/app/widgets/gimpdnd.c @@ -1141,16 +1141,11 @@ gimp_dnd_data_type_get_by_g_type (GType type) { dnd_type = GIMP_DND_TYPE_TOOL; } - else - { - g_warning ("%s(): unsupported GType \"%s\"", - G_GNUC_FUNCTION, g_type_name (type)); - } return dnd_type; } -void +gboolean gimp_dnd_drag_source_set_by_type (GtkWidget *widget, GdkModifierType start_button_mask, GType type, @@ -1158,20 +1153,22 @@ gimp_dnd_drag_source_set_by_type (GtkWidget *widget, { GimpDndType dnd_type; - g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) - return; + return FALSE; gtk_drag_source_set (widget, start_button_mask, &dnd_data_defs[dnd_type].target_entry, 1, actions); + + return TRUE; } -void +gboolean gimp_dnd_drag_dest_set_by_type (GtkWidget *widget, GtkDestDefaults flags, GType type, @@ -1179,20 +1176,22 @@ gimp_dnd_drag_dest_set_by_type (GtkWidget *widget, { GimpDndType dnd_type; - g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) - return; + return FALSE; gtk_drag_dest_set (widget, flags, &dnd_data_defs[dnd_type].target_entry, 1, actions); + + return TRUE; } -void +gboolean gimp_dnd_viewable_source_set (GtkWidget *widget, GType type, GimpDndDragViewableFunc get_viewable_func, @@ -1200,36 +1199,40 @@ gimp_dnd_viewable_source_set (GtkWidget *widget, { GimpDndType dnd_type; - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (get_viewable_func != NULL); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (get_viewable_func != NULL, FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) - return; + return FALSE; gimp_dnd_data_source_set (dnd_type, widget, G_CALLBACK (get_viewable_func), data); + + return TRUE; } -void +gboolean gimp_dnd_viewable_source_unset (GtkWidget *widget, GType type) { GimpDndType dnd_type; - g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) - return; + return FALSE; gimp_dnd_data_source_unset (widget); + + return TRUE; } -void +gboolean gimp_dnd_viewable_dest_add (GtkWidget *widget, GType type, GimpDndDropViewableFunc set_viewable_func, @@ -1237,33 +1240,37 @@ gimp_dnd_viewable_dest_add (GtkWidget *widget, { GimpDndType dnd_type; - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (set_viewable_func != NULL); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (set_viewable_func != NULL, FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) - return; + return FALSE; gimp_dnd_data_dest_add (dnd_type, widget, G_CALLBACK (set_viewable_func), - data); + data); + + return TRUE; } -void +gboolean gimp_dnd_viewable_dest_remove (GtkWidget *widget, GType type) { GimpDndType dnd_type; - g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); dnd_type = gimp_dnd_data_type_get_by_g_type (type); if (dnd_type == GIMP_DND_TYPE_NONE) - return; + return FALSE; gimp_dnd_data_dest_remove (dnd_type, widget); + + return TRUE; } GimpViewable * diff --git a/app/widgets/gimpdnd.h b/app/widgets/gimpdnd.h index 62ea81e47d..c335c61391 100644 --- a/app/widgets/gimpdnd.h +++ b/app/widgets/gimpdnd.h @@ -145,30 +145,30 @@ typedef GimpViewable * (* GimpDndDragViewableFunc) (GtkWidget *widget, gpointer data); -void gimp_dnd_drag_source_set_by_type (GtkWidget *widget, - GdkModifierType start_button_mask, - GType type, - GdkDragAction actions); -void gimp_dnd_viewable_source_set (GtkWidget *widget, - GType type, - GimpDndDragViewableFunc get_viewable_func, - gpointer data); -void gimp_dnd_viewable_source_unset (GtkWidget *widget, - GType type); +gboolean gimp_dnd_drag_source_set_by_type (GtkWidget *widget, + GdkModifierType start_button_mask, + GType type, + GdkDragAction actions); +gboolean gimp_dnd_viewable_source_set (GtkWidget *widget, + GType type, + GimpDndDragViewableFunc get_viewable_func, + gpointer data); +gboolean gimp_dnd_viewable_source_unset (GtkWidget *widget, + GType type); -void gimp_dnd_drag_dest_set_by_type (GtkWidget *widget, - GtkDestDefaults flags, - GType type, - GdkDragAction actions); +gboolean gimp_dnd_drag_dest_set_by_type (GtkWidget *widget, + GtkDestDefaults flags, + GType type, + GdkDragAction actions); -void gimp_dnd_viewable_dest_add (GtkWidget *widget, - GType type, - GimpDndDropViewableFunc set_viewable_func, - gpointer data); -void gimp_dnd_viewable_dest_remove (GtkWidget *widget, - GType type); +gboolean gimp_dnd_viewable_dest_add (GtkWidget *widget, + GType type, + GimpDndDropViewableFunc set_viewable_func, + gpointer data); +gboolean gimp_dnd_viewable_dest_remove (GtkWidget *widget, + GType type); -GimpViewable * gimp_dnd_get_drag_data (GtkWidget *widget); +GimpViewable * gimp_dnd_get_drag_data (GtkWidget *widget); #endif /* __GIMP_DND_H__ */ diff --git a/app/widgets/gimppreview-utils.c b/app/widgets/gimppreview-utils.c index a9d6414b26..5c1ce85122 100644 --- a/app/widgets/gimppreview-utils.c +++ b/app/widgets/gimppreview-utils.c @@ -34,6 +34,7 @@ #include "core/gimppalette.h" #include "core/gimppattern.h" #include "core/gimptoolinfo.h" +#include "core/gimpundo.h" #include "gimpbrushpreview.h" #include "gimpbufferpreview.h" @@ -44,6 +45,7 @@ #include "gimppalettepreview.h" #include "gimppatternpreview.h" #include "gimptoolinfopreview.h" +#include "gimpundopreview.h" GType @@ -90,6 +92,10 @@ gimp_preview_type_from_viewable_type (GType viewable_type) { type = GIMP_TYPE_IMAGEFILE_PREVIEW; } + else if (g_type_is_a (viewable_type, GIMP_TYPE_UNDO)) + { + type = GIMP_TYPE_UNDO_PREVIEW; + } return type; } diff --git a/app/widgets/gimppreview.c b/app/widgets/gimppreview.c index 0ffb0e2745..184efe42f5 100644 --- a/app/widgets/gimppreview.c +++ b/app/widgets/gimppreview.c @@ -630,17 +630,28 @@ gimp_preview_set_viewable (GimpPreview *preview, g_signal_handlers_disconnect_by_func (preview->viewable, G_CALLBACK (gimp_preview_size_changed), preview); + + if (! viewable && ! preview->is_popup) + { + if (gimp_dnd_viewable_source_unset (GTK_WIDGET (preview), + G_TYPE_FROM_INSTANCE (preview->viewable))) + { + gtk_drag_source_unset (GTK_WIDGET (preview)); + } + } } else if (viewable && ! preview->is_popup) { - gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), - GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + if (gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), + GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + viewable_type, + GDK_ACTION_COPY)) + { + gimp_dnd_viewable_source_set (GTK_WIDGET (preview), viewable_type, - GDK_ACTION_COPY); - gimp_dnd_viewable_source_set (GTK_WIDGET (preview), - viewable_type, - gimp_preview_drag_viewable, - NULL); + gimp_preview_drag_viewable, + NULL); + } } preview->viewable = viewable; diff --git a/app/widgets/gimppreviewrenderer.c b/app/widgets/gimppreviewrenderer.c index 0ffb0e2745..184efe42f5 100644 --- a/app/widgets/gimppreviewrenderer.c +++ b/app/widgets/gimppreviewrenderer.c @@ -630,17 +630,28 @@ gimp_preview_set_viewable (GimpPreview *preview, g_signal_handlers_disconnect_by_func (preview->viewable, G_CALLBACK (gimp_preview_size_changed), preview); + + if (! viewable && ! preview->is_popup) + { + if (gimp_dnd_viewable_source_unset (GTK_WIDGET (preview), + G_TYPE_FROM_INSTANCE (preview->viewable))) + { + gtk_drag_source_unset (GTK_WIDGET (preview)); + } + } } else if (viewable && ! preview->is_popup) { - gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), - GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + if (gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), + GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + viewable_type, + GDK_ACTION_COPY)) + { + gimp_dnd_viewable_source_set (GTK_WIDGET (preview), viewable_type, - GDK_ACTION_COPY); - gimp_dnd_viewable_source_set (GTK_WIDGET (preview), - viewable_type, - gimp_preview_drag_viewable, - NULL); + gimp_preview_drag_viewable, + NULL); + } } preview->viewable = viewable; diff --git a/app/widgets/gimpselectioneditor.h b/app/widgets/gimpselectioneditor.h index 2872832550..74d34c419e 100644 --- a/app/widgets/gimpselectioneditor.h +++ b/app/widgets/gimpselectioneditor.h @@ -22,8 +22,6 @@ #include "gimpeditor.h" -#include "gui/gui-types.h" /* temp hack */ - #define GIMP_TYPE_SELECTION_EDITOR (gimp_selection_editor_get_type ()) #define GIMP_SELECTION_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SELECTION_EDITOR, GimpSelectionEditor)) diff --git a/app/widgets/gimpundoeditor.c b/app/widgets/gimpundoeditor.c new file mode 100644 index 0000000000..e92a3ede2f --- /dev/null +++ b/app/widgets/gimpundoeditor.c @@ -0,0 +1,422 @@ +/* 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 + +#include "libgimpwidgets/gimpwidgets.h" + +#include "widgets-types.h" + +#include "core/gimp.h" +#include "core/gimplist.h" +#include "core/gimpimage.h" +#include "core/gimpimage-undo.h" +#include "core/gimpundostack.h" + +#include "gimpcontainerlistview.h" +#include "gimpundoeditor.h" + +#include "libgimp/gimpintl.h" + + +static void gimp_undo_editor_class_init (GimpUndoEditorClass *klass); +static void gimp_undo_editor_init (GimpUndoEditor *undo_editor); + +static void gimp_undo_editor_destroy (GtkObject *object); + +static void gimp_undo_editor_undo_clicked (GtkWidget *widget, + GimpUndoEditor *editor); +static void gimp_undo_editor_redo_clicked (GtkWidget *widget, + GimpUndoEditor *editor); + +static void gimp_undo_editor_undo_event (GimpImage *gimage, + GimpUndoEvent event, + GimpUndo *undo, + GimpUndoEditor *editor); + +static void gimp_undo_editor_select_item (GimpContainerView *view, + GimpUndo *undo, + gpointer insert_data, + GimpUndoEditor *editor); + + +static GimpEditorClass *parent_class = NULL; + + +GType +gimp_undo_editor_get_type (void) +{ + static GType editor_type = 0; + + if (! editor_type) + { + static const GTypeInfo editor_info = + { + sizeof (GimpUndoEditorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gimp_undo_editor_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GimpUndoEditor), + 0, /* n_preallocs */ + (GInstanceInitFunc) gimp_undo_editor_init, + }; + + editor_type = g_type_register_static (GIMP_TYPE_EDITOR, + "GimpUndoEditor", + &editor_info, 0); + } + + return editor_type; +} + +static void +gimp_undo_editor_class_init (GimpUndoEditorClass *klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->destroy = gimp_undo_editor_destroy; +} + +static void +gimp_undo_editor_init (GimpUndoEditor *undo_editor) +{ + undo_editor->gimage = NULL; + undo_editor->container = NULL; + + undo_editor->view = gimp_container_list_view_new (NULL, + NULL, + GIMP_PREVIEW_SIZE_MEDIUM, + FALSE, 3, 3); + gtk_box_pack_start (GTK_BOX (undo_editor), undo_editor->view, TRUE, TRUE, 0); + gtk_widget_show (undo_editor->view); + + g_signal_connect (undo_editor->view, "select_item", + G_CALLBACK (gimp_undo_editor_select_item), + undo_editor); + + undo_editor->undo_button = + gimp_editor_add_button (GIMP_EDITOR (undo_editor), + GTK_STOCK_UNDO, + _("Undo"), NULL, + G_CALLBACK (gimp_undo_editor_undo_clicked), + NULL, + undo_editor); + + undo_editor->redo_button = + gimp_editor_add_button (GIMP_EDITOR (undo_editor), + GTK_STOCK_REDO, + _("Redo"), NULL, + G_CALLBACK (gimp_undo_editor_redo_clicked), + NULL, + undo_editor); + + gtk_widget_set_sensitive (GTK_WIDGET (undo_editor), FALSE); +} + +static void +gimp_undo_editor_destroy (GtkObject *object) +{ + GimpUndoEditor *editor; + + editor = GIMP_UNDO_EDITOR (object); + + if (editor->gimage) + gimp_undo_editor_set_image (editor, NULL); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + + +/* public functions */ + +GtkWidget * +gimp_undo_editor_new (GimpImage *gimage) +{ + GimpUndoEditor *editor; + + g_return_val_if_fail (! gimage || GIMP_IS_IMAGE (gimage), NULL); + + editor = g_object_new (GIMP_TYPE_UNDO_EDITOR, NULL); + + gimp_undo_editor_set_image (editor, gimage); + + return GTK_WIDGET (editor); +} + +void +gimp_undo_editor_set_image (GimpUndoEditor *editor, + GimpImage *gimage) +{ + g_return_if_fail (GIMP_IS_UNDO_EDITOR (editor)); + g_return_if_fail (! gimage || GIMP_IS_IMAGE (gimage)); + + if (gimage == editor->gimage) + return; + + if (editor->gimage) + { + gimp_container_view_set_container (GIMP_CONTAINER_VIEW (editor->view), + NULL); + g_object_unref (editor->container); + editor->container = NULL; + + g_object_unref (editor->base_item); + editor->base_item = NULL; + + g_signal_handlers_disconnect_by_func (editor->gimage, + gimp_undo_editor_undo_event, + editor); + } + else if (gimage) + { + gtk_widget_set_sensitive (GTK_WIDGET (editor), TRUE); + } + + editor->gimage = gimage; + + if (gimage) + { + GimpUndo *top_undo_item; + GimpUndo *top_redo_item; + GList *list; + + /* create a container as model for the undo history list */ + editor->container = gimp_list_new (GIMP_TYPE_UNDO, + GIMP_CONTAINER_POLICY_STRONG); + editor->base_item = gimp_undo_new (gimage, + GIMP_UNDO_GROUP_NONE, + _("[ Base Image ]"), + NULL, 0, FALSE, NULL, NULL); + + /* the list prepends its items, so first add the redo items... */ + for (list = GIMP_LIST (gimage->redo_stack->undos)->list; + list; + list = g_list_next (list)) + { + gimp_container_add (editor->container, GIMP_OBJECT (list->data)); + } + + /* ...reverse the list so the redo items are in ascending order... */ + gimp_list_reverse (GIMP_LIST (editor->container)); + + /* ...then add the undo items in descending order... */ + for (list = GIMP_LIST (gimage->undo_stack->undos)->list; + list; + list = g_list_next (list)) + { + gimp_container_add (editor->container, GIMP_OBJECT (list->data)); + } + + /* ...finally, the first item is the special "base_item" which stands + * for the image with no more undos available to pop + */ + gimp_container_add (editor->container, GIMP_OBJECT (editor->base_item)); + + /* display the container */ + gimp_container_view_set_container (GIMP_CONTAINER_VIEW (editor->view), + editor->container); + + /* get the top item of both stacks */ + top_undo_item = gimp_undo_stack_peek (gimage->undo_stack); + top_redo_item = gimp_undo_stack_peek (gimage->redo_stack); + + gtk_widget_set_sensitive (editor->undo_button, top_undo_item != NULL); + gtk_widget_set_sensitive (editor->redo_button, top_redo_item != NULL); + + g_signal_handlers_block_by_func (editor->view, + gimp_undo_editor_select_item, + editor); + + /* select the current state of the image */ + if (top_undo_item) + { + gimp_container_view_select_item (GIMP_CONTAINER_VIEW (editor->view), + GIMP_VIEWABLE (top_undo_item)); + gimp_undo_create_preview (top_undo_item, FALSE); + } + else + { + gimp_container_view_select_item (GIMP_CONTAINER_VIEW (editor->view), + GIMP_VIEWABLE (editor->base_item)); + gimp_undo_create_preview (editor->base_item, TRUE); + } + + g_signal_handlers_unblock_by_func (editor->view, + gimp_undo_editor_select_item, + editor); + + g_signal_connect (gimage, "undo_event", + G_CALLBACK (gimp_undo_editor_undo_event), + editor); + } + else + { + gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE); + } +} + +static void +gimp_undo_editor_undo_clicked (GtkWidget *widget, + GimpUndoEditor *editor) +{ + if (editor->gimage) + { + if (gimp_image_undo (editor->gimage)) + gimp_image_flush (editor->gimage); + } +} + +static void +gimp_undo_editor_redo_clicked (GtkWidget *widget, + GimpUndoEditor *editor) +{ + if (editor->gimage) + { + if (gimp_image_redo (editor->gimage)) + gimp_image_flush (editor->gimage); + } +} + +static void +gimp_undo_editor_undo_event (GimpImage *gimage, + GimpUndoEvent event, + GimpUndo *undo, + GimpUndoEditor *editor) +{ + GimpUndo *top_undo_item; + GimpUndo *top_redo_item; + + top_undo_item = gimp_undo_stack_peek (gimage->undo_stack); + top_redo_item = gimp_undo_stack_peek (gimage->redo_stack); + + g_signal_handlers_block_by_func (editor->view, + gimp_undo_editor_select_item, + editor); + + switch (event) + { + case GIMP_UNDO_EVENT_UNDO_PUSHED: + gimp_container_insert (editor->container, GIMP_OBJECT (undo), -1); + gimp_container_view_select_item (GIMP_CONTAINER_VIEW (editor->view), + GIMP_VIEWABLE (undo)); + gimp_undo_create_preview (undo, FALSE); + break; + + case GIMP_UNDO_EVENT_UNDO_EXPIRED: + case GIMP_UNDO_EVENT_REDO_EXPIRED: + gimp_container_remove (editor->container, GIMP_OBJECT (undo)); + break; + + case GIMP_UNDO_EVENT_UNDO: + if (top_undo_item) + { + gimp_container_view_select_item (GIMP_CONTAINER_VIEW (editor->view), + GIMP_VIEWABLE (top_undo_item)); + gimp_undo_create_preview (top_undo_item, FALSE); + } + else + { + gimp_container_view_select_item (GIMP_CONTAINER_VIEW (editor->view), + GIMP_VIEWABLE (editor->base_item)); + gimp_undo_create_preview (editor->base_item, TRUE); + } + break; + + case GIMP_UNDO_EVENT_REDO: + gimp_container_view_select_item (GIMP_CONTAINER_VIEW (editor->view), + GIMP_VIEWABLE (top_undo_item)); + gimp_undo_create_preview (top_undo_item, FALSE); + break; + + case GIMP_UNDO_EVENT_UNDO_FREE: + gimp_undo_editor_set_image (editor, NULL); + break; + } + + g_signal_handlers_unblock_by_func (editor->view, + gimp_undo_editor_select_item, + editor); + + gtk_widget_set_sensitive (editor->undo_button, top_undo_item != NULL); + gtk_widget_set_sensitive (editor->redo_button, top_redo_item != NULL); +} + +static void +gimp_undo_editor_select_item (GimpContainerView *view, + GimpUndo *undo, + gpointer insert_data, + GimpUndoEditor *editor) +{ + GimpUndo *top_undo_item; + GimpUndo *top_redo_item; + + top_undo_item = gimp_undo_stack_peek (editor->gimage->undo_stack); + + if (undo == editor->base_item) + { + /* the base_image was selected, pop all available undo items + */ + while (top_undo_item != NULL) + { + gimp_image_undo (editor->gimage); + + top_undo_item = gimp_undo_stack_peek (editor->gimage->undo_stack); + } + } + else if (gimp_container_have (editor->gimage->undo_stack->undos, + GIMP_OBJECT (undo))) + { + /* the selected item is on the undo stack, pop undos until it + * is on the of the undo stack + */ + while (top_undo_item != undo) + { + gimp_image_undo (editor->gimage); + + top_undo_item = gimp_undo_stack_peek (editor->gimage->undo_stack); + } + } + else if (gimp_container_have (editor->gimage->redo_stack->undos, + GIMP_OBJECT (undo))) + { + /* the selected item is on the redo stack, pop redos until it + * is on top of the undo stack + */ + while (top_undo_item != undo) + { + gimp_image_redo (editor->gimage); + + top_undo_item = gimp_undo_stack_peek (editor->gimage->undo_stack); + } + } + + gimp_image_flush (editor->gimage); + + top_redo_item = gimp_undo_stack_peek (editor->gimage->redo_stack); + + gtk_widget_set_sensitive (editor->undo_button, top_undo_item != NULL); + gtk_widget_set_sensitive (editor->redo_button, top_redo_item != NULL); +} diff --git a/app/widgets/gimpundoeditor.h b/app/widgets/gimpundoeditor.h new file mode 100644 index 0000000000..8fe8ac4619 --- /dev/null +++ b/app/widgets/gimpundoeditor.h @@ -0,0 +1,64 @@ +/* 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. + */ + +#ifndef __GIMP_UNDO_EDITOR_H__ +#define __GIMP_UNDO_EDITOR_H__ + + +#include "gimpeditor.h" + + +#define GIMP_TYPE_UNDO_EDITOR (gimp_undo_editor_get_type ()) +#define GIMP_UNDO_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_UNDO_EDITOR, GimpUndoEditor)) +#define GIMP_UNDO_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_UNDO_EDITOR, GimpUndoEditorClass)) +#define GIMP_IS_UNDO_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_UNDO_EDITOR)) +#define GIMP_IS_UNDO_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_UNDO_EDITOR)) +#define GIMP_UNDO_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_UNDO_EDITOR, GimpUndoEditorClass)) + + +typedef struct _GimpUndoEditorClass GimpUndoEditorClass; + +struct _GimpUndoEditor +{ + GimpEditor parent_instance; + + GimpImage *gimage; + + GimpContainer *container; + GtkWidget *view; + + GimpUndo *base_item; + + GtkWidget *undo_button; + GtkWidget *redo_button; +}; + +struct _GimpUndoEditorClass +{ + GimpEditorClass parent_class; +}; + + +GType gimp_undo_editor_get_type (void) G_GNUC_CONST; + +GtkWidget * gimp_undo_editor_new (GimpImage *gimage); +void gimp_undo_editor_set_image (GimpUndoEditor *editor, + GimpImage *gimage); + + +#endif /* __GIMP_UNDO_EDITOR_H__ */ diff --git a/app/widgets/gimpundopreview.c b/app/widgets/gimpundopreview.c new file mode 100644 index 0000000000..f285c0fb86 --- /dev/null +++ b/app/widgets/gimpundopreview.c @@ -0,0 +1,161 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpUndoPreview Widget + * Copyright (C) 2001 Michael Natterer + * + * 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 + +#include "widgets-types.h" + +#include "base/temp-buf.h" + +#include "core/gimpundo.h" + +#include "gimpundopreview.h" + + +static void gimp_undo_preview_class_init (GimpUndoPreviewClass *klass); +static void gimp_undo_preview_init (GimpUndoPreview *preview); + +static void gimp_undo_preview_render (GimpPreview *preview); + + +static GimpPreviewClass *parent_class = NULL; + + +GType +gimp_undo_preview_get_type (void) +{ + static GType preview_type = 0; + + if (! preview_type) + { + static const GTypeInfo preview_info = + { + sizeof (GimpUndoPreviewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gimp_undo_preview_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GimpUndoPreview), + 0, /* n_preallocs */ + (GInstanceInitFunc) gimp_undo_preview_init, + }; + + preview_type = g_type_register_static (GIMP_TYPE_PREVIEW, + "GimpUndoPreview", + &preview_info, 0); + } + + return preview_type; +} + +static void +gimp_undo_preview_class_init (GimpUndoPreviewClass *klass) +{ + GimpPreviewClass *preview_class; + + preview_class = GIMP_PREVIEW_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + preview_class->render = gimp_undo_preview_render; +} + +static void +gimp_undo_preview_init (GimpUndoPreview *preview) +{ +} + +static void +gimp_undo_preview_render (GimpPreview *preview) +{ + GimpUndo *undo; + gint width; + gint height; + gint preview_width; + gint preview_height; + gboolean scaling_up; + TempBuf *render_buf; + gboolean free_buf = FALSE; + + undo = GIMP_UNDO (preview->viewable); + + width = preview->width; + height = preview->height; + + render_buf = gimp_viewable_get_preview (preview->viewable, width, height); + + if (! render_buf) + return; + + gimp_preview_calc_size (preview, + render_buf->width, + render_buf->height, + width, + height, + 1.0, 1.0, + &preview_width, + &preview_height, + &scaling_up); + + if (preview_width != render_buf->width || + preview_height != render_buf->height) + { + render_buf = temp_buf_scale (render_buf, preview_width, preview_height); + + free_buf = TRUE; + } + + if (preview_width < width) render_buf->x = (width - preview_width) / 2; + if (preview_height < height) render_buf->y = (height - preview_height) / 2; + + if (render_buf->x || render_buf->y) + { + TempBuf *temp_buf; + guchar white[4] = { 255, 255, 255, 255 }; + + temp_buf = temp_buf_new (width, height, + render_buf->bytes, + 0, 0, + white); + + temp_buf_copy_area (render_buf, temp_buf, + 0, 0, + render_buf->width, + render_buf->height, + render_buf->x, + render_buf->y); + + if (free_buf) + temp_buf_free (render_buf); + + render_buf = temp_buf; + + free_buf = TRUE; + } + + gimp_preview_render_and_flush (preview, render_buf, -1); + + if (free_buf) + temp_buf_free (render_buf); +} diff --git a/app/widgets/gimpundopreview.h b/app/widgets/gimpundopreview.h new file mode 100644 index 0000000000..fe44e13455 --- /dev/null +++ b/app/widgets/gimpundopreview.h @@ -0,0 +1,51 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpUndoPreview Widget + * Copyright (C) 2001 Michael Natterer + * + * 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_UNDO_PREVIEW_H__ +#define __GIMP_UNDO_PREVIEW_H__ + +#include "gimppreview.h" + +#define GIMP_TYPE_UNDO_PREVIEW (gimp_undo_preview_get_type ()) +#define GIMP_UNDO_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_UNDO_PREVIEW, GimpUndoPreview)) +#define GIMP_UNDO_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_UNDO_PREVIEW, GimpUndoPreviewClass)) +#define GIMP_IS_UNDO_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_UNDO_PREVIEW)) +#define GIMP_IS_UNDO_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_UNDO_PREVIEW)) +#define GIMP_UNDO_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_UNDO_PREVIEW, GimpUndoPreviewClass)) + + +typedef struct _GimpUndoPreviewClass GimpUndoPreviewClass; + +struct _GimpUndoPreview +{ + GimpPreview parent_instance; +}; + +struct _GimpUndoPreviewClass +{ + GimpPreviewClass parent_class; +}; + + +GType gimp_undo_preview_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_UNDO_PREVIEW_H__ */ diff --git a/app/widgets/gimpview.c b/app/widgets/gimpview.c index 0ffb0e2745..184efe42f5 100644 --- a/app/widgets/gimpview.c +++ b/app/widgets/gimpview.c @@ -630,17 +630,28 @@ gimp_preview_set_viewable (GimpPreview *preview, g_signal_handlers_disconnect_by_func (preview->viewable, G_CALLBACK (gimp_preview_size_changed), preview); + + if (! viewable && ! preview->is_popup) + { + if (gimp_dnd_viewable_source_unset (GTK_WIDGET (preview), + G_TYPE_FROM_INSTANCE (preview->viewable))) + { + gtk_drag_source_unset (GTK_WIDGET (preview)); + } + } } else if (viewable && ! preview->is_popup) { - gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), - GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + if (gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), + GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + viewable_type, + GDK_ACTION_COPY)) + { + gimp_dnd_viewable_source_set (GTK_WIDGET (preview), viewable_type, - GDK_ACTION_COPY); - gimp_dnd_viewable_source_set (GTK_WIDGET (preview), - viewable_type, - gimp_preview_drag_viewable, - NULL); + gimp_preview_drag_viewable, + NULL); + } } preview->viewable = viewable; diff --git a/app/widgets/gimpviewrenderer.c b/app/widgets/gimpviewrenderer.c index 0ffb0e2745..184efe42f5 100644 --- a/app/widgets/gimpviewrenderer.c +++ b/app/widgets/gimpviewrenderer.c @@ -630,17 +630,28 @@ gimp_preview_set_viewable (GimpPreview *preview, g_signal_handlers_disconnect_by_func (preview->viewable, G_CALLBACK (gimp_preview_size_changed), preview); + + if (! viewable && ! preview->is_popup) + { + if (gimp_dnd_viewable_source_unset (GTK_WIDGET (preview), + G_TYPE_FROM_INSTANCE (preview->viewable))) + { + gtk_drag_source_unset (GTK_WIDGET (preview)); + } + } } else if (viewable && ! preview->is_popup) { - gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), - GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + if (gimp_dnd_drag_source_set_by_type (GTK_WIDGET (preview), + GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + viewable_type, + GDK_ACTION_COPY)) + { + gimp_dnd_viewable_source_set (GTK_WIDGET (preview), viewable_type, - GDK_ACTION_COPY); - gimp_dnd_viewable_source_set (GTK_WIDGET (preview), - viewable_type, - gimp_preview_drag_viewable, - NULL); + gimp_preview_drag_viewable, + NULL); + } } preview->viewable = viewable; diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h index f1c4d10512..cfc5294dc4 100644 --- a/app/widgets/widgets-types.h +++ b/app/widgets/widgets-types.h @@ -38,16 +38,17 @@ typedef struct _GimpMenuFactory GimpMenuFactory; /* widgets */ typedef struct _GimpPreview GimpPreview; -typedef struct _GimpImagePreview GimpImagePreview; -typedef struct _GimpDrawablePreview GimpDrawablePreview; -typedef struct _GimpImagefilePreview GimpImagefilePreview; typedef struct _GimpBrushPreview GimpBrushPreview; -typedef struct _GimpNavigationPreview GimpNavigationPreview; -typedef struct _GimpPatternPreview GimpPatternPreview; -typedef struct _GimpPalettePreview GimpPalettePreview; -typedef struct _GimpGradientPreview GimpGradientPreview; -typedef struct _GimpToolInfoPreview GimpToolInfoPreview; typedef struct _GimpBufferPreview GimpBufferPreview; +typedef struct _GimpDrawablePreview GimpDrawablePreview; +typedef struct _GimpGradientPreview GimpGradientPreview; +typedef struct _GimpImagePreview GimpImagePreview; +typedef struct _GimpImagefilePreview GimpImagefilePreview; +typedef struct _GimpNavigationPreview GimpNavigationPreview; +typedef struct _GimpPalettePreview GimpPalettePreview; +typedef struct _GimpPatternPreview GimpPatternPreview; +typedef struct _GimpToolInfoPreview GimpToolInfoPreview; +typedef struct _GimpUndoPreview GimpUndoPreview; typedef struct _GimpContainerMenu GimpContainerMenu; typedef struct _GimpContainerMenuImpl GimpContainerMenuImpl; @@ -63,6 +64,7 @@ typedef struct _GimpBrushEditor GimpBrushEditor; typedef struct _GimpGradientEditor GimpGradientEditor; typedef struct _GimpPaletteEditor GimpPaletteEditor; typedef struct _GimpSelectionEditor GimpSelectionEditor; +typedef struct _GimpUndoEditor GimpUndoEditor; typedef struct _GimpContainerView GimpContainerView; typedef struct _GimpContainerListView GimpContainerListView;