]> Pileus Git - ~andy/gtk/commitdiff
Integrate gail into gtk+. Bug #169488.
authorChristian Persch <chpe@src.gnome.org>
Tue, 18 Dec 2007 13:51:12 +0000 (13:51 +0000)
committerChristian Persch <chpe@src.gnome.org>
Tue, 18 Dec 2007 13:51:12 +0000 (13:51 +0000)
* configure.in:
* docs/reference/Makefile.am:
* docs/reference/libgail-util/*:
* gail-uninstalled.pc.in:
* gail.pc.in:
* modules/Makefile.am:
* modules/other/Makefile.am:
* modules/other/gail/*:
* modules/other/gail/libgail-util/*:
* po/POTFILES.skip: Integrate gail into gtk+. Bug #169488.

svn path=/trunk/; revision=19196

153 files changed:
ChangeLog
configure.in
docs/reference/Makefile.am
docs/reference/libgail-util/Makefile.am [new file with mode: 0644]
docs/reference/libgail-util/gail-libgail-util-docs.sgml [new file with mode: 0644]
docs/reference/libgail-util/gail-libgail-util-overrides.txt [new file with mode: 0644]
docs/reference/libgail-util/gail-libgail-util-sections.txt [new file with mode: 0644]
docs/reference/libgail-util/gail-libgail-util.types [new file with mode: 0644]
docs/reference/libgail-util/tmpl/gail-libgail-util-unused.sgml [new file with mode: 0644]
docs/reference/libgail-util/tmpl/gailmisc.sgml [new file with mode: 0644]
docs/reference/libgail-util/tmpl/gailtextutil.sgml [new file with mode: 0644]
gail-uninstalled.pc.in [new file with mode: 0644]
gail.pc.in [new file with mode: 0644]
modules/Makefile.am
modules/other/Makefile.am [new file with mode: 0644]
modules/other/gail/Makefile.am [new file with mode: 0644]
modules/other/gail/gail-private-macros.h [new file with mode: 0644]
modules/other/gail/gail.c [new file with mode: 0644]
modules/other/gail/gail.h [new file with mode: 0644]
modules/other/gail/gailadjustment.c [new file with mode: 0644]
modules/other/gail/gailadjustment.h [new file with mode: 0644]
modules/other/gail/gailarrow.c [new file with mode: 0644]
modules/other/gail/gailarrow.h [new file with mode: 0644]
modules/other/gail/gailbooleancell.c [new file with mode: 0644]
modules/other/gail/gailbooleancell.h [new file with mode: 0644]
modules/other/gail/gailbooleancellfactory.c [new file with mode: 0644]
modules/other/gail/gailbooleancellfactory.h [new file with mode: 0644]
modules/other/gail/gailbox.c [new file with mode: 0644]
modules/other/gail/gailbox.h [new file with mode: 0644]
modules/other/gail/gailbutton.c [new file with mode: 0644]
modules/other/gail/gailbutton.h [new file with mode: 0644]
modules/other/gail/gailcalendar.c [new file with mode: 0644]
modules/other/gail/gailcalendar.h [new file with mode: 0644]
modules/other/gail/gailcell.c [new file with mode: 0644]
modules/other/gail/gailcell.h [new file with mode: 0644]
modules/other/gail/gailcellparent.c [new file with mode: 0644]
modules/other/gail/gailcellparent.h [new file with mode: 0644]
modules/other/gail/gailcheckmenuitem.c [new file with mode: 0644]
modules/other/gail/gailcheckmenuitem.h [new file with mode: 0644]
modules/other/gail/gailchecksubmenuitem.c [new file with mode: 0644]
modules/other/gail/gailchecksubmenuitem.h [new file with mode: 0644]
modules/other/gail/gailclist.c [new file with mode: 0644]
modules/other/gail/gailclist.h [new file with mode: 0644]
modules/other/gail/gailclistcell.c [new file with mode: 0644]
modules/other/gail/gailclistcell.h [new file with mode: 0644]
modules/other/gail/gailcombo.c [new file with mode: 0644]
modules/other/gail/gailcombo.h [new file with mode: 0644]
modules/other/gail/gailcombobox.c [new file with mode: 0644]
modules/other/gail/gailcombobox.h [new file with mode: 0644]
modules/other/gail/gailcontainer.c [new file with mode: 0644]
modules/other/gail/gailcontainer.h [new file with mode: 0644]
modules/other/gail/gailcontainercell.c [new file with mode: 0644]
modules/other/gail/gailcontainercell.h [new file with mode: 0644]
modules/other/gail/gailentry.c [new file with mode: 0644]
modules/other/gail/gailentry.h [new file with mode: 0644]
modules/other/gail/gailexpander.c [new file with mode: 0644]
modules/other/gail/gailexpander.h [new file with mode: 0644]
modules/other/gail/gailfactory.h [new file with mode: 0644]
modules/other/gail/gailframe.c [new file with mode: 0644]
modules/other/gail/gailframe.h [new file with mode: 0644]
modules/other/gail/gailhtmlbox.c [new file with mode: 0644]
modules/other/gail/gailhtmlbox.h [new file with mode: 0644]
modules/other/gail/gailhtmlboxblock.c [new file with mode: 0644]
modules/other/gail/gailhtmlboxembedded.c [new file with mode: 0644]
modules/other/gail/gailhtmlboxtext.c [new file with mode: 0644]
modules/other/gail/gailimage.c [new file with mode: 0644]
modules/other/gail/gailimage.h [new file with mode: 0644]
modules/other/gail/gailimagecell.c [new file with mode: 0644]
modules/other/gail/gailimagecell.h [new file with mode: 0644]
modules/other/gail/gailimagecellfactory.c [new file with mode: 0644]
modules/other/gail/gailimagecellfactory.h [new file with mode: 0644]
modules/other/gail/gailintl.h [new file with mode: 0644]
modules/other/gail/gailitem.c [new file with mode: 0644]
modules/other/gail/gailitem.h [new file with mode: 0644]
modules/other/gail/gaillabel.c [new file with mode: 0644]
modules/other/gail/gaillabel.h [new file with mode: 0644]
modules/other/gail/gaillist.c [new file with mode: 0644]
modules/other/gail/gaillist.h [new file with mode: 0644]
modules/other/gail/gailmenu.c [new file with mode: 0644]
modules/other/gail/gailmenu.h [new file with mode: 0644]
modules/other/gail/gailmenuitem.c [new file with mode: 0644]
modules/other/gail/gailmenuitem.h [new file with mode: 0644]
modules/other/gail/gailmenushell.c [new file with mode: 0644]
modules/other/gail/gailmenushell.h [new file with mode: 0644]
modules/other/gail/gailnotebook.c [new file with mode: 0644]
modules/other/gail/gailnotebook.h [new file with mode: 0644]
modules/other/gail/gailnotebookpage.c [new file with mode: 0644]
modules/other/gail/gailnotebookpage.h [new file with mode: 0644]
modules/other/gail/gailobject.c [new file with mode: 0644]
modules/other/gail/gailobject.h [new file with mode: 0644]
modules/other/gail/gailobjectfactory.c [new file with mode: 0644]
modules/other/gail/gailobjectfactory.h [new file with mode: 0644]
modules/other/gail/gailoptionmenu.c [new file with mode: 0644]
modules/other/gail/gailoptionmenu.h [new file with mode: 0644]
modules/other/gail/gailpaned.c [new file with mode: 0644]
modules/other/gail/gailpaned.h [new file with mode: 0644]
modules/other/gail/gailpixmap.c [new file with mode: 0644]
modules/other/gail/gailpixmap.h [new file with mode: 0644]
modules/other/gail/gailprogressbar.c [new file with mode: 0644]
modules/other/gail/gailprogressbar.h [new file with mode: 0644]
modules/other/gail/gailradiobutton.c [new file with mode: 0644]
modules/other/gail/gailradiobutton.h [new file with mode: 0644]
modules/other/gail/gailradiomenuitem.c [new file with mode: 0644]
modules/other/gail/gailradiomenuitem.h [new file with mode: 0644]
modules/other/gail/gailradiosubmenuitem.c [new file with mode: 0644]
modules/other/gail/gailradiosubmenuitem.h [new file with mode: 0644]
modules/other/gail/gailrange.c [new file with mode: 0644]
modules/other/gail/gailrange.h [new file with mode: 0644]
modules/other/gail/gailrenderercell.c [new file with mode: 0644]
modules/other/gail/gailrenderercell.h [new file with mode: 0644]
modules/other/gail/gailrenderercellfactory.c [new file with mode: 0644]
modules/other/gail/gailrenderercellfactory.h [new file with mode: 0644]
modules/other/gail/gailscale.c [new file with mode: 0644]
modules/other/gail/gailscale.h [new file with mode: 0644]
modules/other/gail/gailscrollbar.c [new file with mode: 0644]
modules/other/gail/gailscrollbar.h [new file with mode: 0644]
modules/other/gail/gailscrolledwindow.c [new file with mode: 0644]
modules/other/gail/gailscrolledwindow.h [new file with mode: 0644]
modules/other/gail/gailseparator.c [new file with mode: 0644]
modules/other/gail/gailseparator.h [new file with mode: 0644]
modules/other/gail/gailspinbutton.c [new file with mode: 0644]
modules/other/gail/gailspinbutton.h [new file with mode: 0644]
modules/other/gail/gailstatusbar.c [new file with mode: 0644]
modules/other/gail/gailstatusbar.h [new file with mode: 0644]
modules/other/gail/gailsubmenuitem.c [new file with mode: 0644]
modules/other/gail/gailsubmenuitem.h [new file with mode: 0644]
modules/other/gail/gailtextcell.c [new file with mode: 0644]
modules/other/gail/gailtextcell.h [new file with mode: 0644]
modules/other/gail/gailtextcellfactory.c [new file with mode: 0644]
modules/other/gail/gailtextcellfactory.h [new file with mode: 0644]
modules/other/gail/gailtextview.c [new file with mode: 0644]
modules/other/gail/gailtextview.h [new file with mode: 0644]
modules/other/gail/gailtogglebutton.c [new file with mode: 0644]
modules/other/gail/gailtogglebutton.h [new file with mode: 0644]
modules/other/gail/gailtoplevel.c [new file with mode: 0644]
modules/other/gail/gailtoplevel.h [new file with mode: 0644]
modules/other/gail/gailtreeview.c [new file with mode: 0644]
modules/other/gail/gailtreeview.h [new file with mode: 0644]
modules/other/gail/gailutil.c [new file with mode: 0644]
modules/other/gail/gailutil.h [new file with mode: 0644]
modules/other/gail/gailwidget.c [new file with mode: 0644]
modules/other/gail/gailwidget.h [new file with mode: 0644]
modules/other/gail/gailwindow.c [new file with mode: 0644]
modules/other/gail/gailwindow.h [new file with mode: 0644]
modules/other/gail/libgail-util/Makefile.am [new file with mode: 0644]
modules/other/gail/libgail-util/gail-util.h [new file with mode: 0644]
modules/other/gail/libgail-util/gailmisc.c [new file with mode: 0644]
modules/other/gail/libgail-util/gailmisc.h [new file with mode: 0644]
modules/other/gail/libgail-util/gailtextutil.c [new file with mode: 0644]
modules/other/gail/libgail-util/gailtextutil.h [new file with mode: 0644]
modules/other/gail/libgail-util/gailutil.def [new file with mode: 0644]
po/POTFILES.in
po/POTFILES.skip

index 68be1d1fa16a3ede627a48b109c4c8c1aca5af1e..2cfd378912514f2bec8e0ad8dc5137a8cd5e9af9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2007-12-18  Christian Persch  <chpe@gnome.org>
+
+       * configure.in:
+       * docs/reference/Makefile.am:
+       * docs/reference/libgail-util/*:
+       * gail-uninstalled.pc.in:
+       * gail.pc.in:
+       * modules/Makefile.am:
+       * modules/other/Makefile.am:
+       * modules/other/gail/*:
+       * modules/other/gail/libgail-util/*:
+       * po/POTFILES.skip: Integrate gail into gtk+. Bug #169488.
+
 2007-12-17  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtksettings.c: Add a gtk-im-module GTK setting
index fbab5bb3c57ffd8d7907934095f29ed82f2157de..58ea15787ed0a6e5f85a94fa1d0ad27dc5d6a923 100644 (file)
@@ -33,7 +33,7 @@ m4_define([gtk_binary_version], [2.10.0])
 # required versions of other packages
 m4_define([glib_required_version], [2.15.0])
 m4_define([pango_required_version], [1.17.3])
-m4_define([atk_required_version], [1.9.0])
+m4_define([atk_required_version], [1.13.0])
 m4_define([cairo_required_version], [1.2.0])
 
 
@@ -1559,6 +1559,36 @@ AC_SUBST(CAIRO_PREFIX)
 AC_SUBST(GTK_DEBUG_FLAGS)
 AC_SUBST(GTK_XIM_FLAGS)
 
+########################
+# Checks needed for gail
+########################
+
+old_LIBS="$LIBS"
+dnl Checks for inet libraries:
+AC_SEARCH_LIBS(gethostent, nsl)
+AC_SEARCH_LIBS(setsockopt, socket)
+AC_SEARCH_LIBS(connect, inet)
+
+dnl check for the sockaddr_un.sun_len member
+AC_CHECK_MEMBER([struct sockaddr_un.sun_len],
+               [struct_sockaddr_un_sun_len=true],
+               [struct_sockaddr_un_suin_len=false],
+               [#include <sys/types.h>
+                #include <sys/un.h>]
+               )
+case $struct_sockaddr_un_sun_len in 
+       true)
+               AC_DEFINE_UNQUOTED(HAVE_SOCKADDR_UN_SUN_LEN, 1, Have the sockaddr_un.sun_len member.)
+               ;;
+       *)
+               ;;
+esac
+
+GAIL_INET_LIBS="$LIBS"
+AC_SUBST([GAIL_INET_LIBS])
+
+LIBS="$old_LIBS"
+
 ################################################################
 # Printing system checks
 ################################################################
@@ -1760,9 +1790,11 @@ gdk-pixbuf-2.0.pc
 gdk-2.0.pc
 gtk+-2.0.pc
 gtk+-unix-print-2.0.pc
+gail.pc
 gdk-pixbuf-2.0-uninstalled.pc
 gdk-2.0-uninstalled.pc
 gtk+-2.0-uninstalled.pc
+gail-uninstalled.pc
 m4macros/Makefile
 po/Makefile.in
 po-properties/Makefile.in
@@ -1778,6 +1810,7 @@ docs/reference/gdk/Makefile
 docs/reference/gdk/version.xml
 docs/reference/gtk/Makefile
 docs/reference/gtk/version.xml
+docs/reference/libgail-util/Makefile
 docs/faq/Makefile
 docs/tools/Makefile
 docs/tutorial/Makefile
@@ -1800,12 +1833,15 @@ gtk/theme-bits/Makefile
 gtk/tests/Makefile
 gtk/xdgmime/Makefile
 modules/Makefile
-modules/input/Makefile
+modules/other/Makefile
+modules/other/gail/Makefile
+modules/other/gail/libgail-util/Makefile
 modules/engines/Makefile
 modules/engines/pixbuf/Makefile
 modules/engines/ms-windows/Makefile
 modules/engines/ms-windows/Theme/Makefile
 modules/engines/ms-windows/Theme/gtk-2.0/Makefile
+modules/input/Makefile
 modules/printbackends/Makefile
 modules/printbackends/cups/Makefile
 modules/printbackends/lpr/Makefile
index 1748f8372b950e8b2ae7204fe71fe2e5e364b474..f4d7451db126653d5994e72d694c666f18ef6cdc 100644 (file)
@@ -1,5 +1,5 @@
 ## Process this file with automake to produce Makefile.in
 include $(top_srcdir)/Makefile.decl
 
-SUBDIRS = gdk-pixbuf gdk gtk
+SUBDIRS = gdk-pixbuf gdk gtk libgail-util
 
diff --git a/docs/reference/libgail-util/Makefile.am b/docs/reference/libgail-util/Makefile.am
new file mode 100644 (file)
index 0000000..a2f2e48
--- /dev/null
@@ -0,0 +1,33 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = 1.7
+
+# The name of the module.
+DOC_MODULE=gail-libgail-util
+
+# The top-level SGML file.
+DOC_MAIN_SGML_FILE=gail-libgail-util-docs.sgml
+
+# The directory containing the source code (if it contains documentation).
+DOC_SOURCE_DIR=../../../modules/other/gail/libgail-util
+
+# Used for dependencies
+HFILE_GLOB = $(top_srcdir)/modules/other/gail/libgail-util/*.h
+CFILE_GLOB = $(top_srcdir)/modules/other/gail/libgail-util/*.c
+
+# CFLAGS and LDFLAGS for compiling scan program. Only needed
+# if $(DOC_MODULE).types is non-empty.
+INCLUDES =                      \
+        -I$(top_srcdir)         \
+        -I$(top_builddir)       \
+        $(DEP_CFLAGS)
+
+GTKDOC_LIBS = $(top_builddir)/modules/other/gail/libgail-util/libgailutil.la
+
+# gtkdoc-mkdb related varaibles
+MKDB_OPTIONS =
+content_files =
+
+HTML_IMAGES =
+
+include $(top_srcdir)/gtk-doc.make
diff --git a/docs/reference/libgail-util/gail-libgail-util-docs.sgml b/docs/reference/libgail-util/gail-libgail-util-docs.sgml
new file mode 100644 (file)
index 0000000..97bb08b
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY gail-libgail-util-gailtextutil SYSTEM "xml/gailtextutil.xml">
+<!ENTITY gail-libgail-util-gailmisc SYSTEM "xml/gailmisc.xml">
+]>
+
+<book>
+  <bookinfo>
+    <title>GAIL Reference Manual</title>
+  </bookinfo>
+  <chapter id="libgail-util-main">
+    <title>GAIL libgail-util Library</title>
+    &gail-libgail-util-gailtextutil;
+    &gail-libgail-util-gailmisc;
+  </chapter>
+</book>
diff --git a/docs/reference/libgail-util/gail-libgail-util-overrides.txt b/docs/reference/libgail-util/gail-libgail-util-overrides.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs/reference/libgail-util/gail-libgail-util-sections.txt b/docs/reference/libgail-util/gail-libgail-util-sections.txt
new file mode 100644 (file)
index 0000000..1ef8ad4
--- /dev/null
@@ -0,0 +1,34 @@
+<SECTION>
+<FILE>gailtextutil</FILE>
+<TITLE>GailTextUtil</TITLE>
+GailTextUtil
+GailOffsetType
+gail_text_util_new
+gail_text_util_text_setup
+gail_text_util_buffer_setup
+gail_text_util_get_text
+gail_text_util_get_substring
+<SUBSECTION Standard>
+GailTextUtilClass
+GAIL_TEXT_UTIL
+GAIL_IS_TEXT_UTIL
+GAIL_TYPE_TEXT_UTIL
+GAIL_TEXT_UTIL_CLASS
+GAIL_IS_TEXT_UTIL_CLASS
+GAIL_TEXT_UTIL_GET_CLASS
+<SUBSECTION Private>
+gail_text_util_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gailmisc</FILE>
+<TITLE>GailMisc</TITLE>
+gail_misc_add_attribute
+gail_misc_layout_get_run_attributes
+gail_misc_get_default_attributes
+gail_misc_get_extents_from_pango_rectangle
+gail_misc_get_index_at_point_in_layout
+gail_misc_get_origins
+gail_misc_add_to_attr_set
+gail_misc_buffer_get_run_attributes
+</SECTION>
diff --git a/docs/reference/libgail-util/gail-libgail-util.types b/docs/reference/libgail-util/gail-libgail-util.types
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs/reference/libgail-util/tmpl/gail-libgail-util-unused.sgml b/docs/reference/libgail-util/tmpl/gail-libgail-util-unused.sgml
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs/reference/libgail-util/tmpl/gailmisc.sgml b/docs/reference/libgail-util/tmpl/gailmisc.sgml
new file mode 100644 (file)
index 0000000..6e9642d
--- /dev/null
@@ -0,0 +1,122 @@
+<!-- ##### SECTION Title ##### -->
+GailMisc
+
+<!-- ##### SECTION Short_Description ##### -->
+GailMisc is a set of utility functions which may be useful to implementors of
+Atk interfaces for custom widgets.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+GailMisc is a set of utility function which are used in the implemementation
+of Atk interfaces for Gtk widgets. They may be useful to implementors of 
+Atk interfaces for custom widgets.
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gail_misc_add_attribute ##### -->
+<para>
+
+</para>
+
+@attrib_set: 
+@attr: 
+@value: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gail_misc_layout_get_run_attributes ##### -->
+<para>
+
+</para>
+
+@attrib_set: 
+@layout: 
+@text: 
+@offset: 
+@start_offset: 
+@end_offset: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gail_misc_get_default_attributes ##### -->
+<para>
+
+</para>
+
+@attrib_set: 
+@layout: 
+@widget: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gail_misc_get_extents_from_pango_rectangle ##### -->
+<para>
+
+</para>
+
+@widget: 
+@char_rect: 
+@x_layout: 
+@y_layout: 
+@x: 
+@y: 
+@width: 
+@height: 
+@coords: 
+
+
+<!-- ##### FUNCTION gail_misc_get_index_at_point_in_layout ##### -->
+<para>
+
+</para>
+
+@widget: 
+@layout: 
+@x_layout: 
+@y_layout: 
+@x: 
+@y: 
+@coords: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gail_misc_get_origins ##### -->
+<para>
+
+</para>
+
+@widget: 
+@x_window: 
+@y_window: 
+@x_toplevel: 
+@y_toplevel: 
+
+
+<!-- ##### FUNCTION gail_misc_add_to_attr_set ##### -->
+<para>
+
+</para>
+
+@attrib_set: 
+@attrs: 
+@attr: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gail_misc_buffer_get_run_attributes ##### -->
+<para>
+
+</para>
+
+@buffer: 
+@offset: 
+@start_offset: 
+@end_offset: 
+@Returns: 
+
+
diff --git a/docs/reference/libgail-util/tmpl/gailtextutil.sgml b/docs/reference/libgail-util/tmpl/gailtextutil.sgml
new file mode 100644 (file)
index 0000000..6b35c2d
--- /dev/null
@@ -0,0 +1,92 @@
+<!-- ##### SECTION Title ##### -->
+GailTextUtil
+
+<!-- ##### SECTION Short_Description ##### -->
+GailTextUtil is a utility class which can be used to implement some of
+the AtkText functions for accessible objects which implement AtkText.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+GailTextUtil is a utility class which can be used to implement the
+AtkText functions which get text for accessible objects which implement
+AtkText.
+
+In GAIL it is used by the accsesible objects for GnomeCanvasText, GtkEntry,
+GtkLabel, GtkCellRendererText and GtkTextview.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### STRUCT GailTextUtil ##### -->
+<para>
+The GailTextCell structure should not be accessed directly.
+
+</para>
+
+@parent: 
+@buffer: 
+
+<!-- ##### ENUM GailOffsetType ##### -->
+<para>
+
+</para>
+
+@GAIL_BEFORE_OFFSET: 
+@GAIL_AT_OFFSET: 
+@GAIL_AFTER_OFFSET: 
+
+<!-- ##### FUNCTION gail_text_util_new ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION gail_text_util_text_setup ##### -->
+<para>
+
+</para>
+
+@textutil: 
+@text: 
+
+
+<!-- ##### FUNCTION gail_text_util_buffer_setup ##### -->
+<para>
+
+</para>
+
+@textutil: 
+@buffer: 
+
+
+<!-- ##### FUNCTION gail_text_util_get_text ##### -->
+<para>
+
+</para>
+
+@textutil: 
+@layout: 
+@function: 
+@boundary_type: 
+@offset: 
+@start_offset: 
+@end_offset: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gail_text_util_get_substring ##### -->
+<para>
+
+</para>
+
+@textutil: 
+@start_pos: 
+@end_pos: 
+@Returns: 
+
+
diff --git a/gail-uninstalled.pc.in b/gail-uninstalled.pc.in
new file mode 100644 (file)
index 0000000..63a49ad
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Gail
+Description: GNOME Accessibility Implementation Library
+Version: @VERSION@
+Requires: atk gtk+-2.0 
+Libs: ${pc_top_builddir}/${pcfiledir}/gail/libgail.la
+Cflags: -I${pc_top_builddir}/${pcfiledir}
diff --git a/gail.pc.in b/gail.pc.in
new file mode 100644 (file)
index 0000000..bab729a
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Gail
+Description: GNOME Accessibility Implementation Library
+Version: @VERSION@
+Requires: atk gtk+-2.0
+Libs: -L${libdir} -lgailutil
+Cflags: -I${includedir}/gail-1.0
index d8e0c5829097d44f550cf31e82ba8a2517c26d17..86a89af3c791c52485e3b03fb31d649c94ae6d15 100644 (file)
@@ -1,8 +1,7 @@
 include $(top_srcdir)/Makefile.decl
 
+SUBDIRS = input engines other
+
 if OS_UNIX
-PRINTBACKENDS_SUBDIR=printbackends
+SUBDIRS += printbackends
 endif
-
-SUBDIRS=input engines $(PRINTBACKENDS_SUBDIR)
-DIST_SUBDIRS=input engines printbackends
diff --git a/modules/other/Makefile.am b/modules/other/Makefile.am
new file mode 100644 (file)
index 0000000..37488eb
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = gail
diff --git a/modules/other/gail/Makefile.am b/modules/other/gail/Makefile.am
new file mode 100644 (file)
index 0000000..0825a41
--- /dev/null
@@ -0,0 +1,173 @@
+include $(top_srcdir)/Makefile.decl
+
+SUBDIRS = libgail-util
+
+if OS_WIN32
+no_undefined = -no-undefined
+endif
+
+moduledir = $(libdir)/gtk-2.0/$(GTK_BINARY_VERSION)/other
+module_LTLIBRARIES = libgail.la
+
+gail_c_sources =                       \
+       gail-private-macros.h           \
+       gail.c                          \
+       gailadjustment.c                \
+       gailarrow.c                     \
+       gailbooleancell.c               \
+       gailbooleancellfactory.c        \
+       gailbox.c                       \
+       gailbutton.c                    \
+       gailcalendar.c                  \
+       gailcell.c                      \
+       gailcellparent.c                \
+       gailcheckmenuitem.c             \
+       gailchecksubmenuitem.c          \
+       gailclist.c                     \
+       gailclistcell.c                 \
+       gailcombo.c                     \
+       gailcombobox.c                  \
+       gailcontainer.c                 \
+       gailcontainercell.c             \
+       gailentry.c                     \
+       gailexpander.c                  \
+       gailframe.c                     \
+       gailimage.c                     \
+       gailimagecell.c                 \
+       gailimagecellfactory.c          \
+       gailitem.c                      \
+       gaillabel.c                     \
+       gaillist.c                      \
+       gailmenu.c                      \
+       gailmenushell.c                 \
+       gailmenuitem.c                  \
+       gailnotebook.c                  \
+       gailnotebookpage.c              \
+       gailobject.c                    \
+       gailobjectfactory.c             \
+       gailoptionmenu.c                \
+       gailpaned.c                     \
+       gailpixmap.c                    \
+       gailprogressbar.c               \
+       gailradiobutton.c               \
+       gailradiomenuitem.c             \
+       gailradiosubmenuitem.c          \
+       gailrange.c                     \
+       gailrenderercell.c              \
+       gailrenderercellfactory.c       \
+       gailscale.c                     \
+       gailscrollbar.c                 \
+       gailscrolledwindow.c            \
+       gailseparator.c                 \
+       gailspinbutton.c                \
+       gailsubmenuitem.c               \
+       gailstatusbar.c                 \
+       gailtextcell.c                  \
+       gailtextcellfactory.c           \
+       gailtextview.c                  \
+       gailtogglebutton.c              \
+       gailtoplevel.c                  \
+       gailtreeview.c                  \
+       gailutil.c                      \
+       gailwidget.c                    \
+       gailwindow.c
+
+libgailincludedir=$(includedir)/gail-1.0/gail
+
+gail_private_h_sources =               \
+       gail.h                          \
+       gailadjustment.h                \
+       gailarrow.h                     \
+       gailbooleancell.h               \
+       gailbooleancellfactory.h        \
+       gailbox.h                       \
+       gailbutton.h                    \
+       gailcalendar.h                  \
+       gailcell.h                      \
+       gailcellparent.h                \
+       gailcheckmenuitem.h             \
+       gailchecksubmenuitem.h          \
+       gailclist.h                     \
+       gailclistcell.h                 \
+       gailcombo.h                     \
+       gailcombobox.h                  \
+       gailcontainercell.h             \
+       gailcontainer.h                 \
+       gailentry.h                     \
+       gailexpander.h                  \
+       gailfactory.h                   \
+       gailframe.h                     \
+       gailimage.h                     \
+       gailimagecell.h                 \
+       gailimagecellfactory.h          \
+       gailintl.h                      \
+       gailitem.h                      \
+       gaillabel.h                     \
+       gaillist.h                      \
+       gailmenu.h                      \
+       gailmenushell.h                 \
+       gailmenuitem.h                  \
+       gailnotebook.h                  \
+       gailnotebookpage.h              \
+       gailobject.h                    \
+       gailobjectfactory.h             \
+       gailoptionmenu.h                \
+       gailpaned.h                     \
+       gailpixmap.h                    \
+       gailprogressbar.h               \
+       gailradiobutton.h               \
+       gailradiomenuitem.h             \
+       gailradiosubmenuitem.h          \
+       gailrange.h                     \
+       gailrenderercell.h              \
+       gailrenderercellfactory.h       \
+       gailscale.h                     \
+       gailscrollbar.h                 \
+       gailscrolledwindow.h            \
+       gailseparator.h                 \
+       gailspinbutton.h                \
+       gailsubmenuitem.h               \
+       gailstatusbar.h                 \
+       gailtextcell.h                  \
+       gailtextcellfactory.h           \
+       gailtextview.h                  \
+       gailtogglebutton.h              \
+       gailtoplevel.h                  \
+       gailtreeview.h                  \
+       gailutil.h                      \
+       gailwindow.h
+
+gail_public_h_sources =        \
+       gailwidget.h
+
+libgail_la_SOURCES =                   \
+       $(gail_c_sources)               \
+       $(gail_public_h_sources)        \
+       $(gail_private_h_sources)
+
+libgailinclude_HEADERS =               \
+       $(gail_public_h_sources)
+
+libgail_la_CPPFLAGS = \
+       -I$(top_srcdir)/modules/other   \
+       -I$(top_srcdir)/gdk     \
+       -I$(top_builddir)/gdk   \
+       -I$(top_srcdir)/gtk     \
+       -I$(top_builddir)/gtk   \
+       -DGTK_VERSION=\"$(GTK_VERSION)\"        \
+       $(AM_CPPFLAGS)
+       
+libgail_la_CFLAGS = \
+       $(GTK_DEP_CFLAGS)       \
+       $(GTK_DEBUG_FLAGS)      \
+       $(AM_CFLAGS)
+
+libgail_la_LIBADD =  \
+        $(GTK_DEP_LIBS)        \
+       $(INTLLIBS)
+
+libgail_la_LDFLAGS =    \
+       $(top_builddir)/modules/other/gail/libgail-util/libgailutil.la  \
+       -rpath $(moduledir) -module -avoid-version \
+       $(no_undefined) \
+        $(LDFLAGS)
diff --git a/modules/other/gail/gail-private-macros.h b/modules/other/gail/gail-private-macros.h
new file mode 100644 (file)
index 0000000..bb2022b
--- /dev/null
@@ -0,0 +1,38 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_PRIVATE_MACROS_H__
+#define __GAIL_PRIVATE_MACROS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Note: these macros are logic macros, not intended to warn on failure. */
+
+#define gail_return_val_if_fail(a, b)  if (!(a)) return (b)
+#define gail_return_if_fail(a) if (!(a)) return
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_PRIVATE_MACROS_H__ */
diff --git a/modules/other/gail/gail.c b/modules/other/gail/gail.c
new file mode 100644 (file)
index 0000000..217eb8c
--- /dev/null
@@ -0,0 +1,982 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <stdio.h>
+#include <stdlib.h>
+#include <atk/atk.h>
+#include <gtk/gtk.h>
+#include "gail.h"
+#include "gailfactory.h"
+
+#define GNOME_ACCESSIBILITY_ENV "GNOME_ACCESSIBILITY"
+
+static gboolean gail_focus_watcher      (GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static gboolean gail_select_watcher     (GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static gboolean gail_deselect_watcher   (GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static gboolean gail_switch_page_watcher(GSignalInvocationHint *ihint,
+                                         guint                  n_param_values,
+                                         const GValue          *param_values,
+                                         gpointer               data);
+static AtkObject* gail_get_accessible_for_widget (GtkWidget    *widget,
+                                                  gboolean     *transient);
+static void     gail_finish_select       (GtkWidget            *widget);
+static void     gail_map_cb              (GtkWidget            *widget);
+static void     gail_map_submenu_cb      (GtkWidget            *widget);
+static gint     gail_focus_idle_handler  (gpointer             data);
+static void     gail_focus_notify        (GtkWidget            *widget);
+static void     gail_focus_notify_when_idle (GtkWidget            *widget);
+
+static void     gail_focus_tracker_init (void);
+static void     gail_focus_object_destroyed (gpointer data);
+static void     gail_focus_tracker (AtkObject *object);
+static void     gail_set_focus_widget (GtkWidget *focus_widget,
+                                       GtkWidget *widget); 
+static void     gail_set_focus_object (AtkObject *focus_obj,
+                                       AtkObject *obj);
+
+GtkWidget* focus_widget = NULL;
+static GtkWidget* next_focus_widget = NULL;
+static gboolean was_deselect = FALSE;
+static GtkWidget* subsequent_focus_widget = NULL;
+static GtkWidget* focus_before_menu = NULL;
+static guint focus_notify_handler = 0;    
+static guint focus_tracker_id = 0;
+static GQuark quark_focus_object = 0;
+
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_WIDGET, gail_widget, gail_widget_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_CONTAINER, gail_container, gail_container_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_BUTTON, gail_button, gail_button_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_ITEM, gail_item, gail_item_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_MENU_ITEM, gail_menu_item, gail_menu_item_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_TOGGLE_BUTTON, gail_toggle_button, gail_toggle_button_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_IMAGE, gail_image, gail_image_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_TEXT_VIEW, gail_text_view, gail_text_view_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_COMBO, gail_combo, gail_combo_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_COMBO_BOX, gail_combo_box, gail_combo_box_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_ENTRY, gail_entry, gail_entry_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_MENU_SHELL, gail_menu_shell, gail_menu_shell_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_MENU, gail_menu, gail_menu_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_WINDOW, gail_window, gail_window_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_RANGE, gail_range, gail_range_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_SCALE, gail_scale, gail_scale_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_CLIST, gail_clist, gail_clist_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_LABEL, gail_label, gail_label_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_STATUSBAR, gail_statusbar, gail_statusbar_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_NOTEBOOK, gail_notebook, gail_notebook_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_CALENDAR, gail_calendar, gail_calendar_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_PROGRESS_BAR, gail_progress_bar, gail_progress_bar_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_SPIN_BUTTON, gail_spin_button, gail_spin_button_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_TREE_VIEW, gail_tree_view, gail_tree_view_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_FRAME, gail_frame, gail_frame_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_RADIO_BUTTON, gail_radio_button, gail_radio_button_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_ARROW, gail_arrow, gail_arrow_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_PIXMAP, gail_pixmap, gail_pixmap_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_SEPARATOR, gail_separator, gail_separator_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_BOX, gail_box, gail_box_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_SCROLLED_WINDOW, gail_scrolled_window, gail_scrolled_window_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_LIST, gail_list, gail_list_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_PANED, gail_paned, gail_paned_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_SCROLLBAR, gail_scrollbar, gail_scrollbar_new)
+GAIL_ACCESSIBLE_FACTORY (GAIL_TYPE_OPTION_MENU, gail_option_menu, gail_option_menu_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_EXPANDER, gail_expander, gail_expander_new)
+
+static AtkObject*
+gail_get_accessible_for_widget (GtkWidget *widget,
+                                gboolean  *transient)
+{
+  AtkObject *obj = NULL;
+  GType gnome_canvas;
+
+  gnome_canvas = g_type_from_name ("GnomeCanvas");
+
+  *transient = FALSE;
+  if (!widget)
+    return NULL;
+
+  if (GTK_IS_ENTRY (widget))
+    {
+      GtkWidget *other_widget = widget->parent;
+      if (GTK_IS_COMBO (other_widget))
+        {
+          gail_set_focus_widget (other_widget, widget);
+          widget = other_widget;
+        }
+    } 
+  else if (GTK_IS_NOTEBOOK (widget)) 
+    {
+      GtkNotebook *notebook;
+      gint page_num = -1;
+
+      notebook = GTK_NOTEBOOK (widget);
+      /*
+       * Report the currently focused tab rather than the currently selected tab
+       */
+      if (notebook->focus_tab)
+        {
+          page_num = g_list_index (notebook->children, notebook->focus_tab->data);
+        }
+      if (page_num != -1)
+        {
+          obj = gtk_widget_get_accessible (widget);
+          obj = atk_object_ref_accessible_child (obj, page_num);
+          g_object_unref (obj);
+        }
+    }
+  else if (GTK_CHECK_TYPE ((widget), gnome_canvas))
+    {
+      GObject *focused_item;
+      GValue value = {0, };
+
+      g_value_init (&value, G_TYPE_OBJECT);
+      g_object_get_property (G_OBJECT (widget), "focused_item", &value);
+      focused_item = g_value_get_object (&value);
+
+      if (focused_item)
+        {
+          AtkObject *tmp;
+
+          obj = atk_gobject_accessible_for_object (G_OBJECT (focused_item));
+          tmp = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
+          if (tmp != NULL)
+            obj = tmp;
+        }
+    }
+  else if (GTK_IS_TOGGLE_BUTTON (widget))
+    {
+      GtkWidget *other_widget = widget->parent;
+      if (GTK_IS_COMBO_BOX (other_widget))
+        {
+          gail_set_focus_widget (other_widget, widget);
+          widget = other_widget;
+        }
+    }
+  if (obj == NULL)
+    {
+      AtkObject *focus_object;
+
+      obj = gtk_widget_get_accessible (widget);
+      focus_object = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
+      /*
+       * We check whether the object for this focus_object has been deleted.
+       * This can happen when navigating to an empty directory in nautilus. 
+       * See bug #141907.
+       */
+      if (ATK_IS_GOBJECT_ACCESSIBLE (focus_object))
+        {
+          if (!atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (focus_object)))
+            focus_object = NULL;
+        }
+      if (focus_object)
+        obj = focus_object;
+    }
+
+  return obj;
+}
+
+static gboolean
+gail_focus_watcher (GSignalInvocationHint *ihint,
+                    guint                  n_param_values,
+                    const GValue          *param_values,
+                    gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  GdkEvent *event;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  event = g_value_get_boxed (param_values + 1);
+  widget = GTK_WIDGET (object);
+
+  if (event->type == GDK_FOCUS_CHANGE) 
+    {
+      if (event->focus_change.in)
+        {
+          if (GTK_IS_WINDOW (widget))
+            {
+              GtkWindow *window;
+
+              window = GTK_WINDOW (widget);
+              if (window->focus_widget)
+                {
+                  /*
+                   * If we already have a potential focus widget set this
+                   * windows's focus widget to focus_before_menu so that 
+                   * it will be reported when menu item is unset.
+                   */
+                  if (next_focus_widget)
+                    {
+                      if (GTK_IS_MENU_ITEM (next_focus_widget) &&
+                          !focus_before_menu)
+                        {
+                          void *vp_focus_before_menu = &focus_before_menu;
+                          focus_before_menu = window->focus_widget;
+                          g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
+                        }
+
+                      return TRUE;
+                    }
+                  widget = window->focus_widget;
+                }
+              else if (window->type == GTK_WINDOW_POPUP) 
+                {
+                 if (GTK_IS_BIN (widget))
+                   {
+                     GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
+
+                     if (GTK_IS_WIDGET (child) && GTK_WIDGET_HAS_GRAB (child))
+                       {
+                         if (GTK_IS_MENU_SHELL (child))
+                           {
+                             if (GTK_MENU_SHELL (child)->active_menu_item)
+                               {
+                                 /*
+                                  * We have a menu which has a menu item selected
+                                  * so we do not report focus on the menu.
+                                  */ 
+                                 return TRUE; 
+                               }
+                           }
+                         widget = child;
+                       } 
+                   }
+                 else /* popup window has no children; this edge case occurs in some custom code (OOo for instance) */
+                   {
+                     return TRUE;
+                   }
+                }
+             else /* Widget is a non-popup toplevel with no focus children; 
+                     don't emit for this case either, as it's useless */
+               {
+                 return TRUE;
+               }
+            }
+        }
+      else
+        {
+          if (next_focus_widget)
+            {
+               GtkWidget *toplevel;
+
+               toplevel = gtk_widget_get_toplevel (next_focus_widget);
+               if (toplevel == widget)
+                 next_focus_widget = NULL; 
+            }
+          /* focus out */
+          widget = NULL;
+        }
+    }
+  else
+    {
+      if (event->type == GDK_MOTION_NOTIFY && GTK_WIDGET_HAS_FOCUS (widget))
+        {
+          if (widget == focus_widget)
+            {
+              return TRUE;
+            }
+        }
+      else
+        {
+          return TRUE;
+        }
+    }
+  /*
+   * If the focus widget is a GtkSocket without a plug
+   * then ignore the focus notification as the embedded
+   * plug will report a focus notification.
+   */
+  if (GTK_IS_SOCKET (widget) &&
+      GTK_SOCKET (widget)->plug_widget == NULL)
+    return TRUE;
+  /*
+   * The widget may not yet be visible on the screen so we wait until it is.
+   */
+  gail_focus_notify_when_idle (widget);
+  return TRUE; 
+}
+
+static gboolean
+gail_select_watcher (GSignalInvocationHint *ihint,
+                     guint                  n_param_values,
+                     const GValue          *param_values,
+                     gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  widget = GTK_WIDGET (object);
+
+  if (!GTK_WIDGET_MAPPED (widget))
+    {
+      g_signal_connect (widget, "map",
+                        G_CALLBACK (gail_map_cb),
+                        NULL);
+    }
+  else
+    gail_finish_select (widget);
+
+  return TRUE;
+}
+
+static void
+gail_finish_select (GtkWidget *widget)
+{
+  if (GTK_IS_MENU_ITEM (widget))
+    {
+      GtkMenuItem* menu_item;
+
+      menu_item = GTK_MENU_ITEM (widget);
+      if (menu_item->submenu &&
+          !GTK_WIDGET_MAPPED (menu_item->submenu))
+        {
+          /*
+           * If the submenu is not visble, wait until it is before
+           * reporting focus on the menu item.
+           */
+          gulong handler_id;
+
+          handler_id = g_signal_handler_find (menu_item->submenu,
+                                              G_SIGNAL_MATCH_FUNC,
+                                              g_signal_lookup ("map",
+                                                               GTK_TYPE_WINDOW),
+                                              0,
+                                              NULL,
+                                              (gpointer) gail_map_submenu_cb,
+                                              NULL); 
+          if (!handler_id)
+            g_signal_connect (menu_item->submenu, "map",
+                              G_CALLBACK (gail_map_submenu_cb),
+                              NULL);
+            return;
+
+        }
+      /*
+       * If we are waiting to report focus on a menubar or a menu item
+       * because of a previous deselect, cancel it.
+       */
+      if (was_deselect &&
+          focus_notify_handler &&
+          next_focus_widget &&
+          (GTK_IS_MENU_BAR (next_focus_widget) ||
+           GTK_IS_MENU_ITEM (next_focus_widget)))
+        {
+          void *vp_next_focus_widget = &next_focus_widget;
+          g_source_remove (focus_notify_handler);
+          g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+         next_focus_widget = NULL;
+          focus_notify_handler = 0;
+          was_deselect = FALSE;
+        }
+    } 
+  /*
+   * If previously focused widget is not a GtkMenuItem or a GtkMenu,
+   * keep track of it so we can return to it after menubar is deactivated
+   */
+  if (focus_widget && 
+      !GTK_IS_MENU_ITEM (focus_widget) && 
+      !GTK_IS_MENU (focus_widget))
+    {
+      void *vp_focus_before_menu = &focus_before_menu;
+      focus_before_menu = focus_widget;
+      g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
+
+    } 
+  gail_focus_notify_when_idle (widget);
+
+  return; 
+}
+
+static void
+gail_map_cb (GtkWidget *widget)
+{
+  gail_finish_select (widget);
+}
+
+static void
+gail_map_submenu_cb (GtkWidget *widget)
+{
+  if (GTK_IS_MENU (widget))
+    {
+      if (GTK_MENU (widget)->parent_menu_item)
+        gail_finish_select (GTK_MENU (widget)->parent_menu_item);
+    }
+}
+
+
+static gboolean
+gail_deselect_watcher (GSignalInvocationHint *ihint,
+                       guint                  n_param_values,
+                       const GValue          *param_values,
+                       gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  GtkWidget *menu_shell;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  widget = GTK_WIDGET (object);
+
+  if (!GTK_IS_MENU_ITEM (widget))
+    return TRUE;
+
+  if (subsequent_focus_widget == widget)
+    subsequent_focus_widget = NULL;
+
+  menu_shell = gtk_widget_get_parent (widget);
+  if (GTK_IS_MENU_SHELL (menu_shell))
+    {
+      GtkWidget *parent_menu_shell;
+
+      parent_menu_shell = GTK_MENU_SHELL (menu_shell)->parent_menu_shell;
+      if (parent_menu_shell)
+        {
+          GtkWidget *active_menu_item;
+
+          active_menu_item = GTK_MENU_SHELL (parent_menu_shell)->active_menu_item;
+          if (active_menu_item)
+            {
+              gail_focus_notify_when_idle (active_menu_item);
+            }
+        }
+      else
+        {
+          if (!GTK_IS_MENU_BAR (menu_shell))
+            {
+              gail_focus_notify_when_idle (menu_shell);
+            }
+        }
+    }
+  was_deselect = TRUE;
+  return TRUE; 
+}
+
+static gboolean 
+gail_switch_page_watcher (GSignalInvocationHint *ihint,
+                          guint                  n_param_values,
+                          const GValue          *param_values,
+                          gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  GtkNotebook *notebook;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+
+  widget = GTK_WIDGET (object);
+
+  if (!GTK_IS_NOTEBOOK (widget))
+    return TRUE;
+
+  notebook = GTK_NOTEBOOK (widget);
+  if (!notebook->focus_tab)
+    return TRUE;
+
+  gail_focus_notify_when_idle (widget);
+  return TRUE;
+}
+
+
+static gint
+gail_focus_idle_handler (gpointer data)
+{
+  GDK_THREADS_ENTER();
+
+  focus_notify_handler = 0;
+  /*
+   * The widget which was to receive focus may have been removed
+   */
+  if (!next_focus_widget)
+    {
+      if (next_focus_widget != data)
+       {
+         GDK_THREADS_LEAVE ();
+         return FALSE;
+       }
+    }
+  else
+    {
+      void *vp_next_focus_widget = &next_focus_widget;
+      g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+      next_focus_widget = NULL;
+    }
+    
+  gail_focus_notify (data);
+
+  GDK_THREADS_LEAVE ();
+  return FALSE; 
+}
+
+static void
+gail_focus_notify (GtkWidget *widget)
+{
+  AtkObject *atk_obj;
+  gboolean transient;
+
+  if (widget != focus_widget)
+    {
+      if (focus_widget)
+        {
+          void *vp_focus_widget = &focus_widget;
+          g_object_remove_weak_pointer (G_OBJECT (focus_widget), vp_focus_widget);
+        }
+      focus_widget = widget;
+      if (focus_widget)
+        {
+          void *vp_focus_widget = &focus_widget;
+          g_object_add_weak_pointer (G_OBJECT (focus_widget), vp_focus_widget);
+          /*
+           * The UI may not have been updated yet; e.g. in gtkhtml2
+           * html_view_layout() is called in a idle handler
+           */
+          if (focus_widget == focus_before_menu)
+            {
+              void *vp_focus_before_menu = &focus_before_menu;
+              g_object_remove_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu);
+              focus_before_menu = NULL;
+            }
+        }
+      gail_focus_notify_when_idle (focus_widget);
+    }
+  else
+    {
+      if (focus_widget)
+        atk_obj  = gail_get_accessible_for_widget (focus_widget, &transient);
+      else
+        atk_obj = NULL;
+      /*
+       * Do not report focus on redundant object
+       */
+      if (atk_obj && 
+         (atk_object_get_role(atk_obj) != ATK_ROLE_REDUNDANT_OBJECT))
+         atk_focus_tracker_notify (atk_obj);
+      if (atk_obj && transient)
+        g_object_unref (atk_obj);
+      if (subsequent_focus_widget)
+        {
+          GtkWidget *tmp_widget = subsequent_focus_widget;
+          subsequent_focus_widget = NULL;
+          gail_focus_notify_when_idle (tmp_widget);
+        }
+    }
+}
+
+static void
+gail_focus_notify_when_idle (GtkWidget *widget)
+{
+  if (focus_notify_handler)
+    {
+      if (widget)
+        {
+          /*
+           * Ignore focus request when menu item is going to be focused.
+           * See bug #124232.
+           */
+          if (GTK_IS_MENU_ITEM (next_focus_widget) && !GTK_IS_MENU_ITEM (widget))
+            return;
+
+          if (next_focus_widget)
+            {
+              if (GTK_IS_MENU_ITEM (next_focus_widget) && GTK_IS_MENU_ITEM (widget))
+                {
+                  if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (next_focus_widget)) == gtk_widget_get_parent (widget))
+                    {
+                      if (subsequent_focus_widget)
+                        g_assert_not_reached ();
+                      subsequent_focus_widget = widget;
+                      return;
+                    } 
+                }
+            }
+          g_source_remove (focus_notify_handler);
+          if (next_focus_widget)
+           {
+             void *vp_next_focus_widget = &next_focus_widget;
+             g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+             next_focus_widget = NULL;
+           }
+        }
+      else
+        /*
+         * Ignore if focus is being set to NULL and we are waiting to set focus
+         */
+        return;
+    }
+
+  if (widget)
+    {
+      void *vp_next_focus_widget = &next_focus_widget;
+      next_focus_widget = widget;
+      g_object_add_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+    }
+  else
+    {
+      /*
+       * We are about to report focus as NULL so remove the weak pointer
+       * for the widget we were waiting to report focus on.
+       */ 
+      if (next_focus_widget)
+        {
+          void *vp_next_focus_widget = &next_focus_widget;
+          g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+          next_focus_widget = NULL;
+        }
+    }
+
+  focus_notify_handler = g_idle_add (gail_focus_idle_handler, widget);
+}
+
+static gboolean
+gail_deactivate_watcher (GSignalInvocationHint *ihint,
+                         guint                  n_param_values,
+                         const GValue          *param_values,
+                         gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  GtkMenuShell *shell;
+  GtkWidget *focus = NULL;
+
+  object = g_value_get_object (param_values + 0);
+  g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE);
+  widget = GTK_WIDGET (object);
+
+  g_return_val_if_fail (GTK_IS_MENU_SHELL(widget), TRUE);
+  shell = GTK_MENU_SHELL(widget);
+  if (!shell->parent_menu_shell)
+    focus = focus_before_menu;
+      
+  /*
+   * If we are waiting to report focus on a menubar or a menu item
+   * because of a previous deselect, cancel it.
+   */
+  if (was_deselect &&
+      focus_notify_handler &&
+      next_focus_widget &&
+      (GTK_IS_MENU_BAR (next_focus_widget) ||
+       GTK_IS_MENU_ITEM (next_focus_widget)))
+    {
+      void *vp_next_focus_widget = &next_focus_widget;
+      g_source_remove (focus_notify_handler);
+      g_object_remove_weak_pointer (G_OBJECT (next_focus_widget), vp_next_focus_widget);
+      next_focus_widget = NULL;
+      focus_notify_handler = 0;
+      was_deselect = FALSE;
+    }
+  gail_focus_notify_when_idle (focus);
+
+  return TRUE; 
+}
+
+static void
+gail_focus_tracker_init (void)
+{
+  static gboolean  emission_hooks_added = FALSE;
+
+  if (!emission_hooks_added)
+    {
+      /*
+       * We cannot be sure that the classes exist so we make sure that they do.
+       */
+      gtk_type_class (GTK_TYPE_WIDGET);
+      gtk_type_class (GTK_TYPE_ITEM);
+      gtk_type_class (GTK_TYPE_MENU_SHELL);
+      gtk_type_class (GTK_TYPE_NOTEBOOK);
+
+      /*
+       * We listen for event_after signal and then check that the
+       * event was a focus in event so we get called after the event.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("event-after", GTK_TYPE_WIDGET), 0,
+             gail_focus_watcher, NULL, (GDestroyNotify) NULL);
+      /*
+       * A "select" signal is emitted when arrow key is used to
+       * move to a list item in the popup window of a GtkCombo or
+       * a menu item in a menu.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("select", GTK_TYPE_ITEM), 0,
+             gail_select_watcher, NULL, (GDestroyNotify) NULL);
+
+      /*
+       * A "deselect" signal is emitted when arrow key is used to
+       * move from a menu item in a menu to the parent menu.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("deselect", GTK_TYPE_ITEM), 0,
+             gail_deselect_watcher, NULL, (GDestroyNotify) NULL);
+
+      /*
+       * We listen for deactivate signals on menushells to determine
+       * when the "focus" has left the menus.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("deactivate", GTK_TYPE_MENU_SHELL), 0,
+             gail_deactivate_watcher, NULL, (GDestroyNotify) NULL);
+
+      /*
+       * We listen for "switch-page" signal on a GtkNotebook to notify
+       * when page has changed because of clicking on a notebook tab.
+       */
+      g_signal_add_emission_hook (
+             g_signal_lookup ("switch-page", GTK_TYPE_NOTEBOOK), 0,
+             gail_switch_page_watcher, NULL, (GDestroyNotify) NULL);
+      emission_hooks_added = TRUE;
+    }
+}
+
+static void
+gail_focus_object_destroyed (gpointer data)
+{
+  GObject *obj;
+
+  obj = G_OBJECT (data);
+  g_object_set_qdata (obj, quark_focus_object, NULL);
+  g_object_unref (obj); 
+}
+
+static void
+gail_focus_tracker (AtkObject *focus_object)
+{
+  /*
+   * Do not report focus on redundant object
+   */
+  if (focus_object && 
+      (atk_object_get_role(focus_object) != ATK_ROLE_REDUNDANT_OBJECT))
+    {
+      AtkObject *old_focus_object;
+
+      if (!GTK_IS_ACCESSIBLE (focus_object))
+        {
+          AtkObject *parent;
+
+          parent = focus_object;
+          while (1)
+            {
+              parent = atk_object_get_parent (parent);
+              if (parent == NULL)
+                break;
+              if (GTK_IS_ACCESSIBLE (parent))
+                break;
+            }
+
+          if (parent)
+            {
+              gail_set_focus_object (focus_object, parent);
+            }
+        }
+      else
+        {
+          old_focus_object = g_object_get_qdata (G_OBJECT (focus_object), quark_focus_object);
+          if (old_focus_object)
+            {
+              g_object_weak_unref (G_OBJECT (old_focus_object),
+                                   (GWeakNotify) gail_focus_object_destroyed,
+                                   focus_object);
+              g_object_set_qdata (G_OBJECT (focus_object), quark_focus_object, NULL);
+              g_object_unref (G_OBJECT (focus_object));
+            }
+        }
+    }
+}
+
+static void 
+gail_set_focus_widget (GtkWidget *focus_widget,
+                       GtkWidget *widget)
+{
+  AtkObject *focus_obj;
+  AtkObject *obj;
+
+  focus_obj = gtk_widget_get_accessible (focus_widget);
+  obj = gtk_widget_get_accessible (widget);
+  gail_set_focus_object (focus_obj, obj);
+}
+
+static void 
+gail_set_focus_object (AtkObject *focus_obj,
+                       AtkObject *obj)
+{
+  AtkObject *old_focus_obj;
+
+  old_focus_obj = g_object_get_qdata (G_OBJECT (obj), quark_focus_object);
+  if (old_focus_obj != obj)
+    {
+      if (old_focus_obj)
+        g_object_weak_unref (G_OBJECT (old_focus_obj),
+                             (GWeakNotify) gail_focus_object_destroyed,
+                             obj);
+      else
+        /*
+         * We call g_object_ref as if obj is destroyed 
+         * while the weak reference exists then destroying the 
+         * focus_obj would cause gail_focus_object_destroyed to be 
+         * called when obj is not a valid GObject.
+         */
+        g_object_ref (obj);
+
+      g_object_weak_ref (G_OBJECT (focus_obj),
+                         (GWeakNotify) gail_focus_object_destroyed,
+                         obj);
+      g_object_set_qdata (G_OBJECT (obj), quark_focus_object, focus_obj);
+    }
+}
+
+/*
+ *   These exported symbols are hooked by gnome-program
+ * to provide automatic module initialization and shutdown.
+ */
+extern void gnome_accessibility_module_init     (void);
+extern void gnome_accessibility_module_shutdown (void);
+
+static int gail_initialized = FALSE;
+
+static void
+gail_accessibility_module_init (void)
+{
+  const char *env_a_t_support;
+  gboolean a_t_support = FALSE;
+
+  if (gail_initialized)
+    {
+      return;
+    }
+  gail_initialized = TRUE;
+  quark_focus_object = g_quark_from_static_string ("gail-focus-object");
+  
+  env_a_t_support = g_getenv (GNOME_ACCESSIBILITY_ENV);
+
+  if (env_a_t_support)
+    a_t_support = atoi (env_a_t_support);
+  if (a_t_support)
+    fprintf (stderr, "GTK Accessibility Module initialized\n");
+
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_WIDGET, gail_widget);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CONTAINER, gail_container);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_BUTTON, gail_button);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_ITEM, gail_item);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU_ITEM, gail_menu_item);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TOGGLE_BUTTON, gail_toggle_button);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_IMAGE, gail_image);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TEXT_VIEW, gail_text_view);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_COMBO, gail_combo);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_COMBO_BOX, gail_combo_box);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_ENTRY, gail_entry);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU_BAR, gail_menu_shell);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_MENU, gail_menu);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_WINDOW, 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);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_NOTEBOOK, gail_notebook);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CALENDAR, gail_calendar);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PROGRESS_BAR, gail_progress_bar);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SPIN_BUTTON, gail_spin_button);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_TREE_VIEW, gail_tree_view);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_FRAME, gail_frame);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_TEXT, gail_text_cell);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_TOGGLE, gail_boolean_cell);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER_PIXBUF, gail_image_cell);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CELL_RENDERER, gail_renderer_cell);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RADIO_BUTTON, gail_radio_button);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_ARROW, gail_arrow);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PIXMAP, gail_pixmap);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SEPARATOR, gail_separator);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_BOX, gail_box);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCROLLED_WINDOW, gail_scrolled_window);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_LIST, gail_list);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_PANED, gail_paned);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_SCROLLBAR, gail_scrollbar);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_OPTION_MENU, gail_option_menu);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_CHECK_MENU_ITEM, gail_check_menu_item);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_RADIO_MENU_ITEM, gail_radio_menu_item);
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_EXPANDER, gail_expander);
+
+  /* LIBGNOMECANVAS SUPPORT */
+  GAIL_WIDGET_SET_FACTORY (GTK_TYPE_OBJECT, gail_object);
+
+  atk_focus_tracker_init (gail_focus_tracker_init);
+  focus_tracker_id = atk_add_focus_tracker (gail_focus_tracker);
+
+  /* Initialize the GailUtility class */
+  g_type_class_unref (g_type_class_ref (GAIL_TYPE_UTIL));
+  g_type_class_unref (g_type_class_ref (GAIL_TYPE_MISC));
+}
+
+/**
+ * gnome_accessibility_module_init:
+ * @void: 
+ * 
+ *   This method is invoked by name from libgnome's
+ * gnome-program.c to activate accessibility support.
+ **/
+void
+gnome_accessibility_module_init (void)
+{
+  gail_accessibility_module_init ();
+}
+
+/**
+ * gnome_accessibility_module_shutdown:
+ * @void: 
+ * 
+ *   This method is invoked by name from libgnome's
+ * gnome-program.c to de-activate accessibility support.
+ **/
+void
+gnome_accessibility_module_shutdown (void)
+{
+  if (!gail_initialized)
+    {
+      return;
+    }
+  gail_initialized = FALSE;
+  atk_remove_focus_tracker (focus_tracker_id);
+
+  fprintf (stderr, "GTK Accessibility Module shutdown\n");
+
+  /* FIXME: de-register the factory types so we can unload ? */
+}
+
+int
+gtk_module_init (gint *argc, char** argv[])
+{
+  gail_accessibility_module_init ();
+
+  return 0;
+}
diff --git a/modules/other/gail/gail.h b/modules/other/gail/gail.h
new file mode 100644 (file)
index 0000000..5ee6277
--- /dev/null
@@ -0,0 +1,54 @@
+#include <gail/gailadjustment.h>
+#include <gail/gailarrow.h>
+#include <gail/gailbooleancell.h>
+#include <gail/gailbooleancellfactory.h>
+#include <gail/gailbox.h>
+#include <gail/gailbutton.h>
+#include <gail/gailcalendar.h>
+#include <gail/gailcell.h>
+#include <gail/gailcheckmenuitem.h>
+#include <gail/gailclist.h>
+#include <gail/gailclistcell.h>
+#include <gail/gailcombo.h>
+#include <gail/gailcombobox.h>
+#include <gail/gailcontainer.h>
+#include <gail/gailcontainercell.h>
+#include <gail/gailentry.h>
+#include <gail/gailexpander.h>
+#include <gail/gailframe.h>
+#include <gail/gailimage.h>
+#include <gail/gailimagecell.h>
+#include <gail/gailimagecellfactory.h>
+#include <gail/gailitem.h>
+#include <gail/gaillabel.h>
+#include <gail/gaillist.h>
+#include <gail/gailmenu.h>
+#include <gail/gailmenushell.h>
+#include <gail/gailmenuitem.h>
+#include <gail/gailnotebook.h>
+#include <gail/gailobject.h>
+#include <gail/gailobjectfactory.h>
+#include <gail/gailoptionmenu.h>
+#include <gail/gailpaned.h>
+#include <gail/gailpixmap.h>
+#include <gail/gailprogressbar.h>
+#include <gail/gailradiobutton.h>
+#include <gail/gailradiomenuitem.h>
+#include <gail/gailrenderercell.h>
+#include <gail/gailrenderercellfactory.h>
+#include <gail/gailrange.h>
+#include <gail/gailscale.h>
+#include <gail/gailscrollbar.h>
+#include <gail/gailscrolledwindow.h>
+#include <gail/gailseparator.h>
+#include <gail/gailspinbutton.h>
+#include <gail/gailstatusbar.h>
+#include <gail/gailtextcell.h>
+#include <gail/gailtextcellfactory.h>
+#include <gail/gailtextview.h>
+#include <gail/gailtogglebutton.h>
+#include <gail/gailtoplevel.h>
+#include <gail/gailtreeview.h>
+#include <gail/gailutil.h>
+#include <gail/gailwidget.h>
+#include <gail/gailwindow.h>
diff --git a/modules/other/gail/gailadjustment.c b/modules/other/gail/gailadjustment.c
new file mode 100644 (file)
index 0000000..3669bd5
--- /dev/null
@@ -0,0 +1,234 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailadjustment.h"
+
+static void     gail_adjustment_class_init        (GailAdjustmentClass *klass);
+
+static void     gail_adjustment_real_initialize   (AtkObject           *obj,
+                                                    gpointer            data);
+
+static void     atk_value_interface_init          (AtkValueIface       *iface);
+
+static void     gail_adjustment_get_current_value (AtkValue            *obj,
+                                                    GValue              *value);
+static void     gail_adjustment_get_maximum_value (AtkValue            *obj,
+                                                    GValue              *value);
+static void     gail_adjustment_get_minimum_value (AtkValue            *obj,
+                                                    GValue              *value);
+static gboolean         gail_adjustment_set_current_value (AtkValue            *obj,
+                                                    const GValue        *value);
+
+static void      gail_adjustment_destroyed         (GtkAdjustment       *adjustment,
+                                                    GailAdjustment      *gail_adjustment);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_adjustment_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailAdjustmentClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_adjustment_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailAdjustment), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    static const GInterfaceInfo atk_value_info =
+    {
+        (GInterfaceInitFunc) atk_value_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+    };
+
+    type = g_type_register_static (ATK_TYPE_OBJECT,
+                                   "GailAdjustment", &tinfo, 0);
+
+    g_type_add_interface_static (type, ATK_TYPE_VALUE,
+                                 &atk_value_info);
+  }
+  return type;
+}
+
+static void     
+gail_adjustment_class_init (GailAdjustmentClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->initialize = gail_adjustment_real_initialize;
+}
+
+AtkObject* 
+gail_adjustment_new (GtkAdjustment *adjustment)
+{
+  GObject *object;
+  AtkObject *atk_object;
+
+  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
+
+  object = g_object_new (GAIL_TYPE_ADJUSTMENT, NULL);
+
+  g_return_val_if_fail (object != NULL, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object_initialize (atk_object, adjustment);
+
+  return atk_object;
+}
+
+static void
+gail_adjustment_real_initialize (AtkObject *obj,
+                                 gpointer  data)
+{
+  GtkAdjustment *adjustment;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  adjustment = GTK_ADJUSTMENT (data);
+
+  obj->role = ATK_ROLE_UNKNOWN;
+  GAIL_ADJUSTMENT (obj)->adjustment = adjustment;
+
+  g_signal_connect_object (G_OBJECT (adjustment),
+                           "destroy",
+                           G_CALLBACK (gail_adjustment_destroyed),
+                           obj, 0);
+}
+
+static void     
+atk_value_interface_init (AtkValueIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_current_value = gail_adjustment_get_current_value;
+  iface->get_maximum_value = gail_adjustment_get_maximum_value;
+  iface->get_minimum_value = gail_adjustment_get_minimum_value;
+  iface->set_current_value = gail_adjustment_set_current_value;
+
+}
+
+static void     
+gail_adjustment_get_current_value (AtkValue             *obj,
+                                   GValue               *value)
+{
+  GtkAdjustment* adjustment;
+  gdouble current_value;
+  adjustment = GAIL_ADJUSTMENT (obj)->adjustment;
+  if (adjustment == NULL)
+  {
+    /* State is defunct */
+    return;
+  }
+
+  current_value = adjustment->value;
+  memset (value,  0, sizeof (GValue));
+  g_value_init (value, G_TYPE_DOUBLE);
+  g_value_set_double (value,current_value);
+}
+
+static void     
+gail_adjustment_get_maximum_value (AtkValue             *obj,
+                                   GValue               *value)
+{
+  GtkAdjustment* adjustment;
+  gdouble maximum_value;
+  adjustment = GAIL_ADJUSTMENT (obj)->adjustment;
+  if (adjustment == NULL)
+  {
+    /* State is defunct */
+    return;
+  }
+
+  maximum_value = adjustment->upper;
+  memset (value,  0, sizeof (GValue));
+  g_value_init (value, G_TYPE_DOUBLE);
+  g_value_set_double (value, maximum_value);
+}
+
+static void     
+gail_adjustment_get_minimum_value (AtkValue             *obj,
+                                   GValue               *value)
+{
+  GtkAdjustment* adjustment;
+  gdouble minimum_value;
+  adjustment = GAIL_ADJUSTMENT (obj)->adjustment;
+  if (adjustment == NULL)
+  {
+    /* State is defunct */
+    return;
+  }
+
+  minimum_value = adjustment->lower;
+  memset (value,  0, sizeof (GValue));
+  g_value_init (value, G_TYPE_DOUBLE);
+  g_value_set_double (value, minimum_value);
+}
+
+static gboolean         
+gail_adjustment_set_current_value (AtkValue             *obj,
+                                   const GValue         *value)
+{
+  if (G_VALUE_HOLDS_DOUBLE (value))
+  {
+    GtkAdjustment* adjustment;
+    gdouble new_value;
+    adjustment = GAIL_ADJUSTMENT (obj)->adjustment;
+    if (adjustment == NULL)
+    {
+      /* State is defunct */
+      return FALSE;
+    }
+    new_value = g_value_get_double (value);
+    gtk_adjustment_set_value (adjustment, new_value);
+
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+static void
+gail_adjustment_destroyed (GtkAdjustment       *adjustment,
+                           GailAdjustment      *gail_adjustment)
+{
+  /*
+   * This is the signal handler for the "destroy" signal for the 
+   * GtkAdjustment. We set the  pointer location to NULL;
+   */
+  gail_adjustment->adjustment = NULL;
+}
diff --git a/modules/other/gail/gailadjustment.h b/modules/other/gail/gailadjustment.h
new file mode 100644 (file)
index 0000000..4a6b38b
--- /dev/null
@@ -0,0 +1,61 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_ADJUSTMENT_H__
+#define __GAIL_ADJUSTMENT_H__
+
+#include <atk/atk.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_ADJUSTMENT                     (gail_adjustment_get_type ())
+#define GAIL_ADJUSTMENT(obj)                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_ADJUSTMENT, GailAdjustment))
+#define GAIL_ADJUSTMENT_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_ADJUSTMENT, GailAdjustmentClass))
+#define GAIL_IS_ADJUSTMENT(obj)                  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_ADJUSTMENT))
+#define GAIL_IS_ADJUSTMENT_CLASS(klass)          (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_ADJUSTMENT))
+#define GAIL_ADJUSTMENT_GET_CLASS(obj)           (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_ADJUSTMENT, GailAdjustmentClass))
+
+typedef struct _GailAdjustment                  GailAdjustment;
+typedef struct _GailAdjustmentClass            GailAdjustmentClass;
+
+struct _GailAdjustment
+{
+  AtkObject parent;
+
+  GtkAdjustment *adjustment;
+};
+
+GType gail_adjustment_get_type (void);
+
+struct _GailAdjustmentClass
+{
+  AtkObjectClass parent_class;
+};
+
+AtkObject *gail_adjustment_new (GtkAdjustment *adjustment);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_ADJUSTMENT_H__ */
diff --git a/modules/other/gail/gailarrow.c b/modules/other/gail/gailarrow.c
new file mode 100644 (file)
index 0000000..c20cbc4
--- /dev/null
@@ -0,0 +1,164 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailarrow.h"
+
+static void     gail_arrow_class_init          (GailArrowClass *klass);
+static void  gail_arrow_object_init            (GailArrow              *arrow);
+
+/* AtkImage */
+static void  atk_image_interface_init   (AtkImageIface  *iface);
+static G_CONST_RETURN gchar* gail_arrow_get_image_description 
+                                        (AtkImage       *obj);
+static gboolean gail_arrow_set_image_description 
+                                        (AtkImage       *obj,
+                                        const gchar    *description);
+static void  gail_arrow_finalize       (GObject         *object);
+
+static GailWidgetClass* parent_class = NULL;
+
+GType
+gail_arrow_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailArrowClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_arrow_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailArrow), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) gail_arrow_object_init, /* instance init */
+      NULL /* value table */
+    };
+
+    static const GInterfaceInfo atk_image_info =
+    {
+        (GInterfaceInitFunc) atk_image_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+    };
+
+    type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                   "GailArrow", &tinfo, 0);
+
+    g_type_add_interface_static (type, ATK_TYPE_IMAGE,
+                                 &atk_image_info);
+  }
+  return type;
+}
+
+static void     
+gail_arrow_class_init          (GailArrowClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gail_arrow_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gail_arrow_object_init (GailArrow *arrow)
+{
+  arrow->image_description = NULL;
+}
+
+AtkObject* 
+gail_arrow_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_ARROW (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_ARROW, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+  accessible->role = ATK_ROLE_ICON;
+
+  return accessible;
+}
+
+static void
+atk_image_interface_init (AtkImageIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_image_description = gail_arrow_get_image_description;
+  iface->set_image_description = gail_arrow_set_image_description;
+}
+
+static G_CONST_RETURN gchar* 
+gail_arrow_get_image_description (AtkImage       *obj)
+{
+  GailArrow* arrow;
+
+  g_return_val_if_fail(GAIL_IS_ARROW(obj), NULL);
+
+  arrow = GAIL_ARROW (obj);
+
+  return arrow->image_description;
+
+}
+
+
+static gboolean 
+gail_arrow_set_image_description (AtkImage       *obj,
+                                  const gchar    *description)
+{
+  GailArrow* arrow;
+
+  g_return_val_if_fail(GAIL_IS_ARROW(obj), FALSE);
+
+  arrow = GAIL_ARROW (obj);
+  g_free (arrow->image_description);
+
+  arrow->image_description = g_strdup (description);
+
+  return TRUE;
+
+}
+
+/*
+ * static void  
+ * gail_arrow_get_image_size (AtkImage       *obj,
+ *                          gint           *height,
+ *                          gint           *width)
+ *
+ * We dont implement this function for GailArrow as gtk hardcodes the size 
+ * of the arrow to be 7x5 and it is not possible to query this.
+ */
+
+static void
+gail_arrow_finalize (GObject      *object)
+{
+  GailArrow *arrow = GAIL_ARROW (object);
+
+  g_free (arrow->image_description);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
diff --git a/modules/other/gail/gailarrow.h b/modules/other/gail/gailarrow.h
new file mode 100644 (file)
index 0000000..b1e7fb2
--- /dev/null
@@ -0,0 +1,61 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_ARROW_H__
+#define __GAIL_ARROW_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_ARROW                      (gail_arrow_get_type ())
+#define GAIL_ARROW(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_ARROW, GailArrow))
+#define GAIL_ARROW_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_ARROW, GailArrowClass))
+#define GAIL_IS_ARROW(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_ARROW))
+#define GAIL_IS_ARROW_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_ARROW))
+#define GAIL_ARROW_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_ARROW, GailArrowClass))
+
+typedef struct _GailArrow              GailArrow;
+typedef struct _GailArrowClass         GailArrowClass;
+
+struct _GailArrow
+{
+  GailWidget parent;
+
+  gchar*     image_description;
+};
+
+GType gail_arrow_get_type (void);
+
+struct _GailArrowClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_arrow_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_ARROW_H__ */
diff --git a/modules/other/gail/gailbooleancell.c b/modules/other/gail/gailbooleancell.c
new file mode 100644 (file)
index 0000000..40590bf
--- /dev/null
@@ -0,0 +1,122 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailbooleancell.h"
+
+static void      gail_boolean_cell_class_init          (GailBooleanCellClass *klass);
+
+/* Misc */
+
+static gboolean gail_boolean_cell_update_cache         (GailRendererCell     *cell,
+                                                        gboolean             emit_change_signal);
+
+gchar *gail_boolean_cell_property_list[] = {
+  "active",
+  "radio",
+  NULL
+};
+
+GType
+gail_boolean_cell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailBooleanCellClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_boolean_cell_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailBooleanCell), /* instance size */
+        0, /* nb preallocs */
+        NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_RENDERER_CELL,
+                                     "GailBooleanCell", &tinfo, 0);
+      gail_cell_type_add_action_interface (type);
+    }
+  return type;
+}
+
+static void 
+gail_boolean_cell_class_init (GailBooleanCellClass *klass)
+{
+  GailRendererCellClass *renderer_cell_class = GAIL_RENDERER_CELL_CLASS (klass);
+
+  renderer_cell_class->update_cache = gail_boolean_cell_update_cache;
+  renderer_cell_class->property_list = gail_boolean_cell_property_list;
+}
+
+AtkObject* 
+gail_boolean_cell_new (void)
+{
+  GObject *object;
+  AtkObject *atk_object;
+  GailRendererCell *cell;
+  GailBooleanCell *boolean_cell;
+
+  object = g_object_new (GAIL_TYPE_BOOLEAN_CELL, NULL);
+
+  g_return_val_if_fail (object != NULL, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object->role = ATK_ROLE_TABLE_CELL;
+
+  cell = GAIL_RENDERER_CELL(object);
+  boolean_cell = GAIL_BOOLEAN_CELL(object);
+
+  cell->renderer = gtk_cell_renderer_toggle_new ();
+  g_object_ref (cell->renderer);
+  gtk_object_sink (GTK_OBJECT (cell->renderer));
+  boolean_cell->cell_value = FALSE;
+  return atk_object;
+}
+
+static gboolean
+gail_boolean_cell_update_cache (GailRendererCell *cell, 
+                                gboolean         emit_change_signal)
+{
+  GailBooleanCell *boolean_cell = GAIL_BOOLEAN_CELL (cell);
+  gboolean rv = FALSE;
+  gboolean new_boolean;
+
+  g_object_get (G_OBJECT(cell->renderer), "active", &new_boolean, NULL);
+
+  if (boolean_cell->cell_value != new_boolean)
+    {
+      rv = TRUE;
+      boolean_cell->cell_value = !(boolean_cell->cell_value);
+
+      /* Update cell's state */
+
+    if (new_boolean)
+      gail_cell_add_state (GAIL_CELL (cell), ATK_STATE_CHECKED, emit_change_signal);
+    else
+      gail_cell_remove_state (GAIL_CELL (cell), ATK_STATE_CHECKED, emit_change_signal);
+    }
+
+  return rv;
+}
diff --git a/modules/other/gail/gailbooleancell.h b/modules/other/gail/gailbooleancell.h
new file mode 100644 (file)
index 0000000..cc5dc2d
--- /dev/null
@@ -0,0 +1,60 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_BOOLEAN_CELL_H__
+#define __GAIL_BOOLEAN_CELL_H__
+
+#include <atk/atk.h>
+#include <gail/gailrenderercell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_BOOLEAN_CELL            (gail_boolean_cell_get_type ())
+#define GAIL_BOOLEAN_CELL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_BOOLEAN_CELL, GailBooleanCell))
+#define GAIL_BOOLEAN_CELL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_BOOLEAN_CELL, GailBooleanCellClass))
+#define GAIL_IS_BOOLEAN_CELL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_BOOLEAN_CELL))
+#define GAIL_IS_BOOLEAN_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_BOOLEAN_CELL))
+#define GAIL_BOOLEAN_CELL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_BOOLEAN_CELL, GailBooleanCellClass))
+
+typedef struct _GailBooleanCell                  GailBooleanCell;
+typedef struct _GailBooleanCellClass             GailBooleanCellClass;
+
+struct _GailBooleanCell
+{
+  GailRendererCell parent;
+  gboolean cell_value;
+};
+
+ GType gail_boolean_cell_get_type (void);
+
+struct _GailBooleanCellClass
+{
+  GailRendererCellClass parent_class;
+};
+
+AtkObject *gail_boolean_cell_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TREE_VIEW_BOOLEAN_CELL_H__ */
diff --git a/modules/other/gail/gailbooleancellfactory.c b/modules/other/gail/gailbooleancellfactory.c
new file mode 100644 (file)
index 0000000..30f11d2
--- /dev/null
@@ -0,0 +1,78 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtkcellrenderertoggle.h>
+#include "gailbooleancellfactory.h"
+#include "gailbooleancell.h"
+
+static void gail_boolean_cell_factory_class_init (GailBooleanCellFactoryClass        *klass);
+
+static AtkObject* gail_boolean_cell_factory_create_accessible (
+                                GObject                              *obj);
+static GType gail_boolean_cell_factory_get_accessible_type (void);
+
+GType
+gail_boolean_cell_factory_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) 
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailBooleanCellFactoryClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_boolean_cell_factory_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailBooleanCellFactory), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+    type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
+                           "GailBooleanCellFactory" , &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void 
+gail_boolean_cell_factory_class_init (GailBooleanCellFactoryClass *klass)
+{
+  AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+  class->create_accessible = gail_boolean_cell_factory_create_accessible;
+  class->get_accessible_type = gail_boolean_cell_factory_get_accessible_type;
+}
+
+static AtkObject* 
+gail_boolean_cell_factory_create_accessible (GObject     *obj)
+{
+  g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (obj), NULL);
+
+  return gail_boolean_cell_new ();
+}
+
+static GType
+gail_boolean_cell_factory_get_accessible_type (void)
+{
+  return GAIL_TYPE_BOOLEAN_CELL;
+}
diff --git a/modules/other/gail/gailbooleancellfactory.h b/modules/other/gail/gailbooleancellfactory.h
new file mode 100644 (file)
index 0000000..fca9c05
--- /dev/null
@@ -0,0 +1,56 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_BOOLEAN_CELL_FACTORY_H__
+#define __GAIL_BOOLEAN_CELL_FACTORY_H__
+
+#include <atk/atkobjectfactory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_BOOLEAN_CELL_FACTORY                 (gail_boolean_cell_factory_get_type ())
+#define GAIL_BOOLEAN_CELL_FACTORY(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_BOOLEAN_CELL_FACTORY, GailBooleanCellFactory))
+#define GAIL_BOOLEAN_CELL_FACTORY_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), AGTK_TYPE_BOOLEAN_CELL_FACTORY, GailBooleanCellFactoryClass))
+#define GAIL_IS_BOOLEAN_CELL_FACTORY(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_BOOLEAN_CELL_FACTORY))
+#define GAIL_IS_BOOLEAN_CELL_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_BOOLEAN_CELL_FACTORY))
+#define GAIL_BOOLEAN_CELL_FACTORY_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_BOOLEAN_CELL_FACTORY, GailBooleanCellFactoryClass))
+
+typedef struct _GailBooleanCellFactory             GailBooleanCellFactory;
+typedef struct _GailBooleanCellFactoryClass        GailBooleanCellFactoryClass;
+
+struct _GailBooleanCellFactory
+{
+  AtkObjectFactory parent;
+};
+
+struct _GailBooleanCellFactoryClass
+{
+  AtkObjectFactoryClass parent_class;
+};
+
+GType gail_boolean_cell_factory_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_BOOLEAN_CELL_FACTORY_H__ */
diff --git a/modules/other/gail/gailbox.c b/modules/other/gail/gailbox.c
new file mode 100644 (file)
index 0000000..08b3ef8
--- /dev/null
@@ -0,0 +1,101 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailbox.h"
+
+static void         gail_box_class_init            (GailBoxClass  *klass); 
+static AtkStateSet* gail_box_ref_state_set         (AtkObject     *accessible);
+
+static GailContainerClass *parent_class = NULL;
+
+GType
+gail_box_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailBoxClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_box_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailBox), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                   "GailBox", &tinfo, 0);
+  }
+  return type;
+}
+
+static void
+gail_box_class_init (GailBoxClass *klass)
+{
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_state_set = gail_box_ref_state_set;
+}
+
+AtkObject* 
+gail_box_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_BOX (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_BOX, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_FILLER;
+
+  return accessible;
+}
+
+static AtkStateSet*
+gail_box_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  if (GTK_IS_VBOX (widget) || GTK_IS_VBUTTON_BOX (widget))
+    atk_state_set_add_state (state_set, ATK_STATE_VERTICAL);
+  else if (GTK_IS_HBOX (widget) || GTK_IS_HBUTTON_BOX (widget))
+    atk_state_set_add_state (state_set, ATK_STATE_HORIZONTAL);
+
+  return state_set;
+}
diff --git a/modules/other/gail/gailbox.h b/modules/other/gail/gailbox.h
new file mode 100644 (file)
index 0000000..17c00ec
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_BOX_H__
+#define __GAIL_BOX_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_BOX                        (gail_box_get_type ())
+#define GAIL_BOX(obj)                        (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_BOX, GailBox))
+#define GAIL_BOX_CLASS(klass)                (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_BOX, GailBoxClass))
+#define GAIL_IS_BOX(obj)                     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_BOX))
+#define GAIL_IS_BOX_CLASS(klass)             (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_BOX))
+#define GAIL_BOX_GET_CLASS(obj)              (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_BOX, GailBoxClass))
+
+typedef struct _GailBox              GailBox;
+typedef struct _GailBoxClass         GailBoxClass;
+
+struct _GailBox
+{
+  GailContainer parent;
+};
+
+GType gail_box_get_type (void);
+
+struct _GailBoxClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_box_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_BOX_H__ */
diff --git a/modules/other/gail/gailbutton.c b/modules/other/gail/gailbutton.c
new file mode 100644 (file)
index 0000000..46b7db3
--- /dev/null
@@ -0,0 +1,1720 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gdk/gdkkeysyms.h>
+#include "gailbutton.h"
+#include <libgail-util/gailmisc.h>
+
+#define GAIL_BUTTON_ATTACHED_MENUS "gtk-attached-menus"
+
+static void                  gail_button_class_init       (GailButtonClass *klass);
+static void                  gail_button_object_init      (GailButton      *button);
+
+static G_CONST_RETURN gchar* gail_button_get_name         (AtkObject       *obj);
+static gint                  gail_button_get_n_children   (AtkObject       *obj);
+static AtkObject*            gail_button_ref_child        (AtkObject       *obj,
+                                                           gint            i);
+static AtkStateSet*          gail_button_ref_state_set    (AtkObject       *obj);
+static void                  gail_button_notify_label_gtk (GObject         *obj,
+                                                           GParamSpec      *pspec,
+                                                           gpointer        data);
+static void                  gail_button_label_map_gtk    (GtkWidget       *widget,
+                                                           gpointer        data);
+
+static void                  gail_button_real_initialize  (AtkObject       *obj,
+                                                           gpointer        data);
+static void                  gail_button_finalize         (GObject        *object);
+static void                  gail_button_init_textutil    (GailButton     *button,
+                                                           GtkWidget      *label);
+
+static void                  gail_button_pressed_enter_handler  (GtkWidget       *widget);
+static void                  gail_button_released_leave_handler (GtkWidget       *widget);
+static gint                  gail_button_real_add_gtk           (GtkContainer    *container,
+                                                                 GtkWidget       *widget,
+                                                                 gpointer        data);
+
+
+static void                  atk_action_interface_init  (AtkActionIface *iface);
+static gboolean              gail_button_do_action      (AtkAction      *action,
+                                                         gint           i);
+static gboolean              idle_do_action             (gpointer       data);
+static gint                  gail_button_get_n_actions  (AtkAction      *action);
+static G_CONST_RETURN gchar* gail_button_get_description(AtkAction      *action,
+                                                         gint           i);
+static G_CONST_RETURN gchar* gail_button_get_keybinding (AtkAction      *action,
+                                                         gint           i);
+static G_CONST_RETURN gchar* gail_button_action_get_name(AtkAction      *action,
+                                                         gint           i);
+static gboolean              gail_button_set_description(AtkAction      *action,
+                                                         gint           i,
+                                                         const gchar    *desc);
+static void                  gail_button_notify_label_weak_ref (gpointer data,
+                                                                GObject  *obj);
+static void                  gail_button_notify_weak_ref       (gpointer data,
+                                                                GObject  *obj);
+
+
+/* AtkImage.h */
+static void                  atk_image_interface_init   (AtkImageIface  *iface);
+static G_CONST_RETURN gchar* gail_button_get_image_description 
+                                                        (AtkImage       *image);
+static void                 gail_button_get_image_position
+                                                        (AtkImage       *image,
+                                                         gint          *x,
+                                                         gint          *y,
+                                                         AtkCoordType   coord_type);
+static void                  gail_button_get_image_size (AtkImage       *image,
+                                                         gint           *width,
+                                                         gint           *height);
+static gboolean              gail_button_set_image_description 
+                                                        (AtkImage       *image,
+                                                         const gchar    *description);
+
+/* atktext.h */ 
+static void      atk_text_interface_init          (AtkTextIface        *iface);
+
+static gchar*    gail_button_get_text             (AtkText           *text,
+                                                    gint             start_pos,
+                                                   gint              end_pos);
+static gunichar          gail_button_get_character_at_offset(AtkText         *text,
+                                                   gint              offset);
+static gchar*     gail_button_get_text_before_offset(AtkText         *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_button_get_text_at_offset   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_button_get_text_after_offset(AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gint      gail_button_get_character_count  (AtkText           *text);
+static void gail_button_get_character_extents      (AtkText          *text,
+                                                   gint              offset,
+                                                   gint              *x,
+                                                   gint              *y,
+                                                   gint              *width,
+                                                   gint              *height,
+                                                   AtkCoordType      coords);
+static gint gail_button_get_offset_at_point        (AtkText           *text,
+                                                    gint              x,
+                                                    gint              y,
+                                                   AtkCoordType      coords);
+static AtkAttributeSet* gail_button_get_run_attributes 
+                                                   (AtkText           *text,
+                                                   gint              offset,
+                                                    gint             *start_offset,
+                                                   gint              *end_offset);
+static AtkAttributeSet* gail_button_get_default_attributes
+                                                   (AtkText           *text);
+static GtkImage*             get_image_from_button      (GtkWidget      *button);
+static GtkWidget*            get_label_from_button      (GtkWidget      *button,
+                                                         gint           index,
+                                                         gboolean       allow_many);
+static gint                  get_n_labels_from_button   (GtkWidget      *button);
+static void                  set_role_for_button        (AtkObject      *accessible,
+                                                         GtkWidget      *button);
+
+static gint                  get_n_attached_menus       (GtkWidget      *widget);
+static GtkWidget*            get_nth_attached_menu      (GtkWidget      *widget,
+                                                         gint           index);
+
+static GailContainer* parent_class = NULL;
+
+GType
+gail_button_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailButtonClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_button_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailButton), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_button_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_action_info =
+      {
+        (GInterfaceInitFunc) atk_action_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_image_info =
+      {
+        (GInterfaceInitFunc) atk_image_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailButton", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                   &atk_action_info);
+      g_type_add_interface_static (type, ATK_TYPE_IMAGE,
+                                   &atk_image_info);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+
+    }
+
+  return type;
+}
+
+static void
+gail_button_class_init (GailButtonClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+  GailContainerClass *container_class;
+
+  widget_class = (GailWidgetClass*)klass;
+  container_class = (GailContainerClass*)klass;
+
+  gobject_class->finalize = gail_button_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_name = gail_button_get_name;
+  class->get_n_children = gail_button_get_n_children;
+  class->ref_child = gail_button_ref_child;
+  class->ref_state_set = gail_button_ref_state_set;
+  class->initialize = gail_button_real_initialize;
+
+  container_class->add_gtk = gail_button_real_add_gtk;
+  container_class->remove_gtk = NULL;
+}
+
+static void
+gail_button_object_init (GailButton      *button)
+{
+  button->click_description = NULL;
+  button->press_description = NULL;
+  button->release_description = NULL;
+  button->click_keybinding = NULL;
+  button->action_queue = NULL;
+  button->action_idle_handler = 0;
+  button->textutil = NULL;
+}
+
+AtkObject* 
+gail_button_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_BUTTON (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_BUTTON, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static G_CONST_RETURN gchar*
+gail_button_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar* name = NULL;
+
+  g_return_val_if_fail (GAIL_IS_BUTTON (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (obj);
+  if (name == NULL)
+    {
+      /*
+       * Get the text on the label
+       */
+      GtkWidget *widget;
+      GtkWidget *child;
+
+      widget = GTK_ACCESSIBLE (obj)->widget;
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+
+      g_return_val_if_fail (GTK_IS_BUTTON (widget), NULL);
+
+      child = get_label_from_button (widget, 0, FALSE);
+      if (GTK_IS_LABEL (child))
+        name = gtk_label_get_text (GTK_LABEL (child)); 
+      else
+        {
+          GtkImage *image;
+
+          image = get_image_from_button (widget);
+          if (GTK_IS_IMAGE (image))
+            {
+              AtkObject *atk_obj;
+
+              atk_obj = gtk_widget_get_accessible (GTK_WIDGET (image));
+              name = atk_object_get_name (atk_obj);
+            }
+        }
+    }
+  return name;
+}
+
+/*
+ * A DownArrow in a GtkToggltButton whose parent is not a ColorCombo
+ * has press as default action.
+ */
+static gboolean
+gail_button_is_default_press (GtkWidget *widget)
+{
+  GtkWidget  *child;
+  GtkWidget  *parent;
+  gboolean ret = FALSE;
+  const gchar *parent_type_name;
+
+  child = GTK_BIN (widget)->child;
+  if (GTK_IS_ARROW (child) &&
+      GTK_ARROW (child)->arrow_type == GTK_ARROW_DOWN)
+    {
+      parent = gtk_widget_get_parent (widget);
+      if (parent)
+        {
+          parent_type_name = g_type_name (G_OBJECT_TYPE (parent));
+          if (strcmp (parent_type_name, "ColorCombo"))
+            return TRUE;
+        }
+    }
+
+  return ret;
+}
+
+static void
+gail_button_real_initialize (AtkObject *obj,
+                             gpointer   data)
+{
+  GailButton *button = GAIL_BUTTON (obj);
+  GtkWidget  *label;
+  GtkWidget  *widget;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  button->state = GTK_STATE_NORMAL;
+
+  g_signal_connect (data,
+                    "pressed",
+                    G_CALLBACK (gail_button_pressed_enter_handler),
+                    NULL);
+  g_signal_connect (data,
+                    "enter",
+                    G_CALLBACK (gail_button_pressed_enter_handler),
+                    NULL);
+  g_signal_connect (data,
+                    "released",
+                    G_CALLBACK (gail_button_released_leave_handler),
+                    NULL);
+  g_signal_connect (data,
+                    "leave",
+                    G_CALLBACK (gail_button_released_leave_handler),
+                    NULL);
+
+
+  widget = GTK_WIDGET (data);
+  label = get_label_from_button (widget, 0, FALSE);
+  if (GTK_IS_LABEL (label))
+    {
+      if (GTK_WIDGET_MAPPED (label))
+        gail_button_init_textutil (button, label);
+      else 
+        g_signal_connect (label,
+                          "map",
+                          G_CALLBACK (gail_button_label_map_gtk),
+                          button);
+    }
+  button->default_is_press = gail_button_is_default_press (widget);
+    
+  set_role_for_button (obj, data);
+}
+
+static void
+gail_button_label_map_gtk (GtkWidget *widget,
+                           gpointer data)
+{
+  GailButton *button; 
+
+  button = GAIL_BUTTON (data);
+  gail_button_init_textutil (button, widget);
+}
+
+static void
+gail_button_notify_label_gtk (GObject           *obj,
+                              GParamSpec        *pspec,
+                              gpointer           data)
+{
+  AtkObject* atk_obj = ATK_OBJECT (data);
+  GtkLabel *label;
+  GailButton *gail_button;
+
+  if (strcmp (pspec->name, "label") == 0)
+    {
+      const gchar* label_text;
+
+      label = GTK_LABEL (obj);
+
+      label_text = gtk_label_get_text (label);
+
+      gail_button = GAIL_BUTTON (atk_obj);
+      gail_text_util_text_setup (gail_button->textutil, label_text);
+
+      if (atk_obj->name == NULL)
+      {
+        /*
+         * The label has changed so notify a change in accessible-name
+         */
+        g_object_notify (G_OBJECT (atk_obj), "accessible-name");
+      }
+      /*
+       * The label is the only property which can be changed
+       */
+      g_signal_emit_by_name (atk_obj, "visible_data_changed");
+    }
+}
+
+static void
+gail_button_notify_weak_ref (gpointer data, GObject* obj)
+{
+  GtkLabel *label = NULL;
+
+  AtkObject* atk_obj = ATK_OBJECT (obj);
+  if (data && GTK_IS_WIDGET (data))
+    {
+      label = GTK_LABEL (data);
+      if (label)
+        {
+          g_signal_handlers_disconnect_by_func (label,
+                                                (GCallback) gail_button_notify_label_gtk,
+                                                GAIL_BUTTON (atk_obj));
+          g_object_weak_unref (G_OBJECT (label),
+                               gail_button_notify_label_weak_ref,
+                               GAIL_BUTTON (atk_obj));
+        }
+    }
+}
+
+static void
+gail_button_notify_label_weak_ref (gpointer data, GObject* obj)
+{
+  GtkLabel *label = NULL;
+  GailButton *button = NULL;
+
+  label = GTK_LABEL (obj);
+  if (data && GAIL_IS_BUTTON (data))
+    {
+      button = GAIL_BUTTON (ATK_OBJECT (data));
+      if (button)
+        g_object_weak_unref (G_OBJECT (button), gail_button_notify_weak_ref,
+                             label);
+    }
+}
+
+
+static void
+gail_button_init_textutil (GailButton  *button,
+                           GtkWidget   *label)
+{
+  const gchar *label_text;
+
+  button->textutil = gail_text_util_new ();
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  gail_text_util_text_setup (button->textutil, label_text);
+  g_object_weak_ref (G_OBJECT (button),
+                     gail_button_notify_weak_ref, label);
+  g_object_weak_ref (G_OBJECT (label),
+                     gail_button_notify_label_weak_ref, button);
+  g_signal_connect (label,
+                    "notify",
+                    (GCallback) gail_button_notify_label_gtk,
+                    button);     
+}
+
+static gint
+gail_button_real_add_gtk (GtkContainer *container,
+                          GtkWidget    *widget,
+                          gpointer     data)
+{
+  GtkLabel *label;
+  GailButton *button;
+
+  if (GTK_IS_LABEL (widget))
+    {
+      const gchar* label_text;
+
+      label = GTK_LABEL (widget);
+
+
+      button = GAIL_BUTTON (data);
+      if (!button->textutil)
+        gail_button_init_textutil (button, widget);
+      else
+        {
+          label_text = gtk_label_get_text (label);
+          gail_text_util_text_setup (button->textutil, label_text);
+        }
+    }
+
+  return 1;
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action = gail_button_do_action;
+  iface->get_n_actions = gail_button_get_n_actions;
+  iface->get_description = gail_button_get_description;
+  iface->get_keybinding = gail_button_get_keybinding;
+  iface->get_name = gail_button_action_get_name;
+  iface->set_description = gail_button_set_description;
+}
+
+static gboolean
+gail_button_do_action (AtkAction *action,
+                       gint      i)
+{
+  GtkWidget *widget;
+  GailButton *button;
+  gboolean return_value = TRUE;
+
+  widget = GTK_ACCESSIBLE (action)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  if (!GTK_WIDGET_IS_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    return FALSE;
+
+  button = GAIL_BUTTON (action); 
+
+  switch (i)
+    {
+    case 0:
+    case 1:
+    case 2:
+      if (!button->action_queue) 
+       {
+         button->action_queue = g_queue_new ();
+       }
+      g_queue_push_head (button->action_queue, (gpointer) i);
+      if (!button->action_idle_handler)
+       button->action_idle_handler = g_idle_add (idle_do_action, button);
+      break;
+    default:
+      return_value = FALSE;
+      break;
+    }
+  return return_value; 
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  GtkButton *button; 
+  GtkWidget *widget;
+  GailButton *gail_button;
+  GdkEvent tmp_event;
+
+  GDK_THREADS_ENTER ();
+
+  gail_button = GAIL_BUTTON (data);
+  gail_button->action_idle_handler = 0;
+  widget = GTK_ACCESSIBLE (gail_button)->widget;
+  tmp_event.button.type = GDK_BUTTON_RELEASE;
+  tmp_event.button.window = widget->window;
+  tmp_event.button.button = 1;
+  tmp_event.button.send_event = TRUE;
+  tmp_event.button.time = GDK_CURRENT_TIME;
+  tmp_event.button.axes = NULL;
+  
+  if (widget == NULL /* State is defunct */ ||
+      !GTK_WIDGET_IS_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+  else
+    gtk_widget_event (widget, &tmp_event);
+
+  button = GTK_BUTTON (widget); 
+  while (!g_queue_is_empty (gail_button->action_queue)) 
+    {
+      gint action_number = (gint) g_queue_pop_head (gail_button->action_queue);
+      if (gail_button->default_is_press)
+        {
+          if (action_number == 0)
+            action_number = 1;
+          else if (action_number == 1)
+            action_number = 0;
+        }
+      switch (action_number)
+       {
+       case 0:
+         gtk_widget_activate (widget);
+         break;
+       case 1:
+         button->in_button = TRUE;
+         gtk_button_enter (button);
+         /*
+          * Simulate a button press event. calling gtk_button_pressed() does
+          * not get the job done for a GtkOptionMenu.  
+          */
+         tmp_event.button.type = GDK_BUTTON_PRESS;
+         tmp_event.button.window = widget->window;
+         tmp_event.button.button = 1;
+         tmp_event.button.send_event = TRUE;
+         tmp_event.button.time = GDK_CURRENT_TIME;
+         tmp_event.button.axes = NULL;
+         
+         gtk_widget_event (widget, &tmp_event);
+         break;
+       case 2:
+         button->in_button = FALSE;
+         gtk_button_leave (button);
+         break;
+       default:
+         g_assert_not_reached ();
+         break;
+       }
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE; 
+}
+
+static gint
+gail_button_get_n_actions (AtkAction *action)
+{
+  return 3;
+}
+
+static G_CONST_RETURN gchar*
+gail_button_get_description (AtkAction *action,
+                             gint      i)
+{
+  GailButton *button;
+  G_CONST_RETURN gchar *return_value;
+
+  button = GAIL_BUTTON (action);
+
+  if (button->default_is_press)
+    {
+      if (i == 0)
+        i = 1;
+      else if (i == 1)
+        i = 0;
+    }
+  switch (i)
+    {
+    case 0:
+      return_value = button->click_description;
+      break;
+    case 1:
+      return_value = button->press_description;
+      break;
+    case 2:
+      return_value = button->release_description;
+      break;
+    default:
+      return_value = NULL;
+      break;
+    }
+  return return_value; 
+}
+
+static G_CONST_RETURN gchar*
+gail_button_get_keybinding (AtkAction *action,
+                            gint      i)
+{
+  GailButton *button;
+  gchar *return_value = NULL;
+
+  button = GAIL_BUTTON (action);
+  if (button->default_is_press)
+    {
+      if (i == 0)
+        i = 1;
+      else if (i == 1)
+        i = 0;
+    }
+  switch (i)
+    {
+    case 0:
+      {
+        /*
+         * We look for a mnemonic on the label
+         */
+        GtkWidget *widget;
+        GtkWidget *label;
+        guint key_val; 
+
+        widget = GTK_ACCESSIBLE (button)->widget;
+        if (widget == NULL)
+          /*
+           * State is defunct
+           */
+          return NULL;
+
+        g_return_val_if_fail (GTK_IS_BUTTON (widget), NULL);
+
+        label = get_label_from_button (widget, 0, FALSE);
+        if (GTK_IS_LABEL (label))
+          {
+            key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); 
+            if (key_val != GDK_VoidSymbol)
+              return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
+          }
+        if (return_value == NULL)
+          {
+            /* Find labelled-by relation */
+            AtkRelationSet *set;
+            AtkRelation *relation;
+            GPtrArray *target;
+            gpointer target_object;
+
+            set = atk_object_ref_relation_set (ATK_OBJECT (action));
+            if (set)
+              {
+                relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
+                if (relation)
+                  {              
+                    target = atk_relation_get_target (relation);
+            
+                    target_object = g_ptr_array_index (target, 0);
+                    if (GTK_IS_ACCESSIBLE (target_object))
+                      {
+                        label = GTK_ACCESSIBLE (target_object)->widget;
+                      } 
+                  }
+                g_object_unref (set);
+              }
+
+            if (GTK_IS_LABEL (label))
+              {
+                key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); 
+                if (key_val != GDK_VoidSymbol)
+                  return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
+              }
+          }
+        g_free (button->click_keybinding);
+        button->click_keybinding = return_value;
+        break;
+      }
+    default:
+      break;
+    }
+  return return_value; 
+}
+
+static G_CONST_RETURN gchar*
+gail_button_action_get_name (AtkAction *action,
+                             gint      i)
+{
+  G_CONST_RETURN gchar *return_value;
+  GailButton *button;
+
+  button = GAIL_BUTTON (action);
+
+  if (button->default_is_press)
+    {
+      if (i == 0)
+        i = 1;
+      else if (i == 1)
+        i = 0;
+    }
+  switch (i)
+    {
+    case 0:
+      /*
+       * This action is a "click" to activate a button or "toggle" to change
+       * the state of a toggle button check box or radio button.
+       */ 
+      return_value = "click";
+      break;
+    case 1:
+      /*
+       * This action simulates a button press by simulating moving the
+       * mouse into the button followed by pressing the left mouse button.
+       */
+      return_value = "press";
+      break;
+    case 2:
+      /*
+       * This action simulates releasing the left mouse button outside the 
+       * button.
+       *
+       * To simulate releasing the left mouse button inside the button use
+       * the click action.
+       */
+      return_value = "release";
+      break;
+    default:
+      return_value = NULL;
+      break;
+    }
+  return return_value; 
+}
+
+static gboolean
+gail_button_set_description (AtkAction      *action,
+                             gint           i,
+                             const gchar    *desc)
+{
+  GailButton *button;
+  gchar **value;
+
+  button = GAIL_BUTTON (action);
+
+  if (button->default_is_press)
+    {
+      if (i == 0)
+        i = 1;
+      else if (i == 1)
+        i = 0;
+    }
+  switch (i)
+    {
+    case 0:
+      value = &button->click_description;
+      break;
+    case 1:
+      value = &button->press_description;
+      break;
+    case 2:
+      value = &button->release_description;
+      break;
+    default:
+      value = NULL;
+      break;
+    }
+  if (value)
+    {
+      g_free (*value);
+      *value = g_strdup (desc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gint
+gail_button_get_n_children (AtkObject* obj)
+{
+  GtkWidget *widget;
+  gint n_children;
+
+  g_return_val_if_fail (GAIL_IS_BUTTON (obj), 0);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  /*
+   * Check whether we have an attached menus for PanelMenuButton
+   */
+  n_children = get_n_attached_menus (widget);
+  if (n_children > 0)
+    return n_children;
+
+  n_children = get_n_labels_from_button (widget);
+  if (n_children <= 1)
+    n_children = 0;
+
+  return n_children;
+}
+
+static AtkObject*
+gail_button_ref_child (AtkObject *obj,
+                       gint      i)
+{
+  GtkWidget *widget;
+  GtkWidget *child_widget;
+  AtkObject *child;
+
+  g_return_val_if_fail (GAIL_IS_BUTTON (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  if (i >= gail_button_get_n_children (obj))
+    return NULL;
+
+  if (get_n_attached_menus (widget) > 0)
+  {
+    child_widget = get_nth_attached_menu (widget, i);
+  }
+  else
+    child_widget = NULL;    
+
+  if (!child_widget) 
+    {
+      if (get_n_labels_from_button (widget) > 1)
+        {
+          child_widget = get_label_from_button (widget, i, TRUE);
+        }
+    }
+
+  if (child_widget)
+    {
+      child = gtk_widget_get_accessible (child_widget);
+      g_object_ref (child);
+    }
+  else
+    child = NULL;
+
+  return child;
+}
+
+static AtkStateSet*
+gail_button_ref_state_set (AtkObject *obj)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+  GtkButton *button;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  button = GTK_BUTTON (widget);
+
+  if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
+    atk_state_set_add_state (state_set, ATK_STATE_ARMED);
+
+  return state_set;
+}
+
+/*
+ * This is the signal handler for the "pressed" or "enter" signal handler
+ * on the GtkButton.
+ *
+ * If the state is now GTK_STATE_ACTIVE we notify a property change
+ */
+static void
+gail_button_pressed_enter_handler (GtkWidget       *widget)
+{
+  AtkObject *accessible;
+
+  if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
+    {
+      accessible = gtk_widget_get_accessible (widget);
+      atk_object_notify_state_change (accessible, ATK_STATE_ARMED, TRUE);
+      GAIL_BUTTON (accessible)->state = GTK_STATE_ACTIVE;
+    }
+}
+
+/*
+ * This is the signal handler for the "released" or "leave" signal handler
+ * on the GtkButton.
+ *
+ * If the state was GTK_STATE_ACTIVE we notify a property change
+ */
+static void
+gail_button_released_leave_handler (GtkWidget       *widget)
+{
+  AtkObject *accessible;
+
+  accessible = gtk_widget_get_accessible (widget);
+  if (GAIL_BUTTON (accessible)->state == GTK_STATE_ACTIVE)
+    {
+      atk_object_notify_state_change (accessible, ATK_STATE_ARMED, FALSE);
+      GAIL_BUTTON (accessible)->state = GTK_STATE_NORMAL;
+    }
+}
+
+static void
+atk_image_interface_init (AtkImageIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_image_description = gail_button_get_image_description;
+  iface->get_image_position = gail_button_get_image_position;
+  iface->get_image_size = gail_button_get_image_size;
+  iface->set_image_description = gail_button_set_image_description;
+}
+
+static GtkImage*
+get_image_from_button (GtkWidget *button)
+{
+  GtkWidget *child;
+  GList *list;
+  GtkImage *image = NULL;
+
+  child = gtk_bin_get_child (GTK_BIN (button));
+  if (GTK_IS_IMAGE (child))
+    image = GTK_IMAGE (child);
+  else
+    {
+      if (GTK_IS_ALIGNMENT (child))
+        child = gtk_bin_get_child (GTK_BIN (child));
+      if (GTK_IS_CONTAINER (child))
+        {
+          list = gtk_container_get_children (GTK_CONTAINER (child));
+          if (!list)
+            return NULL;
+          if (GTK_IS_IMAGE (list->data))
+            image = GTK_IMAGE (list->data);
+          g_list_free (list);
+        }
+    }
+
+  return image;
+}
+
+static G_CONST_RETURN gchar* 
+gail_button_get_image_description (AtkImage *image) {
+
+  GtkWidget *widget;
+  GtkImage  *button_image;
+  AtkObject *obj;
+
+  widget = GTK_ACCESSIBLE (image)->widget;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  button_image = get_image_from_button (widget);
+
+  if (button_image != NULL)
+    {
+      obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
+      return atk_image_get_image_description (ATK_IMAGE (obj));
+    }
+  else 
+    return NULL;
+}
+
+static void
+gail_button_get_image_position (AtkImage     *image,
+                                gint        *x,
+                                gint        *y,
+                                AtkCoordType coord_type)
+{
+  GtkWidget *widget;
+  GtkImage  *button_image;
+  AtkObject *obj;
+
+  widget = GTK_ACCESSIBLE (image)->widget;
+
+  if (widget == NULL)
+    {
+    /*
+     * State is defunct
+     */
+      *x = G_MININT;
+      *y = G_MININT;
+      return;
+    }
+
+  button_image = get_image_from_button (widget);
+
+  if (button_image != NULL)
+    {
+      obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
+      atk_component_get_position (ATK_COMPONENT (obj), x, y, coord_type); 
+    }
+  else
+    {
+      *x = G_MININT;
+      *y = G_MININT;
+    }
+}
+
+static void
+gail_button_get_image_size (AtkImage *image,
+                            gint     *width,
+                            gint     *height)
+{
+  GtkWidget *widget;
+  GtkImage  *button_image;
+  AtkObject *obj;
+
+  widget = GTK_ACCESSIBLE (image)->widget;
+
+  if (widget == NULL)
+    {
+    /*
+     * State is defunct
+     */
+      *width = -1;
+      *height = -1;
+      return;
+    }
+
+  button_image = get_image_from_button (widget);
+
+  if (button_image != NULL)
+    {
+      obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
+      atk_image_get_image_size (ATK_IMAGE (obj), width, height); 
+    }
+  else
+    {
+      *width = -1;
+      *height = -1;
+    }
+}
+
+static gboolean
+gail_button_set_image_description (AtkImage    *image,
+                                   const gchar *description)
+{
+  GtkWidget *widget;
+  GtkImage  *button_image;
+  AtkObject *obj;
+
+  widget = GTK_ACCESSIBLE (image)->widget;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  button_image = get_image_from_button (widget);
+
+  if (button_image != NULL) 
+    {
+      obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
+      return atk_image_set_image_description (ATK_IMAGE (obj), description);
+    }
+  else 
+    return FALSE;
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->get_text = gail_button_get_text;
+  iface->get_character_at_offset = gail_button_get_character_at_offset;
+  iface->get_text_before_offset = gail_button_get_text_before_offset;
+  iface->get_text_at_offset = gail_button_get_text_at_offset;
+  iface->get_text_after_offset = gail_button_get_text_after_offset;
+  iface->get_character_count = gail_button_get_character_count;
+  iface->get_character_extents = gail_button_get_character_extents;
+  iface->get_offset_at_point = gail_button_get_offset_at_point;
+  iface->get_run_attributes = gail_button_get_run_attributes;
+  iface->get_default_attributes = gail_button_get_default_attributes;
+}
+
+static gchar*
+gail_button_get_text (AtkText *text,
+                      gint    start_pos,
+                      gint    end_pos)
+{
+  GtkWidget *widget;
+  GtkWidget  *label;
+  GailButton *button;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL (label))
+    return NULL;
+
+  button = GAIL_BUTTON (text);
+  if (!button->textutil) 
+    gail_button_init_textutil (button, label);
+
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+
+  if (label_text == NULL)
+    return NULL;
+  else
+  {
+    return gail_text_util_get_substring (button->textutil, 
+                                         start_pos, end_pos);
+  }
+}
+
+static gchar*
+gail_button_get_text_before_offset (AtkText         *text,
+                                   gint            offset,
+                                   AtkTextBoundary boundary_type,
+                                   gint            *start_offset,
+                                   gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailButton *button;
+  
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  button = GAIL_BUTTON (text);
+  if (!button->textutil)
+    gail_button_init_textutil (button, label);
+
+  return gail_text_util_get_text (button->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset); 
+}
+
+static gchar*
+gail_button_get_text_at_offset (AtkText         *text,
+                               gint            offset,
+                               AtkTextBoundary boundary_type,
+                               gint            *start_offset,
+                               gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailButton *button;
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  button = GAIL_BUTTON (text);
+  if (!button->textutil)
+    gail_button_init_textutil (button, label);
+
+  return gail_text_util_get_text (button->textutil,
+                              gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET, 
+                              boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_button_get_text_after_offset (AtkText         *text,
+                                  gint            offset,
+                                  AtkTextBoundary boundary_type,
+                                  gint            *start_offset,
+                                  gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailButton *button;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return NULL;
+  }
+  
+  /* Get label */
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  button = GAIL_BUTTON (text);
+  if (!button->textutil)
+    gail_button_init_textutil (button, label);
+
+  return gail_text_util_get_text (button->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gint
+gail_button_get_character_count (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return 0;
+
+  return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
+}
+
+static void
+gail_button_get_character_extents (AtkText      *text,
+                                  gint         offset,
+                                  gint         *x,
+                                  gint         *y,
+                                   gint        *width,
+                                   gint        *height,
+                                  AtkCoordType coords)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  PangoRectangle char_rect;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+  widget = GTK_ACCESSIBLE (text)->widget;
+
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
+  pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
+  
+  gail_misc_get_extents_from_pango_rectangle (label, &char_rect, 
+                    x_layout, y_layout, x, y, width, height, coords);
+} 
+
+static gint 
+gail_button_get_offset_at_point (AtkText      *text,
+                                 gint         x,
+                                 gint         y,
+                                AtkCoordType coords)
+{ 
+  GtkWidget *widget;
+  GtkWidget *label;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return -1;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  
+  index = gail_misc_get_index_at_point_in_layout (label, 
+                                              gtk_label_get_layout (GTK_LABEL (label)), 
+                                              x_layout, y_layout, x, y, coords);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  if (index == -1)
+    {
+      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+        return g_utf8_strlen (label_text, -1);
+
+      return index;  
+    }
+  else
+    return g_utf8_pointer_to_offset (label_text, label_text + index);  
+}
+
+static AtkAttributeSet*
+gail_button_get_run_attributes (AtkText        *text,
+                                gint         offset,
+                                gint         *start_offset,
+                               gint          *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+  GtkJustification justify;
+  GtkTextDirection dir;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  
+  /* Get values set for entire label, if any */
+  justify = gtk_label_get_justify (GTK_LABEL (label));
+  if (justify != GTK_JUSTIFY_CENTER)
+    {
+      at_set = gail_misc_add_attribute (at_set, 
+                                        ATK_TEXT_ATTR_JUSTIFICATION,
+     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
+    }
+  dir = gtk_widget_get_direction (label);
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                gtk_label_get_layout (GTK_LABEL (label)),
+                                                (gchar *) gtk_label_get_text (GTK_LABEL (label)),
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  return at_set;
+}
+
+static AtkAttributeSet*
+gail_button_get_default_attributes (AtkText        *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  at_set = gail_misc_get_default_attributes (at_set,
+                                             gtk_label_get_layout (GTK_LABEL (label)),
+                                             widget);
+  return at_set;
+}
+
+static gunichar 
+gail_button_get_character_at_offset (AtkText            *text,
+                                     gint               offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  const gchar *string;
+  gchar *index;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return '\0';
+
+  label = get_label_from_button (widget, 0, FALSE);
+
+  if (!GTK_IS_LABEL(label))
+    return '\0';
+  string = gtk_label_get_text (GTK_LABEL (label));
+  if (offset >= g_utf8_strlen (string, -1))
+    return '\0';
+  index = g_utf8_offset_to_pointer (string, offset);
+
+  return g_utf8_get_char (index);
+}
+
+static void
+gail_button_finalize (GObject            *object)
+{
+  GailButton *button = GAIL_BUTTON (object);
+
+  g_free (button->click_description);
+  g_free (button->press_description);
+  g_free (button->release_description);
+  g_free (button->click_keybinding);
+  if (button->action_idle_handler)
+    {
+      g_source_remove (button->action_idle_handler);
+      button->action_idle_handler = 0;
+    }
+  if (button->action_queue)
+    {
+      g_queue_free (button->action_queue);
+    }
+  if (button->textutil)
+    {
+      g_object_unref (button->textutil);
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GtkWidget*
+find_label_child (GtkContainer *container,
+                  gint         *index,
+                  gboolean     allow_many)
+{
+  GList *children, *tmp_list;
+  GtkWidget *child;
+  children = gtk_container_get_children (container);
+
+  child = NULL;
+  for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next) 
+    {
+      if (GTK_IS_LABEL (tmp_list->data))
+        {
+          if (!allow_many)
+            {
+              if (child)
+                {
+                  child = NULL;
+                  break;
+                }
+              child = GTK_WIDGET (tmp_list->data);
+            }
+          else
+            {
+              if (*index == 0)
+                {
+                  child = GTK_WIDGET (tmp_list->data);
+                  break;
+                }
+              (*index)--;
+           }
+        }
+       /*
+        * Label for button which are GtkTreeView column headers are in a 
+        * GtkHBox in a GtkAlignment.
+        */
+      else if (GTK_IS_ALIGNMENT (tmp_list->data))
+        {
+          GtkWidget *widget;
+
+          widget = gtk_bin_get_child (GTK_BIN (tmp_list->data));
+          if (GTK_IS_LABEL (widget))
+            {
+              if (!allow_many)
+                {
+                  if (child)
+                    {
+                      child = NULL;
+                      break;
+                    }
+                  child = widget;
+                }
+              else
+                {
+                  if (*index == 0)
+                    {
+                     child = widget;
+                      break;
+                    }
+                  (*index)--;
+               }
+           }
+        }
+      else if (GTK_IS_CONTAINER (tmp_list->data))
+        {
+          child = find_label_child (GTK_CONTAINER (tmp_list->data), index, allow_many);
+          if (child)
+            break;
+        } 
+    }
+  g_list_free (children);
+  return child;
+}
+
+static GtkWidget*
+get_label_from_button (GtkWidget *button,
+                       gint      index,
+                       gboolean  allow_many)
+{
+  GtkWidget *child;
+
+  if (index > 0 && !allow_many)
+    g_warning ("Inconsistent values passed to get_label_from_button");
+
+  child = gtk_bin_get_child (GTK_BIN (button));
+  if (GTK_IS_ALIGNMENT (child))
+    child = gtk_bin_get_child (GTK_BIN (child));
+
+  if (GTK_IS_CONTAINER (child))
+    child = find_label_child (GTK_CONTAINER (child), &index, allow_many);
+  else if (!GTK_IS_LABEL (child))
+    child = NULL;
+
+  return child;
+}
+
+static void
+count_labels (GtkContainer *container,
+              gint         *n_labels)
+{
+  GList *children, *tmp_list;
+  children = gtk_container_get_children (container);
+
+  for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next) 
+    {
+      if (GTK_IS_LABEL (tmp_list->data))
+        {
+          (*n_labels)++;
+        }
+       /*
+        * Label for button which are GtkTreeView column headers are in a 
+        * GtkHBox in a GtkAlignment.
+        */
+      else if (GTK_IS_ALIGNMENT (tmp_list->data))
+        {
+          GtkWidget *widget;
+
+          widget = gtk_bin_get_child (GTK_BIN (tmp_list->data));
+          if (GTK_IS_LABEL (widget))
+            (*n_labels)++;
+        }
+      else if (GTK_IS_CONTAINER (tmp_list->data))
+        {
+          count_labels (GTK_CONTAINER (tmp_list->data), n_labels);
+        } 
+    }
+  g_list_free (children);
+}
+
+static gint
+get_n_labels_from_button (GtkWidget *button)
+{
+  GtkWidget *child;
+  gint n_labels;
+
+  n_labels = 0;
+
+  child = gtk_bin_get_child (GTK_BIN (button));
+  if (GTK_IS_ALIGNMENT (child))
+    child = gtk_bin_get_child (GTK_BIN (child));
+
+  if (GTK_IS_CONTAINER (child))
+    count_labels (GTK_CONTAINER (child), &n_labels);
+
+  return n_labels;
+}
+
+static void
+set_role_for_button (AtkObject *accessible,
+                     GtkWidget *button)
+{
+  GtkWidget *parent;
+  AtkRole role;
+
+  parent = gtk_widget_get_parent (button);
+  if (GTK_IS_TREE_VIEW (parent))
+    {
+      role = ATK_ROLE_TABLE_COLUMN_HEADER;
+      /*
+       * Even though the accessible parent of the column header will
+       * be reported as the table because the parent widget of the
+       * GtkTreeViewColumn's button is the GtkTreeView we set
+       * the accessible parent for column header to be the table
+       * to ensure that atk_object_get_index_in_parent() returns
+       * the correct value; see gail_widget_get_index_in_parent().
+       */
+      atk_object_set_parent (accessible, gtk_widget_get_accessible (parent));
+    }
+  else
+    role = ATK_ROLE_PUSH_BUTTON;
+
+  accessible->role =  role;
+}
+
+static gint
+get_n_attached_menus (GtkWidget  *widget)
+{
+  GList *list_menus;
+  
+  if (widget == NULL)
+    return 0;
+
+  list_menus = g_object_get_data (G_OBJECT (widget), GAIL_BUTTON_ATTACHED_MENUS);
+  if (list_menus == NULL)
+    return 0;
+
+  return g_list_length (list_menus);
+}
+
+static GtkWidget*
+get_nth_attached_menu (GtkWidget  *widget,
+                       gint       index)
+{
+  GtkWidget *attached_menu;
+  GList *list_menus;
+
+  if (widget == NULL)
+    return NULL;
+
+  list_menus = g_object_get_data (G_OBJECT (widget), GAIL_BUTTON_ATTACHED_MENUS);
+  if (list_menus == NULL ||
+      index >= g_list_length (list_menus))
+    return NULL;
+
+  attached_menu = (GtkWidget *) g_list_nth_data (list_menus, index);
+
+  return attached_menu;
+}
diff --git a/modules/other/gail/gailbutton.h b/modules/other/gail/gailbutton.h
new file mode 100644 (file)
index 0000000..2550af9
--- /dev/null
@@ -0,0 +1,77 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_BUTTON_H__
+#define __GAIL_BUTTON_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+#include <libgail-util/gailtextutil.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_BUTTON                     (gail_button_get_type ())
+#define GAIL_BUTTON(obj)                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_BUTTON, GailButton))
+#define GAIL_BUTTON_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_BUTTON, GailButtonClass))
+#define GAIL_IS_BUTTON(obj)                  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_BUTTON))
+#define GAIL_IS_BUTTON_CLASS(klass)          (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_BUTTON))
+#define GAIL_BUTTON_GET_CLASS(obj)           (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_BUTTON, GailButtonClass))
+
+typedef struct _GailButton                   GailButton;
+typedef struct _GailButtonClass              GailButtonClass;
+
+struct _GailButton
+{
+  GailContainer parent;
+
+  /*
+   * Cache the widget state so we know the previous state when it changed
+   */
+  gint8         state;
+
+  gchar         *click_description;
+  gchar         *press_description;
+  gchar         *release_description;
+  gchar         *click_keybinding;
+  guint         action_idle_handler;
+  GQueue        *action_queue;
+
+  GailTextUtil  *textutil;
+
+  gboolean     default_is_press;
+};
+
+GType gail_button_get_type (void);
+
+struct _GailButtonClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_button_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_BUTTON_H__ */
diff --git a/modules/other/gail/gailcalendar.c b/modules/other/gail/gailcalendar.c
new file mode 100644 (file)
index 0000000..7d74f54
--- /dev/null
@@ -0,0 +1,73 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailcalendar.h"
+
+static void         gail_calendar_class_init          (GailCalendarClass *klass);
+
+GType
+gail_calendar_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailCalendarClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_calendar_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailCalendar), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                   "GailCalendar", &tinfo, 0);
+  }
+  return type;
+}
+
+static void
+gail_calendar_class_init (GailCalendarClass *klass)
+{
+}
+
+AtkObject* 
+gail_calendar_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_CALENDAR (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_CALENDAR, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_CALENDAR;
+
+  return accessible;
+}
diff --git a/modules/other/gail/gailcalendar.h b/modules/other/gail/gailcalendar.h
new file mode 100644 (file)
index 0000000..568f4c4
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_CALENDAR_H__
+#define __GAIL_CALENDAR_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CALENDAR                   (gail_calendar_get_type ())
+#define GAIL_CALENDAR(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CALENDAR, GailCalendar))
+#define GAIL_CALENDAR_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CALENDAR, GailCalendarClass))
+#define GAIL_IS_CALENDAR(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CALENDAR))
+#define GAIL_IS_CALENDAR_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CALENDAR))
+#define GAIL_CALENDAR_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CALENDAR, GailCalendarClass))
+
+typedef struct _GailCalendar              GailCalendar;
+typedef struct _GailCalendarClass         GailCalendarClass;
+
+struct _GailCalendar
+{
+  GailWidget parent;
+};
+
+GType gail_calendar_get_type (void);
+
+struct _GailCalendarClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_calendar_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_CALENDAR_H__ */
diff --git a/modules/other/gail/gailcell.c b/modules/other/gail/gailcell.c
new file mode 100644 (file)
index 0000000..6848631
--- /dev/null
@@ -0,0 +1,577 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <stdlib.h>
+#include <gtk/gtk.h>
+#include "gailcontainercell.h"
+#include "gailcell.h"
+#include "gailcellparent.h"
+
+static void        gail_cell_class_init          (GailCellClass       *klass);
+static void         gail_cell_destroyed           (GtkWidget           *widget,
+                                                   GailCell            *cell);
+
+static void         gail_cell_object_init         (GailCell            *cell);
+static void         gail_cell_object_finalize     (GObject             *cell);
+static AtkStateSet* gail_cell_ref_state_set       (AtkObject           *obj);
+static gint         gail_cell_get_index_in_parent (AtkObject           *obj);
+
+/* AtkAction */
+
+static void         gail_cell_atk_action_interface_init 
+                                                  (AtkActionIface      *iface);
+static ActionInfo * _gail_cell_get_action_info    (GailCell            *cell,
+                                                  gint                index);
+static void         _gail_cell_destroy_action_info 
+                                                  (gpointer            data,
+                                                  gpointer            user_data);
+
+static gint         gail_cell_action_get_n_actions 
+                                                  (AtkAction           *action);
+static G_CONST_RETURN gchar*
+                    gail_cell_action_get_name     (AtkAction           *action,
+                                                  gint                index);
+static G_CONST_RETURN gchar *
+                    gail_cell_action_get_description 
+                                                  (AtkAction           *action,
+                                                  gint                index);
+static gboolean     gail_cell_action_set_description 
+                                                  (AtkAction           *action,
+                                                  gint                index,
+                                                  const gchar         *desc);
+static G_CONST_RETURN gchar *
+                    gail_cell_action_get_keybinding 
+                                                  (AtkAction           *action,
+                                                  gint                index);
+static gboolean     gail_cell_action_do_action    (AtkAction           *action,
+                                                  gint                index);
+static gboolean     idle_do_action                (gpointer            data);
+
+static void         atk_component_interface_init  (AtkComponentIface   *iface);
+static void         gail_cell_get_extents         (AtkComponent        *component,
+                                                   gint                *x,
+                                                   gint                *y,
+                                                   gint                *width,
+                                                   gint                *height,
+                                                   AtkCoordType        coord_type);
+static gboolean     gail_cell_grab_focus         (AtkComponent        *component);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_cell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailCellClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_cell_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailCell), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_cell_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_component_info =
+      {
+        (GInterfaceInitFunc) atk_component_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+
+      type = g_type_register_static (ATK_TYPE_OBJECT,
+                                     "GailCell", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+                                   &atk_component_info);
+
+    }
+  return type;
+}
+
+static void     
+gail_cell_class_init (GailCellClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+  g_object_class->finalize = gail_cell_object_finalize;
+
+  class->get_index_in_parent = gail_cell_get_index_in_parent;
+  class->ref_state_set = gail_cell_ref_state_set;
+}
+
+void 
+gail_cell_init (GailCell  *cell,
+                GtkWidget *widget,
+                AtkObject *parent,
+                gint      index)
+{
+  g_return_if_fail (GAIL_IS_CELL (cell));
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  cell->widget = widget;
+  atk_object_set_parent (ATK_OBJECT (cell), parent);
+  cell->index = index;
+
+  g_signal_connect_object (G_OBJECT (widget),
+                           "destroy",
+                           G_CALLBACK (gail_cell_destroyed ),
+                           cell, 0);
+}
+
+static void
+gail_cell_destroyed (GtkWidget       *widget,
+                     GailCell        *cell)
+{
+  /*
+   * This is the signal handler for the "destroy" signal for the 
+   * GtkWidget. We set the  pointer location to NULL;
+   */
+  cell->widget = NULL;
+}
+
+static void
+gail_cell_object_init (GailCell *cell)
+{
+  cell->state_set = atk_state_set_new ();
+  cell->widget = NULL;
+  cell->action_list = NULL;
+  cell->index = 0;
+  atk_state_set_add_state (cell->state_set, ATK_STATE_TRANSIENT);
+  atk_state_set_add_state (cell->state_set, ATK_STATE_ENABLED);
+  atk_state_set_add_state (cell->state_set, ATK_STATE_SENSITIVE);
+  atk_state_set_add_state (cell->state_set, ATK_STATE_SELECTABLE);
+  cell->refresh_index = NULL;
+}
+
+static void
+gail_cell_object_finalize (GObject *obj)
+{
+  GailCell *cell = GAIL_CELL (obj);
+  AtkRelationSet *relation_set;
+  AtkRelation *relation;
+  GPtrArray *target;
+  gpointer target_object;
+  gint i;
+
+  if (cell->state_set)
+    g_object_unref (cell->state_set);
+  g_list_free (cell->action_list);
+  if (cell->action_idle_handler)
+    {
+      g_source_remove (cell->action_idle_handler);
+      cell->action_idle_handler = 0;
+    }
+  relation_set = atk_object_ref_relation_set (ATK_OBJECT (obj));
+  if (ATK_IS_RELATION_SET (relation_set))
+    {
+      relation = atk_relation_set_get_relation_by_type (relation_set, 
+                                                        ATK_RELATION_NODE_CHILD_OF);
+      if (relation)
+        {
+          target = atk_relation_get_target (relation);
+          for (i = 0; i < target->len; i++)
+            {
+              target_object = g_ptr_array_index (target, i);
+              if (GAIL_IS_CELL (target_object))
+                {
+                  g_object_unref (target_object);
+                }
+            }
+        }
+      g_object_unref (relation_set);
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static AtkStateSet *
+gail_cell_ref_state_set (AtkObject *obj)
+{
+  GailCell *cell = GAIL_CELL (obj);
+  g_assert (cell->state_set);
+
+  g_object_ref(cell->state_set);
+  return cell->state_set;
+}
+
+gboolean
+gail_cell_add_state (GailCell     *cell, 
+                     AtkStateType state_type,
+                     gboolean     emit_signal)
+{
+  if (!atk_state_set_contains_state (cell->state_set, state_type))
+    {
+      gboolean rc;
+      AtkObject *parent;
+    
+      rc = atk_state_set_add_state (cell->state_set, state_type);
+      /*
+       * The signal should only be generated if the value changed,
+       * not when the cell is set up.  So states that are set
+       * initially should pass FALSE as the emit_signal argument.
+       */
+
+      if (emit_signal)
+        {
+          atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
+          /* If state_type is ATK_STATE_VISIBLE, additional notification */
+          if (state_type == ATK_STATE_VISIBLE)
+            g_signal_emit_by_name (cell, "visible_data_changed");
+        }
+
+      /* 
+       * If the parent is a flyweight container cell, propagate the state 
+       * change to it also 
+       */
+
+      parent = atk_object_get_parent (ATK_OBJECT (cell));
+      if (GAIL_IS_CONTAINER_CELL (parent))
+        gail_cell_add_state (GAIL_CELL (parent), state_type, emit_signal);
+      return rc;
+    }
+  else
+    return FALSE;
+}
+
+gboolean
+gail_cell_remove_state (GailCell     *cell, 
+                        AtkStateType state_type,
+                        gboolean     emit_signal)
+{
+  if (atk_state_set_contains_state (cell->state_set, state_type))
+    {
+      gboolean rc;
+      AtkObject *parent;
+
+      parent = atk_object_get_parent (ATK_OBJECT (cell));
+
+      rc = atk_state_set_remove_state (cell->state_set, state_type);
+      /*
+       * The signal should only be generated if the value changed,
+       * not when the cell is set up.  So states that are set
+       * initially should pass FALSE as the emit_signal argument.
+       */
+
+      if (emit_signal)
+        {
+          atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
+          /* If state_type is ATK_STATE_VISIBLE, additional notification */
+          if (state_type == ATK_STATE_VISIBLE)
+            g_signal_emit_by_name (cell, "visible_data_changed");
+        }
+
+      /* 
+       * If the parent is a flyweight container cell, propagate the state 
+       * change to it also 
+       */
+
+      if (GAIL_IS_CONTAINER_CELL (parent))
+        gail_cell_remove_state (GAIL_CELL (parent), state_type, emit_signal);
+      return rc;
+    }
+  else
+    return FALSE;
+}
+
+static gint
+gail_cell_get_index_in_parent (AtkObject *obj)
+{
+  GailCell *cell;
+
+  g_assert (GAIL_IS_CELL (obj));
+
+  cell = GAIL_CELL (obj);
+  if (atk_state_set_contains_state (cell->state_set, ATK_STATE_STALE))
+    if (cell->refresh_index)
+      {
+        cell->refresh_index (cell);
+        atk_state_set_remove_state (cell->state_set, ATK_STATE_STALE);
+      }
+  return cell->index;
+}
+
+static void
+gail_cell_atk_action_interface_init (AtkActionIface *iface)
+{
+  g_assert (iface != NULL);
+
+  iface->get_n_actions = gail_cell_action_get_n_actions;
+  iface->do_action = gail_cell_action_do_action;
+  iface->get_name = gail_cell_action_get_name;
+  iface->get_description = gail_cell_action_get_description;
+  iface->set_description = gail_cell_action_set_description;
+  iface->get_keybinding = gail_cell_action_get_keybinding;
+}
+
+void
+gail_cell_type_add_action_interface (GType type)
+{
+  static const GInterfaceInfo atk_action_info =
+  {
+    (GInterfaceInitFunc) gail_cell_atk_action_interface_init,
+    (GInterfaceFinalizeFunc) NULL,
+    NULL
+  };
+  g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                 &atk_action_info);
+}
+
+gboolean
+gail_cell_add_action (GailCell    *cell,
+                     const gchar *action_name,
+                     const gchar *action_description,
+                     const gchar *action_keybinding,
+                     ACTION_FUNC action_func)
+{
+  ActionInfo *info;
+  g_return_val_if_fail (GAIL_IS_CELL (cell), FALSE);
+  info = g_new (ActionInfo, 1);
+
+  if (action_name != NULL)
+    info->name = g_strdup (action_name);
+  else
+    info->name = NULL;
+  if (action_description != NULL)
+    info->description = g_strdup (action_description);
+  else
+    info->description = NULL;
+  if (action_keybinding != NULL)
+    info->keybinding = g_strdup (action_keybinding);
+  else
+    info->keybinding = NULL;
+  info->do_action_func = action_func;
+
+  cell->action_list = g_list_append (cell->action_list, (gpointer) info);
+  return TRUE;
+}
+
+gboolean
+gail_cell_remove_action (GailCell *cell,
+                        gint     action_index)
+{
+  GList *list_node;
+
+  g_return_val_if_fail (GAIL_IS_CELL (cell), FALSE);
+  list_node = g_list_nth (cell->action_list, action_index);
+  if (!list_node)
+    return FALSE;
+  _gail_cell_destroy_action_info (list_node->data, NULL);
+  cell->action_list = g_list_remove_link (cell->action_list, list_node);
+  return TRUE;
+}
+
+
+gboolean
+gail_cell_remove_action_by_name (GailCell    *cell,
+                                const gchar *action_name)
+{
+  GList *list_node;
+  gboolean action_found= FALSE;
+  
+  g_return_val_if_fail (GAIL_IS_CELL (cell), FALSE);
+  for (list_node = cell->action_list; list_node && !action_found; 
+                    list_node = list_node->next)
+    {
+      if (!g_strcasecmp (((ActionInfo *)(list_node->data))->name, action_name))
+       {
+         action_found = TRUE;
+         break;
+       }
+    }
+  if (!action_found)
+    return FALSE;
+  _gail_cell_destroy_action_info (list_node->data, NULL);
+  cell->action_list = g_list_remove_link (cell->action_list, list_node);
+  return TRUE;
+}
+
+static ActionInfo *
+_gail_cell_get_action_info (GailCell *cell,
+                           gint     index)
+{
+  GList *list_node;
+
+  g_return_val_if_fail (GAIL_IS_CELL (cell), NULL);
+  if (cell->action_list == NULL)
+    return NULL;
+  list_node = g_list_nth (cell->action_list, index);
+  if (!list_node)
+    return NULL;
+  return (ActionInfo *) (list_node->data);
+}
+
+
+static void
+_gail_cell_destroy_action_info (gpointer action_info, 
+                                gpointer user_data)
+{
+  ActionInfo *info = (ActionInfo *)action_info;
+  g_assert (info != NULL);
+  g_free (info->name);
+  g_free (info->description);
+  g_free (info->keybinding);
+  g_free (info);
+}
+static gint
+gail_cell_action_get_n_actions (AtkAction *action)
+{
+  GailCell *cell = GAIL_CELL(action);
+  if (cell->action_list != NULL)
+    return g_list_length (cell->action_list);
+  else
+    return 0;
+}
+
+static G_CONST_RETURN gchar *
+gail_cell_action_get_name (AtkAction *action,
+                          gint      index)
+{
+  GailCell *cell = GAIL_CELL(action);
+  ActionInfo *info = _gail_cell_get_action_info (cell, index);
+
+  if (info == NULL)
+    return NULL;
+  return info->name;
+}
+
+static G_CONST_RETURN gchar *
+gail_cell_action_get_description (AtkAction *action,
+                                 gint      index)
+{
+  GailCell *cell = GAIL_CELL(action);
+  ActionInfo *info = _gail_cell_get_action_info (cell, index);
+
+  if (info == NULL)
+    return NULL;
+  return info->description;
+}
+
+static gboolean
+gail_cell_action_set_description (AtkAction   *action,
+                                 gint        index,
+                                 const gchar *desc)
+{
+  GailCell *cell = GAIL_CELL(action);
+  ActionInfo *info = _gail_cell_get_action_info (cell, index);
+
+  if (info == NULL)
+    return FALSE;
+  g_free (info->description);
+  info->description = g_strdup (desc);
+  return TRUE;
+}
+
+static G_CONST_RETURN gchar *
+gail_cell_action_get_keybinding (AtkAction *action,
+                                gint      index)
+{
+  GailCell *cell = GAIL_CELL(action);
+  ActionInfo *info = _gail_cell_get_action_info (cell, index);
+  if (info == NULL)
+    return NULL;
+  return info->keybinding;
+}
+
+static gboolean
+gail_cell_action_do_action (AtkAction *action,
+                           gint      index)
+{
+  GailCell *cell = GAIL_CELL(action);
+  ActionInfo *info = _gail_cell_get_action_info (cell, index);
+  if (info == NULL)
+    return FALSE;
+  if (info->do_action_func == NULL)
+    return FALSE;
+  if (cell->action_idle_handler)
+    return FALSE;
+  cell->action_func = info->do_action_func;
+  cell->action_idle_handler = g_idle_add (idle_do_action, cell);
+  return TRUE;
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  GailCell *cell;
+
+  GDK_THREADS_ENTER ();
+
+  cell = GAIL_CELL (data);
+  cell->action_idle_handler = 0;
+  cell->action_func (cell);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+atk_component_interface_init (AtkComponentIface *iface)
+{
+  g_assert (iface != NULL);
+
+  iface->get_extents = gail_cell_get_extents;
+  iface->grab_focus = gail_cell_grab_focus;
+}
+
+static void 
+gail_cell_get_extents (AtkComponent *component,
+                       gint         *x,
+                       gint         *y,
+                       gint         *width,
+                       gint         *height,
+                       AtkCoordType coord_type)
+{
+  GailCell *gailcell;
+  AtkObject *cell_parent;
+
+  g_assert (GAIL_IS_CELL (component));
+
+  gailcell = GAIL_CELL (component);
+
+  cell_parent = gtk_widget_get_accessible (gailcell->widget);
+
+  gail_cell_parent_get_cell_extents (GAIL_CELL_PARENT (cell_parent), 
+                                   gailcell, x, y, width, height, coord_type);
+}
+
+static gboolean 
+gail_cell_grab_focus (AtkComponent *component)
+{
+  GailCell *gailcell;
+  AtkObject *cell_parent;
+
+  g_assert (GAIL_IS_CELL (component));
+
+  gailcell = GAIL_CELL (component);
+
+  cell_parent = gtk_widget_get_accessible (gailcell->widget);
+
+  return gail_cell_parent_grab_focus (GAIL_CELL_PARENT (cell_parent), 
+                                      gailcell);
+}
diff --git a/modules/other/gail/gailcell.h b/modules/other/gail/gailcell.h
new file mode 100644 (file)
index 0000000..7329c89
--- /dev/null
@@ -0,0 +1,110 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_CELL_H__
+#define __GAIL_CELL_H__
+
+#include <atk/atk.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CELL                           (gail_cell_get_type ())
+#define GAIL_CELL(obj)                           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CELL, GailCell))
+#define GAIL_CELL_CLASS(klass)                   (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CELL, GailCellClass))
+#define GAIL_IS_CELL(obj)                        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CELL))
+#define GAIL_IS_CELL_CLASS(klass)                (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CELL))
+#define GAIL_CELL_GET_CLASS(obj)                 (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CELL, GailCellClass))
+
+typedef struct _GailCell                  GailCell;
+typedef struct _GailCellClass             GailCellClass;
+typedef struct _ActionInfo ActionInfo;
+typedef void (*ACTION_FUNC) (GailCell *cell);
+  
+struct _GailCell
+{
+  AtkObject parent;
+
+  GtkWidget    *widget;
+  /*
+   * This cached value is used only by atk_object_get_index_in_parent()
+   * which updates the value when it is stale.
+   */
+  gint         index;
+  AtkStateSet *state_set;
+  GList       *action_list;
+  void (*refresh_index) (GailCell *cell);
+  gint         action_idle_handler;
+  ACTION_FUNC  action_func;
+};
+
+GType gail_cell_get_type (void);
+
+struct _GailCellClass
+{
+  AtkObjectClass parent_class;
+};
+
+struct _ActionInfo {
+  gchar *name;
+  gchar *description;
+  gchar *keybinding;
+  ACTION_FUNC do_action_func;
+};
+
+
+void      gail_cell_init                 (GailCell        *cell,
+                                          GtkWidget       *widget, 
+                                          AtkObject       *parent,
+                                         gint            index);
+
+gboolean gail_cell_add_state             (GailCell        *cell,
+                                          AtkStateType    state_type,
+                                          gboolean        emit_signal);
+
+gboolean gail_cell_remove_state          (GailCell        *cell,
+                                          AtkStateType    state_type,
+                                          gboolean        emit_signal);
+
+void     gail_cell_type_add_action_interface 
+                                         (GType           type);
+
+gboolean gail_cell_add_action            (GailCell        *cell,
+                                         const gchar     *action_name,
+                                         const gchar     *action_description,
+                                         const gchar     *action_keybinding,
+                                         ACTION_FUNC     action_func);
+
+gboolean gail_cell_remove_action         (GailCell        *cell,
+                                          gint            action_id);
+
+gboolean gail_cell_remove_action_by_name (GailCell        *cell,
+                                          const gchar     *action_name);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_CELL_H__ */
diff --git a/modules/other/gail/gailcellparent.c b/modules/other/gail/gailcellparent.c
new file mode 100644 (file)
index 0000000..06481c6
--- /dev/null
@@ -0,0 +1,124 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+
+ * Copyright 2001 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 <gtk/gtkwidget.h>
+#include "gailcellparent.h"
+
+GType
+gail_cell_parent_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) 
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailCellParentIface),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+
+      };
+
+      type = g_type_register_static (G_TYPE_INTERFACE, "GailCellParent", &tinfo, 0);
+    }
+
+  return type;
+}
+
+/**
+ * gail_cell_parent_get_cell_extents:
+ * @parent: a #GObject instance that implements GailCellParentIface
+ * @cell: a #GailCell whose extents is required
+ * @x: address of #gint to put x coordinate
+ * @y: address of #gint to put y coordinate
+ * @width: address of #gint to put width
+ * @height: address of #gint to put height
+ * @coord_type: specifies whether the coordinates are relative to the screen
+ * or to the components top level window
+ *
+ * Gets the rectangle which gives the extent of the @cell.
+ *
+ **/
+void
+gail_cell_parent_get_cell_extents (GailCellParent *parent,
+                                   GailCell       *cell,
+                                   gint           *x,
+                                   gint           *y,
+                                   gint           *width,
+                                   gint           *height,
+                                   AtkCoordType   coord_type)
+{
+  GailCellParentIface *iface;
+
+  g_return_if_fail (GAIL_IS_CELL_PARENT (parent));
+
+  iface = GAIL_CELL_PARENT_GET_IFACE (parent);
+
+  if (iface->get_cell_extents)
+    (iface->get_cell_extents) (parent, cell, x, y, width, height, coord_type);
+}
+
+/**
+ * gail_cell_parent_get_cell_area:
+ * @parent: a #GObject instance that implements GailCellParentIface
+ * @cell: a #GailCell whose area is required
+ * @cell_rect: address of #GdkRectangle to put the cell area
+ *
+ * Gets the cell area of the @cell.
+ *
+ **/
+void
+gail_cell_parent_get_cell_area (GailCellParent *parent,
+                                GailCell       *cell,
+                                GdkRectangle   *cell_rect)
+{
+  GailCellParentIface *iface;
+
+  g_return_if_fail (GAIL_IS_CELL_PARENT (parent));
+  g_return_if_fail (cell_rect);
+
+  iface = GAIL_CELL_PARENT_GET_IFACE (parent);
+
+  if (iface->get_cell_area)
+    (iface->get_cell_area) (parent, cell, cell_rect);
+}
+/**
+ * gail_cell_parent_grab_focus:
+ * @parent: a #GObject instance that implements GailCellParentIface
+ * @cell: a #GailCell whose area is required
+ *
+ * Puts focus in the specified cell.
+ *
+ **/
+gboolean
+gail_cell_parent_grab_focus (GailCellParent *parent,
+                             GailCell       *cell)
+{
+  GailCellParentIface *iface;
+
+  g_return_val_if_fail (GAIL_IS_CELL_PARENT (parent), FALSE);
+
+  iface = GAIL_CELL_PARENT_GET_IFACE (parent);
+
+  if (iface->grab_focus)
+    return (iface->grab_focus) (parent, cell);
+  else
+    return FALSE;
+}
diff --git a/modules/other/gail/gailcellparent.h b/modules/other/gail/gailcellparent.h
new file mode 100644 (file)
index 0000000..3932093
--- /dev/null
@@ -0,0 +1,88 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ *
+ * Copyright 2001 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_CELL_PARENT_H__
+#define __GAIL_CELL_PARENT_H__
+
+#include <atk/atkobject.h>
+#include <atk/atkutil.h>
+#include <gail/gailcell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * The GailCellParent interface should be supported by any object which
+ * contains children which are flyweights, i.e. do not have corresponding
+ * widgets and the children need help from their parent to provide
+ * functionality. One example is GailTreeView where the children GailCell
+ * need help from the GailTreeView in order to implement 
+ * atk_component_get_extents
+ */
+
+#define GAIL_TYPE_CELL_PARENT            (gail_cell_parent_get_type ())
+#define GAIL_IS_CELL_PARENT(obj)         G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CELL_PARENT)
+#define GAIL_CELL_PARENT(obj)            G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CELL_PARENT, GailCellParent)
+#define GAIL_CELL_PARENT_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GAIL_TYPE_CELL_PARENT, GailCellParentIface))
+
+#ifndef _TYPEDEF_GAIL_CELL_PARENT_
+#define _TYPEDEF_GAIL_CELL_PARENT_
+typedef struct _GailCellParent GailCellParent;
+#endif
+typedef struct _GailCellParentIface GailCellParentIface;
+
+struct _GailCellParentIface
+{
+  GTypeInterface parent;
+  void                  ( *get_cell_extents)      (GailCellParent        *parent,
+                                                   GailCell              *cell,
+                                                   gint                  *x,
+                                                   gint                  *y,
+                                                   gint                  *width,
+                                                   gint                  *height,
+                                                   AtkCoordType          coord_type);
+  void                  ( *get_cell_area)         (GailCellParent        *parent,
+                                                   GailCell              *cell,
+                                                   GdkRectangle          *cell_rect);
+  gboolean              ( *grab_focus)            (GailCellParent        *parent,
+                                                   GailCell              *cell);
+};
+
+GType  gail_cell_parent_get_type               (void);
+
+void   gail_cell_parent_get_cell_extents       (GailCellParent        *parent,
+                                                GailCell              *cell,
+                                                gint                  *x,
+                                                gint                  *y,
+                                                gint                  *width,
+                                                gint                  *height,
+                                                AtkCoordType          coord_type
+);
+void  gail_cell_parent_get_cell_area           (GailCellParent        *parent,
+                                                GailCell              *cell,
+                                                GdkRectangle          *cell_rect);
+gboolean gail_cell_parent_grab_focus           (GailCellParent        *parent,
+                                                GailCell              *cell);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __GAIL_CELL_PARENT_H__ */
diff --git a/modules/other/gail/gailcheckmenuitem.c b/modules/other/gail/gailcheckmenuitem.c
new file mode 100644 (file)
index 0000000..55164f6
--- /dev/null
@@ -0,0 +1,166 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002, 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 "gailcheckmenuitem.h"
+#include "gailchecksubmenuitem.h"
+
+static void      gail_check_menu_item_class_init        (GailCheckMenuItemClass *klass);
+
+static void      gail_check_menu_item_toggled_gtk       (GtkWidget              *widget);
+
+static void      gail_check_menu_item_real_notify_gtk   (GObject                *obj,
+                                                         GParamSpec             *pspec);
+
+static void      gail_check_menu_item_real_initialize   (AtkObject              *obj,
+                                                         gpointer               data);
+
+static AtkStateSet* gail_check_menu_item_ref_state_set  (AtkObject              *accessible);
+
+static GailMenuItemClass *parent_class = NULL;
+
+GType
+gail_check_menu_item_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailCheckMenuItemClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_check_menu_item_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailCheckMenuItem), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_MENU_ITEM,
+                                     "GailCheckMenuItem", &tinfo, 0);
+    }
+
+  return type;
+}
+
+static void
+gail_check_menu_item_class_init (GailCheckMenuItemClass *klass)
+{
+  GailWidgetClass *widget_class;
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  widget_class = (GailWidgetClass*)klass;
+  widget_class->notify_gtk = gail_check_menu_item_real_notify_gtk;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_state_set = gail_check_menu_item_ref_state_set;
+  class->initialize = gail_check_menu_item_real_initialize;
+}
+
+AtkObject* 
+gail_check_menu_item_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_CHECK_MENU_ITEM (widget), NULL);
+
+  if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)))
+    return gail_check_sub_menu_item_new (widget);
+
+  object = g_object_new (GAIL_TYPE_CHECK_MENU_ITEM, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+  return accessible;
+}
+
+static void
+gail_check_menu_item_real_initialize (AtkObject *obj,
+                                      gpointer  data)
+{
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  g_signal_connect (data,
+                    "toggled",
+                    G_CALLBACK (gail_check_menu_item_toggled_gtk),
+                    NULL);
+
+  obj->role = ATK_ROLE_CHECK_MENU_ITEM;
+}
+
+static void
+gail_check_menu_item_toggled_gtk (GtkWidget       *widget)
+{
+  AtkObject *accessible;
+  GtkCheckMenuItem *check_menu_item;
+
+  check_menu_item = GTK_CHECK_MENU_ITEM (widget);
+
+  accessible = gtk_widget_get_accessible (widget);
+  atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, 
+                                  check_menu_item->active);
+} 
+
+static AtkStateSet*
+gail_check_menu_item_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkCheckMenuItem *check_menu_item;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+  if (widget == NULL)
+    return state_set;
+
+  check_menu_item = GTK_CHECK_MENU_ITEM (widget);
+
+  if (gtk_check_menu_item_get_active (check_menu_item))
+    atk_state_set_add_state (state_set, ATK_STATE_CHECKED);
+
+  if (gtk_check_menu_item_get_inconsistent (check_menu_item))
+    atk_state_set_remove_state (state_set, ATK_STATE_ENABLED);
+  return state_set;
+}
+
+static void
+gail_check_menu_item_real_notify_gtk (GObject           *obj,
+                                    GParamSpec        *pspec)
+{
+  GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM (obj);
+  AtkObject *atk_obj;
+
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (check_menu_item));
+
+  if (strcmp (pspec->name, "inconsistent") == 0)
+    atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED,
+                       !gtk_check_menu_item_get_inconsistent (check_menu_item));
+  else
+    GAIL_WIDGET_CLASS (parent_class)->notify_gtk (obj, pspec);
+}
diff --git a/modules/other/gail/gailcheckmenuitem.h b/modules/other/gail/gailcheckmenuitem.h
new file mode 100644 (file)
index 0000000..292cdd9
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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_CHECK_MENU_ITEM_H__
+#define __GAIL_CHECK_MENU_ITEM_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailmenuitem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CHECK_MENU_ITEM              (gail_check_menu_item_get_type ())
+#define GAIL_CHECK_MENU_ITEM(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CHECK_MENU_ITEM, GailCheckMenuItem))
+#define GAIL_CHECK_MENU_ITEM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CHECK_MENU_ITEM, GailCheckMenuItemClass))
+#define GAIL_IS_CHECK_MENU_ITEM(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CHECK_MENU_ITEM))
+#define GAIL_IS_CHECK_MENU_ITEM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CHECK_MENU_ITEM))
+#define GAIL_CHECK_MENU_ITEM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CHECK_MENU_ITEM, GailCheckMenuItemClass))
+
+typedef struct _GailCheckMenuItem              GailCheckMenuItem;
+typedef struct _GailCheckMenuItemClass         GailCheckMenuItemClass;
+
+struct _GailCheckMenuItem
+{
+  GailMenuItem parent;
+};
+
+GType gail_check_menu_item_get_type (void);
+
+struct _GailCheckMenuItemClass
+{
+  GailMenuItemClass parent_class;
+};
+
+AtkObject* gail_check_menu_item_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_CHECK_MENU_ITEM_H__ */
diff --git a/modules/other/gail/gailchecksubmenuitem.c b/modules/other/gail/gailchecksubmenuitem.c
new file mode 100644 (file)
index 0000000..d011f77
--- /dev/null
@@ -0,0 +1,162 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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 "gailchecksubmenuitem.h"
+
+static void      gail_check_sub_menu_item_class_init        (GailCheckSubMenuItemClass *klass);
+
+static void      gail_check_sub_menu_item_toggled_gtk       (GtkWidget              *widget);
+
+static void      gail_check_sub_menu_item_real_notify_gtk   (GObject                *obj,
+                                                             GParamSpec             *pspec);
+
+static void      gail_check_sub_menu_item_real_initialize   (AtkObject              *obj,
+                                                             gpointer               data);
+
+static AtkStateSet* gail_check_sub_menu_item_ref_state_set  (AtkObject              *accessible);
+
+static GailSubMenuItemClass *parent_class = NULL;
+
+GType
+gail_check_sub_menu_item_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailCheckSubMenuItemClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_check_sub_menu_item_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailCheckSubMenuItem), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_SUB_MENU_ITEM,
+                                     "GailCheckSubMenuItem", &tinfo, 0);
+    }
+
+  return type;
+}
+
+static void
+gail_check_sub_menu_item_class_init (GailCheckSubMenuItemClass *klass)
+{
+  GailWidgetClass *widget_class;
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  widget_class = (GailWidgetClass*)klass;
+  widget_class->notify_gtk = gail_check_sub_menu_item_real_notify_gtk;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_state_set = gail_check_sub_menu_item_ref_state_set;
+  class->initialize = gail_check_sub_menu_item_real_initialize;
+}
+
+AtkObject* 
+gail_check_sub_menu_item_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_CHECK_MENU_ITEM (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_CHECK_SUB_MENU_ITEM, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_check_sub_menu_item_real_initialize (AtkObject *obj,
+                                          gpointer  data)
+{
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  g_signal_connect (data,
+                    "toggled",
+                    G_CALLBACK (gail_check_sub_menu_item_toggled_gtk),
+                    NULL);
+
+  obj->role = ATK_ROLE_CHECK_MENU_ITEM;
+}
+
+static void
+gail_check_sub_menu_item_toggled_gtk (GtkWidget       *widget)
+{
+  AtkObject *accessible;
+  GtkCheckMenuItem *check_menu_item;
+
+  check_menu_item = GTK_CHECK_MENU_ITEM (widget);
+
+  accessible = gtk_widget_get_accessible (widget);
+  atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, 
+                                  check_menu_item->active);
+} 
+
+static AtkStateSet*
+gail_check_sub_menu_item_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkCheckMenuItem *check_menu_item;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+  if (widget == NULL)
+    return state_set;
+
+  check_menu_item = GTK_CHECK_MENU_ITEM (widget);
+
+  if (gtk_check_menu_item_get_active (check_menu_item))
+    atk_state_set_add_state (state_set, ATK_STATE_CHECKED);
+
+  if (gtk_check_menu_item_get_inconsistent (check_menu_item))
+    atk_state_set_remove_state (state_set, ATK_STATE_ENABLED);
+  return state_set;
+}
+
+static void
+gail_check_sub_menu_item_real_notify_gtk (GObject           *obj,
+                                          GParamSpec        *pspec)
+{
+  GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM (obj);
+  AtkObject *atk_obj;
+
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (check_menu_item));
+
+  if (strcmp (pspec->name, "inconsistent") == 0)
+    atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED,
+                       !gtk_check_menu_item_get_inconsistent (check_menu_item));
+  else
+    GAIL_WIDGET_CLASS (parent_class)->notify_gtk (obj, pspec);
+}
diff --git a/modules/other/gail/gailchecksubmenuitem.h b/modules/other/gail/gailchecksubmenuitem.h
new file mode 100644 (file)
index 0000000..174cdba
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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_CHECK_SUB_MENU_ITEM_H__
+#define __GAIL_CHECK_SUB_MENU_ITEM_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailsubmenuitem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CHECK_SUB_MENU_ITEM              (gail_check_sub_menu_item_get_type ())
+#define GAIL_CHECK_SUB_MENU_ITEM(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CHECK_SUB_MENU_ITEM, GailCheckSubMenuItem))
+#define GAIL_CHECK_SUB_MENU_ITEM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CHECK_SUB_MENU_ITEM, GailCheckSubMenuItemClass))
+#define GAIL_IS_CHECK_SUB_MENU_ITEM(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CHECK_SUB_MENU_ITEM))
+#define GAIL_IS_CHECK_SUB_MENU_ITEM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CHECK_SUB_MENU_ITEM))
+#define GAIL_CHECK_SUB_MENU_ITEM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CHECK_SUB_MENU_ITEM, GailCheckSubMenuItemClass))
+
+typedef struct _GailCheckSubMenuItem              GailCheckSubMenuItem;
+typedef struct _GailCheckSubMenuItemClass         GailCheckSubMenuItemClass;
+
+struct _GailCheckSubMenuItem
+{
+  GailSubMenuItem parent;
+};
+
+GType gail_check_sub_menu_item_get_type (void);
+
+struct _GailCheckSubMenuItemClass
+{
+  GailSubMenuItemClass parent_class;
+};
+
+AtkObject* gail_check_sub_menu_item_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_CHECK_SUB_MENU_ITEM_H__ */
diff --git a/modules/other/gail/gailclist.c b/modules/other/gail/gailclist.c
new file mode 100644 (file)
index 0000000..d56839e
--- /dev/null
@@ -0,0 +1,1670 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include <stdio.h>
+#include "gailclist.h"
+#include "gailclistcell.h"
+#include "gailcellparent.h"
+
+/* Copied from gtkclist.c */
+/* this defigns the base grid spacing */
+#define CELL_SPACING 1
+
+/* added the horizontal space at the beginning and end of a row*/
+#define COLUMN_INSET 3
+
+
+/* gives the top pixel of the given row in context of
+ * the clist's voffset */
+#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
+                                    (((row) + 1) * CELL_SPACING) + \
+                                    (clist)->voffset)
+
+/* returns the row index from a y pixel location in the
+ * context of the clist's voffset */
+#define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
+                                    ((clist)->row_height + CELL_SPACING))
+/* gives the left pixel of the given column in context of
+ * the clist's hoffset */
+#define COLUMN_LEFT_XPIXEL(clist, colnum)  ((clist)->column[(colnum)].area.x + \
+                                            (clist)->hoffset)
+
+/* returns the column index from a x pixel location in the
+ * context of the clist's hoffset */
+static inline gint
+COLUMN_FROM_XPIXEL (GtkCList * clist,
+                    gint x)
+{
+  gint i, cx;
+
+  for (i = 0; i < clist->columns; i++)
+    if (clist->column[i].visible)
+      {
+        cx = clist->column[i].area.x + clist->hoffset;
+
+        if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
+            x <= (cx + clist->column[i].area.width + COLUMN_INSET))
+          return i;
+      }
+
+  /* no match */
+  return -1;
+}
+
+/* returns the top pixel of the given row in the context of
+ * the list height */
+#define ROW_TOP(clist, row)        (((clist)->row_height + CELL_SPACING) * (row))
+
+/* returns the left pixel of the given column in the context of
+ * the list width */
+#define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
+
+/* returns the total height of the list */
+#define LIST_HEIGHT(clist)         (((clist)->row_height * ((clist)->rows)) + \
+                                    (CELL_SPACING * ((clist)->rows + 1)))
+
+static inline gint
+LIST_WIDTH (GtkCList * clist)
+{
+  gint last_column;
+
+  for (last_column = clist->columns - 1;
+       last_column >= 0 && !clist->column[last_column].visible; last_column--);
+
+  if (last_column >= 0)
+    return (clist->column[last_column].area.x +
+            clist->column[last_column].area.width +
+            COLUMN_INSET + CELL_SPACING);
+  return 0;
+}
+
+/* returns the GList item for the nth row */
+#define ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \
+                                 (clist)->row_list_end : \
+                                 g_list_nth ((clist)->row_list, (row)))
+
+typedef struct _GailCListRow        GailCListRow;
+typedef struct _GailCListCellData   GailCListCellData;
+
+
+static void       gail_clist_class_init            (GailCListClass    *klass);
+static void       gail_clist_real_initialize       (AtkObject         *obj,
+                                                    gpointer          data);
+static void       gail_clist_finalize              (GObject           *object);
+
+static gint       gail_clist_get_n_children        (AtkObject         *obj);
+static AtkObject* gail_clist_ref_child             (AtkObject         *obj,
+                                                    gint              i);
+static AtkStateSet* gail_clist_ref_state_set       (AtkObject         *obj);
+
+
+static void       atk_selection_interface_init     (AtkSelectionIface *iface);
+static gboolean   gail_clist_clear_selection       (AtkSelection   *selection);
+
+static AtkObject* gail_clist_ref_selection         (AtkSelection   *selection,
+                                                    gint           i);
+static gint       gail_clist_get_selection_count   (AtkSelection   *selection);
+static gboolean   gail_clist_is_child_selected     (AtkSelection   *selection,
+                                                    gint           i);
+static gboolean   gail_clist_select_all_selection  (AtkSelection   *selection);
+
+static void       atk_table_interface_init         (AtkTableIface     *iface);
+static gint       gail_clist_get_index_at          (AtkTable      *table,
+                                                    gint          row,
+                                                    gint          column);
+static gint       gail_clist_get_column_at_index   (AtkTable      *table,
+                                                    gint          index);
+static gint       gail_clist_get_row_at_index      (AtkTable      *table,
+                                                    gint          index);
+static AtkObject* gail_clist_ref_at                (AtkTable      *table,
+                                                    gint          row,
+                                                    gint          column);
+static AtkObject* gail_clist_ref_at_actual         (AtkTable      *table,
+                                                    gint          row,
+                                                    gint          column);
+static AtkObject*
+                  gail_clist_get_caption           (AtkTable      *table);
+
+static gint       gail_clist_get_n_columns         (AtkTable      *table);
+static gint       gail_clist_get_n_actual_columns  (GtkCList      *clist);
+
+static G_CONST_RETURN gchar*
+                  gail_clist_get_column_description(AtkTable      *table,
+                                                    gint          column);
+static AtkObject*  gail_clist_get_column_header     (AtkTable      *table,
+                                                    gint          column);
+static gint       gail_clist_get_n_rows            (AtkTable      *table);
+static G_CONST_RETURN gchar*
+                  gail_clist_get_row_description   (AtkTable      *table,
+                                                    gint          row);
+static AtkObject*  gail_clist_get_row_header        (AtkTable      *table,
+                                                    gint          row);
+static AtkObject* gail_clist_get_summary           (AtkTable      *table);
+static gboolean   gail_clist_add_row_selection     (AtkTable      *table,
+                                                    gint          row);
+static gboolean   gail_clist_remove_row_selection  (AtkTable      *table,
+                                                    gint          row);
+static gint       gail_clist_get_selected_rows     (AtkTable      *table,
+                                                    gint          **rows_selected);
+static gboolean   gail_clist_is_row_selected       (AtkTable      *table,
+                                                    gint          row);
+static gboolean   gail_clist_is_selected           (AtkTable      *table,
+                                                    gint          row,
+                                                    gint          column);
+static void       gail_clist_set_caption           (AtkTable      *table,
+                                                    AtkObject     *caption);
+static void       gail_clist_set_column_description(AtkTable      *table,
+                                                    gint          column,
+                                                    const gchar   *description);
+static void       gail_clist_set_column_header     (AtkTable      *table,
+                                                    gint          column,
+                                                    AtkObject     *header);
+static void       gail_clist_set_row_description   (AtkTable      *table,
+                                                    gint          row,
+                                                    const gchar   *description);
+static void       gail_clist_set_row_header        (AtkTable      *table,
+                                                    gint          row,
+                                                    AtkObject     *header);
+static void       gail_clist_set_summary           (AtkTable      *table,
+                                                    AtkObject     *accessible);
+
+/* gailcellparent.h */
+
+static void       gail_cell_parent_interface_init  (GailCellParentIface *iface);
+static void       gail_clist_get_cell_extents      (GailCellParent      *parent,
+                                                    GailCell            *cell,
+                                                    gint                *x,
+                                                    gint                *y,
+                                                    gint                *width,
+                                                    gint                *height,
+                                                    AtkCoordType        coord_type);
+
+static void       gail_clist_get_cell_area         (GailCellParent      *parent,
+                                                    GailCell            *cell,
+                                                    GdkRectangle        *cell_rect);
+
+static void       gail_clist_select_row_gtk        (GtkCList      *clist,
+                                                    int           row,
+                                                    int           column,
+                                                    GdkEvent      *event,
+                                                    gpointer      data);
+static void       gail_clist_unselect_row_gtk      (GtkCList      *clist,
+                                                    int           row,
+                                                    int           column,
+                                                    GdkEvent      *event,
+                                                    gpointer      data);
+static gint       gail_clist_get_visible_column    (AtkTable      *table,
+                                                    int           column);
+static gint       gail_clist_get_actual_column     (AtkTable      *table,
+                                                    int           visible_column);
+static void       gail_clist_set_row_data          (AtkTable      *table,
+                                                    gint          row,
+                                                    const gchar   *description,
+                                                    AtkObject     *header,
+                                                    gboolean      is_header);
+static GailCListRow*
+                  gail_clist_get_row_data          (AtkTable      *table,
+                                                    gint          row);
+static void       gail_clist_get_visible_rect      (GtkCList      *clist,
+                                                    GdkRectangle  *clist_rect);
+static gboolean   gail_clist_is_cell_visible       (GdkRectangle  *cell_rect,
+                                                    GdkRectangle  *visible_rect);
+static void       gail_clist_cell_data_new         (GailCList     *clist,
+                                                    GailCell      *cell,
+                                                    gint          column,
+                                                    gint          row);
+static void       gail_clist_cell_destroyed        (gpointer      data);
+static void       gail_clist_cell_data_remove      (GailCList     *clist,
+                                                    GailCell      *cell);
+static GailCell*  gail_clist_find_cell             (GailCList     *clist,
+                                                    gint          index);
+static void       gail_clist_adjustment_changed    (GtkAdjustment *adjustment,
+                                                    GtkCList      *clist);
+
+struct _GailCListColumn
+{
+  gchar *description;
+  AtkObject *header;
+};
+
+struct _GailCListRow
+{
+  GtkCListRow *row_data;
+  int row_number;
+  gchar *description;
+  AtkObject *header;
+};
+
+struct _GailCListCellData
+{
+  GtkCell *gtk_cell;
+  GailCell *gail_cell;
+  int row_number;
+  int column_number;
+};
+
+static gpointer parent_class = NULL;
+
+GType
+gail_clist_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailCListClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_clist_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailCList), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_table_info =
+      {
+        (GInterfaceInitFunc) atk_table_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_selection_info =
+      {
+        (GInterfaceInitFunc) atk_selection_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo gail_cell_parent_info =
+      {
+        (GInterfaceInitFunc) gail_cell_parent_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailCList", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_TABLE,
+                                   &atk_table_info);
+      g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                   &atk_selection_info);
+      g_type_add_interface_static (type, GAIL_TYPE_CELL_PARENT,
+                                   &gail_cell_parent_info);
+    }
+  return type;
+}
+
+static void
+gail_clist_class_init (GailCListClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+  class->get_n_children = gail_clist_get_n_children;
+  class->ref_child = gail_clist_ref_child;
+  class->ref_state_set = gail_clist_ref_state_set;
+  class->initialize = gail_clist_real_initialize;
+
+  gobject_class->finalize = gail_clist_finalize;
+}
+
+AtkObject* 
+gail_clist_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_CLIST (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_CLIST, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_TABLE;
+
+  return accessible;
+}
+
+static void
+gail_clist_real_initialize (AtkObject *obj,
+                            gpointer  data)
+{
+  GailCList *clist;
+  GtkCList *gtk_clist;
+  gint i;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  clist = GAIL_CLIST (obj);
+
+  clist->caption = NULL;
+  clist->summary = NULL;
+  clist->row_data = NULL;
+  clist->cell_data = NULL;
+  clist->previous_selected_cell = NULL;
+
+  gtk_clist = GTK_CLIST (data);
+  clist->n_cols = gtk_clist->columns;
+  clist->columns = g_new (GailCListColumn, gtk_clist->columns);
+  for (i = 0; i < gtk_clist->columns; i++)
+    {
+      clist->columns[i].description = NULL;
+      clist->columns[i].header = NULL;
+    }
+  /*
+   * Set up signal handlers for select-row and unselect-row
+   */
+  g_signal_connect (gtk_clist,
+                    "select-row",
+                    G_CALLBACK (gail_clist_select_row_gtk),
+                    obj);
+  g_signal_connect (gtk_clist,
+                    "unselect-row",
+                    G_CALLBACK (gail_clist_unselect_row_gtk),
+                    obj);
+  /*
+   * Adjustment callbacks
+   */
+  if (gtk_clist->hadjustment)
+    {
+      g_signal_connect (gtk_clist->hadjustment,
+                        "value_changed",
+                        G_CALLBACK (gail_clist_adjustment_changed),
+                        gtk_clist);
+    }
+  if (gtk_clist->vadjustment)
+    {
+      g_signal_connect (gtk_clist->vadjustment,
+                        "value_changed",
+                        G_CALLBACK (gail_clist_adjustment_changed),
+                        gtk_clist);
+    }
+}
+
+static void
+gail_clist_finalize (GObject            *object)
+{
+  GailCList *clist = GAIL_CLIST (object);
+  gint i;
+  GArray *array;
+
+  if (clist->caption)
+    g_object_unref (clist->caption);
+  if (clist->summary)
+    g_object_unref (clist->summary);
+
+  for (i = 0; i < clist->n_cols; i++)
+    {
+      g_free (clist->columns[i].description);
+      if (clist->columns[i].header)
+        g_object_unref (clist->columns[i].header);
+    }
+  g_free (clist->columns);
+
+  array = clist->row_data;
+
+  if (clist->previous_selected_cell)
+    g_object_unref (clist->previous_selected_cell);
+
+  if (array)
+    {
+      for (i = 0; i < array->len; i++)
+        {
+          GailCListRow *row_data;
+
+          row_data = g_array_index (array, GailCListRow*, i);
+
+          if (row_data->header)
+            g_object_unref (row_data->header);
+          g_free (row_data->description);
+        }
+    }
+
+  if (clist->cell_data)
+    {
+      GList *temp_list;
+
+      for (temp_list = clist->cell_data; temp_list; temp_list = temp_list->next)
+        {
+          g_list_free (temp_list->data);
+        }
+      g_list_free (clist->cell_data);
+    }
+}
+
+static gint
+gail_clist_get_n_children (AtkObject *obj)
+{
+  GtkWidget *widget;
+  gint row, col;
+
+  g_return_val_if_fail (GAIL_IS_CLIST (obj), 0);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  row = gail_clist_get_n_rows (ATK_TABLE (obj));
+  col = gail_clist_get_n_actual_columns (GTK_CLIST (widget));
+  return (row * col);
+}
+
+static AtkObject*
+gail_clist_ref_child (AtkObject *obj,
+                      gint      i)
+{
+  GtkWidget *widget;
+  gint row, col;
+  gint n_columns;
+
+  g_return_val_if_fail (GAIL_IS_CLIST (obj), NULL);
+  g_return_val_if_fail (i >= 0, NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  n_columns = gail_clist_get_n_actual_columns (GTK_CLIST (widget));
+  if (!n_columns)
+    return NULL;
+
+  row = i / n_columns;
+  col = i % n_columns;
+  return gail_clist_ref_at_actual (ATK_TABLE (obj), row, col);
+}
+
+static AtkStateSet*
+gail_clist_ref_state_set (AtkObject *obj)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+
+  if (widget != NULL)
+    atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
+
+  return state_set;
+}
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  
+  iface->clear_selection = gail_clist_clear_selection;
+  iface->ref_selection = gail_clist_ref_selection;
+  iface->get_selection_count = gail_clist_get_selection_count;
+  iface->is_child_selected = gail_clist_is_child_selected;
+  iface->select_all_selection = gail_clist_select_all_selection;
+}
+
+static gboolean
+gail_clist_clear_selection (AtkSelection   *selection)
+{
+  GtkCList *clist;
+  GtkWidget *widget;
+  
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+  
+  clist = GTK_CLIST (widget);
+  gtk_clist_unselect_all(clist);
+  return TRUE;
+}
+
+static AtkObject*
+gail_clist_ref_selection (AtkSelection   *selection,
+                          gint           i)
+{
+  gint visible_columns;
+  gint selected_row;
+  gint selected_column;
+  gint *selected_rows;
+
+  if ( i < 0 && i >= gail_clist_get_selection_count (selection))
+    return NULL;
+
+  visible_columns = gail_clist_get_n_columns (ATK_TABLE (selection));
+  gail_clist_get_selected_rows (ATK_TABLE (selection), &selected_rows);
+  selected_row = selected_rows[i / visible_columns];
+  g_free (selected_rows);
+  selected_column = gail_clist_get_actual_column (ATK_TABLE (selection), 
+                                                  i % visible_columns);
+
+  return gail_clist_ref_at (ATK_TABLE (selection), selected_row, 
+                            selected_column);
+}
+
+static gint
+gail_clist_get_selection_count (AtkSelection   *selection)
+{
+  gint n_rows_selected;
+
+  n_rows_selected = gail_clist_get_selected_rows (ATK_TABLE (selection), NULL);
+
+  if (n_rows_selected > 0)
+    /*
+     * The number of cells selected is the number of columns
+     * times the number of selected rows
+     */
+    return gail_clist_get_n_columns (ATK_TABLE (selection)) * n_rows_selected;
+  return 0;
+}
+
+static gboolean
+gail_clist_is_child_selected (AtkSelection   *selection,
+                              gint           i)
+{
+  gint row;
+
+  row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
+
+  if (row == 0 && i >= gail_clist_get_n_columns (ATK_TABLE (selection)))
+    return FALSE;
+  return gail_clist_is_row_selected (ATK_TABLE (selection), row);
+}
+
+static gboolean
+gail_clist_select_all_selection (AtkSelection   *selection)
+{
+  GtkCList *clist;
+  GtkWidget *widget;
+  /* GtkArg arg; */
+  
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  clist = GTK_CLIST (widget);
+  gtk_clist_select_all(clist);
+
+  return TRUE;
+}
+
+static void
+atk_table_interface_init (AtkTableIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->ref_at = gail_clist_ref_at;
+  iface->get_index_at = gail_clist_get_index_at;
+  iface->get_column_at_index = gail_clist_get_column_at_index;
+  iface->get_row_at_index = gail_clist_get_row_at_index;
+  iface->get_caption = gail_clist_get_caption;
+  iface->get_n_columns = gail_clist_get_n_columns;
+  iface->get_column_description = gail_clist_get_column_description;
+  iface->get_column_header = gail_clist_get_column_header;
+  iface->get_n_rows = gail_clist_get_n_rows;
+  iface->get_row_description = gail_clist_get_row_description;
+  iface->get_row_header = gail_clist_get_row_header;
+  iface->get_summary = gail_clist_get_summary;
+  iface->add_row_selection = gail_clist_add_row_selection;
+  iface->remove_row_selection = gail_clist_remove_row_selection;
+  iface->get_selected_rows = gail_clist_get_selected_rows;
+  iface->is_row_selected = gail_clist_is_row_selected;
+  iface->is_selected = gail_clist_is_selected;
+  iface->set_caption = gail_clist_set_caption;
+  iface->set_column_description = gail_clist_set_column_description;
+  iface->set_column_header = gail_clist_set_column_header;
+  iface->set_row_description = gail_clist_set_row_description;
+  iface->set_row_header = gail_clist_set_row_header;
+  iface->set_summary = gail_clist_set_summary;
+}
+
+static AtkObject*
+gail_clist_ref_at (AtkTable *table,
+                   gint     row,
+                   gint     column)
+{
+  GtkWidget *widget;
+  gint actual_column;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  actual_column = gail_clist_get_actual_column (table, column);
+  return gail_clist_ref_at_actual (table, row, actual_column);
+}
+
+
+static AtkObject*
+gail_clist_ref_at_actual (AtkTable      *table,
+                          gint          row,
+                          gint          column)
+{
+  /*
+   * The column number pased to this function is the actual column number
+   * whereas the column number passed to gail_clist_ref_at is the
+   * visible column number
+   */
+  GtkCList *clist;
+  GtkWidget *widget;
+  GtkCellType cellType;
+  AtkObject *return_object;
+  gint n_rows, n_columns;
+  gint index;
+  GailCell *cell;
+
+  g_return_val_if_fail (GTK_IS_ACCESSIBLE (table), NULL);
+  
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  clist = GTK_CLIST (widget);
+  n_rows = gail_clist_get_n_rows (table); 
+  n_columns = gail_clist_get_n_actual_columns (clist); 
+
+  if (row < 0 || row >= n_rows)
+    return NULL;
+  if (column < 0 || column >= n_columns)
+    return NULL;
+
+  /*
+   * Check whether the child is cached
+   */
+  index =  column + row * n_columns;
+  cell = gail_clist_find_cell (GAIL_CLIST (table), index);
+  if (cell)
+    {
+      g_object_ref (cell);
+      return ATK_OBJECT (cell);
+    }
+  cellType = gtk_clist_get_cell_type(clist, row, column);
+  switch (cellType) 
+    {
+    case GTK_CELL_TEXT:
+    case GTK_CELL_PIXTEXT:
+      return_object = gail_clist_cell_new ();
+      break;
+    case GTK_CELL_PIXMAP:
+      return_object = NULL;
+      break;
+    default:
+      /* Don't handle GTK_CELL_EMPTY or GTK_CELL_WIDGET, return NULL */
+      return_object = NULL;
+      break;
+    }
+  if (return_object)
+    {
+      cell = GAIL_CELL (return_object);
+
+      g_return_val_if_fail (ATK_IS_OBJECT (table), NULL);
+
+      gail_cell_init (cell, widget, ATK_OBJECT (table),
+                      index);
+      /*
+       * Store the cell in a cache
+       */
+      gail_clist_cell_data_new (GAIL_CLIST (table), cell, column, row);
+      /*
+       * If the column is visible, sets the cell's state
+       */
+      if (clist->column[column].visible)
+        {
+          GdkRectangle cell_rect, visible_rect;
+  
+          gail_clist_get_cell_area (GAIL_CELL_PARENT (table), cell, &cell_rect);
+          gail_clist_get_visible_rect (clist, &visible_rect);
+          gail_cell_add_state (cell, ATK_STATE_VISIBLE, FALSE);
+          if (gail_clist_is_cell_visible (&cell_rect, &visible_rect))
+            gail_cell_add_state (cell, ATK_STATE_SHOWING, FALSE);
+        }
+      /*
+       * If a row is selected, all cells in the row are selected
+       */
+      if (gail_clist_is_row_selected (table, row))
+        {
+          gail_cell_add_state (cell, ATK_STATE_SELECTED, FALSE);
+          if (clist->columns == 1)
+            gail_cell_add_state (cell, ATK_STATE_FOCUSED, FALSE);
+        }
+    }
+
+  return return_object; 
+}
+
+static gint
+gail_clist_get_index_at (AtkTable *table,
+                         gint     row,
+                         gint     column)
+{
+  gint n_cols, n_rows;
+
+  n_cols = atk_table_get_n_columns (table);
+  n_rows = atk_table_get_n_rows (table);
+
+  g_return_val_if_fail (row < n_rows, 0);
+  g_return_val_if_fail (column < n_cols, 0);
+
+  return row * n_cols + column;
+}
+
+static gint
+gail_clist_get_column_at_index (AtkTable *table,
+                                gint     index)
+{
+  gint n_cols;
+
+  n_cols = atk_table_get_n_columns (table);
+
+  if (n_cols == 0)
+    return 0;
+  else
+    return (gint) (index % n_cols);
+}
+
+static gint
+gail_clist_get_row_at_index (AtkTable *table,
+                             gint     index)
+{
+  gint n_cols;
+
+  n_cols = atk_table_get_n_columns (table);
+
+  if (n_cols == 0)
+    return 0;
+  else
+    return (gint) (index / n_cols);
+}
+
+static AtkObject*
+gail_clist_get_caption (AtkTable      *table)
+{
+  GailCList* obj = GAIL_CLIST (table);
+
+  return obj->caption;
+}
+
+static gint
+gail_clist_get_n_columns (AtkTable      *table)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  clist = GTK_CLIST (widget);
+
+  return gail_clist_get_visible_column (table, 
+                                  gail_clist_get_n_actual_columns (clist)); 
+}
+
+static gint
+gail_clist_get_n_actual_columns (GtkCList *clist)
+{
+  return clist->columns;
+}
+
+static G_CONST_RETURN gchar*
+gail_clist_get_column_description (AtkTable      *table,
+                                   gint          column)
+{
+  GailCList *clist = GAIL_CLIST (table);
+  GtkWidget *widget;
+  gint actual_column;
+
+  if (column < 0 || column >= gail_clist_get_n_columns (table))
+    return NULL;
+
+  actual_column = gail_clist_get_actual_column (table, column);
+  if (clist->columns[actual_column].description)
+    return (clist->columns[actual_column].description);
+
+  widget = GTK_ACCESSIBLE (clist)->widget;
+  if (widget == NULL)
+    return NULL;
+
+  return gtk_clist_get_column_title (GTK_CLIST (widget), actual_column);
+}
+
+static AtkObject*
+gail_clist_get_column_header (AtkTable      *table,
+                              gint          column)
+{
+  GailCList *clist = GAIL_CLIST (table);
+  GtkWidget *widget;
+  GtkWidget *return_widget;
+  gint actual_column;
+
+  if (column < 0 || column >= gail_clist_get_n_columns (table))
+    return NULL;
+
+  actual_column = gail_clist_get_actual_column (table, column);
+
+  if (clist->columns[actual_column].header)
+    return (clist->columns[actual_column].header);
+
+  widget = GTK_ACCESSIBLE (clist)->widget;
+  if (widget == NULL)
+    return NULL;
+
+  return_widget = gtk_clist_get_column_widget (GTK_CLIST (widget), 
+                                               actual_column);
+  if (return_widget == NULL)
+    return NULL;
+
+  g_return_val_if_fail (GTK_IS_BIN (return_widget), NULL);
+  return_widget = gtk_bin_get_child (GTK_BIN(return_widget));
+
+  return gtk_widget_get_accessible (return_widget);
+}
+
+static gint
+gail_clist_get_n_rows (AtkTable      *table)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  clist = GTK_CLIST (widget);
+  return clist->rows;
+}
+
+static G_CONST_RETURN gchar*
+gail_clist_get_row_description (AtkTable      *table,
+                                gint          row)
+{
+  GailCListRow* row_data;
+
+  row_data = gail_clist_get_row_data (table, row);
+  if (row_data == NULL)
+    return NULL;
+  return row_data->description;
+}
+
+static AtkObject*
+gail_clist_get_row_header (AtkTable      *table,
+                           gint          row)
+{
+  GailCListRow* row_data;
+
+  row_data = gail_clist_get_row_data (table, row);
+  if (row_data == NULL)
+    return NULL;
+  return row_data->header;
+}
+
+static AtkObject*
+gail_clist_get_summary (AtkTable      *table)
+{
+  GailCList* obj = GAIL_CLIST (table);
+
+  return obj->summary;
+}
+
+static gboolean
+gail_clist_add_row_selection (AtkTable      *table,
+                              gint          row)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  clist = GTK_CLIST (widget);
+  gtk_clist_select_row (clist, row, -1);
+  if (gail_clist_is_row_selected (table, row))
+    return TRUE;
+  
+  return FALSE;
+}
+
+static gboolean
+gail_clist_remove_row_selection (AtkTable      *table,
+                                 gint          row)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  clist = GTK_CLIST (widget);
+  if (gail_clist_is_row_selected (table, row))
+  {
+    gtk_clist_select_row (clist, row, -1);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gint
+gail_clist_get_selected_rows (AtkTable *table,
+                              gint     **rows_selected)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+  GList *list;
+  gint n_selected;
+  gint i;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  clist = GTK_CLIST (widget);
+  n_selected = g_list_length (clist->selection);
+
+  if (n_selected == 0) 
+    return 0;
+
+  if (rows_selected)
+    {
+      gint *selected_rows;
+
+      selected_rows = (gint*) g_malloc (sizeof (gint) * n_selected);
+      list = clist->selection;
+
+      i = 0;
+      while (list)
+        {
+          selected_rows[i++] = GPOINTER_TO_INT (list->data);
+          list = list->next;
+        }
+      *rows_selected = selected_rows;
+    }
+  return n_selected;
+}
+
+static gboolean
+gail_clist_is_row_selected (AtkTable      *table,
+                            gint          row)
+{
+  GList *elem;
+  GtkWidget *widget;
+  GtkCList *clist;
+  GtkCListRow *clist_row;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+       return FALSE;
+
+  clist = GTK_CLIST (widget);
+      
+  if (row < 0 || row >= clist->rows)
+    return FALSE;
+
+  elem = ROW_ELEMENT (clist, row);
+  if (!elem)
+    return FALSE;
+  clist_row = elem->data;
+
+  return (clist_row->state == GTK_STATE_SELECTED);
+}
+
+static gboolean
+gail_clist_is_selected (AtkTable      *table,
+                        gint          row,
+                        gint          column)
+{
+  return gail_clist_is_row_selected (table, row);
+}
+
+static void
+gail_clist_set_caption (AtkTable      *table,
+                        AtkObject     *caption)
+{
+  GailCList* obj = GAIL_CLIST (table);
+  AtkPropertyValues values = { NULL };
+  AtkObject *old_caption;
+
+  old_caption = obj->caption;
+  obj->caption = caption;
+  if (obj->caption)
+    g_object_ref (obj->caption);
+
+  g_value_init (&values.old_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.old_value, old_caption);
+  g_value_init (&values.new_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.new_value, obj->caption);
+
+  values.property_name = "accessible-table-caption";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-caption", 
+                         &values, NULL);
+  if (old_caption)
+    g_object_unref (old_caption);
+}
+
+static void
+gail_clist_set_column_description (AtkTable      *table,
+                                   gint          column,
+                                   const gchar   *description)
+{
+  GailCList *clist = GAIL_CLIST (table);
+  AtkPropertyValues values = { NULL };
+  gint actual_column;
+
+  if (column < 0 || column >= gail_clist_get_n_columns (table))
+    return;
+
+  if (description == NULL)
+    return;
+
+  actual_column = gail_clist_get_actual_column (table, column);
+  g_free (clist->columns[actual_column].description);
+  clist->columns[actual_column].description = g_strdup (description);
+
+  g_value_init (&values.new_value, G_TYPE_INT);
+  g_value_set_int (&values.new_value, column);
+
+  values.property_name = "accessible-table-column-description";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-column-description",
+                          &values, NULL);
+
+}
+
+static void
+gail_clist_set_column_header (AtkTable      *table,
+                              gint          column,
+                              AtkObject     *header)
+{
+  GailCList *clist = GAIL_CLIST (table);
+  AtkPropertyValues values = { NULL };
+  gint actual_column;
+
+  if (column < 0 || column >= gail_clist_get_n_columns (table))
+    return;
+
+  actual_column = gail_clist_get_actual_column (table, column);
+  if (clist->columns[actual_column].header)
+    g_object_unref (clist->columns[actual_column].header);
+  if (header)
+    g_object_ref (header);
+  clist->columns[actual_column].header = header;
+
+  g_value_init (&values.new_value, G_TYPE_INT);
+  g_value_set_int (&values.new_value, column);
+
+  values.property_name = "accessible-table-column-header";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-column-header",
+                         &values, NULL);
+}
+
+static void
+gail_clist_set_row_description (AtkTable      *table,
+                                gint          row,
+                                const gchar   *description)
+{
+  gail_clist_set_row_data (table, row, description, NULL, FALSE);
+}
+
+static void
+gail_clist_set_row_header (AtkTable      *table,
+                           gint          row,
+                           AtkObject     *header)
+{
+  gail_clist_set_row_data (table, row, NULL, header, TRUE);
+}
+
+static void
+gail_clist_set_summary (AtkTable      *table,
+                        AtkObject     *accessible)
+{
+  GailCList* obj = GAIL_CLIST (table);
+  AtkPropertyValues values = { 0, };
+  AtkObject *old_summary;
+
+  old_summary = obj->summary;
+  obj->summary = accessible;
+  if (obj->summary)
+    g_object_ref (obj->summary);
+
+  g_value_init (&values.old_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.old_value, old_summary);
+  g_value_init (&values.new_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.new_value, obj->summary);
+
+  values.property_name = "accessible-table-summary";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-summary", 
+                         &values, NULL);
+  if (old_summary)
+    g_object_unref (old_summary);
+}
+
+
+static void gail_cell_parent_interface_init (GailCellParentIface *iface)
+{
+  g_return_if_fail (iface);
+
+  iface->get_cell_extents = gail_clist_get_cell_extents;
+  iface->get_cell_area = gail_clist_get_cell_area;
+}
+
+static void
+gail_clist_get_cell_extents (GailCellParent *parent,
+                             GailCell       *cell,
+                             gint           *x,
+                             gint           *y,
+                             gint           *width,
+                             gint           *height,
+                             AtkCoordType   coord_type)
+{
+  GtkWidget* widget;
+  GtkCList *clist;
+  gint widget_x, widget_y, widget_width, widget_height;
+  GdkRectangle cell_rect;
+  GdkRectangle visible_rect;
+
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  if (widget == NULL)
+    return;
+  clist = GTK_CLIST (widget);
+
+  atk_component_get_extents (ATK_COMPONENT (parent), &widget_x, &widget_y,
+                             &widget_width, &widget_height,
+                             coord_type);
+
+  gail_clist_get_cell_area (parent, cell, &cell_rect);
+  *width = cell_rect.width;
+  *height = cell_rect.height;
+  gail_clist_get_visible_rect (clist, &visible_rect);
+  if (gail_clist_is_cell_visible (&cell_rect, &visible_rect))
+    {
+      *x = cell_rect.x + widget_x;
+      *y = cell_rect.y + widget_y;
+    }
+  else
+    {
+      *x = G_MININT;
+      *y = G_MININT;
+    }
+}
+
+static void
+gail_clist_get_cell_area (GailCellParent *parent,
+                          GailCell       *cell,
+                          GdkRectangle   *cell_rect)
+{
+  GtkWidget* widget;
+  GtkCList *clist;
+  gint column, row, n_columns;
+
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  if (widget == NULL)
+    return;
+  clist = GTK_CLIST (widget);
+
+  n_columns = gail_clist_get_n_actual_columns (clist);
+  g_return_if_fail (n_columns > 0);
+  column = cell->index % n_columns;
+  row = cell->index / n_columns; 
+  cell_rect->x = COLUMN_LEFT (clist, column);
+  cell_rect->y = ROW_TOP (clist, row);
+  cell_rect->width = clist->column[column].area.width;
+  cell_rect->height = clist->row_height;
+}
+
+static void
+gail_clist_select_row_gtk (GtkCList *clist,
+                           gint      row,
+                           gint      column,
+                           GdkEvent *event,
+                           gpointer data)
+{
+  GailCList *gail_clist;
+  GList *temp_list;
+  AtkObject *selected_cell;
+
+  gail_clist = GAIL_CLIST (data);
+
+  for (temp_list = gail_clist->cell_data; temp_list; temp_list = temp_list->next)
+    {
+      GailCListCellData *cell_data;
+
+      cell_data = (GailCListCellData *) (temp_list->data);
+
+      if (row == cell_data->row_number)
+        {
+          /*
+           * Row is selected
+           */
+          gail_cell_add_state (cell_data->gail_cell, ATK_STATE_SELECTED, TRUE);
+        }
+    }
+  if (clist->columns == 1)
+    {
+      selected_cell = gail_clist_ref_at (ATK_TABLE (data), row, 1);
+      if (selected_cell)
+        {
+          if (gail_clist->previous_selected_cell)
+            g_object_unref (gail_clist->previous_selected_cell);
+          gail_clist->previous_selected_cell = selected_cell;
+          gail_cell_add_state (GAIL_CELL (selected_cell), ATK_STATE_FOCUSED, FALSE);
+          g_signal_emit_by_name (gail_clist,
+                                 "active-descendant-changed",
+                                  selected_cell);
+       }
+    }
+
+  g_signal_emit_by_name (gail_clist, "selection_changed");
+}
+
+static void
+gail_clist_unselect_row_gtk (GtkCList *clist,
+                             gint      row,
+                             gint      column,
+                             GdkEvent *event,
+                             gpointer data)
+{
+  GailCList *gail_clist;
+  GList *temp_list;
+
+  gail_clist = GAIL_CLIST (data);
+
+  for (temp_list = gail_clist->cell_data; temp_list; temp_list = temp_list->next)
+    {
+      GailCListCellData *cell_data;
+
+      cell_data = (GailCListCellData *) (temp_list->data);
+
+      if (row == cell_data->row_number)
+        {
+          /*
+           * Row is unselected
+           */
+          gail_cell_add_state (cell_data->gail_cell, ATK_STATE_FOCUSED, FALSE);
+          gail_cell_remove_state (cell_data->gail_cell, ATK_STATE_SELECTED, TRUE);
+       }
+    }
+
+  g_signal_emit_by_name (gail_clist, "selection_changed");
+}
+
+/*
+ * This function determines the number of visible columns
+ * up to and including the specified column
+ */
+static gint
+gail_clist_get_visible_column (AtkTable *table,
+                               int      column)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+  gint i;
+  gint vis_columns;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  clist = GTK_CLIST (widget);
+  for (i = 0, vis_columns = 0; i < column; i++)
+    if (clist->column[i].visible)
+      vis_columns++;
+
+  return vis_columns;  
+}
+
+static gint
+gail_clist_get_actual_column (AtkTable *table,
+                              int      visible_column)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+  gint i;
+  gint vis_columns;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  clist = GTK_CLIST (widget);
+  for (i = 0, vis_columns = 0; i < clist->columns; i++)
+    {
+      if (clist->column[i].visible)
+        {
+          if (visible_column == vis_columns)
+            return i;
+          vis_columns++;
+        }
+    }
+  return 0;  
+}
+
+static void
+gail_clist_set_row_data (AtkTable      *table,
+                         gint          row,
+                         const gchar   *description,
+                         AtkObject     *header,
+                         gboolean      is_header)
+{
+  GtkWidget *widget;
+  GtkCList *gtk_clist;
+  GailCList *gail_clist;
+  GArray *array;
+  GailCListRow* row_data;
+  gint i;
+  gboolean found = FALSE;
+  AtkPropertyValues values = { NULL };
+  gchar *signal_name;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  gtk_clist = GTK_CLIST (widget);
+  if (row < 0 || row >= gtk_clist->rows)
+    return;
+
+  gail_clist = GAIL_CLIST (table);
+
+  if (gail_clist->row_data == NULL)
+    gail_clist->row_data = g_array_sized_new (FALSE, TRUE, 
+                                              sizeof (GailCListRow *), 0);
+
+  array = gail_clist->row_data;
+
+  for (i = 0; i < array->len; i++)
+    {
+      row_data = g_array_index (array, GailCListRow*, i);
+
+      if (row == row_data->row_number)
+        {
+          found = TRUE;
+          if (is_header)
+            {
+              if (row_data->header)
+                g_object_unref (row_data->header);
+              row_data->header = header;
+              if (row_data->header)
+                g_object_ref (row_data->header);
+            }
+          else
+            {
+              g_free (row_data->description);
+              row_data->description = g_strdup (row_data->description);
+            }
+          break;
+        }
+    } 
+  if (!found)
+    {
+      GList *elem;
+
+      elem = ROW_ELEMENT (gtk_clist, row);
+      g_return_if_fail (elem != NULL);
+
+      row_data = g_new (GailCListRow, 1);
+      row_data->row_number = row;
+      row_data->row_data = elem->data;
+      if (is_header)
+        {
+          row_data->header = header;
+          if (row_data->header)
+            g_object_ref (row_data->header);
+          row_data->description = NULL;
+        }
+      else
+        {
+          row_data->description = g_strdup (row_data->description);
+          row_data->header = NULL;
+        }
+      g_array_append_val (array, row_data);
+    }
+
+  g_value_init (&values.new_value, G_TYPE_INT);
+  g_value_set_int (&values.new_value, row);
+
+  if (is_header)
+    {
+      values.property_name = "accessible-table-row-header";
+      signal_name = "property_change::accessible-table-row-header";
+    }
+  else
+    {
+      values.property_name = "accessible-table-row-description";
+      signal_name = "property_change::accessible-table-row-description";
+    }
+  g_signal_emit_by_name (table, 
+                         signal_name,
+                         &values, NULL);
+
+}
+
+static GailCListRow*
+gail_clist_get_row_data (AtkTable      *table,
+                         gint          row)
+{
+  GtkWidget *widget;
+  GtkCList *clist;
+  GailCList *obj;
+  GArray *array;
+  GailCListRow* row_data;
+  gint i;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  clist = GTK_CLIST (widget);
+  if (row < 0 || row >= clist->rows)
+    return NULL;
+
+  obj = GAIL_CLIST (table);
+
+  if (obj->row_data == NULL)
+    return NULL;
+
+  array = obj->row_data;
+
+  for (i = 0; i < array->len; i++)
+    {
+      row_data = g_array_index (array, GailCListRow*, i);
+
+      if (row == row_data->row_number)
+        return row_data;
+    }
+  return NULL;
+}
+
+static void
+gail_clist_get_visible_rect (GtkCList      *clist,
+                             GdkRectangle  *clist_rect)
+{
+  clist_rect->x = - clist->hoffset;
+  clist_rect->y = - clist->voffset;
+  clist_rect->width = clist->clist_window_width;
+  clist_rect->height = clist->clist_window_height;
+}
+
+static gboolean
+gail_clist_is_cell_visible (GdkRectangle  *cell_rect,
+                            GdkRectangle  *visible_rect)
+{
+  /*
+   * A cell is reported as visible if any part of the cell is visible
+   */
+  if (((cell_rect->x + cell_rect->width) < visible_rect->x) ||
+     ((cell_rect->y + cell_rect->height) < visible_rect->y) ||
+     (cell_rect->x > (visible_rect->x + visible_rect->width)) ||
+     (cell_rect->y > (visible_rect->y + visible_rect->height)))
+    return FALSE;
+  else
+    return TRUE;
+}
+
+static void
+gail_clist_cell_data_new (GailCList     *clist,
+                          GailCell      *cell,
+                          gint          column,
+                          gint          row)
+{
+  GList *elem;
+  GailCListCellData *cell_data;
+  GtkCList *gtk_clist;
+  GtkCListRow *clist_row;
+
+  gtk_clist = GTK_CLIST (GTK_ACCESSIBLE (clist)->widget);
+  elem = g_list_nth (gtk_clist->row_list, row);
+  g_return_if_fail (elem != NULL);
+  clist_row = (GtkCListRow *) elem->data;
+  cell_data = g_new (GailCListCellData, 1);
+  cell_data->gail_cell = cell;
+  cell_data->gtk_cell = &(clist_row->cell[column]);
+  cell_data->column_number = column;
+  cell_data->row_number = row;
+  clist->cell_data = g_list_append (clist->cell_data, cell_data);
+
+  g_object_weak_ref (G_OBJECT (cell),
+                     (GWeakNotify) gail_clist_cell_destroyed,
+                     cell);
+}
+
+static void
+gail_clist_cell_destroyed (gpointer      data)
+{
+  GailCell *cell = GAIL_CELL (data);
+  AtkObject* parent;
+
+  parent = atk_object_get_parent (ATK_OBJECT (cell));
+
+  gail_clist_cell_data_remove (GAIL_CLIST (parent), cell);
+}
+
+static void
+gail_clist_cell_data_remove (GailCList *clist,
+                             GailCell  *cell)
+{
+  GList *temp_list;
+
+  for (temp_list = clist->cell_data; temp_list; temp_list = temp_list->next)
+    {
+      GailCListCellData *cell_data;
+
+      cell_data = (GailCListCellData *) temp_list->data;
+      if (cell_data->gail_cell == cell)
+        {
+          clist->cell_data = g_list_remove_link (clist->cell_data, temp_list);
+          g_free (cell_data);
+          return;
+        }
+    }
+  g_warning ("No cell removed in gail_clist_cell_data_remove\n");
+}
+
+static GailCell*
+gail_clist_find_cell (GailCList     *clist,
+                      gint          index)
+{
+  GList *temp_list;
+  gint n_cols;
+
+  n_cols = clist->n_cols;
+
+  for (temp_list = clist->cell_data; temp_list; temp_list = temp_list->next)
+    {
+      GailCListCellData *cell_data;
+      gint real_index;
+
+      cell_data = (GailCListCellData *) (temp_list->data);
+
+      real_index = cell_data->column_number + n_cols * cell_data->row_number;
+      if (real_index == index)
+        return cell_data->gail_cell;
+    }
+  return NULL;
+}
+
+static void
+gail_clist_adjustment_changed (GtkAdjustment *adjustment,
+                               GtkCList      *clist)
+{
+  AtkObject *atk_obj;
+  GdkRectangle visible_rect;
+  GdkRectangle cell_rect;
+  GailCList* obj;
+  GList *temp_list;
+
+  /*
+   * The scrollbars have changed
+   */
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (clist));
+  obj = GAIL_CLIST (atk_obj);
+
+  /* Get the currently visible area */
+  gail_clist_get_visible_rect (clist, &visible_rect);
+
+  /* loop over the cells and report if they are visible or not. */
+  /* Must loop through them all */
+  for (temp_list = obj->cell_data; temp_list; temp_list = temp_list->next)
+    {
+      GailCell *cell;
+      GailCListCellData *cell_data;
+
+      cell_data = (GailCListCellData *) (temp_list->data);
+      cell = cell_data->gail_cell;
+
+      gail_clist_get_cell_area (GAIL_CELL_PARENT (atk_obj), 
+                                cell, &cell_rect);
+      if (gail_clist_is_cell_visible (&cell_rect, &visible_rect))
+        gail_cell_add_state (cell, ATK_STATE_SHOWING, TRUE);
+      else
+        gail_cell_remove_state (cell, ATK_STATE_SHOWING, TRUE);
+    }
+  g_signal_emit_by_name (atk_obj, "visible_data_changed");
+}
+
diff --git a/modules/other/gail/gailclist.h b/modules/other/gail/gailclist.h
new file mode 100644 (file)
index 0000000..92d1df6
--- /dev/null
@@ -0,0 +1,72 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_CLIST_H__
+#define __GAIL_CLIST_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CLIST                      (gail_clist_get_type ())
+#define GAIL_CLIST(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CLIST, GailCList))
+#define GAIL_CLIST_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CLIST, GailCListClass))
+#define GAIL_IS_CLIST(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CLIST))
+#define GAIL_IS_CLIST_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CLIST))
+#define GAIL_CLIST_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CLIST, GailCListClass))
+
+typedef struct _GailCList              GailCList;
+typedef struct _GailCListClass         GailCListClass;
+
+typedef struct _GailCListColumn        GailCListColumn;
+
+struct _GailCList
+{
+  GailContainer parent;
+
+  AtkObject*    caption;
+  AtkObject*    summary;
+
+  /* dynamically allocated array of column structures */
+  GailCListColumn *columns;
+  /* private */
+  gint n_cols;
+  GArray *row_data;
+  GList *cell_data;
+  AtkObject *previous_selected_cell;
+};
+
+GType gail_clist_get_type (void);
+
+struct _GailCListClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_clist_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_CLIST_H__ */
diff --git a/modules/other/gail/gailclistcell.c b/modules/other/gail/gailclistcell.c
new file mode 100644 (file)
index 0000000..09a6b4a
--- /dev/null
@@ -0,0 +1,121 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailclistcell.h"
+
+static void     gail_clist_cell_class_init        (GailCListCellClass *klass);
+
+static G_CONST_RETURN gchar* gail_clist_cell_get_name (AtkObject *accessible);
+
+GType
+gail_clist_cell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailCListCellClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_clist_cell_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailCListCell), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CELL,
+                                     "GailCListCell", &tinfo, 0);
+    }
+  return type;
+}
+
+static void     
+gail_clist_cell_class_init (GailCListCellClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  class->get_name = gail_clist_cell_get_name;
+}
+
+AtkObject* 
+gail_clist_cell_new (void)
+{
+  GObject *object;
+  AtkObject *atk_object;
+
+  object = g_object_new (GAIL_TYPE_CLIST_CELL, NULL);
+
+  g_return_val_if_fail (object != NULL, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object->role = ATK_ROLE_TABLE_CELL;
+
+  g_return_val_if_fail (!ATK_IS_TEXT (atk_object), NULL);
+  
+  return atk_object;
+}
+
+static G_CONST_RETURN gchar*
+gail_clist_cell_get_name (AtkObject *accessible)
+{
+  if (accessible->name)
+    return accessible->name;
+  else
+    {
+      /*
+       * Get the cell's text if it exists
+       */
+      GailCell *cell = GAIL_CELL (accessible);
+      GtkWidget* widget = cell->widget;
+      GtkCellType cell_type;
+      GtkCList *clist;
+      gchar *text = NULL;
+      gint row, column;
+
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+      clist = GTK_CLIST (widget);
+      g_return_val_if_fail (clist->columns, NULL);
+      row = cell->index / clist->columns;
+      column = cell->index % clist->columns;
+      cell_type = gtk_clist_get_cell_type (clist, row, column);
+      switch (cell_type)
+        {
+        case GTK_CELL_TEXT:
+          gtk_clist_get_text (clist, row, column, &text);
+          break;
+        case GTK_CELL_PIXTEXT:
+          gtk_clist_get_pixtext (clist, row, column, &text, NULL, NULL, NULL);
+          break;
+        default:
+          break;
+        }
+      return text;
+    }
+}
diff --git a/modules/other/gail/gailclistcell.h b/modules/other/gail/gailclistcell.h
new file mode 100644 (file)
index 0000000..0cd208c
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_CLIST_CELL_H__
+#define __GAIL_CLIST_CELL_H__
+
+#include <atk/atk.h>
+#include <gail/gailcell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CLIST_CELL                     (gail_clist_cell_get_type ())
+#define GAIL_CLIST_CELL(obj)                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CLIST_CELL, GailCListCell))
+#define GAIL_CLIST_CELL_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CLIST_CELL, GailCListCellClass))
+#define GAIL_IS_CLIST_CELL(obj)                  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CLIST_CELL))
+#define GAIL_IS_CLIST_CELL_CLASS(klass)          (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CLIST_CELL))
+#define GAIL_CLIST_CELL_GET_CLASS(obj)           (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CLIST_CELL, GailCListCellClass))
+
+typedef struct _GailCListCell                  GailCListCell;
+typedef struct _GailCListCellClass             GailCListCellClass;
+
+struct _GailCListCell
+{
+  GailCell parent;
+};
+
+GType gail_clist_cell_get_type (void);
+
+struct _GailCListCellClass
+{
+  GailCellClass parent_class;
+};
+
+AtkObject *gail_clist_cell_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_CLIST_CELL_H__ */
diff --git a/modules/other/gail/gailcombo.c b/modules/other/gail/gailcombo.c
new file mode 100644 (file)
index 0000000..45d6ade
--- /dev/null
@@ -0,0 +1,714 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gtk/gtk.h>
+#include "gailcombo.h"
+
+static void         gail_combo_class_init              (GailComboClass *klass);
+static void         gail_combo_object_init             (GailCombo      *combo);
+static void         gail_combo_real_initialize         (AtkObject      *obj,
+                                                        gpointer       data);
+
+static void         gail_combo_selection_changed_gtk   (GtkWidget      *widget,
+                                                        gpointer       data);
+
+static gint         gail_combo_get_n_children          (AtkObject      *obj);
+static AtkObject*   gail_combo_ref_child               (AtkObject      *obj,
+                                                        gint           i);
+static void         gail_combo_finalize                (GObject        *object);
+static void         atk_action_interface_init          (AtkActionIface *iface);
+
+static gboolean     gail_combo_do_action               (AtkAction      *action,
+                                                        gint           i);
+static gboolean     idle_do_action                     (gpointer       data);
+static gint         gail_combo_get_n_actions           (AtkAction      *action)
+;
+static G_CONST_RETURN gchar* gail_combo_get_description(AtkAction      *action,
+                                                        gint           i);
+static G_CONST_RETURN gchar* gail_combo_get_name       (AtkAction      *action,
+                                                        gint           i);
+static gboolean              gail_combo_set_description(AtkAction      *action,
+                                                        gint           i,
+                                                        const gchar    *desc);
+
+static void         atk_selection_interface_init       (AtkSelectionIface *iface);
+static gboolean     gail_combo_add_selection           (AtkSelection   *selection,
+                                                        gint           i);
+static gboolean     gail_combo_clear_selection         (AtkSelection   *selection);
+static AtkObject*   gail_combo_ref_selection           (AtkSelection   *selection,
+                                                        gint           i);
+static gint         gail_combo_get_selection_count     (AtkSelection   *selection);
+static gboolean     gail_combo_is_child_selected       (AtkSelection   *selection,
+                                                        gint           i);
+static gboolean     gail_combo_remove_selection        (AtkSelection   *selection,
+                                                        gint           i);
+
+static gint         _gail_combo_button_release         (gpointer       data);
+static gint         _gail_combo_popup_release          (gpointer       data);
+
+
+static gpointer parent_class = NULL;
+
+GType
+gail_combo_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailComboClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_combo_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailCombo), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_combo_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_action_info =
+      {
+        (GInterfaceInitFunc) atk_action_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+      static const GInterfaceInfo atk_selection_info =
+      {
+        (GInterfaceInitFunc) atk_selection_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailCombo", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                   &atk_action_info);
+      g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                   &atk_selection_info);
+    }
+
+  return type;
+}
+
+static void
+gail_combo_class_init (GailComboClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gail_combo_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_n_children = gail_combo_get_n_children;
+  class->ref_child = gail_combo_ref_child;
+  class->initialize = gail_combo_real_initialize;
+}
+
+static void
+gail_combo_object_init (GailCombo      *combo)
+{
+  combo->press_description = NULL;
+  combo->old_selection = NULL;
+  combo->deselect_idle_handler = 0;
+  combo->select_idle_handler = 0;
+}
+
+AtkObject* 
+gail_combo_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_COMBO (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_COMBO, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_combo_real_initialize (AtkObject *obj,
+                            gpointer  data)
+{
+  GtkCombo *combo;
+  GtkList *list;
+  GList *slist; 
+  GailCombo *gail_combo;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  combo = GTK_COMBO (data);
+
+  list = GTK_LIST (combo->list);
+  slist = list->selection;
+
+  gail_combo = GAIL_COMBO (obj);
+  if (slist && slist->data)
+    {
+      gail_combo->old_selection = slist->data;
+    }
+  g_signal_connect (combo->list,
+                    "selection_changed",
+                    G_CALLBACK (gail_combo_selection_changed_gtk),
+                    data);
+  atk_object_set_parent (gtk_widget_get_accessible (combo->entry), obj);
+  atk_object_set_parent (gtk_widget_get_accessible (combo->popup), obj);
+
+  obj->role = ATK_ROLE_COMBO_BOX;
+}
+
+static gboolean
+notify_deselect (gpointer data)
+{
+  GailCombo *combo;
+
+  GDK_THREADS_ENTER ();
+
+  combo = GAIL_COMBO (data);
+
+  combo->old_selection = NULL;
+  combo->deselect_idle_handler = 0;
+  g_signal_emit_by_name (data, "selection_changed");
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gboolean
+notify_select (gpointer data)
+{
+  GailCombo *combo;
+
+  GDK_THREADS_ENTER ();
+
+  combo = GAIL_COMBO (data);
+
+  combo->select_idle_handler = 0;
+  g_signal_emit_by_name (data, "selection_changed");
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+gail_combo_selection_changed_gtk (GtkWidget      *widget,
+                                  gpointer       data)
+{
+  GtkCombo *combo;
+  GtkList *list;
+  GList *slist; 
+  AtkObject *obj;
+  GailCombo *gail_combo;
+
+  combo = GTK_COMBO (data);
+  list = GTK_LIST (combo->list);
+  
+  slist = list->selection;
+
+  obj = gtk_widget_get_accessible (GTK_WIDGET (data));
+  gail_combo = GAIL_COMBO (obj);
+  if (slist && slist->data)
+    {
+      if (slist->data != gail_combo->old_selection)
+        {
+          gail_combo->old_selection = slist->data;
+          if (gail_combo->select_idle_handler == 0)
+            gail_combo->select_idle_handler =  g_idle_add (notify_select, gail_combo);
+        }
+      if (gail_combo->deselect_idle_handler)
+        {
+          g_source_remove (gail_combo->deselect_idle_handler);
+          gail_combo->deselect_idle_handler = 0;       
+        }
+    }
+  else
+    {
+      if (gail_combo->deselect_idle_handler == 0)
+        gail_combo->deselect_idle_handler =  g_idle_add (notify_deselect, gail_combo);
+      if (gail_combo->select_idle_handler)
+        {
+          g_source_remove (gail_combo->select_idle_handler);
+          gail_combo->select_idle_handler = 0;       
+        }
+    }
+}
+
+/*
+ * The children of a GailCombo are the list of items and the entry field
+ */
+static gint
+gail_combo_get_n_children (AtkObject* obj)
+{
+  gint n_children = 2;
+  GtkWidget *widget;
+
+  g_return_val_if_fail (GAIL_IS_COMBO (obj), 0);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  return n_children;
+}
+
+static AtkObject*
+gail_combo_ref_child (AtkObject *obj,
+                      gint      i)
+{
+  AtkObject *accessible;
+  GtkWidget *widget;
+
+  g_return_val_if_fail (GAIL_IS_COMBO (obj), NULL);
+
+  if (i < 0 || i > 1)
+    return NULL;
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  if (i == 0)
+    accessible = gtk_widget_get_accessible (GTK_COMBO (widget)->popup);
+  else 
+    accessible = gtk_widget_get_accessible (GTK_COMBO (widget)->entry);
+
+  g_object_ref (accessible);
+  return accessible;
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action = gail_combo_do_action;
+  iface->get_n_actions = gail_combo_get_n_actions;
+  iface->get_description = gail_combo_get_description;
+  iface->get_name = gail_combo_get_name;
+  iface->set_description = gail_combo_set_description;
+}
+
+static gboolean
+gail_combo_do_action (AtkAction *action,
+                       gint      i)
+{
+  GailCombo *combo;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (action)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    return FALSE;
+
+  combo = GAIL_COMBO (action);
+  if (i == 0)
+    {
+      if (combo->action_idle_handler)
+        return FALSE;
+
+      combo->action_idle_handler = g_idle_add (idle_do_action, combo);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+/*
+ * This action is the pressing of the button on the combo box.
+ * The behavior is different depending on whether the list is being
+ * displayed or removed.
+ *
+ * A button press event is simulated on the appropriate widget and 
+ * a button release event is simulated in an idle function.
+ */
+static gboolean
+idle_do_action (gpointer data)
+{
+  GtkCombo *combo;
+  GtkWidget *action_widget;
+  GtkWidget *widget;
+  GailCombo *gail_combo;
+  gboolean do_popup;
+  GdkEvent tmp_event;
+
+  GDK_THREADS_ENTER ();
+
+  gail_combo = GAIL_COMBO (data);
+  gail_combo->action_idle_handler = 0;
+  widget = GTK_ACCESSIBLE (gail_combo)->widget;
+  if (widget == NULL /* State is defunct */ ||
+      !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  combo = GTK_COMBO (widget);
+
+  do_popup = !GTK_WIDGET_MAPPED (combo->popwin);
+
+  tmp_event.button.type = GDK_BUTTON_PRESS; 
+  tmp_event.button.window = widget->window;
+  tmp_event.button.button = 1; 
+  tmp_event.button.send_event = TRUE;
+  tmp_event.button.time = GDK_CURRENT_TIME;
+  tmp_event.button.axes = NULL;
+
+  if (do_popup)
+    {
+      /* Pop up list */
+      action_widget = combo->button;
+
+      gtk_widget_event (action_widget, &tmp_event);
+
+      g_idle_add (_gail_combo_button_release, combo);
+    }
+    else
+    {
+      /* Pop down list */
+      tmp_event.button.window = combo->list->window;
+      gdk_window_set_user_data (combo->list->window, combo->button);
+      action_widget = combo->popwin;
+    
+      gtk_widget_event (action_widget, &tmp_event);
+      g_idle_add (_gail_combo_popup_release, combo);
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gint
+gail_combo_get_n_actions (AtkAction *action)
+{
+  /*
+   * The default behavior of a combo box is to have one action -
+   */
+  return 1;
+}
+
+static G_CONST_RETURN gchar*
+gail_combo_get_description (AtkAction *action,
+                           gint      i)
+{
+  if (i == 0)
+    {
+      GailCombo *combo;
+
+      combo = GAIL_COMBO (action);
+      return combo->press_description;
+    }
+  else
+    return NULL;
+}
+
+static G_CONST_RETURN gchar*
+gail_combo_get_name (AtkAction *action,
+                     gint      i)
+{
+  if (i == 0)
+    return "press";
+  else
+    return NULL;
+}
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->add_selection = gail_combo_add_selection;
+  iface->clear_selection = gail_combo_clear_selection;
+  iface->ref_selection = gail_combo_ref_selection;
+  iface->get_selection_count = gail_combo_get_selection_count;
+  iface->is_child_selected = gail_combo_is_child_selected;
+  iface->remove_selection = gail_combo_remove_selection;
+  /*
+   * select_all_selection does not make sense for a combo box
+   * so no implementation is provided.
+   */
+}
+
+static gboolean
+gail_combo_add_selection (AtkSelection   *selection,
+                          gint           i)
+{
+  GtkCombo *combo;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  combo = GTK_COMBO (widget);
+
+  gtk_list_select_item (GTK_LIST (combo->list), i);
+  return TRUE;
+}
+
+static gboolean 
+gail_combo_clear_selection (AtkSelection   *selection)
+{
+  GtkCombo *combo;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  combo = GTK_COMBO (widget);
+
+  gtk_list_unselect_all (GTK_LIST (combo->list));
+  return TRUE;
+}
+
+static AtkObject*
+gail_combo_ref_selection (AtkSelection   *selection,
+                          gint           i)
+{
+  GtkCombo *combo;
+  GList * list;
+  GtkWidget *item;
+  AtkObject *obj;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  combo = GTK_COMBO (widget);
+
+  /*
+   * A combo box can have only one selection.
+   */
+  if (i != 0)
+    return NULL;
+
+  list = GTK_LIST (combo->list)->selection;
+
+  if (list == NULL)
+    return NULL;
+
+  item = GTK_WIDGET (list->data);
+
+  obj = gtk_widget_get_accessible (item);
+  g_object_ref (obj);
+  return obj;
+}
+
+static gint
+gail_combo_get_selection_count (AtkSelection   *selection)
+{
+  GtkCombo *combo;
+  GList * list;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  combo = GTK_COMBO (widget);
+
+  /*
+   * The number of children currently selected is either 1 or 0 so we
+   * do not bother to count the elements of the selected list.
+   */
+  list = GTK_LIST (combo->list)->selection;
+
+  if (list == NULL)
+    return 0;
+  else
+    return 1;
+}
+
+static gboolean
+gail_combo_is_child_selected (AtkSelection   *selection,
+                              gint           i)
+{
+  GtkCombo *combo;
+  GList * list;
+  GtkWidget *item;
+  gint j;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  combo = GTK_COMBO (widget);
+
+  list = GTK_LIST (combo->list)->selection;
+
+  if (list == NULL)
+    return FALSE;
+
+  item = GTK_WIDGET (list->data);
+
+  j = g_list_index (GTK_LIST (combo->list)->children, item);
+
+  return (j == i);
+}
+
+static gboolean
+gail_combo_remove_selection (AtkSelection   *selection,
+                             gint           i)
+{
+  if (atk_selection_is_child_selected (selection, i))
+    atk_selection_clear_selection (selection);
+
+  return TRUE;
+}
+
+static gint 
+_gail_combo_popup_release (gpointer data)
+{
+  GtkCombo *combo;
+  GtkWidget *action_widget;
+  GdkEvent tmp_event;
+
+  GDK_THREADS_ENTER ();
+
+  combo = GTK_COMBO (data);
+  if (combo->current_button == 0)
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  tmp_event.button.type = GDK_BUTTON_RELEASE; 
+  tmp_event.button.button = 1; 
+  tmp_event.button.time = GDK_CURRENT_TIME;
+  action_widget = combo->button;
+
+  gtk_widget_event (action_widget, &tmp_event);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gint 
+_gail_combo_button_release (gpointer data)
+{
+  GtkCombo *combo;
+  GtkWidget *action_widget;
+  GdkEvent tmp_event;
+
+  GDK_THREADS_ENTER ();
+
+  combo = GTK_COMBO (data);
+  if (combo->current_button == 0)
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  tmp_event.button.type = GDK_BUTTON_RELEASE; 
+  tmp_event.button.button = 1; 
+  tmp_event.button.window = combo->list->window;
+  tmp_event.button.time = GDK_CURRENT_TIME;
+  gdk_window_set_user_data (combo->list->window, combo->button);
+  action_widget = combo->list;
+
+  gtk_widget_event (action_widget, &tmp_event);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gboolean
+gail_combo_set_description (AtkAction      *action,
+                            gint           i,
+                            const gchar    *desc)
+{
+  if (i == 0)
+    {
+      GailCombo *combo;
+
+      combo = GAIL_COMBO (action);
+      g_free (combo->press_description);
+      combo->press_description = g_strdup (desc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void
+gail_combo_finalize (GObject            *object)
+{
+  GailCombo *combo = GAIL_COMBO (object);
+
+  g_free (combo->press_description);
+  if (combo->action_idle_handler)
+    {
+      g_source_remove (combo->action_idle_handler);
+      combo->action_idle_handler = 0;
+    }
+  if (combo->deselect_idle_handler)
+    {
+      g_source_remove (combo->deselect_idle_handler);
+      combo->deselect_idle_handler = 0;       
+    }
+  if (combo->select_idle_handler)
+    {
+      g_source_remove (combo->select_idle_handler);
+      combo->select_idle_handler = 0;       
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
diff --git a/modules/other/gail/gailcombo.h b/modules/other/gail/gailcombo.h
new file mode 100644 (file)
index 0000000..79157af
--- /dev/null
@@ -0,0 +1,67 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_COMBO_H__
+#define __GAIL_COMBO_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_COMBO                      (gail_combo_get_type ())
+#define GAIL_COMBO(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_COMBO, GailCombo))
+#define GAIL_COMBO_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_COMBO, GailComboClass))
+#define GAIL_IS_COMBO(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_COMBO))
+#define GAIL_IS_COMBO_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_COMBO))
+#define GAIL_COMBO_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_COMBO, GailComboClass))
+
+typedef struct _GailCombo              GailCombo;
+typedef struct _GailComboClass         GailComboClass;
+
+struct _GailCombo
+{
+  GailContainer parent;
+
+  gchar         *press_description;
+  guint         action_idle_handler;
+
+  gpointer      old_selection;
+  guint         select_idle_handler;
+  guint         deselect_idle_handler;
+};
+
+GType gail_combo_get_type (void);
+
+struct _GailComboClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_combo_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_COMBO_H__ */
diff --git a/modules/other/gail/gailcombobox.c b/modules/other/gail/gailcombobox.c
new file mode 100644 (file)
index 0000000..316e719
--- /dev/null
@@ -0,0 +1,686 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2004 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 <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "gailcombobox.h"
+
+#if GTK_MINOR_VERSION > 4
+#define GAIL_COMBOX_BOX_A11y_COMPLETE
+#endif
+
+static void         gail_combo_box_class_init              (GailComboBoxClass *klass);
+static void         gail_combo_box_object_init             (GailComboBox      *combo_box);
+static void         gail_combo_box_real_initialize         (AtkObject      *obj,
+                                                            gpointer       data);
+
+static void         gail_combo_box_changed_gtk             (GtkWidget      *widget);
+
+static G_CONST_RETURN gchar* gail_combo_box_get_name       (AtkObject      *obj);
+static gint         gail_combo_box_get_n_children          (AtkObject      *obj);
+static AtkObject*   gail_combo_box_ref_child               (AtkObject      *obj,
+                                                            gint           i);
+static void         gail_combo_box_finalize                (GObject        *object);
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+static void         atk_action_interface_init              (AtkActionIface *iface);
+
+static gboolean     gail_combo_box_do_action               (AtkAction      *action,
+                                                            gint           i);
+static gboolean     idle_do_action                         (gpointer       data);
+static gint         gail_combo_box_get_n_actions           (AtkAction      *action)
+;
+static G_CONST_RETURN gchar* gail_combo_box_get_description(AtkAction      *action,
+                                                            gint           i);
+static G_CONST_RETURN gchar* gail_combo_box_get_keybinding   (AtkAction       *action,
+                                                            gint            i);
+static G_CONST_RETURN gchar* gail_combo_box_action_get_name(AtkAction      *action,
+                                                            gint           i);
+static gboolean              gail_combo_box_set_description(AtkAction      *action,
+                                                            gint           i,
+                                                            const gchar    *desc);
+#endif
+
+static void         atk_selection_interface_init           (AtkSelectionIface *iface);
+static gboolean     gail_combo_box_add_selection           (AtkSelection   *selection,
+                                                            gint           i);
+static gboolean     gail_combo_box_clear_selection         (AtkSelection   *selection);
+static AtkObject*   gail_combo_box_ref_selection           (AtkSelection   *selection,
+                                                            gint           i);
+static gint         gail_combo_box_get_selection_count     (AtkSelection   *selection);
+static gboolean     gail_combo_box_is_child_selected       (AtkSelection   *selection,
+                                                            gint           i);
+static gboolean     gail_combo_box_remove_selection        (AtkSelection   *selection,
+                                                            gint           i);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_combo_box_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailComboBoxClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_combo_box_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailComboBox), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_combo_box_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+      static const GInterfaceInfo atk_action_info =
+      {
+        (GInterfaceInitFunc) atk_action_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+#endif
+      static const GInterfaceInfo atk_selection_info =
+      {
+        (GInterfaceInitFunc) atk_selection_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailComboBox", &tinfo, 0);
+
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                   &atk_action_info);
+#endif
+      g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                   &atk_selection_info);
+    }
+
+  return type;
+}
+
+static void
+gail_combo_box_class_init (GailComboBoxClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gail_combo_box_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_name = gail_combo_box_get_name;
+  class->get_n_children = gail_combo_box_get_n_children;
+  class->ref_child = gail_combo_box_ref_child;
+  class->initialize = gail_combo_box_real_initialize;
+}
+
+static void
+gail_combo_box_object_init (GailComboBox      *combo_box)
+{
+  combo_box->press_description = NULL;
+  combo_box->press_keybinding = NULL;
+  combo_box->old_selection = -1;
+  combo_box->name = NULL;
+  combo_box->popup_set = FALSE;
+}
+
+AtkObject* 
+gail_combo_box_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_COMBO_BOX (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_COMBO_BOX, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_combo_box_real_initialize (AtkObject *obj,
+                                gpointer  data)
+{
+  GtkComboBox *combo_box;
+  GailComboBox *gail_combo_box;
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+  AtkObject *popup;
+#endif
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  combo_box = GTK_COMBO_BOX (data);
+
+  gail_combo_box = GAIL_COMBO_BOX (obj);
+
+  g_signal_connect (combo_box,
+                    "changed",
+                    G_CALLBACK (gail_combo_box_changed_gtk),
+                    NULL);
+  gail_combo_box->old_selection = gtk_combo_box_get_active (combo_box);
+
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+  popup = gtk_combo_box_get_popup_accessible (combo_box);
+  if (popup)
+    {
+      atk_object_set_parent (popup, obj);
+      gail_combo_box->popup_set = TRUE;
+    }
+  if (GTK_IS_COMBO_BOX_ENTRY (combo_box))
+    atk_object_set_parent (gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (combo_box))), obj);
+#endif
+
+  obj->role = ATK_ROLE_COMBO_BOX;
+}
+
+static void
+gail_combo_box_changed_gtk (GtkWidget *widget)
+{
+  GtkComboBox *combo_box;
+  AtkObject *obj;
+  GailComboBox *gail_combo_box;
+  gint index;
+
+  combo_box = GTK_COMBO_BOX (widget);
+
+  index = gtk_combo_box_get_active (combo_box);
+  obj = gtk_widget_get_accessible (widget);
+  gail_combo_box = GAIL_COMBO_BOX (obj);
+  if (gail_combo_box->old_selection != index)
+    {
+      gail_combo_box->old_selection = index;
+      g_signal_emit_by_name (obj, "selection_changed");
+    }
+}
+
+static G_CONST_RETURN gchar* 
+gail_combo_box_get_name (AtkObject *obj)
+{
+  GtkWidget *widget;
+  GtkComboBox *combo_box;
+  GailComboBox *gail_combo_box;
+  GtkTreeIter iter;
+  G_CONST_RETURN gchar *name;
+  GtkTreeModel *model;
+  gint n_columns;
+  gint i;
+
+  g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (obj);
+  if (name)
+    return name;
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  combo_box = GTK_COMBO_BOX (widget);
+  gail_combo_box = GAIL_COMBO_BOX (obj);
+  if (gtk_combo_box_get_active_iter (combo_box, &iter))
+    {
+      model = gtk_combo_box_get_model (combo_box);
+      n_columns = gtk_tree_model_get_n_columns (model);
+      for (i = 0; i < n_columns; i++)
+        {
+          GValue value = { 0, };
+
+          gtk_tree_model_get_value (model, &iter, i, &value);
+          if (G_VALUE_HOLDS_STRING (&value))
+            {
+             if (gail_combo_box->name) g_free (gail_combo_box->name);
+              gail_combo_box->name =  g_strdup ((gchar *) 
+                                               g_value_get_string (&value));
+             g_value_unset (&value);
+              break;
+            }
+         else
+           g_value_unset (&value);
+        }
+    }
+  return gail_combo_box->name;
+}
+
+/*
+ * The children of a GailComboBox are the list of items and the entry field
+ * if it is editable.
+ */
+static gint
+gail_combo_box_get_n_children (AtkObject* obj)
+{
+  gint n_children = 0;
+  GtkWidget *widget;
+
+  g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), 0);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+  n_children++;
+  if (GTK_IS_COMBO_BOX_ENTRY (widget))
+    n_children ++;
+#endif
+
+  return n_children;
+}
+
+static AtkObject*
+gail_combo_box_ref_child (AtkObject *obj,
+                          gint      i)
+{
+  GtkWidget *widget;
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+  AtkObject *child;
+  GailComboBox *box;
+#endif
+
+  g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+  if (i == 0)
+    {
+      child = gtk_combo_box_get_popup_accessible (GTK_COMBO_BOX (widget));
+      box = GAIL_COMBO_BOX (obj);
+      if (box->popup_set == FALSE)
+        {
+          atk_object_set_parent (child, obj);
+          box->popup_set = TRUE;
+        }
+    }
+  else if (i == 1 && GTK_IS_COMBO_BOX_ENTRY (widget))
+    {
+      child = gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (widget)));
+    }
+  else
+    {
+      return NULL;
+    }
+  return g_object_ref (child);
+#else
+  return NULL;
+#endif
+}
+
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action = gail_combo_box_do_action;
+  iface->get_n_actions = gail_combo_box_get_n_actions;
+  iface->get_description = gail_combo_box_get_description;
+  iface->get_keybinding = gail_combo_box_get_keybinding;
+  iface->get_name = gail_combo_box_action_get_name;
+  iface->set_description = gail_combo_box_set_description;
+}
+
+static gboolean
+gail_combo_box_do_action (AtkAction *action,
+                          gint      i)
+{
+  GailComboBox *combo_box;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (action)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    return FALSE;
+
+  combo_box = GAIL_COMBO_BOX (action);
+  if (i == 0)
+    {
+      if (combo_box->action_idle_handler)
+        return FALSE;
+
+      combo_box->action_idle_handler = g_idle_add (idle_do_action, combo_box);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  GtkComboBox *combo_box;
+  GtkWidget *widget;
+  GailComboBox *gail_combo_box;
+  AtkObject *popup;
+  gboolean do_popup;
+
+  GDK_THREADS_ENTER ();
+
+  gail_combo_box = GAIL_COMBO_BOX (data);
+  gail_combo_box->action_idle_handler = 0;
+  widget = GTK_ACCESSIBLE (gail_combo_box)->widget;
+  if (widget == NULL || /* State is defunct */
+      !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  combo_box = GTK_COMBO_BOX (widget);
+
+  popup = gtk_combo_box_get_popup_accessible (combo_box);
+  do_popup = !GTK_WIDGET_MAPPED (GTK_ACCESSIBLE (popup)->widget);
+  if (do_popup)
+      gtk_combo_box_popup (combo_box);
+  else
+      gtk_combo_box_popdown (combo_box);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gint
+gail_combo_box_get_n_actions (AtkAction *action)
+{
+  /*
+   * The default behavior of a combo_box box is to have one action -
+   */
+  return 1;
+}
+
+static G_CONST_RETURN gchar*
+gail_combo_box_get_description (AtkAction *action,
+                           gint      i)
+{
+  if (i == 0)
+    {
+      GailComboBox *combo_box;
+
+      combo_box = GAIL_COMBO_BOX (action);
+      return combo_box->press_description;
+    }
+  else
+    return NULL;
+}
+
+static G_CONST_RETURN gchar*
+gail_combo_box_get_keybinding (AtkAction *action,
+                                   gint      i)
+{
+  GailComboBox *combo_box;
+  gchar *return_value = NULL;
+  combo_box = GAIL_COMBO_BOX (action);
+  switch (i)
+  {
+     case 0:
+      {
+         GtkWidget *widget;                                                        
+         GtkWidget *label;
+         AtkRelationSet *set;
+         AtkRelation *relation;                                                             
+         GPtrArray *target;
+         gpointer target_object;
+         guint key_val;
+
+         combo_box = GAIL_COMBO_BOX (action);
+         widget = GTK_ACCESSIBLE (combo_box)->widget;
+         if (widget == NULL)
+             return NULL;
+         set = atk_object_ref_relation_set (ATK_OBJECT (action));                                                      
+         if (!set)
+             return NULL;
+         label = NULL;
+         relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
+         if (relation)
+         {
+            target = atk_relation_get_target (relation);
+            target_object = g_ptr_array_index (target, 0);
+            if (GTK_IS_ACCESSIBLE (target_object))
+            {
+               label = GTK_ACCESSIBLE (target_object)->widget;
+            }
+         }  
+         g_object_unref (set);
+         if (GTK_IS_LABEL (label))
+         {
+             key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
+            if (key_val != GDK_VoidSymbol)
+             return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
+         }
+          g_free (combo_box->press_keybinding);
+          combo_box->press_keybinding = return_value;
+          break;                                                                                    }                             
+    default:
+          break;
+  }
+  return return_value;
+}
+
+
+static G_CONST_RETURN gchar*
+gail_combo_box_action_get_name (AtkAction *action,
+                                gint      i)
+{
+  if (i == 0)
+    return "press";
+  else
+    return NULL;
+}
+
+static gboolean
+gail_combo_box_set_description (AtkAction   *action,
+                                gint        i,
+                                const gchar *desc)
+{
+  if (i == 0)
+    {
+      GailComboBox *combo_box;
+
+      combo_box = GAIL_COMBO_BOX (action);
+      g_free (combo_box->press_description);
+      combo_box->press_description = g_strdup (desc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+#endif
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->add_selection = gail_combo_box_add_selection;
+  iface->clear_selection = gail_combo_box_clear_selection;
+  iface->ref_selection = gail_combo_box_ref_selection;
+  iface->get_selection_count = gail_combo_box_get_selection_count;
+  iface->is_child_selected = gail_combo_box_is_child_selected;
+  iface->remove_selection = gail_combo_box_remove_selection;
+  /*
+   * select_all_selection does not make sense for a combo_box
+   * so no implementation is provided.
+   */
+}
+
+static gboolean
+gail_combo_box_add_selection (AtkSelection *selection,
+                              gint         i)
+{
+  GtkComboBox *combo_box;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  combo_box = GTK_COMBO_BOX (widget);
+
+  gtk_combo_box_set_active (combo_box, i);
+  return TRUE;
+}
+
+static gboolean 
+gail_combo_box_clear_selection (AtkSelection *selection)
+{
+  GtkComboBox *combo_box;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  combo_box = GTK_COMBO_BOX (widget);
+
+  gtk_combo_box_set_active (combo_box, -1);
+  return TRUE;
+}
+
+static AtkObject*
+gail_combo_box_ref_selection (AtkSelection *selection,
+                              gint         i)
+{
+  GtkComboBox *combo_box;
+  GtkWidget *widget;
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+  AtkObject *obj;
+  gint index;
+#endif
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  combo_box = GTK_COMBO_BOX (widget);
+
+  /*
+   * A combo_box box can have only one selection.
+   */
+  if (i != 0)
+    return NULL;
+
+#ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
+  obj = gtk_combo_box_get_popup_accessible (combo_box);
+  index = gtk_combo_box_get_active (combo_box);
+  return atk_object_ref_accessible_child (obj, index);
+#else
+  return NULL;
+#endif
+}
+
+static gint
+gail_combo_box_get_selection_count (AtkSelection *selection)
+{
+  GtkComboBox *combo_box;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  combo_box = GTK_COMBO_BOX (widget);
+
+  return (gtk_combo_box_get_active (combo_box) == -1) ? 0 : 1;
+}
+
+static gboolean
+gail_combo_box_is_child_selected (AtkSelection *selection,
+                                  gint         i)
+{
+  GtkComboBox *combo_box;
+  gint j;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  combo_box = GTK_COMBO_BOX (widget);
+
+  j = gtk_combo_box_get_active (combo_box);
+
+  return (j == i);
+}
+
+static gboolean
+gail_combo_box_remove_selection (AtkSelection *selection,
+                                 gint         i)
+{
+  if (atk_selection_is_child_selected (selection, i))
+    atk_selection_clear_selection (selection);
+
+  return TRUE;
+}
+
+static void
+gail_combo_box_finalize (GObject *object)
+{
+  GailComboBox *combo_box = GAIL_COMBO_BOX (object);
+
+  g_free (combo_box->press_description);
+  g_free (combo_box->press_keybinding);
+  g_free (combo_box->name);
+  if (combo_box->action_idle_handler)
+    {
+      g_source_remove (combo_box->action_idle_handler);
+      combo_box->action_idle_handler = 0;
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
diff --git a/modules/other/gail/gailcombobox.h b/modules/other/gail/gailcombobox.h
new file mode 100644 (file)
index 0000000..f930729
--- /dev/null
@@ -0,0 +1,68 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2004 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_COMBO_BOX_H__
+#define __GAIL_COMBO_BOX_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_COMBO_BOX                      (gail_combo_box_get_type ())
+#define GAIL_COMBO_BOX(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_COMBO_BOX, GailComboBox))
+#define GAIL_COMBO_BOX_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_COMBO_BOX, GailComboBoxClass))
+#define GAIL_IS_COMBO_BOX(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_COMBO_BOX))
+#define GAIL_IS_COMBO_BOX_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_COMBO_BOX))
+#define GAIL_COMBO_BOX_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_COMBO_BOX, GailComboBoxClass))
+
+typedef struct _GailComboBox              GailComboBox;
+typedef struct _GailComboBoxClass         GailComboBoxClass;
+
+struct _GailComboBox
+{
+  GailContainer parent;
+
+  gchar         *press_keybinding;
+  gchar         *press_description;
+  guint         action_idle_handler;
+
+  gchar         *name;
+  gint          old_selection;
+  gboolean      popup_set;
+};
+
+GType gail_combo_box_get_type (void);
+
+struct _GailComboBoxClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_combo_box_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_COMBO_BOX_H__ */
diff --git a/modules/other/gail/gailcontainer.c b/modules/other/gail/gailcontainer.c
new file mode 100644 (file)
index 0000000..23af912
--- /dev/null
@@ -0,0 +1,298 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gtk/gtk.h>
+#include "gailcontainer.h"
+
+static void         gail_container_class_init          (GailContainerClass *klass);
+static void         gail_container_object_init         (GailContainer      *container);
+
+static gint         gail_container_get_n_children      (AtkObject          *obj);
+static AtkObject*   gail_container_ref_child           (AtkObject          *obj,
+                                                        gint               i);
+static gint         gail_container_add_gtk             (GtkContainer       *container,
+                                                        GtkWidget          *widget,
+                                                        gpointer           data);
+static gint         gail_container_remove_gtk          (GtkContainer       *container,
+                                                        GtkWidget          *widget,
+                                                        gpointer           data);
+static gint         gail_container_real_add_gtk        (GtkContainer       *container,
+                                                        GtkWidget          *widget,
+                                                        gpointer           data);
+static gint         gail_container_real_remove_gtk     (GtkContainer       *container,
+                                                        GtkWidget          *widget,
+                                                        gpointer           data);
+
+static void          gail_container_real_initialize    (AtkObject          *obj,
+                                                        gpointer           data);
+
+static void          gail_container_finalize           (GObject            *object);
+
+static GailWidgetClass *parent_class = NULL;
+
+GType
+gail_container_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailContainerClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_container_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailContainer), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_container_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                     "GailContainer", &tinfo, 0);
+    }
+
+  return type;
+}
+
+static void
+gail_container_class_init (GailContainerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gail_container_finalize;
+
+  class->get_n_children = gail_container_get_n_children;
+  class->ref_child = gail_container_ref_child;
+  class->initialize = gail_container_real_initialize;
+
+  klass->add_gtk = gail_container_real_add_gtk;
+  klass->remove_gtk = gail_container_real_remove_gtk;
+}
+
+static void
+gail_container_object_init (GailContainer      *container)
+{
+  container->children = NULL;
+}
+
+AtkObject* 
+gail_container_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_CONTAINER (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_CONTAINER, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static gint 
+gail_container_get_n_children (AtkObject* obj)
+{
+  GtkWidget *widget;
+  GList *children;
+  gint count = 0;
+
+  g_return_val_if_fail (GAIL_IS_CONTAINER (obj), count);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return 0;
+
+  children = gtk_container_get_children (GTK_CONTAINER(widget));
+  count = g_list_length (children);
+  g_list_free (children);
+
+  return count; 
+}
+
+static AtkObject* 
+gail_container_ref_child (AtkObject *obj,
+                          gint       i)
+{
+  GList *children, *tmp_list;
+  AtkObject  *accessible;
+  GtkWidget *widget;
+
+  g_return_val_if_fail (GAIL_IS_CONTAINER (obj), NULL);
+  g_return_val_if_fail ((i >= 0), NULL);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return NULL;
+
+  children = gtk_container_get_children (GTK_CONTAINER (widget));
+  tmp_list = g_list_nth (children, i);
+  if (!tmp_list)
+    {
+      g_list_free (children);
+      return NULL;
+    }  
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
+
+  g_list_free (children);
+  g_object_ref (accessible);
+  return accessible; 
+}
+
+static gint
+gail_container_add_gtk (GtkContainer *container,
+                        GtkWidget    *widget,
+                        gpointer     data)
+{
+  GailContainer *gail_container = GAIL_CONTAINER (data);
+  GailContainerClass *klass;
+
+  klass = GAIL_CONTAINER_GET_CLASS (gail_container);
+
+  if (klass->add_gtk)
+    return klass->add_gtk (container, widget, data);
+  else
+    return 1;
+}
+static gint
+gail_container_remove_gtk (GtkContainer *container,
+                           GtkWidget    *widget,
+                           gpointer     data)
+{
+  GailContainer *gail_container = GAIL_CONTAINER (data);
+  GailContainerClass *klass;
+
+  klass = GAIL_CONTAINER_GET_CLASS (gail_container);
+
+  if (klass->remove_gtk)
+    return klass->remove_gtk (container, widget, data);
+  else
+    return 1;
+}
+static gint
+gail_container_real_add_gtk (GtkContainer *container,
+                             GtkWidget    *widget,
+                             gpointer     data)
+{
+  AtkObject* atk_parent = ATK_OBJECT (data);
+  AtkObject* atk_child = gtk_widget_get_accessible (widget);
+  GailContainer *gail_container = GAIL_CONTAINER (atk_parent);
+  gint       index;
+
+  g_object_notify (G_OBJECT (atk_child), "accessible_parent");
+
+  g_list_free (gail_container->children);
+  gail_container->children = gtk_container_get_children (container);
+  index = g_list_index (gail_container->children, widget);
+  g_signal_emit_by_name (atk_parent, "children_changed::add", 
+                         index, atk_child, NULL);
+
+  return 1;
+}
+
+static gint
+gail_container_real_remove_gtk (GtkContainer       *container,
+                                GtkWidget          *widget,
+                                gpointer           data)
+{
+  AtkPropertyValues values = { NULL };
+  AtkObject* atk_parent;
+  AtkObject *atk_child;
+  GailContainer *gail_container;
+  gint       index;
+
+  atk_parent = ATK_OBJECT (data);
+  atk_child = gtk_widget_get_accessible (widget);
+
+  if (atk_child)
+    {
+      g_value_init (&values.old_value, G_TYPE_POINTER);
+      g_value_set_pointer (&values.old_value, atk_parent);
+    
+      values.property_name = "accessible-parent";
+
+      g_object_ref (atk_child);
+      g_signal_emit_by_name (atk_child,
+                             "property_change::accessible-parent", &values, NULL);
+      g_object_unref (atk_child);
+    }
+  gail_container = GAIL_CONTAINER (atk_parent);
+  index = g_list_index (gail_container->children, widget);
+  g_list_free (gail_container->children);
+  gail_container->children = gtk_container_get_children (container);
+  if (index >= 0 && index <= g_list_length (gail_container->children))
+    g_signal_emit_by_name (atk_parent, "children_changed::remove", 
+                          index, atk_child, NULL);
+
+  return 1;
+}
+
+static void
+gail_container_real_initialize (AtkObject *obj,
+                                gpointer  data)
+{
+  GailContainer *container = GAIL_CONTAINER (obj);
+  guint handler_id;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  container->children = gtk_container_get_children (GTK_CONTAINER (data));
+
+  /*
+   * We store the handler ids for these signals in case some objects
+   * need to remove these handlers.
+   */
+  handler_id = g_signal_connect (data,
+                                 "add",
+                                 G_CALLBACK (gail_container_add_gtk),
+                                 obj);
+  g_object_set_data (G_OBJECT (obj), "gail-add-handler-id", 
+                     GUINT_TO_POINTER (handler_id));
+  handler_id = g_signal_connect (data,
+                                 "remove",
+                                 G_CALLBACK (gail_container_remove_gtk),
+                                 obj);
+  g_object_set_data (G_OBJECT (obj), "gail-remove-handler-id", 
+                     GUINT_TO_POINTER (handler_id));
+
+  if (GTK_IS_TOOLBAR (data))
+    obj->role = ATK_ROLE_TOOL_BAR;
+  else if (GTK_IS_VIEWPORT (data))
+    obj->role = ATK_ROLE_VIEWPORT;
+  else
+    obj->role = ATK_ROLE_PANEL;
+}
+
+static void
+gail_container_finalize (GObject *object)
+{
+  GailContainer *container = GAIL_CONTAINER (object);
+
+  g_list_free (container->children);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
diff --git a/modules/other/gail/gailcontainer.h b/modules/other/gail/gailcontainer.h
new file mode 100644 (file)
index 0000000..6f0f619
--- /dev/null
@@ -0,0 +1,72 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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_CONTAINER_H__
+#define __GAIL_CONTAINER_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CONTAINER                  (gail_container_get_type ())
+#define GAIL_CONTAINER(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CONTAINER, GailContainer))
+#define GAIL_CONTAINER_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CONTAINER, GailContainerClass))
+#define GAIL_IS_CONTAINER(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CONTAINER))
+#define GAIL_IS_CONTAINER_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CONTAINER))
+#define GAIL_CONTAINER_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CONTAINER, GailContainerClass))
+
+typedef struct _GailContainer                 GailContainer;
+typedef struct _GailContainerClass            GailContainerClass;
+
+struct _GailContainer
+{
+  GailWidget parent;
+
+  /*
+   * Cached list of children
+   */
+  GList      *children;
+};
+
+GType gail_container_get_type (void);
+
+struct _GailContainerClass
+{
+  GailWidgetClass parent_class;
+
+  gint (*add_gtk) (GtkContainer *container,
+                   GtkWidget    *widget,
+                   gpointer     data);
+  gint (*remove_gtk) (GtkContainer *container,
+                      GtkWidget    *widget,
+                      gpointer     data);
+};
+
+AtkObject* gail_container_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_CONTAINER_H__ */
diff --git a/modules/other/gail/gailcontainercell.c b/modules/other/gail/gailcontainercell.c
new file mode 100644 (file)
index 0000000..430ca75
--- /dev/null
@@ -0,0 +1,202 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailcontainercell.h"
+
+static void       gail_container_cell_class_init          (GailContainerCellClass *klass);
+static void       gail_container_cell_finalize            (GObject             *obj);
+
+
+static void       _gail_container_cell_recompute_child_indices 
+                                                          (GailContainerCell *container);
+
+static void       gail_container_cell_refresh_child_index (GailCell *cell);
+
+static gint       gail_container_cell_get_n_children      (AtkObject *obj);
+
+static AtkObject* gail_container_cell_ref_child           (AtkObject *obj,
+                                                           gint      child);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_container_cell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailContainerCellClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_container_cell_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailContainerCell), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CELL,
+                                   "GailContainerCell", &tinfo, 0);
+  }
+  return type;
+}
+
+static void 
+gail_container_cell_class_init (GailContainerCellClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
+  GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+  g_object_class->finalize = gail_container_cell_finalize;
+
+  class->get_n_children = gail_container_cell_get_n_children;
+  class->ref_child = gail_container_cell_ref_child;
+}
+
+
+GailContainerCell * 
+gail_container_cell_new (void)
+{
+  GObject *object;
+  AtkObject *atk_object;
+  GailContainerCell *container;
+
+  object = g_object_new (GAIL_TYPE_CONTAINER_CELL, NULL);
+
+  g_return_val_if_fail (object != NULL, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object->role = ATK_ROLE_TABLE_CELL;
+
+  container = GAIL_CONTAINER_CELL(object);
+  container->children = NULL;
+  container->NChildren = 0;
+  return container;
+}
+
+static void
+gail_container_cell_finalize (GObject *obj)
+{
+  GailContainerCell *container = GAIL_CONTAINER_CELL (obj);
+  GList *list;
+
+  list = container->children;
+  while (list)
+  {
+    g_object_unref (list->data);
+    list = list->next;
+  }
+  g_list_free (container->children);
+  
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+
+void
+gail_container_cell_add_child (GailContainerCell *container,
+                              GailCell *child)
+{
+  gint child_index;
+
+  g_return_if_fail (GAIL_IS_CONTAINER_CELL(container));
+  g_return_if_fail (GAIL_IS_CELL(child));
+
+  child_index = container->NChildren++;
+  container->children = g_list_append (container->children, (gpointer) child);
+  child->index = child_index;
+  atk_object_set_parent (ATK_OBJECT (child), ATK_OBJECT (container));
+  child->refresh_index = gail_container_cell_refresh_child_index;
+}
+
+
+void
+gail_container_cell_remove_child (GailContainerCell *container,
+                                 GailCell *child)
+{
+  g_return_if_fail (GAIL_IS_CONTAINER_CELL(container));
+  g_return_if_fail (GAIL_IS_CELL(child));
+  g_return_if_fail (container->NChildren > 0);
+
+  g_list_remove (container->children, (gpointer) child);
+  _gail_container_cell_recompute_child_indices (container);
+  container->NChildren--;
+}
+
+
+static void
+_gail_container_cell_recompute_child_indices (GailContainerCell *container)
+{
+  gint cur_index = 0;
+  GList *temp_list;
+
+  g_return_if_fail (GAIL_IS_CONTAINER_CELL(container));
+
+  for (temp_list = container->children; temp_list; temp_list = temp_list->next)
+    {
+      GAIL_CELL(temp_list->data)->index = cur_index;
+      cur_index++;
+    }
+}
+
+
+static void
+gail_container_cell_refresh_child_index (GailCell *cell)
+{
+  GailContainerCell *container;
+  g_return_if_fail (GAIL_IS_CELL(cell));
+  container = GAIL_CONTAINER_CELL (atk_object_get_parent (ATK_OBJECT(cell)));
+  g_return_if_fail (GAIL_IS_CONTAINER_CELL (container));
+  _gail_container_cell_recompute_child_indices (container);
+}
+
+
+
+static gint
+gail_container_cell_get_n_children (AtkObject *obj)
+{
+  GailContainerCell *cell;
+  g_return_val_if_fail (GAIL_IS_CONTAINER_CELL(obj), 0);
+  cell = GAIL_CONTAINER_CELL(obj);
+  return cell->NChildren;
+}
+
+
+static AtkObject *
+gail_container_cell_ref_child (AtkObject *obj,
+                              gint       child)
+{
+  GailContainerCell *cell;
+  GList *list_node;
+
+  g_return_val_if_fail (GAIL_IS_CONTAINER_CELL(obj), NULL);
+  cell = GAIL_CONTAINER_CELL(obj);
+  
+  list_node = g_list_nth (cell->children, child);
+  if (!list_node)
+    return NULL;
+
+  return g_object_ref (ATK_OBJECT (list_node->data));
+}
diff --git a/modules/other/gail/gailcontainercell.h b/modules/other/gail/gailcontainercell.h
new file mode 100644 (file)
index 0000000..022b78b
--- /dev/null
@@ -0,0 +1,71 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_CONTAINER_CELL_H__
+#define __GAIL_CONTAINER_CELL_H__
+
+#include <atk/atk.h>
+#include <gail/gailcell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_CONTAINER_CELL            (gail_container_cell_get_type ())
+#define GAIL_CONTAINER_CELL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_CONTAINER_CELL, GailContainerCell))
+#define GAIL_CONTAINER_CELL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_CONTAINER_CELL, GailContainerCellClass))
+#define GAIL_IS_CONTAINER_CELL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_CONTAINER_CELL))
+#define GAIL_IS_CONTAINER_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_CONTAINER_CELL))
+#define GAIL_CONTAINER_CELL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_CONTAINER_CELL, GailContainerCellClass))
+
+typedef struct _GailContainerCell                  GailContainerCell;
+typedef struct _GailContainerCellClass             GailContainerCellClass;
+
+struct _GailContainerCell
+{
+  GailCell parent;
+  GList *children;
+  gint NChildren;
+};
+
+GType gail_container_cell_get_type (void);
+
+struct _GailContainerCellClass
+{
+  GailCellClass parent_class;
+};
+
+GailContainerCell *
+gail_container_cell_new (void);
+
+void
+gail_container_cell_add_child (GailContainerCell *container,
+                              GailCell *child);
+
+void
+gail_container_cell_remove_child (GailContainerCell *container,
+                                 GailCell *child);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TREE_VIEW_TEXT_CELL_H__ */
diff --git a/modules/other/gail/gailentry.c b/modules/other/gail/gailentry.c
new file mode 100644 (file)
index 0000000..4910bc7
--- /dev/null
@@ -0,0 +1,1449 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gdk/gdkkeysyms.h>
+#include "gailentry.h"
+#include "gailcombo.h"
+#include "gailcombobox.h"
+#include <libgail-util/gailmisc.h>
+
+static void       gail_entry_class_init            (GailEntryClass       *klass);
+static void       gail_entry_object_init           (GailEntry            *entry);
+static void      gail_entry_real_initialize       (AtkObject            *obj,
+                                                    gpointer             data);
+static void       text_setup                       (GailEntry            *entry,
+                                                    GtkEntry             *gtk_entry);
+static void      gail_entry_real_notify_gtk       (GObject              *obj,
+                                                    GParamSpec          *pspec);
+static void       gail_entry_finalize              (GObject              *object);
+
+static gint       gail_entry_get_index_in_parent   (AtkObject            *accessible);
+
+/* atkobject.h */
+
+static AtkStateSet* gail_entry_ref_state_set       (AtkObject            *accessible);
+
+/* atktext.h */
+
+static void       atk_text_interface_init          (AtkTextIface         *iface);
+
+static gchar*     gail_entry_get_text              (AtkText              *text,
+                                                    gint                 start_pos,
+                                                    gint                 end_pos);
+static gunichar          gail_entry_get_character_at_offset
+                                                  (AtkText              *text,
+                                                   gint                 offset);
+static gchar*    gail_entry_get_text_before_offset(AtkText              *text,
+                                                   gint                 offset,
+                                                   AtkTextBoundary      boundary_type,
+                                                   gint                 *start_offset,
+                                                   gint                 *end_offset);
+static gchar*    gail_entry_get_text_at_offset    (AtkText              *text,
+                                                   gint                 offset,
+                                                   AtkTextBoundary      boundary_type,
+                                                   gint                 *start_offset,
+                                                   gint                 *end_offset);
+static gchar*    gail_entry_get_text_after_offset (AtkText              *text,
+                                                   gint                 offset,
+                                                   AtkTextBoundary      boundary_type,
+                                                   gint                 *start_offset,
+                                                   gint                 *end_offset);
+static gint       gail_entry_get_caret_offset      (AtkText              *text);
+static gboolean   gail_entry_set_caret_offset      (AtkText              *text,
+                                                   gint                 offset);
+static gint      gail_entry_get_n_selections      (AtkText              *text);
+static gchar*    gail_entry_get_selection         (AtkText              *text,
+                                                   gint                 selection_num,
+                                                   gint                 *start_offset,
+                                                   gint                 *end_offset);
+static gboolean          gail_entry_add_selection         (AtkText              *text,
+                                                   gint                 start_offset,
+                                                   gint                 end_offset);
+static gboolean          gail_entry_remove_selection      (AtkText              *text,
+                                                   gint                 selection_num);
+static gboolean          gail_entry_set_selection         (AtkText              *text,
+                                                   gint                 selection_num,
+                                                   gint                 start_offset,
+                                                   gint                 end_offset);
+static gint      gail_entry_get_character_count   (AtkText              *text);
+static AtkAttributeSet *  gail_entry_get_run_attributes 
+                                                   (AtkText              *text,
+                                                   gint                 offset,
+                                                   gint                 *start_offset,
+                                                   gint                 *end_offset);
+static AtkAttributeSet *  gail_entry_get_default_attributes 
+                                                   (AtkText              *text);
+static void gail_entry_get_character_extents       (AtkText             *text,
+                                                   gint                 offset,
+                                                   gint                 *x,
+                                                   gint                 *y,
+                                                   gint                 *width,
+                                                   gint                 *height,
+                                                   AtkCoordType         coords);
+static gint gail_entry_get_offset_at_point         (AtkText              *text,
+                                                    gint                 x,
+                                                    gint                 y,
+                                                   AtkCoordType         coords);
+/* atkeditabletext.h */
+
+static void       atk_editable_text_interface_init (AtkEditableTextIface *iface);
+static void       gail_entry_set_text_contents     (AtkEditableText      *text,
+                                                    const gchar          *string);
+static void       gail_entry_insert_text           (AtkEditableText      *text,
+                                                    const gchar          *string,
+                                                    gint                 length,
+                                                    gint                 *position);
+static void       gail_entry_copy_text             (AtkEditableText      *text,
+                                                    gint                 start_pos,
+                                                    gint                 end_pos);
+static void       gail_entry_cut_text              (AtkEditableText      *text,
+                                                    gint                 start_pos,
+                                                    gint                 end_pos);
+static void       gail_entry_delete_text           (AtkEditableText      *text,
+                                                    gint                 start_pos,
+                                                    gint                 end_pos);
+static void       gail_entry_paste_text            (AtkEditableText      *text,
+                                                    gint                 position);
+static void       gail_entry_paste_received       (GtkClipboard *clipboard,
+                                                   const gchar  *text,
+                                                   gpointer     data);
+
+
+/* Callbacks */
+
+static void       gail_entry_notify_insert         (GailEntry            *entry);
+static void       gail_entry_notify_delete         (GailEntry            *entry);
+static void      _gail_entry_insert_text_cb       (GtkEntry             *entry,
+                                                    gchar               *arg1,
+                                                    gint                arg2,
+                                                    gpointer            arg3);
+static void      _gail_entry_delete_text_cb       (GtkEntry             *entry,
+                                                    gint                arg1,
+                                                    gint                arg2);
+static void      _gail_entry_changed_cb           (GtkEntry             *entry);
+static gboolean   check_for_selection_change       (GailEntry            *entry,
+                                                    GtkEntry             *gtk_entry);
+
+static void                  atk_action_interface_init   (AtkActionIface  *iface);
+
+static gboolean              gail_entry_do_action        (AtkAction       *action,
+                                                          gint            i);
+static gboolean              idle_do_action              (gpointer        data);
+static gint                  gail_entry_get_n_actions    (AtkAction       *action);
+static G_CONST_RETURN gchar* gail_entry_get_description  (AtkAction       *action,
+                                                          gint            i);
+static G_CONST_RETURN gchar* gail_entry_get_keybinding   (AtkAction       *action,
+                                                          gint            i);
+static G_CONST_RETURN gchar* gail_entry_action_get_name  (AtkAction       *action,
+                                                          gint            i);
+static gboolean              gail_entry_set_description  (AtkAction       *action,
+                                                          gint            i,
+                                                          const gchar     *desc);
+
+static GailWidgetClass *parent_class = NULL;
+
+typedef struct _GailEntryPaste                 GailEntryPaste;
+
+struct _GailEntryPaste
+{
+  GtkEntry* entry;
+  gint position;
+};
+
+GType
+gail_entry_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailEntryClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_entry_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailEntry), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_entry_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_editable_text_info =
+      {
+        (GInterfaceInitFunc) atk_editable_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_action_info =
+      {
+        (GInterfaceInitFunc) atk_action_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                     "GailEntry", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT,
+                                   &atk_editable_text_info);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                   &atk_action_info);
+    }
+  return type;
+}
+
+static void
+gail_entry_class_init (GailEntryClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+
+  widget_class = (GailWidgetClass*)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gail_entry_finalize;
+
+  class->ref_state_set = gail_entry_ref_state_set;
+  class->get_index_in_parent = gail_entry_get_index_in_parent;
+  class->initialize = gail_entry_real_initialize;
+
+  widget_class->notify_gtk = gail_entry_real_notify_gtk;
+}
+
+static void
+gail_entry_object_init (GailEntry *entry)
+{
+  entry->textutil = NULL;
+  entry->signal_name_insert = NULL;
+  entry->signal_name_delete = NULL;
+  entry->cursor_position = 0;
+  entry->selection_bound = 0;
+  entry->activate_description = NULL;
+  entry->activate_keybinding = NULL;
+}
+
+static void
+gail_entry_real_initialize (AtkObject *obj, 
+                            gpointer  data)
+{
+  GtkEntry *entry;
+  GailEntry *gail_entry;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  gail_entry = GAIL_ENTRY (obj);
+  gail_entry->textutil = gail_text_util_new ();
+  
+  g_assert (GTK_IS_ENTRY (data));
+
+  entry = GTK_ENTRY (data);
+  text_setup (gail_entry, entry);
+  gail_entry->cursor_position = entry->current_pos;
+  gail_entry->selection_bound = entry->selection_bound;
+
+  /* Set up signal callbacks */
+  g_signal_connect (data, "insert-text",
+       G_CALLBACK (_gail_entry_insert_text_cb), NULL);
+  g_signal_connect (data, "delete-text",
+       G_CALLBACK (_gail_entry_delete_text_cb), NULL);
+  g_signal_connect (data, "changed",
+       G_CALLBACK (_gail_entry_changed_cb), NULL);
+
+  if (entry->visible)
+    obj->role = ATK_ROLE_TEXT;
+  else
+    obj->role = ATK_ROLE_PASSWORD_TEXT;
+}
+
+static void
+gail_entry_real_notify_gtk (GObject            *obj,
+                            GParamSpec         *pspec)
+{
+  GtkWidget *widget;
+  AtkObject* atk_obj;
+  GtkEntry* gtk_entry;
+  GailEntry* entry;
+
+  widget = GTK_WIDGET (obj);
+  atk_obj = gtk_widget_get_accessible (widget);
+  gtk_entry = GTK_ENTRY (widget);
+  entry = GAIL_ENTRY (atk_obj);
+
+  if (strcmp (pspec->name, "cursor-position") == 0)
+    {
+      gail_entry_notify_insert (entry);
+
+      if (check_for_selection_change (entry, gtk_entry))
+        g_signal_emit_by_name (atk_obj, "text_selection_changed");
+      /*
+       * The entry cursor position has moved so generate the signal.
+       */
+      g_signal_emit_by_name (atk_obj, "text_caret_moved", 
+                             entry->cursor_position);
+    }
+  else if (strcmp (pspec->name, "selection-bound") == 0)
+    {
+      gail_entry_notify_insert (entry);
+
+      if (check_for_selection_change (entry, gtk_entry))
+        g_signal_emit_by_name (atk_obj, "text_selection_changed");
+    }
+  else if (strcmp (pspec->name, "editable") == 0)
+    {
+      gboolean value;
+
+      g_object_get (obj, "editable", &value, NULL);
+      atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE,
+                                               value);
+    }
+  else if (strcmp (pspec->name, "visibility") == 0)
+    {
+      gboolean visibility;
+      AtkRole new_role;
+
+      text_setup (entry, gtk_entry);
+      visibility = gtk_entry_get_visibility (gtk_entry);
+      new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT;
+      atk_object_set_role (atk_obj, new_role);
+    }
+  else if (strcmp (pspec->name, "invisible-char") == 0)
+    {
+      text_setup (entry, gtk_entry);
+    }
+  else
+    parent_class->notify_gtk (obj, pspec);
+}
+
+static void
+text_setup (GailEntry *entry,
+            GtkEntry  *gtk_entry)
+{
+  if (gtk_entry_get_visibility (gtk_entry))
+    {
+      gail_text_util_text_setup (entry->textutil, gtk_entry_get_text (gtk_entry));
+    }
+  else
+    {
+      gunichar invisible_char;
+      GString *tmp_string = g_string_new (NULL);
+      gint ch_len; 
+      gchar buf[7];
+      gint i;
+
+      invisible_char = gtk_entry_get_invisible_char (gtk_entry);
+      if (invisible_char == 0)
+        invisible_char = ' ';
+
+      ch_len = g_unichar_to_utf8 (invisible_char, buf);
+      for (i = 0; i < gtk_entry->text_length; i++)
+        {
+          g_string_append_len (tmp_string, buf, ch_len);
+        }
+
+      gail_text_util_text_setup (entry->textutil, tmp_string->str);
+      g_string_free (tmp_string, TRUE);
+
+    } 
+}
+
+static void
+gail_entry_finalize (GObject            *object)
+{
+  GailEntry *entry = GAIL_ENTRY (object);
+
+  g_object_unref (entry->textutil);
+  g_free (entry->activate_description);
+  g_free (entry->activate_keybinding);
+  if (entry->action_idle_handler)
+    {
+      g_source_remove (entry->action_idle_handler);
+      entry->action_idle_handler = 0;
+    }
+  if (entry->insert_idle_handler)
+    {
+      g_source_remove (entry->insert_idle_handler);
+      entry->insert_idle_handler = 0;
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+AtkObject* 
+gail_entry_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_ENTRY, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static gint
+gail_entry_get_index_in_parent (AtkObject *accessible)
+{
+  /*
+   * If the parent widget is a combo box then the index is 1
+   * otherwise do the normal thing.
+   */
+  if (accessible->accessible_parent)
+    if (GAIL_IS_COMBO (accessible->accessible_parent) ||
+        GAIL_IS_COMBO_BOX (accessible->accessible_parent))
+      return 1;
+
+  return ATK_OBJECT_CLASS (parent_class)->get_index_in_parent (accessible);
+}
+
+/* atkobject.h */
+
+static AtkStateSet*
+gail_entry_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkEntry *entry;
+  gboolean value;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+  
+  if (widget == NULL)
+    return state_set;
+
+  entry = GTK_ENTRY (widget);
+
+  g_object_get (G_OBJECT (entry), "editable", &value, NULL);
+  if (value)
+    atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
+  atk_state_set_add_state (state_set, ATK_STATE_SINGLE_LINE);
+
+  return state_set;
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_text = gail_entry_get_text;
+  iface->get_character_at_offset = gail_entry_get_character_at_offset;
+  iface->get_text_before_offset = gail_entry_get_text_before_offset;
+  iface->get_text_at_offset = gail_entry_get_text_at_offset;
+  iface->get_text_after_offset = gail_entry_get_text_after_offset;
+  iface->get_caret_offset = gail_entry_get_caret_offset;
+  iface->set_caret_offset = gail_entry_set_caret_offset;
+  iface->get_character_count = gail_entry_get_character_count;
+  iface->get_n_selections = gail_entry_get_n_selections;
+  iface->get_selection = gail_entry_get_selection;
+  iface->add_selection = gail_entry_add_selection;
+  iface->remove_selection = gail_entry_remove_selection;
+  iface->set_selection = gail_entry_set_selection;
+  iface->get_run_attributes = gail_entry_get_run_attributes;
+  iface->get_default_attributes = gail_entry_get_default_attributes;
+  iface->get_character_extents = gail_entry_get_character_extents;
+  iface->get_offset_at_point = gail_entry_get_offset_at_point;
+}
+
+static gchar*
+gail_entry_get_text (AtkText *text,
+                     gint    start_pos,
+                     gint    end_pos)
+{
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  return gail_text_util_get_substring (GAIL_ENTRY (text)->textutil, start_pos, end_pos);
+}
+
+static gchar*
+gail_entry_get_text_before_offset (AtkText         *text,
+                                  gint             offset,
+                                  AtkTextBoundary  boundary_type,
+                                  gint             *start_offset,
+                                  gint             *end_offset)
+{
+  GtkWidget *widget;
+  GtkEntry *entry;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  /* Get Entry */
+  entry = GTK_ENTRY (widget);
+
+  return gail_text_util_get_text (GAIL_ENTRY (text)->textutil,
+                          gtk_entry_get_layout (entry), GAIL_BEFORE_OFFSET, 
+                          boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_entry_get_text_at_offset (AtkText          *text,
+                               gint             offset,
+                               AtkTextBoundary  boundary_type,
+                               gint             *start_offset,
+                               gint             *end_offset)
+{
+  GtkWidget *widget;
+  GtkEntry *entry;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  /* Get Entry */
+  entry = GTK_ENTRY (widget);
+
+  return gail_text_util_get_text (GAIL_ENTRY (text)->textutil,
+                            gtk_entry_get_layout (entry), GAIL_AT_OFFSET, 
+                            boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_entry_get_text_after_offset  (AtkText         *text,
+                                  gint             offset,
+                                  AtkTextBoundary  boundary_type,
+                                  gint             *start_offset,
+                                  gint             *end_offset)
+{
+  GtkWidget *widget;
+  GtkEntry *entry;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  /* Get Entry */
+  entry = GTK_ENTRY (widget);
+
+  return gail_text_util_get_text (GAIL_ENTRY (text)->textutil,
+                           gtk_entry_get_layout (entry), GAIL_AFTER_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gint
+gail_entry_get_character_count (AtkText *text)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  entry = GTK_ENTRY (widget);
+  return g_utf8_strlen (gtk_entry_get_text (entry), -1);
+}
+
+static gint
+gail_entry_get_caret_offset (AtkText *text)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  entry = GTK_ENTRY (widget);
+
+  return gtk_editable_get_position (GTK_EDITABLE (entry));
+}
+
+static gboolean
+gail_entry_set_caret_offset (AtkText *text, gint offset)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  entry = GTK_ENTRY (widget);
+
+  gtk_editable_set_position (GTK_EDITABLE (entry), offset);
+  return TRUE;
+}
+
+static AtkAttributeSet*
+gail_entry_get_run_attributes (AtkText *text,
+                              gint    offset,
+                               gint    *start_offset,
+                               gint    *end_offset)
+{
+  GtkWidget *widget;
+  GtkEntry *entry;
+  AtkAttributeSet *at_set = NULL;
+  GtkTextDirection dir;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  entry = GTK_ENTRY (widget);
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                gtk_entry_get_layout (entry),
+                                                entry->text,
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  return at_set;
+}
+
+static AtkAttributeSet*
+gail_entry_get_default_attributes (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkEntry *entry;
+  AtkAttributeSet *at_set = NULL;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  entry = GTK_ENTRY (widget);
+
+  at_set = gail_misc_get_default_attributes (at_set,
+                                             gtk_entry_get_layout (entry),
+                                             widget);
+  return at_set;
+}
+  
+static void
+gail_entry_get_character_extents (AtkText *text,
+                                 gint    offset,
+                                 gint    *x,
+                                 gint    *y,
+                                  gint           *width,
+                                  gint           *height,
+                                 AtkCoordType coords)
+{
+  GtkWidget *widget;
+  GtkEntry *entry;
+  PangoRectangle char_rect;
+  gint index, cursor_index, x_layout, y_layout;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  entry = GTK_ENTRY (widget);
+
+  gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
+  index = g_utf8_offset_to_pointer (entry->text, offset) - entry->text;
+  cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - 
+                          entry->text;
+  if (index > cursor_index)
+    index += entry->preedit_length;
+  pango_layout_index_to_pos (gtk_entry_get_layout(entry), index, &char_rect);
+  gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, 
+                        x_layout, y_layout, x, y, width, height, coords);
+} 
+
+static gint 
+gail_entry_get_offset_at_point (AtkText *text,
+                                gint x,
+                                gint y,
+                               AtkCoordType coords)
+{ 
+  GtkWidget *widget;
+  GtkEntry *entry;
+  gint index, cursor_index, x_layout, y_layout;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  entry = GTK_ENTRY (widget);
+  
+  gtk_entry_get_layout_offsets (entry, &x_layout, &y_layout);
+  
+  index = gail_misc_get_index_at_point_in_layout (widget, 
+               gtk_entry_get_layout(entry), x_layout, y_layout, x, y, coords);
+  if (index == -1)
+    {
+      if (coords == ATK_XY_SCREEN || coords == ATK_XY_WINDOW)
+        return g_utf8_strlen (entry->text, -1);
+
+      return index;  
+    }
+  else
+    {
+      cursor_index = g_utf8_offset_to_pointer (entry->text, 
+                                               entry->current_pos) -
+                                             entry->text;
+      if (index >= cursor_index && entry->preedit_length)
+        {
+          if (index >= cursor_index + entry->preedit_length)
+            index -= entry->preedit_length;
+          else
+            index = cursor_index;
+        }
+      return g_utf8_pointer_to_offset (entry->text, entry->text + index);
+    }
+}
+
+static gint
+gail_entry_get_n_selections (AtkText              *text)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  gint select_start, select_end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  entry = GTK_ENTRY (widget);
+
+  gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
+                                     &select_end);
+
+  if (select_start != select_end)
+    return 1;
+  else
+    return 0;
+}
+
+static gchar*
+gail_entry_get_selection (AtkText *text,
+                         gint    selection_num,
+                          gint    *start_pos,
+                          gint    *end_pos)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+ /* Only let the user get the selection if one is set, and if the
+  * selection_num is 0.
+  */
+  if (selection_num != 0)
+     return NULL;
+
+  entry = GTK_ENTRY (widget);
+  gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), start_pos, end_pos);
+
+  if (*start_pos != *end_pos)
+     return gtk_editable_get_chars (GTK_EDITABLE (entry), *start_pos, *end_pos);
+  else
+     return NULL;
+}
+
+static gboolean
+gail_entry_add_selection (AtkText *text,
+                          gint    start_pos,
+                          gint    end_pos)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  gint select_start, select_end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  entry = GTK_ENTRY (widget);
+
+  gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
+                                     &select_end);
+
+ /* If there is already a selection, then don't allow another to be added,
+  * since GtkEntry only supports one selected region.
+  */
+  if (select_start == select_end)
+    {
+       gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
+       return TRUE;
+    }
+  else
+   return FALSE;
+}
+
+static gboolean
+gail_entry_remove_selection (AtkText *text,
+                             gint    selection_num)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  gint select_start, select_end, caret_pos;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  if (selection_num != 0)
+     return FALSE;
+
+  entry = GTK_ENTRY (widget);
+  gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
+                                     &select_end);
+
+  if (select_start != select_end)
+    {
+     /* Setting the start & end of the selected region to the caret position
+      * turns off the selection.
+      */
+      caret_pos = gtk_editable_get_position (GTK_EDITABLE (entry));
+      gtk_editable_select_region (GTK_EDITABLE (entry), caret_pos, caret_pos);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+gail_entry_set_selection (AtkText *text,
+                         gint    selection_num,
+                          gint    start_pos,
+                          gint    end_pos)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  gint select_start, select_end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+ /* Only let the user move the selection if one is set, and if the
+  * selection_num is 0
+  */
+  if (selection_num != 0)
+     return FALSE;
+
+  entry = GTK_ENTRY (widget);
+
+  gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &select_start, 
+                                     &select_end);
+
+  if (select_start != select_end)
+    {
+      gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void
+atk_editable_text_interface_init (AtkEditableTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->set_text_contents = gail_entry_set_text_contents;
+  iface->insert_text = gail_entry_insert_text;
+  iface->copy_text = gail_entry_copy_text;
+  iface->cut_text = gail_entry_cut_text;
+  iface->delete_text = gail_entry_delete_text;
+  iface->paste_text = gail_entry_paste_text;
+  iface->set_run_attributes = NULL;
+}
+
+static void
+gail_entry_set_text_contents (AtkEditableText *text,
+                              const gchar     *string)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  GtkEditable *editable;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (entry);
+  if (!gtk_editable_get_editable (editable))
+    return;
+
+  gtk_entry_set_text (entry, string);
+}
+
+static void
+gail_entry_insert_text (AtkEditableText *text,
+                        const gchar     *string,
+                        gint            length,
+                        gint            *position)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  GtkEditable *editable;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (entry);
+  if (!gtk_editable_get_editable (editable))
+    return;
+
+  gtk_editable_insert_text (editable, string, length, position);
+}
+
+static void
+gail_entry_copy_text   (AtkEditableText *text,
+                        gint            start_pos,
+                        gint            end_pos)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  GtkEditable *editable;
+  gchar *str;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (entry);
+  str = gtk_editable_get_chars (editable, start_pos, end_pos);
+  gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1);
+}
+
+static void
+gail_entry_cut_text (AtkEditableText *text,
+                     gint            start_pos,
+                     gint            end_pos)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  GtkEditable *editable;
+  gchar *str;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (entry);
+  if (!gtk_editable_get_editable (editable))
+    return;
+  str = gtk_editable_get_chars (editable, start_pos, end_pos);
+  gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1);
+  gtk_editable_delete_text (editable, start_pos, end_pos);
+}
+
+static void
+gail_entry_delete_text (AtkEditableText *text,
+                        gint            start_pos,
+                        gint            end_pos)
+{
+  GtkEntry *entry;
+  GtkWidget *widget;
+  GtkEditable *editable;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (entry);
+  if (!gtk_editable_get_editable (editable))
+    return;
+
+  gtk_editable_delete_text (editable, start_pos, end_pos);
+}
+
+static void
+gail_entry_paste_text (AtkEditableText *text,
+                       gint            position)
+{
+  GtkWidget *widget;
+  GtkEditable *editable;
+  GailEntryPaste paste_struct;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  editable = GTK_EDITABLE (widget);
+  if (!gtk_editable_get_editable (editable))
+    return;
+  paste_struct.entry = GTK_ENTRY (widget);
+  paste_struct.position = position;
+
+  g_object_ref (paste_struct.entry);
+  gtk_clipboard_request_text (gtk_clipboard_get(GDK_NONE),
+    gail_entry_paste_received, &paste_struct);
+}
+
+static void
+gail_entry_paste_received (GtkClipboard *clipboard,
+               const gchar  *text,
+               gpointer     data)
+{
+  GailEntryPaste* paste_struct = (GailEntryPaste *)data;
+
+  if (text)
+    gtk_editable_insert_text (GTK_EDITABLE (paste_struct->entry), text, -1,
+       &(paste_struct->position));
+
+  g_object_unref (paste_struct->entry);
+}
+
+/* Callbacks */
+
+static gboolean
+idle_notify_insert (gpointer data)
+{
+  GailEntry *entry;
+
+  GDK_THREADS_ENTER ();
+
+  entry = GAIL_ENTRY (data);
+  entry->insert_idle_handler = 0;
+  gail_entry_notify_insert (entry);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+gail_entry_notify_insert (GailEntry *entry)
+{
+  if (entry->signal_name_insert)
+    {
+      g_signal_emit_by_name (entry, 
+                             entry->signal_name_insert,
+                             entry->position_insert,
+                             entry->length_insert);
+      entry->signal_name_insert = NULL;
+    }
+}
+
+/* Note arg1 returns the character at the start of the insert.
+ * arg2 returns the number of characters inserted.
+ */
+static void 
+_gail_entry_insert_text_cb (GtkEntry *entry, 
+                            gchar    *arg1, 
+                            gint     arg2,
+                            gpointer arg3)
+{
+  AtkObject *accessible;
+  GailEntry *gail_entry;
+  gint *position = (gint *) arg3;
+
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (entry));
+  gail_entry = GAIL_ENTRY (accessible);
+  if (!gail_entry->signal_name_insert)
+    {
+      gail_entry->signal_name_insert = "text_changed::insert";
+      gail_entry->position_insert = *position;
+      gail_entry->length_insert = g_utf8_strlen(arg1, arg2);
+    }
+  /*
+   * The signal will be emitted when the cursor position is updated.
+   * or in an idle handler if it not updated.
+   */
+   if (gail_entry->insert_idle_handler == 0)
+     gail_entry->insert_idle_handler = g_idle_add (idle_notify_insert, gail_entry);
+}
+
+static gunichar 
+gail_entry_get_character_at_offset (AtkText *text,
+                                    gint     offset)
+{
+  GtkWidget *widget;
+  GailEntry *entry;
+  gchar *string;
+  gchar *index;
+  gunichar unichar;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return '\0';
+
+  entry = GAIL_ENTRY (text);
+  string = gail_text_util_get_substring (entry->textutil, 0, -1);
+  if (offset >= g_utf8_strlen (string, -1))
+    {
+      unichar = '\0';
+    }
+  else
+    {
+      index = g_utf8_offset_to_pointer (string, offset);
+
+      unichar = g_utf8_get_char(index);
+    }
+
+  g_free(string);
+  return unichar;
+}
+
+static void
+gail_entry_notify_delete (GailEntry *entry)
+{
+  if (entry->signal_name_delete)
+    {
+      g_signal_emit_by_name (entry, 
+                             entry->signal_name_delete,
+                             entry->position_delete,
+                             entry->length_delete);
+      entry->signal_name_delete = NULL;
+    }
+}
+
+/* Note arg1 returns the start of the delete range, arg2 returns the
+ * end of the delete range if multiple characters are deleted. 
+ */
+static void 
+_gail_entry_delete_text_cb (GtkEntry *entry, 
+                            gint      arg1, 
+                            gint      arg2)
+{
+  AtkObject *accessible;
+  GailEntry *gail_entry;
+
+  /*
+   * Zero length text deleted so ignore
+   */
+  if (arg2 - arg1 == 0)
+    return;
+
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (entry));
+  gail_entry = GAIL_ENTRY (accessible);
+  if (!gail_entry->signal_name_delete)
+    {
+      gail_entry->signal_name_delete = "text_changed::delete";
+      gail_entry->position_delete = arg1;
+      gail_entry->length_delete = arg2 - arg1;
+    }
+  gail_entry_notify_delete (gail_entry);
+}
+
+static void
+_gail_entry_changed_cb (GtkEntry *entry)
+{
+  AtkObject *accessible;
+  GailEntry *gail_entry;
+
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (entry));
+
+  gail_entry = GAIL_ENTRY (accessible);
+
+  text_setup (gail_entry, entry);
+}
+
+static gboolean 
+check_for_selection_change (GailEntry   *entry,
+                            GtkEntry    *gtk_entry)
+{
+  gboolean ret_val = FALSE;
+  if (gtk_entry->current_pos != gtk_entry->selection_bound)
+    {
+      if (gtk_entry->current_pos != entry->cursor_position ||
+          gtk_entry->selection_bound != entry->selection_bound)
+        /*
+         * This check is here as this function can be called
+         * for notification of selection_bound and current_pos.
+         * The values of current_pos and selection_bound may be the same 
+         * for both notifications and we only want to generate one
+         * text_selection_changed signal.
+         */
+        ret_val = TRUE;
+    }
+  else 
+    {
+      /* We had a selection */
+      ret_val = (entry->cursor_position != entry->selection_bound);
+    }
+  entry->cursor_position = gtk_entry->current_pos;
+  entry->selection_bound = gtk_entry->selection_bound;
+
+  return ret_val;
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action = gail_entry_do_action;
+  iface->get_n_actions = gail_entry_get_n_actions;
+  iface->get_description = gail_entry_get_description;
+  iface->get_keybinding = gail_entry_get_keybinding;
+  iface->get_name = gail_entry_action_get_name;
+  iface->set_description = gail_entry_set_description;
+}
+
+static gboolean
+gail_entry_do_action (AtkAction *action,
+                      gint      i)
+{
+  GailEntry *entry;
+  GtkWidget *widget;
+  gboolean return_value = TRUE;
+
+  entry = GAIL_ENTRY (action);
+  widget = GTK_ACCESSIBLE (action)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    return FALSE;
+
+  switch (i)
+    {
+    case 0:
+      if (entry->action_idle_handler)
+        return_value = FALSE;
+      else
+        entry->action_idle_handler = g_idle_add (idle_do_action, entry);
+      break;
+    default:
+      return_value = FALSE;
+      break;
+    }
+  return return_value; 
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  GailEntry *entry;
+  GtkWidget *widget;
+
+  GDK_THREADS_ENTER ();
+
+  entry = GAIL_ENTRY (data);
+  entry->action_idle_handler = 0;
+  widget = GTK_ACCESSIBLE (entry)->widget;
+  if (widget == NULL /* State is defunct */ ||
+      !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  gtk_widget_activate (widget);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gint
+gail_entry_get_n_actions (AtkAction *action)
+{
+  return 1;
+}
+
+static G_CONST_RETURN gchar*
+gail_entry_get_description (AtkAction *action,
+                            gint      i)
+{
+  GailEntry *entry;
+  G_CONST_RETURN gchar *return_value;
+
+  entry = GAIL_ENTRY (action);
+  switch (i)
+    {
+    case 0:
+      return_value = entry->activate_description;
+      break;
+    default:
+      return_value = NULL;
+      break;
+    }
+  return return_value; 
+}
+
+static G_CONST_RETURN gchar*
+gail_entry_get_keybinding (AtkAction *action,
+                           gint      i)
+{
+  GailEntry *entry;
+  gchar *return_value = NULL;
+
+  entry = GAIL_ENTRY (action);
+  switch (i)
+    {
+    case 0:
+      {
+        /*
+         * We look for a mnemonic on the label
+         */
+        GtkWidget *widget;
+        GtkWidget *label;
+        AtkRelationSet *set;
+        AtkRelation *relation;
+        GPtrArray *target;
+        gpointer target_object;
+        guint key_val; 
+
+        entry = GAIL_ENTRY (action);
+        widget = GTK_ACCESSIBLE (entry)->widget;
+        if (widget == NULL)
+          /*
+           * State is defunct
+           */
+          return NULL;
+
+        /* Find labelled-by relation */
+
+        set = atk_object_ref_relation_set (ATK_OBJECT (action));
+        if (!set)
+          return NULL;
+        label = NULL;
+        relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
+        if (relation)
+          {              
+            target = atk_relation_get_target (relation);
+          
+            target_object = g_ptr_array_index (target, 0);
+            if (GTK_IS_ACCESSIBLE (target_object))
+              {
+                label = GTK_ACCESSIBLE (target_object)->widget;
+              } 
+          }
+
+        g_object_unref (set);
+
+        if (GTK_IS_LABEL (label))
+          {
+            key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); 
+            if (key_val != GDK_VoidSymbol)
+              return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
+          }
+        g_free (entry->activate_keybinding);
+        entry->activate_keybinding = return_value;
+        break;
+      }
+    default:
+      break;
+    }
+  return return_value; 
+}
+
+static G_CONST_RETURN gchar*
+gail_entry_action_get_name (AtkAction *action,
+                            gint      i)
+{
+  G_CONST_RETURN gchar *return_value;
+
+  switch (i)
+    {
+    case 0:
+      return_value = "activate";
+      break;
+    default:
+      return_value = NULL;
+      break;
+  }
+  return return_value; 
+}
+
+static gboolean
+gail_entry_set_description (AtkAction      *action,
+                            gint           i,
+                            const gchar    *desc)
+{
+  GailEntry *entry;
+  gchar **value;
+
+  entry = GAIL_ENTRY (action);
+  switch (i)
+    {
+    case 0:
+      value = &entry->activate_description;
+      break;
+    default:
+      value = NULL;
+      break;
+    }
+
+  if (value)
+    {
+      g_free (*value);
+      *value = g_strdup (desc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
diff --git a/modules/other/gail/gailentry.h b/modules/other/gail/gailentry.h
new file mode 100644 (file)
index 0000000..1fa332f
--- /dev/null
@@ -0,0 +1,78 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_ENTRY_H__
+#define __GAIL_ENTRY_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_ENTRY                      (gail_entry_get_type ())
+#define GAIL_ENTRY(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_ENTRY, GailEntry))
+#define GAIL_ENTRY_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_ENTRY, GailEntryClass))
+#define GAIL_IS_ENTRY(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_ENTRY))
+#define GAIL_IS_ENTRY_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_ENTRY))
+#define GAIL_ENTRY_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_ENTRY, GailEntryClass))
+
+typedef struct _GailEntry              GailEntry;
+typedef struct _GailEntryClass         GailEntryClass;
+
+struct _GailEntry
+{
+  GailWidget parent;
+
+  GailTextUtil *textutil;
+  /*
+   * These fields store information about text changed
+   */
+  gchar          *signal_name_insert;
+  gchar          *signal_name_delete;
+  gint           position_insert;
+  gint           position_delete;
+  gint           length_insert;
+  gint           length_delete;
+  gint           cursor_position;
+  gint           selection_bound;
+
+  gchar          *activate_description;
+  gchar          *activate_keybinding;
+  guint          action_idle_handler;
+  guint          insert_idle_handler;
+};
+
+GType gail_entry_get_type (void);
+
+struct _GailEntryClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_entry_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_ENTRY_H__ */
diff --git a/modules/other/gail/gailexpander.c b/modules/other/gail/gailexpander.c
new file mode 100644 (file)
index 0000000..8d43e2f
--- /dev/null
@@ -0,0 +1,950 @@
+/* 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 <gdk/gdkkeysyms.h>
+#include "gailexpander.h"
+#include <libgail-util/gailmisc.h>
+
+static void                  gail_expander_class_init       (GailExpanderClass *klass);
+static void                  gail_expander_object_init      (GailExpander      *expander);
+
+static G_CONST_RETURN gchar* gail_expander_get_name         (AtkObject         *obj);
+static gint                  gail_expander_get_n_children   (AtkObject         *obj)
+;
+static AtkObject*            gail_expander_ref_child        (AtkObject         *obj,
+                                                             gint              i);
+
+static AtkStateSet*          gail_expander_ref_state_set    (AtkObject         *obj);
+static void                  gail_expander_real_notify_gtk  (GObject           *obj,
+                                                             GParamSpec        *pspec);
+static void                  gail_expander_map_gtk          (GtkWidget         *widget,
+                                                             gpointer          data);
+
+static void                  gail_expander_real_initialize  (AtkObject         *obj,
+                                                             gpointer          data);
+static void                  gail_expander_finalize         (GObject           *object);
+static void                  gail_expander_init_textutil    (GailExpander      *expander,
+                                                             GtkExpander       *widget);
+
+static void                  atk_action_interface_init  (AtkActionIface *iface);
+static gboolean              gail_expander_do_action    (AtkAction      *action,
+                                                         gint           i);
+static gboolean              idle_do_action             (gpointer       data);
+static gint                  gail_expander_get_n_actions(AtkAction      *action);
+static G_CONST_RETURN gchar* gail_expander_get_description
+                                                        (AtkAction      *action,
+                                                         gint           i);
+static G_CONST_RETURN gchar* gail_expander_get_keybinding 
+                                                        (AtkAction      *action,
+                                                         gint           i);
+static G_CONST_RETURN gchar* gail_expander_action_get_name
+                                                        (AtkAction      *action,
+                                                         gint           i);
+static gboolean              gail_expander_set_description
+                                                        (AtkAction      *action,
+                                                         gint           i,
+                                                         const gchar    *desc);
+
+/* atktext.h */ 
+static void      atk_text_interface_init          (AtkTextIface        *iface);
+
+static gchar*    gail_expander_get_text           (AtkText           *text,
+                                                    gint             start_pos,
+                                                   gint              end_pos);
+static gunichar          gail_expander_get_character_at_offset
+                                                   (AtkText          *text,
+                                                   gint              offset);
+static gchar*     gail_expander_get_text_before_offset
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_expander_get_text_at_offset (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_expander_get_text_after_offset
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gint      gail_expander_get_character_count(AtkText           *text);
+static void gail_expander_get_character_extents    (AtkText          *text,
+                                                   gint              offset,
+                                                   gint              *x,
+                                                   gint              *y,
+                                                   gint              *width,
+                                                   gint              *height,
+                                                   AtkCoordType      coords);
+static gint gail_expander_get_offset_at_point      (AtkText           *text,
+                                                    gint              x,
+                                                    gint              y,
+                                                   AtkCoordType      coords);
+static AtkAttributeSet* gail_expander_get_run_attributes 
+                                                   (AtkText           *text,
+                                                   gint              offset,
+                                                    gint             *start_offset,
+                                                   gint              *end_offset);
+static AtkAttributeSet* gail_expander_get_default_attributes
+                                                   (AtkText           *text);
+
+static GailContainer* parent_class = NULL;
+
+GType
+gail_expander_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailExpanderClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_expander_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailExpander), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_expander_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_action_info =
+      {
+        (GInterfaceInitFunc) atk_action_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailExpander", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                   &atk_action_info);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+
+    }
+
+  return type;
+}
+
+static void
+gail_expander_class_init (GailExpanderClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+
+  widget_class = (GailWidgetClass*)klass;
+  widget_class->notify_gtk = gail_expander_real_notify_gtk;
+
+  gobject_class->finalize = gail_expander_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_name = gail_expander_get_name;
+  class->get_n_children = gail_expander_get_n_children;
+  class->ref_child = gail_expander_ref_child;
+  class->ref_state_set = gail_expander_ref_state_set;
+
+  class->initialize = gail_expander_real_initialize;
+}
+
+static void
+gail_expander_object_init (GailExpander *expander)
+{
+  expander->activate_description = NULL;
+  expander->activate_keybinding = NULL;
+  expander->action_idle_handler = 0;
+  expander->textutil = NULL;
+}
+
+AtkObject* 
+gail_expander_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_EXPANDER (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_EXPANDER, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static G_CONST_RETURN gchar*
+gail_expander_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *name;
+  g_return_val_if_fail (GAIL_IS_EXPANDER (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (obj);
+  if (name != NULL)
+    return name;
+  else
+    {
+      /*
+       * Get the text on the label
+       */
+      GtkWidget *widget;
+
+      widget = GTK_ACCESSIBLE (obj)->widget;
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+
+      g_return_val_if_fail (GTK_IS_EXPANDER (widget), NULL);
+
+      return gtk_expander_get_label (GTK_EXPANDER (widget)); 
+    }
+}
+
+static gint
+gail_expander_get_n_children (AtkObject* obj)
+{
+  GtkWidget *widget;
+  GList *children;
+  gint count = 0;
+
+  g_return_val_if_fail (GAIL_IS_CONTAINER (obj), count);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return 0;
+
+  children = gtk_container_get_children (GTK_CONTAINER(widget));
+  count = g_list_length (children);
+  g_list_free (children);
+
+  /* See if there is a label - if there is, reduce our count by 1
+   * since we don't want the label included with the children.
+   */
+  if (gtk_expander_get_label_widget (widget))
+    count -= 1;
+
+  return count; 
+}
+
+static AtkObject*
+gail_expander_ref_child (AtkObject *obj,
+                         gint      i)
+{
+  GList *children, *tmp_list;
+  AtkObject *accessible;
+  GtkWidget *widget;
+  GtkWidget *label;
+  gint index;
+  gint count;
+
+  g_return_val_if_fail (GAIL_IS_CONTAINER (obj), NULL);
+  g_return_val_if_fail ((i >= 0), NULL);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return NULL;
+
+  children = gtk_container_get_children (GTK_CONTAINER (widget));
+
+  /* See if there is a label - if there is, we need to skip it
+   * since we don't want the label included with the children.
+   */
+  label = gtk_expander_get_label_widget (widget);
+  if (label) {
+    count = g_list_length (children);
+    for (index = 0; index <= i; index++) {
+      tmp_list = g_list_nth (children, index);
+      if (label == GTK_WIDGET (tmp_list->data)) {
+       i += 1;
+       break;
+      }
+    }
+  }
+
+  tmp_list = g_list_nth (children, i);
+  if (!tmp_list)
+    {
+      g_list_free (children);
+      return NULL;
+    }  
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
+
+  g_list_free (children);
+  g_object_ref (accessible);
+  return accessible; 
+}
+
+static void
+gail_expander_real_initialize (AtkObject *obj,
+                               gpointer   data)
+{
+  GailExpander *gail_expander = GAIL_EXPANDER (obj);
+  GtkWidget  *expander;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  expander = GTK_WIDGET (data);
+  if (GTK_WIDGET_MAPPED (expander))
+    gail_expander_init_textutil (gail_expander, GTK_EXPANDER (expander));
+  else 
+    g_signal_connect (expander,
+                      "map",
+                      G_CALLBACK (gail_expander_map_gtk),
+                      gail_expander);
+  obj->role = ATK_ROLE_TOGGLE_BUTTON;
+}
+
+static void
+gail_expander_map_gtk (GtkWidget *widget,
+                       gpointer data)
+{
+  GailExpander *expander; 
+
+  expander = GAIL_EXPANDER (data);
+  gail_expander_init_textutil (expander, GTK_EXPANDER (widget));
+}
+
+static void
+gail_expander_real_notify_gtk (GObject    *obj,
+                               GParamSpec *pspec)
+{
+  AtkObject* atk_obj;
+  GtkExpander *expander;
+  GailExpander *gail_expander;
+
+  expander = GTK_EXPANDER (obj);
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (expander));
+;
+  if (strcmp (pspec->name, "label") == 0)
+    {
+      const gchar* label_text;
+
+
+      label_text = gtk_expander_get_label (expander);
+
+      gail_expander = GAIL_EXPANDER (atk_obj);
+      if (gail_expander->textutil)
+        gail_text_util_text_setup (gail_expander->textutil, label_text);
+
+      if (atk_obj->name == NULL)
+      {
+        /*
+         * The label has changed so notify a change in accessible-name
+         */
+        g_object_notify (G_OBJECT (atk_obj), "accessible-name");
+      }
+      /*
+       * The label is the only property which can be changed
+       */
+      g_signal_emit_by_name (atk_obj, "visible_data_changed");
+    }
+  else if (strcmp (pspec->name, "expanded") == 0)
+    {
+      atk_object_notify_state_change (atk_obj, ATK_STATE_CHECKED, 
+                                      gtk_expander_get_expanded (expander));
+      atk_object_notify_state_change (atk_obj, ATK_STATE_EXPANDED, 
+                                      gtk_expander_get_expanded (expander));
+      g_signal_emit_by_name (atk_obj, "visible_data_changed");
+    }
+  else
+    GAIL_WIDGET_CLASS (parent_class)->notify_gtk (obj, pspec);
+}
+
+static void
+gail_expander_init_textutil (GailExpander *expander,
+                             GtkExpander  *widget)
+{
+  const gchar *label_text;
+
+  expander->textutil = gail_text_util_new ();
+  label_text = gtk_expander_get_label (widget);
+  gail_text_util_text_setup (expander->textutil, label_text);
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action = gail_expander_do_action;
+  iface->get_n_actions = gail_expander_get_n_actions;
+  iface->get_description = gail_expander_get_description;
+  iface->get_keybinding = gail_expander_get_keybinding;
+  iface->get_name = gail_expander_action_get_name;
+  iface->set_description = gail_expander_set_description;
+}
+
+static gboolean
+gail_expander_do_action (AtkAction *action,
+                         gint      i)
+{
+  GtkWidget *widget;
+  GailExpander *expander;
+  gboolean return_value = TRUE;
+
+  widget = GTK_ACCESSIBLE (action)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  if (!GTK_WIDGET_IS_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    return FALSE;
+
+  expander = GAIL_EXPANDER (action);
+  switch (i)
+    {
+    case 0:
+      if (expander->action_idle_handler)
+        return_value = FALSE;
+      else
+       expander->action_idle_handler = g_idle_add (idle_do_action, expander);
+      break;
+    default:
+      return_value = FALSE;
+      break;
+    }
+  return return_value; 
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  GtkWidget *widget;
+  GailExpander *gail_expander;
+
+  GDK_THREADS_ENTER ();
+
+  gail_expander = GAIL_EXPANDER (data);
+  gail_expander->action_idle_handler = 0;
+
+  widget = GTK_ACCESSIBLE (gail_expander)->widget;
+  if (widget == NULL /* State is defunct */ ||
+      !GTK_WIDGET_IS_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  gtk_widget_activate (widget);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE; 
+}
+
+static gint
+gail_expander_get_n_actions (AtkAction *action)
+{
+  return 1;
+}
+
+static G_CONST_RETURN gchar*
+gail_expander_get_description (AtkAction *action,
+                               gint      i)
+{
+  GailExpander *expander;
+  G_CONST_RETURN gchar *return_value;
+
+  expander = GAIL_EXPANDER (action);
+
+  switch (i)
+    {
+    case 0:
+      return_value = expander->activate_description;
+      break;
+    default:
+      return_value = NULL;
+      break;
+    }
+  return return_value; 
+}
+
+static G_CONST_RETURN gchar*
+gail_expander_get_keybinding (AtkAction *action,
+                              gint      i)
+{
+  GailExpander *expander;
+  gchar *return_value = NULL;
+
+  switch (i)
+    {
+    case 0:
+      {
+        /*
+         * We look for a mnemonic on the label
+         */
+        GtkWidget *widget;
+        GtkWidget *label;
+
+        expander = GAIL_EXPANDER (action);
+        widget = GTK_ACCESSIBLE (expander)->widget;
+        if (widget == NULL)
+          /*
+           * State is defunct
+           */
+          return NULL;
+
+        g_return_val_if_fail (GTK_IS_EXPANDER (widget), NULL);
+
+        label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+        if (GTK_IS_LABEL (label))
+          {
+            guint key_val; 
+
+            key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label)); 
+            if (key_val != GDK_VoidSymbol)
+              return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
+            g_free (expander->activate_keybinding);
+            expander->activate_keybinding = return_value;
+          }
+        break;
+      }
+    default:
+      break;
+    }
+  return return_value; 
+}
+
+static G_CONST_RETURN gchar*
+gail_expander_action_get_name (AtkAction *action,
+                               gint      i)
+{
+  G_CONST_RETURN gchar *return_value;
+
+  switch (i)
+    {
+    case 0:
+      return_value = "activate";
+      break;
+    default:
+      return_value = NULL;
+      break;
+    }
+  return return_value; 
+}
+
+static gboolean
+gail_expander_set_description (AtkAction      *action,
+                               gint           i,
+                               const gchar    *desc)
+{
+  GailExpander *expander;
+  gchar **value;
+
+  expander = GAIL_EXPANDER (action);
+
+  switch (i)
+    {
+    case 0:
+      value = &expander->activate_description;
+      break;
+    default:
+      value = NULL;
+      break;
+    }
+  if (value)
+    {
+      g_free (*value);
+      *value = g_strdup (desc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static AtkStateSet*
+gail_expander_ref_state_set (AtkObject *obj)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+  GtkExpander *expander;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  expander = GTK_EXPANDER (widget);
+
+  atk_state_set_add_state (state_set, ATK_STATE_EXPANDABLE);
+
+  if (gtk_expander_get_expanded (expander)) {
+    atk_state_set_add_state (state_set, ATK_STATE_CHECKED);
+    atk_state_set_add_state (state_set, ATK_STATE_EXPANDED);
+  }
+
+  return state_set;
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->get_text = gail_expander_get_text;
+  iface->get_character_at_offset = gail_expander_get_character_at_offset;
+  iface->get_text_before_offset = gail_expander_get_text_before_offset;
+  iface->get_text_at_offset = gail_expander_get_text_at_offset;
+  iface->get_text_after_offset = gail_expander_get_text_after_offset;
+  iface->get_character_count = gail_expander_get_character_count;
+  iface->get_character_extents = gail_expander_get_character_extents;
+  iface->get_offset_at_point = gail_expander_get_offset_at_point;
+  iface->get_run_attributes = gail_expander_get_run_attributes;
+  iface->get_default_attributes = gail_expander_get_default_attributes;
+}
+
+static gchar*
+gail_expander_get_text (AtkText *text,
+                        gint    start_pos,
+                        gint    end_pos)
+{
+  GtkWidget *widget;
+  GailExpander *expander;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  expander = GAIL_EXPANDER (text);
+  if (!expander->textutil) 
+    gail_expander_init_textutil (expander, GTK_EXPANDER (widget));
+
+  label_text = gtk_expander_get_label (GTK_EXPANDER (widget));
+
+  if (label_text == NULL)
+    return NULL;
+  else
+    return gail_text_util_get_substring (expander->textutil, 
+                                         start_pos, end_pos);
+}
+
+static gchar*
+gail_expander_get_text_before_offset (AtkText         *text,
+                                     gint            offset,
+                                     AtkTextBoundary boundary_type,
+                                     gint            *start_offset,
+                                     gint            *end_offset)
+{
+  GtkWidget *widget;
+  GailExpander *expander;
+  GtkWidget *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  expander = GAIL_EXPANDER (text);
+  if (!expander->textutil) 
+    gail_expander_init_textutil (expander, GTK_EXPANDER (widget));
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  return gail_text_util_get_text (expander->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)),
+                           GAIL_BEFORE_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset); 
+}
+
+static gchar*
+gail_expander_get_text_at_offset (AtkText         *text,
+                                 gint            offset,
+                                 AtkTextBoundary boundary_type,
+                                 gint            *start_offset,
+                                 gint            *end_offset)
+{
+  GtkWidget *widget;
+  GailExpander *expander;
+  GtkWidget *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  expander = GAIL_EXPANDER (text);
+  if (!expander->textutil) 
+    gail_expander_init_textutil (expander, GTK_EXPANDER (widget));
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  return gail_text_util_get_text (expander->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)),
+                           GAIL_AT_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_expander_get_text_after_offset (AtkText         *text,
+                                    gint            offset,
+                                    AtkTextBoundary boundary_type,
+                                    gint            *start_offset,
+                                    gint            *end_offset)
+{
+  GtkWidget *widget;
+  GailExpander *expander;
+  GtkWidget *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  expander = GAIL_EXPANDER (text);
+  if (!expander->textutil) 
+    gail_expander_init_textutil (expander, GTK_EXPANDER (widget));
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  return gail_text_util_get_text (expander->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)),
+                           GAIL_AFTER_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gint
+gail_expander_get_character_count (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+  if (!GTK_IS_LABEL(label))
+    return 0;
+
+  return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
+}
+
+static void
+gail_expander_get_character_extents (AtkText      *text,
+                                    gint         offset,
+                                    gint         *x,
+                                    gint       *y,
+                                     gint      *width,
+                                     gint      *height,
+                                    AtkCoordType coords)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  PangoRectangle char_rect;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+  widget = GTK_ACCESSIBLE (text)->widget;
+
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+  if (!GTK_IS_LABEL(label))
+    return;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
+  pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
+  
+  gail_misc_get_extents_from_pango_rectangle (label, &char_rect, 
+                    x_layout, y_layout, x, y, width, height, coords);
+} 
+
+static gint 
+gail_expander_get_offset_at_point (AtkText      *text,
+                                   gint         x,
+                                   gint         y,
+                                  AtkCoordType coords)
+{ 
+  GtkWidget *widget;
+  GtkWidget *label;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+
+  if (!GTK_IS_LABEL(label))
+    return -1;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  
+  index = gail_misc_get_index_at_point_in_layout (label, 
+                                              gtk_label_get_layout (GTK_LABEL (label)), 
+                                              x_layout, y_layout, x, y, coords);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  if (index == -1)
+    {
+      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+        return g_utf8_strlen (label_text, -1);
+
+      return index;  
+    }
+  else
+    return g_utf8_pointer_to_offset (label_text, label_text + index);  
+}
+
+static AtkAttributeSet*
+gail_expander_get_run_attributes (AtkText *text,
+                                  gint           offset,
+                                  gint           *start_offset,
+                                 gint    *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+  GtkJustification justify;
+  GtkTextDirection dir;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  
+  /* Get values set for entire label, if any */
+  justify = gtk_label_get_justify (GTK_LABEL (label));
+  if (justify != GTK_JUSTIFY_CENTER)
+    {
+      at_set = gail_misc_add_attribute (at_set, 
+                                        ATK_TEXT_ATTR_JUSTIFICATION,
+     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
+    }
+  dir = gtk_widget_get_direction (label);
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                gtk_label_get_layout (GTK_LABEL (label)),
+                                                (gchar *) gtk_label_get_text (GTK_LABEL (label)),
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  return at_set;
+}
+
+static AtkAttributeSet*
+gail_expander_get_default_attributes (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  at_set = gail_misc_get_default_attributes (at_set,
+                                             gtk_label_get_layout (GTK_LABEL (label)),
+                                             widget);
+  return at_set;
+}
+
+static gunichar 
+gail_expander_get_character_at_offset (AtkText *text,
+                                       gint    offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  const gchar *string;
+  gchar *index;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return '\0';
+
+  label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+
+  if (!GTK_IS_LABEL(label))
+    return '\0';
+  string = gtk_label_get_text (GTK_LABEL (label));
+  if (offset >= g_utf8_strlen (string, -1))
+    return '\0';
+  index = g_utf8_offset_to_pointer (string, offset);
+
+  return g_utf8_get_char (index);
+}
+
+static void
+gail_expander_finalize (GObject *object)
+{
+  GailExpander *expander = GAIL_EXPANDER (object);
+
+  g_free (expander->activate_description);
+  g_free (expander->activate_keybinding);
+  if (expander->action_idle_handler)
+    {
+      g_source_remove (expander->action_idle_handler);
+      expander->action_idle_handler = 0;
+    }
+  if (expander->textutil)
+    g_object_unref (expander->textutil);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
diff --git a/modules/other/gail/gailexpander.h b/modules/other/gail/gailexpander.h
new file mode 100644 (file)
index 0000000..a1e8c29
--- /dev/null
@@ -0,0 +1,66 @@
+/* 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_EXPANDER_H__
+#define __GAIL_EXPANDER_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_EXPANDER              (gail_expander_get_type ())
+#define GAIL_EXPANDER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_EXPANDER, GailExpander))
+#define GAIL_EXPANDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_EXPANDER, GailExpanderClass))
+#define GAIL_IS_EXPANDER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_EXPANDER))
+#define GAIL_IS_EXPANDER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_EXPANDER))
+#define GAIL_EXPANDER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_EXPANDER, GailExpanderClass))
+
+typedef struct _GailExpander              GailExpander;
+typedef struct _GailExpanderClass         GailExpanderClass;
+
+struct _GailExpander
+{
+  GailContainer parent;
+
+  gchar         *activate_description;
+  gchar         *activate_keybinding;
+  guint         action_idle_handler;
+
+  GailTextUtil   *textutil;
+};
+
+GType gail_expander_get_type (void);
+
+struct _GailExpanderClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_expander_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_EXPANDER_H__ */
diff --git a/modules/other/gail/gailfactory.h b/modules/other/gail/gailfactory.h
new file mode 100644 (file)
index 0000000..0ea4dba
--- /dev/null
@@ -0,0 +1,85 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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_FACTORY_H__
+#define _GAIL_FACTORY_H__
+
+#include <glib-object.h>
+#include <atk/atkobject.h>
+
+#define GAIL_ACCESSIBLE_FACTORY(type, type_as_function, opt_create_accessible) \
+                                                                               \
+static GType                                                                   \
+type_as_function ## _factory_get_accessible_type (void)                                \
+{                                                                              \
+  return type;                                                                 \
+}                                                                              \
+                                                                               \
+static AtkObject*                                                              \
+type_as_function ## _factory_create_accessible (GObject *obj)                  \
+{                                                                              \
+  GtkWidget *widget;                                                           \
+  AtkObject *accessible;                                                       \
+                                                                               \
+  g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);                            \
+                                                                               \
+  widget = GTK_WIDGET (obj);                                                   \
+                                                                               \
+  accessible = opt_create_accessible (widget);                                 \
+                                                                               \
+  return accessible;                                                           \
+}                                                                              \
+                                                                               \
+static void                                                                    \
+type_as_function ## _factory_class_init (AtkObjectFactoryClass *klass)         \
+{                                                                              \
+  klass->create_accessible   = type_as_function ## _factory_create_accessible; \
+  klass->get_accessible_type = type_as_function ## _factory_get_accessible_type;\
+}                                                                              \
+                                                                               \
+static GType                                                                   \
+type_as_function ## _factory_get_type (void)                                   \
+{                                                                              \
+  static GType t = 0;                                                          \
+                                                                               \
+  if (!t)                                                                      \
+  {                                                                            \
+    char *name;                                                                        \
+    static const GTypeInfo tinfo =                                             \
+    {                                                                          \
+      sizeof (AtkObjectFactoryClass),                                  \
+      NULL, NULL, (GClassInitFunc) type_as_function ## _factory_class_init,                    \
+      NULL, NULL, sizeof (AtkObjectFactory), 0, NULL, NULL                     \
+    };                                                                         \
+                                                                               \
+    name = g_strconcat (g_type_name (type), "Factory", NULL);                  \
+    t = g_type_register_static (                                               \
+           ATK_TYPE_OBJECT_FACTORY, name, &tinfo, 0);                          \
+    g_free (name);                                                             \
+  }                                                                            \
+                                                                               \
+  return t;                                                                    \
+}
+
+#define GAIL_WIDGET_SET_FACTORY(widget_type, type_as_function)                 \
+       atk_registry_set_factory_type (atk_get_default_registry (),             \
+                                      widget_type,                             \
+                                      type_as_function ## _factory_get_type ())
+
+#endif /* _GAIL_FACTORY_H__ */
diff --git a/modules/other/gail/gailframe.c b/modules/other/gail/gailframe.c
new file mode 100644 (file)
index 0000000..4d85f0c
--- /dev/null
@@ -0,0 +1,113 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 "gailframe.h"
+
+static void                  gail_frame_class_init       (GailFrameClass  *klass);
+static G_CONST_RETURN gchar* gail_frame_get_name         (AtkObject       *obj);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_frame_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailFrameClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_frame_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailFrame), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                   "GailFrame", &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void
+gail_frame_class_init (GailFrameClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  class->get_name = gail_frame_get_name;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+AtkObject* 
+gail_frame_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_FRAME (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_FRAME, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_PANEL;
+
+  return accessible;
+}
+
+static G_CONST_RETURN gchar*
+gail_frame_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *name;
+  g_return_val_if_fail (GAIL_IS_FRAME (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (obj);
+  if (name != NULL)
+  {
+    return name;
+  }
+  else
+  {
+    /*
+     * Get the text on the label
+     */
+    GtkWidget *widget;
+
+    widget = GTK_ACCESSIBLE (obj)->widget;
+    if (widget == NULL)
+    {
+      /*
+       * State is defunct
+       */
+      return NULL;
+    }
+    return gtk_frame_get_label (GTK_FRAME (widget));
+  }
+}
diff --git a/modules/other/gail/gailframe.h b/modules/other/gail/gailframe.h
new file mode 100644 (file)
index 0000000..142c8de
--- /dev/null
@@ -0,0 +1,60 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_FRAME_H__
+#define __GAIL_FRAME_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_FRAME                      (gail_frame_get_type ())
+#define GAIL_FRAME(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_FRAME, GailFrame))
+#define GAIL_FRAME_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_FRAME, GailFrameClass))
+#define GAIL_IS_FRAME(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_FRAME))
+#define GAIL_IS_FRAME_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_FRAME))
+#define GAIL_FRAME_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_FRAME, GailFrameClass))
+
+typedef struct _GailFrame                   GailFrame;
+typedef struct _GailFrameClass              GailFrameClass;
+
+struct _GailFrame
+{
+  GailContainer parent;
+};
+
+GType gail_frame_get_type (void);
+
+struct _GailFrameClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_frame_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_FRAME_H__ */
diff --git a/modules/other/gail/gailhtmlbox.c b/modules/other/gail/gailhtmlbox.c
new file mode 100644 (file)
index 0000000..1d8def6
--- /dev/null
@@ -0,0 +1,289 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailhtmlbox.h"
+#include "gailhtmlview.h"
+#include <libgtkhtml/layout/htmlbox.h>
+
+static void         gail_html_box_class_init               (GailHtmlBoxClass  *klass);
+static void         gail_html_box_initialize               (AtkObject         *obj,
+                                                            gpointer          data);
+static gint         gail_html_box_get_index_in_parent      (AtkObject         *obj);
+static AtkStateSet* gail_html_box_ref_state_set                   (AtkObject         *obj);
+
+static void         gail_html_box_component_interface_init (AtkComponentIface *iface);
+static guint        gail_html_box_add_focus_handler        (AtkComponent      *component,
+                                                            AtkFocusHandler   handler);
+static void         gail_html_box_get_extents              (AtkComponent      *component,
+                                                            gint              *x,
+                                                            gint              *y,
+                                                            gint              *width,
+                                                            gint              *height,
+                                                            AtkCoordType      coord_type);
+static gboolean     gail_html_box_grab_focus               (AtkComponent      *component);
+static void         gail_html_box_remove_focus_handler     (AtkComponent      *component,
+                                                            guint             handler_id);
+
+static AtkGObjectClass *parent_class = NULL;
+
+GType
+gail_html_box_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailHtmlBoxClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_html_box_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailHtmlBox), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_component_info =
+      {
+        (GInterfaceInitFunc) gail_html_box_component_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (ATK_TYPE_GOBJECT,
+                                     "GailHtmlBox", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+                                   &atk_component_info);
+    }
+
+  return type;
+}
+
+static void
+gail_html_box_class_init (GailHtmlBoxClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_ref (ATK_TYPE_GOBJECT);
+
+  class->get_index_in_parent = gail_html_box_get_index_in_parent;
+  class->ref_state_set = gail_html_box_ref_state_set;
+  class->initialize = gail_html_box_initialize;
+}
+
+AtkObject*
+gail_html_box_new (GObject *obj)
+{
+  GObject *object;
+  AtkObject *atk_object;
+
+  g_return_val_if_fail (HTML_IS_BOX (obj), NULL);
+  object = g_object_new (GAIL_TYPE_HTML_BOX, NULL);
+  atk_object = ATK_OBJECT (object);
+  atk_object_initialize (atk_object, obj);
+  atk_object->role = ATK_ROLE_UNKNOWN;
+  return atk_object;
+}
+
+static void
+gail_html_box_initialize (AtkObject *obj,
+                          gpointer  data)
+{
+  HtmlBox *box;
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  box = HTML_BOX (data);
+
+  /*
+   * We do not set the parent here for the root node of a HtmlView
+   */
+  if (box->parent)
+    { 
+      atk_object_set_parent (obj,
+                        atk_gobject_get_accessible (G_OBJECT (box->parent)));
+    }
+}
+
+static gint
+gail_html_box_get_index_in_parent (AtkObject *obj)
+{
+  AtkObject *parent;
+  AtkGObject *atk_gobj;
+  HtmlBox *box;
+  HtmlBox *parent_box;
+  gint n_children = 0;
+  GObject *g_obj;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX (obj), -1);
+
+  atk_gobj = ATK_GOBJECT (obj);
+  g_obj = atk_gobject_get_object (atk_gobj);
+  if (g_obj == NULL)
+    return -1;
+
+  g_return_val_if_fail (HTML_IS_BOX (g_obj), -1);
+  box = HTML_BOX (g_obj);
+  parent = atk_object_get_parent (obj);
+  if (GAIL_IS_HTML_VIEW (parent))
+    {
+      return 0;
+    }
+  else if (ATK_IS_GOBJECT (parent))
+    {
+      parent_box = HTML_BOX (atk_gobject_get_object (ATK_GOBJECT (parent)));
+    }
+  else
+    {
+      g_assert_not_reached ();
+      return -1;
+    }
+
+  if (parent_box)
+    {
+      HtmlBox *child;
+
+      child = parent_box->children;
+
+      while (child)
+        {
+          if (child == box)
+            return n_children;
+
+          n_children++;
+          child = child->next;
+        }
+    }
+  return -1;
+}
+
+static AtkStateSet*
+gail_html_box_ref_state_set (AtkObject   *obj)
+{
+  AtkGObject *atk_gobj;
+  GObject *g_obj;
+  AtkStateSet *state_set;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX (obj), NULL);
+  atk_gobj = ATK_GOBJECT (obj);
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+
+  g_obj = atk_gobject_get_object (atk_gobj);
+  if (g_obj == NULL)
+    {
+      /* Object is defunct */
+      atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
+    }
+  else
+    {
+      HtmlBox *box;
+  
+      box = HTML_BOX (g_obj);
+
+      if (HTML_BOX_GET_STYLE (box)->display != HTML_DISPLAY_NONE)
+        {
+          atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
+          atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
+        }
+    }
+  return state_set;
+} 
+
+static void
+gail_html_box_component_interface_init (AtkComponentIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  /*
+   * Use default implementation for contains and get_position
+   */
+  iface->contains = NULL;
+  iface->get_position = NULL;
+  iface->add_focus_handler = gail_html_box_add_focus_handler;
+  iface->get_extents = gail_html_box_get_extents;
+  iface->get_size = NULL;
+  iface->grab_focus = gail_html_box_grab_focus;
+  iface->remove_focus_handler = gail_html_box_remove_focus_handler;
+  iface->set_extents = NULL;
+  iface->set_position = NULL;
+  iface->set_size = NULL;
+}
+
+static guint
+gail_html_box_add_focus_handler (AtkComponent    *component,
+                                 AtkFocusHandler handler)
+{
+  return g_signal_connect_closure (component, 
+                                   "focus-event",
+                                   g_cclosure_new (
+                                                  G_CALLBACK (handler), NULL,
+                                                  (GClosureNotify) NULL),
+                                   FALSE);
+}
+
+static void
+gail_html_box_get_extents (AtkComponent *component,
+                           gint         *x,
+                           gint         *y,
+                           gint         *width,
+                           gint         *height,
+                           AtkCoordType coord_type)
+{
+  AtkGObject *atk_gobj;
+  HtmlBox *box;
+  GObject *g_obj;
+
+  g_return_if_fail (GAIL_IS_HTML_BOX (component));
+
+  atk_gobj = ATK_GOBJECT (component);
+  g_obj = atk_gobject_get_object (atk_gobj);
+  if (g_obj == NULL)
+    return;
+
+  g_return_if_fail (HTML_IS_BOX (g_obj));
+  box = HTML_BOX (g_obj);
+
+  *x = html_box_get_absolute_x (box);
+  *y = html_box_get_absolute_y (box);
+  *width = box->width;
+  *height = box->height;
+
+  g_print ("%d %d %d %d\n",
+           html_box_get_absolute_x (box),
+           html_box_get_absolute_y (box),
+           html_box_get_containing_block_width (box),
+           html_box_get_containing_block_height (box));
+}
+
+static gboolean
+gail_html_box_grab_focus (AtkComponent    *component)
+{
+  return TRUE;
+}
+
+static void
+gail_html_box_remove_focus_handler (AtkComponent *component,
+                                    guint        handler_id)
+{
+  g_signal_handler_disconnect (ATK_OBJECT (component), handler_id);
+}
diff --git a/modules/other/gail/gailhtmlbox.h b/modules/other/gail/gailhtmlbox.h
new file mode 100644 (file)
index 0000000..bf2200b
--- /dev/null
@@ -0,0 +1,58 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_HTML_BOX_H__
+#define __GAIL_HTML_BOX_H__
+
+#include <atk/atk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_HTML_BOX                   (gail_html_box_get_type ())
+#define GAIL_HTML_BOX(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_HTML_BOX, GailHtmlBox))
+#define GAIL_HTML_BOX_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_HTML_BOX, GailHtmlBoxClass))
+#define GAIL_IS_HTML_BOX(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_HTML_BOX))
+#define GAIL_IS_HTML_BOX_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_HTML_BOX))
+#define GAIL_HTML_BOX_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_HTML_BOX, GailHtmlBoxClass))
+
+typedef struct _GailHtmlBox                 GailHtmlBox;
+typedef struct _GailHtmlBoxClass            GailHtmlBoxClass;
+
+struct _GailHtmlBox
+{
+  AtkGObject parent;
+};
+
+struct _GailHtmlBoxClass
+{
+  AtkGObjectClass parent_class;
+};
+
+GType gail_html_box_get_type (void);
+
+AtkObject* gail_html_box_new (GObject *obj);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_HTML_BOX_H__ */
diff --git a/modules/other/gail/gailhtmlboxblock.c b/modules/other/gail/gailhtmlboxblock.c
new file mode 100644 (file)
index 0000000..9240029
--- /dev/null
@@ -0,0 +1,153 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <libgtkhtml/gtkhtml.h>
+#include "gailhtmlboxblock.h"
+
+static void       gail_html_box_block_class_init      (GailHtmlBoxBlockClass *klass);
+static gint       gail_html_box_block_get_n_children  (AtkObject             *obj);
+static AtkObject* gail_html_box_block_ref_child       (AtkObject             *obj,
+                                                       gint                  i);
+
+static GailHtmlBoxClass *parent_class = NULL;
+
+GType
+gail_html_box_block_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailHtmlBoxBlockClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_html_box_block_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailHtmlBoxBlock), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_HTML_BOX,
+                                     "GailHtmlBoxBlock", &tinfo, 0);
+    }
+
+  return type;
+}
+
+AtkObject*
+gail_html_box_block_new (GObject *obj)
+{
+  GObject *object;
+  AtkObject *atk_object;
+
+  g_return_val_if_fail (HTML_IS_BOX_BLOCK (obj), NULL);
+  object = g_object_new (GAIL_TYPE_HTML_BOX_BLOCK, NULL);
+  atk_object = ATK_OBJECT (object);
+  atk_object_initialize (atk_object, obj);
+  atk_object->role = ATK_ROLE_PANEL;
+  return atk_object;
+}
+
+static void
+gail_html_box_block_class_init (GailHtmlBoxBlockClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_ref (GAIL_TYPE_HTML_BOX);
+
+  class->get_n_children = gail_html_box_block_get_n_children;
+  class->ref_child = gail_html_box_block_ref_child;
+}
+
+static gint
+gail_html_box_block_get_n_children (AtkObject *obj)
+{
+  AtkGObject *atk_gobject;
+  HtmlBox *box;
+  gint n_children = 0;
+  GObject *g_obj;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_BLOCK (obj), 0);
+  atk_gobject = ATK_GOBJECT (obj); 
+  g_obj = atk_gobject_get_object (atk_gobject);
+  if (g_obj == NULL)
+    return 0;
+
+  g_return_val_if_fail (HTML_IS_BOX (g_obj), 0);
+  box = HTML_BOX (g_obj);
+
+  if (box)
+    {
+      HtmlBox *child;
+
+      child = box->children;
+
+      while (child)
+        {
+          n_children++;
+          child = child->next;
+        }
+    }
+  return n_children;
+}
+
+static AtkObject *
+gail_html_box_block_ref_child (AtkObject *obj,
+                               gint      i)
+{
+  AtkGObject *atk_gobject;
+  GObject *g_obj;
+  HtmlBox *box;
+  AtkObject *atk_child = NULL;
+  gint n_children = 0;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_BLOCK (obj), NULL);
+  atk_gobject = ATK_GOBJECT (obj); 
+  g_obj = atk_gobject_get_object (atk_gobject);
+  if (g_obj == NULL)
+    return NULL;
+
+  g_return_val_if_fail (HTML_IS_BOX (g_obj), NULL);
+  box = HTML_BOX (g_obj);
+
+  if (box)
+    {
+      HtmlBox *child;
+
+      child = box->children;
+
+      while (child)
+        {
+          if (n_children == i)
+            {
+              atk_child = atk_gobject_get_accessible (G_OBJECT (child));
+              g_object_ref (atk_child);
+              break;
+            }
+          n_children++;
+          child = child->next;
+        }
+    }
+  return atk_child;
+}
diff --git a/modules/other/gail/gailhtmlboxembedded.c b/modules/other/gail/gailhtmlboxembedded.c
new file mode 100644 (file)
index 0000000..30d20f3
--- /dev/null
@@ -0,0 +1,133 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <libgtkhtml/gtkhtml.h>
+#include "gailhtmlboxembedded.h"
+
+static void       gail_html_box_embedded_class_init      (GailHtmlBoxEmbeddedClass *klass);
+static gint       gail_html_box_embedded_get_n_children  (AtkObject             *obj);
+static AtkObject* gail_html_box_embedded_ref_child       (AtkObject             *obj,
+                                                          gint                  i);
+
+static GailHtmlBoxClass *parent_class = NULL;
+
+GType
+gail_html_box_embedded_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailHtmlBoxEmbeddedClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_html_box_embedded_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailHtmlBoxEmbedded), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_HTML_BOX,
+                                     "GailHtmlBoxEmbedded", &tinfo, 0);
+    }
+
+  return type;
+}
+
+AtkObject*
+gail_html_box_embedded_new (GObject *obj)
+{
+  gpointer object;
+  AtkObject *atk_object;
+
+  g_return_val_if_fail (HTML_IS_BOX_EMBEDDED (obj), NULL);
+  object = g_object_new (GAIL_TYPE_HTML_BOX_EMBEDDED, NULL);
+  atk_object = ATK_OBJECT (object);
+  atk_object_initialize (atk_object, obj);
+  atk_object->role = ATK_ROLE_PANEL;
+  return atk_object;
+}
+
+static void
+gail_html_box_embedded_class_init (GailHtmlBoxEmbeddedClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_ref (GAIL_TYPE_HTML_BOX);
+
+  class->get_n_children = gail_html_box_embedded_get_n_children;
+  class->ref_child = gail_html_box_embedded_ref_child;
+}
+
+static gint
+gail_html_box_embedded_get_n_children (AtkObject *obj)
+{
+  AtkGObject *atk_gobject;
+  HtmlBoxEmbedded *box_embedded;
+  GObject *g_obj;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_EMBEDDED (obj), 0);
+  atk_gobject = ATK_GOBJECT (obj); 
+  g_obj = atk_gobject_get_object (atk_gobject);
+  if (g_obj == NULL)
+    /* State is defunct */
+    return 0;
+
+  g_return_val_if_fail (HTML_IS_BOX_EMBEDDED (g_obj), 0);
+
+  box_embedded = HTML_BOX_EMBEDDED (g_obj);
+  g_return_val_if_fail (box_embedded->widget, 0);
+  return 1;
+}
+
+static AtkObject*
+gail_html_box_embedded_ref_child (AtkObject *obj,
+                                  gint      i)
+{
+  AtkGObject *atk_gobject;
+  HtmlBoxEmbedded *box_embedded;
+  GObject *g_obj;
+  AtkObject *atk_child;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_EMBEDDED (obj), NULL);
+
+  if (i != 0)
+         return NULL;
+
+  atk_gobject = ATK_GOBJECT (obj);
+  g_obj = atk_gobject_get_object (atk_gobject);
+  if (g_obj == NULL)
+    /* State is defunct */
+    return NULL;
+
+  g_return_val_if_fail (HTML_IS_BOX_EMBEDDED (g_obj), NULL);
+
+  box_embedded = HTML_BOX_EMBEDDED (g_obj);
+  g_return_val_if_fail (box_embedded->widget, NULL);
+
+  atk_child = gtk_widget_get_accessible (box_embedded->widget);
+  g_object_ref (atk_child);
+  atk_object_set_parent (atk_child, obj);
+  return atk_child;
+}
diff --git a/modules/other/gail/gailhtmlboxtext.c b/modules/other/gail/gailhtmlboxtext.c
new file mode 100644 (file)
index 0000000..9d2874c
--- /dev/null
@@ -0,0 +1,506 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 "gailhtmlboxtext.h"
+
+static void           gail_html_box_text_class_init          (GailHtmlBoxTextClass *klass);
+static void           gail_html_box_text_text_interface_init (AtkTextIface        *iface);
+static gchar*         gail_html_box_text_get_text            (AtkText             *text,
+                                                              gint                start_offset,
+                                                              gint                end_offset);
+static gchar*         gail_html_box_text_get_text_after_offset 
+                                                             (AtkText             *text,
+                                                              gint                offset,
+                                                              AtkTextBoundary     boundary_type,
+                                                              gint                *start_offset,
+                                                              gint                *end_offset);
+static gchar*         gail_html_box_text_get_text_at_offset  (AtkText             *text,
+                                                              gint                offset,
+                                                              AtkTextBoundary     boundary_type,
+                                                              gint                *start_offset,
+                                                              gint                *end_offset);
+static gchar*         gail_html_box_text_get_text_before_offset 
+                                                             (AtkText             *text,
+                                                              gint                offset,
+                                                              AtkTextBoundary     boundary_type,
+                                                              gint                *start_offset,
+                                                              gint                *end_offset);
+static gunichar       gail_html_box_text_get_character_at_offset 
+                                                              (AtkText            *text,
+                                                               gint               offset);
+static gint           gail_html_box_text_get_character_count  (AtkText            *text);
+static gint           gail_html_box_text_get_caret_offset     (AtkText            *text);
+static gboolean       gail_html_box_text_set_caret_offset     (AtkText            *text,
+                                                               gint               offset);
+static gint           gail_html_box_text_get_offset_at_point  (AtkText            *text,
+                                                               gint               x,
+                                                               gint               y,
+                                                               AtkCoordType       coords);
+static void           gail_html_box_text_get_character_extents (AtkText           *text,
+                                                                gint              offset,
+                                                                gint              *x,
+                                                                gint              *y,
+                                                                gint              *width,
+                                                                gint              *height,
+                                                                AtkCoordType      coords);
+static AtkAttributeSet* 
+                      gail_html_box_text_get_run_attributes    (AtkText           *text,
+                                                                gint              offset,
+                                                                gint              *start_offset,
+                                                                gint              *end_offset);
+static AtkAttributeSet* 
+                      gail_html_box_text_get_default_attributes (AtkText          *text);
+static gint           gail_html_box_text_get_n_selections      (AtkText           *text);
+static gchar*         gail_html_box_text_get_selection         (AtkText           *text,
+                                                                gint              selection_num,
+                                                                gint              *start_pos,
+                                                                gint              *end_pos);
+static gboolean       gail_html_box_text_add_selection         (AtkText           *text,
+                                                                gint              start_pos,
+                                                                gint              end_pos);
+static gboolean       gail_html_box_text_remove_selection      (AtkText           *text,
+                                                                gint              selection_num);
+static gboolean       gail_html_box_text_set_selection         (AtkText           *text,
+                                                                gint              selection_num,
+                                                                gint              start_pos,
+                                                                gint              end_pos);
+static AtkAttributeSet*
+                      add_to_attr_set                          (AtkAttributeSet   *attrib_set,
+                                                                GtkTextAttributes *attrs,
+                                                                AtkTextAttribute  attr);
+static gchar*         get_text_near_offset                     (AtkText           *text,
+                                                                GailOffsetType    function,
+                                                                AtkTextBoundary   boundary_type,
+                                                                gint              offset,
+                                                                gint              *start_offset,
+                                                                gint              *end_offset);
+
+static AtkObjectClass *parent_class = NULL;
+
+GType
+gail_html_box_text_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailHtmlBoxTextClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_html_box_text_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailHtmlBoxText), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) gail_html_box_text_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+      type = g_type_register_static (GAIL_TYPE_HTML_BOX,
+                                     "GailHtmlBoxText", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);      
+    }
+
+  return type;
+}
+
+AtkObject*
+gail_html_box_text_new (GObject *obj)
+{
+  gpointer object;
+  AtkObject *atk_object;
+  GailHtmlBoxText *gail_text;
+
+  g_return_val_if_fail (HTML_IS_BOX_TEXT (obj), NULL);
+  object = g_object_new (GAIL_TYPE_HTML_BOX_TEXT, NULL);
+  atk_object = ATK_OBJECT (object);
+  gail_text = GAIL_HTML_BOX_TEXT (object);
+
+  atk_object_initialize (atk_object, obj);
+  gail_text->texthelper = gail_text_helper_new ();
+#if 0
+  gail_text_helper_text_setup (gail_text->texthelper,
+                               HTML_BOX_TEXT (obj)->master->text);
+#endif
+
+  atk_object->role =  ATK_ROLE_TEXT;
+  return atk_object;
+}
+
+static void
+gail_html_box_text_class_init (GailHtmlBoxTextClass *klass)
+{
+  parent_class = g_type_class_ref (ATK_TYPE_OBJECT);
+}
+
+static void
+gail_html_box_text_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_text = gail_html_box_text_get_text;
+  iface->get_text_after_offset = gail_html_box_text_get_text_after_offset;
+  iface->get_text_at_offset = gail_html_box_text_get_text_at_offset;
+  iface->get_text_before_offset = gail_html_box_text_get_text_before_offset;
+  iface->get_character_at_offset = gail_html_box_text_get_character_at_offset;
+  iface->get_character_count = gail_html_box_text_get_character_count;
+  iface->get_caret_offset = gail_html_box_text_get_caret_offset;
+  iface->set_caret_offset = gail_html_box_text_set_caret_offset;
+  iface->get_offset_at_point = gail_html_box_text_get_offset_at_point;
+  iface->get_character_extents = gail_html_box_text_get_character_extents;
+  iface->get_n_selections = gail_html_box_text_get_n_selections;
+  iface->get_selection = gail_html_box_text_get_selection;
+  iface->add_selection = gail_html_box_text_add_selection;
+  iface->remove_selection = gail_html_box_text_remove_selection;
+  iface->set_selection = gail_html_box_text_set_selection;
+  iface->get_run_attributes = gail_html_box_text_get_run_attributes;
+  iface->get_default_attributes = gail_html_box_text_get_default_attributes;
+}
+
+static gchar*
+gail_html_box_text_get_text (AtkText *text,
+                             gint    start_offset,
+                             gint    end_offset)
+{
+  GailHtmlBoxText *gail_text;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_TEXT (text), NULL);
+  gail_text = GAIL_HTML_BOX_TEXT (text);
+  g_return_val_if_fail (gail_text->texthelper, NULL);
+
+  buffer = gail_text->texthelper->buffer;
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
+  gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
+
+  return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+}
+
+static gchar*
+gail_html_box_text_get_text_after_offset (AtkText         *text,
+                                          gint            offset,
+                                          AtkTextBoundary boundary_type,
+                                          gint            *start_offset,
+                                          gint            *end_offset)
+{
+  return get_text_near_offset (text, GAIL_AFTER_OFFSET,
+                               boundary_type, offset, 
+                               start_offset, end_offset);
+}
+
+static gchar*
+gail_html_box_text_get_text_at_offset (AtkText         *text,
+                                       gint            offset,
+                                       AtkTextBoundary boundary_type,
+                                       gint            *start_offset,
+                                       gint            *end_offset)
+{
+  return get_text_near_offset (text, GAIL_AT_OFFSET,
+                               boundary_type, offset, 
+                               start_offset, end_offset);
+}
+
+static gchar*
+gail_html_box_text_get_text_before_offset (AtkText         *text,
+                                           gint            offset,
+                                           AtkTextBoundary boundary_type,
+                                           gint            *start_offset,
+                                           gint            *end_offset)
+{
+  return get_text_near_offset (text, GAIL_BEFORE_OFFSET,
+                               boundary_type, offset, 
+                               start_offset, end_offset);
+}
+
+static gunichar
+gail_html_box_text_get_character_at_offset (AtkText *text,
+                                            gint    offset)
+{
+  GailHtmlBoxText *gail_item;
+  GtkTextIter start, end;
+  GtkTextBuffer *buffer;
+  gchar *string;
+  gchar *index;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_TEXT (text), 0);
+  gail_item = GAIL_HTML_BOX_TEXT (text);
+  buffer = gail_item->texthelper->buffer;
+  gtk_text_buffer_get_start_iter (buffer, &start);
+  gtk_text_buffer_get_end_iter (buffer, &end);
+  string = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+  index = g_utf8_offset_to_pointer (string, offset);
+  g_free (string);
+
+  return g_utf8_get_char (index);
+}
+
+static gint
+gail_html_box_text_get_character_count (AtkText *text)
+{
+  GtkTextBuffer *buffer;
+  GailHtmlBoxText *gail_text;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_TEXT (text), 0);
+  gail_text = GAIL_HTML_BOX_TEXT (text);
+  g_return_val_if_fail (gail_text->texthelper, 0);
+  buffer = gail_text->texthelper->buffer;
+  return gtk_text_buffer_get_char_count (buffer);
+}
+
+static gint
+gail_html_box_text_get_caret_offset (AtkText *text)
+{
+  GailHtmlBoxText *gail_text;
+  GtkTextBuffer *buffer;
+  GtkTextMark *cursor_mark;
+  GtkTextIter cursor_itr;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_TEXT (text), 0);
+  gail_text = GAIL_HTML_BOX_TEXT (text);
+  g_return_val_if_fail (gail_text->texthelper, 0);
+  buffer = gail_text->texthelper->buffer;
+  cursor_mark = gtk_text_buffer_get_insert (buffer);
+  gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
+  return gtk_text_iter_get_offset (&cursor_itr);
+}
+
+static gboolean
+gail_html_box_text_set_caret_offset (AtkText *text,
+                                     gint    offset)
+{
+  GailHtmlBoxText *gail_text;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
+
+  g_return_val_if_fail (GAIL_IS_HTML_BOX_TEXT (text), FALSE);
+  gail_text = GAIL_HTML_BOX_TEXT (text);
+  g_return_val_if_fail (gail_text->texthelper, FALSE);
+  buffer = gail_text->texthelper->buffer;
+  gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, offset);
+  gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
+  return TRUE;
+}
+
+static gint
+gail_html_box_text_get_offset_at_point (AtkText      *text,
+                                        gint         x,
+                                        gint         y,
+                                        AtkCoordType coords)
+{
+  return -1;
+}
+
+static void
+gail_html_box_text_get_character_extents (AtkText      *text,
+                                          gint         offset,
+                                          gint         *x,
+                                          gint         *y,
+                                          gint         *width,
+                                          gint         *height,
+                                          AtkCoordType coords)
+{
+  return;
+}
+
+static AtkAttributeSet*
+gail_html_box_text_get_run_attributes (AtkText *text,
+                                       gint    offset,
+                                       gint    *start_offset,
+                                       gint    *end_offset)
+{
+  return NULL;
+}
+
+static AtkAttributeSet*
+gail_html_box_text_get_default_attributes (AtkText *text)
+{
+  return NULL;
+}
+
+static gint
+gail_html_box_text_get_n_selections (AtkText *text)
+{
+  return 0;
+}
+
+static gchar*
+gail_html_box_text_get_selection (AtkText *text,
+                                  gint    selection_num,
+                                  gint    *start_pos,
+                                  gint    *end_pos)
+{
+  return NULL;
+}
+
+static gboolean
+gail_html_box_text_add_selection (AtkText *text,
+                                gint    start_pos,
+                                gint    end_pos)
+{
+  return FALSE;
+}
+
+static gboolean
+gail_html_box_text_remove_selection (AtkText *text,
+                                 gint    selection_num)
+{
+  return FALSE;
+}
+
+static gboolean
+gail_html_box_text_set_selection (AtkText *text,
+                                  gint    selection_num,
+                                  gint    start_pos,
+                                  gint    end_pos)
+{
+  return FALSE;
+}
+
+static AtkAttributeSet*
+add_to_attr_set (AtkAttributeSet   *attrib_set,
+                 GtkTextAttributes *attrs,
+                 AtkTextAttribute  attr)
+{
+  gchar *value;
+
+  switch (attr)
+    {
+    case ATK_TEXT_ATTR_LEFT_MARGIN:
+      value = g_strdup_printf ("%i", attrs->left_margin);
+      break;
+    case ATK_TEXT_ATTR_RIGHT_MARGIN:
+      value = g_strdup_printf ("%i", attrs->right_margin);
+      break;
+    case ATK_TEXT_ATTR_INDENT:
+      value = g_strdup_printf ("%i", attrs->indent);
+      break;
+    case ATK_TEXT_ATTR_INVISIBLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->invisible));
+      break;
+    case ATK_TEXT_ATTR_EDITABLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->editable));
+      break;
+    case ATK_TEXT_ATTR_PIXELS_ABOVE_LINES:
+      value = g_strdup_printf ("%i", attrs->pixels_above_lines);
+      break;
+    case ATK_TEXT_ATTR_PIXELS_BELOW_LINES:
+      value = g_strdup_printf ("%i", attrs->pixels_below_lines);
+      break;
+    case ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP:
+      value = g_strdup_printf ("%i", attrs->pixels_inside_wrap);
+      break;
+    case ATK_TEXT_ATTR_BG_FULL_HEIGHT:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->bg_full_height));
+      break;
+    case ATK_TEXT_ATTR_RISE:
+      value = g_strdup_printf ("%i", attrs->appearance.rise);
+      break;
+    case ATK_TEXT_ATTR_UNDERLINE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.underline));
+      break;
+    case ATK_TEXT_ATTR_STRIKETHROUGH:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.strikethrough));
+      break;
+    case ATK_TEXT_ATTR_SIZE:
+      value = g_strdup_printf ("%i", 
+                              pango_font_description_get_size (attrs->font));
+      break;
+    case ATK_TEXT_ATTR_SCALE:
+      value = g_strdup_printf ("%g", attrs->font_scale);
+      break;
+    case ATK_TEXT_ATTR_WEIGHT:
+      value = g_strdup_printf ("%d", 
+                              pango_font_description_get_weight (attrs->font));
+      break;
+    case ATK_TEXT_ATTR_LANGUAGE:
+      value = g_strdup ((gchar *)(attrs->language));
+      break;
+    case ATK_TEXT_ATTR_FAMILY_NAME:
+      value = g_strdup (pango_font_description_get_family (attrs->font));
+      break;
+    case ATK_TEXT_ATTR_BG_COLOR:
+      value = g_strdup_printf ("%u,%u,%u",
+                               attrs->appearance.bg_color.red,
+                               attrs->appearance.bg_color.green,
+                               attrs->appearance.bg_color.blue);
+      break;
+    case ATK_TEXT_ATTR_FG_COLOR:
+      value = g_strdup_printf ("%u,%u,%u",
+                               attrs->appearance.fg_color.red,
+                               attrs->appearance.fg_color.green,
+                               attrs->appearance.fg_color.blue);
+      break;
+    case ATK_TEXT_ATTR_BG_STIPPLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.bg_stipple ? 1 : 0));
+      break;
+    case ATK_TEXT_ATTR_FG_STIPPLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.fg_stipple ? 1 : 0));
+      break;
+    case ATK_TEXT_ATTR_WRAP_MODE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->wrap_mode));
+      break;
+    case ATK_TEXT_ATTR_DIRECTION:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->direction));
+      break;
+    case ATK_TEXT_ATTR_JUSTIFICATION:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->justification));
+      break;
+    case ATK_TEXT_ATTR_STRETCH:
+      value = g_strdup (atk_text_attribute_get_value (attr, 
+                        pango_font_description_get_stretch (attrs->font)));
+      break;
+    case ATK_TEXT_ATTR_VARIANT:
+      value = g_strdup (atk_text_attribute_get_value (attr, 
+                        pango_font_description_get_variant (attrs->font)));
+      break;
+    case ATK_TEXT_ATTR_STYLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, 
+                        pango_font_description_get_style (attrs->font)));
+      break;
+    default:
+      value = NULL;
+      break;
+    }
+  return gail_text_helper_add_attribute (attrib_set, 
+                                         attr,
+                                         value);
+}
+
+static gchar*
+get_text_near_offset (AtkText          *text,
+                      GailOffsetType   function,
+                      AtkTextBoundary  boundary_type,
+                      gint             offset,
+                      gint             *start_offset,
+                      gint             *end_offset)
+{
+  return gail_text_helper_get_text (GAIL_HTML_BOX_TEXT (text)->texthelper, NULL,
+                                    function, boundary_type, offset, 
+                                    start_offset, end_offset);
+}
diff --git a/modules/other/gail/gailimage.c b/modules/other/gail/gailimage.c
new file mode 100644 (file)
index 0000000..e0bcc08
--- /dev/null
@@ -0,0 +1,430 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailimage.h"
+#include "gailintl.h"
+
+static void      gail_image_class_init         (GailImageClass *klass);
+static void      gail_image_object_init        (GailImage      *image);
+static G_CONST_RETURN gchar* gail_image_get_name  (AtkObject     *accessible);
+
+
+static void      atk_image_interface_init      (AtkImageIface  *iface);
+
+static G_CONST_RETURN gchar *
+                 gail_image_get_image_description (AtkImage     *image);
+static void     gail_image_get_image_position    (AtkImage     *image,
+                                                   gint         *x,
+                                                   gint         *y,
+                                                   AtkCoordType coord_type);
+static void      gail_image_get_image_size     (AtkImage        *image,
+                                                gint            *width,
+                                                gint            *height);
+static gboolean  gail_image_set_image_description (AtkImage     *image,
+                                                const gchar     *description);
+static void      gail_image_finalize           (GObject         *object);
+                                                         
+typedef struct _GailImageItem GailImageItem;
+
+struct _GailImageItem
+{
+  GQuark id;
+  gchar *name;
+  gchar *stock_id;
+};
+
+static GailImageItem stock_items [] =
+{
+  { 0, N_("dialog authentication"), "gtk-dialog-authentication"},
+  { 0, N_("dialog information"), "gtk-dialog-info"},
+  { 0, N_("dialog warning"), "gtk-dialog-warning"},
+  { 0, N_("dialog error"), "gtk-dialog-error"},
+  { 0, N_("dialog question"), "gtk-dialog-question"},
+  { 0, N_("drag and drop"), "gtk-dnd"},
+  { 0, N_("multiple drag and drop"), "gtk-dnd-multiple"},
+  { 0, N_("add"), "gtk-add"},
+  { 0, N_("apply"), "gtk-apply"},
+  { 0, N_("bold"), "gtk-bold"},
+  { 0, N_("cancel"), "gtk_cancel"},
+  { 0, N_("cdrom"), "gtk-cdrom"},
+  { 0, N_("clear"), "gtk-clear"},
+  { 0, N_("close"), "gtk-close"},
+  { 0, N_("color picker"), "gtk-color-picker"},
+  { 0, N_("convert"), "gtk-convert"},
+  { 0, N_("copy"), "gtk-copy"},
+  { 0, N_("cut"), "gtk-cut"},
+  { 0, N_("delete"), "gtk-delete"},
+  { 0, N_("execute"), "gtk-execute"},
+  { 0, N_("find"), "gtk-find"},
+  { 0, N_("find and replace"), "gtk-find-and-replace"},
+  { 0, N_("floppy"), "gtk-floppy"},
+  { 0, N_("go to bottom"), "gtk-goto-bottom"},
+  { 0, N_("go to first"), "gtk-goto-first"},
+  { 0, N_("go to last"), "gtk-goto-last"},
+  { 0, N_("go to top"), "gtk-goto-top"},
+  { 0, N_("go back"), "gtk-go-back"},
+  { 0, N_("go down"), "gtk-go-down"},
+  { 0, N_("go forward"), "gtk-go-forward"},
+  { 0, N_("go up"), "gtk-go-up"},
+  { 0, N_("help"), "gtk-help"},
+  { 0, N_("home"), "gtk-home"},
+  { 0, N_("index"), "gtk-index"},
+  { 0, N_("italic"), "gtk-italic"},
+  { 0, N_("jump to"), "gtk-jump-to"},
+  { 0, N_("justify center"), "gtk-justify-center"},
+  { 0, N_("justify fill"), "gtk-justify-fill"},
+  { 0, N_("justify left"), "gtk-justify-left"},
+  { 0, N_("justify right"), "gtk-justify-right"},
+  { 0, N_("missing image"), "gtk-missing-image"},
+  { 0, N_("new"), "gtk-new"},
+  { 0, N_("no"), "gtk-no"},
+  { 0, N_("ok"), "gtk-ok"},
+  { 0, N_("open"), "gtk-open"},
+  { 0, N_("paste"), "gtk-paste"},
+  { 0, N_("preferences"), "gtk-preferences"},
+  { 0, N_("print"), "gtk-print"},
+  { 0, N_("print preview"), "gtk-print-preview"},
+  { 0, N_("properties"), "gtk-properties"},
+  { 0, N_("quit"), "gtk-quit"},
+  { 0, N_("redo"), "gtk-redo"},
+  { 0, N_("refresh"), "gtk-refresh"},
+  { 0, N_("remove"), "gtk-remove"},
+  { 0, N_("revert to saved"), "gtk-revert-to-saved"},
+  { 0, N_("save"), "gtk-save"},
+  { 0, N_("save as"), "gtk-save-as"},
+  { 0, N_("select color"), "gtk-select-color"},
+  { 0, N_("select font"), "gtk-select-font"},
+  { 0, N_("sort ascending"), "gtk-sort-ascending"},
+  { 0, N_("sort descending"), "gtk-sort-descending"},
+  { 0, N_("spell check"), "gtk-spell-check"},
+  { 0, N_("stop"), "gtk-stop"},
+  { 0, N_("strikethrough"), "gtk-strikethrough"},
+  { 0, N_("undelete"), "gtk-undelete"},
+  { 0, N_("underline"), "gtk-underline"},
+  { 0, N_("yes"), "gtk-yes"},
+  { 0, N_("zoom 100 percent"), "gtk-zoom-100"},
+  { 0, N_("zoom fit"), "gtk-zoom-fit"},
+  { 0, N_("zoom in"), "gtk-zoom-in"},
+  { 0, N_("zoom out"), "gtk-zoom-out"},
+
+  { 0, N_("timer"), "gnome-stock-timer"},
+  { 0, N_("timer stop"), "gnome-stock-timer-stop"},
+  { 0, N_("trash"), "gnome-stock-trash"},
+  { 0, N_("trash full"), "gnome-stock-trash-full"},
+  { 0, N_("scores"), "gnome-stock-scores"},
+  { 0, N_("about"), "gnome-stock-about"},
+  { 0, N_("blank"), "gnome-stock-blank"},
+  { 0, N_("volume"), "gnome-stock-volume"},
+  { 0, N_("midi"), "gnome-stock-midi"},
+  { 0, N_("microphone"), "gnome-stock-mic"},
+  { 0, N_("line in"), "gnome-stock-line-in"},
+  { 0, N_("mail"), "gnome-stock-mail"},
+  { 0, N_("mail receive"), "gnome-stock-mail-rcv"},
+  { 0, N_("mail send"), "gnome-stock-mail-snd"},
+  { 0, N_("mail reply"), "gnome-stock-mail-rpl"},
+  { 0, N_("mail forward"), "gnome-stock-mail-fwd"},
+  { 0, N_("mail new"), "gnome-stock-mail-new"},
+  { 0, N_("attach"), "gnome-stock-attach"},
+  { 0, N_("book red"), "gnome-stock-book-red"},
+  { 0, N_("book green"), "gnome-stock-book-green"},
+  { 0, N_("book blue"), "gnome-stock-book-blue"},
+  { 0, N_("book yellow"), "gnome-stock-book-yellow"},
+  { 0, N_("book open"), "gnome-stock-book-open"},
+  { 0, N_("multiple file"), "gnome-stock-multiple-file"},
+  { 0, N_("not"), "gnome-stock-not"},
+  { 0, N_("table borders"), "gnome-stock-table-borders"},
+  { 0, N_("table fill"), "gnome-stock-table-fill"},
+  { 0, N_("text indent"), "gnome-stock-text-indent"},
+  { 0, N_("text unindent"), "gnome-stock-text-unindent"},
+  { 0, N_("text bulleted list"), "gnome-stock-text-bulleted-list"},
+  { 0, N_("text numbered list"), "gnome-stock-text-numbered-list"},
+  { 0, N_("authentication"), "gnome-stock-authentication"}
+};
+
+static gpointer parent_class = NULL;
+
+GType
+gail_image_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailImageClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_image_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailImage), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) gail_image_object_init, /* instance init */
+      NULL /* value table */
+    };
+
+    static const GInterfaceInfo atk_image_info =
+    {
+        (GInterfaceInitFunc) atk_image_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+    };
+
+    type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                   "GailImage", &tinfo, 0);
+
+    g_type_add_interface_static (type, ATK_TYPE_IMAGE,
+                                 &atk_image_info);
+  }
+
+  return type;
+}
+
+static void
+gail_image_class_init (GailImageClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gail_image_finalize;
+  class->get_name = gail_image_get_name;
+}
+
+static void
+gail_image_object_init (GailImage *image)
+{
+  image->image_description = NULL;
+}
+
+AtkObject* 
+gail_image_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_IMAGE (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_IMAGE, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_ICON;
+
+  return accessible;
+}
+
+static void
+init_strings (void)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS (stock_items); i++)
+    stock_items[i].id = g_quark_from_static_string (stock_items[i].stock_id);
+}
+
+static G_CONST_RETURN gchar*
+get_localized_name (const gchar *str)
+{
+  GQuark str_q;
+  gint i;
+
+#if 0
+  static gboolean gettext_initialized = FALSE;
+
+  if (!gettext_initialized)
+    {
+      init_strings ();
+      gettext_initialized = TRUE;
+#ifdef ENABLE_NLS
+      bindtextdomain (GETTEXT_PACKAGE, GAIL_LOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+      bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+#endif
+    }
+#endif
+
+  str_q = g_quark_try_string (str);
+  for (i = 0; i <  G_N_ELEMENTS (stock_items); i++)
+    {
+      if (str_q == stock_items[i].id)
+         return dgettext (GETTEXT_PACKAGE, stock_items[i].name);
+  }
+
+  return str;
+}
+
+static G_CONST_RETURN gchar*
+gail_image_get_name (AtkObject *accessible)
+{
+  G_CONST_RETURN gchar *name;
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (accessible); 
+  if (name)
+    return name;
+  else
+    {
+      GtkWidget* widget = GTK_ACCESSIBLE (accessible)->widget;
+      GtkImage *image;
+
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+
+      g_return_val_if_fail (GTK_IS_IMAGE (widget), NULL);
+      image = GTK_IMAGE (widget);
+
+      if (image->storage_type == GTK_IMAGE_STOCK &&
+          image->data.stock.stock_id)
+        return get_localized_name (image->data.stock.stock_id); 
+      else return NULL;
+    }
+}
+
+static void
+atk_image_interface_init (AtkImageIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_image_description = gail_image_get_image_description;
+  iface->get_image_position = gail_image_get_image_position;
+  iface->get_image_size = gail_image_get_image_size;
+  iface->set_image_description = gail_image_set_image_description;
+}
+
+static G_CONST_RETURN gchar * 
+gail_image_get_image_description (AtkImage     *image)
+{
+  GailImage* aimage = GAIL_IMAGE (image);
+
+  return aimage->image_description;
+}
+
+static void
+gail_image_get_image_position (AtkImage     *image,
+                               gint         *x,
+                               gint         *y,
+                               AtkCoordType coord_type)
+{
+  atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
+}
+
+static void
+gail_image_get_image_size (AtkImage *image, 
+                           gint     *width,
+                           gint     *height)
+{
+  GtkWidget* widget;
+  GtkImage *gtk_image;
+  GtkImageType image_type;
+
+  widget = GTK_ACCESSIBLE (image)->widget;
+  if (widget == 0)
+  {
+    /* State is defunct */
+    *height = -1;
+    *width = -1;
+    return;
+  }
+
+  gtk_image = GTK_IMAGE(widget);
+
+  image_type = gtk_image_get_storage_type(gtk_image);
+  switch(image_type) {
+    case GTK_IMAGE_PIXMAP:
+    {  
+      GdkPixmap *pixmap;
+      gtk_image_get_pixmap(gtk_image, &pixmap, NULL);
+      gdk_window_get_size (pixmap, width, height);
+      break;
+    }
+    case GTK_IMAGE_PIXBUF:
+    {
+      GdkPixbuf *pixbuf;
+      pixbuf = gtk_image_get_pixbuf(gtk_image);
+      *height = gdk_pixbuf_get_height(pixbuf);
+      *width = gdk_pixbuf_get_width(pixbuf);
+      break;
+    }
+    case GTK_IMAGE_IMAGE:
+    {
+      GdkImage *gdk_image;
+      gtk_image_get_image(gtk_image, &gdk_image, NULL);
+      *height = gdk_image->height;
+      *width = gdk_image->width;
+      break;
+    }
+    case GTK_IMAGE_STOCK:
+    {
+      GtkIconSize size;
+      gtk_image_get_stock(gtk_image, NULL, &size);
+      gtk_icon_size_lookup(size, width, height);
+      break;
+    }
+    case GTK_IMAGE_ICON_SET:
+    {
+      GtkIconSize size;
+      gtk_image_get_icon_set(gtk_image, NULL, &size);
+      gtk_icon_size_lookup(size, width, height);
+      break;
+    }
+    case GTK_IMAGE_ANIMATION:
+    {
+      GdkPixbufAnimation *animation;
+      animation = gtk_image_get_animation(gtk_image);
+      *height = gdk_pixbuf_animation_get_height(animation);
+      *width = gdk_pixbuf_animation_get_width(animation);
+      break;
+    }
+    default:
+    {
+      *height = -1;
+      *width = -1;
+      break;
+    }
+  }
+}
+
+static gboolean
+gail_image_set_image_description (AtkImage     *image,
+                                  const gchar  *description)
+{
+  GailImage* aimage = GAIL_IMAGE (image);
+
+  g_free (aimage->image_description);
+  aimage->image_description = g_strdup (description);
+  return TRUE;
+}
+
+static void
+gail_image_finalize (GObject      *object)
+{
+  GailImage *aimage = GAIL_IMAGE (object);
+
+  g_free (aimage->image_description);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
diff --git a/modules/other/gail/gailimage.h b/modules/other/gail/gailimage.h
new file mode 100644 (file)
index 0000000..a30ff20
--- /dev/null
@@ -0,0 +1,61 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_IMAGE_H__
+#define __GAIL_IMAGE_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_IMAGE                      (gail_image_get_type ())
+#define GAIL_IMAGE(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_IMAGE, GailImage))
+#define GAIL_IMAGE_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_IMAGE, GailImageClass))
+#define GAIL_IS_IMAGE(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_IMAGE))
+#define GAIL_IS_IMAGE_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_IMAGE))
+#define GAIL_IMAGE_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_IMAGE, GailImageClass))
+
+typedef struct _GailImage              GailImage;
+typedef struct _GailImageClass         GailImageClass;
+
+struct _GailImage
+{
+  GailWidget parent;
+
+  gchar*     image_description;
+};
+
+GType gail_image_get_type (void);
+
+struct _GailImageClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_image_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_IMAGE_H__ */
diff --git a/modules/other/gail/gailimagecell.c b/modules/other/gail/gailimagecell.c
new file mode 100644 (file)
index 0000000..28f3da7
--- /dev/null
@@ -0,0 +1,207 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailimagecell.h"
+
+static void      gail_image_cell_class_init          (GailImageCellClass *klass);
+static void      gail_image_cell_object_init         (GailImageCell      *image_cell);
+
+static void      gail_image_cell_finalize            (GObject            *object);
+
+/* AtkImage */
+static void      atk_image_interface_init              (AtkImageIface  *iface);
+static G_CONST_RETURN gchar *
+                 gail_image_cell_get_image_description (AtkImage       *image);
+static gboolean  gail_image_cell_set_image_description (AtkImage       *image,
+                                                        const gchar    *description);
+static void      gail_image_cell_get_image_position    (AtkImage       *image,
+                                                        gint           *x,
+                                                        gint           *y,
+                                                        AtkCoordType   coord_type);
+static void      gail_image_cell_get_image_size        (AtkImage       *image,
+                                                        gint           *width,
+                                                        gint           *height);
+
+/* Misc */
+
+static gboolean  gail_image_cell_update_cache          (GailRendererCell *cell,
+                                                        gboolean         emit_change_signal);
+
+gchar *gail_image_cell_property_list[] = {
+  "pixbuf",
+  NULL
+};
+
+static gpointer parent_class = NULL;
+
+GType
+gail_image_cell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailImageCellClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_image_cell_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailImageCell), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_image_cell_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_image_info =
+      {
+        (GInterfaceInitFunc) atk_image_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_RENDERER_CELL,
+                                     "GailImageCell", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_IMAGE,
+                                   &atk_image_info);
+
+    }
+  return type;
+}
+
+static void 
+gail_image_cell_class_init (GailImageCellClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GailRendererCellClass *renderer_cell_class = GAIL_RENDERER_CELL_CLASS(klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gail_image_cell_finalize;
+
+  renderer_cell_class->update_cache = gail_image_cell_update_cache;
+  renderer_cell_class->property_list = gail_image_cell_property_list;
+}
+
+AtkObject* 
+gail_image_cell_new (void)
+{
+  GObject *object;
+  AtkObject *atk_object;
+  GailRendererCell *cell;
+
+  object = g_object_new (GAIL_TYPE_IMAGE_CELL, NULL);
+
+  g_return_val_if_fail (object != NULL, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object->role = ATK_ROLE_TABLE_CELL;
+
+  cell = GAIL_RENDERER_CELL(object);
+
+  cell->renderer = gtk_cell_renderer_pixbuf_new ();
+  g_object_ref (cell->renderer);
+  gtk_object_sink (GTK_OBJECT (cell->renderer));
+  return atk_object;
+}
+
+static void
+gail_image_cell_object_init (GailImageCell *image_cell)
+{
+  image_cell->image_description = NULL;
+}
+
+
+static void
+gail_image_cell_finalize (GObject *object)
+{
+  GailImageCell *image_cell = GAIL_IMAGE_CELL (object);
+
+  g_free (image_cell->image_description);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gail_image_cell_update_cache (GailRendererCell *cell, 
+                              gboolean         emit_change_signal)
+{
+  return FALSE;
+}
+
+static void
+atk_image_interface_init (AtkImageIface  *iface)
+{
+  iface->get_image_description = gail_image_cell_get_image_description;
+  iface->set_image_description = gail_image_cell_set_image_description;
+  iface->get_image_position = gail_image_cell_get_image_position;
+  iface->get_image_size = gail_image_cell_get_image_size;
+}
+
+static G_CONST_RETURN gchar *
+gail_image_cell_get_image_description (AtkImage     *image)
+{
+  GailImageCell *image_cell;
+
+  image_cell = GAIL_IMAGE_CELL (image);
+  return image_cell->image_description;
+}
+
+static gboolean
+gail_image_cell_set_image_description (AtkImage     *image,
+                                       const gchar  *description)
+{
+  GailImageCell *image_cell;
+
+  image_cell = GAIL_IMAGE_CELL (image);
+  g_free (image_cell->image_description);
+  image_cell->image_description = g_strdup (description);
+  if (image_cell->image_description)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+static void
+gail_image_cell_get_image_position (AtkImage     *image,
+                                    gint         *x,
+                                    gint         *y,
+                                    AtkCoordType coord_type)
+{
+  atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
+}
+
+static void
+gail_image_cell_get_image_size (AtkImage *image,
+                                gint     *width,
+                                gint     *height)
+{
+  GailImageCell *cell = GAIL_IMAGE_CELL (image);
+  GtkCellRenderer *cell_renderer;
+  GdkPixbuf *pixbuf;
+
+  cell_renderer  = GAIL_RENDERER_CELL (cell)->renderer;
+  pixbuf = GTK_CELL_RENDERER_PIXBUF (cell_renderer)->pixbuf;
+
+  *width = gdk_pixbuf_get_width (pixbuf);
+  *height = gdk_pixbuf_get_height (pixbuf);
+}
diff --git a/modules/other/gail/gailimagecell.h b/modules/other/gail/gailimagecell.h
new file mode 100644 (file)
index 0000000..7dfd65c
--- /dev/null
@@ -0,0 +1,62 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_IMAGE_CELL_H__
+#define __GAIL_IMAGE_CELL_H__
+
+#include <atk/atk.h>
+#include <gail/gailrenderercell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_IMAGE_CELL            (gail_image_cell_get_type ())
+#define GAIL_IMAGE_CELL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_IMAGE_CELL, GailImageCell))
+#define GAIL_IMAGE_CELL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_IMAGE_CELL, GailImageCellClass))
+#define GAIL_IS_IMAGE_CELL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_IMAGE_CELL))
+#define GAIL_IS_IMAGE_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_IMAGE_CELL))78
+#define GAIL_IMAGE_CELL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_IMAGE_CELL, GailImageCellClass))
+  
+typedef struct _GailImageCell                  GailImageCell;
+typedef struct _GailImageCellClass             GailImageCellClass;
+
+struct _GailImageCell
+{
+  GailRendererCell parent;
+
+  gchar            *image_description;
+  gint             x, y;
+};
+
+GType gail_image_cell_get_type (void);
+
+struct _GailImageCellClass
+{
+  GailRendererCellClass parent_class;
+};
+
+AtkObject *gail_image_cell_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TREE_VIEW_IMAGE_CELL_H__ */
diff --git a/modules/other/gail/gailimagecellfactory.c b/modules/other/gail/gailimagecellfactory.c
new file mode 100644 (file)
index 0000000..77c4b92
--- /dev/null
@@ -0,0 +1,79 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtkcellrendererpixbuf.h>
+#include "gailimagecellfactory.h"
+#include "gailimagecell.h"
+
+static void gail_image_cell_factory_class_init (GailImageCellFactoryClass        *klass);
+
+static AtkObject* gail_image_cell_factory_create_accessible (
+                                GObject                              *obj);
+
+static GType gail_image_cell_factory_get_accessible_type (void);
+
+GType
+gail_image_cell_factory_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) 
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailImageCellFactoryClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_image_cell_factory_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailImageCellFactory), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+    type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
+                           "GailImageCellFactory" , &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void 
+gail_image_cell_factory_class_init (GailImageCellFactoryClass *klass)
+{
+  AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+  class->create_accessible = gail_image_cell_factory_create_accessible;
+  class->get_accessible_type = gail_image_cell_factory_get_accessible_type;
+}
+
+static AtkObject* 
+gail_image_cell_factory_create_accessible (GObject     *obj)
+{
+  g_return_val_if_fail (GTK_IS_CELL_RENDERER_PIXBUF (obj), NULL);
+
+  return gail_image_cell_new ();
+}
+
+static GType
+gail_image_cell_factory_get_accessible_type (void)
+{
+  return GAIL_TYPE_IMAGE_CELL;
+}
diff --git a/modules/other/gail/gailimagecellfactory.h b/modules/other/gail/gailimagecellfactory.h
new file mode 100644 (file)
index 0000000..adf3fd2
--- /dev/null
@@ -0,0 +1,56 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_IMAGE_CELL_FACTORY_H__
+#define __GAIL_IMAGE_CELL_FACTORY_H__
+
+#include <atk/atkobjectfactory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_IMAGE_CELL_FACTORY                 (gail_image_cell_factory_get_type ())
+#define GAIL_IMAGE_CELL_FACTORY(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_IMAGE_CELL_FACTORY, GailImageCellFactory))
+#define GAIL_IMAGE_CELL_FACTORY_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), AGTK_TYPE_IMAGE_CELL_FACTORY, GailImageCellFactoryClass))
+#define GAIL_IS_IMAGE_CELL_FACTORY(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_IMAGE_CELL_FACTORY))
+#define GAIL_IS_IMAGE_CELL_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_IMAGE_CELL_FACTORY))
+#define GAIL_IMAGE_CELL_FACTORY_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_IMAGE_CELL_FACTORY, GailImageCellFactoryClass))
+
+typedef struct _GailImageCellFactory             GailImageCellFactory;
+typedef struct _GailImageCellFactoryClass        GailImageCellFactoryClass;
+
+struct _GailImageCellFactory
+{
+  AtkObjectFactory parent;
+};
+
+struct _GailImageCellFactoryClass
+{
+  AtkObjectFactoryClass parent_class;
+};
+
+GType gail_image_cell_factory_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_IMAGE_CELL_FACTORY_H__ */
diff --git a/modules/other/gail/gailintl.h b/modules/other/gail/gailintl.h
new file mode 100644 (file)
index 0000000..555de79
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __GAILINTL_H__
+#define __GAILINTL_H__
+
+#include "config.h"
+
+#ifdef ENABLE_NLS
+#include<libintl.h>
+#define _(String) dgettext(GETTEXT_PACKAGE,String)
+#ifdef gettext_noop
+#define N_(String) gettext_noop(String)
+#else
+#define N_(String) (String)
+#endif
+#else /* NLS is disabled */
+#define _(String) (String)
+#define N_(String) (String)
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,String) (String)
+#define dcgettext(Domain,String,Type) (String)
+#define bindtextdomain(Domain,Directory) (Domain) 
+#endif
+
+#endif
diff --git a/modules/other/gail/gailitem.c b/modules/other/gail/gailitem.c
new file mode 100644 (file)
index 0000000..dffc784
--- /dev/null
@@ -0,0 +1,760 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailitem.h"
+#include <libgail-util/gailmisc.h>
+
+static void                  gail_item_class_init      (GailItemClass *klass);
+static G_CONST_RETURN gchar* gail_item_get_name        (AtkObject     *obj);
+static gint                  gail_item_get_n_children  (AtkObject     *obj);
+static AtkObject*            gail_item_ref_child       (AtkObject     *obj,
+                                                        gint          i);
+static void                  gail_item_real_initialize (AtkObject     *obj,
+                                                        gpointer      data);
+static void                  gail_item_label_map_gtk   (GtkWidget     *widget,
+                                                        gpointer      data);
+static void                  gail_item_finalize        (GObject       *object);
+static void                  gail_item_init_textutil   (GailItem      *item,
+                                                        GtkWidget     *label);
+static void                  gail_item_notify_label_gtk(GObject       *obj,
+                                                        GParamSpec    *pspec,
+                                                        gpointer      data);
+
+/* atktext.h */ 
+static void      atk_text_interface_init          (AtkTextIface        *iface);
+
+static gchar*    gail_item_get_text               (AtkText           *text,
+                                                    gint             start_pos,
+                                                   gint              end_pos);
+static gunichar          gail_item_get_character_at_offset(AtkText           *text,
+                                                   gint              offset);
+static gchar*     gail_item_get_text_before_offset (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_item_get_text_at_offset     (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_item_get_text_after_offset  (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gint      gail_item_get_character_count    (AtkText           *text);
+static void       gail_item_get_character_extents  (AtkText          *text,
+                                                   gint              offset,
+                                                   gint              *x,
+                                                   gint              *y,
+                                                   gint              *width,
+                                                   gint              *height,
+                                                   AtkCoordType      coords);
+static gint      gail_item_get_offset_at_point     (AtkText           *text,
+                                                    gint              x,
+                                                    gint              y,
+                                                   AtkCoordType      coords);
+static AtkAttributeSet* gail_item_get_run_attributes 
+                                                   (AtkText           *text,
+                                                   gint              offset,
+                                                    gint             *start_offset,
+                                                   gint              *end_offset);
+static AtkAttributeSet* gail_item_get_default_attributes
+                                                   (AtkText           *text);
+static GtkWidget*            get_label_from_container   (GtkWidget    *container);
+
+
+
+static GailContainerClass* parent_class = NULL;
+
+GType
+gail_item_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailItemClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_item_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailItem), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailItem", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+    }
+
+  return type;
+}
+
+static void
+gail_item_class_init (GailItemClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GailContainerClass *container_class;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  container_class = (GailContainerClass *)klass;
+
+  gobject_class->finalize = gail_item_finalize;
+
+  class->get_name = gail_item_get_name;
+  class->get_n_children = gail_item_get_n_children;
+  class->ref_child = gail_item_ref_child;
+  class->initialize = gail_item_real_initialize;
+  /*
+   * As we report the item as having no children we are not interested
+   * in add and remove signals
+   */
+  container_class->add_gtk = NULL;
+  container_class->remove_gtk = NULL;
+}
+
+AtkObject*
+gail_item_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_ITEM (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_ITEM, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_item_real_initialize (AtkObject *obj,
+                           gpointer    data)
+{
+  GailItem *item = GAIL_ITEM (obj);
+  GtkWidget  *label;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  item->textutil = NULL;
+  item->text = NULL;
+
+  label = get_label_from_container (GTK_WIDGET (data));
+  if (GTK_IS_LABEL (label))
+    {
+      if (GTK_WIDGET_MAPPED (label))
+        gail_item_init_textutil (item, label);
+      else
+        g_signal_connect (label,
+                          "map",
+                          G_CALLBACK (gail_item_label_map_gtk),
+                          item);
+    }
+
+  obj->role = ATK_ROLE_LIST_ITEM;
+}
+
+static void
+gail_item_label_map_gtk (GtkWidget *widget,
+                         gpointer data)
+{
+  GailItem *item;
+
+  item = GAIL_ITEM (data);
+  gail_item_init_textutil (item, widget);
+}
+
+static void
+gail_item_init_textutil (GailItem  *item,
+                         GtkWidget *label)
+{
+  const gchar *label_text;
+
+  if (item->textutil == NULL)
+    {
+      item->textutil = gail_text_util_new ();
+      g_signal_connect (label,
+                        "notify",
+                        (GCallback) gail_item_notify_label_gtk,
+                        item);     
+    }
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  gail_text_util_text_setup (item->textutil, label_text);
+}
+
+static void
+gail_item_finalize (GObject *object)
+{
+  GailItem *item = GAIL_ITEM (object);
+
+  if (item->textutil)
+    {
+      g_object_unref (item->textutil);
+    }
+  if (item->text)
+    {
+      g_free (item->text);
+      item->text = NULL;
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static G_CONST_RETURN gchar*
+gail_item_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar* name;
+
+  g_return_val_if_fail (GAIL_IS_ITEM (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (obj);
+  if (name == NULL)
+    {
+      /*
+       * Get the label child
+       */
+      GtkWidget *widget;
+      GtkWidget *label;
+
+      widget = GTK_ACCESSIBLE (obj)->widget;
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+
+      label = get_label_from_container (widget);
+      if (GTK_IS_LABEL (label))
+       return gtk_label_get_text (GTK_LABEL(label));
+      /*
+       * If we have a menu item in a menu attached to a GtkOptionMenu
+       * the label of the selected item is detached from the menu item
+       */
+      else if (GTK_IS_MENU_ITEM (widget))
+        {
+          GtkWidget *parent;
+          GtkWidget *attach;
+          GList *list;
+          AtkObject *parent_obj;
+          gint index;
+
+          parent = gtk_widget_get_parent (widget);
+          if (GTK_IS_MENU (parent))
+            {
+              attach = gtk_menu_get_attach_widget (GTK_MENU (parent)); 
+
+              if (GTK_IS_OPTION_MENU (attach))
+                {
+                  label = get_label_from_container (attach);
+                  if (GTK_IS_LABEL (label))
+                   return gtk_label_get_text (GTK_LABEL(label));
+                }
+              list = gtk_container_get_children (GTK_CONTAINER (parent));
+              index = g_list_index (list, widget);
+
+              if (index < 0 || index > g_list_length (list))
+                {
+                  g_list_free (list);
+                  return NULL;
+                }
+              g_list_free (list);
+
+              parent_obj = atk_object_get_parent (gtk_widget_get_accessible (parent));
+              if (GTK_IS_ACCESSIBLE (parent_obj))
+                {
+                  parent = GTK_ACCESSIBLE (parent_obj)->widget;
+                  if (GTK_IS_COMBO_BOX (parent))
+                    {
+                      GtkTreeModel *model;
+                      GtkTreeIter iter;
+                      GailItem *item;
+                      gint n_columns, i;
+
+                      model = gtk_combo_box_get_model (GTK_COMBO_BOX (parent));                       
+                      item = GAIL_ITEM (obj);
+                      if (gtk_tree_model_iter_nth_child (model, &iter, NULL, index))
+                        {
+                          n_columns = gtk_tree_model_get_n_columns (model);
+                          for (i = 0; i < n_columns; i++)
+                            {
+                              GValue value = { 0, };
+
+                               gtk_tree_model_get_value (model, &iter, i, &value);
+                               if (G_VALUE_HOLDS_STRING (&value))
+                                 {
+                                  g_free (item->text);
+                                   item->text =  (gchar *) g_value_dup_string (&value);
+                                   g_value_unset (&value);
+                                   break;
+                                 }
+                            }
+                        }
+                      name = item->text;
+                    }
+                }
+            }
+        }
+    }
+  return name;
+}
+
+/*
+ * We report that this object has no children
+ */
+
+static gint
+gail_item_get_n_children (AtkObject* obj)
+{
+  return 0;
+}
+
+static AtkObject*
+gail_item_ref_child (AtkObject *obj,
+                     gint      i)
+{
+  return NULL;
+}
+
+static void
+gail_item_notify_label_gtk (GObject           *obj,
+                            GParamSpec        *pspec,
+                            gpointer           data)
+{
+  AtkObject* atk_obj = ATK_OBJECT (data);
+  GtkLabel *label;
+  GailItem *gail_item;
+
+  if (strcmp (pspec->name, "label") == 0)
+    {
+      const gchar* label_text;
+
+      label = GTK_LABEL (obj);
+
+      label_text = gtk_label_get_text (label);
+
+      gail_item = GAIL_ITEM (atk_obj);
+      gail_text_util_text_setup (gail_item->textutil, label_text);
+
+      if (atk_obj->name == NULL)
+      {
+        /*
+         * The label has changed so notify a change in accessible-name
+         */
+        g_object_notify (G_OBJECT (atk_obj), "accessible-name");
+      }
+      /*
+       * The label is the only property which can be changed
+       */
+      g_signal_emit_by_name (atk_obj, "visible_data_changed");
+    }
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->get_text = gail_item_get_text;
+  iface->get_character_at_offset = gail_item_get_character_at_offset;
+  iface->get_text_before_offset = gail_item_get_text_before_offset;
+  iface->get_text_at_offset = gail_item_get_text_at_offset;
+  iface->get_text_after_offset = gail_item_get_text_after_offset;
+  iface->get_character_count = gail_item_get_character_count;
+  iface->get_character_extents = gail_item_get_character_extents;
+  iface->get_offset_at_point = gail_item_get_offset_at_point;
+  iface->get_run_attributes = gail_item_get_run_attributes;
+  iface->get_default_attributes = gail_item_get_default_attributes;
+}
+
+static gchar*
+gail_item_get_text (AtkText *text,
+                    gint    start_pos,
+                    gint    end_pos)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailItem *item;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL (label))
+    return NULL;
+
+  item = GAIL_ITEM (text);
+  if (!item->textutil) 
+    gail_item_init_textutil (item, label);
+
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+
+  if (label_text == NULL)
+    return NULL;
+  else
+  {
+    return gail_text_util_get_substring (item->textutil, 
+                                         start_pos, end_pos);
+  }
+}
+
+static gchar*
+gail_item_get_text_before_offset (AtkText         *text,
+                                 gint            offset,
+                                 AtkTextBoundary boundary_type,
+                                 gint            *start_offset,
+                                 gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailItem *item;
+  
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  item = GAIL_ITEM (text);
+  if (!item->textutil)
+    gail_item_init_textutil (item, label);
+
+  return gail_text_util_get_text (item->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset); 
+}
+
+static gchar*
+gail_item_get_text_at_offset (AtkText         *text,
+                             gint            offset,
+                             AtkTextBoundary boundary_type,
+                             gint            *start_offset,
+                             gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailItem *item;
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  item = GAIL_ITEM (text);
+  if (!item->textutil)
+    gail_item_init_textutil (item, label);
+
+  return gail_text_util_get_text (item->textutil,
+                              gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET, 
+                              boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_item_get_text_after_offset (AtkText         *text,
+                                gint            offset,
+                                AtkTextBoundary boundary_type,
+                                gint            *start_offset,
+                                gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailItem *item;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return NULL;
+  }
+  
+  /* Get label */
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  item = GAIL_ITEM (text);
+  if (!item->textutil)
+    gail_item_init_textutil (item, label);
+
+  return gail_text_util_get_text (item->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gint
+gail_item_get_character_count (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return 0;
+
+  return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
+}
+
+static void
+gail_item_get_character_extents (AtkText      *text,
+                                gint         offset,
+                                gint         *x,
+                                gint         *y,
+                                 gint        *width,
+                                 gint        *height,
+                                AtkCoordType coords)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  PangoRectangle char_rect;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+  widget = GTK_ACCESSIBLE (text)->widget;
+
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
+  pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
+  
+  gail_misc_get_extents_from_pango_rectangle (label, &char_rect, 
+                    x_layout, y_layout, x, y, width, height, coords);
+} 
+
+static gint 
+gail_item_get_offset_at_point (AtkText      *text,
+                               gint         x,
+                               gint         y,
+                              AtkCoordType coords)
+{ 
+  GtkWidget *widget;
+  GtkWidget *label;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return -1;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  
+  index = gail_misc_get_index_at_point_in_layout (label, 
+                                              gtk_label_get_layout (GTK_LABEL (label)), 
+                                              x_layout, y_layout, x, y, coords);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  if (index == -1)
+    {
+      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+        return g_utf8_strlen (label_text, -1);
+
+      return index;  
+    }
+  else
+    return g_utf8_pointer_to_offset (label_text, label_text + index);  
+}
+
+static AtkAttributeSet*
+gail_item_get_run_attributes (AtkText *text,
+                              gint    offset,
+                              gint    *start_offset,
+                             gint    *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+  GtkJustification justify;
+  GtkTextDirection dir;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  
+  /* Get values set for entire label, if any */
+  justify = gtk_label_get_justify (GTK_LABEL (label));
+  if (justify != GTK_JUSTIFY_CENTER)
+    {
+      at_set = gail_misc_add_attribute (at_set, 
+                                        ATK_TEXT_ATTR_JUSTIFICATION,
+     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
+    }
+  dir = gtk_widget_get_direction (label);
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                gtk_label_get_layout (GTK_LABEL (label)),
+                                                (gchar *) gtk_label_get_text (GTK_LABEL (label)),
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  return at_set;
+}
+
+static AtkAttributeSet*
+gail_item_get_default_attributes (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  at_set = gail_misc_get_default_attributes (at_set,
+                                             gtk_label_get_layout (GTK_LABEL (label)),
+                                             widget);
+  return at_set;
+}
+
+static gunichar 
+gail_item_get_character_at_offset (AtkText *text,
+                                   gint           offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  const gchar *string;
+  gchar *index;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return '\0';
+
+  label = get_label_from_container (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return '\0';
+  string = gtk_label_get_text (GTK_LABEL (label));
+  if (offset >= g_utf8_strlen (string, -1))
+    return '\0';
+  index = g_utf8_offset_to_pointer (string, offset);
+
+  return g_utf8_get_char (index);
+}
+
+static GtkWidget*
+get_label_from_container (GtkWidget *container)
+{
+  GtkWidget *label;
+  GList *children, *tmp_list;
+
+  if (!GTK_IS_CONTAINER (container))
+    return NULL;
+  children = gtk_container_get_children (GTK_CONTAINER (container));
+  label = NULL;
+
+  for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next) 
+    {
+      if (GTK_IS_LABEL (tmp_list->data))
+       {
+           label = tmp_list->data;
+           break;
+       }
+      /*
+       * Get label from menu item in desktop background preferences
+       * option menu. See bug #144084.
+       */
+      else if (GTK_IS_BOX (tmp_list->data))
+        {
+           label = get_label_from_container (GTK_WIDGET (tmp_list->data));
+           if (label)
+             break;
+        }
+    }
+  g_list_free (children);
+
+  return label;
+}
diff --git a/modules/other/gail/gailitem.h b/modules/other/gail/gailitem.h
new file mode 100644 (file)
index 0000000..18e4946
--- /dev/null
@@ -0,0 +1,64 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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_ITEM_H__
+#define __GAIL_ITEM_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_ITEM                          (gail_item_get_type ())
+#define GAIL_ITEM(obj)                          (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_ITEM, GailItem))
+#define GAIL_ITEM_CLASS(klass)                  (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_ITEM, GailItemClass))
+#define GAIL_IS_ITEM(obj)                       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_ITEM))
+#define GAIL_IS_ITEM_CLASS(klass)               (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_ITEM))
+#define GAIL_ITEM_GET_CLASS(obj)                (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_ITEM, GailItemClass))
+
+typedef struct _GailItem                   GailItem;
+typedef struct _GailItemClass              GailItemClass;
+
+struct _GailItem
+{
+  GailContainer parent;
+
+  GailTextUtil  *textutil;
+
+  gchar *text;
+};
+
+GType gail_item_get_type (void);
+
+struct _GailItemClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_item_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_ITEM_H__ */
diff --git a/modules/other/gail/gaillabel.c b/modules/other/gail/gaillabel.c
new file mode 100644 (file)
index 0000000..f9c12ee
--- /dev/null
@@ -0,0 +1,1065 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001, 2002, 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 "gaillabel.h"
+#include "gailwindow.h"
+#include <libgail-util/gailmisc.h>
+
+static void       gail_label_class_init            (GailLabelClass    *klass);
+static void      gail_label_real_initialize       (AtkObject         *obj,
+                                                    gpointer         data);
+static void      gail_label_real_notify_gtk       (GObject           *obj,
+                                                    GParamSpec       *pspec);
+static void       gail_label_map_gtk               (GtkWidget         *widget,
+                                                    gpointer          data);
+static void       gail_label_init_text_util        (GailLabel         *gail_label,
+                                                    GtkWidget         *widget);
+static void       gail_label_finalize              (GObject           *object);
+
+static void       atk_text_interface_init          (AtkTextIface      *iface);
+
+/* atkobject.h */
+
+static G_CONST_RETURN gchar* gail_label_get_name         (AtkObject         *accessible);
+static AtkStateSet*          gail_label_ref_state_set   (AtkObject         *accessible);
+static AtkRelationSet*       gail_label_ref_relation_set (AtkObject         *accessible);
+
+/* atktext.h */
+
+static gchar*    gail_label_get_text              (AtkText           *text,
+                                                    gint             start_pos,
+                                                   gint              end_pos);
+static gunichar          gail_label_get_character_at_offset(AtkText          *text,
+                                                   gint              offset);
+static gchar*     gail_label_get_text_before_offset(AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_label_get_text_at_offset    (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_label_get_text_after_offset    (AtkText       *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gint      gail_label_get_character_count   (AtkText           *text);
+static gint      gail_label_get_caret_offset      (AtkText           *text);
+static gboolean          gail_label_set_caret_offset      (AtkText           *text,
+                                                    gint             offset);
+static gint      gail_label_get_n_selections      (AtkText           *text);
+static gchar*    gail_label_get_selection         (AtkText           *text,
+                                                    gint             selection_num,
+                                                    gint             *start_offset,
+                                                    gint             *end_offset);
+static gboolean          gail_label_add_selection         (AtkText           *text,
+                                                    gint             start_offset,
+                                                    gint             end_offset);
+static gboolean          gail_label_remove_selection      (AtkText           *text,
+                                                    gint             selection_num);
+static gboolean          gail_label_set_selection         (AtkText           *text,
+                                                    gint             selection_num,
+                                                    gint             start_offset,
+                                                   gint              end_offset);
+static void gail_label_get_character_extents       (AtkText          *text,
+                                                   gint              offset,
+                                                   gint              *x,
+                                                   gint              *y,
+                                                   gint              *width,
+                                                   gint              *height,
+                                                   AtkCoordType      coords);
+static gint gail_label_get_offset_at_point         (AtkText           *text,
+                                                    gint              x,
+                                                    gint              y,
+                                                   AtkCoordType      coords);
+static AtkAttributeSet* gail_label_get_run_attributes 
+                                                   (AtkText           *text,
+                                                   gint              offset,
+                                                    gint             *start_offset,
+                                                   gint              *end_offset);
+static AtkAttributeSet* gail_label_get_default_attributes
+                                                   (AtkText           *text);
+
+static GailWidgetClass *parent_class = NULL;
+
+GType
+gail_label_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailLabelClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_label_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailLabel), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                     "GailLabel", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+    }
+  return type;
+}
+
+static void
+gail_label_class_init (GailLabelClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+
+  gobject_class->finalize = gail_label_finalize;
+
+  widget_class = (GailWidgetClass*)klass;
+  widget_class->notify_gtk = gail_label_real_notify_gtk;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_name = gail_label_get_name;
+  class->ref_state_set = gail_label_ref_state_set;
+  class->ref_relation_set = gail_label_ref_relation_set;
+  class->initialize = gail_label_real_initialize;
+}
+
+static void
+gail_label_real_initialize (AtkObject *obj,
+                            gpointer  data)
+{
+  GtkWidget  *widget;
+  GailLabel *gail_label;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+  
+  gail_label = GAIL_LABEL (obj);
+
+  gail_label->window_create_handler = 0;
+  gail_label->has_top_level = FALSE;
+  gail_label->cursor_position = 0;
+  gail_label->selection_bound = 0;
+  gail_label->textutil = NULL;
+  gail_label->label_length = 0;
+  
+  widget = GTK_WIDGET (data);
+
+  if (GTK_WIDGET_MAPPED (widget))
+    gail_label_init_text_util (gail_label, widget);
+  else
+    g_signal_connect (widget,
+                      "map",
+                      G_CALLBACK (gail_label_map_gtk),
+                      gail_label);
+
+  /* 
+   * Check whether ancestor of GtkLabel is a GtkButton and if so
+   * set accessible parent for GailLabel
+   */
+  while (widget != NULL)
+    {
+      widget = gtk_widget_get_parent (widget);
+      if (GTK_IS_BUTTON (widget))
+        {
+          atk_object_set_parent (obj, gtk_widget_get_accessible (widget));
+          break;
+        }
+    }
+
+  if (GTK_IS_ACCEL_LABEL (widget))
+    obj->role = ATK_ROLE_ACCEL_LABEL;
+  else
+    obj->role = ATK_ROLE_LABEL;
+}
+
+static void
+gail_label_map_gtk (GtkWidget *widget,
+                    gpointer data)
+{
+  GailLabel *gail_label;
+
+  gail_label = GAIL_LABEL (data);
+  gail_label_init_text_util (gail_label, widget);
+}
+
+static void
+gail_label_init_text_util (GailLabel *gail_label,
+                           GtkWidget *widget)
+{
+  GtkLabel *label;
+  const gchar *label_text;
+
+  if (gail_label->textutil == NULL)
+    gail_label->textutil = gail_text_util_new ();
+
+  label = GTK_LABEL (widget);
+  label_text = gtk_label_get_text (label);
+  gail_text_util_text_setup (gail_label->textutil, label_text);
+  
+  if (label_text == NULL)
+    gail_label->label_length = 0;
+  else
+    gail_label->label_length = g_utf8_strlen (label_text, -1);
+}
+
+AtkObject* 
+gail_label_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_LABEL (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_LABEL, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+notify_name_change (AtkObject *atk_obj)
+{
+  GtkLabel *label;
+  GailLabel *gail_label;
+  GtkWidget *widget;
+  GObject *gail_obj;
+
+  widget = GTK_ACCESSIBLE (atk_obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return;
+
+  gail_obj = G_OBJECT (atk_obj);
+  label = GTK_LABEL (widget);
+  gail_label = GAIL_LABEL (atk_obj);
+
+  if (gail_label->textutil == NULL)
+    return;
+
+  /*
+   * Check whether the label has actually changed before emitting
+   * notification.
+   */
+  if (gail_label->textutil->buffer) 
+    {
+      GtkTextIter start, end;
+      const char *new_label;
+      char *old_label;
+      int same;   
+
+      gtk_text_buffer_get_start_iter (gail_label->textutil->buffer, &start);
+      gtk_text_buffer_get_end_iter (gail_label->textutil->buffer, &end);
+      old_label = gtk_text_buffer_get_text (gail_label->textutil->buffer, &start, &end, FALSE);
+      new_label = gtk_label_get_text (label);
+      same = strcmp (new_label, old_label);
+      g_free (old_label);
+      if (same == 0)
+        return;
+    }
+   
+  /* Create a delete text and an insert text signal */
+  g_signal_emit_by_name (gail_obj, "text_changed::delete", 0, 
+                         gail_label->label_length);
+
+  gail_label_init_text_util (gail_label, widget);
+
+  g_signal_emit_by_name (gail_obj, "text_changed::insert", 0, 
+                         gail_label->label_length);
+
+  if (atk_obj->name == NULL)
+    /*
+     * The label has changed so notify a change in accessible-name
+     */
+    g_object_notify (gail_obj, "accessible-name");
+
+  g_signal_emit_by_name (gail_obj, "visible_data_changed");
+}
+
+static void
+window_created (GObject *obj,
+                gpointer data)
+{
+  g_return_if_fail (GAIL_LABEL (data));
+
+  notify_name_change (ATK_OBJECT (data)); 
+}
+
+static void
+gail_label_real_notify_gtk (GObject           *obj,
+                            GParamSpec        *pspec)
+{
+  GtkWidget *widget = GTK_WIDGET (obj);
+  AtkObject* atk_obj = gtk_widget_get_accessible (widget);
+  GtkLabel *label;
+  GailLabel *gail_label;
+  GObject *gail_obj;
+  AtkObject *top_level;
+  AtkObject *temp_obj;
+
+  gail_label = GAIL_LABEL (atk_obj);
+
+  if (strcmp (pspec->name, "label") == 0)
+    {
+     /* 
+      * We may get a label change for a label which is not attached to an
+      * application. We wait until the toplevel window is created before
+      * emitting the notification.
+      *
+      * This happens when [Ctrl+]Alt+Tab is pressed in metacity
+      */
+      if (!gail_label->has_top_level)
+        {
+          temp_obj = atk_obj;
+          top_level = NULL;
+          while (temp_obj)
+            {
+              top_level = temp_obj;
+              temp_obj = atk_object_get_parent (top_level);
+            }
+          if (atk_object_get_role (top_level) != ATK_ROLE_APPLICATION)
+            {
+              if (gail_label->window_create_handler == 0 && 
+                  GAIL_IS_WINDOW (top_level))
+                gail_label->window_create_handler = g_signal_connect_after (top_level, "create", G_CALLBACK (window_created), atk_obj);
+            }
+          else
+            gail_label->has_top_level = TRUE;
+        }
+      if (gail_label->has_top_level)
+        notify_name_change (atk_obj);
+    }
+  else if (strcmp (pspec->name, "cursor-position") == 0)
+    {
+      gint start, end;
+      gboolean text_caret_moved = FALSE;
+      gboolean selection_changed = FALSE;
+      gboolean is_start = TRUE;
+
+      gail_obj = G_OBJECT (atk_obj);
+      label = GTK_LABEL (widget);
+
+      if (gtk_label_get_selection_bounds (label, &start, &end))
+        {
+          if (start != gail_label->cursor_position ||
+              end != gail_label->selection_bound)
+            {
+              if (end != gail_label->selection_bound)
+                is_start = FALSE;
+              gail_label->selection_bound = end;
+              gail_label->cursor_position = start;
+              text_caret_moved = TRUE;
+              if (start != end)
+                selection_changed = TRUE;
+            }
+        }
+      else 
+        {
+          if (gail_label->cursor_position != gail_label->selection_bound)
+            selection_changed = TRUE;
+          if (gtk_label_get_selectable (label))
+            {
+              if (gail_label->cursor_position != -1 && start != gail_label->cursor_position)
+                text_caret_moved = TRUE;
+              if (gail_label->selection_bound != -1 && end != gail_label->selection_bound)
+                {
+                  text_caret_moved = TRUE;
+                  is_start = FALSE;
+                }
+              gail_label->cursor_position = start;
+              gail_label->selection_bound = end;
+            }
+          else
+            {
+              /* GtkLabel has become non selectable */
+
+              gail_label->cursor_position = 0;
+              gail_label->selection_bound = 0;
+              text_caret_moved = TRUE;
+            }
+
+        }
+        if (text_caret_moved)
+          g_signal_emit_by_name (gail_obj, "text_caret_moved", 
+                                 is_start ? gail_label->cursor_position : gail_label->selection_bound);
+        if (selection_changed)
+          g_signal_emit_by_name (gail_obj, "text_selection_changed");
+
+    }
+  else
+    parent_class->notify_gtk (obj, pspec);
+}
+
+static void
+gail_label_finalize (GObject            *object)
+{
+  GailLabel *label = GAIL_LABEL (object);
+
+  if (label->textutil)
+    g_object_unref (label->textutil);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/* atkobject.h */
+
+static AtkStateSet*
+gail_label_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE);
+
+  return state_set;
+}
+
+AtkRelationSet*
+gail_label_ref_relation_set (AtkObject *obj)
+{
+  GtkWidget *widget;
+  AtkRelationSet *relation_set;
+
+  g_return_val_if_fail (GAIL_IS_LABEL (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  relation_set = ATK_OBJECT_CLASS (parent_class)->ref_relation_set (obj);
+
+  if (!atk_relation_set_contains (relation_set, ATK_RELATION_LABEL_FOR))
+    {
+      /*
+       * Get the mnemonic widget
+       *
+       * The relation set is not updated if the mnemonic widget is changed
+       */
+      GtkWidget *mnemonic_widget = GTK_LABEL (widget)->mnemonic_widget;
+
+      if (mnemonic_widget)
+        {
+          AtkObject *accessible_array[1];
+          AtkRelation* relation;
+
+          if (!GTK_WIDGET_CAN_FOCUS (mnemonic_widget))
+            {
+            /*
+             * Handle the case where a GtkFileChooserButton is specified as the 
+             * mnemonic widget. use the combobox which is a child of the
+             * GtkFileChooserButton as the mnemonic widget. See bug #359843.
+             */
+             if (GTK_IS_BOX (mnemonic_widget))
+               {
+                  GList *list, *tmpl;
+
+                  list = gtk_container_get_children (GTK_CONTAINER (mnemonic_widget));
+                  if (g_list_length (list) == 2)
+                    {
+                      tmpl = g_list_last (list);
+                      if (GTK_IS_COMBO_BOX(tmpl->data))
+                        {
+                          mnemonic_widget = GTK_WIDGET(tmpl->data);
+                        }
+                    }
+                  g_list_free (list);
+                }
+            /*
+             * Handle the case where a GnomeIconEntry is specified as the 
+             * mnemonic widget. use the button which is a grandchild of the
+             * GnomeIconEntry as the mnemonic widget. See bug #133967.
+             */
+              else if (GTK_IS_BOX (mnemonic_widget))
+                {
+                  GList *list;
+
+                  list = gtk_container_get_children (GTK_CONTAINER (mnemonic_widget));
+                  if (g_list_length (list) == 1)
+                    {
+                      if (GTK_IS_ALIGNMENT (list->data))
+                        {
+                          GtkWidget *temp_widget;
+
+                          temp_widget = GTK_BIN (list->data)->child;
+                          if (GTK_IS_BUTTON (temp_widget))
+                            mnemonic_widget = temp_widget;
+                        }
+                      else if (GTK_IS_HBOX (list->data))
+                        {
+                          GtkWidget *temp_widget;
+
+                          temp_widget = GTK_WIDGET (list->data);
+                          g_list_free (list);
+                          list = gtk_container_get_children (GTK_CONTAINER (temp_widget));
+                          if (GTK_IS_COMBO (list->data))
+                            {
+                              mnemonic_widget = GTK_WIDGET (list->data);
+                            }
+                        }
+                    }
+                  g_list_free (list);
+                }
+            }
+          accessible_array[0] = gtk_widget_get_accessible (mnemonic_widget);
+          relation = atk_relation_new (accessible_array, 1,
+                                       ATK_RELATION_LABEL_FOR);
+          atk_relation_set_add (relation_set, relation);
+          /*
+           * Unref the relation so that it is not leaked.
+           */
+          g_object_unref (relation);
+        }
+    }
+  return relation_set;
+}
+
+static G_CONST_RETURN gchar*
+gail_label_get_name (AtkObject *accessible)
+{
+  G_CONST_RETURN gchar *name;
+
+  g_return_val_if_fail (GAIL_IS_LABEL (accessible), NULL);
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (accessible);
+  if (name != NULL)
+    return name;
+  else
+    {
+      /*
+       * Get the text on the label
+       */
+      GtkWidget *widget;
+
+      widget = GTK_ACCESSIBLE (accessible)->widget;
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+
+      g_return_val_if_fail (GTK_IS_LABEL (widget), NULL);
+
+      return gtk_label_get_text (GTK_LABEL (widget));
+    }
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->get_text = gail_label_get_text;
+  iface->get_character_at_offset = gail_label_get_character_at_offset;
+  iface->get_text_before_offset = gail_label_get_text_before_offset;
+  iface->get_text_at_offset = gail_label_get_text_at_offset;
+  iface->get_text_after_offset = gail_label_get_text_after_offset;
+  iface->get_character_count = gail_label_get_character_count;
+  iface->get_caret_offset = gail_label_get_caret_offset;
+  iface->set_caret_offset = gail_label_set_caret_offset;
+  iface->get_n_selections = gail_label_get_n_selections;
+  iface->get_selection = gail_label_get_selection;
+  iface->add_selection = gail_label_add_selection;
+  iface->remove_selection = gail_label_remove_selection;
+  iface->set_selection = gail_label_set_selection;
+  iface->get_character_extents = gail_label_get_character_extents;
+  iface->get_offset_at_point = gail_label_get_offset_at_point;
+  iface->get_run_attributes = gail_label_get_run_attributes;
+  iface->get_default_attributes = gail_label_get_default_attributes;
+}
+
+static gchar*
+gail_label_get_text (AtkText *text,
+                     gint    start_pos,
+                     gint    end_pos)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = GTK_LABEL (widget);
+
+  label_text = gtk_label_get_text (label);
+  if (label_text == NULL)
+    return NULL;
+  else
+  {
+    if (GAIL_LABEL (text)->textutil == NULL) 
+      gail_label_init_text_util (GAIL_LABEL (text), widget);
+    return gail_text_util_get_substring (GAIL_LABEL(text)->textutil, 
+                                         start_pos, end_pos);
+  }
+}
+
+static gchar*
+gail_label_get_text_before_offset (AtkText         *text,
+                                  gint            offset,
+                                  AtkTextBoundary boundary_type,
+                                  gint            *start_offset,
+                                  gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkLabel *label;
+  
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = GTK_LABEL (widget);
+
+  return gail_text_util_get_text (GAIL_LABEL (text)->textutil,
+                           gtk_label_get_layout (label), GAIL_BEFORE_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset); 
+}
+
+static gchar*
+gail_label_get_text_at_offset (AtkText         *text,
+                              gint            offset,
+                              AtkTextBoundary boundary_type,
+                              gint            *start_offset,
+                              gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkLabel *label;
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = GTK_LABEL (widget);
+
+  return gail_text_util_get_text (GAIL_LABEL (text)->textutil,
+                              gtk_label_get_layout (label), GAIL_AT_OFFSET, 
+                              boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_label_get_text_after_offset (AtkText         *text,
+                                 gint            offset,
+                                 AtkTextBoundary boundary_type,
+                                 gint            *start_offset,
+                                 gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkLabel *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return NULL;
+  }
+  
+  /* Get label */
+  label = GTK_LABEL (widget);
+
+  return gail_text_util_get_text (GAIL_LABEL (text)->textutil,
+                           gtk_label_get_layout (label), GAIL_AFTER_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gint
+gail_label_get_character_count (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  label = GTK_LABEL (widget);
+  return g_utf8_strlen (gtk_label_get_text (label), -1);
+}
+
+static gint
+gail_label_get_caret_offset (AtkText *text)
+{
+   return GAIL_LABEL (text)->cursor_position;
+}
+
+static gboolean
+gail_label_set_caret_offset (AtkText *text, 
+                             gint    offset)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  label = GTK_LABEL (widget);
+
+  if (gtk_label_get_selectable (label) &&
+      offset >= 0 &&
+      offset <= g_utf8_strlen (label->text, -1))
+    {
+      gtk_label_select_region (label, offset, offset);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gint
+gail_label_get_n_selections (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+  gint start, end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  label = GTK_LABEL (widget);
+
+  if (!gtk_label_get_selectable (label))
+     return 0;
+
+  if (gtk_label_get_selection_bounds (label, &start, &end))
+     return 1;
+  else 
+     return 0;
+}
+
+static gchar*
+gail_label_get_selection (AtkText *text,
+                         gint    selection_num,
+                          gint    *start_pos,
+                          gint    *end_pos)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = GTK_LABEL (widget);
+
+ /* Only let the user get the selection if one is set, and if the
+  * selection_num is 0.
+  */
+  if (!gtk_label_get_selectable( label) || selection_num != 0)
+     return NULL;
+
+  if (gtk_label_get_selection_bounds (label, start_pos, end_pos))
+    {
+      const gchar* label_text = gtk_label_get_text (label);
+    
+      if (label_text == NULL)
+        return 0;
+      else
+        return gail_text_util_get_substring (GAIL_LABEL (text)->textutil, 
+                                             *start_pos, *end_pos);
+    }
+  else 
+    return NULL;
+}
+
+static gboolean
+gail_label_add_selection (AtkText *text,
+                          gint    start_pos,
+                          gint    end_pos)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+  gint start, end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  label = GTK_LABEL (widget);
+
+  if (!gtk_label_get_selectable (label))
+     return FALSE;
+
+  if (! gtk_label_get_selection_bounds (label, &start, &end))
+    {
+      gtk_label_select_region (label, start_pos, end_pos);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+gail_label_remove_selection (AtkText *text,
+                             gint    selection_num)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+  gint start, end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  if (selection_num != 0)
+     return FALSE;
+
+  label = GTK_LABEL (widget);
+
+  if (!gtk_label_get_selectable (label))
+     return FALSE;
+
+  if (gtk_label_get_selection_bounds (label, &start, &end))
+    {
+      gtk_label_select_region (label, 0, 0);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+gail_label_set_selection (AtkText *text,
+                         gint    selection_num,
+                          gint    start_pos,
+                          gint    end_pos)
+{
+  GtkWidget *widget;
+  GtkLabel  *label;
+  gint start, end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  if (selection_num != 0)
+     return FALSE;
+
+  label = GTK_LABEL (widget);
+
+  if (!gtk_label_get_selectable (label))
+     return FALSE;
+
+  if (gtk_label_get_selection_bounds (label, &start, &end))
+    {
+      gtk_label_select_region (label, start_pos, end_pos);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void
+gail_label_get_character_extents (AtkText      *text,
+                                 gint         offset,
+                                 gint         *x,
+                                 gint         *y,
+                                  gint                *width,
+                                  gint                *height,
+                                 AtkCoordType coords)
+{
+  GtkWidget *widget;
+  GtkLabel *label;
+  PangoRectangle char_rect;
+  gint index, x_layout, y_layout;
+  widget = GTK_ACCESSIBLE (text)->widget;
+
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  label = GTK_LABEL (widget);
+  
+  gtk_label_get_layout_offsets (label, &x_layout, &y_layout);
+  index = g_utf8_offset_to_pointer (label->text, offset) - label->text;
+  pango_layout_index_to_pos (gtk_label_get_layout (label), index, &char_rect);
+  
+  gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, 
+                    x_layout, y_layout, x, y, width, height, coords);
+} 
+
+static gint 
+gail_label_get_offset_at_point (AtkText      *text,
+                                gint         x,
+                                gint         y,
+                               AtkCoordType coords)
+{ 
+  GtkWidget *widget;
+  GtkLabel *label;
+  gint index, x_layout, y_layout;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+  label = GTK_LABEL (widget);
+  
+  gtk_label_get_layout_offsets (label, &x_layout, &y_layout);
+  
+  index = gail_misc_get_index_at_point_in_layout (widget, 
+                                              gtk_label_get_layout (label), 
+                                              x_layout, y_layout, x, y, coords);
+  if (index == -1)
+    {
+      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+        return g_utf8_strlen (label->text, -1);
+
+      return index;  
+    }
+  else
+    return g_utf8_pointer_to_offset (label->text, label->text + index);  
+}
+
+static AtkAttributeSet*
+gail_label_get_run_attributes (AtkText        *text,
+                               gint          offset,
+                               gint          *start_offset,
+                              gint           *end_offset)
+{
+  GtkWidget *widget;
+  GtkLabel *label;
+  AtkAttributeSet *at_set = NULL;
+  GtkJustification justify;
+  GtkTextDirection dir;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = GTK_LABEL (widget);
+  
+  /* Get values set for entire label, if any */
+  justify = gtk_label_get_justify (label);
+  if (justify != GTK_JUSTIFY_CENTER)
+    {
+      at_set = gail_misc_add_attribute (at_set, 
+                                        ATK_TEXT_ATTR_JUSTIFICATION,
+     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
+    }
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                gtk_label_get_layout (label),
+                                                label->text,
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  return at_set;
+}
+
+static AtkAttributeSet*
+gail_label_get_default_attributes (AtkText        *text)
+{
+  GtkWidget *widget;
+  GtkLabel *label;
+  AtkAttributeSet *at_set = NULL;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = GTK_LABEL (widget);
+  
+  at_set = gail_misc_get_default_attributes (at_set,
+                                             gtk_label_get_layout (label),
+                                             widget);
+  return at_set;
+}
+
+static gunichar 
+gail_label_get_character_at_offset (AtkText             *text,
+                                    gint                offset)
+{
+  GtkWidget *widget;
+  GtkLabel *label;
+  const gchar *string;
+  gchar *index;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return '\0';
+
+  label = GTK_LABEL (widget);
+  string = gtk_label_get_text (label);
+  if (offset >= g_utf8_strlen (string, -1))
+    return '\0';
+  index = g_utf8_offset_to_pointer (string, offset);
+
+  return g_utf8_get_char (index);
+}
diff --git a/modules/other/gail/gaillabel.h b/modules/other/gail/gaillabel.h
new file mode 100644 (file)
index 0000000..3c927c4
--- /dev/null
@@ -0,0 +1,67 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_LABEL_H__
+#define __GAIL_LABEL_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_LABEL                      (gail_label_get_type ())
+#define GAIL_LABEL(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_LABEL, GailLabel))
+#define GAIL_LABEL_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_LABEL, GailLabelClass))
+#define GAIL_IS_LABEL(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_LABEL))
+#define GAIL_IS_LABEL_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_LABEL))
+#define GAIL_LABEL_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_LABEL, GailLabelClass))
+
+typedef struct _GailLabel              GailLabel;
+typedef struct _GailLabelClass         GailLabelClass;
+
+struct _GailLabel
+{
+  GailWidget parent;
+
+  GailTextUtil   *textutil;
+  gint           cursor_position;
+  gint           selection_bound;
+  gint           label_length;
+  guint          window_create_handler;
+  gboolean       has_top_level;
+};
+
+GType gail_label_get_type (void);
+
+struct _GailLabelClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_label_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_LABEL_H__ */
diff --git a/modules/other/gail/gaillist.c b/modules/other/gail/gaillist.c
new file mode 100644 (file)
index 0000000..c5d4048
--- /dev/null
@@ -0,0 +1,277 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gaillist.h"
+#include "gailcombo.h"
+
+static void         gail_list_class_init            (GailListClass  *klass); 
+
+static gint         gail_list_get_index_in_parent   (AtkObject      *accessible);
+
+static void         atk_selection_interface_init    (AtkSelectionIface *iface);
+static gboolean     gail_list_add_selection         (AtkSelection   *selection,
+                                                     gint           i);
+static gboolean     gail_list_clear_selection       (AtkSelection   *selection);
+static AtkObject*   gail_list_ref_selection         (AtkSelection   *selection,
+                                                     gint           i);
+static gint         gail_list_get_selection_count   (AtkSelection   *selection);
+static gboolean     gail_list_is_child_selected     (AtkSelection   *selection,
+                                                     gint           i);
+static gboolean     gail_list_remove_selection      (AtkSelection   *selection,
+                                                     gint           i);
+
+
+static GailContainerClass *parent_class = NULL;
+
+GType
+gail_list_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailListClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_list_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailList), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+    static const GInterfaceInfo atk_selection_info =
+    {
+      (GInterfaceInitFunc) atk_selection_interface_init,
+      (GInterfaceFinalizeFunc) NULL,
+      NULL
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                   "GailList", &tinfo, 0);
+
+    g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                   &atk_selection_info);
+
+
+  }
+  return type;
+}
+
+static void
+gail_list_class_init (GailListClass *klass)
+{
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_index_in_parent = gail_list_get_index_in_parent;
+}
+
+AtkObject* 
+gail_list_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_LIST (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_LIST, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_LIST;
+
+  return accessible;
+}
+
+static gint
+gail_list_get_index_in_parent (AtkObject *accessible)
+{
+  /*
+   * If the parent widget is a combo box then the index is 0
+   * otherwise do the normal thing.
+   */
+  if (accessible->accessible_parent)
+  {
+    if (GAIL_IS_COMBO (accessible->accessible_parent))
+      return 0;
+  }
+  return ATK_OBJECT_CLASS (parent_class)->get_index_in_parent (accessible);
+}
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->add_selection = gail_list_add_selection;
+  iface->clear_selection = gail_list_clear_selection;
+  iface->ref_selection = gail_list_ref_selection;
+  iface->get_selection_count = gail_list_get_selection_count;
+  iface->is_child_selected = gail_list_is_child_selected;
+  iface->remove_selection = gail_list_remove_selection;
+  /*
+   * select_all_selection does not make sense for a combo box
+   * so no implementation is provided.
+   */
+}
+
+static gboolean
+gail_list_add_selection (AtkSelection   *selection,
+                         gint           i)
+{
+  GtkList *list;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  list = GTK_LIST (widget);
+
+  gtk_list_select_item (list, i);
+  return TRUE;
+}
+
+static gboolean 
+gail_list_clear_selection (AtkSelection *selection)
+{
+  GtkList *list;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  list = GTK_LIST (widget);
+
+  gtk_list_unselect_all (list);
+  return TRUE;
+}
+
+static AtkObject*
+gail_list_ref_selection (AtkSelection *selection,
+                         gint         i)
+{
+  GtkList *list;
+  GList *g_list;
+  GtkWidget *item;
+  AtkObject *obj;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  list = GTK_LIST (widget);
+
+  /*
+   * A combo box can have only one selection.
+   */
+  if (i != 0)
+    return NULL;
+
+  g_list = list->selection;
+
+  if (g_list == NULL)
+    return NULL;
+
+  item = GTK_WIDGET (g_list->data);
+
+  obj = gtk_widget_get_accessible (item);
+  g_object_ref (obj);
+  return obj;
+}
+
+static gint
+gail_list_get_selection_count (AtkSelection *selection)
+{
+  GtkList *list;
+  GList *g_list;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  list = GTK_LIST (widget);
+
+  g_list = list->selection;
+
+  return g_list_length (g_list);;
+}
+
+static gboolean
+gail_list_is_child_selected (AtkSelection *selection,
+                             gint         i)
+{
+  GtkList *list;
+  GList *g_list;
+  GtkWidget *item;
+  gint j;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  list = GTK_LIST (widget);
+
+  g_list = list->selection;
+
+  if (g_list == NULL)
+    return FALSE;
+
+  item = GTK_WIDGET (g_list->data);
+
+  j = g_list_index (list->children, item);
+
+  return (j == i);
+}
+
+static gboolean
+gail_list_remove_selection (AtkSelection   *selection,
+                             gint           i)
+{
+  if (atk_selection_is_child_selected (selection, i))
+    atk_selection_clear_selection (selection);
+
+  return TRUE;
+}
diff --git a/modules/other/gail/gaillist.h b/modules/other/gail/gaillist.h
new file mode 100644 (file)
index 0000000..cd57874
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_LIST_H__
+#define __GAIL_LIST_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_LIST                       (gail_list_get_type ())
+#define GAIL_LIST(obj)                       (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_LIST, GailList))
+#define GAIL_LIST_CLASS(klass)               (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_LIST, GailListClass))
+#define GAIL_IS_LIST(obj)                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_LIST))
+#define GAIL_IS_LIST_CLASS(klass)            (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_LIST))
+#define GAIL_LIST_GET_CLASS(obj)             (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_LIST, GailListClass))
+
+typedef struct _GailList              GailList;
+typedef struct _GailListClass         GailListClass;
+
+struct _GailList
+{
+  GailContainer parent;
+};
+
+GType gail_list_get_type (void);
+
+struct _GailListClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_list_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_LIST_H__ */
diff --git a/modules/other/gail/gailmenu.c b/modules/other/gail/gailmenu.c
new file mode 100644 (file)
index 0000000..f86c859
--- /dev/null
@@ -0,0 +1,167 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gtk/gtkmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkcombobox.h>
+#include "gailmenu.h"
+
+static void gail_menu_class_init (GailMenuClass *klass);
+
+static void      gail_menu_real_initialize     (AtkObject *obj,
+                                                 gpointer  data);
+
+static AtkObject* gail_menu_get_parent          (AtkObject *accessible);
+static gint       gail_menu_get_index_in_parent (AtkObject *accessible);
+
+static GailMenuShell *parent_class = NULL;
+
+GType
+gail_menu_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailMenuClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_menu_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailMenu), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_MENU_SHELL,
+                                     "GailMenu", &tinfo, 0);
+    }
+
+  return type;
+}
+
+static void
+gail_menu_class_init (GailMenuClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  class->get_parent = gail_menu_get_parent;
+  class->get_index_in_parent = gail_menu_get_index_in_parent;
+  class->initialize = gail_menu_real_initialize;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+AtkObject*
+gail_menu_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_MENU (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_MENU, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  g_object_set_data (G_OBJECT (accessible), "atk-component-layer",
+                    GINT_TO_POINTER (ATK_LAYER_POPUP));
+  return accessible;
+}
+
+static void
+gail_menu_real_initialize (AtkObject *obj,
+                           gpointer  data)
+{
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  obj->role = ATK_ROLE_MENU;
+}
+
+static AtkObject*
+gail_menu_get_parent (AtkObject *accessible)
+{
+  AtkObject *parent;
+
+  parent = accessible->accessible_parent;
+
+  if (parent != NULL)
+    {
+      g_return_val_if_fail (ATK_IS_OBJECT (parent), NULL);
+    }
+  else
+    {
+      GtkWidget *widget, *parent_widget;
+
+      widget = GTK_ACCESSIBLE (accessible)->widget;
+      if (widget == NULL)
+        {
+          /*
+           * State is defunct
+           */
+          return NULL;
+        }
+      g_return_val_if_fail (GTK_IS_MENU (widget), NULL);
+
+      /*
+       * If the menu is attached to a menu item or a button (Gnome Menu)
+       * report the menu item as parent.
+       */
+      parent_widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
+
+      if (!GTK_IS_MENU_ITEM (parent_widget) && !GTK_IS_BUTTON (parent_widget) && !GTK_IS_COMBO_BOX (parent_widget) && !GTK_IS_OPTION_MENU (parent_widget))
+        parent_widget = widget->parent;
+
+      if (parent_widget == NULL)
+        return NULL;
+
+      parent = gtk_widget_get_accessible (parent_widget);
+      atk_object_set_parent (accessible, parent);
+    }
+  return parent;
+}
+
+static gint
+gail_menu_get_index_in_parent (AtkObject *accessible)
+{
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+    {
+      /*
+       * State is defunct
+       */
+      return -1;
+    }
+  g_return_val_if_fail (GTK_IS_MENU (widget), -1);
+
+  if (gtk_menu_get_attach_widget (GTK_MENU (widget)))
+    {
+      return 0;
+    }
+  return ATK_OBJECT_CLASS (parent_class)->get_index_in_parent (accessible);
+}
diff --git a/modules/other/gail/gailmenu.h b/modules/other/gail/gailmenu.h
new file mode 100644 (file)
index 0000000..5c1c5f9
--- /dev/null
@@ -0,0 +1,60 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_MENU_H__
+#define __GAIL_MENU_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailmenushell.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_MENU                          (gail_menu_get_type ())
+#define GAIL_MENU(obj)                          (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_MENU_SHELL, GailMenu))
+#define GAIL_MENU_CLASS(klass)                  (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_MENU, GailMenuClass))
+#define GAIL_IS_MENU(obj)                       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_MENU))
+#define GAIL_IS_MENU_CLASS(klass)               (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_MENU))
+#define GAIL_MENU_GET_CLASS(obj)                (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_MENU, GailMenuClass))
+
+typedef struct _GailMenu                   GailMenu;
+typedef struct _GailMenuClass              GailMenuClass;
+
+struct _GailMenu
+{
+  GailMenuShell parent;
+};
+
+GType gail_menu_get_type (void);
+
+struct _GailMenuClass
+{
+  GailMenuShellClass parent_class;
+};
+
+AtkObject* gail_menu_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_MENU_H__ */
diff --git a/modules/other/gail/gailmenuitem.c b/modules/other/gail/gailmenuitem.c
new file mode 100644 (file)
index 0000000..0425cae
--- /dev/null
@@ -0,0 +1,682 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "gailmenuitem.h"
+#include "gailsubmenuitem.h"
+
+#define KEYBINDING_SEPARATOR ";"
+
+static void gail_menu_item_class_init  (GailMenuItemClass *klass);
+static void gail_menu_item_object_init (GailMenuItem      *menu_item);
+
+static void                  gail_menu_item_real_initialize
+                                                          (AtkObject       *obj,
+                                                           gpointer        data);
+static gint                  gail_menu_item_get_n_children (AtkObject      *obj);
+static AtkObject*            gail_menu_item_ref_child      (AtkObject      *obj,
+                                                            gint           i);
+static void                  gail_menu_item_finalize       (GObject        *object);
+
+static void                  atk_action_interface_init     (AtkActionIface *iface);
+static gboolean              gail_menu_item_do_action      (AtkAction      *action,
+                                                            gint           i);
+static gboolean              idle_do_action                (gpointer       data);
+static gint                  gail_menu_item_get_n_actions  (AtkAction      *action);
+static G_CONST_RETURN gchar* gail_menu_item_get_description(AtkAction      *action,
+                                                            gint           i);
+static G_CONST_RETURN gchar* gail_menu_item_get_name       (AtkAction      *action,
+                                                            gint           i);
+static G_CONST_RETURN gchar* gail_menu_item_get_keybinding (AtkAction      *action,
+                                                            gint           i);
+static gboolean              gail_menu_item_set_description(AtkAction      *action,
+                                                            gint           i,
+                                                            const gchar    *desc);
+static void                  menu_item_select              (GtkItem        *item);
+static void                  menu_item_deselect            (GtkItem        *item);
+static void                  menu_item_selection           (GtkItem        *item,
+                                                            gboolean       selected);
+static gboolean              find_accel                    (GtkAccelKey    *key,
+                                                            GClosure       *closure,
+                                                            gpointer       data);
+static gboolean              find_accel_new                (GtkAccelKey    *key,
+                                                            GClosure       *closure,
+                                                            gpointer       data);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_menu_item_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailMenuItemClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_menu_item_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailMenuItem), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_menu_item_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_action_info =
+      {
+        (GInterfaceInitFunc) atk_action_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_ITEM,
+                                     "GailMenuItem", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                   &atk_action_info);
+    }
+  return type;
+}
+
+static void
+gail_menu_item_class_init (GailMenuItemClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gail_menu_item_finalize;
+
+  class->get_n_children = gail_menu_item_get_n_children;
+  class->ref_child = gail_menu_item_ref_child;
+  class->initialize = gail_menu_item_real_initialize;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gail_menu_item_real_initialize (AtkObject *obj,
+                                gpointer  data)
+{
+  GtkWidget *widget;
+  GtkWidget *parent;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  g_signal_connect (data,
+                    "select",
+                    G_CALLBACK (menu_item_select),
+                    NULL);
+  g_signal_connect (data,
+                    "deselect",
+                    G_CALLBACK (menu_item_deselect),
+                    NULL);
+  widget = GTK_WIDGET (data);
+  parent = gtk_widget_get_parent (widget);
+  if (GTK_IS_MENU (parent))
+    {
+      GtkWidget *parent_widget;
+
+      parent_widget =  gtk_menu_get_attach_widget (GTK_MENU (parent));
+
+      if (!GTK_IS_MENU_ITEM (parent_widget))
+        parent_widget = gtk_widget_get_parent (widget);
+       if (parent_widget)
+        {
+          atk_object_set_parent (obj, gtk_widget_get_accessible (parent_widget));
+        }
+    }
+  g_object_set_data (G_OBJECT (obj), "atk-component-layer",
+                     GINT_TO_POINTER (ATK_LAYER_POPUP));
+
+  if (GTK_IS_TEAROFF_MENU_ITEM (data))
+    obj->role = ATK_ROLE_TEAR_OFF_MENU_ITEM;
+  else if (GTK_IS_SEPARATOR_MENU_ITEM (data))
+    obj->role = ATK_ROLE_SEPARATOR;
+  else
+    obj->role = ATK_ROLE_MENU_ITEM;
+}
+
+static void
+gail_menu_item_object_init (GailMenuItem *menu_item)
+{
+  menu_item->click_keybinding = NULL;
+  menu_item->click_description = NULL;
+}
+
+AtkObject*
+gail_menu_item_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+  
+  g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), NULL);
+
+  if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)))
+    return gail_sub_menu_item_new (widget);
+
+  object = g_object_new (GAIL_TYPE_MENU_ITEM, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+GList *
+get_children (GtkWidget *submenu)
+{
+  GList *children;
+
+  children = gtk_container_get_children (GTK_CONTAINER (submenu));
+  if (g_list_length (children) == 0)
+    {
+      /*
+       * If menu is empty it may be because the menu items are created only 
+       * on demand. For example, in gnome-panel the menu items are created
+       * only when "show" signal is emitted on the menu.
+       *
+       * The following hack forces the menu items to be created.
+       */
+      if (!GTK_WIDGET_VISIBLE (submenu))
+        {
+          GTK_WIDGET_SET_FLAGS (submenu, GTK_VISIBLE);
+          g_signal_emit_by_name (submenu, "show");
+          GTK_WIDGET_UNSET_FLAGS (submenu, GTK_VISIBLE);
+        }
+      g_list_free (children);
+      children = gtk_container_get_children (GTK_CONTAINER (submenu));
+    }
+  return children;
+}
+
+/*
+ * If a menu item has a submenu return the items of the submenu as the 
+ * accessible children; otherwise expose no accessible children.
+ */
+static gint
+gail_menu_item_get_n_children (AtkObject* obj)
+{
+  GtkWidget *widget;
+  GtkWidget *submenu;
+  gint count = 0;
+
+  g_return_val_if_fail (GAIL_IS_MENU_ITEM (obj), count);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return count;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (submenu)
+    {
+      GList *children;
+
+      children = get_children (submenu);
+      count = g_list_length (children);
+      g_list_free (children);
+    }
+  return count;
+}
+
+static AtkObject*
+gail_menu_item_ref_child (AtkObject *obj,
+                          gint       i)
+{
+  AtkObject  *accessible;
+  GtkWidget *widget;
+  GtkWidget *submenu;
+
+  g_return_val_if_fail (GAIL_IS_MENU_ITEM (obj), NULL);
+  g_return_val_if_fail ((i >= 0), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return NULL;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (submenu)
+    {
+      GList *children;
+      GList *tmp_list;
+
+      children = get_children (submenu);
+      tmp_list = g_list_nth (children, i);
+      if (!tmp_list)
+        {
+          g_list_free (children);
+          return NULL;
+        }
+      accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
+      g_list_free (children);
+      g_object_ref (accessible);
+    }
+  else
+    accessible = NULL;
+
+  return accessible;
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action = gail_menu_item_do_action;
+  iface->get_n_actions = gail_menu_item_get_n_actions;
+  iface->get_description = gail_menu_item_get_description;
+  iface->get_name = gail_menu_item_get_name;
+  iface->get_keybinding = gail_menu_item_get_keybinding;
+  iface->set_description = gail_menu_item_set_description;
+}
+
+static gboolean
+gail_menu_item_do_action (AtkAction *action,
+                          gint      i)
+{
+  if (i == 0)
+    {
+      GtkWidget *item;
+      GailMenuItem *gail_menu_item;
+
+      item = GTK_ACCESSIBLE (action)->widget;
+      if (item == NULL)
+        /* State is defunct */
+        return FALSE;
+
+      if (!GTK_WIDGET_SENSITIVE (item) || !GTK_WIDGET_VISIBLE (item))
+        return FALSE;
+
+      gail_menu_item = GAIL_MENU_ITEM (action);
+      if (gail_menu_item->action_idle_handler)
+        return FALSE;
+      else
+       {
+         g_object_ref (gail_menu_item);
+         gail_menu_item->action_idle_handler = g_idle_add (idle_do_action, gail_menu_item);
+       }
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void
+ensure_menus_unposted (GailMenuItem *menu_item)
+{
+  AtkObject *parent;
+  GtkWidget *widget;
+
+  parent = atk_object_get_parent (ATK_OBJECT (menu_item));
+  while (parent)
+    {
+      if (GTK_IS_ACCESSIBLE (parent))
+        {
+          widget = GTK_ACCESSIBLE (parent)->widget;
+          if (GTK_IS_MENU (widget))
+            {
+              if (GTK_WIDGET_MAPPED (widget))
+                gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
+
+              return;
+            }
+        }
+      parent = atk_object_get_parent (parent);
+    }
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  GtkWidget *item;
+  GtkWidget *item_parent;
+  GailMenuItem *menu_item;
+  gboolean item_mapped;
+
+  GDK_THREADS_ENTER ();
+
+  menu_item = GAIL_MENU_ITEM (data);
+  menu_item->action_idle_handler = 0;
+  item = GTK_ACCESSIBLE (menu_item)->widget;
+  if (item == NULL /* State is defunct */ ||
+      !GTK_WIDGET_SENSITIVE (item) || !GTK_WIDGET_VISIBLE (item))
+  {
+    g_object_unref (menu_item);
+    GDK_THREADS_LEAVE ();
+    return FALSE;
+  }
+
+  item_parent = gtk_widget_get_parent (item);
+  gtk_menu_shell_select_item (GTK_MENU_SHELL (item_parent), item);
+  item_mapped = GTK_WIDGET_MAPPED (item);
+  /*
+   * This is what is called when <Return> is pressed for a menu item
+   */
+  g_signal_emit_by_name (item_parent, "activate_current",  
+                         /*force_hide*/ 1); 
+  if (!item_mapped)
+    ensure_menus_unposted (menu_item);
+
+  g_object_unref (menu_item);
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gint
+gail_menu_item_get_n_actions (AtkAction *action)
+{
+  /*
+   * Menu item has 1 action
+   */
+  return 1;
+}
+
+static G_CONST_RETURN gchar*
+gail_menu_item_get_description (AtkAction *action,
+                                gint      i)
+{
+  if (i == 0)
+    {
+      GailMenuItem *item;
+
+      item = GAIL_MENU_ITEM (action);
+      return item->click_description;
+    }
+  else
+    return NULL;
+}
+
+static G_CONST_RETURN gchar*
+gail_menu_item_get_name (AtkAction *action,
+                         gint      i)
+{
+  if (i == 0)
+    return "click";
+  else
+    return NULL;
+}
+
+static G_CONST_RETURN gchar*
+gail_menu_item_get_keybinding (AtkAction *action,
+                               gint      i)
+{
+  /*
+   * This function returns a string of the form A;B;C where
+   * A is the keybinding for the widget; B is the keybinding to traverse
+   * from the menubar and C is the accelerator.
+   * The items in the keybinding to traverse from the menubar are separated
+   * by ":".
+   */
+  GailMenuItem  *gail_menu_item;
+  gchar *keybinding = NULL;
+  gchar *item_keybinding = NULL;
+  gchar *full_keybinding = NULL;
+  gchar *accelerator = NULL;
+
+  gail_menu_item = GAIL_MENU_ITEM (action);
+  if (i == 0)
+    {
+      GtkWidget *item;
+      GtkWidget *temp_item;
+      GtkWidget *child;
+      GtkWidget *parent;
+
+      item = GTK_ACCESSIBLE (action)->widget;
+      if (item == NULL)
+        /* State is defunct */
+        return NULL;
+
+      temp_item = item;
+      while (TRUE)
+        {
+          GdkModifierType mnemonic_modifier = 0;
+          guint key_val;
+          gchar *key, *temp_keybinding;
+
+          child = gtk_bin_get_child (GTK_BIN (temp_item));
+          if (child == NULL)
+            {
+              /* Possibly a tear off menu item; it could also be a menu 
+               * separator generated by gtk_item_factory_create_items()
+               */
+              return NULL;
+            }
+          parent = gtk_widget_get_parent (temp_item);
+          if (!parent)
+            {
+              /*
+               * parent can be NULL when activating a window from the panel
+               */
+              return NULL;
+            }
+          g_return_val_if_fail (GTK_IS_MENU_SHELL (parent), NULL);
+          if (GTK_IS_MENU_BAR (parent))
+            {
+              GtkWidget *toplevel;
+
+              toplevel = gtk_widget_get_toplevel (parent);
+              if (toplevel && GTK_IS_WINDOW (toplevel))
+                mnemonic_modifier = gtk_window_get_mnemonic_modifier (
+                                       GTK_WINDOW (toplevel));
+            }
+          if (GTK_IS_LABEL (child))
+            {
+              key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (child));
+              if (key_val != GDK_VoidSymbol)
+                {
+                  key = gtk_accelerator_name (key_val, mnemonic_modifier);
+                  if (full_keybinding)
+                    temp_keybinding = g_strconcat (key, ":", full_keybinding, NULL);
+                  else 
+                    temp_keybinding = g_strconcat (key, NULL);
+                  if (temp_item == item)
+                    {
+                      item_keybinding = g_strdup (key); 
+                    }
+                  g_free (key);
+                  g_free (full_keybinding);
+                  full_keybinding = temp_keybinding;
+                }
+              else
+                {
+                  /* No keybinding */
+                  g_free (full_keybinding);
+                  full_keybinding = NULL;
+                  break;
+                }        
+            }        
+          if (GTK_IS_MENU_BAR (parent))
+            /* We have reached the menu bar so we are finished */
+            break;
+          g_return_val_if_fail (GTK_IS_MENU (parent), NULL);
+          temp_item = gtk_menu_get_attach_widget (GTK_MENU (parent));
+          if (!GTK_IS_MENU_ITEM (temp_item))
+            {
+              /* 
+               * Menu is attached to something other than a menu item;
+               * probably an option menu
+               */
+              g_free (full_keybinding);
+              full_keybinding = NULL;
+              break;
+            }
+        }
+
+      parent = gtk_widget_get_parent (item);
+      if (GTK_IS_MENU (parent))
+        {
+          GtkAccelGroup *group; 
+          GtkAccelKey *key;
+
+          group = gtk_menu_get_accel_group (GTK_MENU (parent));
+
+          if (group)
+            {
+              key = gtk_accel_group_find (group, find_accel, item);
+            }
+          else
+            {
+              /*
+               * If the menu item is created using GtkAction and GtkUIManager
+               * we get here.
+               */
+              key = NULL;
+              child = GTK_BIN (item)->child;
+              if (GTK_IS_ACCEL_LABEL (child))
+                {
+                  GtkAccelLabel *accel_label;
+
+                  accel_label = GTK_ACCEL_LABEL (child);
+                  if (accel_label->accel_closure)
+                    {
+                      key = gtk_accel_group_find (accel_label->accel_group,
+                                                  find_accel_new,
+                                                  accel_label->accel_closure);
+                    }
+               
+                }
+            }
+
+          if (key)
+            {           
+              accelerator = gtk_accelerator_name (key->accel_key,
+                                                  key->accel_mods);
+            }
+        }
+    }
+  /*
+   * Concatenate the bindings
+   */
+  if (item_keybinding || full_keybinding || accelerator)
+    {
+      gchar *temp;
+      if (item_keybinding)
+        {
+          keybinding = g_strconcat (item_keybinding, KEYBINDING_SEPARATOR, NULL);
+          g_free (item_keybinding);
+        }
+      else
+        keybinding = g_strconcat (KEYBINDING_SEPARATOR, NULL);
+
+      if (full_keybinding)
+        {
+          temp = g_strconcat (keybinding, full_keybinding, 
+                              KEYBINDING_SEPARATOR, NULL);
+          g_free (full_keybinding);
+        }
+      else
+        temp = g_strconcat (keybinding, KEYBINDING_SEPARATOR, NULL);
+
+      g_free (keybinding);
+      keybinding = temp;
+      if (accelerator)
+        {
+          temp = g_strconcat (keybinding, accelerator, NULL);
+          g_free (accelerator);
+          g_free (keybinding);
+          keybinding = temp;
+      }
+    }
+  g_free (gail_menu_item->click_keybinding);
+  gail_menu_item->click_keybinding = keybinding;
+  return keybinding;
+}
+
+static gboolean
+gail_menu_item_set_description (AtkAction      *action,
+                                gint           i,
+                                const gchar    *desc)
+{
+  if (i == 0)
+    {
+      GailMenuItem *item;
+
+      item = GAIL_MENU_ITEM (action);
+      g_free (item->click_description);
+      item->click_description = g_strdup (desc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void
+gail_menu_item_finalize (GObject *object)
+{
+  GailMenuItem *menu_item = GAIL_MENU_ITEM (object);
+
+  g_free (menu_item->click_keybinding);
+  g_free (menu_item->click_description);
+  if (menu_item->action_idle_handler)
+    {
+      g_source_remove (menu_item->action_idle_handler);
+      menu_item->action_idle_handler = 0;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+menu_item_select (GtkItem *item)
+{
+  menu_item_selection (item, TRUE);
+}
+
+static void
+menu_item_deselect (GtkItem *item)
+{
+  menu_item_selection (item, FALSE);
+}
+
+static void
+menu_item_selection (GtkItem  *item,
+                     gboolean selected)
+{
+  AtkObject *obj, *parent;
+
+  obj = gtk_widget_get_accessible (GTK_WIDGET (item));
+  atk_object_notify_state_change (obj, ATK_STATE_SELECTED, selected);
+  parent = atk_object_get_parent (obj);
+  g_signal_emit_by_name (parent, "selection_changed"); 
+}
+
+static gboolean
+find_accel (GtkAccelKey *key,
+            GClosure    *closure,
+            gpointer     data)
+{
+  /*
+   * We assume that closure->data points to the widget
+   * pending gtk_widget_get_accel_closures being made public
+   */
+  return data == (gpointer) closure->data;
+}
+
+static gboolean
+find_accel_new (GtkAccelKey *key,
+                GClosure    *closure,
+                gpointer     data)
+{
+  return data == (gpointer) closure;
+}
diff --git a/modules/other/gail/gailmenuitem.h b/modules/other/gail/gailmenuitem.h
new file mode 100644 (file)
index 0000000..a7e0f64
--- /dev/null
@@ -0,0 +1,64 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_MENU_ITEM_H__
+#define __GAIL_MENU_ITEM_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailitem.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_MENU_ITEM                     (gail_menu_item_get_type ())
+#define GAIL_MENU_ITEM(obj)                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_MENU_ITEM, GailMenuItem))
+#define GAIL_MENU_ITEM_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_MENU_ITEM, GailMenuItemClass))
+#define GAIL_IS_MENU_ITEM(obj)                  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_MENU_ITEM))
+#define GAIL_IS_MENU_ITEM_CLASS(klass)          (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_MENU_ITEM))
+#define GAIL_MENU_ITEM_GET_CLASS(obj)           (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_MENU_ITEM, GailMenuItemClass))
+
+typedef struct _GailMenuItem                   GailMenuItem;
+typedef struct _GailMenuItemClass              GailMenuItemClass;
+
+struct _GailMenuItem
+{
+  GailItem parent;
+
+  gchar    *click_keybinding;
+  gchar    *click_description;
+  guint    action_idle_handler;
+};
+
+GType gail_menu_item_get_type (void);
+
+struct _GailMenuItemClass
+{
+  GailItemClass parent_class;
+};
+
+AtkObject* gail_menu_item_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_MENU_ITEM_H__ */
diff --git a/modules/other/gail/gailmenushell.c b/modules/other/gail/gailmenushell.c
new file mode 100644 (file)
index 0000000..53ae7c5
--- /dev/null
@@ -0,0 +1,281 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailmenushell.h"
+
+static void         gail_menu_shell_class_init          (GailMenuShellClass *klass);
+
+static void         atk_selection_interface_init        (AtkSelectionIface  *iface);
+static gboolean     gail_menu_shell_add_selection       (AtkSelection   *selection,
+                                                         gint           i);
+static gboolean     gail_menu_shell_clear_selection     (AtkSelection   *selection);
+static AtkObject*   gail_menu_shell_ref_selection       (AtkSelection   *selection,
+                                                         gint           i);
+static gint         gail_menu_shell_get_selection_count (AtkSelection   *selection);
+static gboolean     gail_menu_shell_is_child_selected   (AtkSelection   *selection,
+                                                         gint           i);
+static gboolean     gail_menu_shell_remove_selection    (AtkSelection   *selection,
+                                                         gint           i);
+
+GType
+gail_menu_shell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailMenuShellClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_menu_shell_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailMenuShell), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    static const GInterfaceInfo atk_selection_info =
+    {
+        (GInterfaceInitFunc) atk_selection_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                   "GailMenuShell", &tinfo, 0);
+    g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                 &atk_selection_info);
+  }
+
+  return type;
+}
+
+static void
+gail_menu_shell_class_init (GailMenuShellClass *klass)
+{
+}
+
+AtkObject*
+gail_menu_shell_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_MENU_SHELL, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  if (GTK_IS_MENU_BAR (widget))
+    accessible->role = ATK_ROLE_MENU_BAR;
+  else
+    /*
+     * Accessible object for Menu is created in gailmenu.c
+     */
+    accessible->role = ATK_ROLE_UNKNOWN;
+
+  return accessible;
+}
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->add_selection = gail_menu_shell_add_selection;
+  iface->clear_selection = gail_menu_shell_clear_selection;
+  iface->ref_selection = gail_menu_shell_ref_selection;
+  iface->get_selection_count = gail_menu_shell_get_selection_count;
+  iface->is_child_selected = gail_menu_shell_is_child_selected;
+  iface->remove_selection = gail_menu_shell_remove_selection;
+  /*
+   * select_all_selection does not make sense for a menu_shell
+   * so no implementation is provided.
+   */
+}
+
+static gboolean
+gail_menu_shell_add_selection (AtkSelection *selection,
+                               gint          i)
+{
+  GtkMenuShell *shell;
+  GList *item;
+  guint length;
+  GtkWidget *widget;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return FALSE;
+  }
+
+  shell = GTK_MENU_SHELL (widget);
+  length = g_list_length (shell->children);
+  if (i < 0 || i > length)
+    return FALSE;
+
+  item = g_list_nth (shell->children, i);
+  g_return_val_if_fail (item != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_MENU_ITEM(item->data), FALSE);
+   
+  gtk_menu_shell_select_item (shell, GTK_WIDGET (item->data));
+  return TRUE;
+}
+
+static gboolean
+gail_menu_shell_clear_selection (AtkSelection   *selection)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return FALSE;
+  }
+
+  shell = GTK_MENU_SHELL (widget);
+
+  gtk_menu_shell_deselect (shell);
+  return TRUE;
+}
+
+static AtkObject*
+gail_menu_shell_ref_selection (AtkSelection   *selection,
+                               gint           i)
+{
+  GtkMenuShell *shell;
+  AtkObject *obj;
+  GtkWidget *widget;
+
+  if (i != 0)
+    return NULL;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return NULL;
+  }
+
+  shell = GTK_MENU_SHELL (widget);
+  
+  if (shell->active_menu_item != NULL)
+  {
+    obj = gtk_widget_get_accessible (shell->active_menu_item);
+    g_object_ref (obj);
+    return obj;
+  }
+  else
+  {
+    return NULL;
+  }
+}
+
+static gint
+gail_menu_shell_get_selection_count (AtkSelection   *selection)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return 0;
+  }
+
+  shell = GTK_MENU_SHELL (widget);
+
+  /*
+   * Identifies the currently selected menu item
+   */
+  if (shell->active_menu_item == NULL)
+  {
+    return 0;
+  }
+  else
+  {
+    return 1;
+  }
+}
+
+static gboolean
+gail_menu_shell_is_child_selected (AtkSelection   *selection,
+                                   gint           i)
+{
+  GtkMenuShell *shell;
+  gint j;
+  GtkWidget *widget;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return FALSE;
+  }
+
+  shell = GTK_MENU_SHELL (widget);
+  if (shell->active_menu_item == NULL)
+    return FALSE;
+  
+  j = g_list_index (shell->children, shell->active_menu_item);
+
+  return (j==i);   
+}
+
+static gboolean
+gail_menu_shell_remove_selection (AtkSelection   *selection,
+                                  gint           i)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+
+  if (i != 0)
+    return FALSE;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return FALSE;
+  }
+
+  shell = GTK_MENU_SHELL (widget);
+
+  if (shell->active_menu_item && 
+      GTK_MENU_ITEM (shell->active_menu_item)->submenu)
+  {
+    /*
+     * Menu item contains a menu and it is the selected menu item
+     * so deselect it.
+     */
+    gtk_menu_shell_deselect (shell);
+  }
+  return TRUE;
+}
diff --git a/modules/other/gail/gailmenushell.h b/modules/other/gail/gailmenushell.h
new file mode 100644 (file)
index 0000000..a44aa88
--- /dev/null
@@ -0,0 +1,60 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_MENU_SHELL_H__
+#define __GAIL_MENU_SHELL_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_MENU_SHELL                    (gail_menu_shell_get_type ())
+#define GAIL_MENU_SHELL(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_MENU_SHELL, GailMenuShell))
+#define GAIL_MENU_SHELL_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_MENU_SHELL, GailMenuShellClass))
+#define GAIL_IS_MENU_SHELL(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_MENU_SHELL))
+#define GAIL_IS_MENU_SHELL_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_MENU_SHELL))
+#define GAIL_MENU_SHELL_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_MENU_SHELL, GailMenuShellClass))
+
+typedef struct _GailMenuShell                   GailMenuShell;
+typedef struct _GailMenuShellClass              GailMenuShellClass;
+
+struct _GailMenuShell
+{
+  GailContainer parent;
+};
+
+GType gail_menu_shell_get_type (void);
+
+struct _GailMenuShellClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_menu_shell_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_MENU_SHELL_H__ */
diff --git a/modules/other/gail/gailnotebook.c b/modules/other/gail/gailnotebook.c
new file mode 100644 (file)
index 0000000..1e60ac4
--- /dev/null
@@ -0,0 +1,655 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailnotebook.h"
+#include "gailnotebookpage.h"
+#include "gail-private-macros.h"
+
+static void         gail_notebook_class_init          (GailNotebookClass *klass);
+static void         gail_notebook_object_init         (GailNotebook      *notebook);
+static void         gail_notebook_finalize            (GObject           *object);
+static void         gail_notebook_real_initialize     (AtkObject         *obj,
+                                                       gpointer          data);
+
+static void         gail_notebook_real_notify_gtk     (GObject           *obj,
+                                                       GParamSpec        *pspec);
+
+static AtkObject*   gail_notebook_ref_child           (AtkObject      *obj,
+                                                       gint           i);
+static gint         gail_notebook_real_remove_gtk     (GtkContainer   *container,
+                                                       GtkWidget      *widget,
+                                                       gpointer       data);    
+static void         atk_selection_interface_init      (AtkSelectionIface *iface);
+static gboolean     gail_notebook_add_selection       (AtkSelection   *selection,
+                                                       gint           i);
+static AtkObject*   gail_notebook_ref_selection       (AtkSelection   *selection,
+                                                       gint           i);
+static gint         gail_notebook_get_selection_count (AtkSelection   *selection);
+static gboolean     gail_notebook_is_child_selected   (AtkSelection   *selection,
+                                                       gint           i);
+static AtkObject*   find_child_in_list                (GList          *list,
+                                                       gint           index);
+static void         check_cache                       (GailNotebook   *gail_notebook,
+                                                       GtkNotebook    *notebook);
+static void         reset_cache                       (GailNotebook   *gail_notebook,
+                                                       gint           index);
+static void         create_notebook_page_accessible   (GailNotebook   *gail_notebook,
+                                                       GtkNotebook    *notebook,
+                                                       gint           index,
+                                                       gboolean       insert_before,
+                                                       GList          *list);
+static void         gail_notebook_child_parent_set    (GtkWidget      *widget,
+                                                       GtkWidget      *old_parent,
+                                                       gpointer       data);
+static gboolean     gail_notebook_focus_cb            (GtkWidget      *widget,
+                                                       GtkDirectionType type);
+static gboolean     gail_notebook_check_focus_tab     (gpointer       data);
+static void         gail_notebook_destroyed           (gpointer       data);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_notebook_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailNotebookClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_notebook_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailNotebook), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_notebook_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_selection_info = 
+      {
+        (GInterfaceInitFunc) atk_selection_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+       
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailNotebook", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                   &atk_selection_info);
+    }
+  return type;
+}
+
+static void
+gail_notebook_class_init (GailNotebookClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+  GailContainerClass *container_class;
+
+  widget_class = (GailWidgetClass*)klass;
+  container_class = (GailContainerClass*)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+  
+  gobject_class->finalize = gail_notebook_finalize;
+
+  widget_class->notify_gtk = gail_notebook_real_notify_gtk;
+
+  class->ref_child = gail_notebook_ref_child;
+  class->initialize = gail_notebook_real_initialize;
+  /*
+   * We do not provide an implementation of get_n_children
+   * as the implementation in GailContainer returns the correct
+   * number of children.
+   */
+  container_class->remove_gtk = gail_notebook_real_remove_gtk;
+}
+
+static void
+gail_notebook_object_init (GailNotebook      *notebook)
+{
+  notebook->page_cache = NULL;
+  notebook->selected_page = -1;
+  notebook->focus_tab_page = -1;
+  notebook->remove_index = -1;
+  notebook->idle_focus_id = 0;
+}
+
+AtkObject* 
+gail_notebook_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_NOTEBOOK, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static AtkObject*
+gail_notebook_ref_child (AtkObject      *obj,
+                         gint           i)
+{
+  AtkObject *accessible = NULL;
+  GailNotebook *gail_notebook;
+  GtkNotebook *gtk_notebook;
+  GtkWidget *widget;
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  gail_notebook = GAIL_NOTEBOOK (obj);
+  
+  gtk_notebook = GTK_NOTEBOOK (widget);
+  
+  if (gail_notebook->page_count < g_list_length (gtk_notebook->children))
+    check_cache (gail_notebook, gtk_notebook);
+
+  accessible = find_child_in_list (gail_notebook->page_cache, i);
+
+  if (accessible != NULL)
+    g_object_ref (accessible);
+
+  return accessible;
+}
+
+static void
+gail_notebook_page_added (GtkNotebook *gtk_notebook,
+                          GtkWidget   *child,
+                          guint        page_num,
+                          gpointer     data)
+{
+  AtkObject *atk_obj;
+  GailNotebook *notebook;
+
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (gtk_notebook));
+  notebook = GAIL_NOTEBOOK (atk_obj);
+  create_notebook_page_accessible (notebook, gtk_notebook, page_num, FALSE, NULL);
+}
+
+static void
+gail_notebook_real_initialize (AtkObject *obj,
+                               gpointer  data)
+{
+  GailNotebook *notebook;
+  GtkNotebook *gtk_notebook;
+  gint i;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  notebook = GAIL_NOTEBOOK (obj);
+  gtk_notebook = GTK_NOTEBOOK (data);
+  for (i = 0; i < g_list_length (gtk_notebook->children); i++)
+    {
+      create_notebook_page_accessible (notebook, gtk_notebook, i, FALSE, NULL);
+    }
+  notebook->page_count = i;
+  notebook->selected_page = gtk_notebook_get_current_page (gtk_notebook);
+  if (gtk_notebook->focus_tab && gtk_notebook->focus_tab->data)
+    {
+      notebook->focus_tab_page = g_list_index (gtk_notebook->children, gtk_notebook->focus_tab->data);
+    }
+  g_signal_connect (gtk_notebook,
+                    "focus",
+                    G_CALLBACK (gail_notebook_focus_cb),
+                    NULL);
+  g_signal_connect (gtk_notebook,
+                    "page-added",
+                    G_CALLBACK (gail_notebook_page_added),
+                    NULL);
+  g_object_weak_ref (G_OBJECT(gtk_notebook),
+                     (GWeakNotify) gail_notebook_destroyed,
+                     obj);                     
+
+  obj->role = ATK_ROLE_PAGE_TAB_LIST;
+}
+
+static void
+gail_notebook_real_notify_gtk (GObject           *obj,
+                               GParamSpec        *pspec)
+{
+  GtkWidget *widget;
+  AtkObject* atk_obj;
+
+  widget = GTK_WIDGET (obj);
+  atk_obj = gtk_widget_get_accessible (widget);
+
+  if (strcmp (pspec->name, "page") == 0)
+    {
+      gint page_num, old_page_num;
+      gint focus_page_num = 0;
+      gint old_focus_page_num;
+      GailNotebook *gail_notebook;
+      GtkNotebook *gtk_notebook;
+     
+      gail_notebook = GAIL_NOTEBOOK (atk_obj);
+      gtk_notebook = GTK_NOTEBOOK (widget);
+     
+      if (gail_notebook->page_count < g_list_length (gtk_notebook->children))
+       check_cache (gail_notebook, gtk_notebook);
+      /*
+       * Notify SELECTED state change for old and new page
+       */
+      old_page_num = gail_notebook->selected_page;
+      page_num = gtk_notebook_get_current_page (gtk_notebook);
+      gail_notebook->selected_page = page_num;
+      old_focus_page_num = gail_notebook->focus_tab_page;
+      if (gtk_notebook->focus_tab && gtk_notebook->focus_tab->data)
+        {
+          focus_page_num = g_list_index (gtk_notebook->children, gtk_notebook->focus_tab->data);
+          gail_notebook->focus_tab_page = focus_page_num;
+        }
+    
+      if (page_num != old_page_num)
+        {
+          AtkObject *obj;
+
+          if (old_page_num != -1)
+            {
+              obj = gail_notebook_ref_child (atk_obj, old_page_num);
+              if (obj)
+                {
+                  atk_object_notify_state_change (obj,
+                                                  ATK_STATE_SELECTED,
+                                                  FALSE);
+                  g_object_unref (obj);
+                }
+            }
+          obj = gail_notebook_ref_child (atk_obj, page_num);
+          if (obj)
+            {
+              atk_object_notify_state_change (obj,
+                                              ATK_STATE_SELECTED,
+                                              TRUE);
+              g_object_unref (obj);
+              /*
+               * The page which is being displayed has changed but there is
+               * no need to tell the focus tracker as the focus page will also 
+               * change or a widget in the page will receive focus if the
+               * Notebook does not have tabs.
+               */
+            }
+          g_signal_emit_by_name (atk_obj, "selection_changed");
+          g_signal_emit_by_name (atk_obj, "visible_data_changed");
+        }
+      if (gtk_notebook_get_show_tabs (gtk_notebook) &&
+         (focus_page_num != old_focus_page_num))
+        {
+          if (gail_notebook->idle_focus_id)
+            g_source_remove (gail_notebook->idle_focus_id);
+          gail_notebook->idle_focus_id = g_idle_add (gail_notebook_check_focus_tab, atk_obj);
+        }
+    }
+  else
+    GAIL_WIDGET_CLASS (parent_class)->notify_gtk (obj, pspec);
+}
+
+static void
+gail_notebook_finalize (GObject            *object)
+{
+  GailNotebook *notebook = GAIL_NOTEBOOK (object);
+  GList *list;
+
+  /*
+   * Get rid of the GailNotebookPage objects which we have cached.
+   */
+  list = notebook->page_cache;
+  if (list != NULL)
+    {
+      while (list)
+        {
+          g_object_unref (list->data);
+          list = list->next;
+        }
+    }
+
+  g_list_free (notebook->page_cache);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  
+  iface->add_selection = gail_notebook_add_selection;
+  iface->ref_selection = gail_notebook_ref_selection;
+  iface->get_selection_count = gail_notebook_get_selection_count;
+  iface->is_child_selected = gail_notebook_is_child_selected;
+  /*
+   * The following don't make any sense for GtkNotebook widgets.
+   * Unsupported AtkSelection interfaces:
+   * clear_selection();
+   * remove_selection();
+   * select_all_selection();
+   */
+}
+
+/*
+ * GtkNotebook only supports the selection of one page at a time. 
+ * Selecting a page unselects any previous selection, so this 
+ * changes the current selection instead of adding to it.
+ */
+static gboolean
+gail_notebook_add_selection (AtkSelection *selection,
+                             gint         i)
+{
+  GtkNotebook *notebook;
+  GtkWidget *widget;
+  
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+  
+  notebook = GTK_NOTEBOOK (widget);
+  gtk_notebook_set_current_page (notebook, i);
+  return TRUE;
+}
+
+static AtkObject*
+gail_notebook_ref_selection (AtkSelection *selection,
+                             gint i)
+{
+  AtkObject *accessible;
+  GtkWidget *widget;
+  GtkNotebook *notebook;
+  gint pagenum;
+  
+  /*
+   * A note book can have only one selection.
+   */
+  gail_return_val_if_fail (i == 0, NULL);
+  g_return_val_if_fail (GAIL_IS_NOTEBOOK (selection), NULL);
+  
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+       return NULL;
+  
+  notebook = GTK_NOTEBOOK (widget);
+  pagenum = gtk_notebook_get_current_page (notebook);
+  gail_return_val_if_fail (pagenum != -1, NULL);
+  accessible = gail_notebook_ref_child (ATK_OBJECT (selection), pagenum);
+
+  return accessible;
+}
+
+/*
+ * Always return 1 because there can only be one page
+ * selected at any time
+ */
+static gint
+gail_notebook_get_selection_count (AtkSelection *selection)
+{
+  GtkWidget *widget;
+  GtkNotebook *notebook;
+  
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  notebook = GTK_NOTEBOOK (widget);
+  if (notebook == NULL)
+    return 0;
+  else
+    return 1;
+}
+
+static gboolean
+gail_notebook_is_child_selected (AtkSelection *selection,
+                                 gint i)
+{
+  GtkWidget *widget;
+  GtkNotebook *notebook;
+  gint pagenumber;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* 
+     * State is defunct
+     */
+    return FALSE;
+
+  
+  notebook = GTK_NOTEBOOK (widget);
+  pagenumber = gtk_notebook_get_current_page(notebook);
+
+  if (pagenumber == i)
+    return TRUE;
+  else
+    return FALSE; 
+}
+
+static AtkObject*
+find_child_in_list (GList *list,
+                    gint  index)
+{
+  AtkObject *obj = NULL;
+
+  while (list)
+    {
+      if (GAIL_NOTEBOOK_PAGE (list->data)->index == index)
+        {
+          obj = ATK_OBJECT (list->data);
+          break;
+        }
+      list = list->next;
+    }
+  return obj;
+}
+
+static void
+check_cache (GailNotebook *gail_notebook,
+             GtkNotebook  *notebook)
+{
+  GList *gtk_list;
+  GList *gail_list;
+  gint i;
+
+  gtk_list = notebook->children;
+  gail_list = gail_notebook->page_cache;
+
+  i = 0;
+  while (gtk_list)
+    {
+      if (!gail_list)
+        {
+          create_notebook_page_accessible (gail_notebook, notebook, i, FALSE, NULL);
+        }
+      else if (GAIL_NOTEBOOK_PAGE (gail_list->data)->page != gtk_list->data)
+        {
+          create_notebook_page_accessible (gail_notebook, notebook, i, TRUE, gail_list);
+        }
+      else
+        {
+          gail_list = gail_list->next;
+        }
+      i++;
+      gtk_list = gtk_list->next;
+    }
+  gail_notebook->page_count = i;
+}
+
+static void
+reset_cache (GailNotebook *gail_notebook,
+             gint         index)
+{
+  GList *l;
+
+  for (l = gail_notebook->page_cache; l; l = l->next)
+    {
+      if (GAIL_NOTEBOOK_PAGE (l->data)->index > index)
+        GAIL_NOTEBOOK_PAGE (l->data)->index -= 1;
+    }
+}
+
+static void
+create_notebook_page_accessible (GailNotebook *gail_notebook,
+                                 GtkNotebook  *notebook,
+                                 gint         index,
+                                 gboolean     insert_before,
+                                 GList        *list)
+{
+  AtkObject *obj;
+
+  obj = gail_notebook_page_new (notebook, index);
+  g_object_ref (obj);
+  if (insert_before)
+    gail_notebook->page_cache = g_list_insert_before (gail_notebook->page_cache, list, obj);
+  else
+    gail_notebook->page_cache = g_list_append (gail_notebook->page_cache, obj);
+  g_signal_connect (gtk_notebook_get_nth_page (notebook, index), 
+                    "parent_set",
+                    G_CALLBACK (gail_notebook_child_parent_set),
+                    obj);
+}
+
+static void
+gail_notebook_child_parent_set (GtkWidget *widget,
+                                GtkWidget *old_parent,
+                                gpointer   data)
+{
+  GailNotebook *gail_notebook;
+
+  gail_return_if_fail (old_parent != NULL);
+  gail_notebook = GAIL_NOTEBOOK (gtk_widget_get_accessible (old_parent));
+  gail_notebook->remove_index = GAIL_NOTEBOOK_PAGE (data)->index;
+}
+
+static gint
+gail_notebook_real_remove_gtk (GtkContainer *container,
+                               GtkWidget    *widget,
+                               gpointer      data)    
+{
+  GailNotebook *gail_notebook;
+  AtkObject *obj;
+  gint index;
+
+  g_return_val_if_fail (container != NULL, 1);
+  gail_notebook = GAIL_NOTEBOOK (gtk_widget_get_accessible (GTK_WIDGET (container)));
+  index = gail_notebook->remove_index;
+  gail_notebook->remove_index = -1;
+
+  obj = find_child_in_list (gail_notebook->page_cache, index);
+  g_return_val_if_fail (obj, 1);
+  gail_notebook->page_cache = g_list_remove (gail_notebook->page_cache, obj);
+  gail_notebook->page_count -= 1;
+  reset_cache (gail_notebook, index);
+  g_signal_emit_by_name (gail_notebook,
+                         "children_changed::remove",
+                          GAIL_NOTEBOOK_PAGE (obj)->index, 
+                          obj, NULL);
+  g_object_unref (obj);
+  return 1;
+}
+
+static gboolean
+gail_notebook_focus_cb (GtkWidget      *widget,
+                        GtkDirectionType type)
+{
+  AtkObject *atk_obj = gtk_widget_get_accessible (widget);
+  GailNotebook *gail_notebook = GAIL_NOTEBOOK (atk_obj);
+
+  switch (type)
+    {
+    case GTK_DIR_LEFT:
+    case GTK_DIR_RIGHT:
+      if (gail_notebook->idle_focus_id)
+        g_source_remove (gail_notebook->idle_focus_id);
+      gail_notebook->idle_focus_id = g_idle_add (gail_notebook_check_focus_tab, atk_obj);
+      break;
+    default:
+      break;
+    }
+  return FALSE;
+}
+
+static gboolean
+gail_notebook_check_focus_tab (gpointer data)
+{
+  GtkWidget *widget;
+  AtkObject *atk_obj;
+  gint focus_page_num, old_focus_page_num;
+  GailNotebook *gail_notebook;
+  GtkNotebook *gtk_notebook;
+
+  GDK_THREADS_ENTER ();
+
+  atk_obj = ATK_OBJECT (data);
+  gail_notebook = GAIL_NOTEBOOK (atk_obj);
+  widget = GTK_ACCESSIBLE (atk_obj)->widget;
+
+  gtk_notebook = GTK_NOTEBOOK (widget);
+
+  gail_notebook->idle_focus_id = 0;
+
+  if (!gtk_notebook->focus_tab)
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  old_focus_page_num = gail_notebook->focus_tab_page;
+  focus_page_num = g_list_index (gtk_notebook->children, gtk_notebook->focus_tab->data);
+  gail_notebook->focus_tab_page = focus_page_num;
+  if (old_focus_page_num != focus_page_num)
+    {
+      AtkObject *obj;
+
+      obj = atk_object_ref_accessible_child (atk_obj, focus_page_num);
+      atk_focus_tracker_notify (obj);
+      g_object_unref (obj);
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+gail_notebook_destroyed (gpointer data)
+{
+  GailNotebook *gail_notebook = GAIL_NOTEBOOK (data);
+
+  if (gail_notebook->idle_focus_id)
+    g_source_remove (gail_notebook->idle_focus_id);
+}
diff --git a/modules/other/gail/gailnotebook.h b/modules/other/gail/gailnotebook.h
new file mode 100644 (file)
index 0000000..ab17ff1
--- /dev/null
@@ -0,0 +1,73 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_NOTEBOOK_H__
+#define __GAIL_NOTEBOOK_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_NOTEBOOK                   (gail_notebook_get_type ())
+#define GAIL_NOTEBOOK(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_NOTEBOOK, GailNotebook))
+#define GAIL_NOTEBOOK_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_NOTEBOOK, GailNotebookClass))
+#define GAIL_IS_NOTEBOOK(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_NOTEBOOK))
+#define GAIL_IS_NOTEBOOK_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_NOTEBOOK))
+#define GAIL_NOTEBOOK_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_NOTEBOOK, GailNotebookClass))
+
+typedef struct _GailNotebook              GailNotebook;
+typedef struct _GailNotebookClass         GailNotebookClass;
+
+struct _GailNotebook
+{
+  GailContainer parent;
+  
+  /*
+   * page_cache maintains a list of pre-ref'd Notebook Pages.
+   * This cache is queried by gail_notebook_ref_child().
+   * If the page is found in the list then a new page does not
+   * need to be created
+   */
+  GList*       page_cache;
+  gint         selected_page;
+  gint         focus_tab_page;
+  gint         page_count;
+  guint        idle_focus_id;
+
+  gint         remove_index;
+};
+
+GType gail_notebook_get_type (void);
+
+struct _GailNotebookClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_notebook_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_NOTEBOOK_H__ */
diff --git a/modules/other/gail/gailnotebookpage.c b/modules/other/gail/gailnotebookpage.c
new file mode 100644 (file)
index 0000000..b830f91
--- /dev/null
@@ -0,0 +1,868 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailnotebookpage.h"
+#include <libgail-util/gailmisc.h>
+#include "gail-private-macros.h"
+
+static void      gail_notebook_page_class_init      (GailNotebookPageClass     *klass);
+
+static void                  gail_notebook_page_finalize       (GObject   *object);
+static void                  gail_notebook_page_label_map_gtk  (GtkWidget *widget,
+                                                                gpointer  data);
+
+static G_CONST_RETURN gchar* gail_notebook_page_get_name       (AtkObject *accessible);
+static AtkObject*            gail_notebook_page_get_parent     (AtkObject *accessible);
+static gint                  gail_notebook_page_get_n_children (AtkObject *accessible);
+static AtkObject*            gail_notebook_page_ref_child      (AtkObject *accessible,
+                                                                gint      i); 
+static gint                  gail_notebook_page_get_index_in_parent
+                                                               (AtkObject *accessible);
+static AtkStateSet*          gail_notebook_page_ref_state_set  (AtkObject *accessible);
+
+static gint                  gail_notebook_page_notify          (GObject   *obj,
+                                                                 GParamSpec *pspec,
+                                                                 gpointer   user_data);
+static void                  gail_notebook_page_init_textutil   (GailNotebookPage      *notebook_page,
+                                                                 GtkWidget             *label);
+
+static void                  atk_component_interface_init      (AtkComponentIface *iface);
+
+static AtkObject*            gail_notebook_page_ref_accessible_at_point 
+                                                               (AtkComponent *component,
+                                                                gint         x,
+                                                                gint         y,
+                                                                AtkCoordType coord_type);
+
+static void                  gail_notebook_page_get_extents    (AtkComponent *component,
+                                                                gint         *x,
+                                                                gint         *y,
+                                                                gint         *width,
+                                                                gint         *height,
+                                                                AtkCoordType coord_type);
+
+static AtkObject*            _gail_notebook_page_get_tab_label (GailNotebookPage *page);
+
+/* atktext.h */ 
+static void      atk_text_interface_init          (AtkTextIface        *iface);
+
+static gchar*    gail_notebook_page_get_text      (AtkText           *text,
+                                                    gint             start_pos,
+                                                   gint              end_pos);
+static gunichar          gail_notebook_page_get_character_at_offset
+                                                   (AtkText          *text,
+                                                   gint              offset);
+static gchar*     gail_notebook_page_get_text_before_offset
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_notebook_page_get_text_at_offset
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_notebook_page_get_text_after_offset
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gint      gail_notebook_page_get_character_count (AtkText             *text);
+static void       gail_notebook_page_get_character_extents
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   gint              *x,
+                                                   gint              *y,
+                                                   gint              *width,
+                                                   gint              *height,
+                                                   AtkCoordType      coords);
+static gint      gail_notebook_page_get_offset_at_point
+                                                   (AtkText           *text,
+                                                    gint              x,
+                                                    gint              y,
+                                                   AtkCoordType      coords);
+static AtkAttributeSet* gail_notebook_page_get_run_attributes 
+                                                   (AtkText           *text,
+                                                   gint              offset,
+                                                    gint             *start_offset,
+                                                   gint              *end_offset);
+static AtkAttributeSet* gail_notebook_page_get_default_attributes
+                                                   (AtkText           *text);
+static GtkWidget* get_label_from_notebook_page     (GailNotebookPage  *page);
+static GtkWidget* find_label_child (GtkContainer *container);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_notebook_page_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo = 
+      {
+        sizeof (GailNotebookPageClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_notebook_page_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailNotebookPage), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+       
+      static const GInterfaceInfo atk_component_info =
+      {
+        (GInterfaceInitFunc) atk_component_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (ATK_TYPE_OBJECT,
+                                     "GailNotebookPage", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+                                   &atk_component_info);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+    }
+  return type;
+}
+
+static void
+gail_notebook_page_class_init (GailNotebookPageClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+  
+  class->get_name = gail_notebook_page_get_name;
+  class->get_parent = gail_notebook_page_get_parent;
+  class->get_n_children = gail_notebook_page_get_n_children;
+  class->ref_child = gail_notebook_page_ref_child;
+  class->ref_state_set = gail_notebook_page_ref_state_set;
+  class->get_index_in_parent = gail_notebook_page_get_index_in_parent;
+
+  gobject_class->finalize = gail_notebook_page_finalize;
+}
+
+static gint
+notify_child_added (gpointer data)
+{
+  GailNotebookPage *page;
+  AtkObject *atk_object, *atk_parent;
+
+  GDK_THREADS_ENTER ();
+
+  g_return_val_if_fail (GAIL_IS_NOTEBOOK_PAGE (data), FALSE);
+  page = GAIL_NOTEBOOK_PAGE (data);
+  atk_object = ATK_OBJECT (data);
+
+  /* The widget page->notebook may be deleted before this handler is called */
+  if (page->notebook != NULL)
+    {
+      atk_parent = gtk_widget_get_accessible (GTK_WIDGET (page->notebook));
+      atk_object_set_parent (atk_object, atk_parent);
+      g_signal_emit_by_name (atk_parent, "children_changed::add", page->index, atk_object, NULL);
+    }
+  
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+AtkObject*
+gail_notebook_page_new (GtkNotebook *notebook, 
+                        gint        pagenum)
+{
+  GObject *object;
+  AtkObject *atk_object;
+  GailNotebookPage *page;
+  GtkWidget *child;
+  GtkWidget *label;
+  GList *list;
+  
+  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
+
+  child = gtk_notebook_get_nth_page (notebook, pagenum);
+
+  if (!child)
+    return NULL;
+
+  object = g_object_new (GAIL_TYPE_NOTEBOOK_PAGE, NULL);
+  g_return_val_if_fail (object != NULL, NULL);
+
+  page = GAIL_NOTEBOOK_PAGE (object);
+  page->notebook = notebook;
+  g_object_add_weak_pointer (G_OBJECT (page->notebook), (gpointer *)&page->notebook);
+  page->index = pagenum;
+  list = g_list_nth (notebook->children, pagenum);
+  page->page = list->data;
+  page->textutil = NULL;
+  
+  atk_object = ATK_OBJECT (page);
+  atk_object->role = ATK_ROLE_PAGE_TAB;
+  atk_object->layer = ATK_LAYER_WIDGET;
+
+  g_idle_add (notify_child_added, atk_object);
+  /*
+   * We get notified of changes to the label
+   */
+  label = get_label_from_notebook_page (page);
+  if (GTK_IS_LABEL (label))
+    {
+      if (GTK_WIDGET_MAPPED (label))
+        gail_notebook_page_init_textutil (page, label);
+      else
+        g_signal_connect (label,
+                          "map",
+                          G_CALLBACK (gail_notebook_page_label_map_gtk),
+                          page);
+    }
+
+  return atk_object;
+}
+
+static void
+gail_notebook_page_label_map_gtk (GtkWidget *widget,
+                                  gpointer data)
+{
+  GailNotebookPage *page;
+
+  page = GAIL_NOTEBOOK_PAGE (data);
+  gail_notebook_page_init_textutil (page, widget);
+}
+
+static void
+gail_notebook_page_init_textutil (GailNotebookPage *page,
+                                  GtkWidget        *label)
+{
+  const gchar *label_text;
+
+  if (page->textutil == NULL)
+    {
+      page->textutil = gail_text_util_new ();
+      g_signal_connect (label,
+                        "notify",
+                        (GCallback) gail_notebook_page_notify,
+                        page);     
+    }
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  gail_text_util_text_setup (page->textutil, label_text);
+}
+
+static gint
+gail_notebook_page_notify (GObject    *obj, 
+                           GParamSpec *pspec,
+                           gpointer   user_data)
+{
+  AtkObject *atk_obj = ATK_OBJECT (user_data);
+  GtkLabel *label;
+  GailNotebookPage *page;
+
+  if (strcmp (pspec->name, "label") == 0)
+    {
+      const gchar* label_text;
+
+      label = GTK_LABEL (obj);
+
+      label_text = gtk_label_get_text (label);
+
+      page = GAIL_NOTEBOOK_PAGE (atk_obj);
+      gail_text_util_text_setup (page->textutil, label_text);
+
+      if (atk_obj->name == NULL)
+      {
+        /*
+         * The label has changed so notify a change in accessible-name
+         */
+        g_object_notify (G_OBJECT (atk_obj), "accessible-name");
+      }
+      /*
+       * The label is the only property which can be changed
+       */
+      g_signal_emit_by_name (atk_obj, "visible_data_changed");
+    }
+  return 1;
+}
+
+static void
+gail_notebook_page_finalize (GObject *object)
+{
+  GailNotebookPage *page = GAIL_NOTEBOOK_PAGE (object);
+
+  if (page->notebook)
+    g_object_remove_weak_pointer (G_OBJECT (page->notebook), (gpointer *)&page->notebook);
+
+  if (page->textutil)
+    g_object_unref (page->textutil);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+
+}
+
+static G_CONST_RETURN gchar*
+gail_notebook_page_get_name (AtkObject *accessible)
+{
+  g_return_val_if_fail (GAIL_IS_NOTEBOOK_PAGE (accessible), NULL);
+  
+  if (accessible->name != NULL)
+    return accessible->name;
+  else
+    {
+      GtkWidget *label;
+
+      label = get_label_from_notebook_page (GAIL_NOTEBOOK_PAGE (accessible));
+      if (GTK_IS_LABEL (label))
+        return gtk_label_get_text (GTK_LABEL (label));
+      else
+        return NULL;
+    }
+}
+
+static AtkObject*
+gail_notebook_page_get_parent (AtkObject *accessible)
+{
+  GailNotebookPage *page;
+  
+  g_return_val_if_fail (GAIL_IS_NOTEBOOK_PAGE (accessible), NULL);
+  
+  page = GAIL_NOTEBOOK_PAGE (accessible);
+
+  if (!page->notebook)
+    return NULL;
+
+  return gtk_widget_get_accessible (GTK_WIDGET (page->notebook));
+}
+
+static gint
+gail_notebook_page_get_n_children (AtkObject *accessible)
+{
+  /* Notebook page has only one child */
+  g_return_val_if_fail (GAIL_IS_NOTEBOOK_PAGE (accessible), 0);
+
+  return 1;
+}
+
+static AtkObject*
+gail_notebook_page_ref_child (AtkObject *accessible,
+                              gint i)
+{
+  GtkWidget *child;
+  AtkObject *child_obj;
+  GailNotebookPage *page = NULL;
+   
+  g_return_val_if_fail (GAIL_IS_NOTEBOOK_PAGE (accessible), NULL);
+  if (i != 0)
+    return NULL;
+   
+  page = GAIL_NOTEBOOK_PAGE (accessible);
+  if (!page->notebook)
+    return NULL;
+
+  child = gtk_notebook_get_nth_page (page->notebook, page->index);
+  gail_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
+   
+  child_obj = gtk_widget_get_accessible (child);
+  g_object_ref (child_obj);
+  return child_obj;
+}
+
+static gint
+gail_notebook_page_get_index_in_parent (AtkObject *accessible)
+{
+  GailNotebookPage *page;
+
+  g_return_val_if_fail (GAIL_IS_NOTEBOOK_PAGE (accessible), -1);
+  page = GAIL_NOTEBOOK_PAGE (accessible);
+
+  return page->index;
+}
+
+static AtkStateSet*
+gail_notebook_page_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set, *label_state_set, *merged_state_set;
+  AtkObject *atk_label;
+
+  g_return_val_if_fail (GAIL_NOTEBOOK_PAGE (accessible), NULL);
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+
+  atk_label = _gail_notebook_page_get_tab_label (GAIL_NOTEBOOK_PAGE (accessible));
+  if (atk_label)
+    {
+      label_state_set = atk_object_ref_state_set (atk_label);
+      merged_state_set = atk_state_set_or_sets (state_set, label_state_set);
+      g_object_unref (label_state_set);
+      g_object_unref (state_set);
+    }
+  else
+    {
+      AtkObject *child;
+
+      child = atk_object_ref_accessible_child (accessible, 0);
+      gail_return_val_if_fail (child, state_set);
+
+      merged_state_set = state_set;
+      state_set = atk_object_ref_state_set (child);
+      if (atk_state_set_contains_state (state_set, ATK_STATE_VISIBLE))
+        {
+          atk_state_set_add_state (merged_state_set, ATK_STATE_VISIBLE);
+          if (atk_state_set_contains_state (state_set, ATK_STATE_ENABLED))
+              atk_state_set_add_state (merged_state_set, ATK_STATE_ENABLED);
+          if (atk_state_set_contains_state (state_set, ATK_STATE_SHOWING))
+              atk_state_set_add_state (merged_state_set, ATK_STATE_SHOWING);
+
+        } 
+      g_object_unref (state_set);
+      g_object_unref (child);
+    }
+  return merged_state_set;
+}
+
+
+static void
+atk_component_interface_init (AtkComponentIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  /*
+   * We use the default implementations for contains, get_position, get_size
+   */
+  iface->ref_accessible_at_point = gail_notebook_page_ref_accessible_at_point;
+  iface->get_extents = gail_notebook_page_get_extents;
+}
+
+static AtkObject*
+gail_notebook_page_ref_accessible_at_point (AtkComponent *component,
+                                            gint         x,
+                                            gint         y,
+                                            AtkCoordType coord_type)
+{
+  /*
+   * There is only one child so we return it.
+   */
+  AtkObject* child;
+
+  g_return_val_if_fail (ATK_IS_OBJECT (component), NULL);
+
+  child = atk_object_ref_accessible_child (ATK_OBJECT (component), 0);
+  return child;
+}
+
+static void
+gail_notebook_page_get_extents (AtkComponent *component,
+                                gint         *x,
+                                gint         *y,
+                                gint         *width,
+                                gint         *height,
+                                AtkCoordType coord_type)
+{
+  AtkObject *atk_label;
+
+  g_return_if_fail (GAIL_IS_NOTEBOOK_PAGE (component));
+
+  atk_label = _gail_notebook_page_get_tab_label (GAIL_NOTEBOOK_PAGE (component));
+
+  if (!atk_label)
+    {
+      AtkObject *child;
+
+      *width = 0;
+      *height = 0;
+
+      child = atk_object_ref_accessible_child (ATK_OBJECT (component), 0);
+      gail_return_if_fail (child);
+
+      atk_component_get_position (ATK_COMPONENT (child), x, y, coord_type);
+      g_object_unref (child);
+    }
+  else
+    {
+      atk_component_get_extents (ATK_COMPONENT (atk_label), 
+                                 x, y, width, height, coord_type);
+    }
+  return; 
+}
+
+static AtkObject*
+_gail_notebook_page_get_tab_label (GailNotebookPage *page)
+{
+  GtkWidget *label;
+
+  label = get_label_from_notebook_page (page);
+  if (label)
+    return gtk_widget_get_accessible (label);
+  else
+    return NULL;
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->get_text = gail_notebook_page_get_text;
+  iface->get_character_at_offset = gail_notebook_page_get_character_at_offset;
+  iface->get_text_before_offset = gail_notebook_page_get_text_before_offset;
+  iface->get_text_at_offset = gail_notebook_page_get_text_at_offset;
+  iface->get_text_after_offset = gail_notebook_page_get_text_after_offset;
+  iface->get_character_count = gail_notebook_page_get_character_count;
+  iface->get_character_extents = gail_notebook_page_get_character_extents;
+  iface->get_offset_at_point = gail_notebook_page_get_offset_at_point;
+  iface->get_run_attributes = gail_notebook_page_get_run_attributes;
+  iface->get_default_attributes = gail_notebook_page_get_default_attributes;
+}
+
+static gchar*
+gail_notebook_page_get_text (AtkText *text,
+                             gint    start_pos,
+                             gint    end_pos)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  const gchar *label_text;
+
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL (label))
+    return NULL;
+
+  if (!notebook_page->textutil) 
+    gail_notebook_page_init_textutil (notebook_page, label);
+
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+
+  if (label_text == NULL)
+    return NULL;
+  else
+  {
+    return gail_text_util_get_substring (notebook_page->textutil, 
+                                         start_pos, end_pos);
+  }
+}
+
+static gchar*
+gail_notebook_page_get_text_before_offset (AtkText         *text,
+                                          gint            offset,
+                                          AtkTextBoundary boundary_type,
+                                          gint            *start_offset,
+                                          gint            *end_offset)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  if (!notebook_page->textutil)
+    gail_notebook_page_init_textutil (notebook_page, label);
+
+  return gail_text_util_get_text (notebook_page->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset); 
+}
+
+static gchar*
+gail_notebook_page_get_text_at_offset (AtkText         *text,
+                                      gint            offset,
+                                      AtkTextBoundary boundary_type,
+                                      gint            *start_offset,
+                                      gint            *end_offset)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  if (!notebook_page->textutil)
+    gail_notebook_page_init_textutil (notebook_page, label);
+
+  return gail_text_util_get_text (notebook_page->textutil,
+                              gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET, 
+                              boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_notebook_page_get_text_after_offset (AtkText         *text,
+                                         gint            offset,
+                                         AtkTextBoundary boundary_type,
+                                         gint            *start_offset,
+                                         gint            *end_offset)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  if (!notebook_page->textutil)
+    gail_notebook_page_init_textutil (notebook_page, label);
+
+  return gail_text_util_get_text (notebook_page->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gint
+gail_notebook_page_get_character_count (AtkText *text)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return 0;
+
+  return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
+}
+
+static void
+gail_notebook_page_get_character_extents (AtkText      *text,
+                                         gint         offset,
+                                         gint         *x,
+                                         gint         *y,
+                                          gint                *width,
+                                          gint                *height,
+                                         AtkCoordType coords)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  PangoRectangle char_rect;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
+  pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
+  
+  gail_misc_get_extents_from_pango_rectangle (label, &char_rect, 
+                    x_layout, y_layout, x, y, width, height, coords);
+} 
+
+static gint 
+gail_notebook_page_get_offset_at_point (AtkText      *text,
+                                        gint         x,
+                                        gint         y,
+                                       AtkCoordType coords)
+{ 
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return -1;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  
+  index = gail_misc_get_index_at_point_in_layout (label, 
+                                              gtk_label_get_layout (GTK_LABEL (label)), 
+                                              x_layout, y_layout, x, y, coords);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  if (index == -1)
+    {
+      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+        return g_utf8_strlen (label_text, -1);
+
+      return index;  
+    }
+  else
+    return g_utf8_pointer_to_offset (label_text, label_text + index);  
+}
+
+static AtkAttributeSet*
+gail_notebook_page_get_run_attributes (AtkText *text,
+                                       gint    offset,
+                                       gint    *start_offset,
+                                      gint    *end_offset)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  AtkAttributeSet *at_set = NULL;
+  GtkJustification justify;
+  GtkTextDirection dir;
+
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  
+  /* Get values set for entire label, if any */
+  justify = gtk_label_get_justify (GTK_LABEL (label));
+  if (justify != GTK_JUSTIFY_CENTER)
+    {
+      at_set = gail_misc_add_attribute (at_set, 
+                                        ATK_TEXT_ATTR_JUSTIFICATION,
+     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
+    }
+  dir = gtk_widget_get_direction (label);
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                gtk_label_get_layout (GTK_LABEL (label)),
+                                                (gchar *) gtk_label_get_text (GTK_LABEL (label)),
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  return at_set;
+}
+
+static AtkAttributeSet*
+gail_notebook_page_get_default_attributes (AtkText *text)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  AtkAttributeSet *at_set = NULL;
+
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  at_set = gail_misc_get_default_attributes (at_set,
+                                             gtk_label_get_layout (GTK_LABEL (label)),
+                                             label);
+  return at_set;
+}
+
+static gunichar 
+gail_notebook_page_get_character_at_offset (AtkText *text,
+                                            gint    offset)
+{
+  GtkWidget *label;
+  GailNotebookPage *notebook_page;
+  const gchar *string;
+  gchar *index;
+
+  notebook_page = GAIL_NOTEBOOK_PAGE (text);
+  label = get_label_from_notebook_page (notebook_page);
+
+  if (!GTK_IS_LABEL(label))
+    return '\0';
+  string = gtk_label_get_text (GTK_LABEL (label));
+  if (offset >= g_utf8_strlen (string, -1))
+    return '\0';
+  index = g_utf8_offset_to_pointer (string, offset);
+
+  return g_utf8_get_char (index);
+}
+
+static GtkWidget*
+get_label_from_notebook_page (GailNotebookPage *page)
+{
+  GtkWidget *child;
+  GtkNotebook *notebook;
+
+  notebook = page->notebook;
+  if (!notebook)
+    return NULL;
+
+  if (!gtk_notebook_get_show_tabs (notebook))
+    return NULL;
+
+  child = gtk_notebook_get_nth_page (notebook, page->index);
+  if (child == NULL) return NULL;
+  g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
+
+  child = gtk_notebook_get_tab_label (notebook, child);
+
+  if (GTK_IS_LABEL (child))
+    return child;
+
+  if (GTK_IS_CONTAINER (child))
+    child = find_label_child (GTK_CONTAINER (child));
+
+  return child;
+}
+
+static GtkWidget*
+find_label_child (GtkContainer *container)
+{
+  GList *children, *tmp_list;
+  GtkWidget *child;
+
+  children = gtk_container_get_children (container);
+
+  child = NULL;
+  for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
+    {
+      if (GTK_IS_LABEL (tmp_list->data))
+        {
+          child = GTK_WIDGET (tmp_list->data);
+          break;
+        }
+      else if (GTK_IS_CONTAINER (tmp_list->data))
+        {
+          child = find_label_child (GTK_CONTAINER (tmp_list->data));
+          if (child)
+            break;
+        }
+    }
+  g_list_free (children);
+  return child;
+}
diff --git a/modules/other/gail/gailnotebookpage.h b/modules/other/gail/gailnotebookpage.h
new file mode 100644 (file)
index 0000000..50af79c
--- /dev/null
@@ -0,0 +1,69 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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_NOTEBOOK_PAGE_H__
+#define __GAIL_NOTEBOOK_PAGE_H__
+
+#include <atk/atk.h>
+#include <gtk/gtknotebook.h>
+#include <gail/gailnotebook.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_NOTEBOOK_PAGE            (gail_notebook_page_get_type ())
+#define GAIL_NOTEBOOK_PAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj),GAIL_TYPE_NOTEBOOK_PAGE, GailNotebookPage))
+#define GAIL_NOTEBOOK_PAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_NOTEBOOK_PAGE, GailNotebookPageClass))
+#define GAIL_IS_NOTEBOOK_PAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_NOTEBOOK_PAGE))
+#define GAIL_IS_NOTEBOOK_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_NOTEBOOK_PAGE))
+#define GAIL_NOTEBOOK_PAGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_NOTEBOOK_PAGE, GailNotebookPageClass))
+
+typedef struct _GailNotebookPage                      GailNotebookPage;
+typedef struct _GailNotebookPageClass                 GailNotebookPageClass;
+
+struct _GailNotebookPage
+{
+  AtkObject parent;
+
+  GtkNotebook *notebook;
+  GtkNotebookPage *page;
+  
+  gint index;
+
+  GailTextUtil *textutil;
+};
+
+GType gail_notebook_page_get_type (void);
+
+struct _GailNotebookPageClass
+{
+  AtkObjectClass parent_class;
+};
+
+AtkObject *gail_notebook_page_new(GtkNotebook *notebook, gint pagenum);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_NOTEBOOK_PAGE_H__ */
+
diff --git a/modules/other/gail/gailobject.c b/modules/other/gail/gailobject.c
new file mode 100644 (file)
index 0000000..2c6ceb4
--- /dev/null
@@ -0,0 +1,88 @@
+/* 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 <gtk/gtk.h>
+#include "gailobject.h"
+
+static void       gail_object_class_init               (GailObjectClass *klass);
+
+static void       gail_object_real_initialize          (AtkObject       *obj,
+                                                        gpointer        data);
+
+static AtkGObjectAccessibleClass *parent_class = NULL;
+
+GType
+gail_object_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailObjectClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_object_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailObject), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE,
+                                     "GailObject", &tinfo, 0);
+    }
+
+  return type;
+}
+
+AtkObject*
+gail_object_new (GObject *obj)
+{
+  gpointer object;
+  AtkObject *atk_object;
+
+  g_return_val_if_fail (GTK_IS_OBJECT (obj), NULL);
+  object = g_object_new (GAIL_TYPE_OBJECT, NULL);
+  atk_object = ATK_OBJECT (object);
+  atk_object_initialize (atk_object, obj);
+  return atk_object;
+}
+
+static void
+gail_object_class_init (GailObjectClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->initialize = gail_object_real_initialize;
+}
+
+static void
+gail_object_real_initialize (AtkObject *obj,
+                             gpointer  data)
+{
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  obj->role = ATK_ROLE_UNKNOWN;
+}
diff --git a/modules/other/gail/gailobject.h b/modules/other/gail/gailobject.h
new file mode 100644 (file)
index 0000000..ffa36b3
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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_OBJECT_H__
+#define __GAIL_OBJECT_H__
+
+#include <atk/atk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_OBJECT                  (gail_object_get_type ())
+#define GAIL_OBJECT(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_OBJECT, GailObject)
+#define GAIL_OBJECT_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_OBJECT, GailObjectlass))
+#define GAIL_IS_OBJECT(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_OBJECT))
+#define GAIL_IS_OBJECT_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_OBJECT))
+#define GAIL_OBJECT_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_OBJECT, GailObjectlass))
+
+typedef struct _GailObject                 GailObject;
+typedef struct _GailObjectClass            GailObjectClass;
+
+struct _GailObject
+{
+  AtkGObjectAccessible parent;
+};
+
+GType gail_object_get_type (void);
+
+struct _GailObjectClass
+{
+  AtkGObjectAccessibleClass parent_class;
+};
+
+AtkObject* gail_object_new (GObject *obj);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_OBJECT_H__ */
diff --git a/modules/other/gail/gailobjectfactory.c b/modules/other/gail/gailobjectfactory.c
new file mode 100644 (file)
index 0000000..c169baa
--- /dev/null
@@ -0,0 +1,77 @@
+/* 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 <gtk/gtk.h>
+#include "gailobjectfactory.h"
+#include "gailobject.h"
+
+static void gail_object_factory_class_init (GailObjectFactoryClass *klass);
+
+static AtkObject* gail_object_factory_create_accessible (GObject *obj);
+
+static GType gail_object_factory_get_accessible_type (void);
+
+GType
+gail_object_factory_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) 
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailObjectFactoryClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_object_factory_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailObjectFactory), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+    type = g_type_register_static (
+                           ATK_TYPE_OBJECT_FACTORY, 
+                           "GailObjectFactory" , &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void 
+gail_object_factory_class_init (GailObjectFactoryClass *klass)
+{
+  AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+  class->create_accessible = gail_object_factory_create_accessible;
+  class->get_accessible_type = gail_object_factory_get_accessible_type;
+}
+
+static AtkObject* 
+gail_object_factory_create_accessible (GObject   *obj)
+{
+  return gail_object_new (obj);
+}
+
+static GType
+gail_object_factory_get_accessible_type (void)
+{
+  return GAIL_TYPE_OBJECT;
+}
diff --git a/modules/other/gail/gailobjectfactory.h b/modules/other/gail/gailobjectfactory.h
new file mode 100644 (file)
index 0000000..5b8fef8
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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_OBJECT_FACTORY_H__
+#define __GAIL_OBJECT_FACTORY_H__
+
+#include <atk/atkobjectfactory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_OBJECT_FACTORY                 (gail_object_factory_get_type ())
+#define GAIL_OBJECT_FACTORY(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_OBJECT_FACTORY, GailObjectFactory))
+#define GAIL_OBJECT_FACTORY_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_OBJECT_FACTORY, GailObjectFactoryClass))
+#define GAIL_IS_OBJECT_FACTORY(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_OBJECT_FACTORY))
+#define GAIL_IS_OBJECT_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_OBJECT_FACTORY))
+#define GAIL_OBJECT_FACTORY_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_OBJECT_FACTORY, GailObjectFactoryClass))
+
+
+typedef struct _GailObjectFactory                GailObjectFactory;
+typedef struct _GailObjectFactoryClass           GailObjectFactoryClass;
+
+struct _GailObjectFactory
+{
+  AtkObjectFactory parent;
+};
+
+struct _GailObjectFactoryClass
+{
+  AtkObjectFactoryClass parent_class;
+};
+
+GType gail_object_factory_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_OBJECT_FACTORY_H__ */
+
diff --git a/modules/other/gail/gailoptionmenu.c b/modules/other/gail/gailoptionmenu.c
new file mode 100644 (file)
index 0000000..873e939
--- /dev/null
@@ -0,0 +1,388 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gdk/gdkkeysyms.h>
+#include "gailoptionmenu.h"
+
+static void                  gail_option_menu_class_init       (GailOptionMenuClass *klass);
+static void                 gail_option_menu_real_initialize  (AtkObject       *obj,
+                                                                gpointer        data);
+
+static gint                  gail_option_menu_get_n_children   (AtkObject       *obj);
+static AtkObject*            gail_option_menu_ref_child        (AtkObject       *obj,
+                                                                gint            i);
+static gint                  gail_option_menu_real_add_gtk     (GtkContainer    *container,
+                                                                GtkWidget       *widget,
+                                                                gpointer        data);
+static gint                  gail_option_menu_real_remove_gtk  (GtkContainer    *container,
+                                                                GtkWidget       *widget,
+                                                                gpointer        data);
+
+
+static void                  atk_action_interface_init         (AtkActionIface  *iface);
+
+static gboolean              gail_option_menu_do_action        (AtkAction       *action,
+                                                                gint            i);
+static gboolean              idle_do_action                    (gpointer        data);
+static gint                  gail_option_menu_get_n_actions    (AtkAction       *action);
+static G_CONST_RETURN gchar* gail_option_menu_get_description  (AtkAction       *action,
+                                                                gint            i);
+static G_CONST_RETURN gchar* gail_option_menu_action_get_name  (AtkAction       *action,
+                                                                gint            i);
+static gboolean              gail_option_menu_set_description  (AtkAction       *action,
+                                                                gint            i,
+                                                                const gchar     *desc);
+
+static GailButtonClass* parent_class = NULL;
+
+GType
+gail_option_menu_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailOptionMenuClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_option_menu_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailOptionMenu), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+  
+      static const GInterfaceInfo atk_action_info =
+      {
+        (GInterfaceInitFunc) atk_action_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_BUTTON,
+                                     "GailOptionMenu", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                   &atk_action_info);
+    }
+
+  return type;
+}
+
+static void
+gail_option_menu_class_init (GailOptionMenuClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GailContainerClass *container_class;
+
+  container_class = (GailContainerClass *) klass;
+
+  class->get_n_children = gail_option_menu_get_n_children;
+  class->ref_child = gail_option_menu_ref_child;
+  class->initialize = gail_option_menu_real_initialize;
+
+  container_class->add_gtk = gail_option_menu_real_add_gtk;
+  container_class->remove_gtk = gail_option_menu_real_remove_gtk;
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+AtkObject* 
+gail_option_menu_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_OPTION_MENU, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_option_menu_real_initialize (AtkObject *obj,
+                                  gpointer  data)
+{
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  obj->role = ATK_ROLE_COMBO_BOX;
+}
+
+static gint
+gail_option_menu_get_n_children (AtkObject *obj)
+{
+  GtkWidget *widget;
+  GtkOptionMenu *option_menu;
+  gint n_children = 0;
+
+  g_return_val_if_fail (GAIL_IS_OPTION_MENU (obj), 0);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  option_menu = GTK_OPTION_MENU (widget);
+  if (gtk_option_menu_get_menu (option_menu))
+      n_children++;
+
+  return n_children;;
+}
+
+static AtkObject*
+gail_option_menu_ref_child (AtkObject *obj,
+                            gint      i)
+{
+  GtkWidget *widget;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GAIL_IS_OPTION_MENU (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+
+  if (i == 0)
+    accessible = g_object_ref (gtk_widget_get_accessible (gtk_option_menu_get_menu (GTK_OPTION_MENU (widget))));
+   else
+    accessible = NULL;
+
+  return accessible;
+}
+
+static gint
+gail_option_menu_real_add_gtk (GtkContainer *container,
+                               GtkWidget    *widget,
+                               gpointer     data)
+{
+  AtkObject* atk_parent = ATK_OBJECT (data);
+  AtkObject* atk_child = gtk_widget_get_accessible (widget);
+
+  GAIL_CONTAINER_CLASS (parent_class)->add_gtk (container, widget, data);
+
+  g_object_notify (G_OBJECT (atk_child), "accessible_parent");
+
+  g_signal_emit_by_name (atk_parent, "children_changed::add",
+                        1, atk_child, NULL);
+
+  return 1;
+}
+
+static gint 
+gail_option_menu_real_remove_gtk (GtkContainer *container,
+                                  GtkWidget    *widget,
+                                  gpointer     data)
+{
+  AtkPropertyValues values = { NULL };
+  AtkObject* atk_parent = ATK_OBJECT (data);
+  AtkObject *atk_child = gtk_widget_get_accessible (widget);
+
+  g_value_init (&values.old_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.old_value, atk_parent);
+
+  values.property_name = "accessible-parent";
+  g_signal_emit_by_name (atk_child,
+                         "property_change::accessible-parent", &values, NULL);
+  g_signal_emit_by_name (atk_parent, "children_changed::remove",
+                        1, atk_child, NULL);
+
+  return 1;
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action = gail_option_menu_do_action;
+  iface->get_n_actions = gail_option_menu_get_n_actions;
+  iface->get_description = gail_option_menu_get_description;
+  iface->get_name = gail_option_menu_action_get_name;
+  iface->set_description = gail_option_menu_set_description;
+}
+
+static gboolean
+gail_option_menu_do_action (AtkAction *action,
+                            gint      i)
+{
+  GtkWidget *widget;
+  GailButton *button; 
+  gboolean return_value = TRUE;
+
+  button = GAIL_BUTTON (action);
+  widget = GTK_ACCESSIBLE (action)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+
+  if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    return FALSE;
+
+  switch (i)
+    {
+    case 0:
+      if (button->action_idle_handler)
+        return_value = FALSE;
+      else
+        button->action_idle_handler = g_idle_add (idle_do_action, button);
+      break;
+    default:
+      return_value = FALSE;
+      break;
+    }
+  return return_value; 
+}
+
+static gboolean 
+idle_do_action (gpointer data)
+{
+  GtkButton *button; 
+  GtkWidget *widget;
+  GdkEvent tmp_event;
+  GailButton *gail_button;
+
+  GDK_THREADS_ENTER ();
+
+  gail_button = GAIL_BUTTON (data);
+  gail_button->action_idle_handler = 0;
+
+  widget = GTK_ACCESSIBLE (gail_button)->widget;
+  if (widget == NULL /* State is defunct */ ||
+      !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  button = GTK_BUTTON (widget); 
+
+  button->in_button = TRUE;
+  gtk_button_enter (button);
+  /*
+   * Simulate a button press event. calling gtk_button_pressed() does
+   * not get the job done for a GtkOptionMenu.  
+   */
+  tmp_event.button.type = GDK_BUTTON_PRESS;
+  tmp_event.button.window = widget->window;
+  tmp_event.button.button = 1;
+  tmp_event.button.send_event = TRUE;
+  tmp_event.button.time = GDK_CURRENT_TIME;
+  tmp_event.button.axes = NULL;
+
+  gtk_widget_event (widget, &tmp_event);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE; 
+}
+
+static gint
+gail_option_menu_get_n_actions (AtkAction *action)
+{
+  return 1;
+}
+
+static G_CONST_RETURN gchar*
+gail_option_menu_get_description (AtkAction *action,
+                                  gint      i)
+{
+  GailButton *button;
+  G_CONST_RETURN gchar *return_value;
+
+  button = GAIL_BUTTON (action);
+
+  switch (i)
+    {
+    case 0:
+      return_value = button->press_description;
+      break;
+    default:
+      return_value = NULL;
+      break;
+    }
+  return return_value; 
+}
+
+static G_CONST_RETURN gchar*
+gail_option_menu_action_get_name (AtkAction *action,
+                                  gint      i)
+{
+  G_CONST_RETURN gchar *return_value;
+
+  switch (i)
+    {
+    case 0:
+      /*
+       * This action simulates a button press by simulating moving the
+       * mouse into the button followed by pressing the left mouse button.
+       */
+      return_value = "press";
+      break;
+    default:
+      return_value = NULL;
+      break;
+  }
+  return return_value; 
+}
+
+static gboolean
+gail_option_menu_set_description (AtkAction      *action,
+                                  gint           i,
+                                  const gchar    *desc)
+{
+  GailButton *button;
+  gchar **value;
+
+  button = GAIL_BUTTON (action);
+
+  switch (i)
+    {
+    case 0:
+      value = &button->press_description;
+      break;
+    default:
+      value = NULL;
+      break;
+    }
+
+  if (value)
+    {
+      g_free (*value);
+      *value = g_strdup (desc);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
diff --git a/modules/other/gail/gailoptionmenu.h b/modules/other/gail/gailoptionmenu.h
new file mode 100644 (file)
index 0000000..dfd42a5
--- /dev/null
@@ -0,0 +1,60 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_OPTION_MENU_H__
+#define __GAIL_OPTION_MENU_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailbutton.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_OPTION_MENU                (gail_option_menu_get_type ())
+#define GAIL_OPTION_MENU(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_OPTION_MENU, GailOptionMenu))
+#define GAIL_OPTION_MENU_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_OPTION_MENU, GailOptionMenuClass))
+#define GAIL_IS_OPTION_MENU(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_OPTION_MENU))
+#define GAIL_IS_OPTION_MENU_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_OPTION_MENU))
+#define GAIL_OPTION_MENU_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_OPTION_MENU, GailOptionMenuClass))
+
+typedef struct _GailOptionMenu                   GailOptionMenu;
+typedef struct _GailOptionMenuClass              GailOptionMenuClass;
+
+struct _GailOptionMenu
+{
+  GailButton parent;
+};
+
+GType gail_option_menu_get_type (void);
+
+struct _GailOptionMenuClass
+{
+  GailButtonClass parent_class;
+};
+
+AtkObject* gail_option_menu_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_OPTION_MENU_H__ */
diff --git a/modules/other/gail/gailpaned.c b/modules/other/gail/gailpaned.c
new file mode 100644 (file)
index 0000000..a3ac815
--- /dev/null
@@ -0,0 +1,247 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001, 2002, 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 "gailpaned.h"
+
+static void         gail_paned_class_init          (GailPanedClass *klass); 
+
+static void         gail_paned_real_initialize     (AtkObject      *obj,
+                                                    gpointer       data);
+static void         gail_paned_size_allocate_gtk   (GtkWidget      *widget,
+                                                    GtkAllocation  *allocation);
+
+static AtkStateSet* gail_paned_ref_state_set       (AtkObject      *accessible);
+
+static void         atk_value_interface_init       (AtkValueIface  *iface);
+static void         gail_paned_get_current_value   (AtkValue       *obj,
+                                                    GValue         *value);
+static void         gail_paned_get_maximum_value   (AtkValue       *obj,
+                                                    GValue         *value);
+static void         gail_paned_get_minimum_value   (AtkValue       *obj,
+                                                    GValue         *value);
+static gboolean     gail_paned_set_current_value   (AtkValue       *obj,
+                                                    const GValue   *value);
+
+static GailContainerClass *parent_class = NULL;
+
+GType
+gail_paned_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailPanedClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_paned_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailPaned), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_value_info =
+      {
+        (GInterfaceInitFunc) atk_value_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailPaned", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_VALUE,
+                                   &atk_value_info);
+    }
+  return type;
+}
+
+static void
+gail_paned_class_init (GailPanedClass *klass)
+{
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_state_set = gail_paned_ref_state_set;
+  class->initialize = gail_paned_real_initialize;
+}
+
+AtkObject* 
+gail_paned_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_PANED (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_PANED, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static AtkStateSet*
+gail_paned_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  if (GTK_IS_VPANED (widget))
+    atk_state_set_add_state (state_set, ATK_STATE_VERTICAL);
+  else if (GTK_IS_HPANED (widget))
+    atk_state_set_add_state (state_set, ATK_STATE_HORIZONTAL);
+
+  return state_set;
+}
+
+static void
+gail_paned_real_initialize (AtkObject *obj,
+                            gpointer  data)
+{
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  g_signal_connect (data,
+                    "size_allocate",
+                    G_CALLBACK (gail_paned_size_allocate_gtk),
+                    NULL);
+
+  obj->role = ATK_ROLE_SPLIT_PANE;
+}
+static void
+gail_paned_size_allocate_gtk (GtkWidget      *widget,
+                              GtkAllocation  *allocation)
+{
+  AtkObject *obj = gtk_widget_get_accessible (widget);
+
+  g_object_notify (G_OBJECT (obj), "accessible-value");
+}
+
+
+static void
+atk_value_interface_init (AtkValueIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_current_value = gail_paned_get_current_value;
+  iface->get_maximum_value = gail_paned_get_maximum_value;
+  iface->get_minimum_value = gail_paned_get_minimum_value;
+  iface->set_current_value = gail_paned_set_current_value;
+
+}
+
+static void
+gail_paned_get_current_value (AtkValue             *obj,
+                              GValue               *value)
+{
+  GtkWidget* widget;
+  gint current_value;
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  current_value = gtk_paned_get_position (GTK_PANED (widget));
+  memset (value,  0, sizeof (GValue));
+  g_value_init (value, G_TYPE_INT);
+  g_value_set_int (value,current_value);
+}
+
+static void
+gail_paned_get_maximum_value (AtkValue             *obj,
+                              GValue               *value)
+{
+  GtkWidget* widget;
+  gint maximum_value;
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  maximum_value = GTK_PANED (widget)->max_position;
+  memset (value,  0, sizeof (GValue));
+  g_value_init (value, G_TYPE_INT);
+  g_value_set_int (value, maximum_value);
+}
+
+static void
+gail_paned_get_minimum_value (AtkValue             *obj,
+                              GValue               *value)
+{
+  GtkWidget* widget;
+  gint minimum_value;
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  minimum_value = GTK_PANED (widget)->min_position;
+  memset (value,  0, sizeof (GValue));
+  g_value_init (value, G_TYPE_INT);
+  g_value_set_int (value, minimum_value);
+}
+
+/*
+ * Calling atk_value_set_current_value() is no guarantee that the value is
+ * acceptable; it is necessary to listen for accessible-value signals
+ * and check whether the current value has been changed or check what the 
+ * maximum and minimum values are.
+ */
+
+static gboolean
+gail_paned_set_current_value (AtkValue             *obj,
+                              const GValue         *value)
+{
+  GtkWidget* widget;
+  gint new_value;
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  if (G_VALUE_HOLDS_INT (value))
+    {
+      new_value = g_value_get_int (value);
+      gtk_paned_set_position (GTK_PANED (widget), new_value);
+
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
diff --git a/modules/other/gail/gailpaned.h b/modules/other/gail/gailpaned.h
new file mode 100644 (file)
index 0000000..0726025
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_PANED_H__
+#define __GAIL_PANED_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_PANED                      (gail_paned_get_type ())
+#define GAIL_PANED(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_PANED, GailPaned))
+#define GAIL_PANED_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_PANED, GailPanedClass))
+#define GAIL_IS_PANED(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_PANED))
+#define GAIL_IS_PANED_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_PANED))
+#define GAIL_PANED_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_PANED, GailPanedClass))
+
+typedef struct _GailPaned              GailPaned;
+typedef struct _GailPanedClass         GailPanedClass;
+
+struct _GailPaned
+{
+  GailContainer parent;
+};
+
+GType gail_paned_get_type (void);
+
+struct _GailPanedClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_paned_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_PANED_H__ */
diff --git a/modules/other/gail/gailpixmap.c b/modules/other/gail/gailpixmap.c
new file mode 100644 (file)
index 0000000..6540f9c
--- /dev/null
@@ -0,0 +1,198 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailpixmap.h"
+
+static void     gail_pixmap_class_init         (GailPixmapClass *klass);
+static void  gail_pixmap_object_init    (GailPixmap      *pixmap);
+
+/* AtkImage */
+static void  atk_image_interface_init   (AtkImageIface  *iface);
+static G_CONST_RETURN gchar* gail_pixmap_get_image_description 
+                                        (AtkImage       *obj);
+static void  gail_pixmap_get_image_position    
+                                        (AtkImage       *obj,
+                                         gint           *x,
+                                         gint           *y,
+                                         AtkCoordType   coord_type);
+static void  gail_pixmap_get_image_size (AtkImage       *obj,
+                                         gint           *width,
+                                         gint           *height);
+static gboolean gail_pixmap_set_image_description 
+                                        (AtkImage       *obj,
+                                        const gchar    *description);
+static void  gail_pixmap_finalize       (GObject         *object);
+
+static GailWidgetClass* parent_class = NULL;
+
+GType
+gail_pixmap_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailPixmapClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_pixmap_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailPixmap), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_pixmap_object_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_image_info =
+      {
+        (GInterfaceInitFunc) atk_image_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                     "GailPixmap", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_IMAGE,
+                                   &atk_image_info);
+    }
+  return type;
+}
+
+static void     
+gail_pixmap_class_init (GailPixmapClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = gail_pixmap_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gail_pixmap_object_init (GailPixmap *pixmap)
+{
+  pixmap->image_description = NULL;
+}
+
+AtkObject* 
+gail_pixmap_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_assert (GTK_IS_PIXMAP (widget));
+  g_return_val_if_fail (GTK_IS_PIXMAP (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_PIXMAP, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_ICON;
+
+  return accessible;
+}
+
+static void
+atk_image_interface_init (AtkImageIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_image_description = gail_pixmap_get_image_description;
+  iface->get_image_position = gail_pixmap_get_image_position;
+  iface->get_image_size = gail_pixmap_get_image_size;
+  iface->set_image_description = gail_pixmap_set_image_description;
+}
+
+static G_CONST_RETURN gchar* 
+gail_pixmap_get_image_description (AtkImage       *obj)
+{
+  GailPixmap* pixmap;
+
+  g_return_val_if_fail (GAIL_IS_PIXMAP (obj), NULL);
+
+  pixmap = GAIL_PIXMAP (obj);
+
+  return pixmap->image_description;
+}
+
+static void
+gail_pixmap_get_image_position (AtkImage       *obj,
+                                gint           *x,
+                                gint           *y,
+                                AtkCoordType   coord_type)
+{
+  atk_component_get_position (ATK_COMPONENT (obj), x, y, coord_type);
+}
+
+static void  
+gail_pixmap_get_image_size (AtkImage       *obj,
+                            gint           *width,
+                            gint           *height)
+{
+  GtkWidget *widget;
+  GtkPixmap *pixmap;
+  *width = -1;
+  *height = -1;
+
+  g_return_if_fail (GAIL_IS_PIXMAP (obj));
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == 0)
+    /* State is defunct */
+    return;
+
+  g_return_if_fail (GTK_IS_PIXMAP (widget));
+
+  pixmap = GTK_PIXMAP (widget);
+
+  if (pixmap->pixmap)
+    gdk_window_get_size (pixmap->pixmap, width, height);
+}
+
+static gboolean 
+gail_pixmap_set_image_description (AtkImage       *obj,
+                                   const gchar    *description)
+{ 
+  GailPixmap* pixmap;
+
+  g_return_val_if_fail (GAIL_IS_PIXMAP (obj), FALSE);
+
+  pixmap = GAIL_PIXMAP (obj);
+  g_free (pixmap->image_description);
+
+  pixmap->image_description = g_strdup (description);
+
+  return TRUE;
+}
+
+static void
+gail_pixmap_finalize (GObject      *object)
+{
+  GailPixmap *pixmap = GAIL_PIXMAP (object);
+
+  g_free (pixmap->image_description);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
diff --git a/modules/other/gail/gailpixmap.h b/modules/other/gail/gailpixmap.h
new file mode 100644 (file)
index 0000000..889562a
--- /dev/null
@@ -0,0 +1,63 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_PIXMAP_H__
+#define __GAIL_PIXMAP_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_PIXMAP                      (gail_pixmap_get_type ())
+#define GAIL_PIXMAP(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_PIXMAP, GailPixmap))
+#define GAIL_PIXMAP_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_PIXMAP, GailPixmapClass))
+#define GAIL_IS_PIXMAP(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_PIXMAP))
+#define GAIL_IS_PIXMAP_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_PIXMAP))
+#define GAIL_PIXMAP_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_PIXMAP, GailPixmapClass))
+
+typedef struct _GailPixmap              GailPixmap;
+typedef struct _GailPixmapClass         GailPixmapClass;
+
+struct _GailPixmap
+{
+  GailWidget parent;
+
+  gchar*     image_description;
+
+};
+
+GType gail_pixmap_get_type (void);
+
+struct _GailPixmapClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_pixmap_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_PIXMAP_H__ */
+
diff --git a/modules/other/gail/gailprogressbar.c b/modules/other/gail/gailprogressbar.c
new file mode 100644 (file)
index 0000000..1ed4a49
--- /dev/null
@@ -0,0 +1,271 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailprogressbar.h"
+#include "gailadjustment.h"
+
+static void     gail_progress_bar_class_init        (GailProgressBarClass *klass);
+static void      gail_progress_bar_real_initialize   (AtkObject      *obj,
+                                                      gpointer       data);
+static void      gail_progress_bar_finalize          (GObject        *object);
+
+
+static void     atk_value_interface_init            (AtkValueIface  *iface);
+
+
+static void      gail_progress_bar_real_notify_gtk   (GObject        *obj,
+                                                      GParamSpec     *pspec);
+
+static void     gail_progress_bar_get_current_value (AtkValue       *obj,
+                                                     GValue         *value);
+static void     gail_progress_bar_get_maximum_value (AtkValue       *obj,
+                                                     GValue         *value);
+static void     gail_progress_bar_get_minimum_value (AtkValue       *obj,
+                                                     GValue         *value);
+static void      gail_progress_bar_value_changed     (GtkAdjustment  *adjustment,
+                                                      gpointer       data);
+
+static GailWidgetClass *parent_class = NULL;
+
+GType
+gail_progress_bar_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailProgressBarClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_progress_bar_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailProgressBar), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_value_info =
+      {
+        (GInterfaceInitFunc) atk_value_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                     "GailProgressBar", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_VALUE,
+                                   &atk_value_info);
+    }
+  return type;
+}
+
+static void     
+gail_progress_bar_class_init           (GailProgressBarClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+
+  widget_class = (GailWidgetClass*)klass;
+
+  widget_class->notify_gtk = gail_progress_bar_real_notify_gtk;
+
+  class->initialize = gail_progress_bar_real_initialize;
+
+  gobject_class->finalize = gail_progress_bar_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+AtkObject* 
+gail_progress_bar_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_PROGRESS_BAR (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_PROGRESS_BAR, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_progress_bar_real_initialize (AtkObject *obj,
+                                   gpointer  data)
+{
+  GailProgressBar *progress_bar = GAIL_PROGRESS_BAR (obj);
+  GtkProgress *gtk_progress;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  gtk_progress = GTK_PROGRESS (data);
+  /*
+   * If a GtkAdjustment already exists for the spin_button,
+   * create the GailAdjustment
+   */
+  if (gtk_progress->adjustment)
+    {
+      progress_bar->adjustment = gail_adjustment_new (gtk_progress->adjustment);
+      g_signal_connect (gtk_progress->adjustment,
+                        "value-changed",
+                        G_CALLBACK (gail_progress_bar_value_changed),
+                        obj);
+    }
+  else
+    progress_bar->adjustment = NULL;
+
+  obj->role = ATK_ROLE_PROGRESS_BAR;
+}
+
+static void     
+atk_value_interface_init (AtkValueIface *iface)
+{
+
+  g_return_if_fail (iface != NULL);
+
+  iface->get_current_value = gail_progress_bar_get_current_value;
+  iface->get_maximum_value = gail_progress_bar_get_maximum_value;
+  iface->get_minimum_value = gail_progress_bar_get_minimum_value;
+}
+
+static void     
+gail_progress_bar_get_current_value (AtkValue   *obj,
+                                     GValue     *value)
+{
+  GailProgressBar *progress_bar;
+
+  g_return_if_fail (GAIL_IS_PROGRESS_BAR (obj));
+
+  progress_bar = GAIL_PROGRESS_BAR (obj);
+  if (progress_bar->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_current_value (ATK_VALUE (progress_bar->adjustment), value);
+}
+
+static void     
+gail_progress_bar_get_maximum_value (AtkValue   *obj,
+                                     GValue     *value)
+{
+  GailProgressBar *progress_bar;
+
+  g_return_if_fail (GAIL_IS_PROGRESS_BAR (obj));
+
+  progress_bar = GAIL_PROGRESS_BAR (obj);
+  if (progress_bar->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_maximum_value (ATK_VALUE (progress_bar->adjustment), value);
+}
+
+static void     
+gail_progress_bar_get_minimum_value (AtkValue    *obj,
+                                    GValue      *value)
+{
+  GailProgressBar *progress_bar;
+
+  g_return_if_fail (GAIL_IS_PROGRESS_BAR (obj));
+
+  progress_bar = GAIL_PROGRESS_BAR (obj);
+  if (progress_bar->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_minimum_value (ATK_VALUE (progress_bar->adjustment), value);
+}
+
+static void
+gail_progress_bar_finalize (GObject            *object)
+{
+  GailProgressBar *progress_bar = GAIL_PROGRESS_BAR (object);
+
+  if (progress_bar->adjustment)
+    {
+      g_object_unref (progress_bar->adjustment);
+      progress_bar->adjustment = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gail_progress_bar_real_notify_gtk (GObject           *obj,
+                                   GParamSpec        *pspec)
+{
+  GtkWidget *widget = GTK_WIDGET (obj);
+  GailProgressBar *progress_bar = GAIL_PROGRESS_BAR (gtk_widget_get_accessible (widget));
+
+  if (strcmp (pspec->name, "adjustment") == 0)
+    {
+      /*
+       * Get rid of the GailAdjustment for the GtkAdjustment
+       * which was associated with the progress_bar.
+       */
+      if (progress_bar->adjustment)
+        {
+          g_object_unref (progress_bar->adjustment);
+          progress_bar->adjustment = NULL;
+        }
+      /*
+       * Create the GailAdjustment when notify for "adjustment" property
+       * is received
+       */
+      progress_bar->adjustment = gail_adjustment_new (GTK_PROGRESS (widget)->adjustment);
+      g_signal_connect (GTK_PROGRESS (widget)->adjustment,
+                        "value-changed",
+                        G_CALLBACK (gail_progress_bar_value_changed),
+                        progress_bar);
+    }
+  else
+    parent_class->notify_gtk (obj, pspec);
+}
+
+static void
+gail_progress_bar_value_changed (GtkAdjustment    *adjustment,
+                                 gpointer         data)
+{
+  GailProgressBar *progress_bar;
+
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
+
+  progress_bar = GAIL_PROGRESS_BAR (data);
+
+  g_object_notify (G_OBJECT (progress_bar), "accessible-value");
+}
diff --git a/modules/other/gail/gailprogressbar.h b/modules/other/gail/gailprogressbar.h
new file mode 100644 (file)
index 0000000..441cb36
--- /dev/null
@@ -0,0 +1,64 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_PROGRESS_BAR_H__
+#define __GAIL_PROGRESS_BAR_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_PROGRESS_BAR                      (gail_progress_bar_get_type ())
+#define GAIL_PROGRESS_BAR(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_PROGRESS_BAR, GailProgressBar))
+#define GAIL_PROGRESS_BAR_CLASS(klass)                 (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_PROGRESS_BAR, GailProgressBarClass))
+#define GAIL_IS_PROGRESS_BAR(obj)                      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_PROGRESS_BAR))
+#define GAIL_IS_PROGRESS_BAR_CLASS(klass)              (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_PROGRESS_BAR))
+#define GAIL_PROGRESS_BAR_GET_CLASS(obj)               (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_PROGRESS_BAR, GailProgressBarClass))
+
+typedef struct _GailProgressBar         GailProgressBar;
+typedef struct _GailProgressBarClass   GailProgressBarClass;
+
+struct _GailProgressBar
+{
+  GailWidget parent;
+
+  AtkObject *adjustment;
+};
+
+GType gail_progress_bar_get_type (void);
+
+struct _GailProgressBarClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_progress_bar_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_PROGRESS_BAR_H__ */
+
+
diff --git a/modules/other/gail/gailradiobutton.c b/modules/other/gail/gailradiobutton.c
new file mode 100644 (file)
index 0000000..fecdf85
--- /dev/null
@@ -0,0 +1,164 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailradiobutton.h"
+
+static void      gail_radio_button_class_init        (GailRadioButtonClass *klass);
+static void      gail_radio_button_instance_init     (GailRadioButton      *radio_button);
+
+static AtkRelationSet* gail_radio_button_ref_relation_set (AtkObject       *obj)
+;
+
+static GailToggleButtonClass *parent_class = NULL;
+
+GType
+gail_radio_button_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailRadioButtonClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_radio_button_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailRadioButton), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) gail_radio_button_instance_init, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_TOGGLE_BUTTON,
+                                   "GailRadioButton", &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void
+gail_radio_button_class_init (GailRadioButtonClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_relation_set = gail_radio_button_ref_relation_set;
+}
+
+AtkObject* 
+gail_radio_button_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_RADIO_BUTTON (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_RADIO_BUTTON, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_RADIO_BUTTON;
+  return accessible;
+}
+
+static void
+gail_radio_button_instance_init (GailRadioButton *radio_button)
+{
+  radio_button->old_group = NULL;
+}
+
+AtkRelationSet*
+gail_radio_button_ref_relation_set (AtkObject *obj)
+{
+  GtkWidget *widget;
+  AtkRelationSet *relation_set;
+  GSList *list;
+  GailRadioButton *radio_button;
+
+  g_return_val_if_fail (GAIL_IS_RADIO_BUTTON (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+  {
+    /*
+     * State is defunct
+     */
+    return NULL;
+  }
+  radio_button = GAIL_RADIO_BUTTON (obj);
+
+  relation_set = ATK_OBJECT_CLASS (parent_class)->ref_relation_set (obj);
+
+  /*
+   * If the radio button'group has changed remove the relation
+   */
+  list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+  
+  if (radio_button->old_group != list)
+    {
+      AtkRelation *relation;
+
+      relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_MEMBER_OF);
+      atk_relation_set_remove (relation_set, relation);
+    }
+
+  if (!atk_relation_set_contains (relation_set, ATK_RELATION_MEMBER_OF))
+  {
+    /*
+     * Get the members of the button group
+     */
+
+    radio_button->old_group = list;
+    if (list)
+    {
+      AtkObject **accessible_array;
+      guint list_length;
+      AtkRelation* relation;
+      gint i = 0;
+
+      list_length = g_slist_length (list);
+      accessible_array = (AtkObject**) g_malloc (sizeof (AtkObject *) * 
+                          list_length);
+      while (list != NULL)
+      {
+        GtkWidget* list_item = list->data;
+
+        accessible_array[i++] = gtk_widget_get_accessible (list_item);
+
+        list = list->next;
+      }
+      relation = atk_relation_new (accessible_array, list_length,
+                                   ATK_RELATION_MEMBER_OF);
+      g_free (accessible_array);
+
+      atk_relation_set_add (relation_set, relation);
+      /*
+       * Unref the relation so that it is not leaked.
+       */
+      g_object_unref (relation);
+    }
+  }
+  return relation_set;
+}
diff --git a/modules/other/gail/gailradiobutton.h b/modules/other/gail/gailradiobutton.h
new file mode 100644 (file)
index 0000000..d48106b
--- /dev/null
@@ -0,0 +1,61 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_RADIO_BUTTON_H__
+#define __GAIL_RADIO_BUTTON_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailtogglebutton.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_RADIO_BUTTON               (gail_radio_button_get_type ())
+#define GAIL_RADIO_BUTTON(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_RADIO_BUTTON, GailRadioButton))
+#define GAIL_RADIO_BUTTON_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_RADIO_BUTTON, GailRadioButtonClass))
+#define GAIL_IS_RADIO_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_RADIO_BUTTON))
+#define GAIL_IS_RADIO_BUTTON_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_RADIO_BUTTON))
+#define GAIL_RADIO_BUTTON_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_RADIO_BUTTON, GailRadioButtonClass))
+
+typedef struct _GailRadioButton              GailRadioButton;
+typedef struct _GailRadioButtonClass         GailRadioButtonClass;
+
+struct _GailRadioButton
+{
+  GailToggleButton parent;
+
+  GSList *old_group;
+};
+
+GType gail_radio_button_get_type (void);
+
+struct _GailRadioButtonClass
+{
+  GailToggleButtonClass parent_class;
+};
+
+AtkObject* gail_radio_button_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_RADIO_BUTTON_H__ */
diff --git a/modules/other/gail/gailradiomenuitem.c b/modules/other/gail/gailradiomenuitem.c
new file mode 100644 (file)
index 0000000..cb7e208
--- /dev/null
@@ -0,0 +1,168 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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 <gtk/gtk.h>
+#include "gailradiomenuitem.h"
+#include "gailradiosubmenuitem.h"
+
+static void      gail_radio_menu_item_class_init        (GailRadioMenuItemClass *klass);
+static void      gail_radio_menu_item_instance_init     (GailRadioMenuItem      *radio_menu_item);
+
+static AtkRelationSet* gail_radio_menu_item_ref_relation_set (AtkObject       *obj)
+;
+
+static GailCheckMenuItemClass *parent_class = NULL;
+
+GType
+gail_radio_menu_item_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailRadioMenuItemClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_radio_menu_item_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailRadioMenuItem), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) gail_radio_menu_item_instance_init, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CHECK_MENU_ITEM,
+                                   "GailRadioMenuItem", &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void
+gail_radio_menu_item_class_init (GailRadioMenuItemClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_relation_set = gail_radio_menu_item_ref_relation_set;
+}
+
+AtkObject* 
+gail_radio_menu_item_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (widget), NULL);
+
+  if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)))
+    return gail_radio_sub_menu_item_new (widget);
+
+  object = g_object_new (GAIL_TYPE_RADIO_MENU_ITEM, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_RADIO_MENU_ITEM;
+  return accessible;
+}
+
+static void
+gail_radio_menu_item_instance_init (GailRadioMenuItem *radio_menu_item)
+{
+  radio_menu_item->old_group = NULL;
+}
+
+AtkRelationSet*
+gail_radio_menu_item_ref_relation_set (AtkObject *obj)
+{
+  GtkWidget *widget;
+  AtkRelationSet *relation_set;
+  GSList *list;
+  GailRadioMenuItem *radio_menu_item;
+
+  g_return_val_if_fail (GAIL_IS_RADIO_MENU_ITEM (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+  {
+    /*
+     * State is defunct
+     */
+    return NULL;
+  }
+  radio_menu_item = GAIL_RADIO_MENU_ITEM (obj);
+
+  relation_set = ATK_OBJECT_CLASS (parent_class)->ref_relation_set (obj);
+
+  /*
+   * If the radio menu_item'group has changed remove the relation
+   */
+  list = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (widget));
+  
+  if (radio_menu_item->old_group != list)
+    {
+      AtkRelation *relation;
+
+      relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_MEMBER_OF);
+      atk_relation_set_remove (relation_set, relation);
+    }
+
+  if (!atk_relation_set_contains (relation_set, ATK_RELATION_MEMBER_OF))
+  {
+    /*
+     * Get the members of the menu_item group
+     */
+
+    radio_menu_item->old_group = list;
+    if (list)
+    {
+      AtkObject **accessible_array;
+      guint list_length;
+      AtkRelation* relation;
+      gint i = 0;
+
+      list_length = g_slist_length (list);
+      accessible_array = (AtkObject**) g_malloc (sizeof (AtkObject *) * 
+                          list_length);
+      while (list != NULL)
+      {
+        GtkWidget* list_item = list->data;
+
+        accessible_array[i++] = gtk_widget_get_accessible (list_item);
+
+        list = list->next;
+      }
+      relation = atk_relation_new (accessible_array, list_length,
+                                   ATK_RELATION_MEMBER_OF);
+      g_free (accessible_array);
+
+      atk_relation_set_add (relation_set, relation);
+      /*
+       * Unref the relation so that it is not leaked.
+       */
+      g_object_unref (relation);
+    }
+  }
+  return relation_set;
+}
diff --git a/modules/other/gail/gailradiomenuitem.h b/modules/other/gail/gailradiomenuitem.h
new file mode 100644 (file)
index 0000000..b8f6847
--- /dev/null
@@ -0,0 +1,61 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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_RADIO_MENU_ITEM_H__
+#define __GAIL_RADIO_MENU_ITEM_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcheckmenuitem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_RADIO_MENU_ITEM               (gail_radio_menu_item_get_type ())
+#define GAIL_RADIO_MENU_ITEM(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_RADIO_MENU_ITEM, GailRadioMenuItem))
+#define GAIL_RADIO_MENU_ITEM_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_RADIO_MENU_ITEM, GailRadioMenuItemClass))
+#define GAIL_IS_RADIO_MENU_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_RADIO_MENU_ITEM))
+#define GAIL_IS_RADIO_MENU_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_RADIO_MENU_ITEM))
+#define GAIL_RADIO_MENU_ITEM_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_RADIO_MENU_ITEM, GailRadioMenuItemClass))
+
+typedef struct _GailRadioMenuItem              GailRadioMenuItem;
+typedef struct _GailRadioMenuItemClass         GailRadioMenuItemClass;
+
+struct _GailRadioMenuItem
+{
+  GailCheckMenuItem parent;
+
+  GSList *old_group;
+};
+
+GType gail_radio_menu_item_get_type (void);
+
+struct _GailRadioMenuItemClass
+{
+  GailCheckMenuItemClass parent_class;
+};
+
+AtkObject* gail_radio_menu_item_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_RADIO_MENU_ITEM_H__ */
diff --git a/modules/other/gail/gailradiosubmenuitem.c b/modules/other/gail/gailradiosubmenuitem.c
new file mode 100644 (file)
index 0000000..b702567
--- /dev/null
@@ -0,0 +1,164 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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 <gtk/gtk.h>
+#include "gailradiosubmenuitem.h"
+
+static void      gail_radio_sub_menu_item_class_init        (GailRadioSubMenuItemClass *klass);
+static void      gail_radio_sub_menu_item_instance_init     (GailRadioSubMenuItem      *radio_menu_item);
+
+static AtkRelationSet* gail_radio_sub_menu_item_ref_relation_set (AtkObject       *obj)
+;
+
+static GailCheckSubMenuItemClass *parent_class = NULL;
+
+GType
+gail_radio_sub_menu_item_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailRadioSubMenuItemClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_radio_sub_menu_item_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailRadioSubMenuItem), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) gail_radio_sub_menu_item_instance_init, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CHECK_SUB_MENU_ITEM,
+                                   "GailRadioSubMenuItem", &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void
+gail_radio_sub_menu_item_class_init (GailRadioSubMenuItemClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_relation_set = gail_radio_sub_menu_item_ref_relation_set;
+}
+
+AtkObject* 
+gail_radio_sub_menu_item_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_RADIO_SUB_MENU_ITEM, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_RADIO_MENU_ITEM;
+  return accessible;
+}
+
+static void
+gail_radio_sub_menu_item_instance_init (GailRadioSubMenuItem *radio_menu_item)
+{
+  radio_menu_item->old_group = NULL;
+}
+
+AtkRelationSet*
+gail_radio_sub_menu_item_ref_relation_set (AtkObject *obj)
+{
+  GtkWidget *widget;
+  AtkRelationSet *relation_set;
+  GSList *list;
+  GailRadioSubMenuItem *radio_menu_item;
+
+  g_return_val_if_fail (GAIL_IS_RADIO_SUB_MENU_ITEM (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+  {
+    /*
+     * State is defunct
+     */
+    return NULL;
+  }
+  radio_menu_item = GAIL_RADIO_SUB_MENU_ITEM (obj);
+
+  relation_set = ATK_OBJECT_CLASS (parent_class)->ref_relation_set (obj);
+
+  /*
+   * If the radio menu_item'group has changed remove the relation
+   */
+  list = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (widget));
+  
+  if (radio_menu_item->old_group != list)
+    {
+      AtkRelation *relation;
+
+      relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_MEMBER_OF);
+      atk_relation_set_remove (relation_set, relation);
+    }
+
+  if (!atk_relation_set_contains (relation_set, ATK_RELATION_MEMBER_OF))
+  {
+    /*
+     * Get the members of the menu_item group
+     */
+
+    radio_menu_item->old_group = list;
+    if (list)
+    {
+      AtkObject **accessible_array;
+      guint list_length;
+      AtkRelation* relation;
+      gint i = 0;
+
+      list_length = g_slist_length (list);
+      accessible_array = (AtkObject**) g_malloc (sizeof (AtkObject *) * 
+                          list_length);
+      while (list != NULL)
+      {
+        GtkWidget* list_item = list->data;
+
+        accessible_array[i++] = gtk_widget_get_accessible (list_item);
+
+        list = list->next;
+      }
+      relation = atk_relation_new (accessible_array, list_length,
+                                   ATK_RELATION_MEMBER_OF);
+      g_free (accessible_array);
+
+      atk_relation_set_add (relation_set, relation);
+      /*
+       * Unref the relation so that it is not leaked.
+       */
+      g_object_unref (relation);
+    }
+  }
+  return relation_set;
+}
diff --git a/modules/other/gail/gailradiosubmenuitem.h b/modules/other/gail/gailradiosubmenuitem.h
new file mode 100644 (file)
index 0000000..10e2e7e
--- /dev/null
@@ -0,0 +1,61 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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_RADIO_SUB_MENU_ITEM_H__
+#define __GAIL_RADIO_SUB_MENU_ITEM_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailchecksubmenuitem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_RADIO_SUB_MENU_ITEM               (gail_radio_sub_menu_item_get_type ())
+#define GAIL_RADIO_SUB_MENU_ITEM(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_RADIO_SUB_MENU_ITEM, GailRadioSubMenuItem))
+#define GAIL_RADIO_SUB_MENU_ITEM_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_RADIO_SUB_MENU_ITEM, GailRadioSubMenuItemClass))
+#define GAIL_IS_RADIO_SUB_MENU_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_RADIO_SUB_MENU_ITEM))
+#define GAIL_IS_RADIO_SUB_MENU_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_RADIO_SUB_MENU_ITEM))
+#define GAIL_RADIO_SUB_MENU_ITEM_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_RADIO_SUB_MENU_ITEM, GailRadioSubMenuItemClass))
+
+typedef struct _GailRadioSubMenuItem              GailRadioSubMenuItem;
+typedef struct _GailRadioSubMenuItemClass         GailRadioSubMenuItemClass;
+
+struct _GailRadioSubMenuItem
+{
+  GailCheckSubMenuItem parent;
+
+  GSList *old_group;
+};
+
+GType gail_radio_sub_menu_item_get_type (void);
+
+struct _GailRadioSubMenuItemClass
+{
+  GailCheckSubMenuItemClass parent_class;
+};
+
+AtkObject* gail_radio_sub_menu_item_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_RADIO_SUB_MENU_ITEM_H__ */
diff --git a/modules/other/gail/gailrange.c b/modules/other/gail/gailrange.c
new file mode 100644 (file)
index 0000000..2313aee
--- /dev/null
@@ -0,0 +1,554 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <gdk/gdkkeysyms.h>
+#include "gailrange.h"
+#include "gailadjustment.h"
+#include "gail-private-macros.h"
+
+static void        gail_range_class_init        (GailRangeClass *klass);
+
+static void         gail_range_real_initialize   (AtkObject      *obj,
+                                                  gpointer      data);
+
+static void         gail_range_finalize          (GObject        *object);
+
+static AtkStateSet* gail_range_ref_state_set     (AtkObject      *obj);
+
+
+static void         gail_range_real_notify_gtk   (GObject        *obj,
+                                                  GParamSpec     *pspec);
+
+static void        atk_value_interface_init     (AtkValueIface  *iface);
+static void        gail_range_get_current_value (AtkValue       *obj,
+                                                  GValue         *value);
+static void        gail_range_get_maximum_value (AtkValue       *obj,
+                                                  GValue         *value);
+static void        gail_range_get_minimum_value (AtkValue       *obj,
+                                                  GValue         *value);
+static gboolean            gail_range_set_current_value (AtkValue       *obj,
+                                                  const GValue   *value);
+static void         gail_range_value_changed     (GtkAdjustment  *adjustment,
+                                                  gpointer       data);
+
+static void         atk_action_interface_init    (AtkActionIface *iface);
+static gboolean     gail_range_do_action        (AtkAction       *action,
+                                                gint            i);
+static gboolean     idle_do_action              (gpointer        data);
+static gint         gail_range_get_n_actions    (AtkAction       *action);
+static G_CONST_RETURN gchar* gail_range_get_description  (AtkAction    *action, 
+                                                         gint          i);
+static G_CONST_RETURN gchar* gail_range_get_keybinding   (AtkAction     *action,
+                                                         gint            i);
+static G_CONST_RETURN gchar* gail_range_action_get_name  (AtkAction    *action,
+                                                        gint            i);
+static gboolean   gail_range_set_description  (AtkAction       *action,
+                                              gint            i,
+                                              const gchar     *desc);
+static GailWidgetClass *parent_class = NULL;
+
+GType
+gail_range_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_range_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_action_info =
+      {
+       (GInterfaceInitFunc) atk_action_interface_init,
+       (GInterfaceFinalizeFunc) NULL,
+       NULL
+      };
+
+
+      static const GInterfaceInfo atk_value_info =
+      {
+        (GInterfaceInitFunc) atk_value_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                     "GailRange", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_ACTION,
+                                       &atk_action_info);
+
+      g_type_add_interface_static (type, ATK_TYPE_VALUE,
+                                   &atk_value_info);
+    }
+  return type;
+}
+
+static void     
+gail_range_class_init          (GailRangeClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+
+  widget_class = (GailWidgetClass*)klass;
+
+  widget_class->notify_gtk = gail_range_real_notify_gtk;
+
+  class->ref_state_set = gail_range_ref_state_set;
+  class->initialize = gail_range_real_initialize;
+
+  gobject_class->finalize = gail_range_finalize;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+AtkObject* 
+gail_range_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_RANGE (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_RANGE, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_range_real_initialize (AtkObject *obj,
+                            gpointer  data)
+{
+  GailRange *range = GAIL_RANGE (obj);
+  GtkRange *gtk_range;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  gtk_range = GTK_RANGE (data);
+  /*
+   * If a GtkAdjustment already exists for the GtkRange,
+   * create the GailAdjustment
+   */
+  if (gtk_range->adjustment)
+    {
+      range->adjustment = gail_adjustment_new (gtk_range->adjustment);
+      g_signal_connect (gtk_range->adjustment,
+                        "value-changed",
+                        G_CALLBACK (gail_range_value_changed),
+                        range);
+    }
+  else
+    range->adjustment = NULL;
+  range->activate_keybinding=NULL;
+  range->activate_description=NULL;
+  /*
+   * Assumed to GtkScale (either GtkHScale or GtkVScale)
+   */
+  obj->role = ATK_ROLE_SLIDER;
+}
+
+static AtkStateSet*
+gail_range_ref_state_set (AtkObject *obj)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+  GtkRange *range;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  range = GTK_RANGE (widget);
+
+  /*
+   * We do not generate property change for orientation change as there
+   * is no interface to change the orientation which emits a notification
+   */
+  if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
+    atk_state_set_add_state (state_set, ATK_STATE_HORIZONTAL);
+  else
+    atk_state_set_add_state (state_set, ATK_STATE_VERTICAL);
+
+  return state_set;
+}
+
+static void     
+atk_value_interface_init (AtkValueIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_current_value = gail_range_get_current_value;
+  iface->get_maximum_value = gail_range_get_maximum_value;
+  iface->get_minimum_value = gail_range_get_minimum_value;
+  iface->set_current_value = gail_range_set_current_value;
+
+}
+
+static void     
+gail_range_get_current_value (AtkValue         *obj,
+                              GValue           *value)
+{
+  GailRange *range;
+
+  g_return_if_fail (GAIL_IS_RANGE (obj));
+
+  range = GAIL_RANGE (obj);
+  if (range->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_current_value (ATK_VALUE (range->adjustment), value);
+}
+
+static void     
+gail_range_get_maximum_value (AtkValue         *obj,
+                              GValue           *value)
+{
+  GailRange *range;
+
+  g_return_if_fail (GAIL_IS_RANGE (obj));
+
+  range = GAIL_RANGE (obj);
+  if (range->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_maximum_value (ATK_VALUE (range->adjustment), value);
+}
+
+static void     
+gail_range_get_minimum_value (AtkValue         *obj,
+                              GValue           *value)
+{
+  GailRange *range;
+
+  g_return_if_fail (GAIL_IS_RANGE (obj));
+
+  range = GAIL_RANGE (obj);
+  if (range->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_minimum_value (ATK_VALUE (range->adjustment), value);
+}
+
+static gboolean         gail_range_set_current_value (AtkValue         *obj,
+                                               const GValue    *value)
+{
+  GtkWidget *widget;
+
+  g_return_val_if_fail (GAIL_IS_RANGE (obj), FALSE);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return FALSE;
+
+  if (G_VALUE_HOLDS_DOUBLE (value))
+    {
+      GtkRange *range = GTK_RANGE (widget);
+      gdouble new_value;
+
+      new_value = g_value_get_double (value);
+      gtk_range_set_value (range, new_value);
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+static void
+gail_range_finalize (GObject            *object)
+{
+  GailRange *range = GAIL_RANGE (object);
+
+  if (range->adjustment)
+    {
+      /*
+       * The GtkAdjustment may live on so we need to dicsonnect the
+       * signal handler
+       */
+      if (GAIL_ADJUSTMENT (range->adjustment)->adjustment)
+        {
+          g_signal_handlers_disconnect_by_func (GAIL_ADJUSTMENT (range->adjustment)->adjustment,
+                                                (void *)gail_range_value_changed,
+                                                range);
+        }
+      g_object_unref (range->adjustment);
+      range->adjustment = NULL;
+    }
+  range->activate_keybinding=NULL;
+  range->activate_description=NULL;
+  if (range->action_idle_handler)
+   {
+    g_source_remove (range->action_idle_handler);
+    range->action_idle_handler = 0;
+   }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gail_range_real_notify_gtk (GObject           *obj,
+                            GParamSpec        *pspec)
+{
+  GtkWidget *widget = GTK_WIDGET (obj);
+  GailRange *range = GAIL_RANGE (gtk_widget_get_accessible (widget));
+
+  if (strcmp (pspec->name, "adjustment") == 0)
+    {
+      /*
+       * Get rid of the GailAdjustment for the GtkAdjustment
+       * which was associated with the range.
+       */
+      if (range->adjustment)
+        {
+          g_object_unref (range->adjustment);
+          range->adjustment = NULL;
+        }
+      /*
+       * Create the GailAdjustment when notify for "adjustment" property
+       * is received
+       */
+      range->adjustment = gail_adjustment_new (GTK_RANGE (widget)->adjustment);
+      g_signal_connect (GTK_RANGE (widget)->adjustment,
+                        "value-changed",
+                        G_CALLBACK (gail_range_value_changed),
+                        range);
+    }
+  else
+    parent_class->notify_gtk (obj, pspec);
+}
+
+static void
+gail_range_value_changed (GtkAdjustment    *adjustment,
+                          gpointer         data)
+{
+  GailRange *range;
+
+  g_return_if_fail (adjustment != NULL);
+  gail_return_if_fail (data != NULL);
+
+  range = GAIL_RANGE (data);
+
+  g_object_notify (G_OBJECT (range), "accessible-value");
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->do_action = gail_range_do_action;
+  iface->get_n_actions = gail_range_get_n_actions;
+  iface->get_description = gail_range_get_description;
+  iface->get_keybinding = gail_range_get_keybinding;
+  iface->get_name = gail_range_action_get_name;
+  iface->set_description = gail_range_set_description;
+}
+
+static gboolean
+gail_range_do_action (AtkAction *action,
+                     gint      i)
+{
+  GailRange *range;
+  GtkWidget *widget;
+  gboolean return_value = TRUE;
+
+  range = GAIL_RANGE (action);
+  widget = GTK_ACCESSIBLE (action)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return FALSE;
+  if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+    return FALSE;
+  if(i==0)
+   {
+    if (range->action_idle_handler)
+      return_value = FALSE;
+    else
+      range->action_idle_handler = g_idle_add (idle_do_action, range);
+   }
+  else
+     return_value = FALSE;
+  return return_value;
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  GailRange *range;
+  GtkWidget *widget;
+
+  GDK_THREADS_ENTER ();
+
+  range = GAIL_RANGE (data);
+  range->action_idle_handler = 0;
+  widget = GTK_ACCESSIBLE (range)->widget;
+  if (widget == NULL /* State is defunct */ ||
+     !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
+   {
+    GDK_THREADS_LEAVE ();
+    return FALSE;
+   }
+
+   gtk_widget_activate (widget);
+
+   GDK_THREADS_LEAVE ();
+
+   return FALSE;
+}
+
+static gint
+gail_range_get_n_actions (AtkAction *action)
+{
+    return 1;
+}
+
+static G_CONST_RETURN gchar*
+gail_range_get_description (AtkAction *action,
+                              gint      i)
+{
+  GailRange *range;
+  G_CONST_RETURN gchar *return_value;
+
+  range = GAIL_RANGE (action);
+  if (i==0)
+   return_value = range->activate_description;
+  else
+   return_value = NULL;
+  return return_value;
+}
+
+static G_CONST_RETURN gchar*
+gail_range_get_keybinding (AtkAction *action,
+                              gint      i)
+{
+  GailRange *range;
+  gchar *return_value = NULL;
+  range = GAIL_RANGE (action);
+  if(i==0)
+   {
+    GtkWidget *widget;
+    GtkWidget *label;
+    AtkRelationSet *set;
+    AtkRelation *relation;
+    GPtrArray *target;
+    gpointer target_object;
+    guint key_val;
+
+    range = GAIL_RANGE (action);
+    widget = GTK_ACCESSIBLE (range)->widget;
+    if (widget == NULL)
+       return NULL;
+    set = atk_object_ref_relation_set (ATK_OBJECT (action));
+
+    if (!set)
+      return NULL;
+    label = NULL;
+    relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);    
+    if (relation)
+     {
+      target = atk_relation_get_target (relation);
+      target_object = g_ptr_array_index (target, 0);
+      if (GTK_IS_ACCESSIBLE (target_object))
+         label = GTK_ACCESSIBLE (target_object)->widget;
+     }
+    g_object_unref (set);
+    if (GTK_IS_LABEL (label))
+     {
+      key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
+      if (key_val != GDK_VoidSymbol)
+         return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
+      }
+    g_free (range->activate_keybinding);
+    range->activate_keybinding = return_value;
+   }
+  return return_value;
+}
+
+static G_CONST_RETURN gchar*
+gail_range_action_get_name (AtkAction *action,
+                           gint      i)
+{
+  G_CONST_RETURN gchar *return_value;
+  
+  if (i==0)
+   return_value = "activate";
+  else
+   return_value = NULL;
+
+  return return_value;
+}
+
+static gboolean
+gail_range_set_description (AtkAction      *action,
+                           gint           i,
+                           const gchar    *desc)
+{
+  GailRange *range;
+  gchar **value;
+
+  range = GAIL_RANGE (action);
+  
+  if (i==0)
+   value = &range->activate_description;
+  else
+   value = NULL;
+
+  if (value)
+   {
+    g_free (*value);
+    *value = g_strdup (desc);
+    return TRUE;
+   }
+  else
+   return FALSE;
+}
+
+
diff --git a/modules/other/gail/gailrange.h b/modules/other/gail/gailrange.h
new file mode 100644 (file)
index 0000000..ad6bcd4
--- /dev/null
@@ -0,0 +1,66 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_RANGE_H__
+#define __GAIL_RANGE_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_RANGE                          (gail_range_get_type ())
+#define GAIL_RANGE(obj)                          (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_RANGE, GailRange))
+#define GAIL_RANGE_CLASS(klass)                        (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_RANGE, GailRangeClass))
+#define GAIL_IS_RANGE(obj)                     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_RANGE))
+#define GAIL_IS_RANGE_CLASS(klass)             (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_RANGE))
+#define GAIL_RANGE_GET_CLASS(obj)              (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_RANGE, GailRangeClass))
+
+typedef struct _GailRange              GailRange;
+typedef struct _GailRangeClass         GailRangeClass;
+
+struct _GailRange
+{
+  GailWidget parent;
+
+  AtkObject *adjustment;
+  gchar     *activate_description;
+  gchar     *activate_keybinding;
+  guint     action_idle_handler;
+
+};
+
+GType gail_range_get_type (void);
+
+struct _GailRangeClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject* gail_range_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_RANGE_H__ */
diff --git a/modules/other/gail/gailrenderercell.c b/modules/other/gail/gailrenderercell.c
new file mode 100644 (file)
index 0000000..9db9855
--- /dev/null
@@ -0,0 +1,112 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailrenderercell.h"
+
+static void      gail_renderer_cell_class_init          (GailRendererCellClass *klass);
+static void      gail_renderer_cell_object_init         (GailRendererCell      *renderer_cell);
+
+static void      gail_renderer_cell_finalize            (GObject               *object)
+;
+static gpointer parent_class = NULL;
+
+GType
+gail_renderer_cell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailRendererCellClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_renderer_cell_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailRendererCell), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) gail_renderer_cell_object_init, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_CELL,
+                                   "GailRendererCell", &tinfo, 0);
+  }
+  return type;
+}
+
+static void 
+gail_renderer_cell_class_init (GailRendererCellClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  klass->property_list = NULL;
+
+  gobject_class->finalize = gail_renderer_cell_finalize;
+}
+
+static void
+gail_renderer_cell_object_init (GailRendererCell *renderer_cell)
+{
+  renderer_cell->renderer = NULL;
+}
+
+static void
+gail_renderer_cell_finalize (GObject  *object)
+{
+  GailRendererCell *renderer_cell = GAIL_RENDERER_CELL (object);
+
+  if (renderer_cell->renderer)
+    g_object_unref (renderer_cell->renderer);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+gboolean
+gail_renderer_cell_update_cache (GailRendererCell *cell, 
+                                 gboolean         emit_change_signal)
+{
+  GailRendererCellClass *class = GAIL_RENDERER_CELL_GET_CLASS(cell);
+  if (class->update_cache)
+    return (class->update_cache)(cell, emit_change_signal);
+  return FALSE;
+}
+
+AtkObject*
+gail_renderer_cell_new (void)
+{
+  GObject *object;
+  AtkObject *atk_object;
+  GailRendererCell *cell;
+
+  object = g_object_new (GAIL_TYPE_RENDERER_CELL, NULL);
+
+  g_return_val_if_fail (object != NULL, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object->role = ATK_ROLE_TABLE_CELL;
+
+  cell = GAIL_RENDERER_CELL(object);
+
+  return atk_object;
+}
diff --git a/modules/other/gail/gailrenderercell.h b/modules/other/gail/gailrenderercell.h
new file mode 100644 (file)
index 0000000..f380647
--- /dev/null
@@ -0,0 +1,65 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_RENDERER_CELL_H__
+#define __GAIL_RENDERER_CELL_H__
+
+#include <atk/atk.h>
+#include <gail/gailcell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_RENDERER_CELL            (gail_renderer_cell_get_type ())
+#define GAIL_RENDERER_CELL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_RENDERER_CELL, GailRendererCell))
+#define GAIL_RENDERER_CELL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_RENDERER_CELL, GailRendererCellClass))
+#define GAIL_IS_RENDERER_CELL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_RENDERER_CELL))
+#define GAIL_IS_RENDERER_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_RENDERER_CELL))
+#define GAIL_RENDERER_CELL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_RENDERER_CELL, GailRendererCellClass))
+
+typedef struct _GailRendererCell                  GailRendererCell;
+typedef struct _GailRendererCellClass             GailRendererCellClass;
+
+struct _GailRendererCell
+{
+  GailCell parent;
+  GtkCellRenderer *renderer;
+};
+
+GType gail_renderer_cell_get_type (void);
+
+struct _GailRendererCellClass
+{
+  GailCellClass parent_class;
+  gchar **property_list;
+  gboolean (*update_cache)(GailRendererCell *cell, gboolean emit_change_signal);
+};
+
+gboolean
+gail_renderer_cell_update_cache (GailRendererCell *cell, gboolean emit_change_signal);
+
+AtkObject *gail_renderer_cell_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TREE_VIEW_TEXT_CELL_H__ */
diff --git a/modules/other/gail/gailrenderercellfactory.c b/modules/other/gail/gailrenderercellfactory.c
new file mode 100644 (file)
index 0000000..f7a6aa5
--- /dev/null
@@ -0,0 +1,78 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2004 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 <gtk/gtkcellrenderer.h>
+#include "gailrenderercellfactory.h"
+#include "gailrenderercell.h"
+
+static void gail_renderer_cell_factory_class_init (GailRendererCellFactoryClass        *klass);
+
+static AtkObject* gail_renderer_cell_factory_create_accessible (
+                                GObject                              *obj);
+static GType gail_renderer_cell_factory_get_accessible_type (void);
+
+GType
+gail_renderer_cell_factory_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) 
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailRendererCellFactoryClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_renderer_cell_factory_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailRendererCellFactory), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+    type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
+                           "GailRendererCellFactory" , &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void 
+gail_renderer_cell_factory_class_init (GailRendererCellFactoryClass *klass)
+{
+  AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+  class->create_accessible = gail_renderer_cell_factory_create_accessible;
+  class->get_accessible_type = gail_renderer_cell_factory_get_accessible_type;
+}
+
+static AtkObject* 
+gail_renderer_cell_factory_create_accessible (GObject *obj)
+{
+  g_return_val_if_fail (GTK_IS_CELL_RENDERER (obj), NULL);
+
+  return gail_renderer_cell_new ();
+}
+
+static GType
+gail_renderer_cell_factory_get_accessible_type (void)
+{
+  return GAIL_TYPE_RENDERER_CELL;
+}
diff --git a/modules/other/gail/gailrenderercellfactory.h b/modules/other/gail/gailrenderercellfactory.h
new file mode 100644 (file)
index 0000000..6368981
--- /dev/null
@@ -0,0 +1,56 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2004 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_RENDERER_CELL_FACTORY_H__
+#define __GAIL_RENDERER_CELL_FACTORY_H__
+
+#include <atk/atkobjectfactory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_RENDERER_CELL_FACTORY                 (gail_renderer_cell_factory_get_type ())
+#define GAIL_RENDERER_CELL_FACTORY(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_RENDERER_CELL_FACTORY, GailRendererCellFactory))
+#define GAIL_RENDERER_CELL_FACTORY_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), AGTK_TYPE_RENDERER_CELL_FACTORY, GailRendererCellFactoryClass))
+#define GAIL_IS_RENDERER_CELL_FACTORY(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_RENDERER_CELL_FACTORY))
+#define GAIL_IS_RENDERER_CELL_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_RENDERER_CELL_FACTORY))
+#define GAIL_RENDERER_CELL_FACTORY_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_RENDERER_CELL_FACTORY, GailRendererCellFactoryClass))
+
+typedef struct _GailRendererCellFactory             GailRendererCellFactory;
+typedef struct _GailRendererCellFactoryClass        GailRendererCellFactoryClass;
+
+struct _GailRendererCellFactory
+{
+  AtkObjectFactory parent;
+};
+
+struct _GailRendererCellFactoryClass
+{
+  AtkObjectFactoryClass parent_class;
+};
+
+GType gail_renderer_cell_factory_get_type (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_RENDERER_CELL_FACTORY_H__ */
diff --git a/modules/other/gail/gailscale.c b/modules/other/gail/gailscale.c
new file mode 100644 (file)
index 0000000..1a6fefd
--- /dev/null
@@ -0,0 +1,544 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2004 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        atk_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 (GailScale), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_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;
+  const gchar *txt;
+  PangoLayout *layout;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  gail_scale = GAIL_SCALE (obj);
+  gail_scale->textutil = gail_text_util_new ();
+
+  layout = gtk_scale_get_layout (GTK_SCALE (data));
+  if (layout)
+    {
+      txt = pango_layout_get_text (layout);
+      if (txt)
+        {
+          gail_text_util_text_setup (gail_scale->textutil, 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;
+          PangoLayout *layout;
+          const gchar *txt;
+
+          gtk_scale = GTK_SCALE (widget);
+          layout = gtk_scale_get_layout (gtk_scale);
+          if (layout)
+            {
+              txt = pango_layout_get_text (layout);
+              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_OBJECT_CLASS (parent_class)->notify (obj, pspec);
+}
+
+/* atktext.h */
+
+static void
+atk_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;
+
+  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_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); 
+    }
+  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_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);
+    }
+  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_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);
+    }
+  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;
+  const gchar *scale_text;
+  widget = GTK_ACCESSIBLE (text)->widget;
+
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  scale = GTK_SCALE (widget);
+  layout = gtk_scale_get_layout (scale);
+  if (!layout)
+    return;
+  scale_text = pango_layout_get_text (layout);
+  if (!scale_text)
+    return;
+  index = g_utf8_offset_to_pointer (scale_text, offset) - scale_text;
+  gtk_scale_get_layout_offsets (scale, &x_layout, &y_layout);
+  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);
+} 
+
+static gint 
+gail_scale_get_offset_at_point (AtkText      *text,
+                                gint         x,
+                                gint         y,
+                               AtkCoordType coords)
+{ 
+  GtkWidget *widget;
+  GtkScale *scale;
+  PangoLayout *layout;
+  gint index, x_layout, y_layout;
+  const gchar *scale_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  scale = GTK_SCALE (widget);
+  layout = gtk_scale_get_layout (scale);
+  if (!layout)
+    return -1;
+  scale_text = pango_layout_get_text (layout);
+  if (!scale_text)
+    return -1;
+  
+  gtk_scale_get_layout_offsets (scale, &x_layout, &y_layout);
+  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);  
+
+  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;
+  const gchar *scale_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  scale = GTK_SCALE (widget);
+
+  layout = gtk_scale_get_layout (scale);
+  if (!layout)
+    return at_set;
+  scale_text = pango_layout_get_text (layout);
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                layout,
+                                                (gchar *)scale_text,
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  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_layout (GTK_SCALE (widget));
+  if (layout)
+    {
+      at_set = gail_misc_get_default_attributes (at_set,
+                                                 layout,
+                                                 widget);
+    }
+  return at_set;
+}
+
+static gunichar 
+gail_scale_get_character_at_offset (AtkText *text,
+                                    gint    offset)
+{
+  GtkWidget *widget;
+  GtkScale *scale;
+  PangoLayout *layout;
+  const gchar *string;
+  gchar *index;
+  gunichar c;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return '\0';
+
+  scale = GTK_SCALE (widget);
+
+  layout = gtk_scale_get_layout (scale);
+  if (!layout)
+    return '\0';
+  string = pango_layout_get_text (layout);
+  if (offset >= g_utf8_strlen (string, -1))
+    c = '\0';
+  else
+    {
+      index = g_utf8_offset_to_pointer (string, offset);
+
+      c = g_utf8_get_char (index);
+    }
+
+  return c;
+}
diff --git a/modules/other/gail/gailscale.h b/modules/other/gail/gailscale.h
new file mode 100644 (file)
index 0000000..22638a3
--- /dev/null
@@ -0,0 +1,62 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2004 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__ */
diff --git a/modules/other/gail/gailscrollbar.c b/modules/other/gail/gailscrollbar.c
new file mode 100644 (file)
index 0000000..da17889
--- /dev/null
@@ -0,0 +1,134 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailscrollbar.h"
+
+static void        gail_scrollbar_class_init        (GailScrollbarClass *klass);
+
+static gint         gail_scrollbar_get_index_in_parent (AtkObject *accessible);
+
+static GailRangeClass *parent_class = NULL;
+
+GType
+gail_scrollbar_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailScrollbarClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_scrollbar_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailScrollbar), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_RANGE,
+                                   "GailScrollbar", &tinfo, 0);
+  }
+  return type;
+}
+
+static void     
+gail_scrollbar_class_init (GailScrollbarClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  class->get_index_in_parent = gail_scrollbar_get_index_in_parent;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+AtkObject* 
+gail_scrollbar_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_SCROLLBAR (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_SCROLLBAR, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_SCROLL_BAR;
+
+  return accessible;
+}
+
+static gint
+gail_scrollbar_get_index_in_parent (AtkObject *accessible)
+{
+  GtkWidget *widget;
+  GtkScrolledWindow *scrolled_window;
+  gint n_children;
+  GList *children;
+
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+  {
+    /*
+     * State is defunct
+     */
+    return -1;
+  }
+  g_return_val_if_fail (GTK_IS_SCROLLBAR (widget), -1);
+
+  if (!GTK_IS_SCROLLED_WINDOW(widget->parent))
+    return ATK_OBJECT_CLASS (parent_class)->get_index_in_parent (accessible);
+
+  scrolled_window = GTK_SCROLLED_WINDOW (widget->parent);
+  children = gtk_container_get_children (GTK_CONTAINER (scrolled_window));
+  n_children = g_list_length (children);
+  g_list_free (children);
+
+  if (GTK_IS_HSCROLLBAR (widget))
+  {
+    if (!scrolled_window->hscrollbar_visible) 
+    {
+      n_children = -1;
+    }
+  }
+  else if (GTK_IS_VSCROLLBAR (widget))
+  {
+    if (!scrolled_window->vscrollbar_visible) 
+    {
+      n_children = -1;
+    }
+    else if (scrolled_window->hscrollbar_visible) 
+    {
+      n_children++;
+    }
+  }
+  else
+  {
+    n_children = -1;
+  }
+  return n_children;
+} 
diff --git a/modules/other/gail/gailscrollbar.h b/modules/other/gail/gailscrollbar.h
new file mode 100644 (file)
index 0000000..985a716
--- /dev/null
@@ -0,0 +1,60 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_SCROLLBAR_H__
+#define __GAIL_SCROLLBAR_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailrange.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_SCROLLBAR                     (gail_scrollbar_get_type ())
+#define GAIL_SCROLLBAR(obj)                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_SCROLLBAR, GailScrollbar))
+#define GAIL_SCROLLBAR_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_SCROLLBAR, GailScrollbarClass))
+#define GAIL_IS_SCROLLBAR(obj)                  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_SCROLLBAR))
+#define GAIL_IS_SCROLLBAR_CLASS(klass)          (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_SCROLLBAR))
+#define GAIL_SCROLLBAR_GET_CLASS(obj)           (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_SCROLLBAR, GailScrollbarClass))
+
+typedef struct _GailScrollbar          GailScrollbar;
+typedef struct _GailScrollbarClass     GailScrollbarClass;
+
+struct _GailScrollbar
+{
+  GailRange parent;
+};
+
+GType gail_scrollbar_get_type (void);
+
+struct _GailScrollbarClass
+{
+  GailRangeClass parent_class;
+};
+
+AtkObject* gail_scrollbar_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_SCROLLBAR_H__ */
diff --git a/modules/other/gail/gailscrolledwindow.c b/modules/other/gail/gailscrolledwindow.c
new file mode 100644 (file)
index 0000000..024bc28
--- /dev/null
@@ -0,0 +1,243 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001, 2002, 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 "gailscrolledwindow.h"
+
+
+static void         gail_scrolled_window_class_init     (GailScrolledWindowClass  *klass); 
+static void         gail_scrolled_window_real_initialize
+                                                        (AtkObject     *obj,
+                                                         gpointer      data);
+
+static gint         gail_scrolled_window_get_n_children (AtkObject     *object);
+static AtkObject*   gail_scrolled_window_ref_child      (AtkObject     *obj,
+                                                         gint          child);
+static void         gail_scrolled_window_scrollbar_visibility_changed 
+                                                        (GObject       *object,
+                                                         GParamSpec    *pspec,
+                                                         gpointer      user_data);
+
+static GailContainerClass *parent_class = NULL;
+
+GType
+gail_scrolled_window_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailScrolledWindowClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_scrolled_window_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailScrolledWindow), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailScrolledWindow", &tinfo, 0);
+    }
+  return type;
+}
+
+static void
+gail_scrolled_window_class_init (GailScrolledWindowClass *klass)
+{
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_n_children = gail_scrolled_window_get_n_children;
+  class->ref_child = gail_scrolled_window_ref_child;
+  class->initialize = gail_scrolled_window_real_initialize;
+}
+
+AtkObject* 
+gail_scrolled_window_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+  
+  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_SCROLLED_WINDOW, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_scrolled_window_real_initialize (AtkObject *obj,
+                                      gpointer  data)
+{
+  GtkScrolledWindow *window;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  window = GTK_SCROLLED_WINDOW (data);
+  g_signal_connect_data (window->hscrollbar, "notify::visible",
+    (GCallback)gail_scrolled_window_scrollbar_visibility_changed, 
+    obj, NULL, FALSE);
+  g_signal_connect_data (window->vscrollbar, "notify::visible",
+    (GCallback)gail_scrolled_window_scrollbar_visibility_changed, 
+    obj, NULL, FALSE);
+
+  obj->role = ATK_ROLE_SCROLL_PANE;
+}
+
+static gint
+gail_scrolled_window_get_n_children (AtkObject *object)
+{
+  GtkWidget *widget;
+  GtkScrolledWindow *gtk_window;
+  GList *children;
+  gint n_children;
+  widget = GTK_ACCESSIBLE (object)->widget;
+  if (widget == NULL)
+    /* Object is defunct */
+    return 0;
+
+  gtk_window = GTK_SCROLLED_WINDOW (widget);
+   
+  /* Get the number of children returned by the backing GtkScrolledWindow */
+
+  children = gtk_container_get_children (GTK_CONTAINER(gtk_window));
+  n_children = g_list_length (children);
+  g_list_free (children);
+  
+  /* Add one to the count for each visible scrollbar */
+
+  if (gtk_window->hscrollbar_visible)
+    n_children++;
+  if (gtk_window->vscrollbar_visible)
+    n_children++;
+  return n_children;
+}
+
+static AtkObject *
+gail_scrolled_window_ref_child (AtkObject *obj, 
+                                gint      child)
+{
+  GtkWidget *widget;
+  GtkScrolledWindow *gtk_window;
+  GList *children, *tmp_list;
+  gint n_children;
+  AtkObject  *accessible = NULL;
+
+  g_return_val_if_fail (child >= 0, NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /* Object is defunct */
+    return NULL;
+
+  gtk_window = GTK_SCROLLED_WINDOW (widget);
+
+  children = gtk_container_get_children (GTK_CONTAINER (gtk_window));
+  n_children = g_list_length (children);
+
+  if (child == n_children)
+    {
+      if (gtk_window->hscrollbar_visible)
+        accessible = gtk_widget_get_accessible (gtk_window->hscrollbar);
+      else if (gtk_window->vscrollbar_visible)
+        accessible = gtk_widget_get_accessible (gtk_window->vscrollbar);
+    }
+  else if (child == n_children+1 && 
+           gtk_window->hscrollbar_visible &&
+           gtk_window->vscrollbar_visible)
+    accessible = gtk_widget_get_accessible (gtk_window->vscrollbar);
+  else if (child < n_children)
+    {
+      tmp_list = g_list_nth (children, child);
+      if (tmp_list)
+       accessible = gtk_widget_get_accessible (
+               GTK_WIDGET (tmp_list->data));
+    }
+
+  g_list_free (children);
+  if (accessible)
+    g_object_ref (accessible);
+  return accessible; 
+}
+
+static void
+gail_scrolled_window_scrollbar_visibility_changed (GObject    *object,
+                                                   GParamSpec *pspec,
+                                                   gpointer   user_data)
+{
+  if (!strcmp (pspec->name, "visible"))
+    {
+      gint index;
+      gint n_children;
+      gboolean child_added = FALSE;
+      GList *children;
+      AtkObject *child;
+      GtkScrolledWindow *gtk_window;
+      GailScrolledWindow *gail_window = GAIL_SCROLLED_WINDOW (user_data);
+      gchar *signal_name;
+
+      gtk_window = GTK_SCROLLED_WINDOW (GTK_ACCESSIBLE (user_data)->widget);
+      if (gtk_window == NULL)
+        return;
+      children = gtk_container_get_children (GTK_CONTAINER (gtk_window));
+      index = n_children = g_list_length (children);
+      g_list_free (children);
+
+      if ((gpointer) object == (gpointer) (gtk_window->hscrollbar))
+        {
+          if (gtk_window->hscrollbar_visible)
+            child_added = TRUE;
+
+          child = gtk_widget_get_accessible (gtk_window->hscrollbar);
+        }
+      else if ((gpointer) object == (gpointer) (gtk_window->vscrollbar))
+        {
+          if (gtk_window->vscrollbar_visible)
+            child_added = TRUE;
+
+          child = gtk_widget_get_accessible (gtk_window->vscrollbar);
+          if (gtk_window->hscrollbar_visible)
+            index = n_children+1;
+        }
+      else 
+        {
+          g_assert_not_reached ();
+          return;
+        }
+
+      if (child_added)
+        signal_name = "children_changed::add";
+      else
+        signal_name = "children_changed::delete";
+
+      g_signal_emit_by_name (gail_window, signal_name, index, child, NULL);
+    }
+}
diff --git a/modules/other/gail/gailscrolledwindow.h b/modules/other/gail/gailscrolledwindow.h
new file mode 100644 (file)
index 0000000..0812823
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_SCROLLED_WINDOW_H__
+#define __GAIL_SCROLLED_WINDOW_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_SCROLLED_WINDOW            (gail_scrolled_window_get_type ())
+#define GAIL_SCROLLED_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_SCROLLED_WINDOW, GailScrolledWindow))
+#define GAIL_SCROLLED_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_SCROLLED_WINDOW, GailScrolledWindowClass))
+#define GAIL_IS_SCROLLED_WINDOW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_SCROLLED_WINDOW))
+#define GAIL_IS_SCROLLED_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_SCROLLED_WINDOW))
+#define GAIL_SCROLLED_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_SCROLLED_WINDOW, GailScrolledWindowClass))
+
+typedef struct _GailScrolledWindow              GailScrolledWindow;
+typedef struct _GailScrolledWindowClass         GailScrolledWindowClass;
+
+struct _GailScrolledWindow
+{
+  GailContainer parent;
+};
+
+GType gail_scrolled_window_get_type (void);
+
+struct _GailScrolledWindowClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_scrolled_window_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_SCROLLED_WINDOW_H__ */
diff --git a/modules/other/gail/gailseparator.c b/modules/other/gail/gailseparator.c
new file mode 100644 (file)
index 0000000..87eaa5f
--- /dev/null
@@ -0,0 +1,103 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailseparator.h"
+
+static void         gail_separator_class_init            (GailSeparatorClass  *klass); 
+static AtkStateSet* gail_separator_ref_state_set        (AtkObject           *accessible);
+
+static GailWidgetClass *parent_class = NULL;
+
+GType
+gail_separator_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailSeparatorClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_separator_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailSeparator), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (GAIL_TYPE_WIDGET,
+                                   "GailSeparator", &tinfo, 0);
+  }
+  return type;
+}
+
+static void
+gail_separator_class_init (GailSeparatorClass *klass)
+{
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_state_set = gail_separator_ref_state_set;
+}
+
+AtkObject* 
+gail_separator_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_SEPARATOR (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_SEPARATOR, NULL);
+
+  g_return_val_if_fail (GTK_IS_ACCESSIBLE (object), NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  accessible->role = ATK_ROLE_SEPARATOR;
+
+  return accessible;
+}
+
+static AtkStateSet*
+gail_separator_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  if (GTK_IS_VSEPARATOR (widget))
+    atk_state_set_add_state (state_set, ATK_STATE_VERTICAL);
+  else if (GTK_IS_HSEPARATOR (widget))
+    atk_state_set_add_state (state_set, ATK_STATE_HORIZONTAL);
+
+  return state_set;
+}
diff --git a/modules/other/gail/gailseparator.h b/modules/other/gail/gailseparator.h
new file mode 100644 (file)
index 0000000..765b73c
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_SEPARATOR_H__
+#define __GAIL_SEPARATOR_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailwidget.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_SEPARATOR                  (gail_separator_get_type ())
+#define GAIL_SEPARATOR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_SEPARATOR, GailSeparator))
+#define GAIL_SEPARATOR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_SEPARATOR, GailSeparatorClass))
+#define GAIL_IS_SEPARATOR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_SEPARATOR))
+#define GAIL_IS_SEPARATOR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_SEPARATOR))
+#define GAIL_SEPARATOR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_SEPARATOR, GailSeparatorClass))
+
+typedef struct _GailSeparator              GailSeparator;
+typedef struct _GailSeparatorClass         GailSeparatorClass;
+
+struct _GailSeparator
+{
+  GailWidget parent;
+};
+
+GType gail_separator_get_type (void);
+
+struct _GailSeparatorClass
+{
+  GailWidgetClass parent_class;
+};
+
+AtkObject *gail_separator_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_SEPARATOR_H__ */
diff --git a/modules/other/gail/gailspinbutton.c b/modules/other/gail/gailspinbutton.c
new file mode 100644 (file)
index 0000000..d38d1c2
--- /dev/null
@@ -0,0 +1,296 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailspinbutton.h"
+#include "gailadjustment.h"
+#include "gail-private-macros.h"
+
+static void      gail_spin_button_class_init        (GailSpinButtonClass *klass);
+static void      gail_spin_button_real_initialize   (AtkObject      *obj,
+                                                     gpointer       data);
+static void      gail_spin_button_finalize          (GObject        *object);
+
+static void      atk_value_interface_init           (AtkValueIface  *iface);
+
+static void      gail_spin_button_real_notify_gtk   (GObject        *obj,
+                                                     GParamSpec     *pspec);
+
+static void      gail_spin_button_get_current_value (AtkValue       *obj,
+                                                     GValue         *value);
+static void      gail_spin_button_get_maximum_value (AtkValue       *obj,
+                                                     GValue         *value);
+static void      gail_spin_button_get_minimum_value (AtkValue       *obj,
+                                                     GValue         *value);
+static gboolean  gail_spin_button_set_current_value (AtkValue       *obj,
+                                                     const GValue   *value);
+static void      gail_spin_button_value_changed     (GtkAdjustment  *adjustment,
+                                                     gpointer       data);
+                                                         
+static GailWidgetClass *parent_class = NULL;
+
+GType
+gail_spin_button_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailSpinButtonClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_spin_button_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailSpinButton), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_value_info =
+      {
+        (GInterfaceInitFunc) atk_value_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_ENTRY,
+                                     "GailSpinButton", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_VALUE,
+                                   &atk_value_info);
+    }
+
+  return type;
+}
+
+static void
+gail_spin_button_class_init (GailSpinButtonClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  widget_class = (GailWidgetClass*)klass;
+
+  widget_class->notify_gtk = gail_spin_button_real_notify_gtk;
+
+  class->initialize = gail_spin_button_real_initialize;
+
+  gobject_class->finalize = gail_spin_button_finalize;
+}
+
+AtkObject* 
+gail_spin_button_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_SPIN_BUTTON, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_spin_button_real_initialize (AtkObject *obj,
+                                  gpointer  data)
+{
+  GailSpinButton *spin_button = GAIL_SPIN_BUTTON (obj);
+  GtkSpinButton *gtk_spin_button;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  gtk_spin_button = GTK_SPIN_BUTTON (data); 
+  /*
+   * If a GtkAdjustment already exists for the spin_button, 
+   * create the GailAdjustment
+   */
+  if (gtk_spin_button->adjustment)
+    {
+      spin_button->adjustment = gail_adjustment_new (gtk_spin_button->adjustment);
+      g_signal_connect (gtk_spin_button->adjustment,
+                        "value-changed",
+                        G_CALLBACK (gail_spin_button_value_changed),
+                        obj);
+    }
+  else
+    spin_button->adjustment = NULL;
+
+  obj->role = ATK_ROLE_SPIN_BUTTON;
+
+}
+
+static void
+atk_value_interface_init (AtkValueIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_current_value = gail_spin_button_get_current_value;
+  iface->get_maximum_value = gail_spin_button_get_maximum_value;
+  iface->get_minimum_value = gail_spin_button_get_minimum_value;
+  iface->set_current_value = gail_spin_button_set_current_value;
+}
+
+static void
+gail_spin_button_get_current_value (AtkValue       *obj,
+                                    GValue         *value)
+{
+  GailSpinButton *spin_button;
+
+  g_return_if_fail (GAIL_IS_SPIN_BUTTON (obj));
+
+  spin_button = GAIL_SPIN_BUTTON (obj);
+  if (spin_button->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_current_value (ATK_VALUE (spin_button->adjustment), value);
+}
+
+static void      
+gail_spin_button_get_maximum_value (AtkValue       *obj,
+                                    GValue         *value)
+{
+  GailSpinButton *spin_button;
+
+  g_return_if_fail (GAIL_IS_SPIN_BUTTON (obj));
+
+  spin_button = GAIL_SPIN_BUTTON (obj);
+  if (spin_button->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_maximum_value (ATK_VALUE (spin_button->adjustment), value);
+}
+
+static void 
+gail_spin_button_get_minimum_value (AtkValue       *obj,
+                                    GValue         *value)
+{
+ GailSpinButton *spin_button;
+
+  g_return_if_fail (GAIL_IS_SPIN_BUTTON (obj));
+
+  spin_button = GAIL_SPIN_BUTTON (obj);
+  if (spin_button->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return;
+
+  atk_value_get_minimum_value (ATK_VALUE (spin_button->adjustment), value);
+}
+
+static gboolean  
+gail_spin_button_set_current_value (AtkValue       *obj,
+                                    const GValue   *value)
+{
+ GailSpinButton *spin_button;
+
+  g_return_val_if_fail (GAIL_IS_SPIN_BUTTON (obj), FALSE);
+
+  spin_button = GAIL_SPIN_BUTTON (obj);
+  if (spin_button->adjustment == NULL)
+    /*
+     * Adjustment has not been specified
+     */
+    return FALSE;
+
+  return atk_value_set_current_value (ATK_VALUE (spin_button->adjustment), value);
+}
+
+static void
+gail_spin_button_finalize (GObject            *object)
+{
+  GailSpinButton *spin_button = GAIL_SPIN_BUTTON (object);
+
+  if (spin_button->adjustment)
+    {
+      g_object_unref (spin_button->adjustment);
+      spin_button->adjustment = NULL;
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gail_spin_button_real_notify_gtk (GObject    *obj,
+                                  GParamSpec *pspec)
+{
+  GtkWidget *widget = GTK_WIDGET (obj);
+  GailSpinButton *spin_button = GAIL_SPIN_BUTTON (gtk_widget_get_accessible (widget));
+
+  if (strcmp (pspec->name, "adjustment") == 0)
+    {
+      /*
+       * Get rid of the GailAdjustment for the GtkAdjustment
+       * which was associated with the spin_button.
+       */
+      GtkSpinButton* gtk_spin_button;
+
+      if (spin_button->adjustment)
+        {
+          g_object_unref (spin_button->adjustment);
+          spin_button->adjustment = NULL;
+        }
+      /*
+       * Create the GailAdjustment when notify for "adjustment" property
+       * is received
+       */
+      gtk_spin_button = GTK_SPIN_BUTTON (widget);
+      spin_button->adjustment = gail_adjustment_new (gtk_spin_button->adjustment);
+      g_signal_connect (gtk_spin_button->adjustment,
+                        "value-changed",
+                        G_CALLBACK (gail_spin_button_value_changed),
+                        spin_button);
+    }
+  else
+    parent_class->notify_gtk (obj, pspec);
+}
+
+
+static void
+gail_spin_button_value_changed (GtkAdjustment    *adjustment,
+                                gpointer         data)
+{
+  GailSpinButton *spin_button;
+
+  gail_return_if_fail (adjustment != NULL);
+  gail_return_if_fail (data != NULL);
+
+  spin_button = GAIL_SPIN_BUTTON (data);
+
+  g_object_notify (G_OBJECT (spin_button), "accessible-value");
+}
+
diff --git a/modules/other/gail/gailspinbutton.h b/modules/other/gail/gailspinbutton.h
new file mode 100644 (file)
index 0000000..90e8f4a
--- /dev/null
@@ -0,0 +1,61 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_SPIN_BUTTON_H__
+#define __GAIL_SPIN_BUTTON_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailentry.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_SPIN_BUTTON                      (gail_spin_button_get_type ())
+#define GAIL_SPIN_BUTTON(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_SPIN_BUTTON, GailSpinButton))
+#define GAIL_SPIN_BUTTON_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_SPIN_BUTTON, GailSpinButtonClass))
+#define GAIL_IS_SPIN_BUTTON(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_SPIN_BUTTON))
+#define GAIL_IS_SPIN_BUTTON_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_SPIN_BUTTON))
+#define GAIL_SPIN_BUTTON_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_SPIN_BUTTON, GailSpinButtonClass))
+
+typedef struct _GailSpinButton              GailSpinButton;
+typedef struct _GailSpinButtonClass         GailSpinButtonClass;
+
+struct _GailSpinButton
+{
+  GailEntry parent;
+
+  AtkObject *adjustment;
+};
+
+GType gail_spin_button_get_type (void);
+
+struct _GailSpinButtonClass
+{
+  GailEntryClass parent_class;
+};
+
+AtkObject* gail_spin_button_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_SPIN_BUTTON_H__ */
diff --git a/modules/other/gail/gailstatusbar.c b/modules/other/gail/gailstatusbar.c
new file mode 100644 (file)
index 0000000..aca7774
--- /dev/null
@@ -0,0 +1,680 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailstatusbar.h"
+#include <libgail-util/gailmisc.h>
+
+static void         gail_statusbar_class_init          (GailStatusbarClass *klass);
+static G_CONST_RETURN gchar* gail_statusbar_get_name   (AtkObject          *obj);
+static gint         gail_statusbar_get_n_children      (AtkObject          *obj);
+static AtkObject*   gail_statusbar_ref_child           (AtkObject          *obj,
+                                                        gint               i);
+static void         gail_statusbar_real_initialize     (AtkObject          *obj,
+                                                        gpointer           data);
+
+static gint         gail_statusbar_notify              (GObject            *obj,
+                                                        GParamSpec         *pspec,
+                                                        gpointer           user_data);
+static void         gail_statusbar_finalize            (GObject            *object);
+static void         gail_statusbar_init_textutil       (GailStatusbar      *statusbar,
+                                                        GtkWidget          *label);
+
+/* atktext.h */ 
+static void      atk_text_interface_init          (AtkTextIface        *iface);
+
+static gchar*    gail_statusbar_get_text          (AtkText           *text,
+                                                    gint             start_pos,
+                                                   gint              end_pos);
+static gunichar          gail_statusbar_get_character_at_offset
+                                                   (AtkText          *text,
+                                                   gint              offset);
+static gchar*     gail_statusbar_get_text_before_offset
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_statusbar_get_text_at_offset(AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gchar*     gail_statusbar_get_text_after_offset
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   AtkTextBoundary   boundary_type,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+static gint      gail_statusbar_get_character_count (AtkText         *text);
+static void       gail_statusbar_get_character_extents
+                                                   (AtkText          *text,
+                                                   gint              offset,
+                                                   gint              *x,
+                                                   gint              *y,
+                                                   gint              *width,
+                                                   gint              *height,
+                                                   AtkCoordType      coords);
+static gint      gail_statusbar_get_offset_at_point(AtkText           *text,
+                                                    gint              x,
+                                                    gint              y,
+                                                   AtkCoordType      coords);
+static AtkAttributeSet* gail_statusbar_get_run_attributes 
+                                                   (AtkText           *text,
+                                                   gint              offset,
+                                                    gint             *start_offset,
+                                                   gint              *end_offset);
+static AtkAttributeSet* gail_statusbar_get_default_attributes
+                                                   (AtkText           *text);
+static GtkWidget* get_label_from_statusbar         (GtkWidget         *statusbar);
+
+static GailContainerClass* parent_class = NULL;
+
+GType
+gail_statusbar_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailStatusbarClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_statusbar_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailStatusbar), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailStatusbar", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+    }
+  return type;
+}
+
+static void
+gail_statusbar_class_init (GailStatusbarClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GailContainerClass *container_class;
+
+  container_class = (GailContainerClass*)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gail_statusbar_finalize;
+
+  class->get_name = gail_statusbar_get_name;
+  class->get_n_children = gail_statusbar_get_n_children;
+  class->ref_child = gail_statusbar_ref_child;
+  class->initialize = gail_statusbar_real_initialize;
+  /*
+   * As we report the statusbar as having no children we are not interested
+   * in add and remove signals
+   */
+  container_class->add_gtk = NULL;
+  container_class->remove_gtk = NULL;
+}
+
+AtkObject* 
+gail_statusbar_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_STATUSBAR (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_STATUSBAR, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static G_CONST_RETURN gchar*
+gail_statusbar_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar* name;
+
+  g_return_val_if_fail (GAIL_IS_STATUSBAR (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (obj);
+  if (name != NULL)
+    return name;
+  else
+    {
+      /*
+       * Get the text on the label
+       */
+      GtkWidget *widget;
+      GtkWidget *label;
+
+      widget = GTK_ACCESSIBLE (obj)->widget;
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+
+     g_return_val_if_fail (GTK_IS_STATUSBAR (widget), NULL);
+     label = get_label_from_statusbar (widget);
+     if (GTK_IS_LABEL (label))
+       return gtk_label_get_label (GTK_LABEL (label));
+     else 
+       return NULL;
+   }
+}
+
+static gint
+gail_statusbar_get_n_children (AtkObject *obj)
+{
+  GtkWidget *widget;
+  GList *children;
+  gint count = 0;
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return 0;
+
+  children = gtk_container_get_children (GTK_CONTAINER (widget));
+  if (children != NULL)
+    {
+      count = g_list_length (children);
+      g_list_free (children);
+    }
+
+  return count;
+}
+
+static AtkObject*
+gail_statusbar_ref_child (AtkObject *obj,
+                          gint      i)
+{
+  GList *children, *tmp_list;
+  AtkObject  *accessible;
+  GtkWidget *widget;
+
+  g_return_val_if_fail ((i >= 0), NULL);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    return NULL;
+
+  children = gtk_container_get_children (GTK_CONTAINER (widget));
+  if (children == NULL)
+    return NULL;
+
+  tmp_list = g_list_nth (children, i);
+  if (!tmp_list)
+    {
+      g_list_free (children);
+      return NULL;
+    }
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
+
+  g_list_free (children);
+  g_object_ref (accessible);
+  return accessible;
+}
+
+static void
+gail_statusbar_real_initialize (AtkObject *obj,
+                                gpointer  data)
+{
+  GailStatusbar *statusbar = GAIL_STATUSBAR (obj);
+  GtkWidget *label;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  /*
+   * We get notified of changes to the label
+   */
+  label = get_label_from_statusbar (GTK_WIDGET (data));
+  if (GTK_IS_LABEL (label))
+    {
+      gail_statusbar_init_textutil (statusbar, label);
+    }
+
+  obj->role = ATK_ROLE_STATUSBAR;
+
+}
+
+static gint
+gail_statusbar_notify (GObject    *obj, 
+                       GParamSpec *pspec,
+                       gpointer   user_data)
+{
+  AtkObject *atk_obj = ATK_OBJECT (user_data);
+  GtkLabel *label;
+  GailStatusbar *statusbar;
+
+  if (strcmp (pspec->name, "label") == 0)
+    {
+      const gchar* label_text;
+
+      label = GTK_LABEL (obj);
+
+      label_text = gtk_label_get_text (label);
+
+      statusbar = GAIL_STATUSBAR (atk_obj);
+      gail_text_util_text_setup (statusbar->textutil, label_text);
+
+      if (atk_obj->name == NULL)
+      {
+        /*
+         * The label has changed so notify a change in accessible-name
+         */
+        g_object_notify (G_OBJECT (atk_obj), "accessible-name");
+      }
+      /*
+       * The label is the only property which can be changed
+       */
+      g_signal_emit_by_name (atk_obj, "visible_data_changed");
+    }
+  return 1;
+}
+
+static void
+gail_statusbar_init_textutil (GailStatusbar *statusbar,
+                              GtkWidget     *label)
+{
+  const gchar *label_text;
+
+  statusbar->textutil = gail_text_util_new ();
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  gail_text_util_text_setup (statusbar->textutil, label_text);
+  g_signal_connect (label,
+                    "notify",
+                    (GCallback) gail_statusbar_notify,
+                    statusbar);     
+}
+
+static void
+gail_statusbar_finalize (GObject *object)
+{
+  GailStatusbar *statusbar = GAIL_STATUSBAR (object);
+
+  if (statusbar->textutil)
+    {
+      g_object_unref (statusbar->textutil);
+    }
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->get_text = gail_statusbar_get_text;
+  iface->get_character_at_offset = gail_statusbar_get_character_at_offset;
+  iface->get_text_before_offset = gail_statusbar_get_text_before_offset;
+  iface->get_text_at_offset = gail_statusbar_get_text_at_offset;
+  iface->get_text_after_offset = gail_statusbar_get_text_after_offset;
+  iface->get_character_count = gail_statusbar_get_character_count;
+  iface->get_character_extents = gail_statusbar_get_character_extents;
+  iface->get_offset_at_point = gail_statusbar_get_offset_at_point;
+  iface->get_run_attributes = gail_statusbar_get_run_attributes;
+  iface->get_default_attributes = gail_statusbar_get_default_attributes;
+}
+
+static gchar*
+gail_statusbar_get_text (AtkText *text,
+                         gint    start_pos,
+                         gint    end_pos)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailStatusbar *statusbar;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL (label))
+    return NULL;
+
+  statusbar = GAIL_STATUSBAR (text);
+  if (!statusbar->textutil) 
+    gail_statusbar_init_textutil (statusbar, label);
+
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+
+  if (label_text == NULL)
+    return NULL;
+  else
+  {
+    return gail_text_util_get_substring (statusbar->textutil, 
+                                         start_pos, end_pos);
+  }
+}
+
+static gchar*
+gail_statusbar_get_text_before_offset (AtkText         *text,
+                                      gint            offset,
+                                      AtkTextBoundary boundary_type,
+                                      gint            *start_offset,
+                                      gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailStatusbar *statusbar;
+  
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  statusbar = GAIL_STATUSBAR (text);
+  if (!statusbar->textutil)
+    gail_statusbar_init_textutil (statusbar, label);
+
+  return gail_text_util_get_text (statusbar->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset); 
+}
+
+static gchar*
+gail_statusbar_get_text_at_offset (AtkText         *text,
+                                  gint            offset,
+                                  AtkTextBoundary boundary_type,
+                                  gint            *start_offset,
+                                  gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailStatusbar *statusbar;
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+  
+  /* Get label */
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  statusbar = GAIL_STATUSBAR (text);
+  if (!statusbar->textutil)
+    gail_statusbar_init_textutil (statusbar, label);
+
+  return gail_text_util_get_text (statusbar->textutil,
+                              gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET, 
+                              boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar*
+gail_statusbar_get_text_after_offset (AtkText         *text,
+                                     gint            offset,
+                                     AtkTextBoundary boundary_type,
+                                     gint            *start_offset,
+                                     gint            *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  GailStatusbar *statusbar;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return NULL;
+  }
+  
+  /* Get label */
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  statusbar = GAIL_STATUSBAR (text);
+  if (!statusbar->textutil)
+    gail_statusbar_init_textutil (statusbar, label);
+
+  return gail_text_util_get_text (statusbar->textutil,
+                           gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET, 
+                           boundary_type, offset, start_offset, end_offset);
+}
+
+static gint
+gail_statusbar_get_character_count (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return 0;
+
+  return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
+}
+
+static void
+gail_statusbar_get_character_extents (AtkText      *text,
+                                     gint         offset,
+                                     gint         *x,
+                                     gint         *y,
+                                      gint        *width,
+                                      gint        *height,
+                                     AtkCoordType coords)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  PangoRectangle char_rect;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+  widget = GTK_ACCESSIBLE (text)->widget;
+
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
+  pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
+  
+  gail_misc_get_extents_from_pango_rectangle (label, &char_rect, 
+                    x_layout, y_layout, x, y, width, height, coords);
+} 
+
+static gint 
+gail_statusbar_get_offset_at_point (AtkText      *text,
+                                    gint         x,
+                                    gint         y,
+                                   AtkCoordType coords)
+{ 
+  GtkWidget *widget;
+  GtkWidget *label;
+  gint index, x_layout, y_layout;
+  const gchar *label_text;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return -1;
+  
+  gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
+  
+  index = gail_misc_get_index_at_point_in_layout (label, 
+                                              gtk_label_get_layout (GTK_LABEL (label)), 
+                                              x_layout, y_layout, x, y, coords);
+  label_text = gtk_label_get_text (GTK_LABEL (label));
+  if (index == -1)
+    {
+      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+        return g_utf8_strlen (label_text, -1);
+
+      return index;  
+    }
+  else
+    return g_utf8_pointer_to_offset (label_text, label_text + index);  
+}
+
+static AtkAttributeSet*
+gail_statusbar_get_run_attributes (AtkText *text,
+                                   gint    offset,
+                                   gint    *start_offset,
+                                  gint    *end_offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+  GtkJustification justify;
+  GtkTextDirection dir;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+  
+  /* Get values set for entire label, if any */
+  justify = gtk_label_get_justify (GTK_LABEL (label));
+  if (justify != GTK_JUSTIFY_CENTER)
+    {
+      at_set = gail_misc_add_attribute (at_set, 
+                                        ATK_TEXT_ATTR_JUSTIFICATION,
+     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
+    }
+  dir = gtk_widget_get_direction (label);
+  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)));
+    }
+
+  at_set = gail_misc_layout_get_run_attributes (at_set,
+                                                gtk_label_get_layout (GTK_LABEL (label)),
+                                                (gchar *) gtk_label_get_text (GTK_LABEL (label)),
+                                                offset,
+                                                start_offset,
+                                                end_offset);
+  return at_set;
+}
+
+static AtkAttributeSet*
+gail_statusbar_get_default_attributes (AtkText *text)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  AtkAttributeSet *at_set = NULL;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return NULL;
+
+  at_set = gail_misc_get_default_attributes (at_set,
+                                             gtk_label_get_layout (GTK_LABEL (label)),
+                                             widget);
+  return at_set;
+}
+
+static gunichar 
+gail_statusbar_get_character_at_offset (AtkText *text,
+                                        gint   offset)
+{
+  GtkWidget *widget;
+  GtkWidget *label;
+  const gchar *string;
+  gchar *index;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return '\0';
+
+  label = get_label_from_statusbar (widget);
+
+  if (!GTK_IS_LABEL(label))
+    return '\0';
+  string = gtk_label_get_text (GTK_LABEL (label));
+  if (offset >= g_utf8_strlen (string, -1))
+    return '\0';
+  index = g_utf8_offset_to_pointer (string, offset);
+
+  return g_utf8_get_char (index);
+}
+
+static GtkWidget*
+get_label_from_statusbar (GtkWidget *statusbar)
+{
+  return GTK_STATUSBAR (statusbar)->label;
+}
diff --git a/modules/other/gail/gailstatusbar.h b/modules/other/gail/gailstatusbar.h
new file mode 100644 (file)
index 0000000..43d25f3
--- /dev/null
@@ -0,0 +1,62 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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_STATUSBAR_H__
+#define __GAIL_STATUSBAR_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_STATUSBAR                  (gail_statusbar_get_type ())
+#define GAIL_STATUSBAR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_STATUSBAR, GailStatusbar))
+#define GAIL_STATUSBAR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_STATUSBAR, GailStatusbarClass))
+#define GAIL_IS_STATUSBAR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_STATUSBAR))
+#define GAIL_IS_STATUSBAR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_STATUSBAR))
+#define GAIL_STATUSBAR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_STATUSBAR, GailStatusbarClass))
+
+typedef struct _GailStatusbar              GailStatusbar;
+typedef struct _GailStatusbarClass         GailStatusbarClass;
+
+struct _GailStatusbar
+{
+  GailContainer parent;
+
+  GailTextUtil *textutil;
+};
+
+GType gail_statusbar_get_type (void);
+
+struct _GailStatusbarClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_statusbar_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_STATUSBAR_H__ */
diff --git a/modules/other/gail/gailsubmenuitem.c b/modules/other/gail/gailsubmenuitem.c
new file mode 100644 (file)
index 0000000..b26df6b
--- /dev/null
@@ -0,0 +1,382 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002, 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 <gtk/gtk.h>
+#include "gailsubmenuitem.h"
+
+static void         gail_sub_menu_item_class_init       (GailSubMenuItemClass *klass);
+static void         gail_sub_menu_item_real_initialize  (AtkObject      *obj,
+                                                         gpointer       data);
+
+static void         atk_selection_interface_init        (AtkSelectionIface  *iface);
+static gboolean     gail_sub_menu_item_add_selection    (AtkSelection   *selection,
+                                                         gint           i);
+static gboolean     gail_sub_menu_item_clear_selection  (AtkSelection   *selection);
+static AtkObject*   gail_sub_menu_item_ref_selection    (AtkSelection   *selection,
+                                                         gint           i);
+static gint         gail_sub_menu_item_get_selection_count
+                                                        (AtkSelection   *selection);
+static gboolean     gail_sub_menu_item_is_child_selected
+                                                        (AtkSelection   *selection,
+                                                         gint           i);
+static gboolean     gail_sub_menu_item_remove_selection (AtkSelection   *selection,
+                                                         gint           i);
+static gint         menu_item_add_gtk                   (GtkContainer   *container,
+                                                         GtkWidget      *widget);
+static gint         menu_item_remove_gtk                (GtkContainer   *container,
+                                                         GtkWidget      *widget);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_sub_menu_item_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailSubMenuItemClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_sub_menu_item_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailSubMenuItem), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    static const GInterfaceInfo atk_selection_info =
+    {
+        (GInterfaceInitFunc) atk_selection_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+    };
+
+    type = g_type_register_static (GAIL_TYPE_MENU_ITEM,
+                                   "GailSubMenuItem", &tinfo, 0);
+    g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                 &atk_selection_info);
+  }
+
+  return type;
+}
+
+static void
+gail_sub_menu_item_class_init (GailSubMenuItemClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  class->initialize = gail_sub_menu_item_real_initialize;
+
+  parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gail_sub_menu_item_real_initialize (AtkObject *obj,
+                                   gpointer   data)
+{
+  GtkWidget *submenu;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (data));
+  g_return_if_fail (submenu);
+
+  g_signal_connect (submenu,
+                    "add",
+                    G_CALLBACK (menu_item_add_gtk),
+                    NULL);
+  g_signal_connect (submenu,
+                    "remove",
+                    G_CALLBACK (menu_item_remove_gtk),
+                    NULL);
+
+  obj->role = ATK_ROLE_MENU;
+}
+
+AtkObject*
+gail_sub_menu_item_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_SUB_MENU_ITEM, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->add_selection = gail_sub_menu_item_add_selection;
+  iface->clear_selection = gail_sub_menu_item_clear_selection;
+  iface->ref_selection = gail_sub_menu_item_ref_selection;
+  iface->get_selection_count = gail_sub_menu_item_get_selection_count;
+  iface->is_child_selected = gail_sub_menu_item_is_child_selected;
+  iface->remove_selection = gail_sub_menu_item_remove_selection;
+  /*
+   * select_all_selection does not make sense for a submenu of a menu item
+   * so no implementation is provided.
+   */
+}
+
+static gboolean
+gail_sub_menu_item_add_selection (AtkSelection *selection,
+                                  gint          i)
+{
+  GtkMenuShell *shell;
+  GList *item;
+  guint length;
+  GtkWidget *widget;
+  GtkWidget *submenu;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
+  shell = GTK_MENU_SHELL (submenu);
+  length = g_list_length (shell->children);
+  if (i < 0 || i > length)
+    return FALSE;
+
+  item = g_list_nth (shell->children, i);
+  g_return_val_if_fail (item != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_MENU_ITEM(item->data), FALSE);
+   
+  gtk_menu_shell_select_item (shell, GTK_WIDGET (item->data));
+  return TRUE;
+}
+
+static gboolean
+gail_sub_menu_item_clear_selection (AtkSelection   *selection)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+  GtkWidget *submenu;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
+  shell = GTK_MENU_SHELL (submenu);
+
+  gtk_menu_shell_deselect (shell);
+  return TRUE;
+}
+
+static AtkObject*
+gail_sub_menu_item_ref_selection (AtkSelection   *selection,
+                                  gint           i)
+{
+  GtkMenuShell *shell;
+  AtkObject *obj;
+  GtkWidget *widget;
+  GtkWidget *submenu;
+
+  if (i != 0)
+    return NULL;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), NULL);
+  shell = GTK_MENU_SHELL (submenu);
+  
+  if (shell->active_menu_item != NULL)
+    {
+      obj = gtk_widget_get_accessible (shell->active_menu_item);
+      g_object_ref (obj);
+      return obj;
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
+static gint
+gail_sub_menu_item_get_selection_count (AtkSelection   *selection)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+  GtkWidget *submenu;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
+  shell = GTK_MENU_SHELL (submenu);
+
+  /*
+   * Identifies the currently selected menu item
+   */
+  if (shell->active_menu_item == NULL)
+    return 0;
+  else
+    return 1;
+}
+
+static gboolean
+gail_sub_menu_item_is_child_selected (AtkSelection   *selection,
+                                       gint           i)
+{
+  GtkMenuShell *shell;
+  gint j;
+  GtkWidget *widget;
+  GtkWidget *submenu;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
+  shell = GTK_MENU_SHELL (submenu);
+
+  if (shell->active_menu_item == NULL)
+    return FALSE;
+  
+  j = g_list_index (shell->children, shell->active_menu_item);
+
+  return (j==i);   
+}
+
+static gboolean
+gail_sub_menu_item_remove_selection (AtkSelection   *selection,
+                                  gint           i)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+  GtkWidget *submenu;
+
+  if (i != 0)
+    return FALSE;
+
+  widget =  GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
+  shell = GTK_MENU_SHELL (submenu);
+
+  if (shell->active_menu_item && 
+      GTK_MENU_ITEM (shell->active_menu_item)->submenu)
+    {
+    /*
+     * Menu item contains a menu and it is the selected menu item
+     * so deselect it.
+     */
+      gtk_menu_shell_deselect (shell);
+    }
+  return TRUE;
+}
+
+static gint
+menu_item_add_gtk (GtkContainer *container,
+                   GtkWidget   *widget)
+{
+  GtkWidget *parent_widget;
+  AtkObject *atk_parent;
+  AtkObject *atk_child;
+  GailContainer *gail_container;
+  gint index;
+
+  g_return_val_if_fail (GTK_IS_MENU (container), 1);
+
+  parent_widget = gtk_menu_get_attach_widget (GTK_MENU (container));
+  if (GTK_IS_MENU_ITEM (parent_widget))
+    {
+      atk_parent = gtk_widget_get_accessible (parent_widget);
+      atk_child = gtk_widget_get_accessible (widget);
+
+      gail_container = GAIL_CONTAINER (atk_parent);
+      g_object_notify (G_OBJECT (atk_child), "accessible_parent");
+
+      g_list_free (gail_container->children);
+      gail_container->children = gtk_container_get_children (container);
+      index = g_list_index (gail_container->children, widget);
+      g_signal_emit_by_name (atk_parent, "children_changed::add",
+                             index, atk_child, NULL);
+    }
+  return 1;
+}
+
+static gint
+menu_item_remove_gtk (GtkContainer *container,
+                      GtkWidget           *widget)
+{
+  GtkWidget *parent_widget;
+  AtkObject *atk_parent;
+  AtkObject *atk_child;
+  GailContainer *gail_container;
+  AtkPropertyValues values = { NULL };
+  gint index;
+  gint list_length;
+
+  g_return_val_if_fail (GTK_IS_MENU (container), 1);
+
+  parent_widget = gtk_menu_get_attach_widget (GTK_MENU (container));
+  if (GTK_IS_MENU_ITEM (parent_widget))
+    {
+      atk_parent = gtk_widget_get_accessible (parent_widget);
+      atk_child = gtk_widget_get_accessible (widget);
+
+      gail_container = GAIL_CONTAINER (atk_parent);
+      g_value_init (&values.old_value, G_TYPE_POINTER);
+      g_value_set_pointer (&values.old_value, atk_parent);
+      values.property_name = "accessible-parent";
+      g_signal_emit_by_name (atk_child,
+                             "property_change::accessible-parent", &values, NULL);
+
+      index = g_list_index (gail_container->children, widget);
+      list_length = g_list_length (gail_container->children);
+      g_list_free (gail_container->children);
+      gail_container->children = gtk_container_get_children (container);
+      if (index >= 0 && index <= list_length)
+        g_signal_emit_by_name (atk_parent, "children_changed::remove",
+                               index, atk_child, NULL);
+    }
+  return 1;
+}
diff --git a/modules/other/gail/gailsubmenuitem.h b/modules/other/gail/gailsubmenuitem.h
new file mode 100644 (file)
index 0000000..91334c5
--- /dev/null
@@ -0,0 +1,60 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2002 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_SUB_MENU_ITEM_H__
+#define __GAIL_SUB_MENU_ITEM_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailmenuitem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_SUB_MENU_ITEM                     (gail_sub_menu_item_get_type ())
+#define GAIL_SUB_MENU_ITEM(obj)                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_SUB_MENU_ITEM, GailSubMenuItem))
+#define GAIL_SUB_MENU_ITEM_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_SUB_MENU_ITEM, GailSubMenuItemClass))
+#define GAIL_IS_SUB_MENU_ITEM(obj)                  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_SUB_MENU_ITEM))
+#define GAIL_IS_SUB_MENU_ITEM_CLASS(klass)          (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_SUB_MENU_ITEM))
+#define GAIL_SUB_MENU_ITEM_GET_CLASS(obj)           (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_SUB_MENU_ITEM, GailSubMenuItemClass))
+
+typedef struct _GailSubMenuItem                   GailSubMenuItem;
+typedef struct _GailSubMenuItemClass              GailSubMenuItemClass;
+
+struct _GailSubMenuItem
+{
+  GailMenuItem parent;
+
+};
+
+GType gail_sub_menu_item_get_type (void);
+
+struct _GailSubMenuItemClass
+{
+  GailMenuItemClass parent_class;
+};
+
+AtkObject* gail_sub_menu_item_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_SUB_MENU_ITEM_H__ */
diff --git a/modules/other/gail/gailtextcell.c b/modules/other/gail/gailtextcell.c
new file mode 100644 (file)
index 0000000..25c814c
--- /dev/null
@@ -0,0 +1,696 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtk.h>
+#include "gailtextcell.h"
+#include "gailcontainercell.h"
+#include "gailcellparent.h"
+#include <libgail-util/gailmisc.h>
+#include "gail-private-macros.h"
+
+static void      gail_text_cell_class_init             (GailTextCellClass *klass);
+static void      gail_text_cell_init                   (GailTextCell   *text_cell);
+static void      gail_text_cell_finalize               (GObject        *object);
+
+static G_CONST_RETURN gchar* gail_text_cell_get_name    (AtkObject      *atk_obj);
+
+static void      atk_text_interface_init               (AtkTextIface   *iface);
+
+/* atktext.h */
+
+static gchar*    gail_text_cell_get_text               (AtkText        *text,
+                                                       gint            start_pos,
+                                                       gint            end_pos);
+static gunichar gail_text_cell_get_character_at_offset (AtkText        *text,
+                                                        gint           offset);
+static gchar*  gail_text_cell_get_text_before_offset   (AtkText        *text,
+                                                        gint           offset,
+                                                        AtkTextBoundary boundary_type,
+                                                        gint           *start_offset,
+                                                        gint           *end_offset);
+static gchar*  gail_text_cell_get_text_at_offset       (AtkText        *text,
+                                                        gint           offset,
+                                                        AtkTextBoundary boundary_type,
+                                                        gint           *start_offset,
+                                                        gint           *end_offset);
+static gchar*  gail_text_cell_get_text_after_offset    (AtkText        *text,
+                                                        gint           offset,
+                                                        AtkTextBoundary boundary_type,
+                                                        gint           *start_offset,
+                                                        gint           *end_offset);
+static gint      gail_text_cell_get_character_count    (AtkText        *text);
+static gint      gail_text_cell_get_caret_offset       (AtkText        *text);
+static gboolean  gail_text_cell_set_caret_offset       (AtkText        *text,
+                                                        gint           offset);
+static void      gail_text_cell_get_character_extents  (AtkText        *text,
+                                                        gint           offset,
+                                                        gint           *x,
+                                                        gint           *y,
+                                                        gint           *width,
+                                                        gint           *height,
+                                                        AtkCoordType   coords);
+static gint      gail_text_cell_get_offset_at_point    (AtkText        *text,
+                                                        gint           x,
+                                                        gint           y,
+                                                        AtkCoordType   coords);
+static AtkAttributeSet* gail_text_cell_get_run_attributes 
+                                                        (AtkText       *text,
+                                                        gint           offset,
+                                                        gint           *start_offset,      
+                                                        gint           *end_offset); 
+static AtkAttributeSet* gail_text_cell_get_default_attributes 
+                                                        (AtkText        *text);
+
+static PangoLayout*     create_pango_layout             (GtkCellRendererText *gtk_renderer,
+                                                         GtkWidget           *widget);
+static void             add_attr                        (PangoAttrList  *attr_list,
+                                                         PangoAttribute *attr);
+
+/* Misc */
+
+static gboolean gail_text_cell_update_cache            (GailRendererCell *cell,
+                                                        gboolean       emit_change_signal);
+
+gchar *gail_text_cell_property_list[] = {
+  /* Set font_desc first since it resets other values if it is NULL */
+  "font_desc",
+
+  "attributes",
+  "background_gdk",
+  "editable",
+  "family",
+  "foreground_gdk",
+  "rise",
+  "scale",
+  "size",
+  "size_points",
+  "stretch",
+  "strikethrough",
+  "style",
+  "text",
+  "underline",
+  "variant",
+  "weight",
+
+  /* Also need the sets */
+  "background_set",
+  "editable_set",
+  "family_set",
+  "foreground_set",
+  "rise_set",
+  "scale_set",
+  "size_set",
+  "stretch_set",
+  "strikethrough_set",
+  "style_set",
+  "underline_set",
+  "variant_set",
+  "weight_set",
+  NULL
+};
+
+static gpointer parent_class = NULL;
+
+GType
+gail_text_cell_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailTextCellClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_text_cell_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailTextCell), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_text_cell_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_RENDERER_CELL,
+                                     "GailTextCell", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+      gail_cell_type_add_action_interface (type);
+    }
+  return type;
+}
+
+static void 
+gail_text_cell_class_init (GailTextCellClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
+  GailRendererCellClass *renderer_cell_class = GAIL_RENDERER_CELL_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+  renderer_cell_class->update_cache = gail_text_cell_update_cache;
+  renderer_cell_class->property_list = gail_text_cell_property_list;
+
+  atk_object_class->get_name = gail_text_cell_get_name;
+
+  gobject_class->finalize = gail_text_cell_finalize;
+}
+
+/* atktext.h */
+
+static void
+gail_text_cell_init (GailTextCell *text_cell)
+{
+  text_cell->cell_text = NULL;
+  text_cell->caret_pos = 0;
+  text_cell->cell_length = 0;
+  text_cell->textutil = gail_text_util_new ();
+  atk_state_set_add_state (GAIL_CELL (text_cell)->state_set,
+                           ATK_STATE_SINGLE_LINE);
+}
+
+AtkObject* 
+gail_text_cell_new (void)
+{
+  GObject *object;
+  AtkObject *atk_object;
+  GailRendererCell *cell;
+
+  object = g_object_new (GAIL_TYPE_TEXT_CELL, NULL);
+
+  g_return_val_if_fail (object != NULL, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object->role = ATK_ROLE_TABLE_CELL;
+
+  cell = GAIL_RENDERER_CELL(object);
+
+  cell->renderer = gtk_cell_renderer_text_new ();
+  g_object_ref (cell->renderer);
+  gtk_object_sink (GTK_OBJECT (cell->renderer));
+  return atk_object;
+}
+
+static void
+gail_text_cell_finalize (GObject            *object)
+{
+  GailTextCell *text_cell = GAIL_TEXT_CELL (object);
+
+  g_object_unref (text_cell->textutil);
+  g_free (text_cell->cell_text);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static G_CONST_RETURN gchar*
+gail_text_cell_get_name (AtkObject *atk_obj)
+{
+  if (atk_obj->name)
+    return atk_obj->name;
+  else
+    {
+      GailTextCell *text_cell = GAIL_TEXT_CELL (atk_obj);
+
+      return text_cell->cell_text;
+    }
+}
+
+static gboolean
+gail_text_cell_update_cache (GailRendererCell *cell,
+                             gboolean         emit_change_signal)
+{
+  GailTextCell *text_cell = GAIL_TEXT_CELL (cell);
+  AtkObject *obj = ATK_OBJECT (cell);
+  gboolean rv = FALSE;
+  gint temp_length;
+  gchar *new_cache;
+
+  g_object_get (G_OBJECT (cell->renderer), "text", &new_cache, NULL);
+
+  if (text_cell->cell_text)
+    {
+     /*
+      * If the new value is NULL and the old value isn't NULL, then the
+      * value has changed.
+      */
+      if (new_cache == NULL ||
+          g_strcasecmp (text_cell->cell_text, new_cache))
+        {
+          g_free (text_cell->cell_text);
+          temp_length = text_cell->cell_length;
+          text_cell->cell_text = NULL;
+          text_cell->cell_length = 0;
+          if (emit_change_signal)
+            {
+              g_signal_emit_by_name (cell, "text_changed::delete", 0, temp_length);
+              if (obj->name == NULL)
+                g_object_notify (G_OBJECT (obj), "accessible-name");
+            }
+          if (new_cache)
+            rv = TRUE;
+        }
+    }
+  else
+    rv = TRUE;
+
+  if (rv)
+    {
+      if (new_cache == NULL)
+        {
+          text_cell->cell_text = g_strdup ("");
+          text_cell->cell_length = 0;
+        }
+      else
+        {
+          text_cell->cell_text = g_strdup (new_cache);
+          text_cell->cell_length = g_utf8_strlen (new_cache, -1);
+        }
+    }
+
+  g_free (new_cache);
+  gail_text_util_text_setup (text_cell->textutil, text_cell->cell_text);
+  
+  if (rv)
+    {
+      if (emit_change_signal)
+        {
+          g_signal_emit_by_name (cell, "text_changed::insert",
+                                0, text_cell->cell_length);
+
+          if (obj->name == NULL)
+            g_object_notify (G_OBJECT (obj), "accessible-name");
+        }
+    }
+  return rv;
+}
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->get_text = gail_text_cell_get_text;
+  iface->get_character_at_offset = gail_text_cell_get_character_at_offset;
+  iface->get_text_before_offset = gail_text_cell_get_text_before_offset;
+  iface->get_text_at_offset = gail_text_cell_get_text_at_offset;
+  iface->get_text_after_offset = gail_text_cell_get_text_after_offset;
+  iface->get_character_count = gail_text_cell_get_character_count;
+  iface->get_caret_offset = gail_text_cell_get_caret_offset;
+  iface->set_caret_offset = gail_text_cell_set_caret_offset;
+  iface->get_run_attributes = gail_text_cell_get_run_attributes;
+  iface->get_default_attributes = gail_text_cell_get_default_attributes;
+  iface->get_character_extents = gail_text_cell_get_character_extents;
+  iface->get_offset_at_point = gail_text_cell_get_offset_at_point;
+}
+
+static gchar* 
+gail_text_cell_get_text (AtkText *text, 
+                         gint    start_pos,
+                         gint    end_pos)
+{
+  if (GAIL_TEXT_CELL (text)->cell_text)
+    return gail_text_util_get_substring (GAIL_TEXT_CELL (text)->textutil,
+              start_pos, end_pos);
+  else
+    return g_strdup ("");
+}
+
+static gchar* 
+gail_text_cell_get_text_before_offset (AtkText         *text,
+                                       gint            offset,
+                                       AtkTextBoundary boundary_type,
+                                       gint            *start_offset,
+                                       gint            *end_offset)
+{
+  return gail_text_util_get_text (GAIL_TEXT_CELL (text)->textutil,
+        NULL, GAIL_BEFORE_OFFSET, boundary_type, offset, start_offset,
+        end_offset);
+}
+
+static gchar* 
+gail_text_cell_get_text_at_offset (AtkText         *text,
+                                   gint            offset,
+                                   AtkTextBoundary boundary_type,
+                                   gint            *start_offset,
+                                   gint            *end_offset)
+{
+  return gail_text_util_get_text (GAIL_TEXT_CELL (text)->textutil,
+        NULL, GAIL_AT_OFFSET, boundary_type, offset, start_offset, end_offset);
+}
+
+static gchar* 
+gail_text_cell_get_text_after_offset (AtkText         *text,
+                                      gint            offset,
+                                      AtkTextBoundary boundary_type,
+                                      gint            *start_offset,
+                                      gint            *end_offset)
+{
+  return gail_text_util_get_text (GAIL_TEXT_CELL (text)->textutil,
+        NULL, GAIL_AFTER_OFFSET, boundary_type, offset, start_offset,
+        end_offset);
+}
+
+static gint 
+gail_text_cell_get_character_count (AtkText *text)
+{
+  if (GAIL_TEXT_CELL (text)->cell_text != NULL)
+    return GAIL_TEXT_CELL (text)->cell_length;
+  else
+    return 0;
+}
+
+static gint 
+gail_text_cell_get_caret_offset (AtkText *text)
+{
+  return GAIL_TEXT_CELL (text)->caret_pos;
+}
+
+static gboolean 
+gail_text_cell_set_caret_offset (AtkText *text,
+                                 gint    offset)
+{
+  GailTextCell *text_cell = GAIL_TEXT_CELL (text);
+
+  if (text_cell->cell_text == NULL)
+    return FALSE;
+  else
+    {
+
+      /* Only set the caret within the bounds and if it is to a new position. */
+      if (offset >= 0 && 
+          offset <= text_cell->cell_length &&
+          offset != text_cell->caret_pos)
+        {
+          text_cell->caret_pos = offset;
+
+          /* emit the signal */
+          g_signal_emit_by_name (text, "text_caret_moved", offset);
+          return TRUE;
+        }
+      else
+        return FALSE;
+    }
+}
+
+static AtkAttributeSet*
+gail_text_cell_get_run_attributes (AtkText *text,
+                                  gint     offset,
+                                  gint     *start_offset,
+                                  gint     *end_offset) 
+{
+  GailRendererCell *gail_renderer; 
+  GtkCellRendererText *gtk_renderer;
+  AtkAttributeSet *attrib_set = NULL;
+  PangoLayout *layout;
+  AtkObject *parent;
+  GtkWidget *widget;
+
+  gail_renderer = GAIL_RENDERER_CELL (text);
+  gtk_renderer = GTK_CELL_RENDERER_TEXT (gail_renderer->renderer);
+
+  parent = atk_object_get_parent (ATK_OBJECT (text));
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    parent = atk_object_get_parent (parent);
+  g_return_val_if_fail (GAIL_IS_CELL_PARENT (parent), NULL);
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  layout = create_pango_layout (gtk_renderer, widget),
+  attrib_set = gail_misc_layout_get_run_attributes (attrib_set, 
+                                                    layout,
+                                                    gtk_renderer->text,
+                                                    offset,
+                                                    start_offset,
+                                                    end_offset);
+  g_object_unref (G_OBJECT (layout));
+  
+  return attrib_set;
+}
+
+static AtkAttributeSet*
+gail_text_cell_get_default_attributes (AtkText *text)
+{
+  GailRendererCell *gail_renderer; 
+  GtkCellRendererText *gtk_renderer;
+  AtkAttributeSet *attrib_set = NULL;
+  PangoLayout *layout;
+  AtkObject *parent;
+  GtkWidget *widget;
+
+  gail_renderer = GAIL_RENDERER_CELL (text);
+  gtk_renderer = GTK_CELL_RENDERER_TEXT (gail_renderer->renderer);
+
+  parent = atk_object_get_parent (ATK_OBJECT (text));
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    parent = atk_object_get_parent (parent);
+  g_return_val_if_fail (GAIL_IS_CELL_PARENT (parent), NULL);
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  layout = create_pango_layout (gtk_renderer, widget),
+
+  attrib_set = gail_misc_get_default_attributes (attrib_set, 
+                                                 layout,
+                                                 widget);
+  g_object_unref (G_OBJECT (layout));
+  return attrib_set;
+}
+
+/* 
+ * This function is used by gail_text_cell_get_offset_at_point()
+ * and gail_text_cell_get_character_extents(). There is no 
+ * cached PangoLayout for gailtextcell so we must create a temporary
+ * one using this function.
+ */ 
+static PangoLayout*
+create_pango_layout(GtkCellRendererText *gtk_renderer,
+                    GtkWidget           *widget)
+{
+  PangoAttrList *attr_list;
+  PangoLayout *layout;
+  PangoUnderline uline;
+  PangoFontMask mask;
+
+  layout = gtk_widget_create_pango_layout (widget, gtk_renderer->text);
+
+  if (gtk_renderer->extra_attrs)
+    attr_list = pango_attr_list_copy (gtk_renderer->extra_attrs);
+  else
+    attr_list = pango_attr_list_new ();
+
+  if (gtk_renderer->foreground_set)
+    {
+      PangoColor color;
+      color = gtk_renderer->foreground;
+      add_attr (attr_list, pango_attr_foreground_new (color.red,
+                                                      color.green, color.blue));
+    }
+
+  if (gtk_renderer->strikethrough_set)
+    add_attr (attr_list,
+              pango_attr_strikethrough_new (gtk_renderer->strikethrough));
+
+  mask = pango_font_description_get_set_fields (gtk_renderer->font);
+
+  if (mask & PANGO_FONT_MASK_FAMILY)
+    add_attr (attr_list,
+      pango_attr_family_new (pango_font_description_get_family (gtk_renderer->font)));
+
+  if (mask & PANGO_FONT_MASK_STYLE)
+    add_attr (attr_list, pango_attr_style_new (pango_font_description_get_style (gtk_renderer->font)));
+
+  if (mask & PANGO_FONT_MASK_VARIANT)
+    add_attr (attr_list, pango_attr_variant_new (pango_font_description_get_variant (gtk_renderer->font)));
+
+  if (mask & PANGO_FONT_MASK_WEIGHT)
+    add_attr (attr_list, pango_attr_weight_new (pango_font_description_get_weight (gtk_renderer->font)));
+
+  if (mask & PANGO_FONT_MASK_STRETCH)
+    add_attr (attr_list, pango_attr_stretch_new (pango_font_description_get_stretch (gtk_renderer->font)));
+
+  if (mask & PANGO_FONT_MASK_SIZE)
+    add_attr (attr_list, pango_attr_size_new (pango_font_description_get_size (gtk_renderer->font)));
+
+  if (gtk_renderer->scale_set &&
+      gtk_renderer->font_scale != 1.0)
+    add_attr (attr_list, pango_attr_scale_new (gtk_renderer->font_scale));
+
+  if (gtk_renderer->underline_set)
+    uline = gtk_renderer->underline_style;
+  else
+    uline = PANGO_UNDERLINE_NONE;
+
+  if (uline != PANGO_UNDERLINE_NONE)
+    add_attr (attr_list,
+      pango_attr_underline_new (gtk_renderer->underline_style));
+
+  if (gtk_renderer->rise_set)
+    add_attr (attr_list, pango_attr_rise_new (gtk_renderer->rise));
+
+  pango_layout_set_attributes (layout, attr_list);
+  pango_layout_set_width (layout, -1);
+  pango_attr_list_unref (attr_list);
+
+  return layout;
+}
+
+static void 
+add_attr (PangoAttrList  *attr_list,
+         PangoAttribute *attr)
+{
+  attr->start_index = 0;
+  attr->end_index = G_MAXINT;
+  pango_attr_list_insert (attr_list, attr);
+}
+
+static void      
+gail_text_cell_get_character_extents (AtkText          *text,
+                                      gint             offset,
+                                      gint             *x,
+                                      gint             *y,
+                                      gint             *width,
+                                      gint             *height,
+                                      AtkCoordType     coords)
+{
+  GailRendererCell *gail_renderer; 
+  GtkCellRendererText *gtk_renderer;
+  GdkRectangle rendered_rect;
+  GtkWidget *widget;
+  AtkObject *parent;
+  PangoRectangle char_rect;
+  PangoLayout *layout;
+  gint x_offset, y_offset, index, cell_height, cell_width;
+
+  if (!GAIL_TEXT_CELL (text)->cell_text)
+    {
+      *x = *y = *height = *width = 0;
+      return;
+    }
+  if (offset < 0 || offset >= GAIL_TEXT_CELL (text)->cell_length)
+    {
+      *x = *y = *height = *width = 0;
+      return;
+    }
+  gail_renderer = GAIL_RENDERER_CELL (text);
+  gtk_renderer = GTK_CELL_RENDERER_TEXT (gail_renderer->renderer);
+  /*
+   * Thus would be inconsistent with the cache
+   */
+  gail_return_if_fail (gtk_renderer->text);
+
+  parent = atk_object_get_parent (ATK_OBJECT (text));
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    parent = atk_object_get_parent (parent);
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  g_return_if_fail (GAIL_IS_CELL_PARENT (parent));
+  gail_cell_parent_get_cell_area (GAIL_CELL_PARENT (parent), GAIL_CELL (text),
+                                  &rendered_rect);
+
+  gtk_cell_renderer_get_size (GTK_CELL_RENDERER (gtk_renderer), widget,
+    &rendered_rect, &x_offset, &y_offset, &cell_width, &cell_height);
+  layout = create_pango_layout (gtk_renderer, widget);
+
+  index = g_utf8_offset_to_pointer (gtk_renderer->text,
+    offset) - gtk_renderer->text;
+  pango_layout_index_to_pos (layout, index, &char_rect); 
+
+  gail_misc_get_extents_from_pango_rectangle (widget,
+      &char_rect,
+      x_offset + rendered_rect.x + gail_renderer->renderer->xpad,
+      y_offset + rendered_rect.y + gail_renderer->renderer->ypad,
+      x, y, width, height, coords);
+  g_object_unref (layout);
+  return;
+} 
+
+static gint      
+gail_text_cell_get_offset_at_point (AtkText          *text,
+                                    gint             x,
+                                    gint             y,
+                                    AtkCoordType     coords)
+{
+  AtkObject *parent;
+  GailRendererCell *gail_renderer; 
+  GtkCellRendererText *gtk_renderer;
+  GtkWidget *widget;
+  GdkRectangle rendered_rect;
+  PangoLayout *layout;
+  gint x_offset, y_offset, index;
+  if (!GAIL_TEXT_CELL (text)->cell_text)
+    return -1;
+
+  gail_renderer = GAIL_RENDERER_CELL (text);
+  gtk_renderer = GTK_CELL_RENDERER_TEXT (gail_renderer->renderer);
+  parent = atk_object_get_parent (ATK_OBJECT (text));
+
+  g_return_val_if_fail (gtk_renderer->text, -1);
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    parent = atk_object_get_parent (parent);
+
+  widget = GTK_ACCESSIBLE (parent)->widget;
+
+  g_return_val_if_fail (GAIL_IS_CELL_PARENT (parent), -1);
+  gail_cell_parent_get_cell_area (GAIL_CELL_PARENT (parent), GAIL_CELL (text),
+                                  &rendered_rect);
+  gtk_cell_renderer_get_size (GTK_CELL_RENDERER (gtk_renderer), widget,
+     &rendered_rect, &x_offset, &y_offset, NULL, NULL);
+
+  layout = create_pango_layout (gtk_renderer, widget);
+   
+  index = gail_misc_get_index_at_point_in_layout (widget, layout,
+        x_offset + rendered_rect.x + gail_renderer->renderer->xpad,
+        y_offset + rendered_rect.y + gail_renderer->renderer->ypad,
+        x, y, coords);
+  g_object_unref (layout);
+  if (index == -1)
+    {
+      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
+        return g_utf8_strlen (gtk_renderer->text, -1);
+    
+      return index;  
+    }
+  else
+    return g_utf8_pointer_to_offset (gtk_renderer->text,
+       gtk_renderer->text + index);  
+}
+
+static gunichar 
+gail_text_cell_get_character_at_offset (AtkText       *text,
+                                        gint          offset)
+{
+  gchar *index;
+  gchar *string;
+
+  string = GAIL_TEXT_CELL(text)->cell_text;
+
+  if (!string)
+    return '\0';
+
+  if (offset >= g_utf8_strlen (string, -1))
+    return '\0';
+
+  index = g_utf8_offset_to_pointer (string, offset);
+
+  return g_utf8_get_char (index);
+}
+
diff --git a/modules/other/gail/gailtextcell.h b/modules/other/gail/gailtextcell.h
new file mode 100644 (file)
index 0000000..76c1ade
--- /dev/null
@@ -0,0 +1,64 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_TEXT_CELL_H__
+#define __GAIL_TEXT_CELL_H__
+
+#include <atk/atk.h>
+#include <gail/gailrenderercell.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_TEXT_CELL            (gail_text_cell_get_type ())
+#define GAIL_TEXT_CELL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_TEXT_CELL, GailTextCell))
+#define GAIL_TEXT_CELL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TEXT_CELL, GailTextCellClass))
+#define GAIL_IS_TEXT_CELL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_TEXT_CELL))
+#define GAIL_IS_TEXT_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_TEXT_CELL))
+#define GAIL_TEXT_CELL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_TEXT_CELL, GailTextCellClass))
+
+typedef struct _GailTextCell                  GailTextCell;
+typedef struct _GailTextCellClass             GailTextCellClass;
+
+struct _GailTextCell
+{
+  GailRendererCell parent;
+  GailTextUtil *textutil;
+  gchar *cell_text;
+  gint caret_pos;
+  gint cell_length;
+};
+
+GType gail_text_cell_get_type (void);
+
+struct _GailTextCellClass
+{
+  GailRendererCellClass parent_class;
+};
+
+AtkObject *gail_text_cell_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TREE_VIEW_TEXT_CELL_H__ */
diff --git a/modules/other/gail/gailtextcellfactory.c b/modules/other/gail/gailtextcellfactory.c
new file mode 100644 (file)
index 0000000..b981a7c
--- /dev/null
@@ -0,0 +1,79 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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 <gtk/gtkcellrenderertext.h>
+#include "gailtextcellfactory.h"
+#include "gailtextcell.h"
+
+static void gail_text_cell_factory_class_init (GailTextCellFactoryClass        *klass);
+
+static AtkObject* gail_text_cell_factory_create_accessible (
+                                GObject                              *obj);
+
+static GType gail_text_cell_factory_get_accessible_type (void);
+
+GType
+gail_text_cell_factory_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) 
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailTextCellFactoryClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_text_cell_factory_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailTextCellFactory), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+    type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
+                           "GailTextCellFactory" , &tinfo, 0);
+  }
+
+  return type;
+}
+
+static void 
+gail_text_cell_factory_class_init (GailTextCellFactoryClass *klass)
+{
+  AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+  class->create_accessible = gail_text_cell_factory_create_accessible;
+  class->get_accessible_type = gail_text_cell_factory_get_accessible_type;
+}
+
+static AtkObject* 
+gail_text_cell_factory_create_accessible (GObject     *obj)
+{
+  g_return_val_if_fail (GTK_IS_CELL_RENDERER_TEXT (obj), NULL);
+
+  return gail_text_cell_new ();
+}
+
+static GType
+gail_text_cell_factory_get_accessible_type (void)
+{
+  return GAIL_TYPE_TEXT_CELL;
+}
diff --git a/modules/other/gail/gailtextcellfactory.h b/modules/other/gail/gailtextcellfactory.h
new file mode 100644 (file)
index 0000000..1aae137
--- /dev/null
@@ -0,0 +1,56 @@
+/* GAIL - The GNOME Accessibility Enabling Library
+ * Copyright 2001 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_TEXT_CELL_FACTORY_H__
+#define __GAIL_TEXT_CELL_FACTORY_H__
+
+#include <atk/atkobjectfactory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_TEXT_CELL_FACTORY                 (gail_text_cell_factory_get_type ())
+#define GAIL_TEXT_CELL_FACTORY(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_TEXT_CELL_FACTORY, GailTextCellFactory))
+#define GAIL_TEXT_CELL_FACTORY_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), AGTK_TYPE_TEXT_CELL_FACTORY, GailTextCellFactoryClass))
+#define GAIL_IS_TEXT_CELL_FACTORY(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_TEXT_CELL_FACTORY))
+#define GAIL_IS_TEXT_CELL_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_TEXT_CELL_FACTORY))
+#define GAIL_TEXT_CELL_FACTORY_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_TEXT_CELL_FACTORY, GailTextCellFactoryClass))
+
+typedef struct _GailTextCellFactory             GailTextCellFactory;
+typedef struct _GailTextCellFactoryClass        GailTextCellFactoryClass;
+
+struct _GailTextCellFactory
+{
+  AtkObjectFactory parent;
+};
+
+struct _GailTextCellFactoryClass
+{
+  AtkObjectFactoryClass parent_class;
+};
+
+GType gail_text_cell_factory_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TEXT_CELL_FACTORY_H__ */
diff --git a/modules/other/gail/gailtextview.c b/modules/other/gail/gailtextview.c
new file mode 100644 (file)
index 0000000..e99e02a
--- /dev/null
@@ -0,0 +1,1819 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include "gailtextview.h"
+#include <libgail-util/gailmisc.h>
+
+static void       gail_text_view_class_init            (GailTextViewClass *klass);
+static void       gail_text_view_init                  (GailTextView      *text_view);
+
+static void       gail_text_view_real_initialize       (AtkObject         *obj,
+                                                        gpointer          data);
+static void       gail_text_view_real_notify_gtk       (GObject           *obj,
+                                                        GParamSpec        *pspec);
+
+static void       gail_text_view_finalize              (GObject           *object);
+
+static void       atk_text_interface_init              (AtkTextIface     *iface);
+
+/* atkobject.h */
+
+static AtkStateSet* gail_text_view_ref_state_set       (AtkObject        *accessible);
+
+/* atktext.h */
+
+static gchar*     gail_text_view_get_text_after_offset (AtkText          *text,
+                                                        gint             offset,
+                                                        AtkTextBoundary  boundary_type,
+                                                        gint             *start_offset,
+                                                        gint             *end_offset);
+static gchar*     gail_text_view_get_text_at_offset    (AtkText          *text,
+                                                        gint             offset,
+                                                        AtkTextBoundary  boundary_type,
+                                                        gint             *start_offset,
+                                                        gint             *end_offset);
+static gchar*     gail_text_view_get_text_before_offset (AtkText         *text,
+                                                        gint             offset,
+                                                        AtkTextBoundary  boundary_type,
+                                                        gint             *start_offset,
+                                                        gint             *end_offset);
+static gchar*     gail_text_view_get_text              (AtkText*text,
+                                                        gint             start_offset,
+                                                        gint             end_offset);
+static gunichar   gail_text_view_get_character_at_offset (AtkText        *text,
+                                                        gint             offset);
+static gint       gail_text_view_get_character_count   (AtkText          *text);
+static gint       gail_text_view_get_caret_offset      (AtkText          *text);
+static gboolean   gail_text_view_set_caret_offset      (AtkText          *text,
+                                                        gint             offset);
+static gint       gail_text_view_get_offset_at_point   (AtkText          *text,
+                                                        gint             x,
+                                                        gint             y,
+                                                        AtkCoordType     coords);
+static gint       gail_text_view_get_n_selections      (AtkText          *text);
+static gchar*     gail_text_view_get_selection         (AtkText          *text,
+                                                        gint             selection_num,
+                                                        gint             *start_offset,
+                                                        gint             *end_offset);
+static gboolean   gail_text_view_add_selection         (AtkText          *text,
+                                                        gint             start_offset,
+                                                        gint             end_offset);
+static gboolean   gail_text_view_remove_selection      (AtkText          *text,
+                                                        gint             selection_num);
+static gboolean   gail_text_view_set_selection         (AtkText          *text,
+                                                        gint             selection_num,
+                                                        gint             start_offset,
+                                                        gint             end_offset);
+static void       gail_text_view_get_character_extents (AtkText          *text,
+                                                        gint             offset,
+                                                        gint             *x,
+                                                        gint             *y,
+                                                        gint             *width,
+                                                        gint             *height,
+                                                        AtkCoordType     coords);
+static AtkAttributeSet *  gail_text_view_get_run_attributes 
+                                                       (AtkText          *text,
+                                                        gint             offset,
+                                                        gint             *start_offset,
+                                                        gint             *end_offset);
+static AtkAttributeSet *  gail_text_view_get_default_attributes 
+                                                       (AtkText          *text);
+/* atkeditabletext.h */
+
+static void       atk_editable_text_interface_init     (AtkEditableTextIface *iface);
+static gboolean   gail_text_view_set_run_attributes    (AtkEditableText  *text,
+                                                        AtkAttributeSet  *attrib_set,
+                                                        gint             start_offset,
+                                                        gint             end_offset);
+static void       gail_text_view_set_text_contents     (AtkEditableText  *text,
+                                                        const gchar      *string);
+static void       gail_text_view_insert_text           (AtkEditableText  *text,
+                                                        const gchar      *string,
+                                                        gint             length,
+                                                        gint             *position);
+static void       gail_text_view_copy_text             (AtkEditableText  *text,
+                                                        gint             start_pos,
+                                                        gint             end_pos);
+static void       gail_text_view_cut_text              (AtkEditableText  *text,
+                                                        gint             start_pos,
+                                                        gint             end_pos);
+static void       gail_text_view_delete_text           (AtkEditableText  *text,
+                                                        gint             start_pos,
+                                                        gint             end_pos);
+static void       gail_text_view_paste_text            (AtkEditableText  *text,
+                                                        gint             position);
+static void       gail_text_view_paste_received        (GtkClipboard     *clipboard,
+                                                        const gchar      *text,
+                                                        gpointer         data);
+/* AtkStreamableContent */
+static void       atk_streamable_content_interface_init    (AtkStreamableContentIface *iface);
+static gint       gail_streamable_content_get_n_mime_types (AtkStreamableContent *streamable);
+static G_CONST_RETURN gchar* gail_streamable_content_get_mime_type (AtkStreamableContent *streamable,
+                                                                   gint i);
+static GIOChannel* gail_streamable_content_get_stream       (AtkStreamableContent *streamable,
+                                                            const gchar *mime_type);
+/* getURI requires atk-1.12.0 or later
+static void       gail_streamable_content_get_uri          (AtkStreamableContent *streamable);
+*/
+
+/* Callbacks */
+
+static void       _gail_text_view_insert_text_cb       (GtkTextBuffer    *buffer,
+                                                        GtkTextIter      *arg1,
+                                                        gchar            *arg2,
+                                                        gint             arg3,
+                                                        gpointer         user_data);
+static void       _gail_text_view_delete_range_cb      (GtkTextBuffer    *buffer,
+                                                        GtkTextIter      *arg1,
+                                                        GtkTextIter      *arg2,
+                                                        gpointer         user_data);
+static void       _gail_text_view_changed_cb           (GtkTextBuffer    *buffer,
+                                                        gpointer         user_data);
+static void       _gail_text_view_mark_set_cb          (GtkTextBuffer    *buffer,
+                                                        GtkTextIter      *arg1,
+                                                        GtkTextMark      *arg2,
+                                                        gpointer         user_data);
+static gchar*            get_text_near_offset          (AtkText          *text,
+                                                        GailOffsetType   function,
+                                                        AtkTextBoundary  boundary_type,
+                                                        gint             offset,
+                                                        gint             *start_offset,
+                                                        gint             *end_offset);
+static gint             get_insert_offset              (GtkTextBuffer    *buffer);
+static gint             get_selection_bound            (GtkTextBuffer    *buffer);
+static void             emit_text_caret_moved          (GailTextView     *gail_text_view,
+                                                        gint             insert_offset);
+static gint             insert_idle_handler            (gpointer         data);
+
+static GailWidgetClass *parent_class = NULL;
+
+typedef struct _GailTextViewPaste                       GailTextViewPaste;
+
+struct _GailTextViewPaste
+{
+  GtkTextBuffer* buffer;
+  gint position;
+};
+
+GType
+gail_text_view_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailTextViewClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_text_view_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailTextView), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_text_view_init, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_editable_text_info =
+      {
+        (GInterfaceInitFunc) atk_editable_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_text_info =
+      {
+        (GInterfaceInitFunc) atk_text_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo atk_streamable_content_info =
+      {
+        (GInterfaceInitFunc) atk_streamable_content_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailTextView", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT,
+                                   &atk_editable_text_info);
+      g_type_add_interface_static (type, ATK_TYPE_TEXT,
+                                   &atk_text_info);
+      g_type_add_interface_static (type, ATK_TYPE_STREAMABLE_CONTENT,
+                                   &atk_streamable_content_info);
+    }
+
+  return type;
+}
+
+static void
+gail_text_view_class_init (GailTextViewClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GailWidgetClass *widget_class;
+
+  widget_class = (GailWidgetClass*)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gail_text_view_finalize;
+
+  class->ref_state_set = gail_text_view_ref_state_set;
+  class->initialize = gail_text_view_real_initialize;
+
+  widget_class->notify_gtk = gail_text_view_real_notify_gtk;
+}
+
+static void
+gail_text_view_init (GailTextView      *text_view)
+{
+  text_view->textutil = NULL;
+  text_view->signal_name = NULL;
+  text_view->previous_insert_offset = -1;
+  text_view->previous_selection_bound = -1;
+  text_view->insert_notify_handler = 0;
+}
+
+static void
+setup_buffer (GtkTextView  *view, 
+              GailTextView *gail_view)
+{
+  GtkTextBuffer *buffer;
+
+  buffer = view->buffer;
+  if (buffer == NULL)
+    return;
+
+  gail_view->textutil = gail_text_util_new ();
+  gail_text_util_buffer_setup (gail_view->textutil, buffer);
+
+  /* Set up signal callbacks */
+  g_signal_connect_data (buffer, "insert-text",
+     (GCallback) _gail_text_view_insert_text_cb, view, NULL, 0);
+  g_signal_connect_data (buffer, "delete-range",
+     (GCallback) _gail_text_view_delete_range_cb, view, NULL, 0);
+  g_signal_connect_data (buffer, "mark-set",
+     (GCallback) _gail_text_view_mark_set_cb, view, NULL, 0);
+  g_signal_connect_data (buffer, "changed",
+     (GCallback) _gail_text_view_changed_cb, view, NULL, 0);
+
+}
+
+static void
+gail_text_view_real_initialize (AtkObject *obj,
+                                gpointer  data)
+{
+  GtkTextView *view;
+  GailTextView *gail_view;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  view = GTK_TEXT_VIEW (data);
+
+  gail_view = GAIL_TEXT_VIEW (obj);
+  setup_buffer (view, gail_view);
+
+  obj->role = ATK_ROLE_TEXT;
+
+}
+
+static void
+gail_text_view_finalize (GObject            *object)
+{
+  GailTextView *text_view = GAIL_TEXT_VIEW (object);
+
+  g_object_unref (text_view->textutil);
+  if (text_view->insert_notify_handler)
+    g_source_remove (text_view->insert_notify_handler);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+AtkObject*
+gail_text_view_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_TEXT_VIEW, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_text_view_real_notify_gtk (GObject             *obj,
+                                GParamSpec          *pspec)
+{
+  if (!strcmp (pspec->name, "editable"))
+    {
+      AtkObject *atk_obj;
+      gboolean editable;
+
+      atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj));
+      editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj));
+      atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE,
+                                      editable);
+    }
+  else if (!strcmp (pspec->name, "buffer"))
+    {
+      AtkObject *atk_obj;
+
+      atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj));
+      setup_buffer (GTK_TEXT_VIEW (obj), GAIL_TEXT_VIEW (atk_obj));
+    }
+  else
+    parent_class->notify_gtk (obj, pspec);
+}
+
+/* atkobject.h */
+
+static AtkStateSet*
+gail_text_view_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkTextView *text_view;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+    return state_set;
+
+  text_view = GTK_TEXT_VIEW (widget);
+
+  if (gtk_text_view_get_editable (text_view))
+    atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
+  atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE);
+
+  return state_set;
+}
+
+/* atktext.h */
+
+static void
+atk_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_text = gail_text_view_get_text;
+  iface->get_text_after_offset = gail_text_view_get_text_after_offset;
+  iface->get_text_at_offset = gail_text_view_get_text_at_offset;
+  iface->get_text_before_offset = gail_text_view_get_text_before_offset;
+  iface->get_character_at_offset = gail_text_view_get_character_at_offset;
+  iface->get_character_count = gail_text_view_get_character_count;
+  iface->get_caret_offset = gail_text_view_get_caret_offset;
+  iface->set_caret_offset = gail_text_view_set_caret_offset;
+  iface->get_offset_at_point = gail_text_view_get_offset_at_point;
+  iface->get_character_extents = gail_text_view_get_character_extents;
+  iface->get_n_selections = gail_text_view_get_n_selections;
+  iface->get_selection = gail_text_view_get_selection;
+  iface->add_selection = gail_text_view_add_selection;
+  iface->remove_selection = gail_text_view_remove_selection;
+  iface->set_selection = gail_text_view_set_selection;
+  iface->get_run_attributes = gail_text_view_get_run_attributes;
+  iface->get_default_attributes = gail_text_view_get_default_attributes;
+}
+
+static gchar*
+gail_text_view_get_text (AtkText *text,
+                         gint    start_offset,
+                         gint    end_offset)
+{
+  GtkTextView *view;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
+  gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
+
+  return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+}
+
+static gchar*
+gail_text_view_get_text_after_offset (AtkText         *text,
+                                      gint            offset,
+                                      AtkTextBoundary boundary_type,
+                                      gint            *start_offset,
+                                      gint            *end_offset)
+{
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  return get_text_near_offset (text, GAIL_AFTER_OFFSET,
+                               boundary_type, offset, 
+                               start_offset, end_offset);
+}
+
+static gchar*
+gail_text_view_get_text_at_offset (AtkText         *text,
+                                   gint            offset,
+                                   AtkTextBoundary boundary_type,
+                                   gint            *start_offset,
+                                   gint            *end_offset)
+{
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  return get_text_near_offset (text, GAIL_AT_OFFSET,
+                               boundary_type, offset, 
+                               start_offset, end_offset);
+}
+
+static gchar*
+gail_text_view_get_text_before_offset (AtkText         *text,
+                                       gint            offset,
+                                       AtkTextBoundary boundary_type,
+                                       gint            *start_offset,
+                                       gint            *end_offset)
+{
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  return get_text_near_offset (text, GAIL_BEFORE_OFFSET,
+                               boundary_type, offset, 
+                               start_offset, end_offset);
+}
+
+static gunichar
+gail_text_view_get_character_at_offset (AtkText *text,
+                                        gint    offset)
+{
+  GtkWidget *widget;
+  GtkTextIter start, end;
+  GtkTextBuffer *buffer;
+  gchar *string;
+  gunichar unichar;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    return '\0';
+
+  buffer = GAIL_TEXT_VIEW (text)->textutil->buffer;
+  if (offset >= gtk_text_buffer_get_char_count (buffer))
+    return '\0';
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
+  end = start;
+  gtk_text_iter_forward_char (&end);
+  string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
+  unichar = g_utf8_get_char (string);
+  g_free(string);
+  return unichar;
+}
+
+static gint
+gail_text_view_get_character_count (AtkText *text)
+{
+  GtkTextView *view;
+  GtkTextBuffer *buffer;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+  return gtk_text_buffer_get_char_count (buffer);
+}
+
+static gint
+gail_text_view_get_caret_offset (AtkText *text)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  view = GTK_TEXT_VIEW (widget);
+  return get_insert_offset (view->buffer);
+}
+
+static gboolean
+gail_text_view_set_caret_offset (AtkText *text,
+                                 gint    offset)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, offset);
+  gtk_text_buffer_place_cursor (buffer, &pos_itr);
+  return TRUE;
+}
+
+static gint
+gail_text_view_get_offset_at_point (AtkText      *text,
+                                    gint         x,
+                                    gint         y,
+                                    AtkCoordType coords)
+{
+  GtkTextView *view;
+  GtkTextBuffer *buffer;
+  GtkTextIter loc_itr;
+  gint x_widget, y_widget, x_window, y_window, buff_x, buff_y;
+  GtkWidget *widget;
+  GdkWindow *window;
+  GdkRectangle rect;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
+  gdk_window_get_origin (window, &x_widget, &y_widget);
+
+  if (coords == ATK_XY_SCREEN)
+    {
+      x = x - x_widget;
+      y = y - y_widget;
+    }
+  else if (coords == ATK_XY_WINDOW)
+    {
+      window = gdk_window_get_toplevel (window);
+      gdk_window_get_origin (window, &x_window, &y_window);
+
+      x = x - x_widget + x_window;
+      y = y - y_widget + y_window;
+    }
+  else
+    return -1;
+
+  gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_WIDGET,
+                                         x, y, &buff_x, &buff_y);
+  gtk_text_view_get_visible_rect (view, &rect);
+  /*
+   * Clamp point to visible rectangle
+   */
+  buff_x = CLAMP (buff_x, rect.x, rect.x + rect.width - 1);
+  buff_y = CLAMP (buff_y, rect.y, rect.y + rect.height - 1);
+
+  gtk_text_view_get_iter_at_location (view, &loc_itr, buff_x, buff_y);
+  /*
+   * The iter at a location sometimes points to the next character.
+   * See bug 111031. We work around that
+   */
+  gtk_text_view_get_iter_location (view, &loc_itr, &rect);
+  if (buff_x < rect.x)
+    gtk_text_iter_backward_char (&loc_itr);
+  return gtk_text_iter_get_offset (&loc_itr);
+}
+
+static void
+gail_text_view_get_character_extents (AtkText      *text,
+                                      gint         offset,
+                                      gint         *x,
+                                      gint         *y,
+                                      gint         *width,
+                                      gint         *height,
+                                      AtkCoordType coords)
+{
+  GtkTextView *view;
+  GtkTextBuffer *buffer;
+  GtkTextIter iter;
+  GtkWidget *widget;
+  GdkRectangle rectangle;
+  GdkWindow *window;
+  gint x_widget, y_widget, x_window, y_window;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
+  gtk_text_view_get_iter_location (view, &iter, &rectangle);
+
+  window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
+  gdk_window_get_origin (window, &x_widget, &y_widget);
+
+  *height = rectangle.height;
+  *width = rectangle.width;
+
+  gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_WIDGET,
+    rectangle.x, rectangle.y, x, y);
+  if (coords == ATK_XY_WINDOW)
+    {
+      window = gdk_window_get_toplevel (window);
+      gdk_window_get_origin (window, &x_window, &y_window);
+      *x += x_widget - x_window;
+        *y += y_widget - y_window;
+    }
+  else if (coords == ATK_XY_SCREEN)
+    {
+      *x += x_widget;
+      *y += y_widget;
+    }
+  else
+    {
+      *x = 0;
+      *y = 0;
+      *height = 0;
+      *width = 0;
+    }
+}
+
+static AtkAttributeSet*
+gail_text_view_get_run_attributes (AtkText *text,
+                                   gint    offset,
+                                   gint    *start_offset,
+                                   gint    *end_offset)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  view = GTK_TEXT_VIEW (widget);
+
+  return gail_misc_buffer_get_run_attributes (view->buffer, offset, 
+                                              start_offset, end_offset);
+}
+
+static AtkAttributeSet*
+gail_text_view_get_default_attributes (AtkText *text)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextAttributes *text_attrs;
+  AtkAttributeSet *attrib_set = NULL;
+  PangoFontDescription *font;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  view = GTK_TEXT_VIEW (widget);
+  text_attrs = gtk_text_view_get_default_attributes (view);
+
+  font = text_attrs->font;
+
+  if (font)
+    {
+      attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                              ATK_TEXT_ATTR_STYLE);
+
+      attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                              ATK_TEXT_ATTR_VARIANT);
+
+      attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                              ATK_TEXT_ATTR_STRETCH);
+    }
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_JUSTIFICATION);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_DIRECTION);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_WRAP_MODE);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_FG_STIPPLE);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_BG_STIPPLE);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_FG_COLOR);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_BG_COLOR);
+
+  if (font)
+    {
+      attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                              ATK_TEXT_ATTR_FAMILY_NAME);
+    }
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_LANGUAGE);
+
+  if (font)
+    {
+      attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                              ATK_TEXT_ATTR_WEIGHT);
+    }
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_SCALE);
+
+  if (font)
+    {
+      attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                              ATK_TEXT_ATTR_SIZE);
+    }
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_STRIKETHROUGH);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_UNDERLINE);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_RISE);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_BG_FULL_HEIGHT);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                         ATK_TEXT_ATTR_PIXELS_BELOW_LINES);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_PIXELS_ABOVE_LINES);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_EDITABLE);
+    
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_INVISIBLE);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_INDENT);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_RIGHT_MARGIN);
+
+  attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, 
+                                          ATK_TEXT_ATTR_LEFT_MARGIN);
+
+  gtk_text_attributes_unref (text_attrs);
+  return attrib_set;
+}
+
+static gint
+gail_text_view_get_n_selections (AtkText *text)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+  gint select_start, select_end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset (&start);
+  select_end = gtk_text_iter_get_offset (&end);
+
+  if (select_start != select_end)
+     return 1;
+  else
+     return 0;
+}
+
+static gchar*
+gail_text_view_get_selection (AtkText *text,
+                              gint    selection_num,
+                              gint    *start_pos,
+                              gint    *end_pos)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+ /* Only let the user get the selection if one is set, and if the
+  * selection_num is 0.
+  */
+  if (selection_num != 0)
+     return NULL;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+  *start_pos = gtk_text_iter_get_offset (&start);
+  *end_pos = gtk_text_iter_get_offset (&end);
+
+  if (*start_pos != *end_pos)
+    return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+  else
+    return NULL;
+}
+
+static gboolean
+gail_text_view_add_selection (AtkText *text,
+                              gint    start_pos,
+                              gint    end_pos)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
+  GtkTextIter start, end;
+  gint select_start, select_end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset (&start);
+  select_end = gtk_text_iter_get_offset (&end);
+
+ /* If there is already a selection, then don't allow another to be added,
+  * since GtkTextView only supports one selected region.
+  */
+  if (select_start == select_end)
+    {
+      gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, start_pos);
+      gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
+      gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, end_pos);
+      gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+gail_text_view_remove_selection (AtkText *text,
+                                 gint    selection_num)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextMark *cursor_mark;
+  GtkTextIter cursor_itr;
+  GtkTextIter start, end;
+  gint select_start, select_end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  if (selection_num != 0)
+     return FALSE;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset(&start);
+  select_end = gtk_text_iter_get_offset(&end);
+
+  if (select_start != select_end)
+    {
+     /* Setting the start & end of the selected region to the caret position
+      * turns off the selection.
+      */
+      cursor_mark = gtk_text_buffer_get_insert (buffer);
+      gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
+      gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cursor_itr);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+gail_text_view_set_selection (AtkText *text,
+                              gint    selection_num,
+                              gint    start_pos,
+                              gint    end_pos)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
+  GtkTextIter start, end;
+  gint select_start, select_end;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+  {
+    /* State is defunct */
+    return FALSE;
+  }
+
+ /* Only let the user move the selection if one is set, and if the
+  * selection_num is 0
+  */
+  if (selection_num != 0)
+     return FALSE;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset(&start);
+  select_end = gtk_text_iter_get_offset(&end);
+
+  if (select_start != select_end)
+    {
+      gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, start_pos);
+      gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
+      gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, end_pos);
+      gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+/* atkeditabletext.h */
+
+static void
+atk_editable_text_interface_init (AtkEditableTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->set_text_contents = gail_text_view_set_text_contents;
+  iface->insert_text = gail_text_view_insert_text;
+  iface->copy_text = gail_text_view_copy_text;
+  iface->cut_text = gail_text_view_cut_text;
+  iface->delete_text = gail_text_view_delete_text;
+  iface->paste_text = gail_text_view_paste_text;
+  iface->set_run_attributes = gail_text_view_set_run_attributes;
+}
+
+static gboolean
+gail_text_view_set_run_attributes (AtkEditableText *text,
+                                   AtkAttributeSet *attrib_set,
+                                   gint            start_offset,
+                                   gint            end_offset)
+{
+  GtkTextView *view;
+  GtkTextBuffer *buffer;
+  GtkWidget *widget;
+  GtkTextTag *tag;
+  GtkTextIter start;
+  GtkTextIter end;
+  gint j;
+  GdkColor *color;
+  gchar** RGB_vals;
+  GSList *l;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  view = GTK_TEXT_VIEW (widget);
+  if (!gtk_text_view_get_editable (view))
+    return FALSE;
+
+  buffer = view->buffer;
+
+  if (attrib_set == NULL)
+    return FALSE;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
+  gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
+
+  tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
+
+  for (l = attrib_set; l; l = l->next)
+    {
+      gchar *name;
+      gchar *value;
+      AtkAttribute *at;
+
+      at = l->data;
+
+      name = at->name;
+      value = at->value;
+
+      if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LEFT_MARGIN)))
+        g_object_set (G_OBJECT (tag), "left_margin", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RIGHT_MARGIN)))
+        g_object_set (G_OBJECT (tag), "right_margin", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INDENT)))
+        g_object_set (G_OBJECT (tag), "indent", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_ABOVE_LINES)))
+        g_object_set (G_OBJECT (tag), "pixels_above_lines", atoi (value), NULL);
+
+      else if (!g_strcasecmp(name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_BELOW_LINES)))
+        g_object_set (G_OBJECT (tag), "pixels_below_lines", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP)))
+        g_object_set (G_OBJECT (tag), "pixels_inside_wrap", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_SIZE)))
+        g_object_set (G_OBJECT (tag), "size", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RISE)))
+        g_object_set (G_OBJECT (tag), "rise", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WEIGHT)))
+        g_object_set (G_OBJECT (tag), "weight", atoi (value), NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_FULL_HEIGHT)))
+        {
+          g_object_set (G_OBJECT (tag), "bg_full_height", 
+                   (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, 0))),
+                   NULL);
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LANGUAGE)))
+        g_object_set (G_OBJECT (tag), "language", value, NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FAMILY_NAME)))
+        g_object_set (G_OBJECT (tag), "family", value, NULL);
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_EDITABLE)))
+        {
+          g_object_set (G_OBJECT (tag), "editable", 
+                   (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
+                   NULL);
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INVISIBLE)))
+        {
+          g_object_set (G_OBJECT (tag), "invisible", 
+                   (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
+                   NULL);
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_UNDERLINE)))
+        {
+          for (j = 0; j < 3; j++)
+            {
+              if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, j)))
+                {
+                  g_object_set (G_OBJECT (tag), "underline", j, NULL);
+                  break;
+                }
+            } 
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRIKETHROUGH)))
+        {
+          g_object_set (G_OBJECT (tag), "strikethrough", 
+                   (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0))),
+                   NULL);
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_COLOR)))
+        {
+          RGB_vals = g_strsplit (value, ",", 3);
+          color = g_malloc (sizeof (GdkColor));
+          color->red = atoi (RGB_vals[0]);
+          color->green = atoi (RGB_vals[1]);
+          color->blue = atoi (RGB_vals[2]);
+          g_object_set (G_OBJECT (tag), "background_gdk", color, NULL);
+        }
+  
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FG_COLOR)))
+        {
+          RGB_vals = g_strsplit (value, ",", 3);
+          color = g_malloc (sizeof (GdkColor));
+          color->red = atoi (RGB_vals[0]);
+          color->green = atoi (RGB_vals[1]);
+          color->blue = atoi (RGB_vals[2]);
+          g_object_set (G_OBJECT (tag), "foreground_gdk", color, NULL);
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRETCH)))
+        {
+          for (j = 0; j < 9; j++)
+            {
+              if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, j)))
+                {
+                  g_object_set (G_OBJECT (tag), "stretch", j, NULL);
+                  break;
+                }
+            }
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_JUSTIFICATION)))
+        {
+          for (j = 0; j < 4; j++)
+            {
+              if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, j)))
+                {
+                  g_object_set (G_OBJECT (tag), "justification", j, NULL);
+                  break;
+                }
+            }
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_DIRECTION)))
+        {
+          for (j = 0; j < 3; j++)
+            {
+              if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, j)))
+                {
+                  g_object_set (G_OBJECT (tag), "direction", j, NULL);
+                  break;
+                }
+            }
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_VARIANT)))
+        {
+          for (j = 0; j < 2; j++)
+            {
+              if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, j)))
+                {
+                  g_object_set (G_OBJECT (tag), "variant", j, NULL);
+                  break;
+                }
+            }
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WRAP_MODE)))
+        {
+          for (j = 0; j < 3; j++)
+            {
+              if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, j)))
+                {
+                  g_object_set (G_OBJECT (tag), "wrap_mode", j, NULL);
+                  break;
+                }
+            }
+        }
+
+      else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STYLE)))
+        {
+          for (j = 0; j < 3; j++)
+            {
+              if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, j)))
+                {
+                  g_object_set (G_OBJECT (tag), "style", j, NULL);
+                  break;
+              }
+            }
+        }
+
+      else
+        return FALSE;
+    }
+
+  gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
+
+  return TRUE;
+}
+
+static void
+gail_text_view_set_text_contents (AtkEditableText *text,
+                                  const gchar     *string)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  view = GTK_TEXT_VIEW (widget);
+  if (!gtk_text_view_get_editable (view))
+    return;
+  buffer = view->buffer;
+
+  /* The -1 indicates that the input string must be null-terminated */
+  gtk_text_buffer_set_text (buffer, string, -1);
+}
+
+static void
+gail_text_view_insert_text (AtkEditableText *text,
+                            const gchar     *string,
+                            gint            length,
+                            gint            *position)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  view = GTK_TEXT_VIEW (widget);
+  if (!gtk_text_view_get_editable (view))
+    return;
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, *position);
+  gtk_text_buffer_insert (buffer, &pos_itr, string, length);
+}
+
+static void
+gail_text_view_copy_text   (AtkEditableText *text,
+                            gint            start_pos,
+                            gint            end_pos)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+  gchar *str;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  view = GTK_TEXT_VIEW (widget);
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
+  gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
+  str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+  gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1);
+}
+
+static void
+gail_text_view_cut_text (AtkEditableText *text,
+                         gint            start_pos,
+                         gint            end_pos)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+  gchar *str;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  view = GTK_TEXT_VIEW (widget);
+  if (!gtk_text_view_get_editable (view))
+    return;
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
+  gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
+  str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+  gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1);
+  gtk_text_buffer_delete (buffer, &start, &end);
+}
+
+static void
+gail_text_view_delete_text (AtkEditableText *text,
+                            gint            start_pos,
+                            gint            end_pos)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter start_itr;
+  GtkTextIter end_itr;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  view = GTK_TEXT_VIEW (widget);
+  if (!gtk_text_view_get_editable (view))
+    return;
+  buffer = view->buffer;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start_itr, start_pos);
+  gtk_text_buffer_get_iter_at_offset (buffer, &end_itr, end_pos);
+  gtk_text_buffer_delete (buffer, &start_itr, &end_itr);
+}
+
+static void
+gail_text_view_paste_text (AtkEditableText *text,
+                           gint            position)
+{
+  GtkTextView *view;
+  GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GailTextViewPaste paste_struct;
+
+  widget = GTK_ACCESSIBLE (text)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  view = GTK_TEXT_VIEW (widget);
+  if (!gtk_text_view_get_editable (view))
+    return;
+  buffer = view->buffer;
+
+  paste_struct.buffer = buffer;
+  paste_struct.position = position;
+
+  g_object_ref (paste_struct.buffer);
+  gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE),
+    gail_text_view_paste_received, &paste_struct);
+}
+
+static void
+gail_text_view_paste_received (GtkClipboard *clipboard,
+                               const gchar  *text,
+                               gpointer     data)
+{
+  GailTextViewPaste* paste_struct = (GailTextViewPaste *)data;
+  GtkTextIter pos_itr;
+
+  if (text)
+    {
+      gtk_text_buffer_get_iter_at_offset (paste_struct->buffer, &pos_itr,
+         paste_struct->position);
+      gtk_text_buffer_insert (paste_struct->buffer, &pos_itr, text, -1);
+    }
+
+  g_object_unref (paste_struct->buffer);
+}
+
+/* Callbacks */
+
+/* Note arg1 returns the start of the insert range, arg3 returns the
+ * end of the insert range if multiple characters are inserted.  If one
+ * character is inserted they have the same value, which is the caret
+ * location.  arg2 returns the begin location of the insert.
+ */
+static void 
+_gail_text_view_insert_text_cb (GtkTextBuffer *buffer,
+                                GtkTextIter   *arg1, 
+                                gchar         *arg2, 
+                                gint          arg3,
+                                gpointer      user_data)
+{
+  GtkTextView *text = (GtkTextView *) user_data;
+  AtkObject *accessible;
+  GailTextView *gail_text_view;
+  gint position;
+  gint length;
+
+  g_return_if_fail (arg3 > 0);
+
+  accessible = gtk_widget_get_accessible(GTK_WIDGET(text));
+  gail_text_view = GAIL_TEXT_VIEW (accessible);
+
+  gail_text_view->signal_name = "text_changed::insert";
+  position = gtk_text_iter_get_offset (arg1);
+  length = g_utf8_strlen(arg2, arg3);
+  
+  if (gail_text_view->length == 0)
+    {
+      gail_text_view->position = position;
+      gail_text_view->length = length;
+    }
+  else if (gail_text_view->position + gail_text_view->length == position)
+    {
+      gail_text_view->length += length;
+    }
+  else
+    {
+      /*
+       * We have a non-contiguous insert so report what we have
+       */
+      if (gail_text_view->insert_notify_handler)
+        {
+          g_source_remove (gail_text_view->insert_notify_handler);
+        }
+      gail_text_view->insert_notify_handler = 0;
+      insert_idle_handler (gail_text_view);
+      gail_text_view->position = position;
+      gail_text_view->length = length;
+    }
+    
+  /*
+   * The signal will be emitted when the changed signal is received
+   */
+}
+
+/* Note arg1 returns the start of the delete range, arg2 returns the
+ * end of the delete range if multiple characters are deleted.  If one
+ * character is deleted they have the same value, which is the caret
+ * location.
+ */
+static void 
+_gail_text_view_delete_range_cb (GtkTextBuffer *buffer,
+                                 GtkTextIter   *arg1, 
+                                 GtkTextIter   *arg2,
+                                 gpointer      user_data)
+{
+  GtkTextView *text = (GtkTextView *) user_data;
+  AtkObject *accessible;
+  GailTextView *gail_text_view;
+  gint offset = gtk_text_iter_get_offset (arg1);
+  gint length = gtk_text_iter_get_offset (arg2) - offset;
+
+  accessible = gtk_widget_get_accessible(GTK_WIDGET(text));
+  gail_text_view = GAIL_TEXT_VIEW (accessible);
+  if (gail_text_view->insert_notify_handler)
+    {
+      g_source_remove (gail_text_view->insert_notify_handler);
+      gail_text_view->insert_notify_handler = 0;
+      if (gail_text_view->position == offset && 
+          gail_text_view->length == length)
+        {
+        /*
+         * Do not bother with insert and delete notifications
+         */
+          gail_text_view->signal_name = NULL;
+          gail_text_view->position = 0;
+          gail_text_view->length = 0;
+          return;
+        }
+
+      insert_idle_handler (gail_text_view);
+    }
+  g_signal_emit_by_name (accessible, "text_changed::delete",
+                         offset, length);
+}
+
+/* Note arg1 and arg2 point to the same offset, which is the caret
+ * position after the move
+ */
+static void 
+_gail_text_view_mark_set_cb (GtkTextBuffer *buffer,
+                             GtkTextIter   *arg1, 
+                             GtkTextMark   *arg2,
+                             gpointer      user_data)
+{
+  GtkTextView *text = (GtkTextView *) user_data;
+  AtkObject *accessible;
+  GailTextView *gail_text_view;
+  const char *mark_name = gtk_text_mark_get_name(arg2);
+
+  accessible = gtk_widget_get_accessible(GTK_WIDGET(text));
+  gail_text_view = GAIL_TEXT_VIEW (accessible);
+
+  /*
+   * Only generate the signal for the "insert" mark, which
+   * represents the cursor.
+   */
+  if (mark_name && !strcmp(mark_name, "insert"))
+    {
+      int insert_offset, selection_bound;
+      gboolean selection_changed;
+
+      insert_offset = gtk_text_iter_get_offset (arg1);
+
+      selection_bound = get_selection_bound (buffer);
+      if (selection_bound != insert_offset)
+        {
+          if (selection_bound != gail_text_view->previous_selection_bound ||
+              insert_offset != gail_text_view->previous_insert_offset)
+            {
+              selection_changed = TRUE;
+            }
+          else
+            {
+              selection_changed = FALSE;
+            }
+        }
+      else if (gail_text_view->previous_selection_bound != gail_text_view->previous_insert_offset)
+        {
+          selection_changed = TRUE;
+        }
+      else
+        {
+          selection_changed = FALSE;
+        }
+
+      emit_text_caret_moved (gail_text_view, insert_offset);
+      /*
+       * insert and selection_bound marks are different to a selection
+       * has changed
+       */
+      if (selection_changed)
+        g_signal_emit_by_name (accessible, "text_selection_changed");
+      gail_text_view->previous_selection_bound = selection_bound;
+    }
+}
+
+static void 
+_gail_text_view_changed_cb (GtkTextBuffer *buffer,
+                            gpointer      user_data)
+{
+  GtkTextView *text = (GtkTextView *) user_data;
+  AtkObject *accessible;
+  GailTextView *gail_text_view;
+
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (text));
+  gail_text_view = GAIL_TEXT_VIEW (accessible);
+  if (gail_text_view->signal_name)
+    {
+      if (!gail_text_view->insert_notify_handler)
+        {
+          gail_text_view->insert_notify_handler = g_idle_add (insert_idle_handler, accessible);
+        }
+      return;
+    }
+  emit_text_caret_moved (gail_text_view, get_insert_offset (buffer));
+  gail_text_view->previous_selection_bound = get_selection_bound (buffer);
+}
+
+static gchar*
+get_text_near_offset (AtkText          *text,
+                      GailOffsetType   function,
+                      AtkTextBoundary  boundary_type,
+                      gint             offset,
+                      gint             *start_offset,
+                      gint             *end_offset)
+{
+  GtkTextView *view;
+  gpointer layout = NULL;
+
+  view = GTK_TEXT_VIEW (GTK_ACCESSIBLE (text)->widget);
+
+  /*
+   * Pass the GtkTextView to the function gail_text_util_get_text() 
+   * so it can find the start and end of the current line on the display.
+   */
+  if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START ||
+      boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
+    layout = view;
+
+  return gail_text_util_get_text (GAIL_TEXT_VIEW (text)->textutil, layout,
+                                  function, boundary_type, offset, 
+                                    start_offset, end_offset);
+}
+
+static gint
+get_insert_offset (GtkTextBuffer *buffer)
+{
+  GtkTextMark *cursor_mark;
+  GtkTextIter cursor_itr;
+
+  cursor_mark = gtk_text_buffer_get_insert (buffer);
+  gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
+  return gtk_text_iter_get_offset (&cursor_itr);
+}
+
+static gint
+get_selection_bound (GtkTextBuffer *buffer)
+{
+  GtkTextMark *selection_mark;
+  GtkTextIter selection_itr;
+
+  selection_mark = gtk_text_buffer_get_selection_bound (buffer);
+  gtk_text_buffer_get_iter_at_mark (buffer, &selection_itr, selection_mark);
+  return gtk_text_iter_get_offset (&selection_itr);
+}
+
+static void
+emit_text_caret_moved (GailTextView *gail_text_view,
+                       gint          insert_offset)
+{
+  /*
+   * If we have text which has been inserted notify the user
+   */
+  if (gail_text_view->insert_notify_handler)
+    {
+      g_source_remove (gail_text_view->insert_notify_handler);
+      gail_text_view->insert_notify_handler = 0;
+      insert_idle_handler (gail_text_view);
+    }
+
+  if (insert_offset != gail_text_view->previous_insert_offset)
+    {
+      /*
+       * If the caret position has not changed then don't bother notifying
+       *
+       * When mouse click is used to change caret position, notification
+       * is received on button down and button up.
+       */
+      g_signal_emit_by_name (gail_text_view, "text_caret_moved", insert_offset);
+      gail_text_view->previous_insert_offset = insert_offset;
+    }
+}
+
+static gint
+insert_idle_handler (gpointer data)
+{
+  GailTextView *gail_text_view;
+  GtkTextBuffer *buffer;
+
+  GDK_THREADS_ENTER ();
+
+  gail_text_view = GAIL_TEXT_VIEW (data);
+
+  g_signal_emit_by_name (data,
+                         gail_text_view->signal_name,
+                         gail_text_view->position,
+                         gail_text_view->length);
+  gail_text_view->signal_name = NULL;
+  gail_text_view->position = 0;
+  gail_text_view->length = 0;
+
+  buffer = gail_text_view->textutil->buffer;
+  if (gail_text_view->insert_notify_handler)
+    {
+    /*
+     * If called from idle handler notify caret moved
+     */
+      gail_text_view->insert_notify_handler = 0;
+      emit_text_caret_moved (gail_text_view, get_insert_offset (buffer));
+      gail_text_view->previous_selection_bound = get_selection_bound (buffer);
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void       
+atk_streamable_content_interface_init    (AtkStreamableContentIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  
+  iface->get_n_mime_types = gail_streamable_content_get_n_mime_types;
+  iface->get_mime_type = gail_streamable_content_get_mime_type;
+  iface->get_stream = gail_streamable_content_get_stream;
+}
+
+static gint       gail_streamable_content_get_n_mime_types (AtkStreamableContent *streamable)
+{
+    gint n_mime_types = 0;
+
+    if (GAIL_IS_TEXT_VIEW (streamable) && GAIL_TEXT_VIEW (streamable)->textutil)
+    {
+       int i;
+       gboolean advertises_plaintext = FALSE;
+       GdkAtom *atoms =
+            gtk_text_buffer_get_serialize_formats (
+               GAIL_TEXT_VIEW (streamable)->textutil->buffer, 
+               &n_mime_types);
+       for (i = 0; i < n_mime_types-1; ++i)
+           if (!strcmp ("text/plain", gdk_atom_name (atoms[i])))
+               advertises_plaintext = TRUE;
+       if (!advertises_plaintext) ++n_mime_types; 
+        /* we support text/plain even if the GtkTextBuffer doesn't */
+    }
+    return n_mime_types;
+}
+
+static G_CONST_RETURN gchar*       
+gail_streamable_content_get_mime_type (AtkStreamableContent *streamable, gint i)
+{
+    if (GAIL_IS_TEXT_VIEW (streamable) && GAIL_TEXT_VIEW (streamable)->textutil)
+    {
+       gint n_mime_types = 0;
+       GdkAtom *atoms;
+       atoms = gtk_text_buffer_get_serialize_formats (
+           GAIL_TEXT_VIEW (streamable)->textutil->buffer, 
+           &n_mime_types);
+       if (i < n_mime_types)
+       {
+           return gdk_atom_name (atoms [i]);
+       }
+       else if (i == n_mime_types)
+           return "text/plain";
+    }
+    return NULL;
+}
+
+static GIOChannel*       gail_streamable_content_get_stream       (AtkStreamableContent *streamable,
+                                                                  const gchar *mime_type)
+{
+    gint i, n_mime_types = 0;
+    GdkAtom *atoms;
+    if (!GAIL_IS_TEXT_VIEW (streamable) || !GAIL_TEXT_VIEW (streamable)->textutil)
+       return NULL;
+    atoms = gtk_text_buffer_get_serialize_formats (
+       GAIL_TEXT_VIEW (streamable)->textutil->buffer, 
+       &n_mime_types);
+    for (i = 0; i < n_mime_types; ++i) 
+    {
+       if (!strcmp ("text/plain", mime_type) ||
+           !strcmp (gdk_atom_name (atoms[i]), mime_type)) {
+           GtkTextBuffer *buffer;
+           guint8 *cbuf;
+           GError *err = NULL;
+           gsize len, written;
+           gchar tname[80];
+           GtkTextIter start, end;
+           GIOChannel *gio = NULL;
+           int fd;
+           buffer = GAIL_TEXT_VIEW (streamable)->textutil->buffer;
+           gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
+           gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
+           if (!strcmp ("text/plain", mime_type)) 
+           {
+               cbuf = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+               len = strlen (cbuf); 
+           }
+           else
+           {
+               cbuf = gtk_text_buffer_serialize (buffer, buffer, atoms[i], &start, &end, &len);
+           }
+           g_snprintf (tname, 20, "streamXXXXXX");
+           fd = g_mkstemp (tname);
+           gio = g_io_channel_unix_new (fd);
+           g_io_channel_set_encoding (gio, NULL, &err);
+           if (!err) g_io_channel_write_chars (gio, cbuf, (gssize) len, &written, &err);
+           else g_message (err->message);
+           if (!err) g_io_channel_seek_position (gio, 0, G_SEEK_SET, &err);
+           else g_message (err->message);
+           if (!err) g_io_channel_flush (gio, &err);
+           else g_message (err->message);
+           if (err) {
+               g_message ("<error writing to stream [%s]>", tname);
+               g_free (err);
+           }
+           /* make sure the file is removed on unref of the giochannel */
+           else {
+               g_unlink (tname);
+               return gio; 
+           }
+       }
+    }
+    return NULL;
+}
+
diff --git a/modules/other/gail/gailtextview.h b/modules/other/gail/gailtextview.h
new file mode 100644 (file)
index 0000000..4218b7b
--- /dev/null
@@ -0,0 +1,72 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_TEXT_VIEW_H__
+#define __GAIL_TEXT_VIEW_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+#include <libgail-util/gailtextutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_TEXT_VIEW                  (gail_text_view_get_type ())
+#define GAIL_TEXT_VIEW(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_TEXT_VIEW, GailTextView))
+#define GAIL_TEXT_VIEW_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_TEXT_VIEW, GailTextViewClass))
+#define GAIL_IS_TEXT_VIEW(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_TEXT_VIEW))
+#define GAIL_IS_TEXT_VIEW_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_TEXT_VIEW))
+#define GAIL_TEXT_VIEW_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_TEXT_VIEW, GailTextViewClass))
+
+typedef struct _GailTextView              GailTextView;
+typedef struct _GailTextViewClass         GailTextViewClass;
+
+struct _GailTextView
+{
+  GailContainer  parent;
+
+  GailTextUtil   *textutil;
+  gint           previous_insert_offset;
+  gint           previous_selection_bound;
+  /*
+   * These fields store information about text changed
+   */
+  gchar          *signal_name;
+  gint           position;
+  gint           length;
+
+  guint          insert_notify_handler;
+};
+
+GType gail_text_view_get_type (void);
+
+struct _GailTextViewClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_text_view_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TEXT_VIEW_H__ */
diff --git a/modules/other/gail/gailtogglebutton.c b/modules/other/gail/gailtogglebutton.c
new file mode 100644 (file)
index 0000000..13d509c
--- /dev/null
@@ -0,0 +1,165 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailtogglebutton.h"
+
+static void      gail_toggle_button_class_init        (GailToggleButtonClass *klass);
+
+static void      gail_toggle_button_toggled_gtk       (GtkWidget             *widget);
+
+static void      gail_toggle_button_real_notify_gtk   (GObject               *obj,
+                                                       GParamSpec            *pspec);
+
+static void      gail_toggle_button_real_initialize   (AtkObject             *obj,
+                                                       gpointer              data);
+
+static AtkStateSet* gail_toggle_button_ref_state_set  (AtkObject             *accessible);
+
+static GailButtonClass *parent_class = NULL;
+
+GType
+gail_toggle_button_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailToggleButtonClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_toggle_button_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailToggleButton), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      type = g_type_register_static (GAIL_TYPE_BUTTON,
+                                     "GailToggleButton", &tinfo, 0);
+    }
+
+  return type;
+}
+
+static void
+gail_toggle_button_class_init (GailToggleButtonClass *klass)
+{
+  GailWidgetClass *widget_class;
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  widget_class = (GailWidgetClass*)klass;
+  widget_class->notify_gtk = gail_toggle_button_real_notify_gtk;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->ref_state_set = gail_toggle_button_ref_state_set;
+  class->initialize = gail_toggle_button_real_initialize;
+}
+
+AtkObject* 
+gail_toggle_button_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_TOGGLE_BUTTON, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_toggle_button_real_initialize (AtkObject *obj,
+                                    gpointer  data)
+{
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  g_signal_connect (data,
+                    "toggled",
+                    G_CALLBACK (gail_toggle_button_toggled_gtk),
+                    NULL);
+
+  if (GTK_IS_CHECK_BUTTON (data))
+    obj->role = ATK_ROLE_CHECK_BOX;
+  else
+    obj->role = ATK_ROLE_TOGGLE_BUTTON;
+}
+
+static void
+gail_toggle_button_toggled_gtk (GtkWidget       *widget)
+{
+  AtkObject *accessible;
+  GtkToggleButton *toggle_button;
+
+  toggle_button = GTK_TOGGLE_BUTTON (widget);
+
+  accessible = gtk_widget_get_accessible (widget);
+  atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, 
+                                  toggle_button->active);
+} 
+
+static AtkStateSet*
+gail_toggle_button_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkToggleButton *toggle_button;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+  if (widget == NULL)
+    return state_set;
+
+  toggle_button = GTK_TOGGLE_BUTTON (widget);
+
+  if (gtk_toggle_button_get_active (toggle_button))
+    atk_state_set_add_state (state_set, ATK_STATE_CHECKED);
+
+  if (gtk_toggle_button_get_inconsistent (toggle_button))
+    atk_state_set_remove_state (state_set, ATK_STATE_ENABLED);
+  return state_set;
+}
+
+static void
+gail_toggle_button_real_notify_gtk (GObject           *obj,
+                                    GParamSpec        *pspec)
+{
+  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (obj);
+  AtkObject *atk_obj;
+
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (toggle_button));
+
+  if (strcmp (pspec->name, "inconsistent") == 0)
+    atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED,
+                       !gtk_toggle_button_get_inconsistent (toggle_button));
+  else
+    GAIL_WIDGET_CLASS (parent_class)->notify_gtk (obj, pspec);
+}
diff --git a/modules/other/gail/gailtogglebutton.h b/modules/other/gail/gailtogglebutton.h
new file mode 100644 (file)
index 0000000..77580f2
--- /dev/null
@@ -0,0 +1,59 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_TOGGLE_BUTTON_H__
+#define __GAIL_TOGGLE_BUTTON_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailbutton.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_TOGGLE_BUTTON              (gail_toggle_button_get_type ())
+#define GAIL_TOGGLE_BUTTON(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_TOGGLE_BUTTON, GailToggleButton))
+#define GAIL_TOGGLE_BUTTON_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_TOGGLE_BUTTON, GailToggleButtonClass))
+#define GAIL_IS_TOGGLE_BUTTON(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_TOGGLE_BUTTON))
+#define GAIL_IS_TOGGLE_BUTTON_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_TOGGLE_BUTTON))
+#define GAIL_TOGGLE_BUTTON_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_TOGGLE_BUTTON, GailToggleButtonClass))
+
+typedef struct _GailToggleButton              GailToggleButton;
+typedef struct _GailToggleButtonClass         GailToggleButtonClass;
+
+struct _GailToggleButton
+{
+  GailButton parent;
+};
+
+GType gail_toggle_button_get_type (void);
+
+struct _GailToggleButtonClass
+{
+  GailButtonClass parent_class;
+};
+
+AtkObject* gail_toggle_button_new( GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TOGGLE_BUTTON_H__ */
diff --git a/modules/other/gail/gailtoplevel.c b/modules/other/gail/gailtoplevel.c
new file mode 100644 (file)
index 0000000..237204b
--- /dev/null
@@ -0,0 +1,399 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include "gailtoplevel.h"
+
+static void             gail_toplevel_class_init        (GailToplevelClass      *klass);
+static void             gail_toplevel_object_init       (GailToplevel           *toplevel);
+static void             gail_toplevel_object_finalize   (GObject                *obj);
+
+/* atkobject.h */
+
+static gint             gail_toplevel_get_n_children    (AtkObject              *obj);
+static AtkObject*       gail_toplevel_ref_child         (AtkObject              *obj,
+                                                        gint                    i);
+static AtkObject*       gail_toplevel_get_parent        (AtkObject              *obj);
+
+/* Callbacks */
+
+
+static void             gail_toplevel_window_destroyed  (GtkWindow              *window,
+                                                        GailToplevel            *text);
+static gboolean         gail_toplevel_hide_event_watcher (GSignalInvocationHint *ihint,
+                                                        guint                   n_param_values,
+                                                        const GValue            *param_values,
+                                                        gpointer                data);
+static gboolean         gail_toplevel_show_event_watcher (GSignalInvocationHint *ihint,
+                                                        guint                   n_param_values,
+                                                        const GValue            *param_values,
+                                                        gpointer                data);
+
+/* Misc */
+
+static void      _gail_toplevel_remove_child            (GailToplevel           *toplevel,
+                                                        GtkWindow               *window);
+static gboolean  is_attached_menu_window                (GtkWidget              *widget);
+static gboolean  is_combo_window                        (GtkWidget              *widget);
+
+
+static gpointer parent_class = NULL;
+
+GType
+gail_toplevel_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+        {
+          sizeof (GailToplevelClass),
+          (GBaseInitFunc) NULL, /* base init */
+          (GBaseFinalizeFunc) NULL, /* base finalize */
+          (GClassInitFunc) gail_toplevel_class_init, /* class init */
+          (GClassFinalizeFunc) NULL, /* class finalize */
+          NULL, /* class data */
+          sizeof (GailToplevel), /* instance size */
+          0, /* nb preallocs */
+          (GInstanceInitFunc) gail_toplevel_object_init, /* instance init */
+          NULL /* value table */
+        };
+
+      type = g_type_register_static (ATK_TYPE_OBJECT,
+                                   "GailToplevel", &tinfo, 0);
+    }
+
+  return type;
+}
+
+AtkObject*
+gail_toplevel_new (void)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  object = g_object_new (GAIL_TYPE_TOPLEVEL, NULL);
+  g_return_val_if_fail ((object != NULL), NULL);
+
+  accessible = ATK_OBJECT (object);
+  accessible->role = ATK_ROLE_APPLICATION;
+  accessible->name = g_get_prgname();
+  accessible->accessible_parent = NULL;
+
+  return accessible;
+}
+
+static void
+gail_toplevel_class_init (GailToplevelClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
+  GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_n_children = gail_toplevel_get_n_children;
+  class->ref_child = gail_toplevel_ref_child;
+  class->get_parent = gail_toplevel_get_parent;
+
+  g_object_class->finalize = gail_toplevel_object_finalize;
+}
+
+static void
+gail_toplevel_object_init (GailToplevel *toplevel)
+{
+  GtkWindow *window;
+  GtkWidget *widget;
+  GList *l;
+  guint signal_id;
+  
+  l = toplevel->window_list = gtk_window_list_toplevels ();
+
+  while (l)
+    {
+      window = GTK_WINDOW (l->data);
+      widget = GTK_WIDGET (window);
+      if (!window || 
+          !GTK_WIDGET_VISIBLE (widget) ||
+          is_attached_menu_window (widget) ||
+          GTK_WIDGET (window)->parent ||
+          GTK_IS_PLUG (window))
+        {
+          GList *temp_l  = l->next;
+
+          toplevel->window_list = g_list_delete_link (toplevel->window_list, l);
+          l = temp_l;
+        }
+      else
+        {
+          g_signal_connect (G_OBJECT (window), 
+                            "destroy",
+                            G_CALLBACK (gail_toplevel_window_destroyed),
+                            toplevel);
+          l = l->next;
+        }
+    }
+
+  gtk_type_class (GTK_TYPE_WINDOW);
+
+  signal_id  = g_signal_lookup ("show", GTK_TYPE_WINDOW);
+  g_signal_add_emission_hook (signal_id, 0,
+    gail_toplevel_show_event_watcher, toplevel, (GDestroyNotify) NULL);
+
+  signal_id  = g_signal_lookup ("hide", GTK_TYPE_WINDOW);
+  g_signal_add_emission_hook (signal_id, 0,
+    gail_toplevel_hide_event_watcher, toplevel, (GDestroyNotify) NULL);
+}
+
+static void
+gail_toplevel_object_finalize (GObject *obj)
+{
+  GailToplevel *toplevel = GAIL_TOPLEVEL (obj);
+
+  if (toplevel->window_list)
+    g_list_free (toplevel->window_list);
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static AtkObject*
+gail_toplevel_get_parent (AtkObject *obj)
+{
+    return NULL;
+}
+
+static gint
+gail_toplevel_get_n_children (AtkObject *obj)
+{
+  GailToplevel *toplevel = GAIL_TOPLEVEL (obj);
+
+  gint rc = g_list_length (toplevel->window_list);
+  return rc;
+}
+
+static AtkObject*
+gail_toplevel_ref_child (AtkObject *obj,
+                         gint      i)
+{
+  GailToplevel *toplevel;
+  gpointer ptr;
+  GtkWidget *widget;
+  AtkObject *atk_obj;
+
+  toplevel = GAIL_TOPLEVEL (obj);
+  ptr = g_list_nth_data (toplevel->window_list, i);
+  if (!ptr)
+    return NULL;
+  widget = GTK_WIDGET (ptr);
+  atk_obj = gtk_widget_get_accessible (widget);
+
+  g_object_ref (atk_obj);
+  return atk_obj;
+}
+
+/*
+ * Window destroy events on GtkWindow cause a child to be removed
+ * from the toplevel
+ */
+static void
+gail_toplevel_window_destroyed (GtkWindow    *window,
+                                GailToplevel *toplevel)
+{
+  _gail_toplevel_remove_child (toplevel, window);
+}
+
+/*
+ * Show events cause a child to be added to the toplevel
+ */
+static gboolean
+gail_toplevel_show_event_watcher (GSignalInvocationHint *ihint,
+                                  guint                  n_param_values,
+                                  const GValue          *param_values,
+                                  gpointer               data)
+{
+  GailToplevel *toplevel = GAIL_TOPLEVEL (data);
+  AtkObject *atk_obj = ATK_OBJECT (toplevel);
+  GObject *object;
+  GtkWidget *widget;
+  gint n_children;
+  AtkObject *child;
+
+  object = g_value_get_object (param_values + 0);
+
+  if (!GTK_IS_WINDOW (object))
+    return TRUE;
+
+  widget = GTK_WIDGET (object);
+  if (widget->parent || 
+      is_attached_menu_window (widget) ||
+      is_combo_window (widget) ||
+      GTK_IS_PLUG (widget))
+    return TRUE;
+
+  child = gtk_widget_get_accessible (widget);
+  if (!strcmp (atk_role_get_name (atk_object_get_role (child)), "redundant object"))
+    {
+      return TRUE;
+    }
+
+  child = gtk_widget_get_accessible (widget);
+  if (!strcmp (atk_role_get_name (atk_object_get_role (child)), "redundant object"))
+    {
+      return TRUE;
+    }
+
+  /* 
+   * Add the window to the list & emit the signal.
+   * Don't do this for tooltips (Bug #150649).
+   */
+  if (atk_object_get_role (child) != ATK_ROLE_TOOL_TIP)
+  {
+      toplevel->window_list = g_list_append (toplevel->window_list, widget);
+
+      n_children = g_list_length (toplevel->window_list);
+
+      /*
+       * Must subtract 1 from the n_children since the index is 0-based
+       * but g_list_length is 1-based.
+       */
+      atk_object_set_parent (child, atk_obj);
+      g_signal_emit_by_name (atk_obj, "children-changed::add",
+                            n_children - 1, 
+                            child, NULL);
+  }
+
+  /* Connect destroy signal callback */
+  g_signal_connect (G_OBJECT(object), 
+                    "destroy",
+                    G_CALLBACK (gail_toplevel_window_destroyed),
+                    toplevel);
+
+  return TRUE;
+}
+
+/*
+ * Hide events on GtkWindow cause a child to be removed from the toplevel
+ */
+static gboolean
+gail_toplevel_hide_event_watcher (GSignalInvocationHint *ihint,
+                                  guint                  n_param_values,
+                                  const GValue          *param_values,
+                                  gpointer               data)
+{
+  GailToplevel *toplevel = GAIL_TOPLEVEL (data);
+  GObject *object;
+
+  object = g_value_get_object (param_values + 0);
+
+  if (!GTK_IS_WINDOW (object))
+    return TRUE;
+
+  _gail_toplevel_remove_child (toplevel, GTK_WINDOW (object));
+  return TRUE;
+}
+
+/*
+ * Common code used by destroy and hide events on GtkWindow
+ */
+static void
+_gail_toplevel_remove_child (GailToplevel *toplevel, 
+                             GtkWindow    *window)
+{
+  AtkObject *atk_obj = ATK_OBJECT (toplevel);
+  GList *l;
+  guint window_count = 0;
+  AtkObject *child;
+
+  if (toplevel->window_list)
+    {
+        GtkWindow *tmp_window;
+
+        /* Must loop through them all */
+        for (l = toplevel->window_list; l; l = l->next)
+        {
+          tmp_window = GTK_WINDOW (l->data);
+
+          if (window == tmp_window)
+            {
+              /* Remove the window from the window_list & emit the signal */
+              toplevel->window_list = g_list_remove (toplevel->window_list,
+                                                     l->data);
+              child = gtk_widget_get_accessible (GTK_WIDGET (window));
+              g_signal_emit_by_name (atk_obj, "children-changed::remove",
+                                     window_count, 
+                                     child, NULL);
+              atk_object_set_parent (child, NULL);
+              break;
+            }
+
+          window_count++;
+        }
+    }
+}
+
+static gboolean
+is_attached_menu_window (GtkWidget *widget)
+{
+  GtkWidget *child = GTK_BIN (widget)->child;
+  gboolean ret = FALSE;
+
+  if (GTK_IS_MENU (child))
+    {
+      GtkWidget *attach;
+
+      attach = gtk_menu_get_attach_widget (GTK_MENU (child));
+      /* Allow for menu belonging to the Panel Menu, which is a GtkButton */
+      if (GTK_IS_MENU_ITEM (attach) ||
+          GTK_IS_OPTION_MENU (attach) ||
+          GTK_IS_BUTTON (attach))
+        ret = TRUE;
+    }
+  return ret;
+}
+
+static gboolean
+is_combo_window (GtkWidget *widget)
+{
+  GtkWidget *child = GTK_BIN (widget)->child;
+  AtkObject *obj;
+  GtkAccessible *accessible;
+
+  if (!GTK_IS_EVENT_BOX (child))
+    return FALSE;
+
+  child = GTK_BIN (child)->child;
+
+  if (!GTK_IS_FRAME (child))
+    return FALSE;
+
+  child = GTK_BIN (child)->child;
+
+  if (!GTK_IS_SCROLLED_WINDOW (child))
+    return FALSE;
+
+  obj = gtk_widget_get_accessible (child);
+  obj = atk_object_get_parent (obj);
+  accessible = GTK_ACCESSIBLE (obj);
+  if (GTK_IS_COMBO (accessible->widget))
+    return TRUE;
+
+  return  FALSE;
+}
diff --git a/modules/other/gail/gailtoplevel.h b/modules/other/gail/gailtoplevel.h
new file mode 100644 (file)
index 0000000..5044a41
--- /dev/null
@@ -0,0 +1,58 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_TOPLEVEL_H__
+#define __GAIL_TOPLEVEL_H__
+
+#include <atk/atk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_TOPLEVEL               (gail_toplevel_get_type ())
+#define GAIL_TOPLEVEL(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_TOPLEVEL, GailToplevel))
+#define GAIL_TOPLEVEL_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_TOPLEVEL, GailToplevelClass))
+#define GAIL_IS_TOPLEVEL(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_TOPLEVEL))
+#define GAIL_IS_TOPLEVEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_TOPLEVEL))
+#define GAIL_TOPLEVEL_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_TOPLEVEL, GailToplevelClass))
+
+typedef struct _GailToplevel             GailToplevel;
+typedef struct _GailToplevelClass        GailToplevelClass;
+  
+struct _GailToplevel
+{
+  AtkObject parent;
+  GList *window_list;
+};
+
+GType gail_toplevel_get_type (void);
+
+struct _GailToplevelClass
+{
+  AtkObjectClass parent_class;
+};
+
+AtkObject *gail_toplevel_new(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GAIL_TOPLEVEL_H__ */
diff --git a/modules/other/gail/gailtreeview.c b/modules/other/gail/gailtreeview.c
new file mode 100644 (file)
index 0000000..ef3e42e
--- /dev/null
@@ -0,0 +1,4710 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/x11/gdkx.h>
+#endif
+#include <gtk/gtktreeviewcolumn.h>
+#include "gailtreeview.h"
+#include "gailrenderercell.h"
+#include "gailbooleancell.h"
+#include "gailcontainercell.h"
+#include "gailtextcell.h"
+#include "gailcellparent.h"
+#include "gail-private-macros.h"
+
+typedef struct _GailTreeViewRowInfo    GailTreeViewRowInfo;
+typedef struct _GailTreeViewCellInfo   GailTreeViewCellInfo;
+
+static void             gail_tree_view_class_init       (GailTreeViewClass      *klass);
+static void             gail_tree_view_real_initialize  (AtkObject              *obj,
+                                                         gpointer               data);
+static void             gail_tree_view_real_notify_gtk  (GObject               *obj,
+                                                         GParamSpec            *pspec);
+static void             gail_tree_view_finalize         (GObject                *object);
+
+static void             gail_tree_view_connect_widget_destroyed 
+                                                        (GtkAccessible          *accessible);
+static void             gail_tree_view_destroyed        (GtkWidget              *widget,
+                                                         GtkAccessible          *accessible); 
+/* atkobject.h */
+
+static gint             gail_tree_view_get_n_children   (AtkObject              *obj);
+static AtkObject*       gail_tree_view_ref_child        (AtkObject              *obj,
+                                                         gint                   i);
+static AtkStateSet*     gail_tree_view_ref_state_set    (AtkObject              *obj);
+
+/* atkcomponent.h */
+
+static void             atk_component_interface_init    (AtkComponentIface      *iface);
+
+static AtkObject*       gail_tree_view_ref_accessible_at_point
+                                                        (AtkComponent           *component,
+                                                         gint                   x,
+                                                         gint                   y,
+                                                         AtkCoordType           coord_type);
+           
+/* atktable.h */
+
+static void             atk_table_interface_init        (AtkTableIface          *iface);
+
+static gint             gail_tree_view_get_index_at     (AtkTable               *table,
+                                                         gint                   row,
+                                                         gint                   column);
+static gint             gail_tree_view_get_column_at_index
+                                                        (AtkTable               *table,
+                                                         gint                   index);
+static gint             gail_tree_view_get_row_at_index (AtkTable               *table,
+                                                         gint                   index);
+
+static AtkObject*       gail_tree_view_table_ref_at     (AtkTable               *table,
+                                                         gint                   row,
+                                                         gint                   column);
+static gint             gail_tree_view_get_n_rows       (AtkTable               *table);
+static gint             gail_tree_view_get_n_columns    (AtkTable               *table);
+static gint             get_n_actual_columns            (GtkTreeView            *tree_view);
+static gboolean         gail_tree_view_is_row_selected  (AtkTable               *table,
+                                                         gint                   row);
+static gboolean         gail_tree_view_is_selected      (AtkTable               *table,
+                                                         gint                   row,
+                                                         gint                   column);
+static gint             gail_tree_view_get_selected_rows 
+                                                        (AtkTable               *table, 
+                                                         gint                   **selected);
+static gboolean         gail_tree_view_add_row_selection 
+                                                        (AtkTable               *table, 
+                                                         gint                   row);
+static gboolean         gail_tree_view_remove_row_selection 
+                                                        (AtkTable               *table, 
+                                                         gint                   row);
+static AtkObject*       gail_tree_view_get_row_header   (AtkTable               *table,
+                                                         gint                   row);
+static AtkObject*       gail_tree_view_get_column_header 
+                                                        (AtkTable               *table,
+                                                         gint                   column);
+static void             gail_tree_view_set_row_header   (AtkTable               *table,
+                                                         gint                   row,
+                                                         AtkObject              *header);
+static void             gail_tree_view_set_column_header 
+                                                        (AtkTable               *table,
+                                                         gint                   column,
+                                                         AtkObject              *header);
+static AtkObject*
+                        gail_tree_view_get_caption      (AtkTable               *table);
+static void             gail_tree_view_set_caption      (AtkTable               *table,
+                                                         AtkObject              *caption);
+static AtkObject*       gail_tree_view_get_summary      (AtkTable               *table);
+static void             gail_tree_view_set_summary      (AtkTable               *table,
+                                                         AtkObject              *accessible);
+static G_CONST_RETURN gchar*
+                        gail_tree_view_get_row_description 
+                                                        (AtkTable               *table,
+                                                         gint                   row);
+static void             gail_tree_view_set_row_description 
+                                                        (AtkTable               *table,
+                                                         gint                   row,
+                                                         const gchar            *description);
+static G_CONST_RETURN gchar*
+                        gail_tree_view_get_column_description
+                                                        (AtkTable               *table,
+                                                         gint                   column);
+static void             gail_tree_view_set_column_description
+                                                        (AtkTable               *table,
+                                                         gint                   column,
+                                                         const gchar            *description);
+
+static void             set_row_data                    (AtkTable               *table,
+                                                         gint                   row,
+                                                         AtkObject              *header,
+                                                         const gchar            *description,
+                                                         gboolean               is_header);
+static GailTreeViewRowInfo* 
+                        get_row_info                    (AtkTable               *table,
+                                                         gint                   row);
+
+/* atkselection.h */
+
+static void             atk_selection_interface_init    (AtkSelectionIface      *iface);
+static gboolean         gail_tree_view_add_selection    (AtkSelection           *selection,
+                                                         gint                   i);
+static gboolean         gail_tree_view_clear_selection  (AtkSelection           *selection);
+static AtkObject*       gail_tree_view_ref_selection    (AtkSelection           *selection,
+                                                         gint                   i);
+static gint             gail_tree_view_get_selection_count 
+                                                        (AtkSelection           *selection);
+static gboolean         gail_tree_view_is_child_selected 
+                                                        (AtkSelection           *selection,
+                                                         gint                   i);
+
+/* gailcellparent.h */
+
+static void             gail_cell_parent_interface_init (GailCellParentIface    *iface);
+static void             gail_tree_view_get_cell_extents (GailCellParent         *parent,
+                                                         GailCell               *cell,
+                                                         gint                   *x,
+                                                         gint                   *y,
+                                                         gint                   *width,
+                                                         gint                   *height,
+                                                         AtkCoordType           coord_type);
+static void             gail_tree_view_get_cell_area    (GailCellParent         *parent,
+                                                         GailCell               *cell,
+                                                         GdkRectangle           *cell_rect);
+static gboolean         gail_tree_view_grab_cell_focus  (GailCellParent         *parent,
+                                                         GailCell               *cell);
+
+/* signal handling */
+
+static gboolean         gail_tree_view_expand_row_gtk   (GtkTreeView            *tree_view,
+                                                         GtkTreeIter            *iter,
+                                                         GtkTreePath            *path);
+static gint             idle_expand_row                 (gpointer               data);
+static gboolean         gail_tree_view_collapse_row_gtk (GtkTreeView            *tree_view,
+                                                         GtkTreeIter            *iter,
+                                                         GtkTreePath            *path);
+static void             gail_tree_view_size_allocate_gtk (GtkWidget             *widget,
+                                                         GtkAllocation          *allocation);
+static void             gail_tree_view_set_scroll_adjustments
+                                                        (GtkWidget              *widget,
+                                                         GtkAdjustment          *hadj,
+                                                         GtkAdjustment          *vadj);
+static void             gail_tree_view_changed_gtk      (GtkTreeSelection       *selection,
+                                                         gpointer               data);
+
+static void             columns_changed                 (GtkTreeView            *tree_view);
+static void             cursor_changed                  (GtkTreeView            *tree_view);
+static gint             idle_cursor_changed             (gpointer               data);
+
+static void             model_row_changed               (GtkTreeModel           *tree_model,
+                                                         GtkTreePath            *path,
+                                                         GtkTreeIter            *iter,
+                                                         gpointer               user_data);
+static void             column_visibility_changed       (GObject                *object,
+                                                         GParamSpec             *param,
+                                                         gpointer               user_data);
+static void             column_destroy                  (GtkObject              *obj); 
+static void             model_row_inserted              (GtkTreeModel           *tree_model,
+                                                         GtkTreePath            *path,
+                                                         GtkTreeIter            *iter,
+                                                         gpointer               user_data);
+static void             model_row_deleted               (GtkTreeModel           *tree_model,
+                                                         GtkTreePath            *path,
+                                                         gpointer               user_data);
+static void             destroy_count_func              (GtkTreeView            *tree_view,
+                                                         GtkTreePath            *path,
+                                                         gint                   count,
+                                                         gpointer               user_data);
+static void             model_rows_reordered            (GtkTreeModel           *tree_model,
+                                                         GtkTreePath            *path,
+                                                         GtkTreeIter            *iter,
+                                                         gint                   *new_order,
+                                                         gpointer               user_data);
+static void             adjustment_changed              (GtkAdjustment          *adjustment,
+                                                         GtkTreeView            *tree_view);
+
+/* Misc */
+
+static void             set_iter_nth_row                (GtkTreeView            *tree_view,
+                                                         GtkTreeIter            *iter,
+                                                         gint                   row);
+static gint             get_row_from_tree_path          (GtkTreeView            *tree_view,
+                                                         GtkTreePath            *path);
+static GtkTreeViewColumn* get_column                    (GtkTreeView            *tree_view,
+                                                         gint                   in_col);
+static gint             get_actual_column_number        (GtkTreeView            *tree_view,
+                                                         gint                   visible_column);
+static gint             get_visible_column_number       (GtkTreeView            *tree_view,
+                                                         gint                   actual_column);
+static void            iterate_thru_children           (GtkTreeView            *tree_view,
+                                                         GtkTreeModel           *tree_model,
+                                                         GtkTreePath            *tree_path,
+                                                         GtkTreePath            *orig,
+                                                         gint                   *count,
+                                                         gint                   depth);
+static GtkTreeIter*     return_iter_nth_row             (GtkTreeView            *tree_view,
+                                                         GtkTreeModel           *tree_model,
+                                                         GtkTreeIter            *iter,
+                                                         gint                   increment,
+                                                         gint                   row);
+static void             free_row_info                   (GArray                 *array,
+                                                         gint                   array_idx,
+                                                         gboolean               shift);
+static void             clean_cell_info                 (GailTreeView           *tree_view,
+                                                         GList                  *list); 
+static void             clean_rows                      (GailTreeView           *tree_view);
+static void             clean_cols                      (GailTreeView           *tree_view,
+                                                         GtkTreeViewColumn      *tv_col);
+static void             traverse_cells                  (GailTreeView           *tree_view,
+                                                         GtkTreePath            *tree_path,
+                                                         gboolean               set_stale,
+                                                         gboolean               inc_row);
+static gboolean         update_cell_value               (GailRendererCell       *renderer_cell,
+                                                         GailTreeView           *gailview,
+                                                         gboolean               emit_change_signal);
+static void             set_cell_visibility             (GtkTreeView            *tree_view,
+                                                         GailCell               *cell,
+                                                         GtkTreeViewColumn      *tv_col,
+                                                         GtkTreePath            *tree_path,
+                                                         gboolean               emit_signal);
+static gboolean         is_cell_showing                 (GtkTreeView            *tree_view,
+                                                         GdkRectangle           *cell_rect);
+static void             set_expand_state                (GtkTreeView            *tree_view,
+                                                         GtkTreeModel           *tree_model,
+                                                         GailTreeView           *gailview,
+                                                         GtkTreePath            *tree_path,
+                                                         gboolean               set_on_ancestor);
+static void             add_cell_actions                (GailCell               *cell,
+                                                         gboolean               editable);
+
+static void             toggle_cell_expanded            (GailCell               *cell);
+static void             toggle_cell_toggled             (GailCell               *cell);
+static void             edit_cell                       (GailCell               *cell);
+static void             activate_cell                   (GailCell               *cell);
+static void             cell_destroyed                  (gpointer               data);
+#if 0
+static void             cell_info_remove                (GailTreeView           *tree_view, 
+                                                         GailCell               *cell);
+#endif
+static void             cell_info_get_index             (GtkTreeView            *tree_view, 
+                                                         GailTreeViewCellInfo   *info,
+                                                         gint                   *index);
+static void             cell_info_new                   (GailTreeView           *gailview, 
+                                                         GtkTreeModel           *tree_model,
+                                                         GtkTreePath            *path,
+                                                         GtkTreeViewColumn      *tv_col,
+                                                         GailCell               *cell);
+static GailCell*        find_cell                       (GailTreeView           *gailview, 
+                                                         gint                   index);
+static void             refresh_cell_index              (GailCell               *cell);
+static void             get_selected_rows               (GtkTreeModel           *model,
+                                                         GtkTreePath            *path,
+                                                         GtkTreeIter            *iter,
+                                                         gpointer               data);
+static void             connect_model_signals           (GtkTreeView            *view,
+                                                         GailTreeView           *gailview); 
+static void             disconnect_model_signals        (GailTreeView           *gailview); 
+static void             clear_cached_data               (GailTreeView           *view);
+static gint             get_column_number               (GtkTreeView            *tree_view,
+                                                         GtkTreeViewColumn      *column,
+                                                         gboolean               visible); 
+static gint             get_focus_index                 (GtkTreeView            *tree_view);
+static gint             get_index                       (GtkTreeView            *tree_view,
+                                                         GtkTreePath            *path,
+                                                         gint                   actual_column);
+static void             count_rows                      (GtkTreeModel           *model,
+                                                         GtkTreeIter            *iter,
+                                                         GtkTreePath            *end_path,
+                                                         gint                   *count,
+                                                         gint                   level,
+                                                         gint                   depth);
+
+static gboolean         get_next_node_with_child_at_depth 
+                                                        (GtkTreeModel           *model,
+                                                         GtkTreeIter            *iter,
+                                                         GtkTreePath            **path,
+                                                         gint                   level,
+                                                         gint                   depth);
+static gboolean         get_next_node_with_child        (GtkTreeModel           *model,
+                                                         GtkTreePath            *path,
+                                                         GtkTreePath            **return_path);
+static gboolean         get_tree_path_from_row_index    (GtkTreeModel           *model,
+                                                         gint                   row_index,
+                                                         GtkTreePath            **tree_path);
+static gint             get_row_count                   (GtkTreeModel           *model);
+static gboolean         get_path_column_from_index      (GtkTreeView            *tree_view,
+                                                         gint                   index,
+                                                         GtkTreePath            **path,
+                                                         GtkTreeViewColumn      **column);
+static void             set_cell_expandable             (GailCell               *cell);
+
+static GailTreeViewCellInfo* find_cell_info             (GailTreeView           *view,
+                                                         GailCell               *cell,
+                                                          GList**                list,
+                                                        gboolean                live_only);
+static AtkObject *       get_header_from_column         (GtkTreeViewColumn      *tv_col);
+static gboolean          idle_garbage_collect_cell_data (gpointer data);
+static gboolean          garbage_collect_cell_data      (gpointer data);
+
+static GailWidgetClass *parent_class = NULL;
+static GQuark quark_column_desc_object = 0;
+static GQuark quark_column_header_object = 0;
+static gboolean editing = FALSE;
+static const gchar* hadjustment = "hadjustment";
+static const gchar* vadjustment = "vadjustment";
+
+struct _GailTreeViewRowInfo
+{
+  GtkTreeRowReference *row_ref;
+  gchar *description;
+  AtkObject *header;
+};
+
+struct _GailTreeViewCellInfo
+{
+  GailCell *cell;
+  GtkTreeRowReference *cell_row_ref;
+  GtkTreeViewColumn *cell_col_ref;
+  GailTreeView *view;
+  gboolean in_use;
+};
+
+GType
+gail_tree_view_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailTreeViewClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_tree_view_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailTreeView), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_table_info =
+      {
+       (GInterfaceInitFunc) atk_table_interface_init,
+       (GInterfaceFinalizeFunc) NULL,
+       NULL
+      };
+
+      static const GInterfaceInfo atk_selection_info =
+      {
+       (GInterfaceInitFunc) atk_selection_interface_init,
+       (GInterfaceFinalizeFunc) NULL,
+       NULL
+      };
+
+      static const GInterfaceInfo atk_component_info =
+      {
+        (GInterfaceInitFunc) atk_component_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      static const GInterfaceInfo gail_cell_parent_info =
+      {
+       (GInterfaceInitFunc) gail_cell_parent_interface_init,
+       (GInterfaceFinalizeFunc) NULL,
+       NULL
+      };
+
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailTreeView", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_TABLE,
+                                   &atk_table_info);
+      g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+                                   &atk_selection_info);
+      g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+                                   &atk_component_info);
+      g_type_add_interface_static (type, GAIL_TYPE_CELL_PARENT,
+                                   &gail_cell_parent_info);
+    }
+
+  return type;
+}
+
+static void
+gail_tree_view_class_init (GailTreeViewClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkAccessibleClass *accessible_class;
+  GailWidgetClass *widget_class;
+  GailContainerClass *container_class;
+
+  accessible_class = (GtkAccessibleClass*)klass;
+  widget_class = (GailWidgetClass*)klass;
+  container_class = (GailContainerClass*)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_n_children = gail_tree_view_get_n_children;
+  class->ref_child = gail_tree_view_ref_child;
+  class->ref_state_set = gail_tree_view_ref_state_set;
+  class->initialize = gail_tree_view_real_initialize;
+
+  widget_class->notify_gtk = gail_tree_view_real_notify_gtk;
+
+  accessible_class->connect_widget_destroyed = gail_tree_view_connect_widget_destroyed;
+
+  /*
+   * The children of a GtkTreeView are the buttons at the top of the columns
+   * we do not represent these as children so we do not want to report
+   * children added or deleted when these changed.
+   */
+  container_class->add_gtk = NULL;
+  container_class->remove_gtk = NULL;
+
+  gobject_class->finalize = gail_tree_view_finalize;
+
+  quark_column_desc_object = g_quark_from_static_string ("gtk-column-object");
+  quark_column_header_object = g_quark_from_static_string ("gtk-header-object");
+}
+
+static void
+gail_tree_view_real_initialize (AtkObject *obj,
+                                gpointer  data)
+{
+  GailTreeView *view;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model; 
+  GtkAdjustment *adj;
+  GList *tv_cols, *tmp_list;
+  GtkWidget *widget;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  view = GAIL_TREE_VIEW (obj);
+  view->caption = NULL;
+  view->summary = NULL;
+  view->row_data = NULL;
+  view->col_data = NULL;
+  view->cell_data = NULL;
+  view->focus_cell = NULL;
+  view->old_hadj = NULL;
+  view->old_vadj = NULL;
+  view->idle_expand_id = 0;
+  view->idle_expand_path = NULL;
+
+  view->n_children_deleted = 0;
+
+  widget = GTK_WIDGET (data);
+  g_signal_connect_after (widget,
+                          "row-collapsed",
+                          G_CALLBACK (gail_tree_view_collapse_row_gtk),
+                          NULL);
+  g_signal_connect (widget,
+                    "row-expanded",
+                    G_CALLBACK (gail_tree_view_expand_row_gtk),
+                    NULL);
+  g_signal_connect (widget,
+                    "size-allocate",
+                    G_CALLBACK (gail_tree_view_size_allocate_gtk),
+                    NULL);
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tree_model = gtk_tree_view_get_model (tree_view);
+
+  /* Set up signal handling */
+
+  g_signal_connect_data (gtk_tree_view_get_selection (tree_view),
+                         "changed",
+                         (GCallback) gail_tree_view_changed_gtk,
+                        obj, NULL, 0);
+
+  g_signal_connect_data (tree_view, "columns-changed",
+    (GCallback) columns_changed, NULL, NULL, 0);
+  g_signal_connect_data (tree_view, "cursor-changed",
+    (GCallback) cursor_changed, NULL, NULL, 0);
+
+  view->tree_model = tree_model;
+  if (tree_model)
+    {
+      g_object_add_weak_pointer (G_OBJECT (view->tree_model), (gpointer *)&view->tree_model);
+      connect_model_signals (tree_view, view);
+
+      if (GTK_IS_TREE_STORE (tree_model))
+        obj->role = ATK_ROLE_TREE_TABLE;
+      else
+        obj->role = ATK_ROLE_TABLE;
+    }
+  else
+    {
+      obj->role = ATK_ROLE_UNKNOWN;
+    }
+
+  /* adjustment callbacks */
+
+  g_object_get (tree_view, hadjustment, &adj, NULL);
+  view->old_hadj = adj;
+  g_object_add_weak_pointer (G_OBJECT (view->old_hadj), (gpointer *)&view->old_hadj);
+  g_signal_connect (adj, 
+                    "value_changed",
+                    G_CALLBACK (adjustment_changed),
+                    tree_view);
+
+  g_object_get (tree_view, vadjustment, &adj, NULL);
+  view->old_vadj = adj;
+  g_object_add_weak_pointer (G_OBJECT (view->old_vadj), (gpointer *)&view->old_vadj);
+  g_signal_connect (adj, 
+                    "value_changed",
+                    G_CALLBACK (adjustment_changed),
+                    tree_view);
+  g_signal_connect_after (widget,
+                          "set_scroll_adjustments",
+                          G_CALLBACK (gail_tree_view_set_scroll_adjustments),
+                          NULL);
+
+  view->col_data = g_array_sized_new (FALSE, TRUE, 
+                                      sizeof(GtkTreeViewColumn *), 0);
+
+  tv_cols = gtk_tree_view_get_columns (tree_view);
+
+  for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
+    {
+      g_signal_connect_data (tmp_list->data, "notify::visible",
+       (GCallback)column_visibility_changed, 
+        tree_view, NULL, FALSE);
+      g_signal_connect_data (tmp_list->data, "destroy",
+       (GCallback)column_destroy, 
+        NULL, NULL, FALSE);
+      g_array_append_val (view->col_data, tmp_list->data);
+    }
+
+  gtk_tree_view_set_destroy_count_func (tree_view, 
+                                        destroy_count_func,
+                                        NULL, NULL);
+  g_list_free (tv_cols);
+}
+
+static void
+gail_tree_view_real_notify_gtk (GObject             *obj,
+                                GParamSpec          *pspec)
+{
+  GtkWidget *widget;
+  AtkObject* atk_obj;
+  GtkTreeView *tree_view;
+  GailTreeView *gailview;
+  GtkAdjustment *adj;
+
+  widget = GTK_WIDGET (obj);
+  atk_obj = gtk_widget_get_accessible (widget);
+  tree_view = GTK_TREE_VIEW (widget);
+  gailview = GAIL_TREE_VIEW (atk_obj);
+
+  if (strcmp (pspec->name, "model") == 0)
+    {
+      GtkTreeModel *tree_model;
+      AtkRole role;
+
+      tree_model = gtk_tree_view_get_model (tree_view);
+      if (gailview->tree_model)
+        disconnect_model_signals (gailview);
+      clear_cached_data (gailview);
+      gailview->tree_model = tree_model;
+      /*
+       * if there is no model the GtkTreeView is probably being destroyed
+       */
+      if (tree_model)
+        {
+          g_object_add_weak_pointer (G_OBJECT (gailview->tree_model), (gpointer *)&gailview->tree_model);
+          connect_model_signals (tree_view, gailview);
+
+          if (GTK_IS_TREE_STORE (tree_model))
+            role = ATK_ROLE_TREE_TABLE;
+          else
+            role = ATK_ROLE_TABLE;
+        }
+      else
+        {
+          role = ATK_ROLE_UNKNOWN;
+        }
+      atk_object_set_role (atk_obj, role);
+      g_object_freeze_notify (G_OBJECT (atk_obj));
+      g_signal_emit_by_name (atk_obj, "model_changed");
+      g_signal_emit_by_name (atk_obj, "visible_data_changed");
+      g_object_thaw_notify (G_OBJECT (atk_obj));
+    }
+  else if (strcmp (pspec->name, hadjustment) == 0)
+    {
+      g_object_get (tree_view, hadjustment, &adj, NULL);
+      g_signal_handlers_disconnect_by_func (gailview->old_hadj, 
+                                           (gpointer) adjustment_changed,
+                                           widget);
+      gailview->old_hadj = adj;
+      g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
+      g_signal_connect (adj, 
+                        "value_changed",
+                        G_CALLBACK (adjustment_changed),
+                        tree_view);
+    }
+  else if (strcmp (pspec->name, vadjustment) == 0)
+    {
+      g_object_get (tree_view, vadjustment, &adj, NULL);
+      g_signal_handlers_disconnect_by_func (gailview->old_vadj, 
+                                           (gpointer) adjustment_changed,
+                                           widget);
+      gailview->old_vadj = adj;
+      g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_vadj);
+      g_signal_connect (adj, 
+                        "value_changed",
+                        G_CALLBACK (adjustment_changed),
+                        tree_view);
+    }
+  else
+    parent_class->notify_gtk (obj, pspec);
+}
+
+AtkObject*
+gail_tree_view_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_TREE_VIEW, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+static void
+gail_tree_view_finalize (GObject           *object)
+{
+  GailTreeView *view = GAIL_TREE_VIEW (object);
+
+  clear_cached_data (view);
+
+  /* remove any idle handlers still pending */
+  if (view->idle_garbage_collect_id)
+      g_source_remove (view->idle_garbage_collect_id);
+
+  if (view->caption)
+    g_object_unref (view->caption);
+  if (view->summary)
+    g_object_unref (view->summary);
+
+  if (view->tree_model)
+    disconnect_model_signals (view);
+
+  if (view->col_data)
+    {
+      GArray *array = view->col_data;
+
+     /*
+      * No need to free the contents of the array since it
+      * just contains pointers to the GtkTreeViewColumn
+      * objects that are in the GtkTreeView.
+      */
+      g_array_free (array, TRUE);
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gail_tree_view_connect_widget_destroyed (GtkAccessible *accessible)
+{
+  if (accessible->widget)
+    {
+      g_signal_connect_after (accessible->widget,
+                              "destroy",
+                              G_CALLBACK (gail_tree_view_destroyed),
+                              accessible);
+    }
+  GTK_ACCESSIBLE_CLASS (parent_class)->connect_widget_destroyed (accessible);
+}
+
+static void
+gail_tree_view_destroyed (GtkWidget *widget,
+                          GtkAccessible *accessible)
+{
+  GtkAdjustment *adj;
+  GailTreeView *gailview;
+
+  gail_return_if_fail (GTK_IS_TREE_VIEW (widget));
+
+  gailview = GAIL_TREE_VIEW (accessible);
+  adj = gailview->old_hadj;
+  if (adj)
+    g_signal_handlers_disconnect_by_func (adj, 
+                                          (gpointer) adjustment_changed,
+                                          widget);
+  adj = gailview->old_vadj;
+  if (adj)
+    g_signal_handlers_disconnect_by_func (adj, 
+                                          (gpointer) adjustment_changed,
+                                          widget);
+  if (gailview->tree_model)
+    {
+      disconnect_model_signals (gailview);
+      gailview->tree_model = NULL;
+    }
+  if (gailview->focus_cell)
+    {
+      g_object_unref (gailview->focus_cell);
+      gailview->focus_cell = NULL;
+    }
+  if (gailview->idle_expand_id) 
+    {
+      g_source_remove (gailview->idle_expand_id);
+      gailview->idle_expand_id = 0;
+    }
+}
+
+gint 
+get_focus_index (GtkTreeView *tree_view)
+{
+  GtkTreePath *focus_path;
+  GtkTreeViewColumn *focus_column;
+  gint index;
+
+  gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
+  if (focus_path && focus_column)
+    {
+
+      index = get_index (tree_view, focus_path,
+                         get_column_number (tree_view, focus_column, FALSE));
+    }
+  else
+    index = -1;
+
+  if (focus_path)
+    gtk_tree_path_free (focus_path);
+
+  return index;
+}
+
+AtkObject *
+gail_tree_view_ref_focus_cell (GtkTreeView *tree_view)
+{
+  /*
+   * This function returns a reference to the accessible object for the cell
+   * in the treeview which has focus, if a cell has focus.
+   */
+  AtkObject *focus_cell = NULL;
+  AtkObject *atk_obj;
+  gint focus_index;
+
+  focus_index = get_focus_index (tree_view);
+  if (focus_index >= 0)
+    {
+      atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+      focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
+    }
+
+  return focus_cell;
+}
+
+/* atkobject.h */
+
+static gint
+gail_tree_view_get_n_children (AtkObject *obj)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model;
+  gint n_rows, n_cols;
+
+  gail_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), 0);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return 0;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tree_model = gtk_tree_view_get_model (tree_view);
+
+  /*
+   * We get the total number of rows including those which are collapsed
+   */
+  n_rows = get_row_count (tree_model);
+  /*
+   * We get the total number of columns including those which are not visible
+   */
+  n_cols = get_n_actual_columns (tree_view);
+  return (n_rows * n_cols);
+}
+
+static AtkObject*
+gail_tree_view_ref_child (AtkObject *obj, 
+                          gint      i)
+{
+  GtkWidget *widget;
+  GailTreeView *gailview;
+  GailCell *cell;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model; 
+  GtkCellRenderer *renderer;
+  GtkTreeIter iter;
+  GtkTreeViewColumn *tv_col;
+  GtkTreeSelection *selection;
+  GtkTreePath *path;
+  AtkRegistry *default_registry;
+  AtkObjectFactory *factory;
+  AtkObject *child;
+  AtkObject *parent;
+  GtkTreeViewColumn *expander_tv;
+  GList *renderer_list;
+  GList *l;
+  GailContainerCell *container = NULL;
+  GailRendererCell *renderer_cell;
+  gboolean is_expander, is_expanded, retval;
+  gboolean editable = FALSE;
+  gint focus_index;
+
+  g_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), NULL);
+  g_return_val_if_fail (i >= 0, NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  if (i >= gail_tree_view_get_n_children (obj))
+    return NULL;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  if (i < get_n_actual_columns (tree_view))
+    {
+      tv_col = gtk_tree_view_get_column (tree_view, i);
+      child = get_header_from_column (tv_col);
+      if (child)
+        g_object_ref (child);
+      return child;
+    }
+
+  gailview = GAIL_TREE_VIEW (obj);
+  /*
+   * Check whether the child is cached
+   */
+  cell = find_cell (gailview, i);
+  if (cell)
+    {
+      g_object_ref (cell);
+      return ATK_OBJECT (cell);
+    }
+
+  if (gailview->focus_cell == NULL)
+      focus_index = get_focus_index (tree_view);
+  else
+      focus_index = -1;
+  /*
+   * Find the TreePath and GtkTreeViewColumn for the index
+   */
+  if (!get_path_column_from_index (tree_view, i, &path, &tv_col))
+    return NULL;
+  tree_model = gtk_tree_view_get_model (tree_view);
+  retval = gtk_tree_model_get_iter (tree_model, &iter, path);
+  gail_return_val_if_fail (retval, NULL);
+
+  expander_tv = gtk_tree_view_get_expander_column (tree_view);
+  is_expander = FALSE;
+  is_expanded = FALSE;
+  if (gtk_tree_model_iter_has_child (tree_model, &iter))
+    {
+      if (expander_tv == tv_col)
+        {
+          is_expander = TRUE;
+          is_expanded = gtk_tree_view_row_expanded (tree_view, path);
+        }
+    } 
+  gtk_tree_view_column_cell_set_cell_data (tv_col, tree_model, &iter, 
+                                           is_expander, is_expanded);
+
+  renderer_list = gtk_tree_view_column_get_cell_renderers (tv_col);
+
+  /* If there are more than one renderer in the list, make a container */
+
+  if (renderer_list && renderer_list->next)
+    {
+      GailCell *container_cell;
+
+      container = gail_container_cell_new ();
+      gail_return_val_if_fail (container, NULL);
+
+      container_cell = GAIL_CELL (container);
+      gail_cell_init (container_cell,
+                      widget, ATK_OBJECT (gailview), 
+                      i);
+      /*
+       * The GailTreeViewCellInfo structure for the container will be before
+       * the ones for the cells so that the first one we find for a position
+       * will be for the container
+       */
+      cell_info_new (gailview, tree_model, path, tv_col, container_cell);
+      container_cell->refresh_index = refresh_cell_index;
+      parent = ATK_OBJECT (container);
+    }
+  else
+    parent = ATK_OBJECT (gailview);
+
+  child = NULL;
+
+  /*
+   * Now we make a fake cell_renderer if there is no cell in renderer_list
+   */
+
+  if (renderer_list == NULL)
+  {
+    GtkCellRenderer *fake_renderer;
+    fake_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
+    default_registry = atk_get_default_registry ();
+    factory = atk_registry_get_factory (default_registry,
+                                        GTK_OBJECT_TYPE (fake_renderer));
+    child = atk_object_factory_create_accessible (factory,
+                                                  G_OBJECT (fake_renderer));
+    gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
+    cell = GAIL_CELL (child);
+    renderer_cell = GAIL_RENDERER_CELL (child);
+    renderer_cell->renderer = fake_renderer;
+
+    /* Create the GailTreeViewCellInfo structure for this cell */
+    cell_info_new (gailview, tree_model, path, tv_col, cell);
+
+    gail_cell_init (cell,
+                    widget, parent, 
+                    i);
+
+    cell->refresh_index = refresh_cell_index;
+
+    /* set state if it is expandable */
+    if (is_expander)
+    {
+      set_cell_expandable (cell);
+      if (is_expanded)
+        gail_cell_add_state (cell, 
+                             ATK_STATE_EXPANDED,
+                             FALSE);
+    }
+  } else {
+    for (l = renderer_list; l; l = l->next)
+      {
+        renderer = GTK_CELL_RENDERER (l->data);
+
+        if (GTK_IS_CELL_RENDERER_TEXT (renderer))
+          g_object_get (G_OBJECT (renderer), "editable", &editable, NULL);
+
+        default_registry = atk_get_default_registry ();
+        factory = atk_registry_get_factory (default_registry,
+                                            GTK_OBJECT_TYPE (renderer));
+        child = atk_object_factory_create_accessible (factory,
+                                                      G_OBJECT (renderer));
+        gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
+        cell = GAIL_CELL (child);
+        renderer_cell = GAIL_RENDERER_CELL (child);
+
+        /* Create the GailTreeViewCellInfo structure for this cell */
+        cell_info_new (gailview, tree_model, path, tv_col, cell);
+
+        gail_cell_init (cell,
+                        widget, parent, 
+                        i);
+
+        if (container)
+          gail_container_cell_add_child (container, cell);
+        else
+          cell->refresh_index = refresh_cell_index;
+
+        update_cell_value (renderer_cell, gailview, FALSE);
+        /* Add the actions appropriate for this cell */
+        add_cell_actions (cell, editable);
+
+        /* set state if it is expandable */
+        if (is_expander)
+          {
+            set_cell_expandable (cell);
+            if (is_expanded)
+              gail_cell_add_state (cell, 
+                                   ATK_STATE_EXPANDED,
+                                   FALSE);
+          }
+        /*
+         * If the column is visible, sets the cell's state
+         */
+        if (gtk_tree_view_column_get_visible (tv_col))
+          set_cell_visibility (tree_view, cell, tv_col, path, FALSE);
+        /*
+         * If the row is selected, all cells on the row are selected
+         */
+        selection = gtk_tree_view_get_selection (tree_view);
+
+        if (gtk_tree_selection_path_is_selected (selection, path))
+          gail_cell_add_state (cell, ATK_STATE_SELECTED, FALSE);
+
+        gail_cell_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
+        if (focus_index == i)
+          {
+            gailview->focus_cell = g_object_ref (cell);
+            gail_cell_add_state (cell, ATK_STATE_FOCUSED, FALSE);
+          }
+      }
+    g_list_free (renderer_list); 
+    if (container)
+      child =  ATK_OBJECT (container);
+  } 
+
+  if (expander_tv == tv_col)
+    {
+      AtkRelationSet *relation_set;
+      AtkObject *accessible_array[1];
+      AtkRelation* relation;
+      AtkObject *parent_node;
+
+      relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
+
+      gtk_tree_path_up (path);
+      if (gtk_tree_path_get_depth (path) == 0)
+        parent_node = obj;
+      else
+        {
+          gint parent_index;
+          gint n_columns;
+
+          n_columns = get_n_actual_columns (tree_view);
+          parent_index = get_index (tree_view, path, i % n_columns);
+          parent_node = atk_object_ref_accessible_child (obj, parent_index);
+        }
+      accessible_array[0] = parent_node;
+      relation = atk_relation_new (accessible_array, 1,
+                                   ATK_RELATION_NODE_CHILD_OF);
+      atk_relation_set_add (relation_set, relation);
+      g_object_unref (relation);
+      g_object_unref (relation_set);
+    }
+  gtk_tree_path_free (path);
+
+  /*
+   * We do not increase the reference count here; when g_object_unref() is 
+   * called for the cell then cell_destroyed() is called and
+   * this removes the cell from the cache.
+   */
+  return child;
+}
+
+static AtkStateSet*
+gail_tree_view_ref_state_set (AtkObject *obj)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+  widget = GTK_ACCESSIBLE (obj)->widget;
+
+  if (widget != NULL)
+    atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
+
+  return state_set;
+}
+
+/* atkcomponent.h */
+
+static void
+atk_component_interface_init (AtkComponentIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->ref_accessible_at_point = gail_tree_view_ref_accessible_at_point;
+}
+
+static AtkObject*
+gail_tree_view_ref_accessible_at_point (AtkComponent           *component,
+                                        gint                   x,
+                                        gint                   y,
+                                        AtkCoordType           coord_type)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreePath *path;
+  GtkTreeViewColumn *tv_column;
+  gint x_pos, y_pos;
+  gboolean ret_val;
+
+  widget = GTK_ACCESSIBLE (component)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  tree_view = GTK_TREE_VIEW (widget);
+
+  atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
+  ret_val = gtk_tree_view_get_path_at_pos (tree_view, 
+                                           x - x_pos, y - y_pos, 
+                                           &path, &tv_column, NULL, NULL);
+  if (ret_val)
+    {
+      gint index, column;
+
+      column = get_column_number (tree_view, tv_column, FALSE);
+      index = get_index (tree_view, path, column);
+      gtk_tree_path_free (path);
+
+      return gail_tree_view_ref_child (ATK_OBJECT (component), index);
+    } 
+  else
+    {
+      g_warning ("gail_tree_view_ref_accessible_at_point: gtk_tree_view_get_path_at_pos () failed\n");
+    }
+  return NULL;
+}
+           
+/* atktable.h */
+
+static void 
+atk_table_interface_init (AtkTableIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->ref_at = gail_tree_view_table_ref_at;
+  iface->get_n_rows = gail_tree_view_get_n_rows;       
+  iface->get_n_columns = gail_tree_view_get_n_columns; 
+  iface->get_index_at = gail_tree_view_get_index_at;   
+  iface->get_column_at_index = gail_tree_view_get_column_at_index;     
+  iface->get_row_at_index = gail_tree_view_get_row_at_index;   
+  iface->is_row_selected = gail_tree_view_is_row_selected;
+  iface->is_selected = gail_tree_view_is_selected;
+  iface->get_selected_rows = gail_tree_view_get_selected_rows;
+  iface->add_row_selection = gail_tree_view_add_row_selection;
+  iface->remove_row_selection = gail_tree_view_remove_row_selection;
+  iface->get_column_extent_at = NULL;
+  iface->get_row_extent_at = NULL;
+  iface->get_row_header = gail_tree_view_get_row_header;
+  iface->set_row_header = gail_tree_view_set_row_header;
+  iface->get_column_header = gail_tree_view_get_column_header;
+  iface->set_column_header = gail_tree_view_set_column_header;
+  iface->get_caption = gail_tree_view_get_caption;
+  iface->set_caption = gail_tree_view_set_caption;
+  iface->get_summary = gail_tree_view_get_summary;
+  iface->set_summary = gail_tree_view_set_summary;
+  iface->get_row_description = gail_tree_view_get_row_description;
+  iface->set_row_description = gail_tree_view_set_row_description;
+  iface->get_column_description = gail_tree_view_get_column_description;
+  iface->set_column_description = gail_tree_view_set_column_description;
+}
+
+static gint
+gail_tree_view_get_index_at (AtkTable *table,
+                             gint     row,
+                             gint     column)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  gint actual_column;
+  gint n_cols, n_rows;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  gint index;
+
+  n_cols = atk_table_get_n_columns (table);
+  n_rows = atk_table_get_n_rows (table);
+
+  if (row >= n_rows ||
+      column >= n_cols)
+    return -1;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  actual_column = get_actual_column_number (tree_view, column);
+
+  set_iter_nth_row (tree_view, &iter, row);
+  path = gtk_tree_model_get_path (gtk_tree_view_get_model (tree_view), &iter);
+
+  index = get_index (tree_view, path, actual_column);
+  gtk_tree_path_free (path);
+
+  return index;
+}
+
+static gint
+gail_tree_view_get_column_at_index (AtkTable *table,
+                                    gint     index)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  gint n_columns;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  n_columns = get_n_actual_columns (tree_view);
+
+  if (n_columns == 0)
+    return 0;
+  index = index % n_columns;
+
+  return get_visible_column_number (tree_view, index);
+}
+
+static gint
+gail_tree_view_get_row_at_index (AtkTable *table,
+                                 gint     index)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreePath *path;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return -1;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  if (get_path_column_from_index (tree_view, index, &path, NULL))
+    {
+      gint row = get_row_from_tree_path (tree_view, path);
+      gtk_tree_path_free (path);
+      return row;
+    }
+  else
+    return -1;
+}
+
+static AtkObject* 
+gail_tree_view_table_ref_at (AtkTable *table,
+                             gint     row, 
+                             gint     column)
+{
+  gint index;
+
+  index = gail_tree_view_get_index_at (table, row, column);
+  if (index == -1)
+    return NULL;
+  
+  return gail_tree_view_ref_child (ATK_OBJECT (table), index);
+}
+
+static gint 
+gail_tree_view_get_n_rows (AtkTable *table)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model;
+  gint n_rows;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tree_model = gtk_tree_view_get_model (tree_view);
+
+  if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
+   /* 
+    * If working with a LIST store, then this is a faster way
+    * to get the number of rows.
+    */
+    n_rows = gtk_tree_model_iter_n_children (tree_model, NULL);
+  else
+    {
+      GtkTreePath *root_tree;
+
+      n_rows = 0;
+      root_tree = gtk_tree_path_new_root ();
+      iterate_thru_children (tree_view, tree_model,
+                             root_tree, NULL, &n_rows, 0);
+      g_free (root_tree);
+    }
+
+  return n_rows;
+}
+
+/*
+ * The function get_n_actual_columns returns the number of columns in the 
+ * GtkTreeView. i.e. it include both visible and non-visible columns.
+ */
+static gint 
+get_n_actual_columns (GtkTreeView *tree_view)
+{
+  GList *columns;
+  gint n_cols;
+
+  columns = gtk_tree_view_get_columns (tree_view);
+  n_cols = g_list_length (columns);
+  g_list_free (columns);
+  return n_cols;
+}
+
+static gint 
+gail_tree_view_get_n_columns (AtkTable *table)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeViewColumn *tv_col;
+  gint n_cols = 0;
+  gint i = 0;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tv_col = gtk_tree_view_get_column (tree_view, i);
+
+  while (tv_col != NULL) 
+    {
+      if (gtk_tree_view_column_get_visible (tv_col)) 
+        n_cols++;
+
+      i++;
+      tv_col = gtk_tree_view_get_column (tree_view, i);
+    }
+
+  return n_cols;
+}
+
+static gboolean 
+gail_tree_view_is_row_selected (AtkTable *table,
+                                gint     row)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeSelection *selection;
+  GtkTreeIter iter;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  if (row < 0)
+    return FALSE;
+
+  tree_view = GTK_TREE_VIEW (widget);
+
+  selection = gtk_tree_view_get_selection (tree_view);
+
+  set_iter_nth_row (tree_view, &iter, row);
+
+  return gtk_tree_selection_iter_is_selected (selection, &iter);
+}
+
+static gboolean 
+gail_tree_view_is_selected (AtkTable *table, 
+                            gint     row, 
+                            gint     column)
+{
+  return gail_tree_view_is_row_selected (table, row);
+}
+
+static gint 
+gail_tree_view_get_selected_rows (AtkTable *table,
+                                  gint     **rows_selected)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model;
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+  GtkTreePath *tree_path;
+  gint ret_val = 0;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return 0;
+
+  tree_view = GTK_TREE_VIEW (widget);
+
+  selection = gtk_tree_view_get_selection (tree_view);
+
+  switch (selection->type)
+    {
+    case GTK_SELECTION_SINGLE:
+    case GTK_SELECTION_BROWSE:
+      if (gtk_tree_selection_get_selected (selection, &tree_model, &iter))
+        {
+          gint row;
+
+          if (rows_selected)
+            {
+              *rows_selected = (gint *)g_malloc (sizeof(gint));
+              tree_path = gtk_tree_model_get_path (tree_model, &iter);
+              row = get_row_from_tree_path (tree_view, tree_path);
+              gtk_tree_path_free (tree_path);
+
+              /* shouldn't ever happen */
+              g_return_val_if_fail (row != -1, 0);
+
+              *rows_selected[0] = row;
+            }
+          ret_val = 1;
+        }
+      break;
+    case GTK_SELECTION_MULTIPLE:
+      {
+        GPtrArray *array = g_ptr_array_new();
+
+        gtk_tree_selection_selected_foreach (selection,
+                                             get_selected_rows,
+                                             array);
+        ret_val = array->len;
+
+        if (rows_selected && ret_val)
+          {
+            gint i;
+            *rows_selected = (gint *) g_malloc (ret_val * sizeof (gint));
+
+            for (i = 0; i < ret_val; i++)
+              {
+                gint row;
+
+                tree_path = (GtkTreePath *) g_ptr_array_index (array, i);
+                row = get_row_from_tree_path (tree_view, tree_path);
+                gtk_tree_path_free (tree_path);
+                (*rows_selected)[i] = row;
+              }
+          }
+        g_ptr_array_free (array, FALSE);
+      }
+      break;
+    case GTK_SELECTION_NONE:
+      break; 
+    }
+  return ret_val;
+}
+
+static gboolean 
+gail_tree_view_add_row_selection (AtkTable *table, 
+                                  gint     row)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model;
+  GtkTreeSelection *selection;
+  GtkTreePath *tree_path;
+  GtkTreeIter iter_to_row;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+  
+  if (!gail_tree_view_is_row_selected (table, row))
+    {
+      tree_view = GTK_TREE_VIEW (widget);
+      tree_model = gtk_tree_view_get_model (tree_view);
+      selection = gtk_tree_view_get_selection (tree_view);
+
+      if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
+        {
+          tree_path = gtk_tree_path_new ();
+          gtk_tree_path_append_index (tree_path, row);
+          gtk_tree_selection_select_path (selection,tree_path);
+          gtk_tree_path_free (tree_path);
+        }
+      else
+        { 
+          set_iter_nth_row (tree_view, &iter_to_row, row);
+          if (&iter_to_row != NULL)
+            gtk_tree_selection_select_iter (selection, &iter_to_row);
+          else
+            return FALSE;
+        }
+    }
+
+  return gail_tree_view_is_row_selected (table, row);
+}
+
+static gboolean 
+gail_tree_view_remove_row_selection (AtkTable *table, 
+                                     gint     row)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeSelection *selection;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  tree_view = GTK_TREE_VIEW (widget);
+
+  selection = gtk_tree_view_get_selection (tree_view);
+
+  if (gail_tree_view_is_row_selected (table, row)) 
+    {
+      gtk_tree_selection_unselect_all (selection);
+      return TRUE;
+    }
+  else return FALSE;
+}
+
+static AtkObject* 
+gail_tree_view_get_row_header (AtkTable *table, 
+                               gint     row)
+{
+  GailTreeViewRowInfo *row_info;
+
+  row_info = get_row_info (table, row);
+  if (row_info)
+    return row_info->header;
+  else
+    return NULL;
+}
+
+static void
+gail_tree_view_set_row_header (AtkTable  *table, 
+                               gint      row, 
+                               AtkObject *header)
+{
+  set_row_data (table, row, header, NULL, TRUE);
+}
+
+static AtkObject* 
+gail_tree_view_get_column_header (AtkTable *table, 
+                                  gint     in_col)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeViewColumn *tv_col;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tv_col = get_column (tree_view, in_col);
+  return get_header_from_column (tv_col);
+}
+
+static void
+gail_tree_view_set_column_header (AtkTable  *table, 
+                                  gint      in_col,
+                                  AtkObject *header)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeViewColumn *tv_col;
+  AtkObject *rc;
+  AtkPropertyValues values = { NULL };
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tv_col = get_column (tree_view, in_col);
+  if (tv_col == NULL)
+     return;
+
+  rc = g_object_get_qdata (G_OBJECT (tv_col),
+                          quark_column_header_object);
+  if (rc)
+    g_object_unref (rc);
+
+  g_object_set_qdata (G_OBJECT (tv_col),
+                       quark_column_header_object,
+                       header);
+  if (header)
+    g_object_ref (header);
+  g_value_init (&values.new_value, G_TYPE_INT);
+  g_value_set_int (&values.new_value, in_col);
+
+  values.property_name = "accessible-table-column-header";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-column-header",
+                         &values, NULL);
+}
+
+static AtkObject*
+gail_tree_view_get_caption (AtkTable   *table)
+{
+  GailTreeView* obj = GAIL_TREE_VIEW (table);
+
+  return obj->caption;
+}
+
+static void
+gail_tree_view_set_caption (AtkTable   *table,
+                            AtkObject   *caption)
+{
+  GailTreeView* obj = GAIL_TREE_VIEW (table);
+  AtkPropertyValues values = { NULL };
+  AtkObject *old_caption;
+
+  old_caption = obj->caption;
+  obj->caption = caption;
+  if (obj->caption)
+    g_object_ref (obj->caption);
+  g_value_init (&values.old_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.old_value, old_caption);
+  g_value_init (&values.new_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.new_value, obj->caption);
+
+  values.property_name = "accessible-table-caption-object";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-caption-object", 
+                         &values, NULL);
+  if (old_caption)
+    g_object_unref (old_caption);
+}
+
+static G_CONST_RETURN gchar*
+gail_tree_view_get_column_description (AtkTable          *table,
+                                       gint       in_col)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeViewColumn *tv_col;
+  gchar *rc;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tv_col = get_column (tree_view, in_col);
+  if (tv_col == NULL)
+     return NULL;
+
+  rc = g_object_get_qdata (G_OBJECT (tv_col),
+                           quark_column_desc_object);
+
+  if (rc != NULL)
+    return rc;
+  else
+    {
+      gchar *title_text;
+
+      g_object_get (tv_col, "title", &title_text, NULL);
+      return title_text;
+    }
+}
+
+static void
+gail_tree_view_set_column_description (AtkTable           *table,
+                                       gint        in_col,
+                                       const gchar *description)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeViewColumn *tv_col;
+  AtkPropertyValues values = { NULL };
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tv_col = get_column (tree_view, in_col);
+  if (tv_col == NULL)
+     return;
+
+  g_object_set_qdata (G_OBJECT (tv_col),
+                      quark_column_desc_object,
+                      g_strdup (description));
+  g_value_init (&values.new_value, G_TYPE_INT);
+  g_value_set_int (&values.new_value, in_col);
+
+  values.property_name = "accessible-table-column-description";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-column-description",
+                         &values, NULL);
+}
+
+static G_CONST_RETURN gchar*
+gail_tree_view_get_row_description (AtkTable    *table,
+                                    gint        row)
+{
+  GailTreeViewRowInfo *row_info;
+
+  row_info = get_row_info (table, row);
+  if (row_info)
+    return row_info->description;
+  else
+    return NULL;
+}
+
+static void
+gail_tree_view_set_row_description (AtkTable    *table,
+                                    gint        row,
+                                    const gchar *description)
+{
+  set_row_data (table, row, NULL, description, FALSE);
+}
+
+static AtkObject*
+gail_tree_view_get_summary (AtkTable   *table)
+{
+  GailTreeView* obj = GAIL_TREE_VIEW (table);
+
+  return obj->summary;
+}
+
+static void
+gail_tree_view_set_summary (AtkTable    *table,
+                            AtkObject   *accessible)
+{
+  GailTreeView* obj = GAIL_TREE_VIEW (table);
+  AtkPropertyValues values = { NULL };
+  AtkObject *old_summary;
+
+  old_summary = obj->summary;
+  obj->summary = accessible;
+  if (obj->summary)
+    g_object_ref (obj->summary);
+  g_value_init (&values.old_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.old_value, old_summary);
+  g_value_init (&values.new_value, G_TYPE_POINTER);
+  g_value_set_pointer (&values.new_value, obj->summary);
+
+  values.property_name = "accessible-table-summary";
+  g_signal_emit_by_name (table, 
+                         "property_change::accessible-table-ummary",
+                         &values, NULL);
+  if (old_summary)
+    g_object_unref (old_summary);
+}
+
+static void
+set_row_data (AtkTable    *table, 
+              gint        row, 
+              AtkObject   *header,
+              const gchar *description,
+              gboolean    is_header)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model;
+  GailTreeView* obj = GAIL_TREE_VIEW (table);
+  GailTreeViewRowInfo* row_info;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GArray *array;
+  gboolean found = FALSE;
+  gint i;
+  AtkPropertyValues values = { NULL };
+  gchar *signal_name;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tree_model = gtk_tree_view_get_model (tree_view);
+
+  set_iter_nth_row (tree_view, &iter, row);
+  path = gtk_tree_model_get_path (tree_model, &iter);
+
+  if (obj->row_data == NULL)
+    obj->row_data = g_array_sized_new (FALSE, TRUE,
+                                       sizeof(GailTreeViewRowInfo *), 0);
+
+  array = obj->row_data;
+
+  for (i = 0; i < array->len; i++)
+    {
+      GtkTreePath *row_path;
+
+      row_info = g_array_index (array, GailTreeViewRowInfo*, i);
+      row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
+
+      if (row_path != NULL)
+        {
+          if (path && gtk_tree_path_compare (row_path, path) == 0)
+            found = TRUE;
+
+          gtk_tree_path_free (row_path);
+
+          if (found)
+            {
+              if (is_header)
+                {
+                  if (row_info->header)
+                    g_object_unref (row_info->header);
+                  row_info->header = header;
+                  if (row_info->header)
+                    g_object_ref (row_info->header);
+                }
+              else
+                {
+                  g_free (row_info->description);
+                  row_info->description = g_strdup (description);
+                }
+              break;
+            }
+        }
+    }
+
+  if (!found)
+    {
+      /* if not found */
+      row_info = g_malloc (sizeof(GailTreeViewRowInfo));
+      row_info->row_ref = gtk_tree_row_reference_new (tree_model, path);
+      if (is_header)
+        {
+          row_info->header = header;
+          if (row_info->header)
+            g_object_ref (row_info->header);
+          row_info->description = NULL;
+        }
+      else
+        {
+          row_info->header = NULL;
+          row_info->description = g_strdup (description);
+        }
+      g_array_append_val (array, row_info);
+    }
+  g_value_init (&values.new_value, G_TYPE_INT);
+  g_value_set_int (&values.new_value, row);
+
+  if (is_header)
+    {
+      values.property_name = "accessible-table-row-header";
+      signal_name = "property_change::accessible-table-row-header";
+    }
+  else
+    {
+      values.property_name = "accessible-table-row-description";
+      signal_name = "property-change::accessible-table-row-description";
+    }
+  g_signal_emit_by_name (table, 
+                         signal_name,
+                         &values, NULL);
+
+  gtk_tree_path_free (path);
+}
+
+
+static GailTreeViewRowInfo*
+get_row_info (AtkTable    *table,
+              gint        row)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model;
+  GailTreeView* obj = GAIL_TREE_VIEW (table);
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GArray *array;
+  GailTreeViewRowInfo *rc = NULL;
+
+  widget = GTK_ACCESSIBLE (table)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return NULL;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  tree_model = gtk_tree_view_get_model (tree_view);
+
+  set_iter_nth_row (tree_view, &iter, row);
+  path = gtk_tree_model_get_path (tree_model, &iter);
+  array = obj->row_data;
+
+  if (array != NULL)
+    {
+      GailTreeViewRowInfo *row_info;
+      GtkTreePath *row_path;
+      gint i;
+
+      for (i = 0; i < array->len; i++)
+        {
+          row_info = g_array_index (array, GailTreeViewRowInfo*, i);
+          row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
+          if (row_path != NULL)
+            {
+              if (path && gtk_tree_path_compare (row_path, path) == 0)
+                rc = row_info;
+
+              gtk_tree_path_free (row_path);
+
+              if (rc != NULL)
+                break;
+            }
+        }
+    }
+
+  gtk_tree_path_free (path);
+  return rc;
+}
+/* atkselection.h */
+
+static void atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+  iface->add_selection = gail_tree_view_add_selection;
+  iface->clear_selection = gail_tree_view_clear_selection;
+  iface->ref_selection = gail_tree_view_ref_selection;
+  iface->get_selection_count = gail_tree_view_get_selection_count;
+  iface->is_child_selected = gail_tree_view_is_child_selected;
+}
+
+static gboolean
+gail_tree_view_add_selection (AtkSelection *selection,
+                              gint         i)
+{
+  AtkTable *table;
+  gint n_columns;
+  gint row;
+
+  table = ATK_TABLE (selection);
+  n_columns = gail_tree_view_get_n_columns (table);
+  if (n_columns != 1)
+    return FALSE;
+
+  row = gail_tree_view_get_row_at_index (table, i);
+  return gail_tree_view_add_row_selection (table, row);
+}
+
+static gboolean
+gail_tree_view_clear_selection (AtkSelection *selection)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeSelection *tree_selection;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+  tree_view = GTK_TREE_VIEW (widget);
+
+  tree_selection = gtk_tree_view_get_selection (tree_view);
+  gtk_tree_selection_unselect_all (tree_selection);  
+
+  return TRUE;
+}
+
+static AtkObject*  
+gail_tree_view_ref_selection (AtkSelection *selection, 
+                              gint         i)
+{
+  AtkTable *table;
+  gint row;
+  gint n_selected;
+  gint n_columns;
+  gint *selected;
+
+  table = ATK_TABLE (selection);
+  n_columns = gail_tree_view_get_n_columns (table);
+  n_selected = gail_tree_view_get_selected_rows (table, &selected);
+  if (i >= n_columns * n_selected)
+    return NULL;
+
+  row = selected[i / n_columns];
+  g_free (selected);
+
+  return gail_tree_view_table_ref_at (table, row, i % n_columns);
+}
+
+static gint
+gail_tree_view_get_selection_count (AtkSelection *selection)
+{
+  AtkTable *table;
+  gint n_selected;
+
+  table = ATK_TABLE (selection);
+  n_selected = gail_tree_view_get_selected_rows (table, NULL);
+  if (n_selected > 0)
+    n_selected *= gail_tree_view_get_n_columns (table);
+  return n_selected;
+}
+
+static gboolean
+gail_tree_view_is_child_selected (AtkSelection *selection, 
+                                  gint         i)
+{
+  GtkWidget *widget;
+  gint row;
+
+  widget = GTK_ACCESSIBLE (selection)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
+
+  return gail_tree_view_is_row_selected (ATK_TABLE (selection), row);
+}
+
+
+static void gail_cell_parent_interface_init (GailCellParentIface *iface)
+{
+  g_return_if_fail (iface);
+
+  iface->get_cell_extents = gail_tree_view_get_cell_extents;
+  iface->get_cell_area = gail_tree_view_get_cell_area;
+  iface->grab_focus = gail_tree_view_grab_cell_focus;
+}
+
+static void
+gail_tree_view_get_cell_extents (GailCellParent *parent,
+                                 GailCell       *cell,
+                                 gint           *x,
+                                 gint           *y,
+                                 gint           *width,
+                                 gint           *height,
+                                 AtkCoordType   coord_type)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GdkWindow *bin_window;
+  GdkRectangle cell_rect;
+  gint w_x, w_y;
+
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  gail_tree_view_get_cell_area (parent, cell, &cell_rect);
+  bin_window = gtk_tree_view_get_bin_window (tree_view);
+  gdk_window_get_origin (bin_window, &w_x, &w_y);
+
+  if (coord_type == ATK_XY_WINDOW)
+    {
+      GdkWindow *window;
+      gint x_toplevel, y_toplevel;
+
+      window = gdk_window_get_toplevel (bin_window);
+      gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
+
+      w_x -= x_toplevel;
+      w_y -= y_toplevel;
+    }
+
+  *width = cell_rect.width;
+  *height = cell_rect.height;
+  if (is_cell_showing (tree_view, &cell_rect))
+    {
+      *x = cell_rect.x + w_x;
+      *y = cell_rect.y + w_y;
+    }
+  else
+    {
+      *x = G_MININT;
+      *y = G_MININT;
+    }
+}
+
+#define EXTRA_EXPANDER_PADDING 4
+
+static void
+gail_tree_view_get_cell_area (GailCellParent *parent,
+                              GailCell       *cell,
+                              GdkRectangle   *cell_rect)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeViewColumn *tv_col;
+  GtkTreePath *path;
+  AtkObject *parent_cell;
+  GailTreeViewCellInfo *cell_info;
+  GailCell *top_cell;
+
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return;
+
+  tree_view = GTK_TREE_VIEW (widget);
+  parent_cell = atk_object_get_parent (ATK_OBJECT (cell));
+  if (parent_cell != ATK_OBJECT (parent))
+    {
+      /*
+       * GailCell is in a GailContainerCell
+       */
+      top_cell = GAIL_CELL (parent_cell);
+    }
+  else
+    {
+      top_cell = cell;
+    }
+  cell_info = find_cell_info (GAIL_TREE_VIEW (parent), top_cell, NULL, TRUE);
+  gail_return_if_fail (cell_info);
+  gail_return_if_fail (cell_info->cell_col_ref);
+  gail_return_if_fail (cell_info->cell_row_ref);
+  path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+  tv_col = cell_info->cell_col_ref;
+  if (path && cell_info->in_use)
+    {
+      GtkTreeViewColumn *expander_column;
+      gint focus_line_width;
+
+      gtk_tree_view_get_cell_area (tree_view, path, tv_col, cell_rect);
+      expander_column = gtk_tree_view_get_expander_column (tree_view);
+      if (expander_column == tv_col)
+        {
+          gint expander_size;
+
+          gtk_widget_style_get (widget,
+                                "expander_size", &expander_size,
+                                NULL);
+
+          cell_rect->x += expander_size + EXTRA_EXPANDER_PADDING;
+          cell_rect->width -= expander_size + EXTRA_EXPANDER_PADDING;
+        }
+      gtk_widget_style_get (widget,
+                            "focus-line-width", &focus_line_width,
+                            NULL);
+
+      cell_rect->x += focus_line_width;
+      cell_rect->width -= 2 * focus_line_width; 
+
+      gtk_tree_path_free (path);
+
+      /*
+       * A column has more than one renderer so we find the position and width
+       * of each.
+       */
+      if (top_cell != cell)
+        {
+          gint cell_index;
+          gboolean found;
+          gint cell_start;
+          gint cell_width;
+          GList *renderers;
+          GtkCellRenderer *renderer;
+
+         cell_index = atk_object_get_index_in_parent (ATK_OBJECT (cell));
+         renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
+         renderer = g_list_nth_data (renderers, cell_index);
+
+         found = gtk_tree_view_column_cell_get_position (tv_col, renderer, &cell_start, &cell_width);
+          if (found)
+            {
+              cell_rect->x += cell_start;
+              cell_rect->width = cell_width;
+            }
+         g_list_free (renderers);
+       }
+
+    }
+}
+
+static gboolean
+gail_tree_view_grab_cell_focus  (GailCellParent *parent,
+                                 GailCell       *cell)
+{
+  GtkWidget *widget;
+  GtkTreeView *tree_view;
+  GtkTreeViewColumn *tv_col;
+  GtkTreePath *path;
+  AtkObject *parent_cell;
+  AtkObject *cell_object;
+  GailTreeViewCellInfo *cell_info;
+  GtkCellRenderer *renderer = NULL;
+  GtkWidget *toplevel;
+  gint index;
+
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  if (widget == NULL)
+    /* State is defunct */
+    return FALSE;
+
+  tree_view = GTK_TREE_VIEW (widget);
+
+  cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+  gail_return_val_if_fail (cell_info, FALSE);
+  gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
+  gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
+  cell_object = ATK_OBJECT (cell);
+  parent_cell = atk_object_get_parent (cell_object);
+  tv_col = cell_info->cell_col_ref;
+  if (parent_cell != ATK_OBJECT (parent))
+    {
+      /*
+       * GailCell is in a GailContainerCell.
+       * The GtkTreeViewColumn has multiple renderers; 
+       * find the corresponding one.
+       */
+      GList *renderers;
+
+      renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
+      if (cell_info->in_use) {
+         index = atk_object_get_index_in_parent (cell_object);
+         renderer = g_list_nth_data (renderers, index);
+      }
+      g_list_free (renderers);
+    }
+  path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+  if (path && cell_info->in_use)
+    {
+      if (renderer)
+        gtk_tree_view_set_cursor_on_cell (tree_view, path, tv_col, renderer, FALSE);
+      else
+        gtk_tree_view_set_cursor (tree_view, path, tv_col, FALSE);
+
+      gtk_tree_path_free (path);
+      gtk_widget_grab_focus (widget);
+      toplevel = gtk_widget_get_toplevel (widget);
+      if (GTK_WIDGET_TOPLEVEL (toplevel))
+       {
+#ifdef GDK_WINDOWING_X11
+         gtk_window_present_with_time (GTK_WINDOW (toplevel), gdk_x11_get_server_time (widget->window));
+#else
+         gtk_window_present (GTK_WINDOW (toplevel));
+#endif
+       }
+
+      return TRUE;
+    }
+  else
+      return FALSE; 
+}
+
+/* signal handling */
+
+static gboolean
+gail_tree_view_expand_row_gtk (GtkTreeView       *tree_view,
+                               GtkTreeIter        *iter,
+                               GtkTreePath        *path)
+{
+  AtkObject *atk_obj;
+  GailTreeView *gailview;
+
+  g_assert (GTK_IS_TREE_VIEW (tree_view));
+
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+
+  g_assert (GAIL_IS_TREE_VIEW (atk_obj));
+
+  gailview = GAIL_TREE_VIEW (atk_obj);
+
+  /*
+   * The visible rectangle has not been updated when this signal is emitted
+   * so we process the signal when the GTK processing is completed
+   */
+  /* this seems wrong since it overwrites any other pending expand handlers... */
+  gailview->idle_expand_path = gtk_tree_path_copy (path);
+  if (gailview->idle_expand_id) g_source_remove (gailview->idle_expand_id);
+  gailview->idle_expand_id = g_idle_add (idle_expand_row, gailview);
+  return FALSE;
+}
+
+static gint
+idle_expand_row (gpointer data)
+{
+  GailTreeView *gailview = data;
+  GtkTreePath *path;
+  GtkTreeView *tree_view;
+  GtkTreeIter iter;
+  GtkTreeModel *tree_model;
+  gint n_inserted, row;
+
+  GDK_THREADS_ENTER ();
+
+  path = gailview->idle_expand_path;
+  tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
+
+  g_assert (GTK_IS_TREE_VIEW (tree_view));
+
+  tree_model = gtk_tree_view_get_model(tree_view);
+
+  g_assert (GTK_IS_TREE_MODEL (tree_model));
+
+  if (!path || !gtk_tree_model_get_iter (tree_model, &iter, path))
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  /*
+   * Update visibility of cells below expansion row
+   */
+  traverse_cells (gailview, path, FALSE, FALSE);
+  /*
+   * Figure out number of visible children, the following test
+   * should not fail
+   */
+  if (gtk_tree_model_iter_has_child (tree_model, &iter))
+    {
+      GtkTreePath *path_copy;
+
+     /*
+      * By passing path into this function, we find the number of
+      * visible children of path.
+      */
+      path_copy = gtk_tree_path_copy (path);
+      gtk_tree_path_append_index(path_copy, 0);
+
+      n_inserted = 0;
+      iterate_thru_children (tree_view, tree_model,
+                             path_copy, NULL, &n_inserted, 0);
+      gtk_tree_path_free (path_copy);
+    }
+  else
+    {
+      /* We can get here if the row expanded callback deleted the row */
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  /* Set expand state */
+  set_expand_state (tree_view, tree_model, gailview, path, TRUE);
+
+  row = get_row_from_tree_path (tree_view, path);
+
+  /* shouldn't ever happen */
+  if (row == -1)
+    g_assert_not_reached ();
+
+  /* Must add 1 because the "added rows" are below the row being expanded */
+  row += 1;
+  
+  g_signal_emit_by_name (gailview, "row_inserted", row, n_inserted);
+
+  gailview->idle_expand_path = NULL;
+
+  gtk_tree_path_free (path);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gboolean
+gail_tree_view_collapse_row_gtk (GtkTreeView       *tree_view,
+                                 GtkTreeIter        *iter,
+                                 GtkTreePath        *path)
+{
+  GtkTreeModel *tree_model;
+  AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+  GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
+  gint row;
+
+  tree_model = gtk_tree_view_get_model (tree_view);
+
+  clean_rows (gailview);
+
+  /*
+   * Update visibility of cells below collapsed row
+   */
+  traverse_cells (gailview, path, FALSE, FALSE);
+  /* Set collapse state */
+  set_expand_state (tree_view, tree_model, gailview, path, FALSE);
+
+  gail_return_val_if_fail (gailview->n_children_deleted, FALSE);
+  row = get_row_from_tree_path (tree_view, path);
+  gail_return_val_if_fail (row != -1, FALSE);
+  g_signal_emit_by_name (atk_obj, "row_deleted", row, 
+                         gailview->n_children_deleted);
+  gailview->n_children_deleted = 0;
+  return FALSE;
+}
+
+static void
+gail_tree_view_size_allocate_gtk (GtkWidget     *widget,
+                                  GtkAllocation *allocation)
+{
+  AtkObject *atk_obj = gtk_widget_get_accessible (widget);
+  GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
+
+  /*
+   * If the size allocation changes, the visibility of cells may change so
+   * update the cells visibility.
+   */
+  traverse_cells (gailview, NULL, FALSE, FALSE);
+}
+
+static void
+gail_tree_view_set_scroll_adjustments (GtkWidget     *widget,
+                                       GtkAdjustment *hadj,
+                                       GtkAdjustment *vadj)
+{
+  AtkObject *atk_obj = gtk_widget_get_accessible (widget);
+  GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
+  GtkAdjustment *adj;
+
+  g_object_get (widget, hadjustment, &adj, NULL);
+  if (gailview->old_hadj != adj)
+     {
+        g_signal_handlers_disconnect_by_func (gailview->old_hadj, 
+                                              (gpointer) adjustment_changed,
+                                              widget);
+        gailview->old_hadj = adj;
+        g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
+        g_signal_connect (adj, 
+                          "value_changed",
+                          G_CALLBACK (adjustment_changed),
+                          widget);
+     } 
+  g_object_get (widget, vadjustment, &adj, NULL);
+  if (gailview->old_vadj != adj)
+     {
+        g_signal_handlers_disconnect_by_func (gailview->old_vadj, 
+                                              (gpointer) adjustment_changed,
+                                              widget);
+        gailview->old_vadj = adj;
+        g_object_add_weak_pointer (G_OBJECT (gailview->old_vadj), (gpointer *)&gailview->old_vadj);
+        g_signal_connect (adj, 
+                          "value_changed",
+                          G_CALLBACK (adjustment_changed),
+                          widget);
+     } 
+}
+
+static void
+gail_tree_view_changed_gtk (GtkTreeSelection *selection,
+                            gpointer         data)
+{
+  GailTreeView *gailview;
+  GtkTreeView *tree_view;
+  GtkWidget *widget;
+  GList *cell_list;
+  GList *l;
+  GailTreeViewCellInfo *info;
+  GtkTreeSelection *tree_selection;
+  GtkTreePath *path;
+
+  gailview = GAIL_TREE_VIEW (data);
+  cell_list = gailview->cell_data;
+  widget = GTK_ACCESSIBLE (gailview)->widget;
+  if (widget == NULL)
+    /*
+     * destroy signal emitted for widget
+     */
+    return;
+  tree_view = GTK_TREE_VIEW (widget);
+
+  tree_selection = gtk_tree_view_get_selection (tree_view);
+
+  for (l = cell_list; l; l = l->next)
+    {
+      info = (GailTreeViewCellInfo *) (l->data);
+
+      if (info->in_use)
+      {
+         gail_cell_remove_state (info->cell, ATK_STATE_SELECTED, TRUE); 
+         
+         path = gtk_tree_row_reference_get_path (info->cell_row_ref);
+         if (path && gtk_tree_selection_path_is_selected (tree_selection, path))
+             gail_cell_add_state (info->cell, ATK_STATE_SELECTED, TRUE); 
+         gtk_tree_path_free (path);
+      }
+    }
+  if (GTK_WIDGET_REALIZED (widget))
+    g_signal_emit_by_name (gailview, "selection_changed");
+}
+
+static void
+columns_changed (GtkTreeView *tree_view)
+{
+  AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET(tree_view));
+  GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
+  GList *tv_cols, *tmp_list;
+  gboolean column_found;
+  gboolean move_found = FALSE;
+  gboolean stale_set = FALSE;
+  gint column_count = 0;
+  gint i;
+
+ /*
+  * This function must determine if the change is an add, delete or
+  * a move based upon its cache of TreeViewColumns in
+  * gailview->col_data
+  */
+  tv_cols = gtk_tree_view_get_columns (tree_view);
+
+  /* check for adds or moves */
+  for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
+    {
+      column_found = FALSE;
+
+      for (i = 0; i < gailview->col_data->len; i++)
+        {
+
+          if ((GtkTreeViewColumn *)tmp_list->data ==
+              (GtkTreeViewColumn *)g_array_index (gailview->col_data,
+               GtkTreeViewColumn *, i))
+            {
+              column_found = TRUE;
+
+              /* If the column isn't in the same position, a move happened */
+              if (!move_found && i != column_count)
+                {
+                  if (!stale_set)
+                    {
+                      /* Set all rows to ATK_STATE_STALE */
+                      traverse_cells (gailview, NULL, TRUE, FALSE);
+                      stale_set = TRUE;
+                    }
+  
+                  /* Just emit one column reordered signal when a move happens */
+                  g_signal_emit_by_name (atk_obj, "column_reordered");
+                  move_found = TRUE;
+                }
+
+              break;
+            }
+        }
+
+     /*
+      * If column_found is FALSE, then an insert happened for column
+      * number column_count
+      */
+      if (!column_found)
+        {
+          gint n_cols, n_rows, row;
+
+          if (!stale_set)
+            {
+              /* Set all rows to ATK_STATE_STALE */
+              traverse_cells (gailview, NULL, TRUE, FALSE);
+              stale_set = TRUE;
+            }
+
+          /* Generate column-inserted signal */
+          g_signal_emit_by_name (atk_obj, "column_inserted", column_count, 1);
+
+          /* Generate children-changed signals */
+          n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
+          n_cols = get_n_actual_columns (tree_view);
+          for (row = 0; row < n_rows; row++)
+            {
+             /*
+              * Pass NULL as the child object, i.e. 4th argument.
+              */
+              g_signal_emit_by_name (atk_obj, "children_changed::add",
+                                    ((row * n_cols) + column_count), NULL, NULL);
+            }
+        }
+
+      column_count++;
+    }
+
+  /* check for deletes */
+  for (i = 0; i < gailview->col_data->len; i++)
+    {
+      column_found = FALSE;
+
+      for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
+        {
+            if ((GtkTreeViewColumn *)tmp_list->data ==
+                (GtkTreeViewColumn *)g_array_index (gailview->col_data,
+                 GtkTreeViewColumn *, i))
+              {
+                column_found = TRUE;
+                break;
+              }
+        }
+
+       /*
+        * If column_found is FALSE, then a delete happened for column
+        * number i
+        */
+      if (!column_found)
+        {
+          gint n_rows, n_cols, row;
+
+          clean_cols (gailview,
+                      (GtkTreeViewColumn *)g_array_index (gailview->col_data,
+                     GtkTreeViewColumn *, i));
+
+          if (!stale_set)
+            {
+              /* Set all rows to ATK_STATE_STALE */
+              traverse_cells (gailview, NULL, TRUE, FALSE);
+              stale_set = TRUE;
+            }
+
+          /* Generate column-deleted signal */
+          g_signal_emit_by_name (atk_obj, "column_deleted", i, 1);
+
+          /* Generate children-changed signals */
+          n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
+          n_cols = get_n_actual_columns (tree_view);
+          for (row = 0; row < n_rows; row++)
+            {
+             /*
+              * Pass NULL as the child object, 4th argument.
+              */
+              g_signal_emit_by_name (atk_obj, "children_changed::remove",
+                                    ((row * n_cols) + column_count), NULL, NULL);
+            }
+        }
+    }
+   
+  /* rebuild the array */
+
+  g_array_free (gailview->col_data, TRUE);
+  gailview->col_data = g_array_sized_new (FALSE, TRUE,
+    sizeof(GtkTreeViewColumn *), 0);
+
+  for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
+     g_array_append_val (gailview->col_data, tmp_list->data);
+  g_list_free (tv_cols);
+}
+
+static void
+cursor_changed (GtkTreeView *tree_view)
+{
+  /*
+   * We notify the focus change in a idle handler so that the processing
+   * of the cursor change is completed when the focus handler is called.
+   * This will allow actions to be called in the focus handler
+   */ 
+  g_idle_add (idle_cursor_changed, gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
+}
+
+static gint
+idle_cursor_changed (gpointer data)
+{
+  GtkTreeView *tree_view;
+  GtkWidget *widget;
+  AtkObject *parent;
+  AtkObject *cell;
+
+  GDK_THREADS_ENTER ();
+
+  parent = ATK_OBJECT (data);
+
+  widget = GTK_ACCESSIBLE (parent)->widget;
+  /*
+   * Widget has been deleted
+   */
+  if (widget == NULL)
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  tree_view = GTK_TREE_VIEW (widget);
+
+  cell = gail_tree_view_ref_focus_cell (tree_view);
+  if (cell)
+    {
+      GailTreeView *gail_tree_view;
+
+      gail_tree_view = GAIL_TREE_VIEW (parent);
+
+      if (cell != gail_tree_view->focus_cell)
+        {
+          if (gail_tree_view->focus_cell)
+            {
+              gail_cell_remove_state (GAIL_CELL (gail_tree_view->focus_cell), ATK_STATE_ACTIVE, FALSE); 
+              g_object_unref (gail_tree_view->focus_cell);
+            }
+          gail_tree_view->focus_cell = cell;
+
+          if (GTK_WIDGET_HAS_FOCUS (widget))
+            gail_cell_add_state (GAIL_CELL (cell), ATK_STATE_ACTIVE, FALSE);
+          g_signal_emit_by_name (parent,
+                                 "active-descendant-changed",
+                                 cell);
+        }
+      else
+        g_object_unref (cell);
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+model_row_changed (GtkTreeModel *tree_model,
+                   GtkTreePath  *path, 
+                   GtkTreeIter  *iter,
+                   gpointer     user_data)
+{
+  GtkTreeView *tree_view = GTK_TREE_VIEW(user_data);
+  GailTreeView *gailview;
+  GtkTreePath *cell_path;
+  GList *l;
+  GailTreeViewCellInfo *cell_info;
+  gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
+
+  /* Loop through our cached cells */
+  /* Must loop through them all */
+  for (l = gailview->cell_data; l; l = l->next)
+    {
+      cell_info = (GailTreeViewCellInfo *) l->data;
+      if (cell_info->in_use) 
+      {
+         cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+
+         if (cell_path != NULL)
+         {
+             if (path && gtk_tree_path_compare (cell_path, path) == 0)
+             {
+                 if (GAIL_IS_RENDERER_CELL (cell_info->cell))
+                 {
+                     update_cell_value (GAIL_RENDERER_CELL (cell_info->cell),
+                                        gailview, TRUE);
+                 }
+             }
+             gtk_tree_path_free (cell_path);
+         }
+      }
+    }
+  g_signal_emit_by_name (gailview, "visible-data-changed");
+}
+
+static void
+column_visibility_changed (GObject    *object,
+                           GParamSpec *pspec,
+                           gpointer   user_data)
+{
+  if (strcmp (pspec->name, "visible") == 0)
+    {
+      /*
+       * A column has been made visible or invisible
+       *
+       * We update our cache of cells and emit model_changed signal
+       */ 
+      GtkTreeView *tree_view = (GtkTreeView *)user_data;
+      GailTreeView *gailview;
+      GList *l;
+      GailTreeViewCellInfo *cell_info;
+      GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
+      GtkTreeViewColumn *tv_col;
+
+      gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
+);
+      g_signal_emit_by_name (gailview, "model_changed");
+
+      for (l = gailview->cell_data; l; l = l->next)
+        {
+          cell_info = (GailTreeViewCellInfo *) l->data;
+         if (cell_info->in_use) 
+         {
+             tv_col = cell_info->cell_col_ref;
+             if (tv_col == this_col)
+             {
+                 GtkTreePath *row_path;
+                 row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+                 if (GAIL_IS_RENDERER_CELL (cell_info->cell))
+                 {
+                     if (gtk_tree_view_column_get_visible (tv_col))
+                         set_cell_visibility (tree_view, 
+                                              cell_info->cell, 
+                                              tv_col, row_path, FALSE);
+                     else
+                     {
+                         gail_cell_remove_state (cell_info->cell, 
+                                                 ATK_STATE_VISIBLE, TRUE);
+                         gail_cell_remove_state (cell_info->cell, 
+                                                 ATK_STATE_SHOWING, TRUE);
+                     }
+                 }
+                 gtk_tree_path_free (row_path);
+             }
+         }
+        }
+    }
+}
+
+/*
+ * This is the signal handler for the "destroy" signal for a GtkTreeViewColumn
+ *
+ * We check whether we have stored column description or column header
+ * and if so we get rid of it.
+ */
+static void
+column_destroy (GtkObject *obj)
+{
+  GtkTreeViewColumn *tv_col = GTK_TREE_VIEW_COLUMN (obj);
+  AtkObject *header;
+  gchar *desc;
+
+  header = g_object_get_qdata (G_OBJECT (tv_col),
+                          quark_column_header_object);
+  if (header)
+    g_object_unref (header);
+  desc = g_object_get_qdata (G_OBJECT (tv_col),
+                           quark_column_desc_object);
+  g_free (desc); 
+}
+
+static void
+model_row_inserted (GtkTreeModel *tree_model,
+                    GtkTreePath  *path, 
+                    GtkTreeIter  *iter, 
+                    gpointer     user_data)
+{
+  GtkTreeView *tree_view = (GtkTreeView *)user_data;
+  GtkTreePath *path_copy;
+  AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+  GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
+  gint row, n_inserted, child_row;
+
+  if (gailview->idle_expand_id)
+    {
+      g_source_remove (gailview->idle_expand_id);
+      /* don't do this if the insertion precedes the idle path, since it will now be invalid */
+      if (path && gailview->idle_expand_path &&
+         (gtk_tree_path_compare (path, gailview->idle_expand_path) > 0))
+         set_expand_state (tree_view, tree_model, gailview, gailview->idle_expand_path, FALSE);
+      if (gailview->idle_expand_path) 
+         gtk_tree_path_free (gailview->idle_expand_path);
+      gailview->idle_expand_id = 0;
+    }
+  /* Check to see if row is visible */
+  row = get_row_from_tree_path (tree_view, path);
+
+ /*
+  * A row insert is not necessarily visible.  For example,
+  * a row can be draged & dropped into another row, which
+  * causes an insert on the model that isn't visible in the
+  * view.  Only generate a signal if the inserted row is
+  * visible.
+  */
+  if (row != -1)
+    {
+      GtkTreeIter iter;
+      gint n_cols, col;
+
+      gtk_tree_model_get_iter (tree_model, &iter, path);
+
+      /* Figure out number of visible children. */
+      if (gtk_tree_model_iter_has_child (tree_model, &iter))
+        {
+         /*
+          * By passing path into this function, we find the number of
+          * visible children of path.
+          */
+          n_inserted = 0;
+          iterate_thru_children (tree_view, tree_model,
+                                 path, NULL, &n_inserted, 0);
+
+          /* Must add one to include the row that is being added */
+          n_inserted++;
+        }
+      else
+      n_inserted = 1;
+
+      /* Set rows below the inserted row to ATK_STATE_STALE */
+      traverse_cells (gailview, path, TRUE, TRUE);
+
+      /* Generate row-inserted signal */
+      g_signal_emit_by_name (atk_obj, "row_inserted", row, n_inserted);
+
+      /* Generate children-changed signals */
+      n_cols = gail_tree_view_get_n_columns (ATK_TABLE (atk_obj));
+      for (child_row = row; child_row < (row + n_inserted); child_row++)
+        {
+          for (col = 0; col < n_cols; col++)
+            {
+             /*
+              * Pass NULL as the child object, i.e. 4th argument
+              */
+              g_signal_emit_by_name (atk_obj, "children_changed::add",
+                                    ((row * n_cols) + col), NULL, NULL);
+            }
+        }
+    }
+  else
+    {
+     /*
+      * The row has been inserted inside another row.  This can
+      * cause a row that previously couldn't be expanded to now
+      * be expandable.
+      */
+      path_copy = gtk_tree_path_copy (path);
+      gtk_tree_path_up (path_copy);
+      set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
+      gtk_tree_path_free (path_copy);
+    }
+}
+
+static void
+model_row_deleted (GtkTreeModel *tree_model,
+                   GtkTreePath  *path, 
+                   gpointer     user_data)
+{
+  GtkTreeView *tree_view;
+  GtkTreePath *path_copy;
+  AtkObject *atk_obj;
+  GailTreeView *gailview;
+  gint row;
+
+  tree_view = (GtkTreeView *)user_data;
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+  gailview = GAIL_TREE_VIEW (atk_obj);
+
+  if (gailview->idle_expand_id)
+    {
+      g_source_remove (gailview->idle_expand_id);
+      gtk_tree_path_free (gailview->idle_expand_path);
+      gailview->idle_expand_id = 0;
+    }
+  /* Check to see if row is visible */
+  clean_rows (gailview);
+
+  /* Set rows at or below the specified row to ATK_STATE_STALE */
+  traverse_cells (gailview, path, TRUE, TRUE);
+
+  /*
+   * If deleting a row with a depth > 1, then this may affect the
+   * expansion/contraction of its parent(s).  Make sure this is
+   * handled.
+   */
+  if (gtk_tree_path_get_depth (path) > 1)
+    {
+      path_copy = gtk_tree_path_copy (path);
+      gtk_tree_path_up (path_copy);
+      set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
+      gtk_tree_path_free (path_copy);
+    }
+  row = get_row_from_tree_path (tree_view, path);
+  /*
+   * If the row which is deleted is not visible because it is a child of
+   * a collapsed row then row will be -1
+   */
+  if (row > 0)
+    g_signal_emit_by_name (atk_obj, "row_deleted", row, 
+                           gailview->n_children_deleted + 1);
+  gailview->n_children_deleted = 0;
+}
+
+/* 
+ * This function gets called when a row is deleted or when rows are
+ * removed from the view due to a collapse event.  Note that the
+ * count is the number of visible *children* of the deleted row,
+ * so it does not include the row being deleted.
+ *
+ * As this function is called before the rows are removed we just note the
+ * number of rows and then deal with it when we get a notification that
+ * rows were deleted or collapsed.
+ */
+static void
+destroy_count_func (GtkTreeView *tree_view, 
+                    GtkTreePath *path,
+                    gint        count,
+                    gpointer    user_data)
+{
+  AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+  GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
+
+  gail_return_if_fail (gailview->n_children_deleted == 0);
+  gailview->n_children_deleted = count;
+}
+
+static void 
+model_rows_reordered (GtkTreeModel *tree_model,
+                      GtkTreePath  *path, 
+                      GtkTreeIter  *iter,
+                      gint         *new_order, 
+                      gpointer     user_data)
+{
+  GtkTreeView *tree_view = (GtkTreeView *)user_data;
+  AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+  GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
+
+  if (gailview->idle_expand_id)
+    {
+      g_source_remove (gailview->idle_expand_id);
+      gtk_tree_path_free (gailview->idle_expand_path);
+      gailview->idle_expand_id = 0;
+    }
+  traverse_cells (gailview, NULL, TRUE, FALSE);
+
+  g_signal_emit_by_name (atk_obj, "row_reordered");
+}
+
+static void
+adjustment_changed (GtkAdjustment *adjustment, 
+                    GtkTreeView   *tree_view)
+{
+  AtkObject *atk_obj;
+  GailTreeView* obj;
+
+  /*
+   * The scrollbars have changed
+   */
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+  obj = GAIL_TREE_VIEW (atk_obj);
+
+  traverse_cells (obj, NULL, FALSE, FALSE);
+}
+
+static void
+set_cell_visibility (GtkTreeView       *tree_view,
+                     GailCell          *cell,
+                     GtkTreeViewColumn *tv_col,
+                     GtkTreePath       *tree_path,
+                     gboolean          emit_signal)
+{
+  GdkRectangle cell_rect;
+
+  /* Get these three values in tree coords */
+  if (GTK_WIDGET_REALIZED (GTK_WIDGET (tree_view)))
+    gtk_tree_view_get_cell_area (tree_view, tree_path, tv_col, &cell_rect);
+  else
+    cell_rect.height = 0;
+
+  if (cell_rect.height > 0)
+    {
+      /*
+       * The height will be zero for a cell for which an antecedent is not 
+       * expanded
+       */
+      gail_cell_add_state (cell, ATK_STATE_VISIBLE, emit_signal);
+      if (is_cell_showing (tree_view, &cell_rect))
+        gail_cell_add_state (cell, ATK_STATE_SHOWING, emit_signal);
+      else
+        gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
+    }
+  else
+    {
+      gail_cell_remove_state (cell, ATK_STATE_VISIBLE, emit_signal);
+      gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
+    }
+}
+
+static gboolean 
+is_cell_showing (GtkTreeView   *tree_view,
+                 GdkRectangle  *cell_rect)
+{
+  GdkRectangle rect, *visible_rect;
+  GdkRectangle rect1, *tree_cell_rect;
+  gboolean is_showing;
+ /*
+  * A cell is considered "SHOWING" if any part of the cell is in the visible 
+  * area.  Other ways we could do this is by a cell's midpoint or if the cell 
+  * is fully in the visible range.  Since we have the cell_rect x,y,width,height
+  * of the cell, any of these is easy to compute.
+  *
+  * It is assumed that cell's rectangle is in widget coordinates so we
+  * must transform to tree cordinates.
+  */
+  visible_rect = &rect;
+  tree_cell_rect = &rect1;
+  tree_cell_rect->x = cell_rect->x;
+  tree_cell_rect->width = cell_rect->width;
+  tree_cell_rect->height = cell_rect->height;
+
+  gtk_tree_view_get_visible_rect (tree_view, visible_rect);
+  gtk_tree_view_widget_to_tree_coords (tree_view, cell_rect->x, cell_rect->y,
+                                       NULL, &(rect1.y));
+
+  if (((tree_cell_rect->x + tree_cell_rect->width) < visible_rect->x) ||
+     ((tree_cell_rect->y + tree_cell_rect->height) < (visible_rect->y)) ||
+     (tree_cell_rect->x > (visible_rect->x + visible_rect->width)) ||
+     (tree_cell_rect->y > (visible_rect->y + visible_rect->height)))
+    is_showing =  FALSE;
+  else
+    is_showing = TRUE;
+
+  return is_showing;
+}
+
+/* Misc Public */
+
+/*
+ * This function is called when a cell's flyweight is created in
+ * gail_tree_view_table_ref_at with emit_change_signal set to FALSE
+ * and in model_row_changed() on receipt of "row-changed" signal when 
+ * emit_change_signal is set to TRUE
+ */
+static gboolean
+update_cell_value (GailRendererCell *renderer_cell,
+                   GailTreeView     *gailview,
+                   gboolean         emit_change_signal)
+{
+  GailTreeViewCellInfo *cell_info;
+  GtkTreeView *tree_view;
+  GtkTreeModel *tree_model;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GList *renderers, *cur_renderer;
+  GParamSpec *spec;
+  GailRendererCellClass *gail_renderer_cell_class;
+  GtkCellRendererClass *gtk_cell_renderer_class;
+  GailCell *cell;
+  gchar **prop_list;
+  AtkObject *parent;
+  gboolean is_expander, is_expanded;
+  
+  gail_renderer_cell_class = GAIL_RENDERER_CELL_GET_CLASS (renderer_cell);
+  if (renderer_cell->renderer)
+    gtk_cell_renderer_class = GTK_CELL_RENDERER_GET_CLASS (renderer_cell->renderer);
+  else
+    gtk_cell_renderer_class = NULL;
+
+  prop_list = gail_renderer_cell_class->property_list;
+
+  cell = GAIL_CELL (renderer_cell);
+  cell_info = find_cell_info (gailview, cell, NULL, TRUE);
+  gail_return_val_if_fail (cell_info, FALSE);
+  gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
+  gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
+
+  if (emit_change_signal && cell_info->in_use)
+    {
+      tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
+      tree_model = gtk_tree_view_get_model (tree_view);
+      path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+      if (path == NULL)
+        return FALSE;
+
+      gtk_tree_model_get_iter (tree_model, &iter, path);
+      is_expander = FALSE;
+      is_expanded = FALSE;
+      if (gtk_tree_model_iter_has_child (tree_model, &iter))
+        {
+          GtkTreeViewColumn *expander_tv;
+
+          expander_tv = gtk_tree_view_get_expander_column (tree_view);
+          if (expander_tv == cell_info->cell_col_ref)
+            {
+              is_expander = TRUE;
+              is_expanded = gtk_tree_view_row_expanded (tree_view, path);
+            }
+        } 
+      gtk_tree_path_free (path);
+      gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
+                                  tree_model, &iter, is_expander, is_expanded);
+    }
+  renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
+  gail_return_val_if_fail (renderers, FALSE);
+
+  /*
+   * If the cell is in a container, it's index is used to find the renderer 
+   * in the list
+   */
+
+  /*
+   * Otherwise, we assume that the cell is represented by the first renderer 
+   * in the list
+   */
+
+  if (cell_info->in_use) {
+      parent = atk_object_get_parent (ATK_OBJECT (cell));
+      if (!ATK_IS_OBJECT (cell)) g_on_error_query (NULL);
+      if (GAIL_IS_CONTAINER_CELL (parent))
+         cur_renderer = g_list_nth (renderers, cell->index);
+      else
+         cur_renderer = renderers;
+  }
+  else {
+      return FALSE;
+  }
+  
+  gail_return_val_if_fail (cur_renderer != NULL, FALSE);
+
+  if (gtk_cell_renderer_class)
+    {
+      while (*prop_list)
+        {
+          spec = g_object_class_find_property
+                           (G_OBJECT_CLASS (gtk_cell_renderer_class), *prop_list);
+
+          if (spec != NULL)
+            {
+              GValue value = { 0, };
+
+              g_value_init (&value, spec->value_type);
+              g_object_get_property (cur_renderer->data, *prop_list, &value);
+              g_object_set_property (G_OBJECT (renderer_cell->renderer),
+                                     *prop_list, &value);
+              g_value_unset(&value);
+            }
+          else
+            g_warning ("Invalid property: %s\n", *prop_list);
+          prop_list++;
+        }
+    }
+  g_list_free (renderers);
+  return gail_renderer_cell_update_cache (renderer_cell, emit_change_signal);
+}
+
+static void 
+set_iter_nth_row (GtkTreeView *tree_view, 
+                  GtkTreeIter *iter, 
+                  gint        row)
+{
+  GtkTreeModel *tree_model;
+  
+  tree_model = gtk_tree_view_get_model (tree_view);
+  gtk_tree_model_get_iter_root (tree_model, iter);
+  iter = return_iter_nth_row (tree_view, tree_model, iter, 0 , row);
+}
+
+static gint 
+get_row_from_tree_path (GtkTreeView *tree_view,
+                        GtkTreePath *path)
+{
+  GtkTreeModel *tree_model;
+  GtkTreePath *root_tree;
+  gint row;
+
+  tree_model = gtk_tree_view_get_model (tree_view);
+
+  if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
+    row = gtk_tree_path_get_indices (path)[0];
+  else
+    {
+      root_tree = gtk_tree_path_new_root ();
+      row = 0;
+      iterate_thru_children (tree_view, tree_model, root_tree, path, &row, 0);
+      gtk_tree_path_free (root_tree);
+    }
+
+  return row;
+}
+
+/* Misc Private */
+
+/*
+ * Get the specified GtkTreeViewColumn in the GtkTreeView.
+ * Only visible columns are considered.
+ */
+static GtkTreeViewColumn* 
+get_column (GtkTreeView *tree_view, 
+            gint        in_col)
+{
+  GtkTreeViewColumn *tv_col;
+  gint n_cols = -1;
+  gint i = 0;
+  if (in_col < 0)
+    {
+       g_warning ("Request for invalid column %d\n", in_col);
+       return NULL;
+    }
+
+  tv_col = gtk_tree_view_get_column (tree_view, i);
+
+  while (tv_col != NULL)
+    {
+      if (gtk_tree_view_column_get_visible (tv_col)) 
+        n_cols++;
+      if (in_col == n_cols)
+        break;
+      tv_col = gtk_tree_view_get_column (tree_view, ++i);
+    }
+
+  if (in_col != n_cols)
+    {
+       g_warning ("Request for invalid column %d\n", in_col);
+       return NULL;
+    }
+  return tv_col;
+}
+
+static gint
+get_actual_column_number (GtkTreeView *tree_view,
+                          gint        visible_column)
+{
+  GtkTreeViewColumn *tv_col;
+  gint actual_column = 0;
+  gint visible_columns = -1;
+  /*
+   * This function calculates the column number which corresponds to the
+   * specified visible column number
+   */
+  tv_col = gtk_tree_view_get_column (tree_view, actual_column);
+
+  while (tv_col != NULL)
+    {
+      if (gtk_tree_view_column_get_visible (tv_col)) 
+        visible_columns++;
+      if (visible_columns == visible_column)
+        return actual_column;
+      tv_col = gtk_tree_view_get_column (tree_view, ++actual_column);
+    }
+  g_warning ("get_actual_column_number failed for %d\n", visible_column);
+  return -1;
+}
+
+static gint
+get_visible_column_number (GtkTreeView *tree_view,
+                           gint        actual_column)
+{
+  GtkTreeViewColumn *tv_col;
+  gint column = 0;
+  gint visible_columns = -1;
+  /*
+   * This function calculates the visible column number which corresponds to the
+   * specified actual column number
+   */
+  tv_col = gtk_tree_view_get_column (tree_view, column);
+
+  while (tv_col != NULL)
+    {
+      if (gtk_tree_view_column_get_visible (tv_col)) 
+        {
+          visible_columns++;
+          if (actual_column == column)
+            return visible_columns;
+        }
+      else
+        if (actual_column == column)
+          return -1;
+      tv_col = gtk_tree_view_get_column (tree_view, ++column);
+    }
+  g_warning ("get_visible_column_number failed for %d\n", actual_column);
+  return -1;
+}
+
+/**
+ * Helper recursive function that returns GtkTreeIter pointer to nth row.
+ **/
+static GtkTreeIter* 
+return_iter_nth_row(GtkTreeView  *tree_view,
+                    GtkTreeModel *tree_model, 
+                    GtkTreeIter  *iter, 
+                    gint         increment,
+                    gint         row)
+{
+  GtkTreePath *current_path = gtk_tree_model_get_path (tree_model, iter);
+  GtkTreeIter new_iter;
+  gboolean row_expanded;
+
+  if (increment == row) {
+    gtk_tree_path_free (current_path);
+    return iter;
+  }
+
+  row_expanded = gtk_tree_view_row_expanded (tree_view, current_path);
+  gtk_tree_path_free (current_path);
+
+  new_iter = *iter;
+  if ((row_expanded && gtk_tree_model_iter_children (tree_model, iter, &new_iter)) ||
+      (gtk_tree_model_iter_next (tree_model, iter)) ||
+      (gtk_tree_model_iter_parent (tree_model, iter, &new_iter) &&
+          (gtk_tree_model_iter_next (tree_model, iter))))
+    return return_iter_nth_row (tree_view, tree_model, iter,
+      ++increment, row);
+
+  return NULL;         
+}
+
+/**
+ * Recursively called until the row specified by orig is found.
+ *
+ * *count will be set to the visible row number of the child
+ * relative to the row that was initially passed in as tree_path.
+ *
+ * *count will be -1 if orig is not found as a child (a row that is
+ * not visible will not be found, e.g. if the row is inside a
+ * collapsed row).  If NULL is passed in as orig, *count will
+ * be a count of the visible children.
+ *
+ * NOTE: the value for depth must be 0 when this recursive function
+ * is initially called, or it may not function as expected.
+ **/
+static void 
+iterate_thru_children(GtkTreeView  *tree_view,
+                      GtkTreeModel *tree_model,
+                      GtkTreePath  *tree_path,
+                      GtkTreePath  *orig,
+                      gint         *count,
+                      gint         depth)
+{
+  GtkTreeIter iter;
+
+  if (!gtk_tree_model_get_iter (tree_model, &iter, tree_path))
+    return;
+
+  if (tree_path && orig && !gtk_tree_path_compare (tree_path, orig)) 
+    /* Found it! */
+    return;
+
+  if (tree_path && orig && gtk_tree_path_compare (tree_path, orig) > 0)
+    {
+      /* Past it, so return -1 */
+      *count = -1;
+      return;
+    }
+  else if (gtk_tree_view_row_expanded (tree_view, tree_path) && 
+    gtk_tree_model_iter_has_child (tree_model, &iter)) 
+    {
+      (*count)++;
+      gtk_tree_path_append_index (tree_path, 0);
+      iterate_thru_children (tree_view, tree_model, tree_path,
+                             orig, count, (depth + 1));
+      return;
+    }
+  else if (gtk_tree_model_iter_next (tree_model, &iter)) 
+    {
+      (*count)++;
+      tree_path = gtk_tree_model_get_path (tree_model, &iter);
+       if (tree_path)
+         {
+           iterate_thru_children (tree_view, tree_model, tree_path,
+                                 orig, count, depth); 
+           gtk_tree_path_free (tree_path);
+         }
+      return;
+  }
+  else if (gtk_tree_path_up (tree_path))
+    {
+      GtkTreeIter temp_iter;
+      gboolean exit_loop = FALSE;
+      gint new_depth = depth - 1;
+
+      (*count)++;
+
+     /*
+      * Make sure that we back up until we find a row
+      * where gtk_tree_path_next does not return NULL.
+      */
+      while (!exit_loop)
+        {
+          if (gtk_tree_path_get_depth (tree_path) == 0)
+              /* depth is now zero so */
+            return;
+          gtk_tree_path_next (tree_path);      
+
+          /* Verify that the next row is a valid row! */
+          exit_loop = gtk_tree_model_get_iter (tree_model, &temp_iter, tree_path);
+
+          if (!exit_loop)
+            {
+              /* Keep going up until we find a row that has a valid next */
+              if (gtk_tree_path_get_depth(tree_path) > 1)
+                {
+                  new_depth--;
+                  gtk_tree_path_up (tree_path);
+                }
+              else
+                {
+                 /*
+                  * If depth is 1 and gtk_tree_model_get_iter returns FALSE,
+                  * then we are at the last row, so just return.
+                  */ 
+                  if (orig != NULL)
+                    *count = -1;
+
+                  return;
+                }
+            }
+        }
+
+     /*
+      * This guarantees that we will stop when we hit the end of the
+      * children.
+      */
+      if (new_depth < 0)
+        return;
+
+      iterate_thru_children (tree_view, tree_model, tree_path,
+                            orig, count, new_depth);
+      return;
+    }
+
+ /*
+  * If it gets here, then the path wasn't found.  Situations
+  * that would cause this would be if the path passed in is
+  * invalid or contained within the last row, but not visible
+  * because the last row is not expanded.  If NULL was passed
+  * in then a row count is desired, so only set count to -1
+  * if orig is not NULL.
+  */
+  if (orig != NULL)
+    *count = -1;
+
+  return;
+}
+
+static void
+clean_cell_info (GailTreeView *gailview,
+                 GList        *list) 
+{
+  GailTreeViewCellInfo *cell_info;
+  GObject *obj;
+
+  g_assert (GAIL_IS_TREE_VIEW (gailview));
+
+  cell_info = list->data;
+
+  if (cell_info->in_use) {
+      obj = G_OBJECT (cell_info->cell);
+      
+      gail_cell_add_state (cell_info->cell, ATK_STATE_DEFUNCT, TRUE);
+      g_object_weak_unref (obj, (GWeakNotify) cell_destroyed, cell_info);
+      cell_info->in_use = FALSE; 
+      if (!gailview->garbage_collection_pending) {
+         gailview->garbage_collection_pending = TRUE;
+         gailview->idle_garbage_collect_id = 
+             g_idle_add (idle_garbage_collect_cell_data, gailview);
+      }
+  }
+}
+
+static void 
+clean_rows (GailTreeView *gailview)
+{
+  GArray *array;
+
+  /* Clean GailTreeViewRowInfo data */
+
+  array = gailview->row_data;
+  if (array != NULL)
+    {
+      GailTreeViewRowInfo *row_info;
+      GtkTreePath *row_path;
+      gint i;
+
+     /*
+      * Loop backwards so that calls to free_row_info
+      * do not affect the index numbers 
+      */
+      for (i = (array->len - 1); i >= 0; i  --)
+        {
+          row_info = g_array_index (array, GailTreeViewRowInfo*, i);
+          row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
+
+          /* Remove any rows that have become invalid */
+          if (row_path == NULL)
+            free_row_info (array, i, TRUE);
+          else
+            gtk_tree_path_free (row_path);
+        }
+    }
+
+  /* Clean GailTreeViewCellInfo data */
+
+  if (gailview->cell_data != NULL)
+    {
+      GailTreeViewCellInfo *cell_info;
+      GtkTreePath *row_path;
+      GList *cur_list;
+      GList *temp_list;
+
+      temp_list = gailview->cell_data;
+
+      /* Must loop through them all */
+      while (temp_list != NULL)
+        {
+          cur_list = temp_list;
+          cell_info = temp_list->data;
+          temp_list = temp_list->next;
+          row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+
+         /*
+          * If the cell has become invalid because the row has been removed, 
+          * then set the cell's state to ATK_STATE_DEFUNCT and remove the cell
+          * from gailview->cell_data.  If row_path is NULL then the row has
+          * been removed.
+          */
+          if (row_path == NULL)
+            {
+              clean_cell_info (gailview, cur_list);
+            }
+          else
+            {
+              gtk_tree_path_free (row_path);
+            }
+        }
+    }
+}
+
+static void 
+clean_cols (GailTreeView      *gailview,
+            GtkTreeViewColumn *tv_col)
+{
+  /* Clean GailTreeViewCellInfo data */
+
+  if (gailview->cell_data != NULL)
+    {
+      GailTreeViewCellInfo *cell_info;
+      GList *cur_list, *temp_list;
+
+      temp_list = gailview->cell_data;
+
+      while (temp_list != NULL)
+        {
+          cur_list = temp_list;
+          cell_info = temp_list->data;
+          temp_list = temp_list->next;
+
+         /*
+          * If the cell has become invalid because the column tv_col
+          * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
+          * and remove the cell from gailview->cell_data. 
+          */
+          if (cell_info->cell_col_ref == tv_col)
+            {
+              clean_cell_info (gailview, cur_list);
+            }
+        }
+    }
+}
+
+
+static gboolean
+idle_garbage_collect_cell_data (gpointer data)
+{
+      GailTreeView *tree_view;
+
+      GDK_THREADS_ENTER ();
+      g_assert (GAIL_IS_TREE_VIEW (data));
+      tree_view = (GailTreeView *)data;
+
+      /* this is the idle handler (only one instance allowed), so
+       * we can safely delete it.
+       */
+      tree_view->garbage_collection_pending = FALSE;
+      tree_view->idle_garbage_collect_id = 0;
+
+      tree_view->garbage_collection_pending = garbage_collect_cell_data (data);
+
+      GDK_THREADS_LEAVE ();
+
+      /* N.B.: if for some reason another handler has re-enterantly been queued 
+       * while this handler was being serviced, it has its own gsource, therefore this handler
+       * should always return FALSE.
+       */
+      return FALSE; 
+}
+
+static gboolean
+garbage_collect_cell_data (gpointer data)
+{
+      GailTreeView *tree_view;
+      GList *temp_list;
+      GailTreeViewCellInfo *cell_info;
+
+      g_assert (GAIL_IS_TREE_VIEW (data));
+      tree_view = (GailTreeView *)data;
+      temp_list = g_list_copy (tree_view->cell_data);
+
+      tree_view->garbage_collection_pending = FALSE;
+      if (tree_view->idle_garbage_collect_id != 0) 
+      {
+         g_source_remove (tree_view->idle_garbage_collect_id);
+         tree_view->idle_garbage_collect_id = 0;
+      }
+
+      /* Must loop through them all */
+      while (temp_list != NULL)
+      {
+          cell_info = temp_list->data;
+         if (!cell_info->in_use)
+         {
+             /* g_object_unref (cell_info->cell); */
+             tree_view->cell_data = g_list_remove (tree_view->cell_data, 
+                                                   cell_info);
+             if (cell_info->cell_row_ref)
+                 gtk_tree_row_reference_free (cell_info->cell_row_ref);
+             g_free (cell_info);
+         }
+          temp_list = temp_list->next;
+      }
+      g_list_free (temp_list);
+
+      return tree_view->garbage_collection_pending;
+}
+
+/**
+ * If tree_path is passed in as NULL, then all cells are acted on.
+ * Otherwise, just act on those cells that are on a row greater than 
+ * the specified tree_path. If inc_row is passed in as TRUE, then rows 
+ * greater and equal to the specified tree_path are acted on.
+ *
+ * if set_stale is set the ATK_STATE_STALE is set on cells which are to be
+ * acted on. 
+ *
+ * The function set_cell_visibility() is called on all cells to be
+ * acted on to update the visibility of the cell.
+ **/
+static void 
+traverse_cells (GailTreeView *tree_view,
+                GtkTreePath  *tree_path,
+                gboolean     set_stale,
+                gboolean     inc_row)
+{
+  if (tree_view->cell_data != NULL)
+    {
+      GailTreeViewCellInfo *cell_info;
+      GtkTreeView *gtk_tree_view;
+      GList *temp_list;
+      GtkWidget *widget;
+
+      g_assert (GTK_IS_ACCESSIBLE (tree_view));
+
+      widget = GTK_ACCESSIBLE (tree_view)->widget;
+      if (!widget)
+        /* Widget is being deleted */
+        return;
+
+      gtk_tree_view = GTK_TREE_VIEW (widget);
+      temp_list = tree_view->cell_data;
+
+      /* Must loop through them all */
+      while (temp_list != NULL)
+        {
+          GtkTreePath *row_path;
+          gboolean act_on_cell;
+
+          cell_info = temp_list->data;
+          temp_list = temp_list->next;
+
+         if (cell_info->in_use)
+         {
+             row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+             g_assert (row_path != NULL);
+             if (tree_path == NULL)
+                 act_on_cell = TRUE;
+             else 
+             {
+                 gint comparison;
+                 
+                 comparison =  gtk_tree_path_compare (row_path, tree_path);
+                 if ((comparison > 0) ||
+                     (comparison == 0 && inc_row))
+                     act_on_cell = TRUE;
+                 else
+                     act_on_cell = FALSE;
+             }
+             if (!cell_info->in_use) g_warning ("warning: cell info destroyed during traversal");
+             if (act_on_cell && cell_info->in_use)
+             {
+                 if (set_stale)
+                     gail_cell_add_state (cell_info->cell, ATK_STATE_STALE, TRUE);
+                 set_cell_visibility (gtk_tree_view,
+                                      cell_info->cell,
+                                      cell_info->cell_col_ref,
+                                      row_path, TRUE);
+             }
+             gtk_tree_path_free (row_path);
+         }
+       }
+    }
+  g_signal_emit_by_name (tree_view, "visible-data-changed");
+}
+
+static void
+free_row_info (GArray   *array,
+               gint     array_idx,
+               gboolean shift)
+{
+  GailTreeViewRowInfo* obj;
+
+  obj = g_array_index (array, GailTreeViewRowInfo*, array_idx);
+
+  g_free (obj->description);
+  if (obj->row_ref != NULL)
+    gtk_tree_row_reference_free (obj->row_ref);
+  if (obj->header)
+    g_object_unref (obj->header);
+  g_free (obj);
+
+  if (shift)
+    g_array_remove_index (array, array_idx);
+}
+
+/*
+ * If the tree_path passed in has children, then
+ * ATK_STATE_EXPANDABLE is set.  If the row is expanded
+ * ATK_STATE_EXPANDED is turned on.  If the row is 
+ * collapsed, then ATK_STATE_EXPANDED is removed.
+ * 
+ * If the tree_path passed in has no children, then
+ * ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED are removed.
+ *
+ * If set_on_ancestor is TRUE, then this function will also
+ * update all cells that are ancestors of the tree_path.
+ */
+static void
+set_expand_state (GtkTreeView  *tree_view,
+                  GtkTreeModel *tree_model,
+                  GailTreeView *gailview,
+                  GtkTreePath  *tree_path,
+                  gboolean     set_on_ancestor)
+{
+  if (gailview->cell_data != NULL)
+    {
+      GtkTreeViewColumn *expander_tv;
+      GailTreeViewCellInfo *cell_info;
+      GList *temp_list;
+      GtkTreePath *cell_path;
+      GtkTreeIter iter;
+      gboolean found;
+
+      temp_list = gailview->cell_data;
+
+      while (temp_list != NULL)
+        {
+          cell_info = temp_list->data;
+          temp_list = temp_list->next;
+         if (cell_info->in_use)
+         {
+             cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+             found = FALSE;
+             
+             if (cell_path != NULL)
+             {
+                 GailCell *cell  = GAIL_CELL (cell_info->cell);
+                 
+                 expander_tv = gtk_tree_view_get_expander_column (tree_view);
+                 
+                 /*
+                  * Only set state for the cell that is in the column with the
+                  * expander toggle
+                  */
+                 if (expander_tv == cell_info->cell_col_ref)
+                 {
+                     if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
+                         found = TRUE;
+                     else if (set_on_ancestor &&
+                              gtk_tree_path_get_depth (cell_path) <
+                              gtk_tree_path_get_depth (tree_path) && 
+                              gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
+                         /* Only set if set_on_ancestor was passed in as TRUE */
+                         found = TRUE;
+                 }
+                 
+                 /*
+                  * Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
+                  * for ancestors and found cells.
+                  */
+                 if (found)
+                 {
+                     /*
+                      * Must check against cell_path since cell_path
+                      * can be equal to or an ancestor of tree_path.
+                      */
+                     gtk_tree_model_get_iter (tree_model, &iter, cell_path);
+                     
+                     /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
+                     if (gtk_tree_model_iter_has_child (tree_model, &iter)) 
+                     {
+                         set_cell_expandable (cell);
+                         
+                         if (gtk_tree_view_row_expanded (tree_view, cell_path))
+                             gail_cell_add_state (cell, ATK_STATE_EXPANDED, TRUE);
+                         else
+                             gail_cell_remove_state (cell, 
+                                                     ATK_STATE_EXPANDED, TRUE);
+                     }
+                     else
+                     {
+                         gail_cell_remove_state (cell, 
+                                                 ATK_STATE_EXPANDED, TRUE);
+                         if (gail_cell_remove_state (cell,
+                                                     ATK_STATE_EXPANDABLE, TRUE))
+                             /* The state may have been propagated to the container cell */
+                             if (!GAIL_IS_CONTAINER_CELL (cell))
+                                 gail_cell_remove_action_by_name (cell,
+                                                                  "expand or contract");
+                     }
+                     
+                     /*
+                      * We assume that each cell in the cache once and
+                      * a container cell is before its child cells so we are 
+                      * finished if set_on_ancestor is not set to TRUE.
+                      */
+                     if (!set_on_ancestor)
+                         break;
+                 }
+             }
+             gtk_tree_path_free (cell_path);
+         }
+       }
+    }
+}
+
+
+static void
+add_cell_actions (GailCell *cell,
+                  gboolean editable)
+{
+  if (GAIL_IS_BOOLEAN_CELL (cell))
+    gail_cell_add_action (cell,
+       "toggle",
+       "toggles the cell", /* action description */
+       NULL,
+       toggle_cell_toggled);
+  if (editable)
+    gail_cell_add_action (cell,
+       "edit",
+       "creates a widget in which the contents of the cell can be edited", 
+       NULL,
+       edit_cell);
+  gail_cell_add_action (cell,
+       "activate",
+       "activate the cell", 
+       NULL,
+       activate_cell);
+}
+
+static void
+toggle_cell_expanded (GailCell *cell)
+{
+  GailTreeViewCellInfo *cell_info;
+  GtkTreeView *tree_view;
+  GtkTreePath *path;
+  AtkObject *parent;
+  AtkStateSet *stateset;
+  
+  parent = atk_object_get_parent (ATK_OBJECT (cell));
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    parent = atk_object_get_parent (parent);
+
+  cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+  gail_return_if_fail (cell_info);
+  gail_return_if_fail (cell_info->cell_col_ref);
+  gail_return_if_fail (cell_info->cell_row_ref);
+
+  tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
+  path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+  gail_return_if_fail (path);
+
+  stateset = atk_object_ref_state_set (ATK_OBJECT (cell));
+  if (atk_state_set_contains_state (stateset, ATK_STATE_EXPANDED))
+    gtk_tree_view_collapse_row (tree_view, path);
+  else
+    gtk_tree_view_expand_row (tree_view, path, TRUE);
+  g_object_unref (stateset);
+  gtk_tree_path_free (path);
+  return;
+}
+
+static void
+toggle_cell_toggled (GailCell *cell)
+{
+  GailTreeViewCellInfo *cell_info;
+  GtkTreeView *tree_view;
+  GtkTreePath *path;
+  gchar *pathstring;
+  GList *renderers, *cur_renderer;
+  AtkObject *parent;
+  gboolean is_container_cell = FALSE;
+
+  parent = atk_object_get_parent (ATK_OBJECT (cell));
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    {
+      is_container_cell = TRUE;
+      parent = atk_object_get_parent (parent);
+    }
+
+  cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+  gail_return_if_fail (cell_info);
+  gail_return_if_fail (cell_info->cell_col_ref);
+  gail_return_if_fail (cell_info->cell_row_ref);
+
+  tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
+  path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+  gail_return_if_fail (path);
+  pathstring = gtk_tree_path_to_string (path);
+
+  renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
+  gail_return_if_fail (renderers);
+
+  /* 
+   * if the cell is in a container, it's index is used to find the 
+   * renderer in the list
+   */
+
+  if (is_container_cell)
+    cur_renderer = g_list_nth (renderers, cell->index);
+  else
+  /*
+   * Otherwise, we assume that the cell is represented by the first 
+   * renderer in the list 
+   */
+    cur_renderer = renderers;
+
+  gail_return_if_fail (cur_renderer);
+
+  g_signal_emit_by_name (cur_renderer->data, "toggled", pathstring);
+  g_list_free (renderers);
+  g_free (pathstring);
+  gtk_tree_path_free (path);
+  return;
+}
+
+static void
+edit_cell (GailCell *cell)
+{
+  GailTreeViewCellInfo *cell_info;
+  GtkTreeView *tree_view;
+  GtkTreePath *path;
+  AtkObject *parent;
+  gboolean is_container_cell = FALSE;
+
+  editing = TRUE;
+  parent = atk_object_get_parent (ATK_OBJECT (cell));
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    {
+      is_container_cell = TRUE;
+      parent = atk_object_get_parent (parent);
+    }
+
+  cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+  gail_return_if_fail (cell_info);
+  gail_return_if_fail (cell_info->cell_col_ref);
+  gail_return_if_fail (cell_info->cell_row_ref);
+
+  tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
+  path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+  gail_return_if_fail (path);
+  gtk_tree_view_set_cursor (tree_view, path, cell_info->cell_col_ref, TRUE);
+  gtk_tree_path_free (path);
+  return;
+}
+
+static void
+activate_cell (GailCell *cell)
+{
+  GailTreeViewCellInfo *cell_info;
+  GtkTreeView *tree_view;
+  GtkTreePath *path;
+  AtkObject *parent;
+  gboolean is_container_cell = FALSE;
+
+  editing = TRUE;
+  parent = atk_object_get_parent (ATK_OBJECT (cell));
+  if (GAIL_IS_CONTAINER_CELL (parent))
+    {
+      is_container_cell = TRUE;
+      parent = atk_object_get_parent (parent);
+    }
+
+  cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+  gail_return_if_fail (cell_info);
+  gail_return_if_fail (cell_info->cell_col_ref);
+  gail_return_if_fail (cell_info->cell_row_ref);
+
+  tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
+  path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+  gail_return_if_fail (path);
+  gtk_tree_view_row_activated (tree_view, path, cell_info->cell_col_ref);
+  gtk_tree_path_free (path);
+  return;
+}
+
+static void
+cell_destroyed (gpointer data)
+{
+  GailTreeViewCellInfo *cell_info = data;
+
+  gail_return_if_fail (cell_info);
+  if (cell_info->in_use) {
+      cell_info->in_use = FALSE;
+
+      g_assert (GAIL_IS_TREE_VIEW (cell_info->view));
+      if (!cell_info->view->garbage_collection_pending) {
+         cell_info->view->garbage_collection_pending = TRUE;
+         cell_info->view->idle_garbage_collect_id =
+           g_idle_add (idle_garbage_collect_cell_data, cell_info->view);
+      }
+  }
+}
+
+#if 0
+static void
+cell_info_remove (GailTreeView *tree_view, 
+                  GailCell     *cell)
+{
+  GailTreeViewCellInfo *info;
+  GList *temp_list;
+
+  info = find_cell_info (tree_view, cell, &temp_list, FALSE);
+  if (info)
+    {
+      info->in_use = FALSE;
+      return;
+    }
+  g_warning ("No cell removed in cell_info_remove\n");
+}
+#endif
+
+static void
+cell_info_get_index (GtkTreeView            *tree_view, 
+                     GailTreeViewCellInfo   *info,
+                     gint                   *index)
+{
+  GtkTreePath *path;
+  gint column_number;
+
+  path = gtk_tree_row_reference_get_path (info->cell_row_ref);
+  gail_return_if_fail (path);
+
+  column_number = get_column_number (tree_view, info->cell_col_ref, FALSE);
+  *index = get_index (tree_view, path, column_number);
+  gtk_tree_path_free (path);
+}
+
+static void
+cell_info_new (GailTreeView      *gailview, 
+               GtkTreeModel      *tree_model, 
+               GtkTreePath       *path,
+               GtkTreeViewColumn *tv_col,
+               GailCell          *cell )
+{
+  GailTreeViewCellInfo *cell_info;
+
+  g_assert (GAIL_IS_TREE_VIEW (gailview));
+
+  cell_info = g_new (GailTreeViewCellInfo, 1);
+  cell_info->cell_row_ref = gtk_tree_row_reference_new (tree_model, path);
+
+  cell_info->cell_col_ref = tv_col;
+  cell_info->cell = cell;
+  cell_info->in_use = TRUE; /* if we've created it, assume it's in use */
+  cell_info->view = gailview;
+  gailview->cell_data = g_list_append (gailview->cell_data, cell_info);
+      
+  /* Setup weak reference notification */
+
+  g_object_weak_ref (G_OBJECT (cell),
+                     (GWeakNotify) cell_destroyed,
+                     cell_info);
+}
+
+static GailCell*
+find_cell (GailTreeView *gailview, 
+           gint         index)
+{
+  GailTreeViewCellInfo *info;
+  GtkTreeView *tree_view;
+  GList *cell_list;
+  GList *l;
+  gint real_index;
+  gboolean needs_cleaning = FALSE;
+  GailCell *retval = NULL;
+
+  tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
+  cell_list = gailview->cell_data;
+
+  for (l = cell_list; l; l = l->next)
+    {
+      info = (GailTreeViewCellInfo *) (l->data);
+      if (info->in_use)
+      {
+         cell_info_get_index (tree_view, info, &real_index);
+         if (index == real_index)
+         {
+             retval =  info->cell;
+             break;
+         }
+      }
+      else
+      {
+         needs_cleaning = TRUE;
+      }
+    }
+  if (needs_cleaning)
+     garbage_collect_cell_data (gailview);
+
+  return retval;
+}
+
+static void
+refresh_cell_index (GailCell *cell)
+{
+  GailTreeViewCellInfo *info;
+  AtkObject *parent;
+  GtkTreeView *tree_view;
+  gint index;
+
+  parent = atk_object_get_parent (ATK_OBJECT (cell));
+  gail_return_if_fail (GAIL_IS_TREE_VIEW (parent));
+
+  tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
+
+  /* Find this cell in the GailTreeView's cache */
+
+  info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+  gail_return_if_fail (info);
+  
+  cell_info_get_index (tree_view, info, &index); 
+  cell->index = index;
+}
+
+static void
+get_selected_rows (GtkTreeModel *model,
+                   GtkTreePath  *path,
+                   GtkTreeIter  *iter,
+                   gpointer     data)
+{
+  GPtrArray *array = (GPtrArray *)data;
+
+  g_ptr_array_add (array, gtk_tree_path_copy (path));
+}
+
+static void
+connect_model_signals (GtkTreeView  *view,
+                       GailTreeView *gailview)
+{
+  GObject *obj;
+
+  obj = G_OBJECT (gailview->tree_model);
+  g_signal_connect_data (obj, "row-changed",
+                         (GCallback) model_row_changed, view, NULL, 0);
+  g_signal_connect_data (obj, "row-inserted",
+                         (GCallback) model_row_inserted, view, NULL, 
+                         G_CONNECT_AFTER);
+  g_signal_connect_data (obj, "row-deleted",
+                         (GCallback) model_row_deleted, view, NULL, 
+                         G_CONNECT_AFTER);
+  g_signal_connect_data (obj, "rows-reordered",
+                         (GCallback) model_rows_reordered, view, NULL, 
+                         G_CONNECT_AFTER);
+}
+
+static void
+disconnect_model_signals (GailTreeView *view) 
+{
+  GObject *obj;
+  GtkWidget *widget;
+
+  obj = G_OBJECT (view->tree_model);
+  widget = GTK_ACCESSIBLE (view)->widget;
+  g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_changed, widget);
+  g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_inserted, widget);
+  g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_deleted, widget);
+  g_signal_handlers_disconnect_by_func (obj, (gpointer) model_rows_reordered, widget);
+}
+
+static void
+clear_cached_data (GailTreeView  *view)
+{
+  GList *temp_list;
+
+  if (view->row_data)
+    {
+      GArray *array = view->row_data;
+      gint i;
+
+     /*
+      * Since the third argument to free_row_info is FALSE, we don't remove 
+      * the element.  Therefore it is safe to loop forward.
+      */
+      for (i = 0; i < array->len; i++)
+        free_row_info (array, i, FALSE);
+
+      g_array_free (array, TRUE);
+
+      view->row_data = NULL;
+    }
+
+  if (view->cell_data)
+    {
+      /* Must loop through them all */
+      for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
+        {
+           clean_cell_info (view, temp_list);
+        }
+    }
+  garbage_collect_cell_data (view);
+  if (view->cell_data)
+      g_list_free (view->cell_data);
+  
+  view->cell_data = NULL;
+}
+
+/*
+ * Returns the column number of the specified GtkTreeViewColumn
+ *
+ * If visible is set, the value returned will be the visible column number, 
+ * i.e. suitable for use in AtkTable function. If visible is not set, the
+ * value returned is the actual column number, which is suitable for use in 
+ * getting an index value.
+ */
+static gint
+get_column_number (GtkTreeView       *tree_view,
+                   GtkTreeViewColumn *column,
+                   gboolean          visible)
+{
+  GList *temp_list, *column_list;
+  GtkTreeViewColumn *tv_column;
+  gint ret_val;
+
+  column_list = gtk_tree_view_get_columns (tree_view);
+  ret_val = 0;
+  for (temp_list = column_list; temp_list; temp_list = temp_list->next)
+    {
+      tv_column = GTK_TREE_VIEW_COLUMN (temp_list->data);
+      if (tv_column == column)
+        break;
+      if (!visible || gtk_tree_view_column_get_visible (tv_column))
+        ret_val++;
+    }
+  if (temp_list == NULL)
+    {
+      ret_val = -1;
+    }
+  g_list_free (column_list);
+  return ret_val;
+} 
+
+static gint
+get_index (GtkTreeView       *tree_view,
+           GtkTreePath       *path,
+           gint              actual_column)
+{
+  gint depth = 0;
+  gint index = 1;
+  gint *indices = NULL;
+
+
+  if (path)
+    {
+      depth = gtk_tree_path_get_depth (path);
+      indices = gtk_tree_path_get_indices (path);
+    }
+
+  if (depth > 1)
+    {
+      GtkTreePath *copy_path;
+      GtkTreeModel *model;
+
+      model = gtk_tree_view_get_model (tree_view);
+      copy_path = gtk_tree_path_copy (path);
+      gtk_tree_path_up (copy_path);
+      count_rows (model, NULL, copy_path, &index, 0, depth);
+      gtk_tree_path_free (copy_path);
+    }
+
+  if (path)
+    index += indices[depth-1];
+  index *= get_n_actual_columns (tree_view);
+  index +=  actual_column;
+  return index;
+}
+
+/*
+ * The function count_rows counts the number of rows starting at iter and ending
+ * at end_path. The value of level is the depth of iter and the value of depth
+ * is the depth of end_path. Rows at depth before end_path are counted.
+ * This functions counts rows which are not visible because an ancestor is 
+ * collapsed.
+ */
+static void 
+count_rows (GtkTreeModel *model,
+            GtkTreeIter *iter,
+            GtkTreePath *end_path,
+            gint        *count,
+            gint        level,
+            gint        depth)
+{
+  GtkTreeIter child_iter;
+  
+  if (!model) return;
+
+  level++;
+
+  *count += gtk_tree_model_iter_n_children (model, iter);
+
+#if 0
+  g_print ("count_rows : %d level: %d depth: %d\n", *count, level, depth);
+  if (iter != NULL)
+    g_print ("path: %s\n",
+            gtk_tree_path_to_string (gtk_tree_model_get_path (model, iter)));
+#endif
+
+  if (level >= depth)
+    return;
+
+  if (gtk_tree_model_iter_children (model, &child_iter, iter))
+    {
+      gboolean ret_val = TRUE;
+
+      while (ret_val)
+        {
+          if (level == depth - 1)
+            {
+              GtkTreePath *iter_path; 
+              gboolean finished = FALSE;
+
+              iter_path = gtk_tree_model_get_path (model, &child_iter);
+              if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
+                finished = TRUE;
+              gtk_tree_path_free (iter_path);
+              if (finished)
+                break;
+            }
+          if (gtk_tree_model_iter_has_child (model, &child_iter))
+            count_rows (model, &child_iter, end_path, count, level, depth);
+          ret_val = gtk_tree_model_iter_next (model, &child_iter);
+        }
+    }
+}
+
+/*
+ * Find the next node, which has children, at the specified depth below
+ * the specified iter. The level is the depth of the current iter.
+ * The position of the node is returned in path and the return value of TRUE 
+ * means that a node was found.
+ */
+
+gboolean get_next_node_with_child_at_depth (GtkTreeModel *model,
+                                            GtkTreeIter  *iter,
+                                            GtkTreePath  **path,
+                                            gint         level,
+                                            gint         depth)
+{
+  GtkTreeIter child_iter;
+
+  *path = NULL;
+
+  if (gtk_tree_model_iter_children (model, &child_iter, iter))
+    {
+      level++;
+
+      while (TRUE)
+        {
+          while (!gtk_tree_model_iter_has_child (model, &child_iter))
+            {
+              if (!gtk_tree_model_iter_next (model, &child_iter))
+                return FALSE;
+            }
+
+          if (level == depth)
+          /* We have found what we were looking for */
+            {
+              *path = gtk_tree_model_get_path (model, &child_iter);
+              return TRUE;
+            }
+
+          if (get_next_node_with_child_at_depth (model, &child_iter, path,
+                                                 level, depth))
+            return TRUE;
+
+          if (!gtk_tree_model_iter_next (model, &child_iter))
+            return FALSE;
+        }
+    }
+  return FALSE;
+}
+
+/*
+ * Find the next node, which has children, at the same depth as 
+ * the specified GtkTreePath.
+ */
+static gboolean 
+get_next_node_with_child (GtkTreeModel *model,
+                          GtkTreePath  *path,
+                          GtkTreePath  **return_path)
+{
+  GtkTreeIter iter;
+  gint depth;
+
+  gtk_tree_model_get_iter (model, &iter, path);
+
+  while (gtk_tree_model_iter_next (model, &iter))
+    {
+      if (gtk_tree_model_iter_has_child (model, &iter))
+        {
+          *return_path = gtk_tree_model_get_path (model, &iter);
+          return TRUE;
+        }
+    }
+  depth = gtk_tree_path_get_depth (path);
+  while (gtk_tree_path_up (path))
+    {
+      if (gtk_tree_path_get_depth (path) == 0)
+        break;
+
+      gtk_tree_model_get_iter (model, &iter, path);
+      while (gtk_tree_model_iter_next (model, &iter))
+        if (get_next_node_with_child_at_depth (model, &iter, return_path,
+                                         gtk_tree_path_get_depth (path), depth))
+          return TRUE;
+    }
+  *return_path = NULL;
+  return FALSE;
+}
+
+static gboolean 
+get_tree_path_from_row_index (GtkTreeModel *model,
+                              gint         row_index,
+                              GtkTreePath  **tree_path)
+{
+  GtkTreeIter iter;
+  gint count;
+  gint depth;
+
+  count = gtk_tree_model_iter_n_children (model, NULL);
+  if (count > row_index)
+    {
+      if (gtk_tree_model_iter_nth_child (model, &iter, NULL, row_index))
+        {
+          *tree_path = gtk_tree_model_get_path (model, &iter);
+          return TRUE;
+        }
+      else
+        return FALSE;
+    }
+  else
+     row_index -= count;
+
+  depth = 0;
+  while (TRUE)
+    {
+      depth++;
+
+      if (get_next_node_with_child_at_depth (model, NULL, tree_path, 0, depth))
+        {
+          GtkTreePath *next_path;
+
+          while (TRUE)
+            {
+              gtk_tree_model_get_iter (model, &iter, *tree_path);
+              count = gtk_tree_model_iter_n_children (model, &iter);
+              if (count > row_index)
+                {
+                  gtk_tree_path_append_index (*tree_path, row_index);
+                  return TRUE;
+                }
+              else
+                row_index -= count;
+
+              if (!get_next_node_with_child (model,  *tree_path, &next_path))
+                break;
+           
+              gtk_tree_path_free (*tree_path);
+              *tree_path = next_path;
+            }
+        }
+      else
+        {
+          g_warning ("Index value is too large\n");
+          gtk_tree_path_free (*tree_path);
+           *tree_path = NULL;
+          return FALSE;
+        }
+    }  
+}
+
+/*
+ * This function returns the number of rows, including those which are collapsed
+ */
+static gint
+get_row_count (GtkTreeModel *model)
+{
+  gint n_rows = 1;
+
+  count_rows (model, NULL, NULL, &n_rows, 0, G_MAXINT);
+
+  return n_rows;
+}
+
+static gboolean
+get_path_column_from_index (GtkTreeView       *tree_view,
+                            gint              index,
+                            GtkTreePath       **path,
+                            GtkTreeViewColumn **column)
+{
+  GtkTreeModel *tree_model;
+  gint n_columns;
+
+  tree_model = gtk_tree_view_get_model (tree_view);
+  n_columns = get_n_actual_columns (tree_view);
+  if (n_columns == 0)
+    return FALSE;
+  /* First row is the column headers */
+  index -= n_columns;
+  if (index < 0)
+    return FALSE;
+
+  if (path)
+    {
+      gint row_index;
+      gboolean retval;
+
+      row_index = index / n_columns;
+      retval = get_tree_path_from_row_index (tree_model, row_index, path);
+      gail_return_val_if_fail (retval, FALSE);
+      if (*path == NULL)
+        return FALSE;
+    }    
+
+  if (column)
+    {
+      *column = gtk_tree_view_get_column (tree_view, index % n_columns);
+      if (*column == NULL)
+        {
+         if (path)
+            gtk_tree_path_free (*path);
+          return FALSE;
+        }
+  }
+  return TRUE;
+}
+
+static void
+set_cell_expandable (GailCell *cell)
+{
+  if (gail_cell_add_state (cell, 
+                           ATK_STATE_EXPANDABLE,
+                           FALSE))
+    gail_cell_add_action (cell,
+                          "expand or contract", /* action name */
+                          "expands or contracts the row in the tree view "
+                          "containing this cell", /* description */
+                          NULL, /* Keybinding */
+                          toggle_cell_expanded);
+}
+
+static GailTreeViewCellInfo*
+find_cell_info (GailTreeView *view,
+                GailCell     *cell,
+                GList**      list,
+               gboolean     live_only)
+{
+  GList *temp_list;
+  GailTreeViewCellInfo *cell_info;
+
+  for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
+    {
+      cell_info = (GailTreeViewCellInfo *) temp_list->data;
+      if (cell_info->cell == cell && (!live_only || cell_info->in_use))
+        {
+          if (list)
+            *list = temp_list;
+          return cell_info;
+        }
+    }
+  return NULL;
+}
+
+static AtkObject *
+get_header_from_column (GtkTreeViewColumn *tv_col)
+{
+  AtkObject *rc;
+  GtkWidget *header_widget;
+
+  if (tv_col == NULL)
+    return NULL;
+
+  /* If the user has set a header object, use that */
+
+  rc = g_object_get_qdata (G_OBJECT (tv_col), quark_column_header_object);
+
+  if (rc == NULL)
+    {
+      /* If the user has not set a header object, grab the column */
+      /* header object defined by the GtkTreeView */
+
+      header_widget = tv_col->button;
+
+      if (header_widget)
+        {
+          rc = gtk_widget_get_accessible (header_widget);
+        }
+      else
+        rc = NULL;
+    }
+  return rc;
+}
diff --git a/modules/other/gail/gailtreeview.h b/modules/other/gail/gailtreeview.h
new file mode 100644 (file)
index 0000000..6f15331
--- /dev/null
@@ -0,0 +1,77 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_TREE_VIEW_H__
+#define __GAIL_TREE_VIEW_H__
+
+#include <gtk/gtk.h>
+#include <gail/gailcontainer.h>
+#include <gail/gailcell.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_TREE_VIEW                  (gail_tree_view_get_type ())
+#define GAIL_TREE_VIEW(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_TREE_VIEW, GailTreeView))
+#define GAIL_TREE_VIEW_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_TREE_VIEW, GailTreeViewClass))
+#define GAIL_IS_TREE_VIEW(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_TREE_VIEW))
+#define GAIL_IS_TREE_VIEW_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_TREE_VIEW))
+#define GAIL_TREE_VIEW_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_TREE_VIEW, GailTreeViewClass))
+
+typedef struct _GailTreeView              GailTreeView;
+typedef struct _GailTreeViewClass         GailTreeViewClass;
+
+struct _GailTreeView
+{
+  GailContainer parent;
+
+  AtkObject*   caption;
+  AtkObject*   summary;
+  gint          n_children_deleted;
+  GArray*       col_data;
+  GArray*      row_data;
+  GList*        cell_data;
+  GtkTreeModel  *tree_model;
+  AtkObject     *focus_cell;
+  GtkAdjustment *old_hadj;
+  GtkAdjustment *old_vadj;
+  guint         idle_expand_id;
+  guint         idle_garbage_collect_id;
+  GtkTreePath   *idle_expand_path;
+  gboolean      garbage_collection_pending;
+};
+
+GType gail_tree_view_get_type (void);
+
+struct _GailTreeViewClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_tree_view_new (GtkWidget *widget);
+
+AtkObject* gail_tree_view_ref_focus_cell (GtkTreeView *treeview);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_TREE_VIEW_H__ */
diff --git a/modules/other/gail/gailutil.c b/modules/other/gail/gailutil.c
new file mode 100644 (file)
index 0000000..bdfa625
--- /dev/null
@@ -0,0 +1,658 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include "gailutil.h"
+#include "gailtoplevel.h"
+#include "gailwindow.h"
+#include "gail-private-macros.h"
+
+static void            gail_util_class_init                    (GailUtilClass          *klass);
+
+/* atkutil.h */
+
+static guint           gail_util_add_global_event_listener     (GSignalEmissionHook    listener,
+                                                                const gchar*           event_type);
+static void            gail_util_remove_global_event_listener  (guint                  remove_listener);
+static guint           gail_util_add_key_event_listener        (AtkKeySnoopFunc        listener,
+                                                                gpointer               data);
+static void            gail_util_remove_key_event_listener     (guint                  remove_listener);
+static AtkObject*      gail_util_get_root                      (void);
+static G_CONST_RETURN gchar *gail_util_get_toolkit_name                (void);
+static G_CONST_RETURN gchar *gail_util_get_toolkit_version      (void);
+
+/* gailmisc/AtkMisc */
+static void            gail_misc_class_init                    (GailMiscClass          *klass);
+
+static void gail_misc_threads_enter (AtkMisc *misc);
+static void gail_misc_threads_leave (AtkMisc *misc);
+
+/* Misc */
+
+static void            _listener_info_destroy                  (gpointer               data);
+static guint            add_listener                           (GSignalEmissionHook    listener,
+                                                                 const gchar            *object_type,
+                                                                 const gchar            *signal,
+                                                                 const gchar            *hook_data);
+static void             do_window_event_initialization          (void);
+static gboolean         state_event_watcher                     (GSignalInvocationHint  *hint,
+                                                                 guint                  n_param_values,
+                                                                 const GValue           *param_values,
+                                                                 gpointer               data);
+static void             window_added                             (AtkObject             *atk_obj,
+                                                                  guint                 index,
+                                                                  AtkObject             *child);
+static void             window_removed                           (AtkObject             *atk_obj,
+                                                                  guint                 index,
+                                                                  AtkObject             *child);
+static gboolean        window_focus                              (GtkWidget             *widget,
+                                                                  GdkEventFocus         *event);
+static gboolean         configure_event_watcher                 (GSignalInvocationHint  *hint,
+                                                                 guint                  n_param_values,
+                                                                 const GValue           *param_values,
+                                                                 gpointer               data);
+                                                                  
+
+static AtkObject* root = NULL;
+static GHashTable *listener_list = NULL;
+static gint listener_idx = 1;
+static GHashTable *key_listener_list = NULL;
+static guint key_snooper_id = 0;
+
+typedef struct _GailUtilListenerInfo GailUtilListenerInfo;
+typedef struct _GailKeyEventInfo GailKeyEventInfo;
+
+struct _GailUtilListenerInfo
+{
+   gint key;
+   guint signal_id;
+   gulong hook_id;
+};
+
+struct _GailKeyEventInfo
+{
+  AtkKeyEventStruct *key_event;
+  gpointer func_data;
+};
+
+GType
+gail_util_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailUtilClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_util_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailUtil), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (ATK_TYPE_UTIL,
+                                   "GailUtil", &tinfo, 0);
+  }
+  return type;
+}
+
+static void     
+gail_util_class_init (GailUtilClass *klass)
+{
+  AtkUtilClass *atk_class;
+  gpointer data;
+
+  data = g_type_class_peek (ATK_TYPE_UTIL);
+  atk_class = ATK_UTIL_CLASS (data);
+
+  atk_class->add_global_event_listener =
+    gail_util_add_global_event_listener;
+  atk_class->remove_global_event_listener =
+    gail_util_remove_global_event_listener;
+  atk_class->add_key_event_listener =
+    gail_util_add_key_event_listener;
+  atk_class->remove_key_event_listener =
+    gail_util_remove_key_event_listener;
+  atk_class->get_root = gail_util_get_root;
+  atk_class->get_toolkit_name = gail_util_get_toolkit_name;
+  atk_class->get_toolkit_version = gail_util_get_toolkit_version;
+
+  listener_list = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, 
+     _listener_info_destroy);
+}
+
+static guint
+gail_util_add_global_event_listener (GSignalEmissionHook listener,
+                                    const gchar *event_type)
+{
+  guint rc = 0;
+  gchar **split_string;
+
+  split_string = g_strsplit (event_type, ":", 3);
+
+  if (split_string)
+    {
+      if (!strcmp ("window", split_string[0]))
+        {
+          static gboolean initialized = FALSE;
+
+          if (!initialized)
+            {
+              do_window_event_initialization ();
+              initialized = TRUE;
+            }
+          rc = add_listener (listener, "GailWindow", split_string[1], event_type);
+        }
+      else
+        {
+          rc = add_listener (listener, split_string[1], split_string[2], event_type);
+        }
+
+      g_strfreev (split_string);
+    }
+
+  return rc;
+}
+
+static void
+gail_util_remove_global_event_listener (guint remove_listener)
+{
+  if (remove_listener > 0)
+  {
+    GailUtilListenerInfo *listener_info;
+    gint tmp_idx = remove_listener;
+
+    listener_info = (GailUtilListenerInfo *)
+      g_hash_table_lookup(listener_list, &tmp_idx);
+
+    if (listener_info != NULL)
+      {
+        /* Hook id of 0 and signal id of 0 are invalid */
+        if (listener_info->hook_id != 0 && listener_info->signal_id != 0)
+          {
+            /* Remove the emission hook */
+            g_signal_remove_emission_hook(listener_info->signal_id,
+              listener_info->hook_id);
+
+            /* Remove the element from the hash */
+            g_hash_table_remove(listener_list, &tmp_idx);
+          }
+        else
+          {
+            g_warning("Invalid listener hook_id %ld or signal_id %d\n",
+              listener_info->hook_id, listener_info->signal_id);
+          }
+      }
+    else
+      {
+        g_warning("No listener with the specified listener id %d", 
+          remove_listener);
+      }
+  }
+  else
+  {
+    g_warning("Invalid listener_id %d", remove_listener);
+  }
+}
+
+
+static
+AtkKeyEventStruct *
+atk_key_event_from_gdk_event_key (GdkEventKey *key)
+{
+  AtkKeyEventStruct *event = g_new0 (AtkKeyEventStruct, 1);
+  switch (key->type)
+    {
+    case GDK_KEY_PRESS:
+           event->type = ATK_KEY_EVENT_PRESS;
+           break;
+    case GDK_KEY_RELEASE:
+           event->type = ATK_KEY_EVENT_RELEASE;
+           break;
+    default:
+           g_assert_not_reached ();
+           return NULL;
+    }
+  event->state = key->state;
+  event->keyval = key->keyval;
+  event->length = key->length;
+  if (key->string && key->string [0] && 
+      (key->state & GDK_CONTROL_MASK ||
+       g_unichar_isgraph (g_utf8_get_char (key->string))))
+    {
+      event->string = key->string;
+    }
+  else if (key->type == GDK_KEY_PRESS ||
+           key->type == GDK_KEY_RELEASE)
+    {
+      event->string = gdk_keyval_name (key->keyval);       
+    }
+  event->keycode = key->hardware_keycode;
+  event->timestamp = key->time;
+#ifdef GAIL_DEBUG  
+  g_print ("GailKey:\tsym %u\n\tmods %x\n\tcode %u\n\ttime %lx\n",
+          (unsigned int) event->keyval,
+          (unsigned int) event->state,
+          (unsigned int) event->keycode,
+          (unsigned long int) event->timestamp);
+#endif
+  return event;
+}
+
+static gboolean
+notify_hf (gpointer key, gpointer value, gpointer data)
+{
+  GailKeyEventInfo *info = (GailKeyEventInfo *) data;
+  return (*(AtkKeySnoopFunc) value) (info->key_event, info->func_data) ? TRUE : FALSE;
+}
+
+static void
+insert_hf (gpointer key, gpointer value, gpointer data)
+{
+  GHashTable *new_table = (GHashTable *) data;
+  g_hash_table_insert (new_table, key, value);
+}
+
+static gint
+gail_key_snooper (GtkWidget *the_widget, GdkEventKey *event, gpointer func_data)
+{
+  /* notify each AtkKeySnoopFunc in turn... */
+  GailKeyEventInfo *info = g_new0 (GailKeyEventInfo, 1);
+  gint consumed = 0;
+  if (key_listener_list)
+    {
+      GHashTable *new_hash = g_hash_table_new (NULL, NULL);        
+      g_hash_table_foreach (key_listener_list, insert_hf, new_hash);       
+      info->key_event = atk_key_event_from_gdk_event_key (event);
+      info->func_data = func_data;
+      consumed = g_hash_table_foreach_steal (new_hash, notify_hf, info);
+      g_hash_table_destroy (new_hash);
+    }
+  g_free (info->key_event);
+  g_free (info);
+  return (consumed ? 1 : 0);
+}
+
+static guint
+gail_util_add_key_event_listener (AtkKeySnoopFunc  listener,
+                                 gpointer         data)
+{
+  static guint key=0;
+  if (!key_listener_list)
+  {
+    key_listener_list = g_hash_table_new (NULL, NULL);   
+    key_snooper_id = gtk_key_snooper_install (gail_key_snooper, data);
+  }
+  g_hash_table_insert (key_listener_list, GUINT_TO_POINTER (key++), (gpointer) listener);
+  /* XXX: we don't check to see if n_listeners > MAXUINT */
+  return key;
+}
+
+static void
+gail_util_remove_key_event_listener (guint remove_listener)
+{
+  g_hash_table_remove (key_listener_list, GUINT_TO_POINTER (remove_listener));
+  if (g_hash_table_size (key_listener_list) == 0)
+    {
+      gtk_key_snooper_remove (key_snooper_id);
+    }
+}
+
+static AtkObject*
+gail_util_get_root (void)
+{
+  if (!root)
+    root = gail_toplevel_new();
+
+  return root;
+}
+
+static G_CONST_RETURN gchar *
+gail_util_get_toolkit_name (void)
+{
+  return "GAIL";
+}
+
+static G_CONST_RETURN gchar *
+gail_util_get_toolkit_version (void)
+{
+ /*
+  * Version is passed in as a -D flag when this file is
+  * compiled.
+  */
+  return GTK_VERSION;
+}
+
+static void
+_listener_info_destroy (gpointer data)
+{
+   g_free(data);
+}
+
+static guint
+add_listener (GSignalEmissionHook listener,
+              const gchar         *object_type,
+              const gchar         *signal,
+              const gchar         *hook_data)
+{
+  GType type;
+  guint signal_id;
+  gint  rc = 0;
+
+  type = g_type_from_name (object_type);
+  if (type)
+    {
+      signal_id  = g_signal_lookup (signal, type);
+      if (signal_id > 0)
+        {
+          GailUtilListenerInfo *listener_info;
+
+          rc = listener_idx;
+
+          listener_info = g_malloc(sizeof(GailUtilListenerInfo));
+          listener_info->key = listener_idx;
+          listener_info->hook_id =
+                          g_signal_add_emission_hook (signal_id, 0, listener,
+                                                     g_strdup (hook_data),
+                                                     (GDestroyNotify) g_free);
+          listener_info->signal_id = signal_id;
+
+         g_hash_table_insert(listener_list, &(listener_info->key), listener_info);
+          listener_idx++;
+        }
+      else
+        {
+          g_warning("Invalid signal type %s\n", signal);
+        }
+    }
+  else
+    {
+      g_warning("Invalid object type %s\n", object_type);
+    }
+  return rc;
+}
+
+static void
+do_window_event_initialization (void)
+{
+  AtkObject *root;
+
+  /*
+   * Ensure that GailWindowClass exists.
+   */
+  g_type_class_ref (GAIL_TYPE_WINDOW);
+  g_signal_add_emission_hook (g_signal_lookup ("window-state-event", GTK_TYPE_WIDGET),
+                              0, state_event_watcher, NULL, (GDestroyNotify) NULL);
+  g_signal_add_emission_hook (g_signal_lookup ("configure-event", GTK_TYPE_WIDGET),
+                              0, configure_event_watcher, NULL, (GDestroyNotify) NULL);
+
+  root = atk_get_root ();
+  g_signal_connect (root, "children-changed::add",
+                    (GCallback) window_added, NULL);
+  g_signal_connect (root, "children-changed::remove",
+                    (GCallback) window_removed, NULL);
+}
+
+static gboolean
+state_event_watcher (GSignalInvocationHint  *hint,
+                     guint                  n_param_values,
+                     const GValue           *param_values,
+                     gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  AtkObject *atk_obj;
+  AtkObject *parent;
+  GdkEventWindowState *event;
+  gchar *signal_name;
+  guint signal_id;
+
+  object = g_value_get_object (param_values + 0);
+  /*
+   * The object can be a GtkMenu when it is popped up; we ignore this
+   */
+  if (!GTK_IS_WINDOW (object))
+    return FALSE;
+
+  event = g_value_get_boxed (param_values + 1);
+  gail_return_val_if_fail (event->type == GDK_WINDOW_STATE, FALSE);
+  widget = GTK_WIDGET (object);
+
+  if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
+    {
+      signal_name = "maximize";
+    }
+  else if (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)
+    {
+      signal_name = "minimize";
+    }
+  else if (event->new_window_state == 0)
+    {
+      signal_name = "restore";
+    }
+  else
+    return TRUE;
+  
+  atk_obj = gtk_widget_get_accessible (widget);
+
+  if (GAIL_IS_WINDOW (atk_obj))
+    {
+      parent = atk_object_get_parent (atk_obj);
+      if (parent == atk_get_root ())
+       {
+         signal_id = g_signal_lookup (signal_name, GAIL_TYPE_WINDOW); 
+         g_signal_emit (atk_obj, signal_id, 0);
+       }
+      
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+static void
+window_added (AtkObject *atk_obj,
+              guint     index,
+              AtkObject *child)
+{
+  GtkWidget *widget;
+
+  if (!GAIL_IS_WINDOW (child)) return;
+
+  widget = GTK_ACCESSIBLE (child)->widget;
+  gail_return_if_fail (widget);
+
+  g_signal_connect (widget, "focus-in-event",  
+                    (GCallback) window_focus, NULL);
+  g_signal_connect (widget, "focus-out-event",  
+                    (GCallback) window_focus, NULL);
+  g_signal_emit (child, g_signal_lookup ("create", GAIL_TYPE_WINDOW), 0); 
+}
+
+
+static void
+window_removed (AtkObject *atk_obj,
+                 guint     index,
+                 AtkObject *child)
+{
+  GtkWidget *widget;
+  GtkWindow *window;
+
+  if (!GAIL_IS_WINDOW (child)) return;
+
+  widget = GTK_ACCESSIBLE (child)->widget;
+  gail_return_if_fail (widget);
+
+  window = GTK_WINDOW (widget);
+  /*
+   * Deactivate window if it is still focused and we are removing it. This
+   * can happen when a dialog displayed by gok is removed.
+   */
+  if (window->is_active &&
+      window->has_toplevel_focus)
+    {
+      gchar *signal_name;
+      AtkObject *atk_obj;
+
+      atk_obj = gtk_widget_get_accessible (widget);
+      signal_name =  "deactivate";
+      g_signal_emit (atk_obj, g_signal_lookup (signal_name, GAIL_TYPE_WINDOW), 0); 
+    }
+
+  g_signal_handlers_disconnect_by_func (widget, (gpointer) window_focus, NULL);
+  g_signal_emit (child, g_signal_lookup ("destroy", GAIL_TYPE_WINDOW), 0); 
+}
+
+static gboolean
+window_focus (GtkWidget     *widget,
+              GdkEventFocus *event)
+{
+  gchar *signal_name;
+  AtkObject *atk_obj;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  atk_obj = gtk_widget_get_accessible (widget);
+  signal_name =  (event->in) ? "activate" : "deactivate";
+  g_signal_emit (atk_obj, g_signal_lookup (signal_name, GAIL_TYPE_WINDOW), 0); 
+
+  return FALSE;
+}
+
+static gboolean 
+configure_event_watcher (GSignalInvocationHint  *hint,
+                         guint                  n_param_values,
+                         const GValue           *param_values,
+                         gpointer               data)
+{
+  GObject *object;
+  GtkWidget *widget;
+  AtkObject *atk_obj;
+  AtkObject *parent;
+  GdkEvent *event;
+  gchar *signal_name;
+  guint signal_id;
+
+  object = g_value_get_object (param_values + 0);
+  if (!GTK_IS_WINDOW (object))
+    /*
+     * GtkDrawingArea can send a GDK_CONFIGURE event but we ignore here
+     */
+    return FALSE;
+
+  event = g_value_get_boxed (param_values + 1);
+  if (event->type != GDK_CONFIGURE)
+    return FALSE;
+  if (GTK_WINDOW (object)->configure_request_count)
+    /*
+     * There is another ConfigureRequest pending so we ignore this one.
+     */
+    return TRUE;
+  widget = GTK_WIDGET (object);
+  if (widget->allocation.x == ((GdkEventConfigure *)event)->x &&
+      widget->allocation.y == ((GdkEventConfigure *)event)->y &&
+      widget->allocation.width == ((GdkEventConfigure *)event)->width &&
+      widget->allocation.height == ((GdkEventConfigure *)event)->height)
+    return TRUE;
+
+  if (widget->allocation.width != ((GdkEventConfigure *)event)->width ||
+      widget->allocation.height != ((GdkEventConfigure *)event)->height)
+    {
+      signal_name = "resize";
+    }
+  else
+    {
+      signal_name = "move";
+    }
+
+  atk_obj = gtk_widget_get_accessible (widget);
+  if (GAIL_IS_WINDOW (atk_obj))
+    {
+      parent = atk_object_get_parent (atk_obj);
+      if (parent == atk_get_root ())
+       {
+         signal_id = g_signal_lookup (signal_name, GAIL_TYPE_WINDOW); 
+         g_signal_emit (atk_obj, signal_id, 0);
+       }
+      
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+GType
+gail_misc_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+  {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (GailMiscClass),
+      (GBaseInitFunc) NULL, /* base init */
+      (GBaseFinalizeFunc) NULL, /* base finalize */
+      (GClassInitFunc) gail_misc_class_init, /* class init */
+      (GClassFinalizeFunc) NULL, /* class finalize */
+      NULL, /* class data */
+      sizeof (GailMisc), /* instance size */
+      0, /* nb preallocs */
+      (GInstanceInitFunc) NULL, /* instance init */
+      NULL /* value table */
+    };
+
+    type = g_type_register_static (ATK_TYPE_MISC,
+                                   "GailMisc", &tinfo, 0);
+  }
+  return type;
+}
+
+static void     
+gail_misc_class_init (GailMiscClass *klass)
+{
+  AtkMiscClass *miscclass = ATK_MISC_CLASS (klass);
+  miscclass->threads_enter =
+    gail_misc_threads_enter;
+  miscclass->threads_leave =
+    gail_misc_threads_leave;
+  atk_misc_instance = g_object_new (GAIL_TYPE_MISC, NULL);
+}
+
+static void gail_misc_threads_enter (AtkMisc *misc)
+{
+  GDK_THREADS_ENTER ();
+}
+
+static void gail_misc_threads_leave (AtkMisc *misc)
+{
+  GDK_THREADS_LEAVE ();
+}
diff --git a/modules/other/gail/gailutil.h b/modules/other/gail/gailutil.h
new file mode 100644 (file)
index 0000000..4b968a6
--- /dev/null
@@ -0,0 +1,80 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_UTIL_H__
+#define __GAIL_UTIL_H__
+
+#include <atk/atk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_UTIL                           (gail_util_get_type ())
+#define GAIL_UTIL(obj)                           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_UTIL, GailUtil))
+#define GAIL_UTIL_CLASS(klass)                   (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_UTIL, GailUtilClass))
+#define GAIL_IS_UTIL(obj)                        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_UTIL))
+#define GAIL_IS_UTIL_CLASS(klass)                (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_UTIL))
+#define GAIL_UTIL_GET_CLASS(obj)                 (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_UTIL, GailUtilClass))
+
+typedef struct _GailUtil                  GailUtil;
+typedef struct _GailUtilClass             GailUtilClass;
+  
+struct _GailUtil
+{
+  AtkUtil parent;
+  GList *listener_list;
+};
+
+GType gail_util_get_type (void);
+
+struct _GailUtilClass
+{
+  AtkUtilClass parent_class;
+};
+
+#define GAIL_TYPE_MISC                           (gail_misc_get_type ())
+#define GAIL_MISC(obj)                           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_MISC, GailMisc))
+#define GAIL_MISC_CLASS(klass)                   (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_MISC, GailMiscClass))
+#define GAIL_IS_MISC(obj)                        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_MISC))
+#define GAIL_IS_MISC_CLASS(klass)                (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_MISC))
+#define GAIL_MISC_GET_CLASS(obj)                 (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_MISC, GailMiscClass))
+
+typedef struct _GailMisc                  GailMisc;
+typedef struct _GailMiscClass             GailMiscClass;
+  
+struct _GailMisc
+{
+  AtkMisc parent;
+};
+
+GType gail_misc_get_type (void);
+
+struct _GailMiscClass
+{
+  AtkMiscClass parent_class;
+};
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_UTIL_H__ */
diff --git a/modules/other/gail/gailwidget.c b/modules/other/gail/gailwidget.c
new file mode 100644 (file)
index 0000000..7283479
--- /dev/null
@@ -0,0 +1,1111 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/x11/gdkx.h>
+#endif
+#include "gailwidget.h"
+#include "gailnotebookpage.h"
+#include "gail-private-macros.h"
+
+extern GtkWidget *focus_widget;
+
+static void gail_widget_class_init (GailWidgetClass *klass);
+
+static void gail_widget_connect_widget_destroyed (GtkAccessible    *accessible);
+static void gail_widget_destroyed                (GtkWidget        *widget,
+                                                  GtkAccessible    *accessible);
+
+static G_CONST_RETURN gchar* gail_widget_get_description (AtkObject *accessible);
+static AtkObject* gail_widget_get_parent (AtkObject *accessible);
+static AtkStateSet* gail_widget_ref_state_set (AtkObject *accessible);
+static AtkRelationSet* gail_widget_ref_relation_set (AtkObject *accessible);
+static gint gail_widget_get_index_in_parent (AtkObject *accessible);
+
+static void atk_component_interface_init (AtkComponentIface *iface);
+
+static guint    gail_widget_add_focus_handler
+                                           (AtkComponent    *component,
+                                            AtkFocusHandler handler);
+
+static void     gail_widget_get_extents    (AtkComponent    *component,
+                                            gint            *x,
+                                            gint            *y,
+                                            gint            *width,
+                                            gint            *height,
+                                            AtkCoordType    coord_type);
+
+static void     gail_widget_get_size       (AtkComponent    *component,
+                                            gint            *width,
+                                            gint            *height);
+
+static AtkLayer gail_widget_get_layer      (AtkComponent *component);
+
+static gboolean gail_widget_grab_focus     (AtkComponent    *component);
+
+
+static void     gail_widget_remove_focus_handler 
+                                           (AtkComponent    *component,
+                                            guint           handler_id);
+
+static gboolean gail_widget_set_extents    (AtkComponent    *component,
+                                            gint            x,
+                                            gint            y,
+                                            gint            width,
+                                            gint            height,
+                                            AtkCoordType    coord_type);
+
+static gboolean gail_widget_set_position   (AtkComponent    *component,
+                                            gint            x,
+                                            gint            y,
+                                            AtkCoordType    coord_type);
+
+static gboolean gail_widget_set_size       (AtkComponent    *component,
+                                            gint            width,
+                                            gint            height);
+
+static gint       gail_widget_map_gtk            (GtkWidget     *widget);
+static void       gail_widget_real_notify_gtk    (GObject       *obj,
+                                                  GParamSpec    *pspec);
+static void       gail_widget_notify_gtk         (GObject       *obj,
+                                                  GParamSpec    *pspec);
+static gboolean   gail_widget_focus_gtk          (GtkWidget     *widget,
+                                                  GdkEventFocus *event);
+static gboolean   gail_widget_real_focus_gtk     (GtkWidget     *widget,
+                                                  GdkEventFocus *event);
+static void       gail_widget_size_allocate_gtk  (GtkWidget     *widget,
+                                                  GtkAllocation *allocation);
+
+static void       gail_widget_focus_event        (AtkObject     *obj,
+                                                  gboolean      focus_in);
+
+static void       gail_widget_real_initialize    (AtkObject     *obj,
+                                                  gpointer      data);
+static GtkWidget* gail_widget_find_viewport      (GtkWidget     *widget);
+static gboolean   gail_widget_on_screen          (GtkWidget     *widget);
+
+static gpointer parent_class = NULL;
+
+GType
+gail_widget_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailWidgetClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_widget_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailWidget), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+
+      static const GInterfaceInfo atk_component_info =
+      {
+        (GInterfaceInitFunc) atk_component_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };
+
+      type = g_type_register_static (GTK_TYPE_ACCESSIBLE,
+                                     "GailWidget", &tinfo, 0);
+      g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+                                   &atk_component_info);
+    }
+
+  return type;
+}
+
+static void
+gail_widget_class_init (GailWidgetClass *klass)
+{
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+  GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  klass->notify_gtk = gail_widget_real_notify_gtk;
+  klass->focus_gtk = gail_widget_real_focus_gtk;
+
+  accessible_class->connect_widget_destroyed = gail_widget_connect_widget_destroyed;
+
+  class->get_description = gail_widget_get_description;
+  class->get_parent = gail_widget_get_parent;
+  class->ref_relation_set = gail_widget_ref_relation_set;
+  class->ref_state_set = gail_widget_ref_state_set;
+  class->get_index_in_parent = gail_widget_get_index_in_parent;
+  class->initialize = gail_widget_real_initialize;
+}
+
+/**
+ * This function  specifies the GtkWidget for which the GailWidget was created 
+ * and specifies a handler to be called when the GtkWidget is destroyed.
+ **/
+static void 
+gail_widget_real_initialize (AtkObject *obj,
+                             gpointer  data)
+{
+  GtkAccessible *accessible;
+  GtkWidget *widget;
+
+  g_return_if_fail (GTK_IS_WIDGET (data));
+
+  widget = GTK_WIDGET (data);
+
+  accessible = GTK_ACCESSIBLE (obj);
+  accessible->widget = widget;
+  gtk_accessible_connect_widget_destroyed (accessible);
+  g_signal_connect_after (widget,
+                          "focus-in-event",
+                          G_CALLBACK (gail_widget_focus_gtk),
+                          NULL);
+  g_signal_connect_after (widget,
+                          "focus-out-event",
+                          G_CALLBACK (gail_widget_focus_gtk),
+                          NULL);
+  g_signal_connect (widget,
+                    "notify",
+                    G_CALLBACK (gail_widget_notify_gtk),
+                    NULL);
+  g_signal_connect (widget,
+                    "size_allocate",
+                    G_CALLBACK (gail_widget_size_allocate_gtk),
+                    NULL);
+  atk_component_add_focus_handler (ATK_COMPONENT (accessible),
+                                   gail_widget_focus_event);
+  /*
+   * Add signal handlers for GTK signals required to support property changes
+   */
+  g_signal_connect (widget,
+                    "map",
+                    G_CALLBACK (gail_widget_map_gtk),
+                    NULL);
+  g_signal_connect (widget,
+                    "unmap",
+                    G_CALLBACK (gail_widget_map_gtk),
+                    NULL);
+  g_object_set_data (G_OBJECT (obj), "atk-component-layer",
+                    GINT_TO_POINTER (ATK_LAYER_WIDGET));
+
+  obj->role = ATK_ROLE_UNKNOWN;
+}
+
+AtkObject* 
+gail_widget_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+  object = g_object_new (GAIL_TYPE_WIDGET, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  return accessible;
+}
+
+/*
+ * This function specifies the function to be called when the widget
+ * is destroyed
+ */
+static void
+gail_widget_connect_widget_destroyed (GtkAccessible *accessible)
+{
+  if (accessible->widget)
+    {
+      g_signal_connect_after (accessible->widget,
+                              "destroy",
+                              G_CALLBACK (gail_widget_destroyed),
+                              accessible);
+    }
+}
+
+/*
+ * This function is called when the widget is destroyed.
+ * It sets the widget field in the GtkAccessible structure to NULL
+ * and emits a state-change signal for the state ATK_STATE_DEFUNCT
+ */
+static void 
+gail_widget_destroyed (GtkWidget     *widget,
+                       GtkAccessible *accessible)
+{
+  accessible->widget = NULL;
+  atk_object_notify_state_change (ATK_OBJECT (accessible), ATK_STATE_DEFUNCT,
+                                  TRUE);
+}
+
+static G_CONST_RETURN gchar*
+gail_widget_get_description (AtkObject *accessible)
+{
+  if (accessible->description)
+    return accessible->description;
+  else
+    {
+      /* Get the tooltip from the widget */
+      GtkAccessible *obj = GTK_ACCESSIBLE (accessible);
+      GtkTooltipsData *data;
+
+      gail_return_val_if_fail (obj, NULL);
+
+      if (obj->widget == NULL)
+        /*
+         * Object is defunct
+         */
+        return NULL;
+      gail_return_val_if_fail (GTK_WIDGET (obj->widget), NULL);
+    
+      data = gtk_tooltips_data_get (obj->widget);
+      if (data == NULL)
+        return NULL;
+
+      return data->tip_text;
+    }
+}
+
+static AtkObject* 
+gail_widget_get_parent (AtkObject *accessible)
+{
+  AtkObject *parent;
+
+  parent = accessible->accessible_parent;
+
+  if (parent != NULL)
+    g_return_val_if_fail (ATK_IS_OBJECT (parent), NULL);
+  else
+    {
+      GtkWidget *widget, *parent_widget;
+
+      widget = GTK_ACCESSIBLE (accessible)->widget;
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+      gail_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+      parent_widget = widget->parent;
+      if (parent_widget == NULL)
+        return NULL;
+
+      /*
+       * For a widget whose parent is a GtkNoteBook, we return the
+       * accessible object corresponding the GtkNotebookPage containing
+       * the widget as the accessible parent.
+       */
+      if (GTK_IS_NOTEBOOK (parent_widget))
+        {
+          gint page_num;
+          GtkWidget *child;
+          GtkNotebook *notebook;
+
+          page_num = 0;
+          notebook = GTK_NOTEBOOK (parent_widget);
+          while (TRUE)
+            {
+              child = gtk_notebook_get_nth_page (notebook, page_num);
+              if (!child)
+                break;
+              if (child == widget)
+                {
+                  parent = gtk_widget_get_accessible (parent_widget);
+                  parent = atk_object_ref_accessible_child (parent, page_num);
+                  g_object_unref (parent);
+                  return parent;
+                }
+              page_num++;
+            }
+        }
+
+      parent = gtk_widget_get_accessible (parent_widget);
+    }
+  return parent;
+}
+
+static GtkWidget*
+find_label (GtkWidget *widget)
+{
+  GList *labels;
+  GtkWidget *label;
+  GtkWidget *temp_widget;
+
+  labels = gtk_widget_list_mnemonic_labels (widget);
+  label = NULL;
+  if (labels)
+    {
+      if (labels->data)
+        {
+          if (labels->next)
+            {
+              g_warning ("Widget (%s) has more than one label", G_OBJECT_TYPE_NAME (widget));
+              
+            }
+          else
+            {
+              label = labels->data;
+            }
+        }
+      g_list_free (labels);
+    }
+
+  /*
+   * Ignore a label within a button; bug #136602
+   */
+  if (label && GTK_IS_BUTTON (widget))
+    {
+      temp_widget = label;
+      while (temp_widget)
+        {
+          if (temp_widget == widget)
+            {
+              label = NULL;
+              break;
+            }
+          temp_widget = gtk_widget_get_parent (temp_widget);
+        }
+    } 
+  return label;
+}
+
+static AtkRelationSet*
+gail_widget_ref_relation_set (AtkObject *obj)
+{
+  GtkWidget *widget;
+  AtkRelationSet *relation_set;
+  GtkWidget *label;
+  AtkObject *array[1];
+  AtkRelation* relation;
+
+  gail_return_val_if_fail (GAIL_IS_WIDGET (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  relation_set = ATK_OBJECT_CLASS (parent_class)->ref_relation_set (obj);
+
+  if (GTK_IS_BOX (widget) && !GTK_IS_COMBO (widget))
+      /*
+       * Do not report labelled-by for a GtkBox which could be a 
+       * GnomeFileEntry.
+       */
+    return relation_set;
+
+  if (!atk_relation_set_contains (relation_set, ATK_RELATION_LABELLED_BY))
+    {
+      label = find_label (widget);
+      if (label == NULL)
+        {
+          if (GTK_IS_BUTTON (widget))
+            /*
+             * Handle the case where GnomeIconEntry is the mnemonic widget.
+             * The GtkButton which is a grandchild of the GnomeIconEntry
+             * should really be the mnemonic widget. See bug #133967.
+             */
+            {
+              GtkWidget *temp_widget;
+
+              temp_widget = gtk_widget_get_parent (widget);
+
+              if (GTK_IS_ALIGNMENT (temp_widget))
+                {
+                  temp_widget = gtk_widget_get_parent (temp_widget);
+                  if (GTK_IS_BOX (temp_widget))
+                    {
+                      label = find_label (temp_widget);
+                 
+                      if (!label)
+                        label = find_label (gtk_widget_get_parent (temp_widget));
+                    }
+                }
+            }
+          else if (GTK_IS_COMBO (widget))
+            /*
+             * Handle the case when GnomeFileEntry is the mnemonic widget.
+             * The GnomeEntry which is a grandchild of the GnomeFileEntry
+             * should be the mnemonic widget. See bug #137584.
+             */
+            {
+              GtkWidget *temp_widget;
+
+              temp_widget = gtk_widget_get_parent (widget);
+
+              if (GTK_IS_HBOX (temp_widget))
+                {
+                  temp_widget = gtk_widget_get_parent (temp_widget);
+                  if (GTK_IS_BOX (temp_widget))
+                    {
+                      label = find_label (temp_widget);
+                    }
+                }
+            }
+          else if (GTK_IS_COMBO_BOX (widget))
+            /*
+             * Handle the case when GtkFileChooserButton is the mnemonic
+             * widget.  The GtkComboBox which is a child of the
+             * GtkFileChooserButton should be the mnemonic widget.
+             * See bug #359843.
+             */
+            {
+              GtkWidget *temp_widget;
+
+              temp_widget = gtk_widget_get_parent (widget);
+              if (GTK_IS_HBOX (temp_widget))
+                {
+                  label = find_label (temp_widget);
+                }
+            }
+        }
+
+      if (label)
+        {
+         array [0] = gtk_widget_get_accessible (label);
+
+         relation = atk_relation_new (array, 1, ATK_RELATION_LABELLED_BY);
+         atk_relation_set_add (relation_set, relation);
+         g_object_unref (relation);
+        }
+    }
+
+  return relation_set;
+}
+
+static AtkStateSet*
+gail_widget_ref_state_set (AtkObject *accessible)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (accessible)->widget;
+  AtkStateSet *state_set;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+
+  if (widget == NULL)
+    {
+      atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
+    }
+  else
+    {
+      if (GTK_WIDGET_IS_SENSITIVE (widget))
+        {
+          atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
+          atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
+        }
+  
+      if (GTK_WIDGET_CAN_FOCUS (widget))
+        {
+          atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
+        }
+      /*
+       * We do not currently generate notifications when an ATK object 
+       * corresponding to a GtkWidget changes visibility by being scrolled 
+       * on or off the screen.  The testcase for this is the main window 
+       * of the testgtk application in which a set of buttons in a GtkVBox 
+       * is in a scrooled window with a viewport.
+       *
+       * To generate the notifications we would need to do the following: 
+       * 1) Find the GtkViewPort among the antecendents of the objects
+       * 2) Create an accesible for the GtkViewPort
+       * 3) Connect to the value-changed signal on the viewport
+       * 4) When the signal is received we need to traverse the children 
+       * of the viewport and check whether the children are visible or not 
+       * visible; we may want to restrict this to the widgets for which 
+       * accessible objects have been created.
+       * 5) We probably need to store a variable on_screen in the 
+       * GailWidget data structure so we can determine whether the value has 
+       * changed.
+       */
+      if (GTK_WIDGET_VISIBLE (widget))
+        {
+          atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
+          if (gail_widget_on_screen (widget) &&
+              GTK_WIDGET_MAPPED (widget))
+            {
+              atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
+            }
+        }
+  
+      if (GTK_WIDGET_HAS_FOCUS (widget) && (widget == focus_widget))
+        {
+          AtkObject *focus_obj;
+
+          focus_obj = g_object_get_data (G_OBJECT (accessible), "gail-focus-object");
+          if (focus_obj == NULL)
+            atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
+        }
+      if (GTK_WIDGET_HAS_DEFAULT(widget))
+        {
+          atk_state_set_add_state (state_set, ATK_STATE_DEFAULT);
+        }
+    }
+  return state_set;
+}
+
+static gint
+gail_widget_get_index_in_parent (AtkObject *accessible)
+{
+  GtkWidget *widget;
+  GtkWidget *parent_widget;
+  gint index;
+  GList *children;
+  GType type;
+
+  type = g_type_from_name ("GailCanvasWidget");
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return -1;
+
+  if (accessible->accessible_parent)
+    {
+      AtkObject *parent;
+
+      parent = accessible->accessible_parent;
+
+      if (GAIL_IS_NOTEBOOK_PAGE (parent) ||
+          G_TYPE_CHECK_INSTANCE_TYPE ((parent), type))
+        return 0;
+      else
+        {
+          gint n_children, i;
+          gboolean found = FALSE;
+
+          n_children = atk_object_get_n_accessible_children (parent);
+          for (i = 0; i < n_children; i++)
+            {
+              AtkObject *child;
+
+              child = atk_object_ref_accessible_child (parent, i);
+              if (child == accessible)
+                found = TRUE;
+
+              g_object_unref (child); 
+              if (found)
+                return i;
+            }
+        }
+    }
+
+  gail_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
+  parent_widget = widget->parent;
+  if (parent_widget == NULL)
+    return -1;
+  gail_return_val_if_fail (GTK_IS_CONTAINER (parent_widget), -1);
+
+  children = gtk_container_get_children (GTK_CONTAINER (parent_widget));
+
+  index = g_list_index (children, widget);
+  g_list_free (children);
+  return index;  
+}
+
+static void 
+atk_component_interface_init (AtkComponentIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  /*
+   * Use default implementation for contains and get_position
+   */
+  iface->add_focus_handler = gail_widget_add_focus_handler;
+  iface->get_extents = gail_widget_get_extents;
+  iface->get_size = gail_widget_get_size;
+  iface->get_layer = gail_widget_get_layer;
+  iface->grab_focus = gail_widget_grab_focus;
+  iface->remove_focus_handler = gail_widget_remove_focus_handler;
+  iface->set_extents = gail_widget_set_extents;
+  iface->set_position = gail_widget_set_position;
+  iface->set_size = gail_widget_set_size;
+}
+
+static guint 
+gail_widget_add_focus_handler (AtkComponent    *component,
+                               AtkFocusHandler handler)
+{
+  GSignalMatchType match_type;
+  gulong ret;
+  guint signal_id;
+
+  match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC;
+  signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT);
+
+  ret = g_signal_handler_find (component, match_type, signal_id, 0, NULL,
+                               (gpointer) handler, NULL);
+  if (!ret)
+    {
+      return g_signal_connect_closure_by_id (component, 
+                                             signal_id, 0,
+                                             g_cclosure_new (
+                                             G_CALLBACK (handler), NULL,
+                                             (GClosureNotify) NULL),
+                                             FALSE);
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+static void 
+gail_widget_get_extents (AtkComponent   *component,
+                         gint           *x,
+                         gint           *y,
+                         gint           *width,
+                         gint           *height,
+                         AtkCoordType   coord_type)
+{
+  GdkWindow *window;
+  gint x_window, y_window;
+  gint x_toplevel, y_toplevel;
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+
+  if (widget == NULL)
+    /*
+     * Object is defunct
+     */
+    return;
+
+  gail_return_if_fail (GTK_IS_WIDGET (widget));
+
+  *width = widget->allocation.width;
+  *height = widget->allocation.height;
+  if (!gail_widget_on_screen (widget) || (!GTK_WIDGET_DRAWABLE (widget)))
+    {
+      *x = G_MININT;
+      *y = G_MININT;
+      return;
+    }
+
+  if (widget->parent)
+    {
+      *x = widget->allocation.x;
+      *y = widget->allocation.y;
+      window = gtk_widget_get_parent_window (widget);
+    }
+  else
+    {
+      *x = 0;
+      *y = 0;
+      window = widget->window;
+    }
+  gdk_window_get_origin (window, &x_window, &y_window);
+  *x += x_window;
+  *y += y_window;
+
+ if (coord_type == ATK_XY_WINDOW) 
+    { 
+      window = gdk_window_get_toplevel (widget->window);
+      gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
+
+      *x -= x_toplevel;
+      *y -= y_toplevel;
+    }
+}
+
+static void 
+gail_widget_get_size (AtkComponent   *component,
+                      gint           *width,
+                      gint           *height)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+
+  if (widget == NULL)
+    /*
+     * Object is defunct
+     */
+    return;
+
+  gail_return_if_fail (GTK_IS_WIDGET (widget));
+
+  *width = widget->allocation.width;
+  *height = widget->allocation.height;
+}
+
+static AtkLayer
+gail_widget_get_layer (AtkComponent *component)
+{
+  gint layer;
+  layer = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (component), "atk-component-layer"));
+
+  return (AtkLayer) layer;
+}
+
+static gboolean 
+gail_widget_grab_focus (AtkComponent   *component)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+  GtkWidget *toplevel;
+
+  gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+  if (GTK_WIDGET_CAN_FOCUS (widget))
+    {
+      gtk_widget_grab_focus (widget);
+      toplevel = gtk_widget_get_toplevel (widget);
+      if (GTK_WIDGET_TOPLEVEL (toplevel))
+       {
+#ifdef GDK_WINDOWING_X11
+         gtk_window_present_with_time (GTK_WINDOW (toplevel), gdk_x11_get_server_time (widget->window));
+#else
+         gtk_window_present (GTK_WINDOW (toplevel));
+#endif
+       }
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void 
+gail_widget_remove_focus_handler (AtkComponent   *component,
+                                  guint          handler_id)
+{
+  g_signal_handler_disconnect (component, handler_id);
+}
+
+static gboolean 
+gail_widget_set_extents (AtkComponent   *component,
+                         gint           x,
+                         gint           y,
+                         gint           width,
+                         gint           height,
+                         AtkCoordType   coord_type)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+
+  if (widget == NULL)
+    /*
+     * Object is defunct
+     */
+    return FALSE;
+  gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    {
+      if (coord_type == ATK_XY_WINDOW)
+        {
+          gint x_current, y_current;
+          GdkWindow *window = widget->window;
+
+          gdk_window_get_origin (window, &x_current, &y_current);
+          x_current += x;
+          y_current += y;
+          if (x_current < 0 || y_current < 0)
+            return FALSE;
+          else
+            {
+              gtk_widget_set_uposition (widget, x_current, y_current);
+              gtk_widget_set_usize (widget, width, height);
+              return TRUE;
+            }
+        }
+      else if (coord_type == ATK_XY_SCREEN)
+        {  
+          gtk_widget_set_uposition (widget, x, y);
+          gtk_widget_set_usize (widget, width, height);
+          return TRUE;
+        }
+    }
+  return FALSE;
+}
+
+static gboolean
+gail_widget_set_position (AtkComponent   *component,
+                          gint           x,
+                          gint           y,
+                          AtkCoordType   coord_type)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+
+  if (widget == NULL)
+    /*
+     * Object is defunct
+     */
+    return FALSE;
+  gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    {
+      if (coord_type == ATK_XY_WINDOW)
+        {
+          gint x_current, y_current;
+          GdkWindow *window = widget->window;
+
+          gdk_window_get_origin (window, &x_current, &y_current);
+          x_current += x;
+          y_current += y;
+          if (x_current < 0 || y_current < 0)
+            return FALSE;
+          else
+            {
+              gtk_widget_set_uposition (widget, x_current, y_current);
+              return TRUE;
+            }
+        }
+      else if (coord_type == ATK_XY_SCREEN)
+        {  
+          gtk_widget_set_uposition (widget, x, y);
+          return TRUE;
+        }
+    }
+  return FALSE;
+}
+
+static gboolean 
+gail_widget_set_size (AtkComponent   *component,
+                      gint           width,
+                      gint           height)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+
+  if (widget == NULL)
+    /*
+     * Object is defunct
+     */
+    return FALSE;
+  gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    {
+      gtk_widget_set_usize (widget, width, height);
+      return TRUE;
+    }
+  else
+   return FALSE;
+}
+
+/*
+ * This function is a signal handler for notify_in_event and focus_out_event
+ * signal which gets emitted on a GtkWidget.
+ */
+static gboolean
+gail_widget_focus_gtk (GtkWidget     *widget,
+                       GdkEventFocus *event)
+{
+  GailWidget *gail_widget;
+  GailWidgetClass *klass;
+
+  gail_widget = GAIL_WIDGET (gtk_widget_get_accessible (widget));
+  klass = GAIL_WIDGET_GET_CLASS (gail_widget);
+  if (klass->focus_gtk)
+    return klass->focus_gtk (widget, event);
+  else
+    return FALSE;
+}
+
+/*
+ * This function is the signal handler defined for focus_in_event and
+ * focus_out_event got GailWidget.
+ *
+ * It emits a focus-event signal on the GailWidget.
+ */
+static gboolean
+gail_widget_real_focus_gtk (GtkWidget     *widget,
+                            GdkEventFocus *event)
+{
+  AtkObject* accessible;
+  gboolean return_val;
+  return_val = FALSE;
+
+  accessible = gtk_widget_get_accessible (widget);
+  g_signal_emit_by_name (accessible, "focus_event", event->in, &return_val);
+  return FALSE;
+}
+
+static void
+gail_widget_size_allocate_gtk (GtkWidget     *widget,
+                               GtkAllocation *allocation)
+{
+  AtkObject* accessible;
+  AtkRectangle rect;
+
+  accessible = gtk_widget_get_accessible (widget);
+  if (ATK_IS_COMPONENT (accessible))
+    {
+      rect.x = allocation->x;
+      rect.y = allocation->y;
+      rect.width = allocation->width;
+      rect.height = allocation->height;
+      g_signal_emit_by_name (accessible, "bounds_changed", &rect);
+    }
+}
+
+/*
+ * This function is the signal handler defined for map and unmap signals.
+ */
+static gint
+gail_widget_map_gtk (GtkWidget     *widget)
+{
+  AtkObject* accessible;
+
+  accessible = gtk_widget_get_accessible (widget);
+  atk_object_notify_state_change (accessible, ATK_STATE_SHOWING,
+                                  GTK_WIDGET_MAPPED (widget));
+  return 1;
+}
+
+/*
+ * This function is a signal handler for notify signal which gets emitted 
+ * when a property changes value on the GtkWidget associated with the object.
+ *
+ * It calls a function for the GailWidget type
+ */
+static void 
+gail_widget_notify_gtk (GObject     *obj,
+                        GParamSpec  *pspec)
+{
+  GailWidget *widget;
+  GailWidgetClass *klass;
+
+  widget = GAIL_WIDGET (gtk_widget_get_accessible (GTK_WIDGET (obj)));
+  klass = GAIL_WIDGET_GET_CLASS (widget);
+  if (klass->notify_gtk)
+    klass->notify_gtk (obj, pspec);
+}
+
+/*
+ * This function is a signal handler for notify signal which gets emitted 
+ * when a property changes value on the GtkWidget associated with a GailWidget.
+ *
+ * It constructs an AtkPropertyValues structure and emits a "property_changed"
+ * signal which causes the user specified AtkPropertyChangeHandler
+ * to be called.
+ */
+static void 
+gail_widget_real_notify_gtk (GObject     *obj,
+                             GParamSpec  *pspec)
+{
+  GtkWidget* widget = GTK_WIDGET (obj);
+  AtkObject* atk_obj = gtk_widget_get_accessible (widget);
+  AtkState state;
+  gboolean value;
+
+  if (strcmp (pspec->name, "has-focus") == 0)
+    /*
+     * We use focus-in-event and focus-out-event signals to catch
+     * focus changes so we ignore this.
+     */
+    return;
+  else if (strcmp (pspec->name, "visible") == 0)
+    {
+      state = ATK_STATE_VISIBLE;
+      value = GTK_WIDGET_VISIBLE (widget);
+    }
+  else if (strcmp (pspec->name, "sensitive") == 0)
+    {
+      state = ATK_STATE_SENSITIVE;
+      value = GTK_WIDGET_SENSITIVE (widget);
+    }
+  else
+    return;
+
+  atk_object_notify_state_change (atk_obj, state, value);
+}
+
+static void 
+gail_widget_focus_event (AtkObject   *obj,
+                         gboolean    focus_in)
+{
+  AtkObject *focus_obj;
+
+  focus_obj = g_object_get_data (G_OBJECT (obj), "gail-focus-object");
+  if (focus_obj == NULL)
+    focus_obj = obj;
+  atk_object_notify_state_change (focus_obj, ATK_STATE_FOCUSED, focus_in);
+}
+
+static GtkWidget*
+gail_widget_find_viewport (GtkWidget *widget)
+{
+  /*
+   * Find an antecedent which is a GtkViewPort
+   */
+  GtkWidget *parent;
+
+  parent = widget->parent;
+  while (parent != NULL)
+    {
+      if (GTK_IS_VIEWPORT (parent))
+        break;
+      parent = parent->parent;
+    }
+  return parent;
+}
+
+/*
+ * This function checks whether the widget has an antecedent which is 
+ * a GtkViewport and, if so, whether any part of the widget intersects
+ * the visible rectangle of the GtkViewport.
+ */ 
+static gboolean gail_widget_on_screen (GtkWidget *widget)
+{
+  GtkWidget *viewport;
+  gboolean return_value;
+
+  viewport = gail_widget_find_viewport (widget);
+  if (viewport)
+    {
+      GtkAdjustment *adjustment;
+      GdkRectangle visible_rect;
+
+      adjustment = gtk_viewport_get_vadjustment (GTK_VIEWPORT (viewport));
+      visible_rect.y = adjustment->value;
+      adjustment = gtk_viewport_get_hadjustment (GTK_VIEWPORT (viewport));
+      visible_rect.x = adjustment->value;
+      visible_rect.width = viewport->allocation.width;
+      visible_rect.height = viewport->allocation.height;
+             
+      if (((widget->allocation.x + widget->allocation.width) < visible_rect.x) ||
+         ((widget->allocation.y + widget->allocation.height) < visible_rect.y) ||
+         (widget->allocation.x > (visible_rect.x + visible_rect.width)) ||
+         (widget->allocation.y > (visible_rect.y + visible_rect.height)))
+        return_value = FALSE;
+      else
+        return_value = TRUE;
+    }
+  else
+    {
+      /*
+       * Check whether the widget has been placed of the screen. The
+       * widget may be MAPPED as when toolbar items do not fit on the toolbar.
+       */
+      if (widget->allocation.x + widget->allocation.width <= 0 &&
+          widget->allocation.y + widget->allocation.height <= 0)
+        return_value = FALSE;
+      else 
+        return_value = TRUE;
+    }
+
+  return return_value;
+}
diff --git a/modules/other/gail/gailwidget.h b/modules/other/gail/gailwidget.h
new file mode 100644 (file)
index 0000000..04fdae0
--- /dev/null
@@ -0,0 +1,71 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_WIDGET_H__
+#define __GAIL_WIDGET_H__
+
+#include <gtk/gtkaccessible.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_WIDGET                     (gail_widget_get_type ())
+#define GAIL_WIDGET(obj)                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_WIDGET, GailWidget))
+#define GAIL_WIDGET_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_WIDGET, GailWidgetClass))
+#define GAIL_IS_WIDGET(obj)                  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_WIDGET))
+#define GAIL_IS_WIDGET_CLASS(klass)          (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_WIDGET))
+#define GAIL_WIDGET_GET_CLASS(obj)           (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_WIDGET, GailWidgetClass))
+
+typedef struct _GailWidget                   GailWidget;
+typedef struct _GailWidgetClass              GailWidgetClass;
+
+struct _GailWidget
+{
+  GtkAccessible parent;
+};
+
+GType gail_widget_get_type (void);
+
+struct _GailWidgetClass
+{
+  GtkAccessibleClass parent_class;
+
+  /*
+   * Signal handler for notify signal on GTK widget
+   */
+  void (*notify_gtk)                   (GObject             *object,
+                                        GParamSpec          *pspec);
+  /*
+   * Signal handler for focus_in_event and focus_out_event signal on GTK widget
+   */
+  gboolean (*focus_gtk)                (GtkWidget           *widget,
+                                        GdkEventFocus       *event);
+
+};
+
+AtkObject*     gail_widget_new         (GtkWidget       *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_WIDGET_H__ */
diff --git a/modules/other/gail/gailwindow.c b/modules/other/gail/gailwindow.c
new file mode 100644 (file)
index 0000000..c6c9fd0
--- /dev/null
@@ -0,0 +1,1094 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001, 2002, 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 "gailwindow.h"
+#include "gailtoplevel.h"
+#include "gail-private-macros.h"
+
+enum {
+  ACTIVATE,
+  CREATE,
+  DEACTIVATE,
+  DESTROY,
+  MAXIMIZE,
+  MINIMIZE,
+  MOVE,
+  RESIZE,
+  RESTORE,
+  LAST_SIGNAL
+};
+
+static void gail_window_class_init (GailWindowClass *klass);
+
+static void                  gail_window_real_initialize (AtkObject    *obj,
+                                                          gpointer     data);
+static void                  gail_window_finalize        (GObject      *object);
+
+static G_CONST_RETURN gchar* gail_window_get_name       (AtkObject     *accessible);
+
+static AtkObject*            gail_window_get_parent     (AtkObject     *accessible);
+static gint                  gail_window_get_index_in_parent (AtkObject *accessible);
+static gboolean              gail_window_real_focus_gtk (GtkWidget     *widget,
+                                                         GdkEventFocus *event);
+
+static AtkStateSet*          gail_window_ref_state_set  (AtkObject     *accessible);
+static AtkRelationSet*       gail_window_ref_relation_set  (AtkObject     *accessible);
+static void                  gail_window_real_notify_gtk (GObject      *obj,
+                                                          GParamSpec   *pspec);
+static gint                  gail_window_get_mdi_zorder (AtkComponent  *component);
+
+static gboolean              gail_window_state_event_gtk (GtkWidget           *widget,
+                                                          GdkEventWindowState *event);
+
+/* atkcomponent.h */
+static void                  atk_component_interface_init (AtkComponentIface    *iface);
+
+static void                  gail_window_get_extents      (AtkComponent         *component,
+                                                           gint                 *x,
+                                                           gint                 *y,
+                                                           gint                 *width,
+                                                           gint                 *height,
+                                                           AtkCoordType         coord_type);
+static void                  gail_window_get_size         (AtkComponent         *component,
+                                                           gint                 *width,
+                                                           gint                 *height);
+
+static guint gail_window_signals [LAST_SIGNAL] = { 0, };
+
+static gpointer parent_class = NULL;
+
+GType
+gail_window_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailWindowClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_window_class_init, /* class init */
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof (GailWindow), /* instance size */
+        0, /* nb preallocs */
+        (GInstanceInitFunc) NULL, /* instance init */
+        NULL /* value table */
+      };
+  
+      static const GInterfaceInfo atk_component_info =
+      {
+        (GInterfaceInitFunc) atk_component_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL
+      };      
+      type = g_type_register_static (GAIL_TYPE_CONTAINER,
+                                     "GailWindow", &tinfo, 0);
+
+      g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+                                   &atk_component_info);
+    }
+
+  return type;
+}
+
+static void
+gail_window_class_init (GailWindowClass *klass)
+{
+  GailWidgetClass *widget_class;
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gail_window_finalize;
+
+  widget_class = (GailWidgetClass*)klass;
+  widget_class->focus_gtk = gail_window_real_focus_gtk;
+  widget_class->notify_gtk = gail_window_real_notify_gtk;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  class->get_name = gail_window_get_name;
+  class->get_parent = gail_window_get_parent;
+  class->get_index_in_parent = gail_window_get_index_in_parent;
+  class->ref_relation_set = gail_window_ref_relation_set;
+  class->ref_state_set = gail_window_ref_state_set;
+  class->initialize = gail_window_real_initialize;
+
+  gail_window_signals [ACTIVATE] =
+    g_signal_new ("activate",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [CREATE] =
+    g_signal_new ("create",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [DEACTIVATE] =
+    g_signal_new ("deactivate",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [DESTROY] =
+    g_signal_new ("destroy",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [MAXIMIZE] =
+    g_signal_new ("maximize",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [MINIMIZE] =
+    g_signal_new ("minimize",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [MOVE] =
+    g_signal_new ("move",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [RESIZE] =
+    g_signal_new ("resize",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  gail_window_signals [RESTORE] =
+    g_signal_new ("restore",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* default signal handler */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+AtkObject*
+gail_window_new (GtkWidget *widget)
+{
+  GObject *object;
+  AtkObject *accessible;
+
+  gail_return_val_if_fail (widget != NULL, NULL);
+  /*
+   * A GailWindow can be created for a GtkHandleBox or a GtkWindow
+   */
+  if (!GTK_IS_WINDOW (widget) &&
+      !GTK_IS_HANDLE_BOX (widget))
+    gail_return_val_if_fail (FALSE, NULL);
+
+  object = g_object_new (GAIL_TYPE_WINDOW, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, widget);
+
+  /*
+   * Notify that tooltip is showing
+   */
+  if (accessible->role == ATK_ROLE_TOOL_TIP &&
+      GTK_WIDGET_MAPPED (widget))
+    atk_object_notify_state_change (accessible, ATK_STATE_SHOWING, 1);
+
+  return accessible;
+}
+
+static void
+gail_window_real_initialize (AtkObject *obj,
+                             gpointer  data)
+{
+  GtkWidget *widget;
+  GailWindow *window;
+
+  ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+  window = GAIL_WINDOW (obj);
+  window->name_change_handler = 0;
+  window->previous_name = g_strdup (gtk_window_get_title (GTK_WINDOW (data)));
+  widget = GTK_WIDGET (data);
+
+  g_signal_connect (data,
+                    "window_state_event",
+                    G_CALLBACK (gail_window_state_event_gtk),
+                    NULL);
+  g_object_set_data (G_OBJECT (obj), "atk-component-layer",
+                     GINT_TO_POINTER (ATK_LAYER_WINDOW));
+
+  if (GTK_IS_FILE_SELECTION (widget))
+    obj->role = ATK_ROLE_FILE_CHOOSER;
+  else if (GTK_IS_COLOR_SELECTION_DIALOG (widget))
+    obj->role = ATK_ROLE_COLOR_CHOOSER;
+  else if (GTK_IS_FONT_SELECTION_DIALOG (widget))
+    obj->role = ATK_ROLE_FONT_CHOOSER;
+  else if (GTK_IS_MESSAGE_DIALOG (widget))
+    obj->role = ATK_ROLE_ALERT;
+  else if (GTK_IS_DIALOG (widget))
+    obj->role = ATK_ROLE_DIALOG;
+  else
+    {
+      const gchar *name;
+
+      name = gtk_widget_get_name (widget);
+      if (name && (!strcmp (name, "gtk-tooltip") ||
+                   !strcmp (name, "gtk-tooltips")))
+        obj->role = ATK_ROLE_TOOL_TIP;
+      else if (GTK_IS_PLUG (widget))
+        obj->role = ATK_ROLE_PANEL;
+      else if (GTK_WINDOW (widget)->type == GTK_WINDOW_POPUP)
+        obj->role = ATK_ROLE_WINDOW;
+      else
+        obj->role = ATK_ROLE_FRAME;
+    }
+}
+
+static void
+gail_window_finalize (GObject *object)
+{
+  GailWindow* window = GAIL_WINDOW (object);
+
+  if (window->name_change_handler)
+    {
+      g_source_remove (window->name_change_handler);
+      window->name_change_handler = 0;
+    }
+  if (window->previous_name)
+    {
+      g_free (window->previous_name);
+      window->previous_name = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static G_CONST_RETURN gchar*
+gail_window_get_name (AtkObject *accessible)
+{
+  G_CONST_RETURN gchar* name;
+
+  name = ATK_OBJECT_CLASS (parent_class)->get_name (accessible);
+  if (name == NULL)
+    {
+      /*
+       * Get the window title if it exists
+       */
+      GtkWidget* widget = GTK_ACCESSIBLE (accessible)->widget; 
+
+      if (widget == NULL)
+        /*
+         * State is defunct
+         */
+        return NULL;
+
+      gail_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+      if (GTK_IS_WINDOW (widget))
+        {
+          GtkWindow *window = GTK_WINDOW (widget);
+          name = gtk_window_get_title (window);
+          if (name == NULL &&
+              accessible->role == ATK_ROLE_TOOL_TIP)
+            {
+              GtkWidget *child;
+
+              child = gtk_bin_get_child (GTK_BIN (window));
+              /* could be some kind of egg notification bubble thingy? */
+
+              /* Handle new GTK+ GNOME 2.20 tooltips */
+              if (GTK_IS_ALIGNMENT(child))
+                {
+                  child = gtk_bin_get_child (GTK_BIN (child));
+                  if (GTK_IS_BOX(child)) 
+                    {
+                      GList *children;
+                      guint count;
+                      children = gtk_container_get_children (child);
+                      count = g_list_length (children);
+                      if (count == 2) 
+                        {
+                          child = (GtkWidget *) g_list_nth_data (children, 1);
+                        }
+                      g_list_free (children);                
+                    }
+                }
+
+              if (!GTK_IS_LABEL (child)) 
+              { 
+                  g_message ("ATK_ROLE_TOOLTIP object found, but doesn't look like a tooltip.");
+                  return NULL;
+              }
+              name = gtk_label_get_text (GTK_LABEL (child));
+            }
+        }
+    }
+  return name;
+}
+
+static AtkObject*
+gail_window_get_parent (AtkObject *accessible)
+{
+  AtkObject* parent;
+
+  parent = ATK_OBJECT_CLASS (parent_class)->get_parent (accessible);
+
+  return parent;
+}
+
+static gint
+gail_window_get_index_in_parent (AtkObject *accessible)
+{
+  GtkWidget* widget = GTK_ACCESSIBLE (accessible)->widget; 
+  AtkObject* atk_obj = atk_get_root ();
+  gint index = -1;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return -1;
+
+  gail_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
+
+  index = ATK_OBJECT_CLASS (parent_class)->get_index_in_parent (accessible);
+  if (index != -1)
+    return index;
+
+  if (GTK_IS_WINDOW (widget))
+    {
+      GtkWindow *window = GTK_WINDOW (widget);
+      if (GAIL_IS_TOPLEVEL (atk_obj))
+        {
+         GailToplevel* toplevel = GAIL_TOPLEVEL (atk_obj);
+         index = g_list_index (toplevel->window_list, window);
+       }
+      else
+        {
+         int i, sibling_count = atk_object_get_n_accessible_children (atk_obj);
+         for (i = 0; i < sibling_count && index == -1; ++i)
+           {
+             AtkObject *child = atk_object_ref_accessible_child (atk_obj, i);
+             if (accessible == child) index = i;
+             g_object_unref (G_OBJECT (child));
+           }
+       }
+    }
+  return index;
+}
+
+static gboolean
+gail_window_real_focus_gtk (GtkWidget     *widget,
+                            GdkEventFocus *event)
+{
+  AtkObject* obj;
+
+  obj = gtk_widget_get_accessible (widget);
+  atk_object_notify_state_change (obj, ATK_STATE_ACTIVE, event->in);
+
+  return FALSE;
+}
+
+static AtkRelationSet*
+gail_window_ref_relation_set (AtkObject *obj)
+{
+  GtkWidget *widget;
+  AtkRelationSet *relation_set;
+  AtkObject *array[1];
+  AtkRelation* relation;
+  GtkWidget *current_widget;
+
+  gail_return_val_if_fail (GAIL_IS_WIDGET (obj), NULL);
+
+  widget = GTK_ACCESSIBLE (obj)->widget;
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return NULL;
+
+  relation_set = ATK_OBJECT_CLASS (parent_class)->ref_relation_set (obj);
+
+  if (atk_object_get_role (obj) == ATK_ROLE_TOOL_TIP)
+    {
+      relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_POPUP_FOR);
+
+      if (relation)
+        {
+          atk_relation_set_remove (relation_set, relation);
+        }
+      if (GTK_WIDGET_VISIBLE(widget) && gtk_tooltips_get_info_from_tip_window (GTK_WINDOW (widget), NULL, &current_widget))
+        {
+          array [0] = gtk_widget_get_accessible (current_widget);
+
+          relation = atk_relation_new (array, 1, ATK_RELATION_POPUP_FOR);
+          atk_relation_set_add (relation_set, relation);
+          g_object_unref (relation);
+        }
+    }
+  return relation_set;
+}
+
+static AtkStateSet*
+gail_window_ref_state_set (AtkObject *accessible)
+{
+  AtkStateSet *state_set;
+  GtkWidget *widget;
+  GtkWindow *window;
+  GdkWindowState state;
+
+  state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+  widget = GTK_ACCESSIBLE (accessible)->widget;
+  if (widget == NULL)
+    return state_set;
+
+  window = GTK_WINDOW (widget);
+
+  if (window->has_focus)
+    atk_state_set_add_state (state_set, ATK_STATE_ACTIVE);
+
+  if (widget->window)
+    {
+      state = gdk_window_get_state (widget->window);
+      if (state & GDK_WINDOW_STATE_ICONIFIED)
+        atk_state_set_add_state (state_set, ATK_STATE_ICONIFIED);
+    } 
+  if (gtk_window_get_modal (window))
+    atk_state_set_add_state (state_set, ATK_STATE_MODAL);
+
+  if (gtk_window_get_resizable (window))
+    atk_state_set_add_state (state_set, ATK_STATE_RESIZABLE);
+  return state_set;
+}
+
+static gboolean
+idle_notify_name_change (gpointer data)
+{
+  GailWindow *window;
+  AtkObject *obj;
+
+  GDK_THREADS_ENTER ();
+
+  window = GAIL_WINDOW (data);
+  window->name_change_handler = 0;
+  if (GTK_ACCESSIBLE (window)->widget == NULL)
+    {
+      GDK_THREADS_LEAVE ();
+      return FALSE;
+    }
+
+  obj = ATK_OBJECT (window);
+  if (obj->name == NULL)
+    {
+    /*
+     * The title has changed so notify a change in accessible-name
+     */
+      g_object_notify (G_OBJECT (obj), "accessible-name");
+    }
+  g_signal_emit_by_name (obj, "visible_data_changed");
+  GDK_THREADS_LEAVE ();
+  return FALSE;
+}
+
+static void
+gail_window_real_notify_gtk (GObject           *obj,
+                             GParamSpec                *pspec)
+{
+  GtkWidget *widget = GTK_WIDGET (obj);
+  AtkObject* atk_obj = gtk_widget_get_accessible (widget);
+  GailWindow *window = GAIL_WINDOW (atk_obj);
+  const gchar *name;
+  gboolean name_changed = FALSE;
+
+  if (strcmp (pspec->name, "title") == 0)
+    {
+      name = gtk_window_get_title (GTK_WINDOW (widget));
+      if (name)
+        {
+         if (window->previous_name == NULL ||
+             strcmp (name, window->previous_name) != 0)
+           name_changed = TRUE;
+        }
+      else if (window->previous_name != NULL)
+        name_changed = TRUE;
+
+      if (name_changed)
+        {
+          g_free (window->previous_name);
+          window->previous_name = g_strdup (name);
+       
+          if (window->name_change_handler == 0)
+            window->name_change_handler = g_idle_add (idle_notify_name_change, atk_obj);    
+        }
+    }
+  else
+    GAIL_WIDGET_CLASS (parent_class)->notify_gtk (obj, pspec);
+}
+
+static gboolean
+gail_window_state_event_gtk (GtkWidget           *widget,
+                             GdkEventWindowState *event)
+{
+  AtkObject* obj;
+
+  obj = gtk_widget_get_accessible (widget);
+  atk_object_notify_state_change (obj, ATK_STATE_ICONIFIED,
+                         (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) != 0);
+  return FALSE;
+}
+
+static void
+atk_component_interface_init (AtkComponentIface *iface)
+{
+  gail_return_if_fail (iface != NULL);
+
+  iface->get_extents = gail_window_get_extents;
+  iface->get_size = gail_window_get_size;
+  iface->get_mdi_zorder = gail_window_get_mdi_zorder;
+}
+
+static void
+gail_window_get_extents (AtkComponent  *component,
+                         gint          *x,
+                         gint          *y,
+                         gint          *width,
+                         gint          *height,
+                         AtkCoordType  coord_type)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget; 
+  GdkRectangle rect;
+  gint x_toplevel, y_toplevel;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return;
+
+  gail_return_if_fail (GTK_IS_WINDOW (widget));
+
+  if (!GTK_WIDGET_TOPLEVEL (widget))
+    {
+      AtkComponentIface *parent_iface;
+
+      parent_iface = (AtkComponentIface *) g_type_interface_peek_parent (ATK_COMPONENT_GET_IFACE (component));
+      parent_iface->get_extents (component, x, y, width, height, coord_type);
+      return;
+    }
+
+  gdk_window_get_frame_extents (widget->window, &rect);
+
+  *width = rect.width;
+  *height = rect.height;
+  if (!GTK_WIDGET_DRAWABLE (widget))
+    {
+      *x = G_MININT;
+      *y = G_MININT;
+      return;
+    }
+  *x = rect.x;
+  *y = rect.y;
+  if (coord_type == ATK_XY_WINDOW)
+    {
+      gdk_window_get_origin (widget->window, &x_toplevel, &y_toplevel);
+      *x -= x_toplevel;
+      *y -= y_toplevel;
+    }
+}
+
+static void
+gail_window_get_size (AtkComponent *component,
+                      gint         *width,
+                      gint         *height)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget; 
+  GdkRectangle rect;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return;
+
+  gail_return_if_fail (GTK_IS_WINDOW (widget));
+
+  if (!GTK_WIDGET_TOPLEVEL (widget))
+    {
+      AtkComponentIface *parent_iface;
+
+      parent_iface = (AtkComponentIface *) g_type_interface_peek_parent (ATK_COMPONENT_GET_IFACE (component));
+      parent_iface->get_size (component, width, height);
+      return;
+    }
+  gdk_window_get_frame_extents (widget->window, &rect);
+
+  *width = rect.width;
+  *height = rect.height;
+}
+
+#if defined (GDK_WINDOWING_X11)
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <gdk/x11/gdkx.h>
+
+/* _NET_CLIENT_LIST_STACKING monitoring */
+
+typedef struct {
+  Window     *stacked_windows;
+  int         stacked_windows_len;
+  GdkWindow  *root_window;
+  guint       update_handler;
+  int        *desktop;
+  guint       update_desktop_handler;
+  gboolean   *desktop_changed;
+
+  guint       screen_initialized : 1;
+  guint       update_stacked_windows : 1;
+} GailScreenInfo;
+
+static GailScreenInfo *gail_screens = NULL;
+static int             num_screens = 0;
+static Atom            _net_client_list_stacking = None;
+static Atom            _net_wm_desktop = None;
+
+static gint
+get_window_desktop (Window window)
+{
+  Atom            ret_type;
+  int             format;
+  gulong          nitems;
+  gulong          bytes_after;
+  guchar         *cardinals;
+  int             error;
+  int             result;
+  int             desktop;
+
+  if (_net_wm_desktop == None)
+    _net_wm_desktop =
+               XInternAtom (gdk_display, "_NET_WM_DESKTOP", False);
+
+  gdk_error_trap_push ();
+  result = XGetWindowProperty (gdk_display, window, _net_wm_desktop,
+                               0, G_MAXLONG,
+                               False, XA_CARDINAL,
+                               &ret_type, &format, &nitems,
+                               &bytes_after, &cardinals);
+  error = gdk_error_trap_pop();
+  /* nitems < 1 will occur if the property is not set */
+  if (error != Success || result != Success || nitems < 1)
+    return -1;
+
+  desktop = *cardinals;
+
+  XFree (cardinals);
+  if (nitems != 1)
+    return -1;
+  return desktop;
+}
+
+static void
+free_screen_info (GailScreenInfo *info)
+{
+  if (info->stacked_windows)
+    XFree (info->stacked_windows);
+  if (info->desktop)
+    g_free (info->desktop);
+  if (info->desktop_changed)
+    g_free (info->desktop_changed);
+
+  info->stacked_windows = NULL;
+  info->stacked_windows_len = 0;
+  info->desktop = NULL;
+  info->desktop_changed = NULL;
+}
+
+static gboolean
+get_stacked_windows (GailScreenInfo *info)
+{
+  Atom    ret_type;
+  int     format;
+  gulong  nitems;
+  gulong  bytes_after;
+  guchar *data;
+  int     error;
+  int     result;
+  int     i;
+  int     j;
+  int    *desktops;
+  gboolean *desktops_changed;
+
+  if (_net_client_list_stacking == None)
+    _net_client_list_stacking =
+               XInternAtom (gdk_display, "_NET_CLIENT_LIST_STACKING", False);
+
+  gdk_error_trap_push ();
+  ret_type = None;
+  result = XGetWindowProperty (gdk_display,
+                               GDK_WINDOW_XWINDOW (info->root_window),
+                               _net_client_list_stacking,
+                               0, G_MAXLONG,
+                               False, XA_WINDOW, &ret_type, &format, &nitems,
+                               &bytes_after, &data);
+  error = gdk_error_trap_pop ();
+  /* nitems < 1 will occur if the property is not set */
+  if (error != Success || result != Success || nitems < 1)
+    {
+      free_screen_info (info);
+      return FALSE;
+    }
+
+  if (ret_type != XA_WINDOW)
+    {
+      XFree (data);
+      free_screen_info (info);
+      return FALSE;
+    }
+
+  desktops = g_malloc0 (nitems * sizeof (int));
+  desktops_changed = g_malloc0 (nitems * sizeof (gboolean));
+  for (i = 0; i < nitems; i++)
+    {
+      gboolean window_found = FALSE;
+
+      for (j = 0; j < info->stacked_windows_len; j++)
+        {
+          if (info->stacked_windows [j] == data [i])
+            {
+              desktops [i] = info->desktop [j];
+              desktops_changed [i] = info->desktop_changed [j];
+              window_found = TRUE;
+              break;
+            }
+        }
+      if (!window_found)
+        {
+          desktops [i] = get_window_desktop (data [i]);
+          desktops_changed [i] = FALSE;
+        }
+    }
+  free_screen_info (info);
+  info->stacked_windows = (Window*) data;
+  info->stacked_windows_len = nitems;
+  info->desktop = desktops;
+  info->desktop_changed = desktops_changed;
+
+  return TRUE;
+}
+
+static gboolean
+update_screen_info (gpointer data)
+{
+  int screen_n = GPOINTER_TO_INT (data);
+
+  GDK_THREADS_ENTER ();
+
+  gail_screens [screen_n].update_handler = 0;
+  gail_screens [screen_n].update_stacked_windows = FALSE;
+
+  get_stacked_windows (&gail_screens [screen_n]);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gboolean
+update_desktop_info (gpointer data)
+{
+  int screen_n = GPOINTER_TO_INT (data);
+  GailScreenInfo *info;
+  int i;
+
+  GDK_THREADS_ENTER ();
+
+  info = &gail_screens [screen_n];
+  info->update_desktop_handler = 0;
+
+  for (i = 0; i < info->stacked_windows_len; i++)
+    {
+      if (info->desktop_changed [i])
+        {
+          info->desktop [i] = get_window_desktop (info->stacked_windows [i]);
+          info->desktop_changed [i] = FALSE;
+        }
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static GdkFilterReturn
+filter_func (GdkXEvent *gdkxevent,
+            GdkEvent  *event,
+            gpointer   data)
+{
+  XEvent *xevent = gdkxevent;
+
+  if (xevent->type == PropertyNotify)
+    {
+      if (xevent->xproperty.atom == _net_client_list_stacking)
+        {
+          int     screen_n;
+          GdkWindow *window;
+
+          window = event->any.window;
+
+          if (window)
+            {
+              screen_n = gdk_screen_get_number (
+                  gdk_drawable_get_screen (GDK_DRAWABLE (window)));
+
+              gail_screens [screen_n].update_stacked_windows = TRUE;
+              if (!gail_screens [screen_n].update_handler)
+                {
+                  gail_screens [screen_n].update_handler = g_idle_add (update_screen_info,
+                                                                      GINT_TO_POINTER (screen_n));
+                }
+            }
+        }
+      else if (xevent->xproperty.atom == _net_wm_desktop)
+        {
+          int     i;
+          int     j;
+          GailScreenInfo *info;
+
+          for (i = 0; i < num_screens; i++)
+            {
+              info = &gail_screens [i];
+              for (j = 0; j < info->stacked_windows_len; j++)
+                {
+                  if (xevent->xany.window == info->stacked_windows [j])
+                    {
+                      info->desktop_changed [j] = TRUE;
+                      if (!info->update_desktop_handler)
+                        {
+                          info->update_desktop_handler = g_idle_add (update_desktop_info, 
+                                                                     GINT_TO_POINTER (i));
+                        }
+                      break;
+                    }
+                }
+            }
+        }
+    }
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+display_closed (GdkDisplay *display,
+               gboolean    is_error)
+{
+  int i;
+
+  for (i = 0; i < num_screens; i++)
+    {
+      if (gail_screens [i].update_handler)
+       {
+         g_source_remove (gail_screens [i].update_handler);
+         gail_screens [i].update_handler = 0;
+       }
+
+      if (gail_screens [i].update_desktop_handler)
+       {
+         g_source_remove (gail_screens [i].update_desktop_handler);
+         gail_screens [i].update_desktop_handler = 0;
+       }
+
+      free_screen_info (&gail_screens [i]);
+    }
+
+  g_free (gail_screens);
+  gail_screens = NULL;
+  num_screens = 0;
+}
+
+static void
+init_gail_screens (void)
+{
+  GdkDisplay *display;
+
+  display = gdk_display_get_default ();
+
+  num_screens = gdk_display_get_n_screens (display);
+
+  gail_screens = g_new0 (GailScreenInfo, num_screens);
+  gdk_window_add_filter (NULL, filter_func, NULL);
+
+  g_signal_connect (display, "closed", G_CALLBACK (display_closed), NULL);
+}
+
+static void
+init_gail_screen (GdkScreen *screen,
+                  int        screen_n)
+{
+  XWindowAttributes attrs;
+
+  gail_screens [screen_n].root_window = gdk_screen_get_root_window (screen);
+
+  get_stacked_windows (&gail_screens [screen_n]);
+
+  XGetWindowAttributes (gdk_display,
+                       GDK_WINDOW_XWINDOW (gail_screens [screen_n].root_window),
+                       &attrs); 
+
+  XSelectInput (gdk_display,
+               GDK_WINDOW_XWINDOW (gail_screens [screen_n].root_window),
+               attrs.your_event_mask | PropertyChangeMask);
+           
+  gail_screens [screen_n].screen_initialized = TRUE;
+}
+
+static GailScreenInfo *
+get_screen_info (GdkScreen *screen)
+{
+  int screen_n;
+
+  gail_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  screen_n = gdk_screen_get_number (screen);
+
+  if (gail_screens && gail_screens [screen_n].screen_initialized)
+    return &gail_screens [screen_n];
+
+  if (!gail_screens)
+    init_gail_screens ();
+
+  g_assert (gail_screens != NULL);
+
+  init_gail_screen (screen, screen_n);
+
+  g_assert (gail_screens [screen_n].screen_initialized);
+
+  return &gail_screens [screen_n];
+}
+
+static gint
+get_window_zorder (GdkWindow *window)
+{
+  GailScreenInfo *info;
+  Window          xid;
+  int             i;
+  int             zorder;
+  int             w_desktop;
+
+  gail_return_val_if_fail (GDK_IS_WINDOW (window), -1);
+
+  info = get_screen_info (
+               gdk_drawable_get_screen (GDK_DRAWABLE (window)));
+
+  gail_return_val_if_fail (info->stacked_windows != NULL, -1);
+
+  xid = GDK_WINDOW_XID (window);
+
+  w_desktop = -1;
+  for (i = 0; i < info->stacked_windows_len; i++)
+    {
+      if (info->stacked_windows [i] == xid)
+        {
+          w_desktop = info->desktop[i];
+          break;
+        }
+    }
+  if (w_desktop < 0)
+    return w_desktop;
+
+  zorder = 0;
+  for (i = 0; i < info->stacked_windows_len; i++)
+    {
+      if (info->stacked_windows [i] == xid)
+        {
+          return zorder;
+        }
+      else
+        {
+          if (info->desktop[i] == w_desktop)
+            zorder++;
+        }
+     }
+
+  return -1;
+}
+
+static gint
+gail_window_get_mdi_zorder (AtkComponent *component)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return -1;
+
+  gail_return_val_if_fail (GTK_IS_WINDOW (widget), -1);
+
+  return get_window_zorder (widget->window);
+}
+
+#elif defined (GDK_WINDOWING_WIN32)
+
+static gint
+gail_window_get_mdi_zorder (AtkComponent *component)
+{
+  GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
+
+  if (widget == NULL)
+    /*
+     * State is defunct
+     */
+    return -1;
+
+  gail_return_val_if_fail (GTK_IS_WINDOW (widget), -1);
+
+  return 0;                    /* Punt, FIXME */
+}
+
+#else
+#error Port to this GDK backend
+#endif
diff --git a/modules/other/gail/gailwindow.h b/modules/other/gail/gailwindow.h
new file mode 100644 (file)
index 0000000..289f83d
--- /dev/null
@@ -0,0 +1,63 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_WINDOW_H__
+#define __GAIL_WINDOW_H__
+
+#include <gtk/gtkaccessible.h>
+#include <gail/gailcontainer.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAIL_TYPE_WINDOW                        (gail_window_get_type ())
+#define GAIL_WINDOW(obj)                        (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_WINDOW, GailWindow))
+#define GAIL_WINDOW_CLASS(klass)                (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_WINDOW, GailWindowClass))
+#define GAIL_IS_WINDOW(obj)                     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_WINDOW))
+#define GAIL_IS_WINDOW_CLASS(klass)             (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_WINDOW))
+#define GAIL_WINDOW_GET_CLASS(obj)              (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_WINDOW, GailWindowClass))
+
+typedef struct _GailWindow                   GailWindow;
+typedef struct _GailWindowClass              GailWindowClass;
+
+struct _GailWindow
+{
+  GailContainer parent;
+
+  guint name_change_handler;
+  gchar *previous_name;
+};
+
+GType gail_window_get_type (void);
+
+struct _GailWindowClass
+{
+  GailContainerClass parent_class;
+};
+
+AtkObject* gail_window_new (GtkWidget *widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GAIL_WINDOW_H__ */
diff --git a/modules/other/gail/libgail-util/Makefile.am b/modules/other/gail/libgail-util/Makefile.am
new file mode 100644 (file)
index 0000000..428ac9e
--- /dev/null
@@ -0,0 +1,76 @@
+include $(top_srcdir)/Makefile.decl
+
+EXTRA_DIST += gailutil.def
+if OS_WIN32
+export_symbols = -export-symbols gailutil.def
+no_undefined = -no-undefined
+install-libtool-import-lib:
+       $(INSTALL) .libs/libgailutil.dll.a $(DESTDIR)$(libdir)
+uninstall-libtool-import-lib:
+       -rm $(DESTDIR)$(libdir)/libgailutil.dll.a
+else
+install-libtool-import-lib:
+uninstall-libtool-import-lib:
+endif
+
+if MS_LIB_AVAILABLE
+noinst_DATA = gailutil.lib
+
+install-ms-lib:
+       $(INSTALL) gailutil.lib $(DESTDIR)$(libdir)
+
+uninstall-ms-lib:
+       -rm $(DESTDIR)$(libdir)/gailutil.lib
+else
+install-ms-lib:
+uninstall-ms-lib:
+endif
+
+
+lib_LTLIBRARIES = libgailutil.la
+
+util_c_sources =               \
+       gailmisc.c              \
+       gailtextutil.c
+
+libgailutilincludedir=$(includedir)/gail-1.0/libgail-util
+
+util_public_h_sources =                \
+       gailmisc.h              \
+       gailtextutil.h          \
+       gail-util.h
+
+libgailutil_la_SOURCES =       \
+       $(util_c_sources)
+
+libgailutilinclude_HEADERS =   \
+       $(util_public_h_sources)
+
+libgailutil_la_CPPFLAGS = \
+       -I$(top_srcdir)/gdk     \
+       -I$(top_builddir)/gdk   \
+       -I$(top_srcdir)/gtk     \
+       -I$(top_builddir)/gtk   \
+       $(AM_CPPFLAGS)
+
+libgailutil_la_CFLAGS = \
+       $(GTK_DEP_CFLAGS)       \
+       $(GTK_DEBUG_FLAGS)      \
+       $(AM_CFLAGS)
+
+libgailutil_la_LIBADD = \
+       $(GTK_DEP_LIBS)
+
+libgailutil_la_LDFLAGS = \
+       -version-info $(LT_VERSION_INFO)        \
+       $(no_undefined)                         \
+       $(export_symbols)                       \
+        $(LDFLAGS)
+
+gailutil.lib: libgailutil.la gailutil.def
+       lib -name:libgailutil-@LT_CURRENT_MINUS_AGE@.dll -def:gailutil.def -out:$@
+
+install-data-local: install-ms-lib install-libtool-import-lib
+
+uninstall-local: uninstall-ms-lib uninstall-libtool-import-lib
+
diff --git a/modules/other/gail/libgail-util/gail-util.h b/modules/other/gail/libgail-util/gail-util.h
new file mode 100644 (file)
index 0000000..87824f6
--- /dev/null
@@ -0,0 +1,2 @@
+#include <libgail-util/gailmisc.h>
+#include <libgail-util/gailtextutil.h>
diff --git a/modules/other/gail/libgail-util/gailmisc.c b/modules/other/gail/libgail-util/gailmisc.c
new file mode 100644 (file)
index 0000000..cd02743
--- /dev/null
@@ -0,0 +1,1112 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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.
+ */
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include "gailmisc.h"
+
+/* IMPORTANT!!! This source file does NOT contain the implementation
+ * code for AtkUtil - for that code, please see gail/gail.c.
+ */
+
+/**
+ * gail_misc_get_extents_from_pango_rectangle:
+ * @widget: The widget that contains the PangoLayout, that contains
+ *   the PangoRectangle
+ * @char_rect: The #PangoRectangle from which to calculate extents
+ * @x_layout: The x-offset at which the widget displays the
+ *   PangoLayout that contains the PangoRectangle, relative to @widget
+ * @y_layout: The y-offset at which the widget displays the
+ *   PangoLayout that contains the PangoRectangle, relative to @widget
+ * @x: The x-position of the #PangoRectangle relative to @coords
+ * @y: The y-position of the #PangoRectangle relative to @coords
+ * @width: The width of the #PangoRectangle
+ * @height: The  height of the #PangoRectangle
+ * @coords: An #AtkCoordType enumeration
+ *
+ * Gets the extents of @char_rect in device coordinates,
+ * relative to either top-level window or screen coordinates as
+ * specified by @coords.
+ **/
+void
+gail_misc_get_extents_from_pango_rectangle (GtkWidget      *widget,
+                                            PangoRectangle *char_rect,
+                                            gint           x_layout,
+                                            gint           y_layout,
+                                            gint           *x,
+                                            gint           *y,
+                                            gint           *width,
+                                            gint           *height,
+                                            AtkCoordType   coords)
+{
+  gint x_window, y_window, x_toplevel, y_toplevel;
+
+  gail_misc_get_origins (widget, &x_window, &y_window, 
+                         &x_toplevel, &y_toplevel);
+
+  *x = (char_rect->x / PANGO_SCALE) + x_layout + x_window;
+  *y = (char_rect->y / PANGO_SCALE) + y_layout + y_window;
+  if (coords == ATK_XY_WINDOW)
+    {
+      *x -= x_toplevel;
+      *y -= y_toplevel;
+    }
+  else if (coords != ATK_XY_SCREEN)
+    {
+      *x = 0;
+      *y = 0;
+      *height = 0;
+      *width = 0;
+      return;
+    }
+  *height = char_rect->height / PANGO_SCALE;
+  *width = char_rect->width / PANGO_SCALE;
+
+  return;
+}
+
+/**
+ * gail_misc_get_index_at_point_in_layout:
+ * @widget: A #GtkWidget
+ * @layout: The #PangoLayout from which to get the index at the
+ *   specified point.
+ * @x_layout: The x-offset at which the widget displays the
+ *   #PangoLayout, relative to @widget
+ * @y_layout: The y-offset at which the widget displays the
+ *   #PangoLayout, relative to @widget
+ * @x: The x-coordinate relative to @coords at which to
+ *   calculate the index
+ * @y: The y-coordinate relative to @coords at which to
+ *   calculate the index
+ * @coords: An #AtkCoordType enumeration
+ *
+ * Gets the byte offset at the specified @x and @y in a #PangoLayout.
+ *
+ * Returns: the byte offset at the specified @x and @y in a
+ *   #PangoLayout
+ **/
+gint
+gail_misc_get_index_at_point_in_layout (GtkWidget   *widget,
+                                        PangoLayout *layout,
+                                        gint        x_layout,
+                                        gint        y_layout,
+                                        gint        x,
+                                        gint        y,
+                                        AtkCoordType coords)
+{
+  gint index, x_window, y_window, x_toplevel, y_toplevel;
+  gint x_temp, y_temp;
+  gboolean ret;
+
+  gail_misc_get_origins (widget, &x_window, &y_window, 
+                         &x_toplevel, &y_toplevel);
+  x_temp =  x - x_layout - x_window;
+  y_temp =  y - y_layout - y_window;
+  if (coords == ATK_XY_WINDOW)
+    {
+      x_temp += x_toplevel;  
+      y_temp += y_toplevel;
+    }
+  else if (coords != ATK_XY_SCREEN)
+    return -1;
+
+  ret = pango_layout_xy_to_index (layout, 
+                                  x_temp * PANGO_SCALE,
+                                  y_temp * PANGO_SCALE,
+                                  &index, NULL);
+  if (!ret)
+    {
+      if (x_temp < 0 || y_temp < 0)
+        index = 0;
+      else
+        index = -1; 
+    }
+  return index;
+}
+
+/**
+ * gail_misc_add_attribute:
+ * @attrib_set: The #AtkAttributeSet to add the attribute to
+ * @attr: The AtkTextAttrribute which identifies the attribute to be added
+ * @value: The attribute value
+ *
+ * Creates an #AtkAttribute from @attr and @value, and adds it
+ * to @attrib_set. 
+ *
+ * Returns: A pointer to the new #AtkAttributeSet.
+ **/
+AtkAttributeSet*
+gail_misc_add_attribute (AtkAttributeSet *attrib_set,
+                         AtkTextAttribute attr,
+                         gchar           *value)
+{
+  AtkAttributeSet *return_set;
+  AtkAttribute *at = g_malloc (sizeof (AtkAttribute));
+  at->name = g_strdup (atk_text_attribute_get_name (attr));
+  at->value = value;
+  return_set = g_slist_prepend(attrib_set, at);
+  return return_set;
+}
+
+/**
+ * gail_misc_layout_get_run_attributes:
+ * @attrib_set: The #AtkAttributeSet to add the attribute to
+ * @layout: The PangoLayout from which the attributes will be obtained
+ * @text: The text 
+ * @offset: The offset at which the attributes are required
+ * @start_offset: The start offset of the current run
+ * @end_offset: The end offset of the current run
+ *
+ * Adds the attributes for the run starting at offset to the specified
+ * attribute set.
+ *
+ * Returns: A pointer to the #AtkAttributeSet.
+ **/
+AtkAttributeSet* 
+gail_misc_layout_get_run_attributes (AtkAttributeSet *attrib_set,
+                                     PangoLayout     *layout,
+                                     gchar           *text,
+                                     gint            offset,
+                                     gint            *start_offset,
+                                     gint            *end_offset)
+{
+  PangoAttrIterator *iter;
+  PangoAttrList *attr;  
+  PangoAttrString *pango_string;
+  PangoAttrInt *pango_int;
+  PangoAttrColor *pango_color;
+  PangoAttrLanguage *pango_lang;
+  PangoAttrFloat *pango_float;
+  gint index, start_index, end_index;
+  gboolean is_next = TRUE;
+  gchar *value = NULL;
+  glong len;
+
+  len = g_utf8_strlen (text, -1);
+  /* Grab the attributes of the PangoLayout, if any */
+  if ((attr = pango_layout_get_attributes (layout)) == NULL)
+    {
+      *start_offset = 0;
+      *end_offset = len;
+      return attrib_set;
+    }
+  iter = pango_attr_list_get_iterator (attr);
+  /* Get invariant range offsets */
+  /* If offset out of range, set offset in range */
+  if (offset > len)
+    offset = len;
+  else if (offset < 0)
+    offset = 0;
+
+  index = g_utf8_offset_to_pointer (text, offset) - text;
+  pango_attr_iterator_range (iter, &start_index, &end_index);
+  while (is_next)
+    {
+      if (index >= start_index && index < end_index)
+        {
+          *start_offset = g_utf8_pointer_to_offset (text, 
+                                                    text + start_index);  
+          if (end_index == G_MAXINT)
+          /* Last iterator */
+            end_index = len;
+      
+          *end_offset = g_utf8_pointer_to_offset (text, 
+                                                  text + end_index);  
+          break;
+        }  
+      is_next = pango_attr_iterator_next (iter);
+      pango_attr_iterator_range (iter, &start_index, &end_index);
+    }
+  /* Get attributes */
+  if ((pango_string = (PangoAttrString*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_FAMILY)) != NULL)
+    {
+      value = g_strdup_printf("%s", pango_string->value);
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_FAMILY_NAME, 
+                                            value);
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_STYLE)) != NULL)
+    {
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_STYLE, 
+      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, pango_int->value)));
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_WEIGHT)) != NULL)
+    {
+      value = g_strdup_printf("%i", pango_int->value);
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_WEIGHT, 
+                                            value);
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_VARIANT)) != NULL)
+    {
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_VARIANT, 
+       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, pango_int->value)));
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_STRETCH)) != NULL)
+    {
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_STRETCH, 
+       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, pango_int->value)));
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_SIZE)) != NULL)
+    {
+      value = g_strdup_printf("%i", pango_int->value / PANGO_SCALE);
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_SIZE,
+                                            value);
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_UNDERLINE)) != NULL)
+    {
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_UNDERLINE, 
+       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, pango_int->value)));
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_STRIKETHROUGH)) != NULL)
+    {
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_STRIKETHROUGH, 
+       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, pango_int->value)));
+    } 
+  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_RISE)) != NULL)
+    {
+      value = g_strdup_printf("%i", pango_int->value);
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_RISE,
+                                            value);
+    } 
+  if ((pango_lang = (PangoAttrLanguage*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_LANGUAGE)) != NULL)
+    {
+      value = g_strdup( pango_language_to_string( pango_lang->value));
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_LANGUAGE, 
+                                            value);
+    } 
+  if ((pango_float = (PangoAttrFloat*) pango_attr_iterator_get (iter, 
+                                   PANGO_ATTR_SCALE)) != NULL)
+    {
+      value = g_strdup_printf("%g", pango_float->value);
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_SCALE, 
+                                            value);
+    } 
+  if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, 
+                                    PANGO_ATTR_FOREGROUND)) != NULL)
+    {
+      value = g_strdup_printf ("%u,%u,%u", 
+                               pango_color->color.red, 
+                               pango_color->color.green, 
+                               pango_color->color.blue);
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_FG_COLOR, 
+                                            value);
+    } 
+  if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, 
+                                     PANGO_ATTR_BACKGROUND)) != NULL)
+    {
+      value = g_strdup_printf ("%u,%u,%u", 
+                               pango_color->color.red, 
+                               pango_color->color.green, 
+                               pango_color->color.blue);
+      attrib_set = gail_misc_add_attribute (attrib_set, 
+                                            ATK_TEXT_ATTR_BG_COLOR, 
+                                            value);
+    } 
+  pango_attr_iterator_destroy (iter);
+  return attrib_set;
+}
+
+/**
+ * gail_misc_get_default_attributes:
+ * @attrib_set: The #AtkAttributeSet to add the attribute to
+ * @layout: The PangoLayout from which the attributes will be obtained
+ * @widget: The GtkWidget for which the default attributes are required.
+ *
+ * Adds the default attributes to the specified attribute set.
+ *
+ * Returns: A pointer to the #AtkAttributeSet.
+ **/
+AtkAttributeSet* 
+gail_misc_get_default_attributes (AtkAttributeSet *attrib_set,
+                                  PangoLayout     *layout,
+                                  GtkWidget       *widget)
+{
+  PangoContext *context;
+  GtkStyle *style_value;
+  gint int_value;
+  PangoWrapMode mode;
+
+  attrib_set = gail_misc_add_attribute (attrib_set, 
+                                        ATK_TEXT_ATTR_DIRECTION,
+     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, 
+                                        gtk_widget_get_direction (widget))));
+
+  context = pango_layout_get_context (layout);
+  if (context)
+    {
+      PangoLanguage* language;
+      PangoFontDescription* font;
+
+      language = pango_context_get_language (context);
+      if (language)
+        {
+          attrib_set = gail_misc_add_attribute (attrib_set,
+                                                ATK_TEXT_ATTR_LANGUAGE,
+                      g_strdup (pango_language_to_string (language)));
+        }
+      font = pango_context_get_font_description (context);
+      if (font)
+        {
+          attrib_set = gail_misc_add_attribute (attrib_set,
+                                                ATK_TEXT_ATTR_STYLE,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE,
+                                   pango_font_description_get_style (font))));
+          attrib_set = gail_misc_add_attribute (attrib_set,
+                                                ATK_TEXT_ATTR_VARIANT,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT,
+                                   pango_font_description_get_variant (font))));
+          attrib_set = gail_misc_add_attribute (attrib_set,
+                                                ATK_TEXT_ATTR_STRETCH,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH,
+                                   pango_font_description_get_stretch (font))));
+          attrib_set = gail_misc_add_attribute (attrib_set,
+                                                ATK_TEXT_ATTR_FAMILY_NAME,
+              g_strdup (pango_font_description_get_family (font)));
+          attrib_set = gail_misc_add_attribute (attrib_set,
+                                                ATK_TEXT_ATTR_WEIGHT,
+                    g_strdup_printf ("%d",
+                                   pango_font_description_get_weight (font)));
+          attrib_set = gail_misc_add_attribute (attrib_set,
+                                                ATK_TEXT_ATTR_SIZE,
+                    g_strdup_printf ("%i",
+                                   pango_font_description_get_size (font) / PANGO_SCALE));
+        }
+    }
+  if (pango_layout_get_justify (layout))
+    {
+      int_value = 3;
+    }
+  else
+    {
+      PangoAlignment align;
+
+      align = pango_layout_get_alignment (layout);
+      if (align == PANGO_ALIGN_LEFT)
+        int_value = 0;
+      else if (align == PANGO_ALIGN_CENTER)
+        int_value = 2;
+      else /* if (align == PANGO_ALIGN_RIGHT) */
+        int_value = 1;
+    }
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_JUSTIFICATION,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, 
+                                                      int_value))); 
+  mode = pango_layout_get_wrap (layout);
+  if (mode == PANGO_WRAP_WORD)
+    int_value = 2;
+  else /* if (mode == PANGO_WRAP_CHAR) */
+    int_value = 1;
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_WRAP_MODE,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, 
+                                                      int_value))); 
+
+  style_value = gtk_widget_get_style (widget);
+  if (style_value)
+    {
+      GdkColor color;
+      gchar *value;
+
+      color = style_value->base[GTK_STATE_NORMAL];
+      value = g_strdup_printf ("%u,%u,%u",
+                               color.red, color.green, color.blue);
+      attrib_set = gail_misc_add_attribute (attrib_set,
+                                            ATK_TEXT_ATTR_BG_COLOR,
+                                            value); 
+      color = style_value->text[GTK_STATE_NORMAL];
+      value = g_strdup_printf ("%u,%u,%u",
+                               color.red, color.green, color.blue);
+      attrib_set = gail_misc_add_attribute (attrib_set,
+                                            ATK_TEXT_ATTR_FG_COLOR,
+                                            value); 
+    }
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_FG_STIPPLE,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_FG_STIPPLE, 
+                                                      0))); 
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_BG_STIPPLE,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_STIPPLE, 
+                                                      0))); 
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_STRIKETHROUGH,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 
+                                                      0))); 
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_UNDERLINE,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, 
+                                                      0))); 
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_RISE,
+                                               g_strdup_printf ("%i", 0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_SCALE,
+                                               g_strdup_printf ("%g", 1.0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_BG_FULL_HEIGHT,
+                                               g_strdup_printf ("%i", 0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP,
+                                               g_strdup_printf ("%i", 0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_PIXELS_BELOW_LINES,
+                                        g_strdup_printf ("%i", 0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_PIXELS_ABOVE_LINES,
+                                        g_strdup_printf ("%i", 0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_EDITABLE,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 
+                                                      0))); 
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_INVISIBLE,
+              g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_INVISIBLE, 
+                                                      0))); 
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_INDENT,
+                                        g_strdup_printf ("%i", 0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_RIGHT_MARGIN,
+                                        g_strdup_printf ("%i", 0));
+  attrib_set = gail_misc_add_attribute (attrib_set,
+                                        ATK_TEXT_ATTR_LEFT_MARGIN,
+                                        g_strdup_printf ("%i", 0));
+  return attrib_set;
+}
+
+/**
+ * gail_misc_get_origins:
+ * @widget: a #GtkWidget
+ * @x_window: the x-origin of the widget->window
+ * @y_window: the y-origin of the widget->window
+ * @x_toplevel: the x-origin of the toplevel window for widget->window
+ * @y_toplevel: the y-origin of the toplevel window for widget->window
+ *
+ * Gets the origin of the widget window, and the origin of the
+ * widgets top-level window.
+ **/
+void
+gail_misc_get_origins (GtkWidget *widget,
+                       gint      *x_window,
+                       gint      *y_window,
+                       gint      *x_toplevel,
+                       gint      *y_toplevel)
+{
+  GdkWindow *window;
+
+  if (GTK_IS_TREE_VIEW (widget))
+    window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget));
+  else
+    window = widget->window;
+  gdk_window_get_origin (window, x_window, y_window);
+  window = gdk_window_get_toplevel (widget->window);
+  gdk_window_get_origin (window, x_toplevel, y_toplevel);
+}
+
+/**
+ * gail_misc_add_to_attr_set:
+ * @attrib_set: An #AtkAttributeSet
+ * @attrs: The #GtkTextAttributes containing the attribute value
+ * @attr: The #AtkTextAttribute to be added
+ *
+ * Gets the value for the AtkTextAttribute from the GtkTextAttributes
+ * and adds it to the AttributeSet.
+ *
+ * Returns: A pointer to the updated #AtkAttributeSet.
+ **/
+AtkAttributeSet*
+gail_misc_add_to_attr_set (AtkAttributeSet   *attrib_set,
+                           GtkTextAttributes *attrs,
+                           AtkTextAttribute  attr)
+{
+  gchar *value;
+
+  switch (attr)
+    {
+    case ATK_TEXT_ATTR_LEFT_MARGIN:
+      value = g_strdup_printf ("%i", attrs->left_margin);
+      break;
+    case ATK_TEXT_ATTR_RIGHT_MARGIN:
+      value = g_strdup_printf ("%i", attrs->right_margin);
+      break;
+    case ATK_TEXT_ATTR_INDENT:
+      value = g_strdup_printf ("%i", attrs->indent);
+      break;
+    case ATK_TEXT_ATTR_INVISIBLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->invisible));
+      break;
+    case ATK_TEXT_ATTR_EDITABLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->editable));
+      break;
+    case ATK_TEXT_ATTR_PIXELS_ABOVE_LINES:
+      value = g_strdup_printf ("%i", attrs->pixels_above_lines);
+      break;
+    case ATK_TEXT_ATTR_PIXELS_BELOW_LINES:
+      value = g_strdup_printf ("%i", attrs->pixels_below_lines);
+      break;
+    case ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP:
+      value = g_strdup_printf ("%i", attrs->pixels_inside_wrap);
+      break;
+    case ATK_TEXT_ATTR_BG_FULL_HEIGHT:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->bg_full_height));
+      break;
+    case ATK_TEXT_ATTR_RISE:
+      value = g_strdup_printf ("%i", attrs->appearance.rise);
+      break;
+    case ATK_TEXT_ATTR_UNDERLINE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.underline));
+      break;
+    case ATK_TEXT_ATTR_STRIKETHROUGH:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.strikethrough));
+      break;
+    case ATK_TEXT_ATTR_SIZE:
+      value = g_strdup_printf ("%i", 
+                              pango_font_description_get_size (attrs->font) / PANGO_SCALE);
+      break;
+    case ATK_TEXT_ATTR_SCALE:
+      value = g_strdup_printf ("%g", attrs->font_scale);
+      break;
+    case ATK_TEXT_ATTR_WEIGHT:
+      value = g_strdup_printf ("%d", 
+                              pango_font_description_get_weight (attrs->font));
+      break;
+    case ATK_TEXT_ATTR_LANGUAGE:
+      value = g_strdup ((gchar *)(attrs->language));
+      break;
+    case ATK_TEXT_ATTR_FAMILY_NAME:
+      value = g_strdup (pango_font_description_get_family (attrs->font));
+      break;
+    case ATK_TEXT_ATTR_BG_COLOR:
+      value = g_strdup_printf ("%u,%u,%u",
+                               attrs->appearance.bg_color.red,
+                               attrs->appearance.bg_color.green,
+                               attrs->appearance.bg_color.blue);
+      break;
+    case ATK_TEXT_ATTR_FG_COLOR:
+      value = g_strdup_printf ("%u,%u,%u",
+                               attrs->appearance.fg_color.red,
+                               attrs->appearance.fg_color.green,
+                               attrs->appearance.fg_color.blue);
+      break;
+    case ATK_TEXT_ATTR_BG_STIPPLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.bg_stipple ? 1 : 0));
+      break;
+    case ATK_TEXT_ATTR_FG_STIPPLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->appearance.fg_stipple ? 1 : 0));
+      break;
+    case ATK_TEXT_ATTR_WRAP_MODE:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->wrap_mode));
+      break;
+    case ATK_TEXT_ATTR_DIRECTION:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->direction));
+      break;
+    case ATK_TEXT_ATTR_JUSTIFICATION:
+      value = g_strdup (atk_text_attribute_get_value (attr, attrs->justification));
+      break;
+    case ATK_TEXT_ATTR_STRETCH:
+      value = g_strdup (atk_text_attribute_get_value (attr, 
+                        pango_font_description_get_stretch (attrs->font)));
+      break;
+    case ATK_TEXT_ATTR_VARIANT:
+      value = g_strdup (atk_text_attribute_get_value (attr, 
+                        pango_font_description_get_variant (attrs->font)));
+      break;
+    case ATK_TEXT_ATTR_STYLE:
+      value = g_strdup (atk_text_attribute_get_value (attr, 
+                        pango_font_description_get_style (attrs->font)));
+      break;
+    default:
+      value = NULL;
+      break;
+    }
+  return gail_misc_add_attribute (attrib_set, attr, value);
+}
+
+/**
+ * gail_misc_buffer_get_run_attributes:
+ * @buffer: The #GtkTextBuffer for which the attributes will be obtained
+ * @offset: The offset at which the attributes are required
+ * @start_offset: The start offset of the current run
+ * @end_offset: The end offset of the current run
+ *
+ * Creates an AtkAttributeSet which contains the attributes for the 
+ * run starting at offset.
+ *
+ * Returns: A pointer to the #AtkAttributeSet.
+ **/
+AtkAttributeSet*
+gail_misc_buffer_get_run_attributes (GtkTextBuffer *buffer,
+                                     gint          offset,
+                                     gint          *start_offset,
+                                     gint          *end_offset)
+{
+  GtkTextIter iter;
+  AtkAttributeSet *attrib_set = NULL;
+  AtkAttribute *at;
+  GSList *tags, *temp_tags;
+  gdouble scale = 1;
+  gboolean val_set = FALSE;
+  PangoFontMask mask;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
+
+  gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
+  *end_offset = gtk_text_iter_get_offset (&iter);
+
+  gtk_text_iter_backward_to_tag_toggle (&iter, NULL);
+  *start_offset = gtk_text_iter_get_offset (&iter);
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
+
+  tags = gtk_text_iter_get_tags (&iter);
+  tags = g_slist_reverse (tags);
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      PangoFontDescription *font;
+
+      font = tag->values->font;
+
+      if (font)
+        {
+          mask = pango_font_description_get_set_fields (font);
+          val_set = mask & PANGO_FONT_MASK_STYLE;
+          if (val_set)
+            attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                    ATK_TEXT_ATTR_STYLE);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      PangoFontDescription *font;
+
+      font = tag->values->font;
+
+      if (font)
+        {
+          mask = pango_font_description_get_set_fields (font);
+          val_set = mask & PANGO_FONT_MASK_VARIANT;
+          if (val_set)
+            attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                    ATK_TEXT_ATTR_VARIANT);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      PangoFontDescription *font;
+
+      font = tag->values->font;
+
+      if (font)
+        {
+          mask = pango_font_description_get_set_fields (font);
+          val_set = mask & PANGO_FONT_MASK_STRETCH;
+          if (val_set)
+            attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                    ATK_TEXT_ATTR_STRETCH);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->justification_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_JUSTIFICATION);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      if (tag->values->direction != GTK_TEXT_DIR_NONE)
+        {
+          val_set = TRUE;
+          attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                  ATK_TEXT_ATTR_DIRECTION);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->wrap_mode_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_WRAP_MODE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->fg_stipple_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_FG_STIPPLE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->bg_stipple_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_BG_STIPPLE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->fg_color_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_FG_COLOR);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+  
+      val_set = tag->bg_color_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_BG_COLOR);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      PangoFontDescription *font;
+
+      font = tag->values->font;
+
+      if (font)
+        {
+          mask = pango_font_description_get_set_fields (font);
+          val_set = mask & PANGO_FONT_MASK_FAMILY;
+          if (val_set)
+            attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                    ATK_TEXT_ATTR_FAMILY_NAME);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->language_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_LANGUAGE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      PangoFontDescription *font;
+
+      font = tag->values->font;
+
+      if (font)
+        {
+          mask = pango_font_description_get_set_fields (font);
+          val_set = mask & PANGO_FONT_MASK_WEIGHT;
+          if (val_set)
+            attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                    ATK_TEXT_ATTR_WEIGHT);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+
+  /*
+   * scale is special as the scale is the product of all scale values
+   * specified.
+   */
+  temp_tags = tags;
+  while (temp_tags)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      if (tag->scale_set)
+        {
+          val_set = TRUE;
+          scale *= tag->values->font_scale;
+        }
+      temp_tags = temp_tags->next;
+    }
+  if (val_set)
+    {
+      at = g_malloc(sizeof(AtkAttribute));
+      at->name = g_strdup(atk_text_attribute_get_name (ATK_TEXT_ATTR_SCALE));
+      at->value = g_strdup_printf("%g", scale);
+      attrib_set = g_slist_prepend(attrib_set, at);
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      PangoFontDescription *font;
+
+      font = tag->values->font;
+
+      if (font)
+        {
+          mask = pango_font_description_get_set_fields (font);
+          val_set = mask & PANGO_FONT_MASK_SIZE;
+          if (val_set)
+            attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                    ATK_TEXT_ATTR_SIZE);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->strikethrough_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_STRIKETHROUGH);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->underline_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_UNDERLINE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->rise_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_RISE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->bg_full_height_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_BG_FULL_HEIGHT);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->pixels_inside_wrap_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->pixels_below_lines_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_PIXELS_BELOW_LINES);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->pixels_above_lines_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_PIXELS_ABOVE_LINES);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->editable_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_EDITABLE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->invisible_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_INVISIBLE);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->indent_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_INDENT);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->right_margin_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_RIGHT_MARGIN);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      val_set = tag->left_margin_set;
+      if (val_set)
+        attrib_set = gail_misc_add_to_attr_set (attrib_set, tag->values, 
+                                                ATK_TEXT_ATTR_LEFT_MARGIN);
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  g_slist_free (tags);
+  return attrib_set;
+}
diff --git a/modules/other/gail/libgail-util/gailmisc.h b/modules/other/gail/libgail-util/gailmisc.h
new file mode 100644 (file)
index 0000000..ced98e6
--- /dev/null
@@ -0,0 +1,86 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_MISC_H__
+#define __GAIL_MISC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus */
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <pango/pango.h>
+
+AtkAttributeSet* gail_misc_add_attribute          (AtkAttributeSet   *attrib_set,
+                                                   AtkTextAttribute   attr,
+                                                   gchar             *value);
+AtkAttributeSet* gail_misc_layout_get_run_attributes
+                                                  (AtkAttributeSet   *attrib_set,
+                                                   PangoLayout       *layout,
+                                                   gchar             *text,
+                                                   gint              offset,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+
+AtkAttributeSet* gail_misc_get_default_attributes (AtkAttributeSet   *attrib_set,
+                                                   PangoLayout       *layout,
+                                                   GtkWidget         *widget);
+
+void             gail_misc_get_extents_from_pango_rectangle
+                                                  (GtkWidget         *widget,
+                                                   PangoRectangle    *char_rect,
+                                                   gint              x_layout,
+                                                   gint              y_layout,
+                                                   gint              *x,
+                                                  gint              *y,
+                                                   gint              *width,
+                                                   gint              *height,
+                                                   AtkCoordType      coords);
+
+gint             gail_misc_get_index_at_point_in_layout
+                                                  (GtkWidget         *widget,
+                                                   PangoLayout       *layout, 
+                                                   gint              x_layout,
+                                                   gint              y_layout,
+                                                   gint              x,
+                                                   gint              y,
+                                                   AtkCoordType      coords);
+
+void            gail_misc_get_origins            (GtkWidget         *widget,
+                                                   gint              *x_window,
+                                                  gint              *y_window,
+                                                  gint              *x_toplevel,
+                                                  gint              *y_toplevel);
+
+AtkAttributeSet* gail_misc_add_to_attr_set        (AtkAttributeSet   *attrib_set,
+                                                  GtkTextAttributes *attrs,
+                                                  AtkTextAttribute  attr);
+
+AtkAttributeSet* gail_misc_buffer_get_run_attributes
+                                                  (GtkTextBuffer     *buffer,
+                                                   gint              offset,
+                                                   gint              *start_offset,
+                                                   gint              *end_offset);
+
+#ifdef __cplusplus 
+}
+#endif /*cplusplus */
+
+#endif /*__GAIL_MISC_H__ */
diff --git a/modules/other/gail/libgail-util/gailtextutil.c b/modules/other/gail/libgail-util/gailtextutil.c
new file mode 100644 (file)
index 0000000..66fd9f1
--- /dev/null
@@ -0,0 +1,769 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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.
+ */
+
+#include <stdlib.h>
+#include "gailtextutil.h"
+
+static void gail_text_util_class_init      (GailTextUtilClass *klass);
+
+static void gail_text_util_init            (GailTextUtil      *textutil);
+static void gail_text_util_finalize        (GObject           *object);
+
+
+static void get_pango_text_offsets         (PangoLayout         *layout,
+                                            GtkTextBuffer       *buffer,
+                                            GailOffsetType      function,
+                                            AtkTextBoundary     boundary_type,
+                                            gint                offset,
+                                            gint                *start_offset,
+                                            gint                *end_offset,
+                                            GtkTextIter         *start_iter,
+                                            GtkTextIter         *end_iter);
+static GObjectClass *parent_class = NULL;
+
+GType
+gail_text_util_get_type(void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo tinfo =
+      {
+        sizeof (GailTextUtilClass),
+        (GBaseInitFunc) NULL, /* base init */
+        (GBaseFinalizeFunc) NULL, /* base finalize */
+        (GClassInitFunc) gail_text_util_class_init,
+        (GClassFinalizeFunc) NULL, /* class finalize */
+        NULL, /* class data */
+        sizeof(GailTextUtil),
+        0, /* nb preallocs */
+        (GInstanceInitFunc) gail_text_util_init,
+        NULL, /* value table */
+      };
+
+      type = g_type_register_static (G_TYPE_OBJECT, "GailTextUtil", &tinfo, 0);
+    }
+  return type;
+}
+
+/**
+ * gail_text_util_new:
+ *
+ * This function creates a new GailTextUtil object.
+ *
+ * Returns: the GailTextUtil object
+ **/
+GailTextUtil*
+gail_text_util_new (void)
+{
+  return GAIL_TEXT_UTIL (g_object_new (GAIL_TYPE_TEXT_UTIL, NULL));
+}
+
+static void
+gail_text_util_init (GailTextUtil *textutil)
+{
+  textutil->buffer = NULL;
+}
+
+static void
+gail_text_util_class_init (GailTextUtilClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = gail_text_util_finalize;
+}
+
+static void
+gail_text_util_finalize (GObject *object)
+{
+  GailTextUtil *textutil = GAIL_TEXT_UTIL (object);
+
+  if (textutil->buffer)
+    g_object_unref (textutil->buffer);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * gail_text_util_text_setup:
+ * @textutil: The #GailTextUtil to be initialized.
+ * @text: A gchar* which points to the text to be stored in the GailTextUtil
+ *
+ * This function initializes the GailTextUtil with the specified character string,
+ **/
+void
+gail_text_util_text_setup (GailTextUtil *textutil,
+                           const gchar  *text)
+{
+  g_return_if_fail (GAIL_IS_TEXT_UTIL (textutil));
+
+  if (textutil->buffer)
+    {
+      if (!text)
+        {
+          g_object_unref (textutil->buffer);
+          textutil->buffer = NULL;
+          return;
+        }
+    }
+  else
+    {
+      textutil->buffer = gtk_text_buffer_new (NULL);
+    }
+
+  gtk_text_buffer_set_text (textutil->buffer, text, -1);
+}
+
+/**
+ * gail_text_util_buffer_setup:
+ * @textutil: A #GailTextUtil to be initialized
+ * @buffer: The #GtkTextBuffer which identifies the text to be stored in the GailUtil.
+ *
+ * This function initializes the GailTextUtil with the specified GtkTextBuffer
+ **/
+void
+gail_text_util_buffer_setup  (GailTextUtil  *textutil,
+                              GtkTextBuffer   *buffer)
+{
+  g_return_if_fail (GAIL_IS_TEXT_UTIL (textutil));
+
+  textutil->buffer = g_object_ref (buffer);
+}
+
+/**
+ * gail_text_util_get_text:
+ * @textutil: A #GailTextUtil
+ * @layout: A gpointer which is a PangoLayout, a GtkTreeView of NULL
+ * @function: An enumeration specifying whether to return the text before, at, or
+ *   after the offset.
+ * @boundary_type: The boundary type.
+ * @offset: The offset of the text in the GailTextUtil 
+ * @start_offset: Address of location in which the start offset is returned
+ * @end_offset: Address of location in which the end offset is returned
+ *
+ * This function gets the requested substring from the text in the GtkTextUtil.
+ * The layout is used only for getting the text on a line. The value is NULL 
+ * for a GtkTextView which is not wrapped, is a GtkTextView for a GtkTextView 
+ * which is wrapped and is a PangoLayout otherwise.
+ *
+ * Returns: the substring requested
+ **/
+gchar*
+gail_text_util_get_text (GailTextUtil    *textutil,
+                         gpointer        layout,
+                         GailOffsetType  function,
+                         AtkTextBoundary boundary_type,
+                         gint            offset,
+                         gint            *start_offset,
+                         gint            *end_offset)
+{
+  GtkTextIter start, end;
+  gint line_number;
+  GtkTextBuffer *buffer;
+
+  g_return_val_if_fail (GAIL_IS_TEXT_UTIL (textutil), NULL);
+
+  buffer = textutil->buffer;
+  if (buffer == NULL)
+    {
+      *start_offset = 0;
+      *end_offset = 0;
+      return NULL;
+    }
+
+  if (!gtk_text_buffer_get_char_count (buffer))
+    {
+      *start_offset = 0;
+      *end_offset = 0;
+      return g_strdup ("");
+    }
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
+
+    
+  end = start;
+
+  switch (function)
+    {
+    case GAIL_BEFORE_OFFSET:
+      switch (boundary_type)
+        {
+        case ATK_TEXT_BOUNDARY_CHAR:
+          gtk_text_iter_backward_char(&start);
+          break;
+        case ATK_TEXT_BOUNDARY_WORD_START:
+          if (!gtk_text_iter_starts_word (&start))
+            gtk_text_iter_backward_word_start (&start);
+          end = start;
+          gtk_text_iter_backward_word_start(&start);
+          break;
+        case ATK_TEXT_BOUNDARY_WORD_END:
+          if (gtk_text_iter_inside_word (&start) &&
+              !gtk_text_iter_starts_word (&start))
+            gtk_text_iter_backward_word_start (&start);
+          while (!gtk_text_iter_ends_word (&start))
+            {
+              if (!gtk_text_iter_backward_char (&start))
+                break;
+            }
+          end = start;
+          gtk_text_iter_backward_word_start(&start);
+          while (!gtk_text_iter_ends_word (&start))
+            {
+              if (!gtk_text_iter_backward_char (&start))
+                break;
+            }
+          break;
+        case ATK_TEXT_BOUNDARY_SENTENCE_START:
+          if (!gtk_text_iter_starts_sentence (&start))
+            gtk_text_iter_backward_sentence_start (&start);
+          end = start;
+          gtk_text_iter_backward_sentence_start (&start);
+          break;
+        case ATK_TEXT_BOUNDARY_SENTENCE_END:
+          if (gtk_text_iter_inside_sentence (&start) &&
+              !gtk_text_iter_starts_sentence (&start))
+            gtk_text_iter_backward_sentence_start (&start);
+          while (!gtk_text_iter_ends_sentence (&start))
+            {
+              if (!gtk_text_iter_backward_char (&start))
+                break;
+            }
+          end = start;
+          gtk_text_iter_backward_sentence_start (&start);
+          while (!gtk_text_iter_ends_sentence (&start))
+            {
+              if (!gtk_text_iter_backward_char (&start))
+                break;
+            }
+          break;
+        case ATK_TEXT_BOUNDARY_LINE_START:
+          if (layout == NULL)
+            {
+              line_number = gtk_text_iter_get_line (&start);
+              if (line_number == 0)
+                {
+                  gtk_text_buffer_get_iter_at_offset (buffer,
+                    &start, 0);
+                }
+              else
+                {
+                  gtk_text_iter_backward_line (&start);
+                  gtk_text_iter_forward_line (&start);
+                }
+              end = start;
+              gtk_text_iter_backward_line (&start);
+            }
+          else if GTK_IS_TEXT_VIEW (layout)
+            {
+              GtkTextView *view = GTK_TEXT_VIEW (layout);
+
+              gtk_text_view_backward_display_line_start (view, &start);
+              end = start;
+              gtk_text_view_backward_display_line (view, &start);
+            }
+          else if (PANGO_IS_LAYOUT (layout))
+            get_pango_text_offsets (PANGO_LAYOUT (layout),
+                                    buffer,
+                                    function,
+                                    boundary_type,
+                                    offset,
+                                    start_offset,
+                                    end_offset,
+                                    &start,
+                                    &end);
+          break;
+        case ATK_TEXT_BOUNDARY_LINE_END:
+          if (layout == NULL)
+            {
+              line_number = gtk_text_iter_get_line (&start);
+              if (line_number == 0)
+                {
+                  gtk_text_buffer_get_iter_at_offset (buffer,
+                    &start, 0);
+                  end = start;
+                }
+              else
+                {
+                  gtk_text_iter_backward_line (&start);
+                  end = start;
+                  while (!gtk_text_iter_ends_line (&start))
+                    {
+                      if (!gtk_text_iter_backward_char (&start))
+                        break;
+                    }
+                  gtk_text_iter_forward_to_line_end (&end);
+                }
+            }
+          else if GTK_IS_TEXT_VIEW (layout)
+            {
+              GtkTextView *view = GTK_TEXT_VIEW (layout);
+
+              gtk_text_view_backward_display_line_start (view, &start);
+              if (!gtk_text_iter_is_start (&start))
+                {
+                  gtk_text_view_backward_display_line (view, &start);
+                  end = start;
+                  if (!gtk_text_iter_is_start (&start))
+                    {
+                      gtk_text_view_backward_display_line (view, &start);
+                      gtk_text_view_forward_display_line_end (view, &start);
+                    }
+                  gtk_text_view_forward_display_line_end (view, &end);
+                } 
+              else
+                {
+                  end = start;
+                }
+            }
+          else if (PANGO_IS_LAYOUT (layout))
+            get_pango_text_offsets (PANGO_LAYOUT (layout),
+                                    buffer,
+                                    function,
+                                    boundary_type,
+                                    offset,
+                                    start_offset,
+                                    end_offset,
+                                    &start,
+                                    &end);
+          break;
+        }
+      break;
+    case GAIL_AT_OFFSET:
+      switch (boundary_type)
+        {
+        case ATK_TEXT_BOUNDARY_CHAR:
+          gtk_text_iter_forward_char (&end);
+          break;
+        case ATK_TEXT_BOUNDARY_WORD_START:
+          if (!gtk_text_iter_starts_word (&start))
+            gtk_text_iter_backward_word_start (&start);
+          if (gtk_text_iter_inside_word (&end))
+            gtk_text_iter_forward_word_end (&end);
+          while (!gtk_text_iter_starts_word (&end))
+            {
+              if (!gtk_text_iter_forward_char (&end))
+                break;
+            }
+          break;
+        case ATK_TEXT_BOUNDARY_WORD_END:
+          if (gtk_text_iter_inside_word (&start) &&
+              !gtk_text_iter_starts_word (&start))
+            gtk_text_iter_backward_word_start (&start);
+          while (!gtk_text_iter_ends_word (&start))
+            {
+              if (!gtk_text_iter_backward_char (&start))
+                break;
+            }
+          gtk_text_iter_forward_word_end (&end);
+          break;
+        case ATK_TEXT_BOUNDARY_SENTENCE_START:
+          if (!gtk_text_iter_starts_sentence (&start))
+            gtk_text_iter_backward_sentence_start (&start);
+          if (gtk_text_iter_inside_sentence (&end))
+            gtk_text_iter_forward_sentence_end (&end);
+          while (!gtk_text_iter_starts_sentence (&end))
+            {
+              if (!gtk_text_iter_forward_char (&end))
+                break;
+            }
+          break;
+        case ATK_TEXT_BOUNDARY_SENTENCE_END:
+          if (gtk_text_iter_inside_sentence (&start) &&
+              !gtk_text_iter_starts_sentence (&start))
+            gtk_text_iter_backward_sentence_start (&start);
+          while (!gtk_text_iter_ends_sentence (&start))
+            {
+              if (!gtk_text_iter_backward_char (&start))
+                break;
+            }
+          gtk_text_iter_forward_sentence_end (&end);
+          break;
+        case ATK_TEXT_BOUNDARY_LINE_START:
+          if (layout == NULL)
+            {
+              line_number = gtk_text_iter_get_line (&start);
+              if (line_number == 0)
+                {
+                  gtk_text_buffer_get_iter_at_offset (buffer,
+                    &start, 0);
+                }
+              else
+                {
+                  gtk_text_iter_backward_line (&start);
+                  gtk_text_iter_forward_line (&start);
+                }
+              gtk_text_iter_forward_line (&end);
+            }
+          else if GTK_IS_TEXT_VIEW (layout)
+            {
+              GtkTextView *view = GTK_TEXT_VIEW (layout);
+
+              gtk_text_view_backward_display_line_start (view, &start);
+              /*
+               * The call to gtk_text_iter_forward_to_end() is needed
+               * because of bug 81960
+               */
+              if (!gtk_text_view_forward_display_line (view, &end))
+                gtk_text_iter_forward_to_end (&end);
+            }
+          else if PANGO_IS_LAYOUT (layout)
+            get_pango_text_offsets (PANGO_LAYOUT (layout),
+                                    buffer,
+                                    function,
+                                    boundary_type,
+                                    offset,
+                                    start_offset,
+                                    end_offset,
+                                    &start,
+                                    &end);
+
+          break;
+        case ATK_TEXT_BOUNDARY_LINE_END:
+          if (layout == NULL)
+            {
+              line_number = gtk_text_iter_get_line (&start);
+              if (line_number == 0)
+                {
+                  gtk_text_buffer_get_iter_at_offset (buffer,
+                    &start, 0);
+                }
+              else
+                {
+                  gtk_text_iter_backward_line (&start);
+                  gtk_text_iter_forward_line (&start);
+                }
+              while (!gtk_text_iter_ends_line (&start))
+                {
+                  if (!gtk_text_iter_backward_char (&start))
+                    break;
+                }
+              gtk_text_iter_forward_to_line_end (&end);
+            }
+          else if GTK_IS_TEXT_VIEW (layout)
+            {
+              GtkTextView *view = GTK_TEXT_VIEW (layout);
+
+              gtk_text_view_backward_display_line_start (view, &start);
+              if (!gtk_text_iter_is_start (&start))
+                {
+                  gtk_text_view_backward_display_line (view, &start);
+                  gtk_text_view_forward_display_line_end (view, &start);
+                } 
+              gtk_text_view_forward_display_line_end (view, &end);
+            }
+          else if PANGO_IS_LAYOUT (layout)
+            get_pango_text_offsets (PANGO_LAYOUT (layout),
+                                    buffer,
+                                    function,
+                                    boundary_type,
+                                    offset,
+                                    start_offset,
+                                    end_offset,
+                                    &start,
+                                    &end);
+          break;
+        }
+      break;
+  
+    case GAIL_AFTER_OFFSET:
+      switch (boundary_type)
+        {
+        case ATK_TEXT_BOUNDARY_CHAR:
+          gtk_text_iter_forward_char(&start);
+          gtk_text_iter_forward_chars(&end, 2);
+          break;
+        case ATK_TEXT_BOUNDARY_WORD_START:
+          if (gtk_text_iter_inside_word (&end))
+            gtk_text_iter_forward_word_end (&end);
+          while (!gtk_text_iter_starts_word (&end))
+            {
+              if (!gtk_text_iter_forward_char (&end))
+                break;
+            }
+          start = end;
+          if (!gtk_text_iter_is_end (&end))
+            {
+              gtk_text_iter_forward_word_end (&end);
+              while (!gtk_text_iter_starts_word (&end))
+                {
+                  if (!gtk_text_iter_forward_char (&end))
+                    break;
+                }
+            }
+          break;
+        case ATK_TEXT_BOUNDARY_WORD_END:
+          gtk_text_iter_forward_word_end (&end);
+          start = end;
+          if (!gtk_text_iter_is_end (&end))
+            gtk_text_iter_forward_word_end (&end);
+          break;
+        case ATK_TEXT_BOUNDARY_SENTENCE_START:
+          if (gtk_text_iter_inside_sentence (&end))
+            gtk_text_iter_forward_sentence_end (&end);
+          while (!gtk_text_iter_starts_sentence (&end))
+            {
+              if (!gtk_text_iter_forward_char (&end))
+                break;
+            }
+          start = end;
+          if (!gtk_text_iter_is_end (&end))
+            {
+              gtk_text_iter_forward_sentence_end (&end);
+              while (!gtk_text_iter_starts_sentence (&end))
+                {
+                  if (!gtk_text_iter_forward_char (&end))
+                    break;
+                }
+            }
+          break;
+        case ATK_TEXT_BOUNDARY_SENTENCE_END:
+          gtk_text_iter_forward_sentence_end (&end);
+          start = end;
+          if (!gtk_text_iter_is_end (&end))
+            gtk_text_iter_forward_sentence_end (&end);
+          break;
+        case ATK_TEXT_BOUNDARY_LINE_START:
+          if (layout == NULL)
+            {
+              gtk_text_iter_forward_line (&end);
+              start = end;
+              gtk_text_iter_forward_line (&end);
+            }
+          else if GTK_IS_TEXT_VIEW (layout)
+            {
+              GtkTextView *view = GTK_TEXT_VIEW (layout);
+
+              gtk_text_view_forward_display_line (view, &end);
+              start = end; 
+              gtk_text_view_forward_display_line (view, &end);
+            }
+          else if (PANGO_IS_LAYOUT (layout))
+            get_pango_text_offsets (PANGO_LAYOUT (layout),
+                                    buffer,
+                                    function,
+                                    boundary_type,
+                                    offset,
+                                    start_offset,
+                                    end_offset,
+                                    &start,
+                                    &end);
+          break;
+        case ATK_TEXT_BOUNDARY_LINE_END:
+          if (layout == NULL)
+            {
+              gtk_text_iter_forward_line (&start);
+              end = start;
+              if (!gtk_text_iter_is_end (&start))
+                { 
+                  while (!gtk_text_iter_ends_line (&start))
+                  {
+                    if (!gtk_text_iter_backward_char (&start))
+                      break;
+                  }
+                  gtk_text_iter_forward_to_line_end (&end);
+                }
+            }
+          else if GTK_IS_TEXT_VIEW (layout)
+            {
+              GtkTextView *view = GTK_TEXT_VIEW (layout);
+
+              gtk_text_view_forward_display_line_end (view, &end);
+              start = end; 
+              gtk_text_view_forward_display_line (view, &end);
+              gtk_text_view_forward_display_line_end (view, &end);
+            }
+          else if (PANGO_IS_LAYOUT (layout))
+            get_pango_text_offsets (PANGO_LAYOUT (layout),
+                                    buffer,
+                                    function,
+                                    boundary_type,
+                                    offset,
+                                    start_offset,
+                                    end_offset,
+                                    &start,
+                                    &end);
+          break;
+        }
+      break;
+    }
+  *start_offset = gtk_text_iter_get_offset (&start);
+  *end_offset = gtk_text_iter_get_offset (&end);
+
+  return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+}
+
+/**
+ * gail_text_util_get_substring:
+ * @textutil: A #GailTextUtil
+ * @start_pos: The start position of the substring
+ * @end_pos: The end position of the substring.
+ *
+ * Gets the substring indicated by @start_pos and @end_pos
+ *
+ * Returns: the substring indicated by @start_pos and @end_pos
+ **/
+gchar*
+gail_text_util_get_substring (GailTextUtil *textutil,
+                              gint         start_pos, 
+                              gint         end_pos)
+{
+  GtkTextIter start, end;
+  GtkTextBuffer *buffer;
+
+  g_return_val_if_fail(GAIL_IS_TEXT_UTIL (textutil), NULL);
+
+  buffer = textutil->buffer;
+  if (buffer == NULL)
+     return NULL;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
+  if (end_pos < 0)
+    gtk_text_buffer_get_end_iter (buffer, &end);
+  else
+    gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
+
+  return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+}
+
+static void
+get_pango_text_offsets (PangoLayout         *layout,
+                        GtkTextBuffer       *buffer,
+                        GailOffsetType      function,
+                        AtkTextBoundary     boundary_type,
+                        gint                offset,
+                        gint                *start_offset,
+                        gint                *end_offset,
+                        GtkTextIter         *start_iter,
+                        GtkTextIter         *end_iter)
+{
+  PangoLayoutIter *iter;
+  PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
+  gint index, start_index, end_index;
+  const gchar *text;
+  gboolean found = FALSE;
+
+  text = pango_layout_get_text (layout);
+  index = g_utf8_offset_to_pointer (text, offset) - text;
+  iter = pango_layout_get_iter (layout);
+  do
+    {
+      line = pango_layout_iter_get_line (iter);
+      start_index = line->start_index;
+      end_index = start_index + line->length;
+
+      if (index >= start_index && index <= end_index)
+        {
+          /*
+           * Found line for offset
+           */
+          switch (function)
+            {
+            case GAIL_BEFORE_OFFSET:
+                  /*
+                   * We want the previous line
+                   */
+              if (prev_line)
+                {
+                  switch (boundary_type)
+                    {
+                    case ATK_TEXT_BOUNDARY_LINE_START:
+                      end_index = start_index;
+                      start_index = prev_line->start_index;
+                      break;
+                    case ATK_TEXT_BOUNDARY_LINE_END:
+                      if (prev_prev_line)
+                        start_index = prev_prev_line->start_index + 
+                                  prev_prev_line->length;
+                      end_index = prev_line->start_index + prev_line->length;
+                      break;
+                    default:
+                      g_assert_not_reached();
+                    }
+                }
+              else
+                start_index = end_index = 0;
+              break;
+            case GAIL_AT_OFFSET:
+              switch (boundary_type)
+                {
+                case ATK_TEXT_BOUNDARY_LINE_START:
+                  if (pango_layout_iter_next_line (iter))
+                    end_index = pango_layout_iter_get_line (iter)->start_index;
+                  break;
+                case ATK_TEXT_BOUNDARY_LINE_END:
+                  if (prev_line)
+                    start_index = prev_line->start_index + 
+                                  prev_line->length;
+                  break;
+                default:
+                  g_assert_not_reached();
+                }
+              break;
+            case GAIL_AFTER_OFFSET:
+               /*
+                * We want the next line
+                */
+              if (pango_layout_iter_next_line (iter))
+                {
+                  line = pango_layout_iter_get_line (iter);
+                  switch (boundary_type)
+                    {
+                    case ATK_TEXT_BOUNDARY_LINE_START:
+                      start_index = line->start_index;
+                      if (pango_layout_iter_next_line (iter))
+                        end_index = pango_layout_iter_get_line (iter)->start_index;
+                      else
+                        end_index = start_index + line->length;
+                      break;
+                    case ATK_TEXT_BOUNDARY_LINE_END:
+                      start_index = end_index;
+                      end_index = line->start_index + line->length;
+                      break;
+                    default:
+                      g_assert_not_reached();
+                    }
+                }
+              else
+                start_index = end_index;
+              break;
+            }
+          found = TRUE;
+          break;
+        }
+      prev_prev_line = prev_line; 
+      prev_line = line; 
+    }
+  while (pango_layout_iter_next_line (iter));
+
+  if (!found)
+    {
+      start_index = prev_line->start_index + prev_line->length;
+      end_index = start_index;
+    }
+  pango_layout_iter_free (iter);
+  *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
+  *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
+  gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
+  gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
+}
diff --git a/modules/other/gail/libgail-util/gailtextutil.h b/modules/other/gail/libgail-util/gailtextutil.h
new file mode 100644 (file)
index 0000000..530e699
--- /dev/null
@@ -0,0 +1,91 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 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_TEXT_UTIL_H__
+#define __GAIL_TEXT_UTIL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus */
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#define GAIL_TYPE_TEXT_UTIL                  (gail_text_util_get_type ())
+#define GAIL_TEXT_UTIL(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAIL_TYPE_TEXT_UTIL, GailTextUtil))
+#define GAIL_TEXT_UTIL_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GAIL_TYPE_TEXT_UTIL, GailTextUtilClass))
+#define GAIL_IS_TEXT_UTIL(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAIL_TYPE_TEXT_UTIL))
+#define GAIL_IS_TEXT_UTIL_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GAIL_TYPE_TEXT_UTIL))
+#define GAIL_TEXT_UTIL_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GAIL_TYPE_TEXT_UTIL, GailTextUtilClass))
+
+/**
+ *GailOffsetType:
+ *@GAIL_BEFORE_OFFSET: Text before offset is required.
+ *@GAIL_AT_OFFSET: Text at offset is required,
+ *@GAIL_AFTER_OFFSET: Text after offset is required.
+ *
+ * Specifies which of the functions atk_text_get_text_before_offset(),
+ * atk_text_get_text_at_offset(), atk_text_get_text_after_offset() the
+ * function gail_text_util_get_text() is being called for.
+ **/
+typedef enum
+{
+  GAIL_BEFORE_OFFSET,
+  GAIL_AT_OFFSET,
+  GAIL_AFTER_OFFSET
+}GailOffsetType;
+
+typedef struct _GailTextUtil           GailTextUtil;
+typedef struct _GailTextUtilClass      GailTextUtilClass;
+
+struct _GailTextUtil
+{
+  GObject parent;
+
+  GtkTextBuffer *buffer;
+};
+
+struct _GailTextUtilClass
+{
+  GObjectClass parent_class;
+};
+
+GType         gail_text_util_get_type      (void);
+GailTextUtil* gail_text_util_new           (void);
+
+void          gail_text_util_text_setup    (GailTextUtil    *textutil,
+                                            const gchar     *text);
+void          gail_text_util_buffer_setup  (GailTextUtil    *textutil,
+                                            GtkTextBuffer   *buffer);
+gchar*        gail_text_util_get_text      (GailTextUtil    *textutil,
+                                             gpointer        layout,
+                                            GailOffsetType  function,
+                                            AtkTextBoundary boundary_type,
+                                            gint            offset,
+                                            gint            *start_offset,
+                                            gint            *end_offset);
+gchar*        gail_text_util_get_substring (GailTextUtil    *textutil,
+                                            gint            start_pos,
+                                            gint            end_pos);
+
+#ifdef __cplusplus 
+}
+#endif /*cplusplus */
+
+#endif /*__GAIL_TEXT_UTIL_H__ */
diff --git a/modules/other/gail/libgail-util/gailutil.def b/modules/other/gail/libgail-util/gailutil.def
new file mode 100644 (file)
index 0000000..2077be1
--- /dev/null
@@ -0,0 +1,15 @@
+EXPORTS
+       gail_misc_add_attribute
+       gail_misc_add_to_attr_set
+       gail_misc_buffer_get_run_attributes
+       gail_misc_get_default_attributes
+       gail_misc_get_extents_from_pango_rectangle
+       gail_misc_get_index_at_point_in_layout
+       gail_misc_get_origins
+       gail_misc_layout_get_run_attributes
+       gail_text_util_buffer_setup
+       gail_text_util_get_substring
+       gail_text_util_get_text
+       gail_text_util_get_type
+       gail_text_util_new
+       gail_text_util_text_setup
index 5070ca94bbe5a067dad1dd73afe4286dbd609290..a92e214559e105d3e5122ac5fc2bd90da04a378c 100644 (file)
@@ -17,6 +17,7 @@ gdk-pixbuf/io-bmp.c
 gdk-pixbuf/io-gif.c
 gdk-pixbuf/io-ico.c
 gdk-pixbuf/io-icns.c
+gdk-pixbuf/io-jasper.c
 gdk-pixbuf/io-jpeg.c
 gdk-pixbuf/io-pcx.c
 gdk-pixbuf/io-png.c
index 0f3232e198c9f6224209fc262ff2c167b5692d5e..736e9548a76f10a7de3222b6e9ae2a004c241773 100644 (file)
@@ -1,2 +1,4 @@
 demos/gtk-demo/demo.ui
 gtk/paper_names.c
+modules/other/gail/gailimage.c
+