Index: gtkhscale.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkhscale.c,v
retrieving revision 1.43
diff -u -p -r1.43 gtkhscale.c
--- gtkhscale.c	4 Oct 2002 22:49:28 -0000	1.43
+++ gtkhscale.c	22 Jul 2003 08:35:13 -0000
@@ -37,6 +37,14 @@ static void     gtk_hscale_init         
 static gboolean gtk_hscale_expose           (GtkWidget      *widget,
                                              GdkEventExpose *event);
 
+static void     gtk_hscale_get_layout_offsets (GtkScale       *scale,
+                                               gint           *x,
+                                               gint           *y);
+static gboolean gtk_hscale_do_get_offsets   (GtkWidget      *widget,
+                                             PangoLayout    *layout,
+                                             gint           *x,
+                                             gint           *y);
+
 GType
 gtk_hscale_get_type (void)
 {
@@ -69,13 +77,17 @@ gtk_hscale_class_init (GtkHScaleClass *c
 {
   GtkWidgetClass *widget_class;
   GtkRangeClass *range_class;
+  GtkScaleClass *scale_class;
   
   widget_class = GTK_WIDGET_CLASS (class);
   range_class = GTK_RANGE_CLASS (class);
+  scale_class = GTK_SCALE_CLASS (class);
 
   parent_class = g_type_class_peek_parent (class);
 
   range_class->slider_detail = "hscale";
+
+  scale_class->get_layout_offsets = gtk_hscale_get_layout_offsets;
   
   widget_class->expose_event = gtk_hscale_expose;
 }
@@ -145,13 +157,9 @@ static gboolean
 gtk_hscale_expose (GtkWidget      *widget,
                    GdkEventExpose *event)
 {
-  GtkRange *range;
-  GtkHScale *hscale;
   GtkScale *scale;
   
-  range = GTK_RANGE (widget);
   scale = GTK_SCALE (widget);
-  hscale = GTK_HSCALE (widget);
 
   /* We need to chain up _first_ so the various geometry members of
    * GtkRange struct are updated.
@@ -162,58 +170,12 @@ gtk_hscale_expose (GtkWidget      *widge
   if (scale->draw_value)
     {
       PangoLayout *layout;
-      PangoRectangle logical_rect;
-      gchar *txt;
       gint x, y;
       GtkStateType state_type;
-      gint value_spacing;
 
-      gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
-      
-      txt = _gtk_scale_format_value (scale,
-                                     GTK_RANGE (scale)->adjustment->value);
-      
-      layout = gtk_widget_create_pango_layout (widget, txt);
-      g_free (txt);
-      
-      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-      
-      switch (scale->value_pos)
-        {
-        case GTK_POS_LEFT:
-          x = range->range_rect.x - value_spacing - logical_rect.width;
-          y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2;
-          break;
-          
-        case GTK_POS_RIGHT:
-          x = range->range_rect.x + range->range_rect.width + value_spacing;
-          y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2;
-          break;
-          
-        case GTK_POS_TOP:
-          x = range->slider_start +
-            (range->slider_end - range->slider_start - logical_rect.width) / 2;
-          x = CLAMP (x, 0, widget->allocation.width - logical_rect.width);
-          y = range->range_rect.y - logical_rect.height - value_spacing;
-          break;
-          
-        case GTK_POS_BOTTOM:
-          x = range->slider_start +
-            (range->slider_end - range->slider_start - logical_rect.width) / 2;
-          x = CLAMP (x, 0, widget->allocation.width - logical_rect.width);
-          y = range->range_rect.y + range->range_rect.height + value_spacing;
-          break;
-
-        default:
-          g_return_val_if_reached (FALSE);
-          x = 0;
-          y = 0;
-          break;
-        }
+      layout = gtk_scale_get_layout (scale);
+      gtk_scale_get_layout_offsets (scale, &x, &y);
 
-      x += widget->allocation.x;
-      y += widget->allocation.y;
-      
       state_type = GTK_STATE_NORMAL;
       if (!GTK_WIDGET_IS_SENSITIVE (scale))
         state_type = GTK_STATE_INSENSITIVE;
@@ -228,8 +190,85 @@ gtk_hscale_expose (GtkWidget      *widge
                         x, y,
                         layout);
 
-      g_object_unref (layout);
     }
   
   return FALSE;
+}
+
+static void     
+gtk_hscale_get_layout_offsets (GtkScale *scale,
+                               gint     *x,
+                               gint     *y)
+{
+  GtkWidget *widget;
+  PangoLayout *layout;
+
+  g_return_if_fail (GTK_IS_HSCALE (scale));
+  layout = gtk_scale_get_layout (scale);
+  widget = GTK_WIDGET (scale);
+      
+  if (layout)    
+    gtk_hscale_do_get_offsets (widget, layout, x, y);
+  else
+    {
+      *x = 0;
+      *y = 0;
+    }
+}
+
+static gboolean
+gtk_hscale_do_get_offsets (GtkWidget   *widget,
+                           PangoLayout *layout,
+                           gint           *x,
+                           gint           *y)
+{
+  GtkRange *range;
+  GtkScale *scale;
+  PangoRectangle logical_rect;
+  gint value_spacing;
+
+  gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
+
+  range = GTK_RANGE (widget);
+  scale = GTK_SCALE (widget);
+
+  pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+      
+  switch (scale->value_pos)
+    {
+     case GTK_POS_LEFT:
+       *x = range->range_rect.x - value_spacing - logical_rect.width;
+       *y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2;
+       break;
+          
+    case GTK_POS_RIGHT:
+      *x = range->range_rect.x + range->range_rect.width + value_spacing;
+      *y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2;
+      break;
+          
+    case GTK_POS_TOP:
+      *x = range->slider_start +
+        (range->slider_end - range->slider_start - logical_rect.width) / 2;
+      *x = CLAMP (*x, 0, widget->allocation.width - logical_rect.width);
+      *y = range->range_rect.y - logical_rect.height - value_spacing;
+      break;
+          
+    case GTK_POS_BOTTOM:
+      *x = range->slider_start +
+        (range->slider_end - range->slider_start - logical_rect.width) / 2;
+      *x = CLAMP (*x, 0, widget->allocation.width - logical_rect.width);
+      *y = range->range_rect.y + range->range_rect.height + value_spacing;
+      break;
+
+    default:
+      g_return_val_if_reached (FALSE);
+      *x = 0;
+      *y = 0;
+      break;
+    }
+
+  *x += widget->allocation.x;
+  *y += widget->allocation.y;
+      
+  return TRUE;
 }
Index: gtkscale.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkscale.c,v
retrieving revision 1.38
diff -u -p -r1.38 gtkscale.c
--- gtkscale.c	4 Oct 2002 22:49:28 -0000	1.38
+++ gtkscale.c	22 Jul 2003 08:35:13 -0000
@@ -68,6 +68,11 @@ static void gtk_scale_style_set        (
                                         GtkStyle      *previous);
 static void gtk_scale_get_range_border (GtkRange      *range,
                                         GtkBorder     *border);
+static void gtk_scale_finalize         (GObject       *object);
+static void gtk_scale_screen_changed   (GtkWidget     *widget,
+                                        GdkScreen     *old_screen);
+
+static GQuark          quark_layout = 0;
 
 GType
 gtk_scale_get_type (void)
@@ -133,10 +138,14 @@ gtk_scale_class_init (GtkScaleClass *cla
   
   parent_class = g_type_class_peek_parent (class);
   
+  quark_layout = g_quark_from_static_string ("gtk-scale-layout");
+
   gobject_class->set_property = gtk_scale_set_property;
   gobject_class->get_property = gtk_scale_get_property;
+  gobject_class->finalize = gtk_scale_finalize;
 
   widget_class->style_set = gtk_scale_style_set;
+  widget_class->screen_changed = gtk_scale_screen_changed;
 
   range_class->get_range_border = gtk_scale_get_range_border;
   
@@ -407,6 +416,7 @@ gtk_scale_set_digits (GtkScale *scale,
       if (scale->draw_value)
 	range->round_digits = digits;
       
+      _gtk_scale_clear_layout (scale);
       gtk_widget_queue_resize (GTK_WIDGET (scale));
 
       g_object_notify (G_OBJECT (scale), "digits");
@@ -437,6 +447,8 @@ gtk_scale_set_draw_value (GtkScale *scal
       else
 	GTK_RANGE (scale)->round_digits = -1;
 
+      _gtk_scale_clear_layout (scale);
+
       gtk_widget_queue_resize (GTK_WIDGET (scale));
 
       g_object_notify (G_OBJECT (scale), "draw_value");
@@ -461,6 +473,7 @@ gtk_scale_set_value_pos (GtkScale       
     {
       scale->value_pos = pos;
 
+      _gtk_scale_clear_layout (scale);
       if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale))
 	gtk_widget_queue_resize (GTK_WIDGET (scale));
 
@@ -586,9 +599,17 @@ gtk_scale_style_set (GtkWidget *widget,
   
   range->min_slider_size = slider_length;
   
+  _gtk_scale_clear_layout (GTK_SCALE (widget));
+
   (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
 }
 
+static void
+gtk_scale_screen_changed (GtkWidget *widget,
+                          GdkScreen *old_screen)
+{
+  _gtk_scale_clear_layout (GTK_SCALE (widget));
+}
 
 /**
  * _gtk_scale_format_value:
@@ -618,3 +639,103 @@ _gtk_scale_format_value (GtkScale *scale
     return g_strdup_printf ("%0.*f", scale->digits,
                             value);
 }
+
+static void
+gtk_scale_finalize (GObject *object)
+{
+  GtkScale *scale;
+
+  g_return_if_fail (GTK_IS_SCALE (object));
+
+  scale = GTK_SCALE (object);
+
+  _gtk_scale_clear_layout (scale);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * gtk_scale_get_layout:
+ * @scale: A #GtkScale
+ *
+ * Gets the #PangoLayout used to disdplay the scale. The returned object
+ * is owned by the scale so does not need to be freed by the caller.
+ *
+ * Return valueL the #PangoLayout for this scale.
+ **/
+PangoLayout *
+gtk_scale_get_layout (GtkScale *scale)
+{
+  PangoLayout *layout;
+  gchar *txt;
+
+  g_return_val_if_fail (GTK_IS_SCALE (scale), NULL);
+
+  layout = g_object_get_qdata (G_OBJECT (scale), quark_layout);
+
+  if (!layout)
+    {
+      if (scale->draw_value)
+        {
+          layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL);
+          g_object_set_qdata (G_OBJECT (scale), quark_layout, layout);
+        }
+    }
+
+  txt = _gtk_scale_format_value (scale,
+                                 GTK_RANGE (scale)->adjustment->value);
+  pango_layout_set_text (layout, txt, -1);
+  g_free (txt);
+
+  return layout;
+}
+
+/**
+ * gtk_scale_get_layout_offsets:
+ * @scale: a #GtkScale
+ * @x: location to store X offset of layout, or %NULL
+ * @y: location to store Y offset of layout, or %NULL
+ *
+ * Obtains the coordinates where the scale will draw the #PangoLayout
+ * representing the text in the scale. Remember
+ * when using the #PangoLayout function you need to convert to
+ * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
+ *
+ **/
+void 
+gtk_scale_get_layout_offsets (GtkScale *scale,
+                              gint     *x,
+                              gint     *y)
+{
+  gint *real_x, *real_y;
+  gint local_x, local_y;
+
+  if (x)
+    real_x = x;
+  else
+    real_x = &local_x;
+  
+  if (y)
+    real_y = y;
+  else
+    real_y = &local_y;
+  
+  if (GTK_SCALE_GET_CLASS (scale)->get_layout_offsets)
+    (GTK_SCALE_GET_CLASS (scale)->get_layout_offsets) (scale, real_x, real_y);
+}
+
+void _gtk_scale_clear_layout (GtkScale *scale)
+{
+  PangoLayout *layout;
+
+  g_return_if_fail (GTK_IS_SCALE (scale));
+
+  layout = g_object_get_qdata (G_OBJECT (scale), quark_layout);
+
+  if (G_IS_OBJECT (layout))
+    {
+      g_object_unref (layout);
+      g_object_set_qdata (G_OBJECT (scale), quark_layout, NULL);
+    }
+}
+
Index: gtkscale.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkscale.h,v
retrieving revision 1.20
diff -u -p -r1.20 gtkscale.h
--- gtkscale.h	4 Oct 2002 22:49:28 -0000	1.20
+++ gtkscale.h	22 Jul 2003 08:35:13 -0000
@@ -66,8 +66,10 @@ struct _GtkScaleClass
   
   void (* draw_value) (GtkScale *scale);
 
+  void (* get_layout_offsets) (GtkScale *scale,
+                               gint     *x,
+                               gint     *y);
   /* Padding for future expansion */
-  void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
   void (*_gtk_reserved3) (void);
   void (*_gtk_reserved4) (void);
@@ -85,12 +87,18 @@ void            gtk_scale_set_value_pos 
                                           GtkPositionType  pos);
 GtkPositionType gtk_scale_get_value_pos  (GtkScale        *scale);
 
+PangoLayout     *gtk_scale_get_layout       (GtkScale        *scale);
+void            gtk_scale_get_layout_offset (GtkScale        *scale,
+                                             gint            *x,
+                                             gint            *y);
+void    _gtk_scale_clear_layout    (GtkScale        *scale);
 
 void    _gtk_scale_get_value_size  (GtkScale        *scale,
                                     gint            *width,
                                     gint            *height);
 gchar  *_gtk_scale_format_value   (GtkScale        *scale,
                                    gdouble          value);
+
 
 #ifdef __cplusplus
 }
