Index: gail/gail/Makefile.am
===================================================================
RCS file: /cvs/gnome/gail/gail/Makefile.am,v
retrieving revision 1.61
diff -u -p -r1.61 Makefile.am
--- gail/gail/Makefile.am	21 Feb 2003 15:24:33 -0000	1.61
+++ gail/gail/Makefile.am	5 Mar 2003 16:10:14 -0000
@@ -52,6 +52,7 @@ gail_c_sources =			\
 	gailradiosubmenuitem.c		\
 	gailrange.c			\
 	gailrenderercell.c		\
+	gailscale.c			\
 	gailscrollbar.c			\
 	gailscrolledwindow.c		\
 	gailseparator.c			\
@@ -122,6 +123,7 @@ gail_private_h_sources =		\
 	gailradiosubmenuitem.h		\
 	gailrange.h			\
 	gailrenderercell.h		\
+	gailscale.h			\
 	gailscrollbar.h			\
 	gailscrolledwindow.h		\
 	gailseparator.h			\
Index: gail/gail/gail.c
===================================================================
RCS file: /cvs/gnome/gail/gail/gail.c,v
retrieving revision 1.79
diff -u -p -r1.79 gail.c
--- gail/gail/gail.c	21 Feb 2003 15:24:33 -0000	1.79
+++ gail/gail/gail.c	5 Mar 2003 16:10:14 -0000
@@ -92,6 +92,7 @@ GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_OPTIO
 GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_CANVAS, gail_canvas, gail_canvas_new)
 GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_CHECK_MENU_ITEM, gail_check_menu_item, gail_check_menu_item_new)
 GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_RADIO_MENU_ITEM, gail_radio_menu_item, gail_radio_menu_item_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_SCALE, gail_scale, gail_scale_new)
 
 static AtkObject*
 gail_get_accessible_for_widget (GtkWidget *widget,
@@ -635,6 +636,7 @@ gail_accessibility_module_init (void)
   GAIL_WIDGET_SET_FACTORY (GTK_TYPE_WINDOW, gail_window);
   GAIL_WIDGET_SET_FACTORY (GTK_TYPE_HANDLE_BOX, gail_window);
   GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RANGE, gail_range);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCALE, gail_scale);
   GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CLIST, gail_clist);
   GAIL_WIDGET_SET_FACTORY (GTK_TYPE_LABEL, gail_label);
   GAIL_WIDGET_SET_FACTORY (GTK_TYPE_STATUSBAR, gail_statusbar);
Index: gail/gail/gail.h
===================================================================
RCS file: /cvs/gnome/gail/gail/gail.h,v
retrieving revision 1.43
diff -u -p -r1.43 gail.h
--- gail/gail/gail.h	21 Feb 2003 15:24:33 -0000	1.43
+++ gail/gail/gail.h	5 Mar 2003 16:10:14 -0000
@@ -42,6 +42,7 @@
 #include <gail/gailradiobutton.h>
 #include <gail/gailradiomenuitem.h>
 #include <gail/gailrange.h>
+#include <gail/gailscale.h>
 #include <gail/gailscrollbar.h>
 #include <gail/gailscrolledwindow.h>
 #include <gail/gailseparator.h>
