Index: gtk/gtkexpander.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkexpander.c,v
retrieving revision 1.20
diff -u -p -r1.20 gtkexpander.c
--- gtk/gtkexpander.c	26 Mar 2005 05:49:14 -0000	1.20
+++ gtk/gtkexpander.c	13 Oct 2005 20:59:03 -0000
@@ -32,6 +32,7 @@
 #include "gtkintl.h"
 #include "gtkprivate.h"
 #include <gdk/gdkkeysyms.h>
+#include <gdk/x11/gdkx.h>
 #include "gtkalias.h"
 
 #define GTK_EXPANDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_EXPANDER, GtkExpanderPrivate))
@@ -59,6 +60,14 @@ struct _GtkExpanderPrivate
   GtkExpanderStyle  expander_style;
   guint             animation_timeout;
 
+  gint expand_height;
+  gint expand_width;
+  gint expand_total_height;
+  gint expand_total_width;
+  GdkPixmap *expand_pixmap;
+  
+  gint top_height;
+  
   guint             expanded : 1;
   guint             use_underline : 1;
   guint             use_markup : 1; 
@@ -491,6 +500,11 @@ gtk_expander_size_request (GtkWidget    
       requisition->width = MAX (requisition->width, child_requisition.width);
       requisition->height += child_requisition.height + priv->spacing;
     }
+  else if (priv->expand_pixmap)
+    {
+      requisition->height += priv->expand_height + priv->spacing;
+      requisition->width = MAX (requisition->width, priv->expand_width);
+    }
 
   requisition->width  += 2 * border_width;
   requisition->height += 2 * border_width;
@@ -580,6 +594,7 @@ gtk_expander_size_allocate (GtkWidget   
   gint focus_width;
   gint focus_pad;
   gint label_height;
+  gint top_height;
 
   expander = GTK_EXPANDER (widget);
   bin = GTK_BIN (widget);
@@ -659,14 +674,15 @@ gtk_expander_size_allocate (GtkWidget   
 			      MAX (allocation->width - 2 * border_width, 1), rect.width);
     }
 
