? text-undo.diff
Index: app/core/gimpimage-undo-push.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-undo-push.c,v
retrieving revision 1.219
diff -u -p -r1.219 gimpimage-undo-push.c
--- app/core/gimpimage-undo-push.c	20 Mar 2004 20:10:05 -0000	1.219
+++ app/core/gimpimage-undo-push.c	21 Mar 2004 20:35:04 -0000
@@ -49,8 +49,7 @@
 #include "gimplist.h"
 #include "gimpparasitelist.h"
 
-#include "text/gimptext.h"
-#include "text/gimptextlayer.h"
+#include "text/gimptextundo.h"
 
 #include "vectors/gimpvectors.h"
 
@@ -1737,22 +1736,6 @@ undo_free_layer_properties (GimpUndo    
 /*  Text Layer Undo  */
 /*********************/
 
-typedef struct _TextUndo TextUndo;
-
-struct _TextUndo
-{
-  GimpText         *text;
-  const GParamSpec *pspec;
-  GValue           *value;
-};
-
-static gboolean undo_pop_text_layer  (GimpUndo            *undo,
-                                      GimpUndoMode         undo_mode,
-                                      GimpUndoAccumulator *accum);
-static void     undo_free_text_layer (GimpUndo            *undo,
-                                      GimpUndoMode         undo_mode);
-
-
 gboolean
 gimp_image_undo_push_text_layer (GimpImage        *gimage,
                                  const gchar      *undo_desc,
@@ -1760,131 +1743,21 @@ gimp_image_undo_push_text_layer (GimpIma
                                  const GParamSpec *pspec)
 {
   GimpUndo *undo;
-  gssize    size;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
-  g_return_val_if_fail (GIMP_IS_TEXT_LAYER (layer), FALSE);
-  g_return_val_if_fail (pspec == NULL || pspec->owner_type == GIMP_TYPE_TEXT,
-                        FALSE);
-  g_return_val_if_fail (pspec == NULL || layer->text != NULL, FALSE);
-
-  size = sizeof (TextUndo);
-
-  if (pspec)
-    {
-      /*  this is incorrect, but how can it be done better?  */
-      size += sizeof (GValue);
-    }
-  else if (layer->text)
-    {
-      size += gimp_object_get_memsize (GIMP_OBJECT (layer->text), NULL);
-    }
-
-  undo = gimp_image_undo_push_item (gimage, GIMP_ITEM (layer),
-                                    size, sizeof (TextUndo),
-                                    GIMP_UNDO_TEXT_LAYER, undo_desc,
-                                    TRUE,
-                                    undo_pop_text_layer,
-                                    undo_free_text_layer);
-
-  if (undo)
-    {
-      TextUndo *tu = undo->data;
-
-      if (pspec)
-        {
-          tu->pspec = pspec;
-          tu->value = g_new0 (GValue, 1);
-
-          g_value_init (tu->value, pspec->value_type);
-          g_object_get_property (G_OBJECT (layer->text),
-                                 pspec->name, tu->value);
-        }
-      else if (layer->text)
-        {
-          tu->text = gimp_config_duplicate (GIMP_CONFIG (layer->text));
-        }
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
 
-static gboolean
-undo_pop_text_layer (GimpUndo            *undo,
-                     GimpUndoMode         undo_mode,
-                     GimpUndoAccumulator *accum)
-{
-  TextUndo      *tu    = undo->data;
-  GimpTextLayer *layer = GIMP_TEXT_LAYER (GIMP_ITEM_UNDO (undo)->item);
-
-  if (tu->pspec)
-    {
-      GValue *value;
-
-      g_return_val_if_fail (layer->text != NULL, FALSE);
-
-      value = g_new0 (GValue, 1);
-      g_value_init (value, tu->pspec->value_type);
-
-      g_object_get_property (G_OBJECT (layer->text),
-                             tu->pspec->name, value);
-
-      g_object_set_property (G_OBJECT (layer->text),
-                             tu->pspec->name, tu->value);
-
-      g_value_unset (tu->value);
-      g_free (tu->value);
-
-      tu->value = value;
-    }
-  else
-    {
-      GimpText *text;
-
-      if (tu->text)
-        undo->size -= gimp_object_get_memsize (GIMP_OBJECT (tu->text), NULL);
+  gimp_image_dirty (gimage);
 
-      text = (layer->text ?
-              gimp_config_duplicate (GIMP_CONFIG (layer->text)) : NULL);
-
-      if (layer->text && tu->text)
-        gimp_config_sync (GIMP_CONFIG (tu->text),
-                          GIMP_CONFIG (layer->text), 0);
-      else
-        gimp_text_layer_set_text (layer, tu->text);
-
-      if (tu->text)
-        g_object_unref (tu->text);
+  if (gimage->undo_freeze_count > 0)
+    return FALSE;
 
-      tu->text = text;
+  undo = gimp_text_undo_new (layer, pspec, undo_desc);
 
-      if (tu->text)
-        undo->size += gimp_object_get_memsize (GIMP_OBJECT (tu->text), NULL);
-    }
+  gimp_image_undo_push_undo (gimage, undo);
 
   return TRUE;
 }
 
-static void
-undo_free_text_layer (GimpUndo     *undo,
-                      GimpUndoMode  undo_mode)
-{
-  TextUndo *tu = undo->data;
-
-  if (tu->text)
-    g_object_unref (tu->text);
-
-  if (tu->pspec)
-    {
-      g_value_unset (tu->value);
-      g_free (tu->value);
-    }
-
-  g_free (tu);
-}
-
 
 /*****************************/
 /*  Add/Remove Channel Undo  */
Index: app/core/gimpimage-undo.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-undo.c,v
retrieving revision 1.14
diff -u -p -r1.14 gimpimage-undo.c
--- app/core/gimpimage-undo.c	14 Mar 2004 23:19:45 -0000	1.14
+++ app/core/gimpimage-undo.c	21 Mar 2004 20:35:04 -0000
@@ -210,16 +210,13 @@ gimp_image_undo_push_item (GimpImage    
                            GimpUndoPopFunc   pop_func,
                            GimpUndoFreeFunc  free_func)
 {
-  GimpUndo *new;
+  GimpUndo *undo;
   gpointer  undo_struct = NULL;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
   g_return_val_if_fail (item == NULL || GIMP_IS_ITEM (item), NULL);
   g_return_val_if_fail (type > GIMP_UNDO_GROUP_LAST, NULL);
 
-  if (! name)
-    name = gimp_image_undo_type_to_name (type);
-
   /* Does this undo dirty the image?  If so, we always want to mark
    * image dirty, even if we can't actually push the undo.
    */
@@ -229,6 +226,43 @@ gimp_image_undo_push_item (GimpImage    
   if (gimage->undo_freeze_count > 0)
     return NULL;
 
+  if (! name)
+    name = gimp_image_undo_type_to_name (type);
+
+  if (struct_size > 0)
+    undo_struct = g_malloc0 (struct_size);
+
+  if (item)
+    {
+      undo = gimp_item_undo_new (gimage, item,
+                                 type, name,
+                                 undo_struct, size,
+                                 dirties_image,
+                                 pop_func, free_func);
+    }
+  else
+    {
+      undo = gimp_undo_new (gimage,
+                            type, name,
+                            undo_struct, size,
+                            dirties_image,
+                            pop_func, free_func);
+    }
+
+  gimp_image_undo_push_undo (gimage, undo);
+
+  return undo;
+}
+
+void
+gimp_image_undo_push_undo (GimpImage *gimage,
+                           GimpUndo  *undo)
+{
+  g_return_if_fail (GIMP_IS_IMAGE (gimage));
+  g_return_if_fail (GIMP_IS_UNDO (undo));
+  g_return_if_fail (undo->gimage == gimage);
+  g_return_if_fail (gimage->undo_freeze_count == 0);
+
   /*  nuke the redo stack  */
   gimp_image_undo_free_redo (gimage);
 
@@ -241,33 +275,13 @@ gimp_image_undo_push_item (GimpImage    
   if (gimage->dirty < 0)
     gimage->dirty = 10000;
 
-  if (struct_size > 0)
-    undo_struct = g_malloc0 (struct_size);
-
-  if (item)
-    {
-      new = gimp_item_undo_new (gimage, item,
-                                type, name,
-                                undo_struct, size,
-                                dirties_image,
-                                pop_func, free_func);
-    }
-  else
-    {
-      new = gimp_undo_new (gimage,
-                           type, name,
-                           undo_struct, size,
-                           dirties_image,
-                           pop_func, free_func);
-    }
-
   if (gimage->pushing_undo_group == GIMP_UNDO_GROUP_NONE)
     {
-      gimp_undo_stack_push_undo (gimage->undo_stack, new);
+      gimp_undo_stack_push_undo (gimage->undo_stack, undo);
 
       gimp_image_undo_free_space (gimage);
 
-      gimp_image_undo_event (gimage, GIMP_UNDO_EVENT_UNDO_PUSHED, new);
+      gimp_image_undo_event (gimage, GIMP_UNDO_EVENT_UNDO_PUSHED, undo);
     }
   else
     {
@@ -275,10 +289,8 @@ gimp_image_undo_push_item (GimpImage    
 
       undo_group = GIMP_UNDO_STACK (gimp_undo_stack_peek (gimage->undo_stack));
 
-      gimp_undo_stack_push_undo (undo_group, new);
+      gimp_undo_stack_push_undo (undo_group, undo);
     }
-
-  return new;
 }
 
 
Index: app/core/gimpimage-undo.h
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-undo.h,v
retrieving revision 1.4
diff -u -p -r1.4 gimpimage-undo.h
--- app/core/gimpimage-undo.h	16 Nov 2003 17:51:23 -0000	1.4
+++ app/core/gimpimage-undo.h	21 Mar 2004 20:35:04 -0000
@@ -47,6 +47,8 @@ GimpUndo * gimp_image_undo_push_item   (
                                         gboolean          dirties_image,
                                         GimpUndoPopFunc   pop_func,
                                         GimpUndoFreeFunc  free_func);
+void       gimp_image_undo_push_undo   (GimpImage        *gimage,
+                                        GimpUndo         *undo);
 
 
 #endif /* __GIMP_IMAGE_UNDO_H__ */
Index: app/text/Makefile.am
===================================================================
RCS file: /cvs/gnome/gimp/app/text/Makefile.am,v
retrieving revision 1.20
diff -u -p -r1.20 Makefile.am
--- app/text/Makefile.am	9 Feb 2004 09:11:08 -0000	1.20
+++ app/text/Makefile.am	21 Mar 2004 20:35:04 -0000
@@ -45,7 +45,9 @@ libapptext_a_sources = \
 	gimptextlayout.c		\
 	gimptextlayout.h		\
 	gimptextlayout-render.c		\
-	gimptextlayout-render.h
+	gimptextlayout-render.h		\
+	gimptextundo.c			\
+	gimptextundo.h
 
 libapptext_a_built_sources = text-enums.c
 
Index: app/text/text-types.h
===================================================================
RCS file: /cvs/gnome/gimp/app/text/text-types.h,v
retrieving revision 1.5
diff -u -p -r1.5 text-types.h
--- app/text/text-types.h	25 Mar 2003 22:00:59 -0000	1.5
+++ app/text/text-types.h	21 Mar 2004 20:35:04 -0000
@@ -32,6 +32,7 @@ typedef struct _GimpFontList   GimpFontL
 typedef struct _GimpText       GimpText;
 typedef struct _GimpTextLayer  GimpTextLayer;
 typedef struct _GimpTextLayout GimpTextLayout;
+typedef struct _GimpTextUndo   GimpTextUndo;
 
 
 #endif /* __TEXT_TYPES_H__ */
Index: app/tools/gimptexttool.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimptexttool.c,v
retrieving revision 1.228
diff -u -p -r1.228 gimptexttool.c
--- app/tools/gimptexttool.c	20 Mar 2004 20:10:04 -0000	1.228
+++ app/tools/gimptexttool.c	21 Mar 2004 20:35:05 -0000
@@ -37,6 +37,8 @@
 #include "core/gimpimage-undo-push.h"
 #include "core/gimplayer-floating-sel.h"
 #include "core/gimptoolinfo.h"
+#include "core/gimpundo.h"
+#include "core/gimpundostack.h"
 
 #include "config/gimpconfig.h"
 #include "config/gimpconfig-utils.h"
@@ -44,6 +46,7 @@
 #include "text/gimptext.h"
 #include "text/gimptext-vectors.h"
 #include "text/gimptextlayer.h"
+#include "text/gimptextundo.h"
 
 #include "widgets/gimpdialogfactory.h"
 #include "widgets/gimphelp-ids.h"
@@ -59,6 +62,9 @@
 #include "gimp-intl.h"
 
 
+#define TEXT_UNDO_TIMEOUT 3
+
+
 /*  local function prototypes  */
 
 static void      gimp_text_tool_class_init     (GimpTextToolClass *klass);
@@ -485,7 +491,8 @@ gimp_text_tool_apply (GimpTextTool *text
   GObject          *src;
   GObject          *dest;
   GList            *list;
-  gboolean          undo_group;
+  gboolean          push_undo  = TRUE;
+  gboolean          undo_group = FALSE;
 
   if (text_tool->idle_id)
     {
@@ -512,20 +519,50 @@ gimp_text_tool_apply (GimpTextTool *text
   if (g_list_length (list) == 1)
     pspec = list->data;
 
-  gimp_tool_control_set_preserve (GIMP_TOOL (text_tool)->control, TRUE);
+  if (pspec)
+    {
+      GimpUndo *undo = gimp_undo_stack_peek (image->undo_stack);
 
-  /*  If the layer contains a mask,
-   *  gimp_text_layer_render() might have to resize it.
-   */
-  undo_group = ((text_tool->layer->mask != NULL) || text_layer->modified);
-  if (undo_group)
-    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, NULL);
-
-  if (text_layer->modified)
-    gimp_image_undo_push_drawable_mod (image, NULL,
-                                       GIMP_DRAWABLE (text_layer));
+      /*  If we are changing a single property, we might not have to
+       *  push an undo at all.
+       */
+      if (GIMP_IS_TEXT_UNDO (undo) &&
+          !gimp_undo_stack_peek (image->redo_stack))
+        {
+          GimpTextUndo *text_undo = GIMP_TEXT_UNDO (undo);
+
+          if (text_undo->pspec == pspec)
+            {
+              guint now = time (NULL);
+
+              if (now >= text_undo->time &&
+                  now - text_undo->time < TEXT_UNDO_TIMEOUT)
+                {
+                  push_undo = FALSE;
+                  text_undo->time = now;
+                  gimp_undo_refresh_preview (undo);
+                }
+            }
+        }
+    }
 
-  gimp_image_undo_push_text_layer (image, NULL, text_layer, pspec);
+  if (push_undo)
+    {
+      gimp_tool_control_set_preserve (GIMP_TOOL (text_tool)->control, TRUE);
+
+      /*  If the layer contains a mask,
+       *  gimp_text_layer_render() might have to resize it.
+       */
+      undo_group = ((text_tool->layer->mask != NULL) || text_layer->modified);
+      if (undo_group)
+        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, NULL);
+
+      if (text_layer->modified)
+        gimp_image_undo_push_drawable_mod (image, NULL,
+                                           GIMP_DRAWABLE (text_layer));
+
+      gimp_image_undo_push_text_layer (image, NULL, text_layer, pspec);
+    }
 
   src  = G_OBJECT (text_tool->proxy);
   dest = G_OBJECT (text_tool->text);
@@ -561,12 +598,15 @@ gimp_text_tool_apply (GimpTextTool *text
   g_signal_handlers_unblock_by_func (dest,
                                      gimp_text_tool_text_notify, text_tool);
 
-  if (undo_group)
-    gimp_image_undo_group_end (image);
+  if (push_undo)
+    {
+      if (undo_group)
+        gimp_image_undo_group_end (image);
 
-  gimp_tool_control_set_preserve (GIMP_TOOL (text_tool)->control, FALSE);
+      gimp_tool_control_set_preserve (GIMP_TOOL (text_tool)->control, FALSE);
+    }
 
-  gimp_image_flush (gimp_item_get_image (GIMP_ITEM (text_tool->layer)));
+  gimp_image_flush (image);
 }
 
 static void