Index: gtkvscale.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkvscale.c,v
retrieving revision 1.42
diff -u -p -r1.42 gtkvscale.c
--- gtkvscale.c	4 Oct 2002 22:49:28 -0000	1.42
+++ gtkvscale.c	22 Jul 2003 08:35:14 -0000
@@ -39,6 +39,14 @@ static void     gtk_vscale_init         
 static gboolean gtk_vscale_expose           (GtkWidget      *widget,
                                              GdkEventExpose *event);
 
+static void	gtk_vscale_get_layout_offsets (GtkScale		*scale,
+                                               gint		*x,
+                                               gint		*y);
+static gboolean	gtk_vscale_do_get_offsets     (GtkWidget	*widget,
+                                               PangoLayout	*layout,
+                                               gint		*x,
+                                               gint		*y);
+
 GType
 gtk_vscale_get_type (void)
 {
@@ -71,14 +79,18 @@ gtk_vscale_class_init (GtkVScaleClass *c
 {
   GtkWidgetClass *widget_class;
   GtkRangeClass *range_class;
+  GtkScaleClass *scale_class;
   
   widget_class = GTK_WIDGET_CLASS (class);
   range_class = GTK_RANGE_CLASS (class); 
+  scale_class = GTK_SCALE_CLASS (class); 
 
   parent_class = g_type_class_peek_parent (class);
 
   range_class->slider_detail = "vscale";
   
+  scale_class->get_layout_offsets = gtk_vscale_get_layout_offsets;
+
   widget_class->expose_event = gtk_vscale_expose;
 }
 
@@ -147,13 +159,9 @@ static gboolean
 gtk_vscale_expose (GtkWidget      *widget,
                    GdkEventExpose *event)
 {
-  GtkRange *range;
-  GtkVScale *vscale;
   GtkScale *scale;
   
-  range = GTK_RANGE (widget);
   scale = GTK_SCALE (widget);
-  vscale = GTK_VSCALE (widget);
   
   /* We need to chain up _first_ so the various geometry members of
    * GtkRange struct are updated.
@@ -164,56 +172,12 @@ gtk_vscale_expose (GtkWidget      *widge
   if (scale->draw_value)
     {
       PangoLayout *layout;
-      PangoRectangle logical_rect;
-      gchar *txt;
       gint x, y;
       GtkStateType state_type;
-      gint value_spacing;
 
-      gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
-      
-      txt = _gtk_scale_format_value (scale,
-                                     GTK_RANGE (scale)->adjustment->value);
-      
-      layout = gtk_widget_create_pango_layout (widget, txt);
-      g_free (txt);
-      
-      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-      
-      switch (scale->value_pos)
-        {
-        case GTK_POS_LEFT:
-          x = range->range_rect.x - logical_rect.width - value_spacing;
-          y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
-          y = CLAMP (y, 0, widget->allocation.height - logical_rect.height);
-          break;
-          
-        case GTK_POS_RIGHT:
-          x = range->range_rect.x + range->range_rect.width + value_spacing;
-          y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
-          y = CLAMP (y, 0, widget->allocation.height - logical_rect.height);
-          break;
-          
-        case GTK_POS_TOP:
-          x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
-          y = range->range_rect.y - logical_rect.height - value_spacing;
-          break;
-          
-        case GTK_POS_BOTTOM:
-          x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
-          y = range->range_rect.y + range->range_rect.height + value_spacing;
-          break;
-
-        default:
-          g_return_val_if_reached (FALSE);
-          x = 0;
-          y = 0;
-          break;
-        }
-      
-      x += widget->allocation.x;
-      y += widget->allocation.y;
-      
+      layout = gtk_scale_get_layout (widget);
+      gtk_scale_get_layout_offsets (widget, &x, &y);
+
       state_type = GTK_STATE_NORMAL;
       if (!GTK_WIDGET_IS_SENSITIVE (scale))
         state_type = GTK_STATE_INSENSITIVE;
@@ -227,9 +191,86 @@ gtk_vscale_expose (GtkWidget      *widge
                         "vscale",
                         x, y,
                         layout);
-
-      g_object_unref (layout);
     }
   
   return FALSE;
+
 }
+
+static void
+gtk_vscale_get_layout_offsets (GtkScale *scale,
+                               gint     *x,
+                               gint     *y)
+{
+  GtkWidget *widget;
+  PangoLayout *layout;
+
+  g_return_if_fail (GTK_IS_VSCALE (scale));
+  widget = GTK_WIDGET (scale);
+
+  layout = gtk_scale_get_layout (scale);
+      
+  if (layout)
+    gtk_vscale_do_get_offsets (widget, layout, x, y);
+  else
+    {
+      *x = 0;
+      *y = 0;
+    }
+}
+
+static gboolean
+gtk_vscale_do_get_offsets (GtkWidget   *widget,
+                           PangoLayout *layout,
+                           gint        *x,
+                           gint	       *y)
+{
+  GtkRange *range;
+  GtkScale *scale;
+  PangoRectangle logical_rect;
+  gint value_spacing;
+
+  range = GTK_RANGE (widget);
+  scale = GTK_SCALE (widget);
+
+  gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
+      
+  pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+    
+  switch (scale->value_pos)
+    {
+    case GTK_POS_LEFT:
+      *x = range->range_rect.x - logical_rect.width - value_spacing;
+      *y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
+      *y = CLAMP (*y, 0, widget->allocation.height - logical_rect.height);
+      break;
+      
+    case GTK_POS_RIGHT:
+      *x = range->range_rect.x + range->range_rect.width + value_spacing;
+      *y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
+      *y = CLAMP (*y, 0, widget->allocation.height - logical_rect.height);
+      break;
+          
+    case GTK_POS_TOP:
+      *x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
+      *y = range->range_rect.y - logical_rect.height - value_spacing;
+      break;
+          
+    case GTK_POS_BOTTOM:
+      *x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
+      *y = range->range_rect.y + range->range_rect.height + value_spacing;
+      break;
+
+    default:
+      g_return_val_if_reached (FALSE);
+      *x = 0;
+      *y = 0;
+      break;
+    }
+
+  *x += widget->allocation.x;
+  *y += widget->allocation.y;
+      
+  return TRUE;
+}
+