+
+  top_height = MAX (2 * expander_spacing + expander_size,
+		    label_height +
+		    (interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
+  priv->top_height = top_height;
+  
   if (child_visible)
     {
       GtkAllocation child_allocation;
-      gint top_height;
-
-      top_height = MAX (2 * expander_spacing + expander_size,
-			label_height +
-			(interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
 
       child_allocation.x = widget->allocation.x + border_width;
       child_allocation.y = widget->allocation.y + border_width + top_height + priv->spacing;
@@ -853,18 +869,48 @@ static gboolean
 gtk_expander_expose (GtkWidget      *widget,
 		     GdkEventExpose *event)
 {
-  if (GTK_WIDGET_DRAWABLE (widget))
+
+  if (GTK_WIDGET_DRAWABLE (widget) && event->window == widget->window)
     {
       GtkExpander *expander = GTK_EXPANDER (widget);
+      GtkExpanderPrivate *priv;
+      gint border_width;
 
+      priv = expander->priv;
+  
       gtk_expander_paint (expander);
 
       if (GTK_WIDGET_HAS_FOCUS (expander))
 	gtk_expander_paint_focus (expander, &event->area);
 
+      if (priv->expand_pixmap)
+	{
+	  gint x, y;
+	  cairo_t *cr;
+	  
+	  border_width = GTK_CONTAINER (widget)->border_width;
+
+	  x = widget->allocation.x + border_width;
+	  y = widget->allocation.y + border_width + priv->top_height + priv->spacing;
+
+	  cr = gdk_cairo_create (widget->window);
+	  cairo_translate (cr, x, y);
+	  cairo_scale (cr,
+		       (double) priv->expand_width / priv->expand_total_width,
+		       (double) priv->expand_height / priv->expand_total_height);
+	  gdk_cairo_set_source_pixmap (cr, priv->expand_pixmap, 0, 0);
+	  cairo_paint (cr);
+	  cairo_destroy (cr);
+	}
+      
       GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
     }
-
+  else if (gdk_window_is_offscreen (event->window))
+    {
+      GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+    }
+    
+  
   return FALSE;
 }
 
@@ -1222,6 +1268,7 @@ gtk_expander_animation_timeout (GtkExpan
 {
   GtkExpanderPrivate *priv = expander->priv;
   GdkRectangle area;
+  gboolean change_visibility = FALSE;
   gboolean finish = FALSE;
 
   GDK_THREADS_ENTER();
@@ -1238,9 +1285,22 @@ gtk_expander_animation_timeout (GtkExpan
 	{
 	  priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
 	}
+      else if (priv->expand_height < priv->expand_total_height ||
+	       priv->expand_width < priv->expand_total_width)
+	{
+	  priv->expand_height += 15;
+	  priv->expand_height = MIN (priv->expand_height, priv->expand_total_height);
+	  
+	  priv->expand_width += 15;
+	  priv->expand_width = MIN (priv->expand_width, priv->expand_total_width);
+	  
+	  //gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, NULL, FALSE);
+	  gtk_widget_queue_resize (GTK_WIDGET (expander));
+	}
       else
 	{
 	  priv->expander_style = GTK_EXPANDER_EXPANDED;
+	  change_visibility = TRUE;
 	  finish = TRUE;
 	}
     }
@@ -1250,6 +1310,16 @@ gtk_expander_animation_timeout (GtkExpan
 	{
 	  priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
 	}
+      else if (priv->expand_height > 0)
+	{
+	  priv->expand_height -= 15;
+	  if (priv->expand_height <= 0)
+	    priv->expand_height = 0;
+	  
+	  //gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, NULL, FALSE);
+	  gtk_widget_queue_resize (GTK_WIDGET (expander));
+	  change_visibility = TRUE;
+	}
       else
 	{
 	  priv->expander_style = GTK_EXPANDER_COLLAPSED;
@@ -1257,13 +1327,21 @@ gtk_expander_animation_timeout (GtkExpan
 	}
     }
 
-  if (finish)
+  if (change_visibility)
     {
-      priv->animation_timeout = 0;
       if (GTK_BIN (expander)->child)
 	gtk_widget_set_child_visible (GTK_BIN (expander)->child, priv->expanded);
       gtk_widget_queue_resize (GTK_WIDGET (expander));
     }
+  if (finish)
+    {
+      if (priv->expand_pixmap != NULL)
+	{
+	  g_object_unref (priv->expand_pixmap);
+	  priv->expand_pixmap = NULL;
+	}
+      priv->animation_timeout = 0;
+    }
 
   GDK_THREADS_LEAVE();
 
@@ -1274,10 +1352,92 @@ static void
 gtk_expander_start_animation (GtkExpander *expander)
 {
   GtkExpanderPrivate *priv = expander->priv;
+  GtkWidget *widget;
+  GtkBin *bin;
 
   if (priv->animation_timeout)
     g_source_remove (priv->animation_timeout);
 
+  widget = GTK_WIDGET (expander);
+  bin = GTK_BIN (expander);
+  if (bin->child)
+    {
+      gint border_width;
+
+      border_width = GTK_CONTAINER (widget)->border_width;
+	  
+      if (priv->expanded)
+	{
+	  GtkRequisition child_requisition;
+	  GtkAllocation child_allocation;
+	  GdkWindow *offscreen_window;
+	  GdkWindowAttr attributes;
+	  gint attributes_mask;
+	  
+	  gtk_widget_size_request (bin->child, &child_requisition);
+
+	  priv->expand_total_width = MAX (child_requisition.width,
+					  widget->allocation.width - 2 * border_width);
+	  priv->expand_total_height = child_requisition.height;
+	  priv->expand_height = 0;
+	  priv->expand_width = widget->allocation.width - 2 * border_width;
+	  
+	  gtk_widget_unrealize (bin->child);
+	      
+	  attributes.window_type = GDK_WINDOW_CHILD;
+	  attributes.x = 0;
+	  attributes.y = 0;
+	  attributes.width = child_requisition.width;
+	  attributes.height = child_requisition.height;
+	  attributes.wclass = GDK_INPUT_OUTPUT;
+	  attributes.event_mask =
+	    gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+	  attributes.visual = gtk_widget_get_visual (widget);
+	  attributes.colormap = gtk_widget_get_colormap (widget);
+
+	  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+	  
+	  offscreen_window = gdk_window_new_offscreen (widget->window, &attributes,
+						       attributes_mask);
+	  gdk_window_set_user_data (offscreen_window, widget);
+	  gdk_window_show (offscreen_window);
+	  
+	  gtk_widget_set_parent_window (bin->child,
+					offscreen_window);
+	  
+	  child_allocation.x = 0;
+	  child_allocation.y = 0;
+	  child_allocation.width = priv->expand_total_width;
+	  child_allocation.height = priv->expand_total_height;
+	  gtk_widget_size_allocate (bin->child, &child_allocation);
+
+	  gtk_widget_set_child_visible (bin->child, TRUE);
+	  gtk_widget_show (bin->child);
+	  
+	  gdk_window_invalidate_rect (offscreen_window, NULL, TRUE);
+	  gdk_window_process_updates (offscreen_window, TRUE);
+
+	  priv->expand_pixmap = gdk_window_get_offscreen_pixmap (offscreen_window);
+	  g_object_ref (priv->expand_pixmap);
+	  
+	  gtk_widget_hide (bin->child);
+	  gtk_widget_set_child_visible (bin->child, FALSE);
+	  gtk_widget_unrealize (bin->child);
+	  gtk_widget_set_parent_window (bin->child, widget->window);
+	  gtk_widget_show (bin->child);
+	  
+	  gdk_window_destroy (offscreen_window);
+	}
+      else
+	{
+	  priv->expand_pixmap = gtk_widget_get_snapshot (bin->child);
+	  priv->expand_total_height = bin->child->allocation.height;
+	  priv->expand_total_width = widget->allocation.height - 2 * border_width;
+	  priv->expand_height = priv->expand_total_height;
+	  priv->expand_width = priv->expand_total_width;
+	}
+    }
+  
   priv->animation_timeout =
 		g_timeout_add (50,
 			       (GSourceFunc) gtk_expander_animation_timeout,