*** /dev/null	Wed Mar  5 16:12:59 2003
--- gail/gail/gailscale.h	Wed Mar  5 11:39:50 2003
***************
*** 0 ****
--- 1,62 ----
+ /* GAIL - The GNOME Accessibility Implementation Library
+  * Copyright 2003 Sun Microsystems Inc.
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library 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
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public
+  * License along with this library; if not, write to the
+  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  * Boston, MA 02111-1307, USA.
+  */
+ 
+ #ifndef __GAIL_SCALE_H__
+ #define __GAIL_SCALE_H__
+ 
+ #include <gtk/gtkaccessible.h>
+ #include <gail/gailrange.h>
+ #include <libgail-util/gailtextutil.h>
+ 
+ #ifdef __cplusplus
+ extern "C" {
+ #endif /* __cplusplus */
+ 
+ #define GAIL_TYPE_SCALE                         (gail_scale_get_type ())
+ #define GAIL_SCALE(obj)                         (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_SCALE, GailScale))
+ #define GAIL_SCALE_CLASS(klass)			(G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_SCALE, GailScaleClass))
+ #define GAIL_IS_SCALE(obj)			(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_SCALE))
+ #define GAIL_IS_SCALE_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_SCALE))
+ #define GAIL_SCALE_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_SCALE, GailScaleClass))
+ 
+ typedef struct _GailScale		GailScale;
+ typedef struct _GailScaleClass		GailScaleClass;
+ 
+ struct _GailScale
+ {
+   GailRange parent;
+ 
+   GailTextUtil *textutil;
+ };
+ 
+ GType gail_scale_get_type (void);
+ 
+ struct _GailScaleClass
+ {
+   GailRangeClass parent_class;
+ };
+ 
+ AtkObject* gail_scale_new (GtkWidget *widget);
+ 
+ #ifdef __cplusplus
+ }
+ #endif /* __cplusplus */
+ 
+ 
+ #endif /* __GAIL_SCALE_H__ */
*** /dev/null	Wed Mar  5 16:12:59 2003
--- gail/gail/gailscale.c	Wed Mar  5 16:10:29 2003
***************
*** 0 ****
--- 1,539 ----
+ /* GAIL - The GNOME Accessibility Implementation Library
+  * Copyright 2003 Sun Microsystems Inc.
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library 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
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, write to the
+  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  * Boston, MA 02111-1307, USA.
+  */
+ 
+ #include <string.h>
+ #include <gtk/gtk.h>
+ #include "gailscale.h"
+ #include <libgail-util/gailmisc.h>
+ 
+ static void	    gail_scale_class_init        (GailScaleClass *klass);
+ 
+ static void         gail_scale_real_initialize   (AtkObject      *obj,
+                                                   gpointer      data);
+ static void         gail_scale_notify            (GObject       *obj,
+                                                   GParamSpec    *pspec);
+ static void         gail_scale_finalize          (GObject        *object);
+ 
+ /* atktext.h */ 
+ static void	    gail_scale_text_interface_init (AtkTextIface      *iface);
+ 
+ static gchar*	    gail_scale_get_text	           (AtkText	      *text,
+                                                     gint	      start_pos,
+ 						    gint	      end_pos);
+ static gunichar	    gail_scale_get_character_at_offset
+                                                    (AtkText	      *text,
+ 						    gint	      offset);
+ static gchar*       gail_scale_get_text_before_offset
+                                                    (AtkText	      *text,
+  						    gint	      offset,
+ 						    AtkTextBoundary   boundary_type,
+ 						    gint	      *start_offset,
+ 						    gint	      *end_offset);
+ static gchar*       gail_scale_get_text_at_offset  (AtkText	      *text,
+  						    gint	      offset,
+ 						    AtkTextBoundary   boundary_type,
+ 						    gint	      *start_offset,
+ 						    gint	      *end_offset);
+ static gchar*      gail_scale_get_text_after_offset
+                                                    (AtkText	      *text,
+  						    gint	      offset,
+ 						    AtkTextBoundary   boundary_type,
+ 						    gint	      *start_offset,
+ 						    gint	      *end_offset);
+ static gint	   gail_scale_get_character_count  (AtkText	      *text);
+ static void        gail_scale_get_character_extents
+                                                    (AtkText	      *text,
+ 						    gint 	      offset,
+ 		                                    gint 	      *x,
+                     		   	            gint 	      *y,
+                                 		    gint 	      *width,
+                                      		    gint 	      *height,
+ 			        		    AtkCoordType      coords);
+ static gint        gail_scale_get_offset_at_point  (AtkText           *text,
+                                                     gint              x,
+                                                     gint              y,
+ 			                            AtkCoordType      coords);
+ static AtkAttributeSet* gail_scale_get_run_attributes 
+                                                    (AtkText           *text,
+               					    gint 	      offset,
+                                                     gint 	      *start_offset,
+ 					            gint	      *end_offset);
+ static AtkAttributeSet* gail_scale_get_default_attributes
+                                                    (AtkText           *text);
+ 
+ static gpointer parent_class = NULL;
+ 
+ GType
+ gail_scale_get_type (void)
+ {
+   static GType type = 0;
+ 
+   if (!type)
+     {
+       static const GTypeInfo tinfo =
+       {
+         sizeof (GailRangeClass),
+         (GBaseInitFunc) NULL, /* base init */
+         (GBaseFinalizeFunc) NULL, /* base finalize */
+         (GClassInitFunc) gail_scale_class_init, /* class init */
+         (GClassFinalizeFunc) NULL, /* class finalize */
+         NULL, /* class data */
+         sizeof (GailRange), /* instance size */
+         0, /* nb preallocs */
+         (GInstanceInitFunc) NULL, /* instance init */
+         NULL /* value table */
+       };
+ 
+       static const GInterfaceInfo atk_text_info =
+       {
+         (GInterfaceInitFunc) gail_scale_text_interface_init,
+         (GInterfaceFinalizeFunc) NULL,
+         NULL
+       };
+       type = g_type_register_static (GAIL_TYPE_RANGE,
+                                      "GailScale", &tinfo, 0);
+ 
+       g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                    &atk_text_info);
+     }
+   return type;
+ }
+ 
+ static void	 
+ gail_scale_class_init (GailScaleClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+ 
+   class->initialize = gail_scale_real_initialize;
+ 
+   gobject_class->finalize = gail_scale_finalize;
+   gobject_class->notify = gail_scale_notify;
+ 
+   parent_class = g_type_class_peek_parent (klass);
+ }
+ 
+ AtkObject* 
+ gail_scale_new (GtkWidget *widget)
+ {
+   GObject *object;
+   AtkObject *accessible;
+ 
+   g_return_val_if_fail (GTK_IS_RANGE (widget), NULL);
+ 
+   object = g_object_new (GAIL_TYPE_SCALE, NULL);
+ 
+   accessible = ATK_OBJECT (object);
+   atk_object_initialize (accessible, widget);
+ 
+   return accessible;
+ }
+ 
+ static void
+ gail_scale_real_initialize (AtkObject *obj,
+                             gpointer  data)
+ {
+   GailScale *gail_scale;
+   gchar *txt;
+ 
+   ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+ 
+   gail_scale = GAIL_SCALE (obj);
+   gail_scale->textutil = gail_text_util_new ();
+ 
+   txt = gtk_scale_get_text (GTK_SCALE (data));
+   if (txt)
+     {
+       gail_text_util_text_setup (gail_scale->textutil, txt);
+       g_free (txt);
+     }
+ }
+ 
+ static void
+ gail_scale_finalize (GObject *object)
+ {
+   GailScale *scale = GAIL_SCALE (object);
+ 
+   g_object_unref (scale->textutil);
+   G_OBJECT_CLASS (parent_class)->finalize (object);
+ 
+ }
+ 
+ static void
+ gail_scale_notify (GObject    *obj,
+                    GParamSpec *pspec)
+ {
+   GailScale *scale = GAIL_SCALE (obj);
+ 
+   if (strcmp (pspec->name, "accessible-value") == 0)
+     {
+       GtkWidget *widget;
+ 
+       widget = GTK_ACCESSIBLE (obj)->widget;
+       if (widget)
+         {
+           GtkScale *gtk_scale;
+           gchar *txt;
+ 
+           gtk_scale = GTK_SCALE (widget);
+           txt = gtk_scale_get_text (gtk_scale);
+           if (txt)
+             {
+ 	      g_signal_emit_by_name (obj, "text_changed::delete", 0,
+                                      gtk_text_buffer_get_char_count (scale->textutil->buffer));
+               gail_text_util_text_setup (scale->textutil, txt);
+ 	      g_signal_emit_by_name (obj, "text_changed::insert", 0,
+                                      g_utf8_strlen (txt, -1));
+               g_free (txt);
+             }
+         }
+     }
+   G_OBJECT_CLASS (parent_class)->notify (obj, pspec);
+ }
+ 
+ /* atktext.h */
+ 
+ static void
+ gail_scale_text_interface_init (AtkTextIface *iface)
+ {
+   g_return_if_fail (iface != NULL);
+   iface->get_text = gail_scale_get_text;
+   iface->get_character_at_offset = gail_scale_get_character_at_offset;
+   iface->get_text_before_offset = gail_scale_get_text_before_offset;
+   iface->get_text_at_offset = gail_scale_get_text_at_offset;
+   iface->get_text_after_offset = gail_scale_get_text_after_offset;
+   iface->get_character_count = gail_scale_get_character_count;
+   iface->get_character_extents = gail_scale_get_character_extents;
+   iface->get_offset_at_point = gail_scale_get_offset_at_point;
+   iface->get_run_attributes = gail_scale_get_run_attributes;
+   iface->get_default_attributes = gail_scale_get_default_attributes;
+ }
+ 
+ static gchar*
+ gail_scale_get_text (AtkText *text,
+                      gint    start_pos,
+                      gint    end_pos)
+ {
+   GtkWidget *widget;
+   GailScale *scale;
+   const gchar *label_text;
+ 
+   widget = GTK_ACCESSIBLE (text)->widget;
+   if (widget == NULL)
+     /* State is defunct */
+     return NULL;
+ 
+   scale = GAIL_SCALE (text);
+   return gail_text_util_get_substring (scale->textutil, 
+                                        start_pos, end_pos);
+ }
+ 
+ static gchar*
+ gail_scale_get_text_before_offset (AtkText         *text,
+      				   gint            offset,
+ 				   AtkTextBoundary boundary_type,
+ 				   gint            *start_offset,
+ 				   gint            *end_offset)
+ {
+   GtkWidget *widget;
+   GailScale *scale;
+   PangoLayout *layout;
+   gchar *txt;
+   
+   widget = GTK_ACCESSIBLE (text)->widget;
+   
+   if (widget == NULL)
+     /* State is defunct */
+     return NULL;
+   
+   scale = GAIL_SCALE (text);
+   layout = gtk_scale_get_text_layout (GTK_SCALE (widget));
+   if (layout)
+     {
+       txt =  gail_text_util_get_text (scale->textutil,
+                            layout, GAIL_BEFORE_OFFSET, 
+                            boundary_type, offset, start_offset, end_offset); 
+       g_object_unref (layout);
+     }
+   else
+     txt = NULL;
+ 
+   return txt;
+ }
+ 
+ static gchar*
+ gail_scale_get_text_at_offset (AtkText         *text,
+ 	   		       gint            offset,
+ 			       AtkTextBoundary boundary_type,
+  			       gint            *start_offset,
+ 			       gint            *end_offset)
+ {
+   GtkWidget *widget;
+   GailScale *scale;
+   PangoLayout *layout;
+   gchar *txt;
+  
+   widget = GTK_ACCESSIBLE (text)->widget;
+   
+   if (widget == NULL)
+     /* State is defunct */
+     return NULL;
+   
+   scale = GAIL_SCALE (text);
+   layout = gtk_scale_get_text_layout (GTK_SCALE (widget));
+   if (layout)
+     {
+       txt =  gail_text_util_get_text (scale->textutil,
+                               layout, GAIL_AT_OFFSET, 
+                               boundary_type, offset, start_offset, end_offset);
+       g_object_unref (layout);
+     }
+   else
+     txt = NULL;
+ 
+   return txt;
+ }
+ 
+ static gchar*
+ gail_scale_get_text_after_offset (AtkText         *text,
+ 				  gint            offset,
+ 				  AtkTextBoundary boundary_type,
+ 				  gint            *start_offset,
+ 				  gint            *end_offset)
+ {
+   GtkWidget *widget;
+   GailScale *scale;
+   PangoLayout *layout;
+   gchar *txt;
+ 
+   widget = GTK_ACCESSIBLE (text)->widget;
+   
+   if (widget == NULL)
+     /* State is defunct */
+     return NULL;
+   
+   scale = GAIL_SCALE (text);
+   layout = gtk_scale_get_text_layout (GTK_SCALE (widget));
+   if (layout)
+     {
+       txt =  gail_text_util_get_text (scale->textutil,
+                               layout, GAIL_AFTER_OFFSET, 
+                               boundary_type, offset, start_offset, end_offset);
+       g_object_unref (layout);
+     }
+   else
+     txt = NULL;
+ 
+   return txt;
+ }
+ 
+ static gint
+ gail_scale_get_character_count (AtkText *text)
+ {
+   GtkWidget *widget;
+   GailScale *scale;
+ 
+   widget = GTK_ACCESSIBLE (text)->widget;
+   if (widget == NULL)
+     /* State is defunct */
+     return 0;
+ 
+   scale = GAIL_SCALE (text);
+   if (scale->textutil->buffer)
+     return gtk_text_buffer_get_char_count (scale->textutil->buffer);
+   else
+     return 0;
+ 
+ }
+ 
+ static void
+ gail_scale_get_character_extents (AtkText      *text,
+ 				  gint         offset,
+ 		                  gint         *x,
+                     		  gint 	       *y,
+                                   gint 	       *width,
+                                   gint 	       *height,
+ 			          AtkCoordType coords)
+ {
+   GtkWidget *widget;
+   GtkScale *scale;
+   PangoRectangle char_rect;
+   PangoLayout *layout;
+   gint index, x_layout, y_layout;
+   gchar *scale_text;
+  
+   widget = GTK_ACCESSIBLE (text)->widget;
+ 
+   if (widget == NULL)
+     /* State is defunct */
+     return;
+ 
+   scale = GTK_SCALE (widget);
+   scale_text = gtk_scale_get_text (scale);
+   if (!scale_text)
+     return;
+   gtk_scale_get_text_offsets (scale, &x_layout, &y_layout);
+   layout = gtk_scale_get_text_layout (scale);
+   index = g_utf8_offset_to_pointer (scale_text, offset) - scale_text;
+   pango_layout_index_to_pos (layout, index, &char_rect);
+   gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, 
+                     x_layout, y_layout, x, y, width, height, coords);
+   g_free (scale_text);
+   g_object_unref (layout);
+ } 
+ 
+ static gint 
+ gail_scale_get_offset_at_point (AtkText      *text,
+                                 gint         x,
+                                 gint         y,
+ 	          		AtkCoordType coords)
+ { 
+   GtkWidget *widget;
+   GtkScale *scale;
+   PangoRectangle char_rect;
+   PangoLayout *layout;
+   gint index, x_layout, y_layout;
+   gchar *scale_text;
+ 
+   widget = GTK_ACCESSIBLE (text)->widget;
+   if (widget == NULL)
+     /* State is defunct */
+     return -1;
+ 
+   scale = GTK_SCALE (widget);
+   scale_text = gtk_scale_get_text (scale);
+   if (!scale_text)
+     return -1;
+   gtk_scale_get_text_offsets (scale, &x_layout, &y_layout);
+   layout = gtk_scale_get_text_layout (scale);
+   
+   index = gail_misc_get_index_at_point_in_layout (widget, 
+                                               layout, 
+                                               x_layout, y_layout, x, y, coords);
+   if (index == -1)
+     {
+       if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+         index = g_utf8_strlen (scale_text, -1);
+ 
+     }
+   else
+     index = g_utf8_pointer_to_offset (scale_text, scale_text + index);  
+ 
+   g_free (scale_text);
+   g_object_unref (layout);
+   return index;
+ }
+ 
+ static AtkAttributeSet*
+ gail_scale_get_run_attributes (AtkText *text,
+                                gint    offset,
+                                gint    *start_offset,
+ 	                       gint    *end_offset)
+ {
+   GtkWidget *widget;
+   GtkScale *scale;
+   AtkAttributeSet *at_set = NULL;
+   GtkTextDirection dir;
+   PangoLayout *layout;
+   gchar *scale_text;
+ 
+   widget = GTK_ACCESSIBLE (text)->widget;
+   if (widget == NULL)
+     /* State is defunct */
+     return NULL;
+ 
+   scale = GTK_SCALE (widget);
+ 
+   scale_text = gtk_scale_get_text (scale);
+   if (!scale_text)
+     return at_set;
+ 
+   dir = gtk_widget_get_direction (widget);
+   if (dir == GTK_TEXT_DIR_RTL)
+     {
+       at_set = gail_misc_add_attribute (at_set, 
+                                         ATK_TEXT_ATTR_DIRECTION,
+      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
+     }
+ 
+   layout = gtk_scale_get_text_layout (scale);
+   at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                 layout,
+                                                 scale_text,
+                                                 offset,
+                                                 start_offset,
+                                                 end_offset);
+   g_object_unref (layout);
+   g_free (scale_text);
+   return at_set;
+ }
+ 
+ static AtkAttributeSet*
+ gail_scale_get_default_attributes (AtkText *text)
+ {
+   GtkWidget *widget;
+   AtkAttributeSet *at_set = NULL;
+   PangoLayout *layout;
+ 
+   widget = GTK_ACCESSIBLE (text)->widget;
+   if (widget == NULL)
+     /* State is defunct */
+     return NULL;
+ 
+   layout = gtk_scale_get_text_layout (GTK_SCALE (widget));
+   if (layout)
+     {
+       at_set = gail_misc_get_default_attributes (at_set,
+                                                  layout,
+                                                  widget);
+       g_object_unref (layout);
+     }
+   return at_set;
+ }
+ 
+ static gunichar 
+ gail_scale_get_character_at_offset (AtkText *text,
+                                     gint    offset)
+ {
+   GtkWidget *widget;
+   GtkScale *scale;
+   gchar *string;
+   gchar *index;
+   gunichar c;
+ 
+   widget = GTK_ACCESSIBLE (text)->widget;
+   if (widget == NULL)
+     /* State is defunct */
+     return '\0';
+ 
+   scale = GTK_SCALE (widget);
+ 
+   string = gtk_scale_get_text (scale);
+   if (offset >= g_utf8_strlen (string, -1))
+     c = '\0';
+   else
+     {
+       index = g_utf8_offset_to_pointer (string, offset);
+ 
+       c = g_utf8_get_char (index);
+     }
+   g_free (string);
+ 
+   return c;
+ }
