summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--configure.in40
-rw-r--r--docs/reference/Makefile.am2
-rw-r--r--docs/reference/libgail-util/Makefile.am33
-rw-r--r--docs/reference/libgail-util/gail-libgail-util-docs.sgml17
-rw-r--r--docs/reference/libgail-util/gail-libgail-util-overrides.txt0
-rw-r--r--docs/reference/libgail-util/gail-libgail-util-sections.txt34
-rw-r--r--docs/reference/libgail-util/gail-libgail-util.types0
-rw-r--r--docs/reference/libgail-util/tmpl/gail-libgail-util-unused.sgml0
-rw-r--r--docs/reference/libgail-util/tmpl/gailmisc.sgml122
-rw-r--r--docs/reference/libgail-util/tmpl/gailtextutil.sgml92
-rw-r--r--gail-uninstalled.pc.in11
-rw-r--r--gail.pc.in11
-rw-r--r--modules/Makefile.am7
-rw-r--r--modules/other/Makefile.am1
-rw-r--r--modules/other/gail/Makefile.am173
-rw-r--r--modules/other/gail/gail-private-macros.h38
-rw-r--r--modules/other/gail/gail.c982
-rw-r--r--modules/other/gail/gail.h54
-rw-r--r--modules/other/gail/gailadjustment.c234
-rw-r--r--modules/other/gail/gailadjustment.h61
-rw-r--r--modules/other/gail/gailarrow.c164
-rw-r--r--modules/other/gail/gailarrow.h61
-rw-r--r--modules/other/gail/gailbooleancell.c122
-rw-r--r--modules/other/gail/gailbooleancell.h60
-rw-r--r--modules/other/gail/gailbooleancellfactory.c78
-rw-r--r--modules/other/gail/gailbooleancellfactory.h56
-rw-r--r--modules/other/gail/gailbox.c101
-rw-r--r--modules/other/gail/gailbox.h59
-rw-r--r--modules/other/gail/gailbutton.c1720
-rw-r--r--modules/other/gail/gailbutton.h77
-rw-r--r--modules/other/gail/gailcalendar.c73
-rw-r--r--modules/other/gail/gailcalendar.h59
-rw-r--r--modules/other/gail/gailcell.c577
-rw-r--r--modules/other/gail/gailcell.h110
-rw-r--r--modules/other/gail/gailcellparent.c124
-rw-r--r--modules/other/gail/gailcellparent.h88
-rw-r--r--modules/other/gail/gailcheckmenuitem.c166
-rw-r--r--modules/other/gail/gailcheckmenuitem.h59
-rw-r--r--modules/other/gail/gailchecksubmenuitem.c162
-rw-r--r--modules/other/gail/gailchecksubmenuitem.h59
-rw-r--r--modules/other/gail/gailclist.c1670
-rw-r--r--modules/other/gail/gailclist.h72
-rw-r--r--modules/other/gail/gailclistcell.c121
-rw-r--r--modules/other/gail/gailclistcell.h59
-rw-r--r--modules/other/gail/gailcombo.c714
-rw-r--r--modules/other/gail/gailcombo.h67
-rw-r--r--modules/other/gail/gailcombobox.c686
-rw-r--r--modules/other/gail/gailcombobox.h68
-rw-r--r--modules/other/gail/gailcontainer.c298
-rw-r--r--modules/other/gail/gailcontainer.h72
-rw-r--r--modules/other/gail/gailcontainercell.c202
-rw-r--r--modules/other/gail/gailcontainercell.h71
-rw-r--r--modules/other/gail/gailentry.c1449
-rw-r--r--modules/other/gail/gailentry.h78
-rw-r--r--modules/other/gail/gailexpander.c950
-rw-r--r--modules/other/gail/gailexpander.h66
-rw-r--r--modules/other/gail/gailfactory.h85
-rw-r--r--modules/other/gail/gailframe.c113
-rw-r--r--modules/other/gail/gailframe.h60
-rw-r--r--modules/other/gail/gailhtmlbox.c289
-rw-r--r--modules/other/gail/gailhtmlbox.h58
-rw-r--r--modules/other/gail/gailhtmlboxblock.c153
-rw-r--r--modules/other/gail/gailhtmlboxembedded.c133
-rw-r--r--modules/other/gail/gailhtmlboxtext.c506
-rw-r--r--modules/other/gail/gailimage.c430
-rw-r--r--modules/other/gail/gailimage.h61
-rw-r--r--modules/other/gail/gailimagecell.c207
-rw-r--r--modules/other/gail/gailimagecell.h62
-rw-r--r--modules/other/gail/gailimagecellfactory.c79
-rw-r--r--modules/other/gail/gailimagecellfactory.h56
-rw-r--r--modules/other/gail/gailintl.h24
-rw-r--r--modules/other/gail/gailitem.c760
-rw-r--r--modules/other/gail/gailitem.h64
-rw-r--r--modules/other/gail/gaillabel.c1065
-rw-r--r--modules/other/gail/gaillabel.h67
-rw-r--r--modules/other/gail/gaillist.c277
-rw-r--r--modules/other/gail/gaillist.h59
-rw-r--r--modules/other/gail/gailmenu.c167
-rw-r--r--modules/other/gail/gailmenu.h60
-rw-r--r--modules/other/gail/gailmenuitem.c682
-rw-r--r--modules/other/gail/gailmenuitem.h64
-rw-r--r--modules/other/gail/gailmenushell.c281
-rw-r--r--modules/other/gail/gailmenushell.h60
-rw-r--r--modules/other/gail/gailnotebook.c655
-rw-r--r--modules/other/gail/gailnotebook.h73
-rw-r--r--modules/other/gail/gailnotebookpage.c868
-rw-r--r--modules/other/gail/gailnotebookpage.h69
-rw-r--r--modules/other/gail/gailobject.c88
-rw-r--r--modules/other/gail/gailobject.h58
-rw-r--r--modules/other/gail/gailobjectfactory.c77
-rw-r--r--modules/other/gail/gailobjectfactory.h58
-rw-r--r--modules/other/gail/gailoptionmenu.c388
-rw-r--r--modules/other/gail/gailoptionmenu.h60
-rw-r--r--modules/other/gail/gailpaned.c247
-rw-r--r--modules/other/gail/gailpaned.h59
-rw-r--r--modules/other/gail/gailpixmap.c198
-rw-r--r--modules/other/gail/gailpixmap.h63
-rw-r--r--modules/other/gail/gailprogressbar.c271
-rw-r--r--modules/other/gail/gailprogressbar.h64
-rw-r--r--modules/other/gail/gailradiobutton.c164
-rw-r--r--modules/other/gail/gailradiobutton.h61
-rw-r--r--modules/other/gail/gailradiomenuitem.c168
-rw-r--r--modules/other/gail/gailradiomenuitem.h61
-rw-r--r--modules/other/gail/gailradiosubmenuitem.c164
-rw-r--r--modules/other/gail/gailradiosubmenuitem.h61
-rw-r--r--modules/other/gail/gailrange.c554
-rw-r--r--modules/other/gail/gailrange.h66
-rw-r--r--modules/other/gail/gailrenderercell.c112
-rw-r--r--modules/other/gail/gailrenderercell.h65
-rw-r--r--modules/other/gail/gailrenderercellfactory.c78
-rw-r--r--modules/other/gail/gailrenderercellfactory.h56
-rw-r--r--modules/other/gail/gailscale.c544
-rw-r--r--modules/other/gail/gailscale.h62
-rw-r--r--modules/other/gail/gailscrollbar.c134
-rw-r--r--modules/other/gail/gailscrollbar.h60
-rw-r--r--modules/other/gail/gailscrolledwindow.c243
-rw-r--r--modules/other/gail/gailscrolledwindow.h59
-rw-r--r--modules/other/gail/gailseparator.c103
-rw-r--r--modules/other/gail/gailseparator.h59
-rw-r--r--modules/other/gail/gailspinbutton.c296
-rw-r--r--modules/other/gail/gailspinbutton.h61
-rw-r--r--modules/other/gail/gailstatusbar.c680
-rw-r--r--modules/other/gail/gailstatusbar.h62
-rw-r--r--modules/other/gail/gailsubmenuitem.c382
-rw-r--r--modules/other/gail/gailsubmenuitem.h60
-rw-r--r--modules/other/gail/gailtextcell.c696
-rw-r--r--modules/other/gail/gailtextcell.h64
-rw-r--r--modules/other/gail/gailtextcellfactory.c79
-rw-r--r--modules/other/gail/gailtextcellfactory.h56
-rw-r--r--modules/other/gail/gailtextview.c1819
-rw-r--r--modules/other/gail/gailtextview.h72
-rw-r--r--modules/other/gail/gailtogglebutton.c165
-rw-r--r--modules/other/gail/gailtogglebutton.h59
-rw-r--r--modules/other/gail/gailtoplevel.c399
-rw-r--r--modules/other/gail/gailtoplevel.h58
-rw-r--r--modules/other/gail/gailtreeview.c4710
-rw-r--r--modules/other/gail/gailtreeview.h77
-rw-r--r--modules/other/gail/gailutil.c658
-rw-r--r--modules/other/gail/gailutil.h80
-rw-r--r--modules/other/gail/gailwidget.c1111
-rw-r--r--modules/other/gail/gailwidget.h71
-rw-r--r--modules/other/gail/gailwindow.c1094
-rw-r--r--modules/other/gail/gailwindow.h63
-rw-r--r--modules/other/gail/libgail-util/Makefile.am76
-rw-r--r--modules/other/gail/libgail-util/gail-util.h2
-rw-r--r--modules/other/gail/libgail-util/gailmisc.c1112
-rw-r--r--modules/other/gail/libgail-util/gailmisc.h86
-rw-r--r--modules/other/gail/libgail-util/gailtextutil.c769
-rw-r--r--modules/other/gail/libgail-util/gailtextutil.h91
-rw-r--r--modules/other/gail/libgail-util/gailutil.def15
-rw-r--r--po/POTFILES.in1
-rw-r--r--po/POTFILES.skip2
153 files changed, 39654 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 68be1d1fa..2cfd37891 100644
--- 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
diff --git a/configure.in b/configure.in
index fbab5bb3c..58ea15787 100644
--- a/configure.in
+++ b/configure.in
@@ -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
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 1748f8372..f4d7451db 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -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
index 000000000..a2f2e4807
--- /dev/null
+++ b/docs/reference/libgail-util/Makefile.am
@@ -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
index 000000000..97bb08be2
--- /dev/null
+++ b/docs/reference/libgail-util/gail-libgail-util-docs.sgml
@@ -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
index 000000000..e69de29bb
--- /dev/null
+++ b/docs/reference/libgail-util/gail-libgail-util-overrides.txt
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
index 000000000..1ef8ad444
--- /dev/null
+++ b/docs/reference/libgail-util/gail-libgail-util-sections.txt
@@ -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
index 000000000..e69de29bb
--- /dev/null
+++ b/docs/reference/libgail-util/gail-libgail-util.types
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
index 000000000..e69de29bb
--- /dev/null
+++ b/docs/reference/libgail-util/tmpl/gail-libgail-util-unused.sgml
diff --git a/docs/reference/libgail-util/tmpl/gailmisc.sgml b/docs/reference/libgail-util/tmpl/gailmisc.sgml
new file mode 100644
index 000000000..6e9642df9
--- /dev/null
+++ b/docs/reference/libgail-util/tmpl/gailmisc.sgml
@@ -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
index 000000000..6b35c2d37
--- /dev/null
+++ b/docs/reference/libgail-util/tmpl/gailtextutil.sgml
@@ -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
index 000000000..63a49adbe
--- /dev/null
+++ b/gail-uninstalled.pc.in
@@ -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
index 000000000..bab729a89
--- /dev/null
+++ b/gail.pc.in
@@ -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
diff --git a/modules/Makefile.am b/modules/Makefile.am
index d8e0c5829..86a89af3c 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -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
index 000000000..37488eb5e
--- /dev/null
+++ b/modules/other/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = gail
diff --git a/modules/other/gail/Makefile.am b/modules/other/gail/Makefile.am
new file mode 100644
index 000000000..0825a41da
--- /dev/null
+++ b/modules/other/gail/Makefile.am
@@ -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
index 000000000..bb2022ba7
--- /dev/null
+++ b/modules/other/gail/gail-private-macros.h
@@ -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
index 000000000..217eb8caa
--- /dev/null
+++ b/modules/other/gail/gail.c
@@ -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
index 000000000..5ee6277c0
--- /dev/null
+++ b/modules/other/gail/gail.h
@@ -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
index 000000000..3669bd57e
--- /dev/null
+++ b/modules/other/gail/gailadjustment.c
@@ -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
index 000000000..4a6b38b87
--- /dev/null
+++ b/modules/other/gail/gailadjustment.h
@@ -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
index 000000000..c20cbc411
--- /dev/null
+++ b/modules/other/gail/gailarrow.c
@@ -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
index 000000000..b1e7fb272
--- /dev/null
+++ b/modules/other/gail/gailarrow.h
@@ -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
index 000000000..40590bf82
--- /dev/null
+++ b/modules/other/gail/gailbooleancell.c
@@ -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
index 000000000..cc5dc2d6d
--- /dev/null
+++ b/modules/other/gail/gailbooleancell.h
@@ -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
index 000000000..30f11d254
--- /dev/null
+++ b/modules/other/gail/gailbooleancellfactory.c
@@ -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
index 000000000..fca9c058d
--- /dev/null
+++ b/modules/other/gail/gailbooleancellfactory.h
@@ -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
index 000000000..08b3ef865
--- /dev/null
+++ b/modules/other/gail/gailbox.c
@@ -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
index 000000000..17c00ece0
--- /dev/null
+++ b/modules/other/gail/gailbox.h
@@ -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
index 000000000..46b7db33a
--- /dev/null
+++ b/modules/other/gail/gailbutton.c
@@ -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
index 000000000..2550af921
--- /dev/null
+++ b/modules/other/gail/gailbutton.h
@@ -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
index 000000000..7d74f54e2
--- /dev/null
+++ b/modules/other/gail/gailcalendar.c
@@ -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
index 000000000..568f4c478
--- /dev/null
+++ b/modules/other/gail/gailcalendar.h
@@ -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
index 000000000..684863186
--- /dev/null
+++ b/modules/other/gail/gailcell.c
@@ -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
index 000000000..7329c8986
--- /dev/null
+++ b/modules/other/gail/gailcell.h
@@ -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
index 000000000..06481c65b
--- /dev/null
+++ b/modules/other/gail/gailcellparent.c
@@ -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
index 000000000..3932093cc
--- /dev/null
+++ b/modules/other/gail/gailcellparent.h
@@ -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
index 000000000..55164f6f8
--- /dev/null
+++ b/modules/other/gail/gailcheckmenuitem.c
@@ -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
index 000000000..292cdd9aa
--- /dev/null
+++ b/modules/other/gail/gailcheckmenuitem.h
@@ -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
index 000000000..d011f77a9
--- /dev/null
+++ b/modules/other/gail/gailchecksubmenuitem.c
@@ -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
index 000000000..174cdbafe
--- /dev/null
+++ b/modules/other/gail/gailchecksubmenuitem.h
@@ -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
index 000000000..d56839e3e
--- /dev/null
+++ b/modules/other/gail/gailclist.c
@@ -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
index 000000000..92d1df692
--- /dev/null
+++ b/modules/other/gail/gailclist.h
@@ -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
index 000000000..09a6b4a84
--- /dev/null
+++ b/modules/other/gail/gailclistcell.c
@@ -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
index 000000000..0cd208ce2
--- /dev/null
+++ b/modules/other/gail/gailclistcell.h
@@ -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
index 000000000..45d6ade37
--- /dev/null
+++ b/modules/other/gail/gailcombo.c
@@ -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
index 000000000..79157af44
--- /dev/null
+++ b/modules/other/gail/gailcombo.h
@@ -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
index 000000000..316e719f1
--- /dev/null
+++ b/modules/other/gail/gailcombobox.c
@@ -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
index 000000000..f9307296d
--- /dev/null
+++ b/modules/other/gail/gailcombobox.h
@@ -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
index 000000000..23af9124c
--- /dev/null
+++ b/modules/other/gail/gailcontainer.c
@@ -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
index 000000000..6f0f61954
--- /dev/null
+++ b/modules/other/gail/gailcontainer.h
@@ -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
index 000000000..430ca75bb
--- /dev/null
+++ b/modules/other/gail/gailcontainercell.c
@@ -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
index 000000000..022b78bb6
--- /dev/null
+++ b/modules/other/gail/gailcontainercell.h
@@ -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
index 000000000..4910bc756
--- /dev/null
+++ b/modules/other/gail/gailentry.c
@@ -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
index 000000000..1fa332f1c
--- /dev/null
+++ b/modules/other/gail/gailentry.h
@@ -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
index 000000000..8d43e2fdc
--- /dev/null
+++ b/modules/other/gail/gailexpander.c
@@ -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
index 000000000..a1e8c29d0
--- /dev/null
+++ b/modules/other/gail/gailexpander.h
@@ -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
index 000000000..0ea4dbac4
--- /dev/null
+++ b/modules/other/gail/gailfactory.h
@@ -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
index 000000000..4d85f0c7d
--- /dev/null
+++ b/modules/other/gail/gailframe.c
@@ -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
index 000000000..142c8deb7
--- /dev/null
+++ b/modules/other/gail/gailframe.h
@@ -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
index 000000000..1d8def6ad
--- /dev/null
+++ b/modules/other/gail/gailhtmlbox.c
@@ -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
index 000000000..bf2200bbb
--- /dev/null
+++ b/modules/other/gail/gailhtmlbox.h
@@ -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
index 000000000..9240029ee
--- /dev/null
+++ b/modules/other/gail/gailhtmlboxblock.c
@@ -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
index 000000000..30d20f36f
--- /dev/null
+++ b/modules/other/gail/gailhtmlboxembedded.c
@@ -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
index 000000000..9d2874cbb
--- /dev/null
+++ b/modules/other/gail/gailhtmlboxtext.c
@@ -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
index 000000000..e0bcc08df
--- /dev/null
+++ b/modules/other/gail/gailimage.c
@@ -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
index 000000000..a30ff204d
--- /dev/null
+++ b/modules/other/gail/gailimage.h
@@ -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
index 000000000..28f3da7dc
--- /dev/null
+++ b/modules/other/gail/gailimagecell.c
@@ -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
index 000000000..7dfd65c54
--- /dev/null
+++ b/modules/other/gail/gailimagecell.h
@@ -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
index 000000000..77c4b92e6
--- /dev/null
+++ b/modules/other/gail/gailimagecellfactory.c
@@ -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
index 000000000..adf3fd29d
--- /dev/null
+++ b/modules/other/gail/gailimagecellfactory.h
@@ -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
index 000000000..555de7978
--- /dev/null
+++ b/modules/other/gail/gailintl.h
@@ -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
index 000000000..dffc784c0
--- /dev/null
+++ b/modules/other/gail/gailitem.c
@@ -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
index 000000000..18e49461f
--- /dev/null
+++ b/modules/other/gail/gailitem.h
@@ -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
index 000000000..f9c12ee26
--- /dev/null
+++ b/modules/other/gail/gaillabel.c
@@ -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
index 000000000..3c927c44a
--- /dev/null
+++ b/modules/other/gail/gaillabel.h
@@ -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
index 000000000..c5d40485e
--- /dev/null
+++ b/modules/other/gail/gaillist.c
@@ -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
index 000000000..cd57874bb
--- /dev/null
+++ b/modules/other/gail/gaillist.h
@@ -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
index 000000000..f86c859cd
--- /dev/null
+++ b/modules/other/gail/gailmenu.c
@@ -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
index 000000000..5c1c5f9e7
--- /dev/null
+++ b/modules/other/gail/gailmenu.h
@@ -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
index 000000000..0425cae42
--- /dev/null
+++ b/modules/other/gail/gailmenuitem.c
@@ -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
index 000000000..a7e0f6472
--- /dev/null
+++ b/modules/other/gail/gailmenuitem.h
@@ -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
index 000000000..53ae7c502
--- /dev/null
+++ b/modules/other/gail/gailmenushell.c
@@ -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
index 000000000..a44aa884e
--- /dev/null
+++ b/modules/other/gail/gailmenushell.h
@@ -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
index 000000000..1e60ac44a
--- /dev/null
+++ b/modules/other/gail/gailnotebook.c
@@ -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
index 000000000..ab17ff1c3
--- /dev/null
+++ b/modules/other/gail/gailnotebook.h
@@ -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
index 000000000..b830f912e
--- /dev/null
+++ b/modules/other/gail/gailnotebookpage.c
@@ -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
index 000000000..50af79cfc
--- /dev/null
+++ b/modules/other/gail/gailnotebookpage.h
@@ -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
index 000000000..2c6ceb475
--- /dev/null
+++ b/modules/other/gail/gailobject.c
@@ -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
index 000000000..ffa36b3d1
--- /dev/null
+++ b/modules/other/gail/gailobject.h
@@ -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
index 000000000..c169baaea
--- /dev/null
+++ b/modules/other/gail/gailobjectfactory.c
@@ -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
index 000000000..5b8fef83a
--- /dev/null
+++ b/modules/other/gail/gailobjectfactory.h
@@ -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
index 000000000..873e93977
--- /dev/null
+++ b/modules/other/gail/gailoptionmenu.c
@@ -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
index 000000000..dfd42a5e0
--- /dev/null
+++ b/modules/other/gail/gailoptionmenu.h
@@ -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
index 000000000..a3ac815a4
--- /dev/null
+++ b/modules/other/gail/gailpaned.c
@@ -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
index 000000000..0726025c4
--- /dev/null
+++ b/modules/other/gail/gailpaned.h
@@ -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
index 000000000..6540f9c2a
--- /dev/null
+++ b/modules/other/gail/gailpixmap.c
@@ -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
index 000000000..889562a66
--- /dev/null
+++ b/modules/other/gail/gailpixmap.h
@@ -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
index 000000000..1ed4a49ac
--- /dev/null
+++ b/modules/other/gail/gailprogressbar.c
@@ -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
index 000000000..441cb36d6
--- /dev/null
+++ b/modules/other/gail/gailprogressbar.h
@@ -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
index 000000000..fecdf85ea
--- /dev/null
+++ b/modules/other/gail/gailradiobutton.c
@@ -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
index 000000000..d48106bf2
--- /dev/null
+++ b/modules/other/gail/gailradiobutton.h
@@ -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
index 000000000..cb7e20803
--- /dev/null
+++ b/modules/other/gail/gailradiomenuitem.c
@@ -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
index 000000000..b8f6847bd
--- /dev/null
+++ b/modules/other/gail/gailradiomenuitem.h
@@ -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
index 000000000..b702567b8
--- /dev/null
+++ b/modules/other/gail/gailradiosubmenuitem.c
@@ -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
index 000000000..10e2e7eb7
--- /dev/null
+++ b/modules/other/gail/gailradiosubmenuitem.h
@@ -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
index 000000000..2313aeeda
--- /dev/null
+++ b/modules/other/gail/gailrange.c
@@ -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
index 000000000..ad6bcd45b
--- /dev/null
+++ b/modules/other/gail/gailrange.h
@@ -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
index 000000000..9db9855c0
--- /dev/null
+++ b/modules/other/gail/gailrenderercell.c
@@ -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
index 000000000..f380647f2
--- /dev/null
+++ b/modules/other/gail/gailrenderercell.h
@@ -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
index 000000000..f7a6aa57b
--- /dev/null
+++ b/modules/other/gail/gailrenderercellfactory.c
@@ -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
index 000000000..636898126
--- /dev/null
+++ b/modules/other/gail/gailrenderercellfactory.h
@@ -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
index 000000000..1a6fefd99
--- /dev/null
+++ b/modules/other/gail/gailscale.c
@@ -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
index 000000000..22638a3d1
--- /dev/null
+++ b/modules/other/gail/gailscale.h
@@ -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
index 000000000..da17889c3
--- /dev/null
+++ b/modules/other/gail/gailscrollbar.c
@@ -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
index 000000000..985a71641
--- /dev/null
+++ b/modules/other/gail/gailscrollbar.h
@@ -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
index 000000000..024bc2812
--- /dev/null
+++ b/modules/other/gail/gailscrolledwindow.c
@@ -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
index 000000000..0812823a6
--- /dev/null
+++ b/modules/other/gail/gailscrolledwindow.h
@@ -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
index 000000000..87eaa5fc1
--- /dev/null
+++ b/modules/other/gail/gailseparator.c
@@ -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
index 000000000..765b73cf3
--- /dev/null
+++ b/modules/other/gail/gailseparator.h
@@ -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
index 000000000..d38d1c209
--- /dev/null
+++ b/modules/other/gail/gailspinbutton.c
@@ -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
index 000000000..90e8f4ab7
--- /dev/null
+++ b/modules/other/gail/gailspinbutton.h
@@ -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
index 000000000..aca7774a5
--- /dev/null
+++ b/modules/other/gail/gailstatusbar.c
@@ -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
index 000000000..43d25f33f
--- /dev/null
+++ b/modules/other/gail/gailstatusbar.h
@@ -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
index 000000000..b26df6b9a
--- /dev/null
+++ b/modules/other/gail/gailsubmenuitem.c
@@ -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
index 000000000..91334c587
--- /dev/null
+++ b/modules/other/gail/gailsubmenuitem.h
@@ -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
index 000000000..25c814cb2
--- /dev/null
+++ b/modules/other/gail/gailtextcell.c
@@ -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
index 000000000..76c1ade87
--- /dev/null
+++ b/modules/other/gail/gailtextcell.h
@@ -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
index 000000000..b981a7c91
--- /dev/null
+++ b/modules/other/gail/gailtextcellfactory.c
@@ -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
index 000000000..1aae137ff
--- /dev/null
+++ b/modules/other/gail/gailtextcellfactory.h
@@ -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
index 000000000..e99e02a1f
--- /dev/null
+++ b/modules/other/gail/gailtextview.c
@@ -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
index 000000000..4218b7b84
--- /dev/null
+++ b/modules/other/gail/gailtextview.h
@@ -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
index 000000000..13d509c74
--- /dev/null
+++ b/modules/other/gail/gailtogglebutton.c
@@ -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
index 000000000..77580f26b
--- /dev/null
+++ b/modules/other/gail/gailtogglebutton.h
@@ -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
index 000000000..237204b02
--- /dev/null
+++ b/modules/other/gail/gailtoplevel.c
@@ -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
index 000000000..5044a4152
--- /dev/null
+++ b/modules/other/gail/gailtoplevel.h
@@ -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
index 000000000..ef3e42e07
--- /dev/null
+++ b/modules/other/gail/gailtreeview.c
@@ -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
index 000000000..6f153318e
--- /dev/null
+++ b/modules/other/gail/gailtreeview.h
@@ -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
index 000000000..bdfa62516
--- /dev/null
+++ b/modules/other/gail/gailutil.c
@@ -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
index 000000000..4b968a62c
--- /dev/null
+++ b/modules/other/gail/gailutil.h
@@ -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
index 000000000..728347913
--- /dev/null
+++ b/modules/other/gail/gailwidget.c
@@ -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
index 000000000..04fdae050
--- /dev/null
+++ b/modules/other/gail/gailwidget.h
@@ -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
index 000000000..c6c9fd050
--- /dev/null
+++ b/modules/other/gail/gailwindow.c
@@ -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
index 000000000..289f83d1b
--- /dev/null
+++ b/modules/other/gail/gailwindow.h
@@ -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
index 000000000..428ac9e3a
--- /dev/null
+++ b/modules/other/gail/libgail-util/Makefile.am
@@ -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
index 000000000..87824f652
--- /dev/null
+++ b/modules/other/gail/libgail-util/gail-util.h
@@ -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
index 000000000..cd02743a0
--- /dev/null
+++ b/modules/other/gail/libgail-util/gailmisc.c
@@ -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
index 000000000..ced98e60d
--- /dev/null
+++ b/modules/other/gail/libgail-util/gailmisc.h
@@ -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
index 000000000..66fd9f115
--- /dev/null
+++ b/modules/other/gail/libgail-util/gailtextutil.c
@@ -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
index 000000000..530e699b0
--- /dev/null
+++ b/modules/other/gail/libgail-util/gailtextutil.h
@@ -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
index 000000000..2077be15f
--- /dev/null
+++ b/modules/other/gail/libgail-util/gailutil.def
@@ -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
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5070ca94b..a92e21455 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -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
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 0f3232e19..736e9548a 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1,2 +1,4 @@
demos/gtk-demo/demo.ui
gtk/paper_names.c
+modules/other/gail/gailimage.c
+