Add Cally
authorAlejandro Piñeiro <apinheiro@igalia.com>
Mon, 14 Jun 2010 11:38:25 +0000 (13:38 +0200)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Mon, 5 Jul 2010 15:45:43 +0000 (16:45 +0100)
The Clutter Accessibility Library is an implementation of the ATK,
the Accessibility Toolkit, which exposes Clutter actors to accessibility
tools. This allows not only writing accessible user interfaces, but also
allows testing and verification frameworks based on A11Y technologies to
inspect and test a Clutter scene graph.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2097

Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
24 files changed:
clutter/Makefile.am
clutter/cally/Makefile.am [new file with mode: 0644]
clutter/cally/cally-actor-private.h [new file with mode: 0644]
clutter/cally/cally-actor.c [new file with mode: 0644]
clutter/cally/cally-actor.h [new file with mode: 0644]
clutter/cally/cally-clone.c [new file with mode: 0644]
clutter/cally/cally-clone.h [new file with mode: 0644]
clutter/cally/cally-factory.h [new file with mode: 0644]
clutter/cally/cally-group.c [new file with mode: 0644]
clutter/cally/cally-group.h [new file with mode: 0644]
clutter/cally/cally-rectangle.c [new file with mode: 0644]
clutter/cally/cally-rectangle.h [new file with mode: 0644]
clutter/cally/cally-root.c [new file with mode: 0644]
clutter/cally/cally-root.h [new file with mode: 0644]
clutter/cally/cally-stage.c [new file with mode: 0644]
clutter/cally/cally-stage.h [new file with mode: 0644]
clutter/cally/cally-text.c [new file with mode: 0644]
clutter/cally/cally-text.h [new file with mode: 0644]
clutter/cally/cally-texture.c [new file with mode: 0644]
clutter/cally/cally-texture.h [new file with mode: 0644]
clutter/cally/cally-util.c [new file with mode: 0644]
clutter/cally/cally-util.h [new file with mode: 0644]
clutter/cally/cally.pc.in [new file with mode: 0644]
configure.ac

index 7501780..cc204b2 100644 (file)
@@ -2,7 +2,7 @@ include $(top_srcdir)/build/autotools/Makefile.am.silent
 
 NULL =
 
-SUBDIRS = cogl $(CLUTTER_WINSYS_BASE) $(CLUTTER_WINSYS)
+SUBDIRS = cogl $(CLUTTER_WINSYS_BASE) $(CLUTTER_WINSYS) cally
 
 if LOCAL_JSON_GLIB
 SUBDIRS += json
@@ -12,7 +12,7 @@ clutter_json_libadd = $(top_builddir)/clutter/json/libclutter-json.la
 clutter_json_gir = ClutterJson-@CLUTTER_API_VERSION@.gir
 endif
 
-DIST_SUBDIRS = glx egl cogl json osx x11 win32 fruity
+DIST_SUBDIRS = glx egl cogl json osx x11 win32 fruity cally
 
 # common definitions
 CLEANFILES =
@@ -39,6 +39,7 @@ endif # SUPPORT_WIN32
 
 INCLUDES = \
        -I$(top_srcdir)                                 \
+       -I$(top_srcdir)/clutter/cally                   \
        -I$(top_srcdir)/clutter/cogl                    \
        -I$(top_srcdir)/clutter/cogl/pango              \
        -I$(top_srcdir)/clutter                         \
@@ -260,13 +261,16 @@ source_h_priv = \
 
 libclutter_@CLUTTER_SONAME_INFIX@_@CLUTTER_API_VERSION@_la_LIBADD = \
        $(CLUTTER_LIBS) \
+       $(top_builddir)/clutter/cally/libcally.la \
        $(top_builddir)/clutter/cogl/cogl/libclutter-cogl.la \
        $(top_builddir)/clutter/cogl/pango/libcoglpango.la \
        $(top_builddir)/clutter/$(CLUTTER_WINSYS)/libclutter-$(CLUTTER_WINSYS).la \
        $(clutter_json_libadd) \
        $(CLUTTER_WINSYS_BASE_LIB)
 
+
 libclutter_@CLUTTER_SONAME_INFIX@_@CLUTTER_API_VERSION@_la_DEPENDENCIES = \
+       $(top_builddir)/clutter/cally/libcally.la \
        $(top_builddir)/clutter/cogl/cogl/libclutter-cogl.la \
        $(top_builddir)/clutter/cogl/pango/libcoglpango.la \
        $(top_builddir)/clutter/$(CLUTTER_WINSYS)/libclutter-$(CLUTTER_WINSYS).la \
@@ -289,7 +293,7 @@ libclutter_@CLUTTER_SONAME_INFIX@_@CLUTTER_API_VERSION@_la_LDFLAGS = \
        $(CLUTTER_LT_LDFLAGS) \
        $(GCOV_LDFLAGS) \
        -export-dynamic \
-       -export-symbols-regex "^(clutter|cogl|json).*" \
+       -export-symbols-regex "^(clutter|cogl|cally|json).*" \
        -rpath $(libdir) \
        $(win32_resources_ldflag) \
        $(NULL)
diff --git a/clutter/cally/Makefile.am b/clutter/cally/Makefile.am
new file mode 100644 (file)
index 0000000..75cec6a
--- /dev/null
@@ -0,0 +1,79 @@
+include $(top_srcdir)/build/autotools/Makefile.am.silent
+
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+
+# pkg-config ==================================================================
+pc_files = \
+       cally-$(CLUTTER_API_VERSION).pc
+
+cally-$(CLUTTER_API_VERSION).pc: cally.pc
+       $(QUIET_GEN)cp -f $< $(@F)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pc_files)
+
+EXTRA_DIST += cally.pc.in
+CLEANFILES += $(pc_files)
+
+noinst_LTLIBRARIES = libcally.la
+
+cally_h_sources =              cally.h                 \
+                               cally-actor.h           \
+                               cally-factory.h         \
+                               cally-group.h           \
+                               cally-rectangle.h       \
+                               cally-root.h            \
+                               cally-stage.h           \
+                               cally-text.h            \
+                               cally-texture.h         \
+                               cally-clone.h           \
+                               cally-util.h
+
+cally_private_h_sources =      cally-actor-private.h
+
+cally_c_sources =              cally.c                 \
+                               cally-actor.c           \
+                               cally-group.c           \
+                               cally-rectangle.c       \
+                               cally-root.c            \
+                               cally-stage.c           \
+                               cally-text.c            \
+                               cally-texture.c         \
+                               cally-clone.c           \
+                               cally-util.c
+
+libcally_la_SOURCES =                                  \
+       $(cally_private_h_sources)                      \
+       $(cally_h_sources)                              \
+       $(cally_c_sources)
+
+INCLUDES = \
+       -I$(top_srcdir)                                 \
+       -I$(top_srcdir)/clutter                         \
+       -I$(top_srcdir)/clutter/cally                   \
+       -I$(top_srcdir)/clutter/cogl
+
+AM_CPPFLAGS = \
+       -DG_LOG_DOMAIN=\"Cally\"                        \
+       -DCLUTTER_COMPILATION                           \
+       -DVERSION=\"$(VERSION)\"                        \
+       $(CLUTTER_DEBUG_CFLAGS)
+
+AM_CFLAGS = \
+       $(CLUTTER_CFLAGS)                               \
+       $(MAINTAINER_CFLAGS)
+
+
+libcallydir=$(includedir)/clutter-@CLUTTER_API_VERSION@/cally
+
+# In opposit to GAIL, CALLY exports all the headers. It will very
+# unlikely in any real final clutter-based application to use only raw
+# CALLY. In fact, after HAIL experience, probably export GAIL
+# interfaces would be a good idea
+libcally_HEADERS = \
+       $(cally_h_sources)
+
+libcally_la_LIBADD =                                   \
+       $(CLUTTER_LIBS)
\ No newline at end of file
diff --git a/clutter/cally/cally-actor-private.h b/clutter/cally/cally-actor-private.h
new file mode 100644 (file)
index 0000000..b9c0d0b
--- /dev/null
@@ -0,0 +1,35 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+#ifndef __CALLY_ACTOR_PRIVATE_H__
+#define __CALLY_ACTOR_PRIVATE_H__
+
+#include "cally-actor.h"
+
+/*
+ * Auxiliar define, in order to get the clutter actor from the AtkObject using
+ * AtkGObject methods
+ *
+ */
+#define CALLY_GET_CLUTTER_ACTOR(cally_object) \
+  (CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (cally_object))))
+
+#endif /* __CALLY_ACTOR_PRIVATE_H__ */
diff --git a/clutter/cally/cally-actor.c b/clutter/cally/cally-actor.c
new file mode 100644 (file)
index 0000000..b8a86de
--- /dev/null
@@ -0,0 +1,1491 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * Some parts are based on GailWidget, GailContaineer, GailCell from GAIL
+ * 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.
+ */
+
+/**
+ * SECTION:cally-actor
+ * @short_description: Implementation of the ATK interfaces for #ClutterActor
+ * @see_also: #ClutterActor
+ *
+ * #CallyActor implements the required ATK interfaces of #ClutterActor
+ * exposing the common elements on each ClutterActor (position, extents, etc).
+ */
+
+/**
+ *
+ * IMPLEMENTATION NOTES:
+ *
+ * ####
+ *
+ * Focus: clutter hasn't got the focus concept in the same way that GTK, but it
+ * has a key focus managed by the stage. Basically any actor can be focused using
+ * clutter_stage_set_key_focus. So, we will use this approach: all actors are
+ * focusable, and we get the currently focused using clutter_stage_get_key_focus
+ * This affects focus related stateset and some atk_componenet focus methods (like
+ * grab focus)
+ *
+ * ####
+ *
+ * #ClutterContainer : cally_actor implements some of his methods based on
+ * #ClutterContainer interface, although there are the posibility to not
+ * implement it. Could be strange to do that but:
+ *   * Some methods (like get_n_children and ref_child) are easily implemented using
+ *     this interface so a general implementation can be done
+ *   * #ClutterContainer is a popular interface, so several classes will implement
+ *     that.
+ *   * So we can implement a a11y class similar to GailContainer for each clutter
+ *     object implementing that, and their clutter subclasses will have a proper
+ *     a11y class, but not if they are parallel classes (ie: #ClutterGroup,
+ *     #TinyFrame, #TinyScrollView)
+ *   * So, on all this objects, will be required to reimplement again some methods
+ *     on the objects.
+ *   * A auxiliar object (a kind of a11y specific #ClutterContainer implementation)
+ *     could be used to implement this methods in only a place, anyway, this will
+ *     require some code on each concrete class to manage it.
+ *   * So this implementation is based in that is better to manage a interface
+ *     on the top abstract object, instead that C&P some code, with the minor
+ *     problem that we need to check if we are implementing or not the interface.
+ *
+ * This methods can be reimplemented, in concrete cases that we can get ways more
+ * efficient to implement that. Take a look to #CallyGroup as a example of this.
+ *
+ * Anyway, there are several examples of behaviour changes depending of the current
+ * type of the object you are granting access.
+ *
+ * TODO,FIXME: check if an option would be to use a dynamic type, as
+ * it has been done on the webkit a11y implementation:
+ *      See: https://bugs.webkit.org/show_bug.cgi?id=21546
+ *
+ * ###
+ *
+ * #AtkAction implementation. As ClutterActor has signals for "press"
+ * and "release", and most of the general Clutter objects are being
+ * used as buttons, it has sense to implement #AtkAction on
+ * #CallyActor, so this actions were added in this level.
+ *
+ * So we should search a way to extend #AtkAction on subclasses, to
+ * add actions. The direct solution would be just extend it normally,
+ * but we also should have the option to remove actions if required.
+ *
+ * So it was used the solution implemented in GailCell: maintain a
+ * list of actions, and add a _add_action and _remove_action public
+ * methods.
+ *
+ * This is another reason to not isolate CALLY as GAIL (although the
+ * current idea is to not do that).
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <clutter/clutter.h>
+
+#ifdef HAVE_CLUTTER_X11
+#include <clutter/x11/clutter-x11.h>
+#endif
+
+#include <math.h>
+
+#include "cally-actor.h"
+#include "cally-actor-private.h"
+
+typedef struct _CallyActorActionInfo CallyActorActionInfo;
+
+/**
+ * CallyActorActionInfo:
+ * @name: name of the action
+ * @description: description of the action
+ * @keybinding: keybinding related to the action
+ * @do_action_func: callback
+ *
+ * Utility structure to maintain the different actions added to the
+ * #CallyActor
+ */
+struct _CallyActorActionInfo
+{
+  gchar       *name;
+  gchar       *description;
+  gchar       *keybinding;
+  CallyActionFunc  do_action_func;
+};
+
+static void cally_actor_class_init (CallyActorClass *klass);
+static void cally_actor_init       (CallyActor *cally_actor);
+static void cally_actor_initialize (AtkObject *obj,
+                                   gpointer   data);
+static void cally_actor_finalize   (GObject *obj);
+
+/* AtkObject.h */
+static AtkObject*            cally_actor_get_parent          (AtkObject *obj);
+static gint                  cally_actor_get_index_in_parent (AtkObject *obj);
+static AtkStateSet*          cally_actor_ref_state_set       (AtkObject *obj);
+static G_CONST_RETURN gchar* cally_actor_get_name            (AtkObject *obj);
+static gint                  cally_actor_get_n_children      (AtkObject *obj);
+static AtkObject*            cally_actor_ref_child           (AtkObject *obj,
+                                                             gint       i);
+static gboolean             _cally_actor_all_parents_visible (ClutterActor *actor);
+
+/* ClutterContainer */
+static gint cally_actor_add_actor          (ClutterActor *container,
+                                           ClutterActor *actor,
+                                           gpointer      data);
+static gint cally_actor_remove_actor      (ClutterActor *container,
+                                          ClutterActor *actor,
+                                          gpointer      data);
+static gint cally_actor_real_add_actor    (ClutterActor *container,
+                                          ClutterActor *actor,
+                                          gpointer      data);
+static gint cally_actor_real_remove_actor (ClutterActor *container,
+                                          ClutterActor *actor,
+                                          gpointer      data);
+
+/* AtkComponent.h */
+static void     cally_actor_component_interface_init (AtkComponentIface *iface);
+static void     cally_actor_get_extents              (AtkComponent *component,
+                                                     gint         *x,
+                                                     gint         *y,
+                                                     gint         *width,
+                                                     gint         *height,
+                                                     AtkCoordType  coord_type);
+static gint     cally_actor_get_mdi_zorder           (AtkComponent *component);
+static gboolean cally_actor_grab_focus               (AtkComponent *component);
+static guint    cally_actor_add_focus_handler        (AtkComponent *component,
+                                                      AtkFocusHandler handler);
+static void     cally_actor_remove_focus_handler     (AtkComponent *component,
+                                                      guint handler_id);
+static void     cally_actor_focus_event              (AtkObject   *obj,
+                                                      gboolean    focus_in);
+static gboolean _is_actor_on_screen                 (ClutterActor *actor);
+static void     _get_top_level_origin               (ClutterActor *actor,
+                                                     gint         *x,
+                                                     gint         *y);
+
+/* AtkAction.h */
+static void                  cally_actor_action_interface_init  (AtkActionIface *iface);
+static gboolean              cally_actor_action_do_action       (AtkAction *action,
+                                                                gint       i);
+static gboolean              idle_do_action                    (gpointer data);
+static gint                  cally_actor_action_get_n_actions   (AtkAction *action);
+static G_CONST_RETURN gchar* cally_actor_action_get_description (AtkAction *action,
+                                                                gint       i);
+static G_CONST_RETURN gchar* cally_actor_action_get_keybinding  (AtkAction *action,
+                                                                gint       i);
+static G_CONST_RETURN gchar* cally_actor_action_get_name        (AtkAction *action,
+                                                                gint       i);
+static gboolean              cally_actor_action_set_description (AtkAction   *action,
+                                                                gint         i,
+                                                                const gchar *desc);
+static void                  _cally_actor_press_action          (CallyActor *cally_actor);
+static void                  _cally_actor_release_action        (CallyActor *cally_actor);
+static void                  _cally_actor_click_action          (CallyActor *cally_actor);
+static void                  _cally_actor_destroy_action_info   (gpointer      action_info,
+                                                                gpointer      user_data);
+static void                  _cally_actor_clean_action_list     (CallyActor *cally_actor);
+
+static CallyActorActionInfo*  _cally_actor_get_action_info       (CallyActor *cally_actor,
+                                                                gint       index);
+/* Misc functions */
+static void cally_actor_notify_clutter          (GObject    *obj,
+                                                GParamSpec *pspec);
+static void cally_actor_real_notify_clutter     (GObject    *obj,
+                                                 GParamSpec *pspec);
+static gboolean cally_actor_focus_clutter       (ClutterActor *actor,
+                                                 gpointer      data);
+static gboolean cally_actor_real_focus_clutter  (ClutterActor *actor,
+                                                 gpointer      data);
+
+G_DEFINE_TYPE_WITH_CODE (CallyActor,
+                         cally_actor,
+                         ATK_TYPE_GOBJECT_ACCESSIBLE,
+                         G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT,
+                                                cally_actor_component_interface_init)
+                         G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION,
+                                                cally_actor_action_interface_init));
+
+#define CALLY_ACTOR_GET_PRIVATE(obj) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CALLY_TYPE_ACTOR, CallyActorPrivate))
+
+
+struct _CallyActorPrivate
+{
+  GQueue *action_queue;
+  guint   action_idle_handler;
+  GList  *action_list;
+
+  GList *children;
+};
+
+
+AtkObject*
+cally_actor_new (ClutterActor *actor)
+{
+  gpointer   object;
+  AtkObject *atk_object;
+
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
+
+  object = g_object_new (CALLY_TYPE_ACTOR, NULL);
+
+  atk_object = ATK_OBJECT (object);
+  atk_object_initialize (atk_object, actor);
+
+  return atk_object;
+}
+
+static void
+cally_actor_initialize (AtkObject *obj,
+                        gpointer   data)
+{
+  CallyActor        *self  = NULL;
+  CallyActorPrivate *priv  = NULL;
+  ClutterActor     *actor = NULL;
+  guint             handler_id;
+
+  ATK_OBJECT_CLASS (cally_actor_parent_class)->initialize (obj, data);
+
+  self = CALLY_ACTOR(obj);
+  priv = self->priv;
+  actor = CLUTTER_ACTOR (data);
+
+  g_signal_connect_after (actor,
+                          "key-focus-in",
+                          G_CALLBACK (cally_actor_focus_clutter),
+                          GINT_TO_POINTER (TRUE));
+  g_signal_connect_after (actor,
+                          "key-focus-out",
+                          G_CALLBACK (cally_actor_focus_clutter),
+                          GINT_TO_POINTER (FALSE));
+  g_signal_connect (actor,
+                    "notify",
+                    G_CALLBACK (cally_actor_notify_clutter),
+                    NULL);
+  atk_component_add_focus_handler (ATK_COMPONENT (self),
+                                   cally_actor_focus_event);
+
+  g_object_set_data (G_OBJECT (obj), "atk-component-layer",
+                     GINT_TO_POINTER (ATK_LAYER_MDI));
+
+  /* add basic actions */
+  cally_actor_add_action (self, "press", NULL, NULL,
+                         _cally_actor_press_action);
+
+  cally_actor_add_action (self, "release", NULL, NULL,
+                         _cally_actor_release_action);
+
+  cally_actor_add_action (self, "click", NULL, NULL,
+                         _cally_actor_click_action);
+
+  /* Depends if the object implement ClutterContainer */
+  if (CLUTTER_IS_CONTAINER(actor))
+    {
+      priv->children = clutter_container_get_children (CLUTTER_CONTAINER (actor));
+
+      /*
+       * We store the handler ids for these signals in case some objects
+       * need to remove these handlers.
+       */
+      handler_id = g_signal_connect (actor,
+                                     "actor-added",
+                                     G_CALLBACK (cally_actor_add_actor),
+                                     obj);
+      g_object_set_data (G_OBJECT (obj), "cally-add-handler-id",
+                         GUINT_TO_POINTER (handler_id));
+      handler_id = g_signal_connect (actor,
+                                     "actor-removed",
+                                     G_CALLBACK (cally_actor_remove_actor),
+                                     obj);
+      g_object_set_data (G_OBJECT (obj), "cally-remove-handler-id",
+                         GUINT_TO_POINTER (handler_id));
+
+      obj->role = ATK_ROLE_PANEL; /* typically objects implementing ClutterContainer
+                                     interface would be a panel */
+    }
+  else
+    {
+      priv->children = NULL;
+      obj->role = ATK_ROLE_UNKNOWN;
+    }
+}
+
+static void
+cally_actor_class_init (CallyActorClass *klass)
+{
+  AtkObjectClass *class         = ATK_OBJECT_CLASS (klass);
+  GObjectClass   *gobject_class = G_OBJECT_CLASS (klass);
+
+  klass->focus_clutter  = cally_actor_real_focus_clutter;
+  klass->notify_clutter = cally_actor_real_notify_clutter;
+  klass->add_actor      = cally_actor_real_add_actor;
+  klass->remove_actor   = cally_actor_real_remove_actor;
+
+  /* GObject */
+  gobject_class->finalize = cally_actor_finalize;
+
+  /* AtkObject */
+  class->get_name            = cally_actor_get_name;
+  class->get_parent          = cally_actor_get_parent;
+  class->get_index_in_parent = cally_actor_get_index_in_parent;
+  class->ref_state_set       = cally_actor_ref_state_set;
+  class->initialize          = cally_actor_initialize;
+  class->get_n_children      = cally_actor_get_n_children;
+  class->ref_child           = cally_actor_ref_child;
+
+  g_type_class_add_private (gobject_class, sizeof (CallyActorPrivate));
+}
+
+static void
+cally_actor_init (CallyActor *cally_actor)
+{
+  CallyActorPrivate *priv = CALLY_ACTOR_GET_PRIVATE (cally_actor);
+
+  cally_actor->priv = priv;
+
+  priv->action_queue        = NULL;
+  priv->action_idle_handler = 0;
+
+  priv->action_list = NULL;
+
+  priv->children = NULL;
+}
+
+
+static void
+cally_actor_finalize (GObject *obj)
+{
+  CallyActor        *cally_actor = NULL;
+  CallyActorPrivate *priv       = NULL;
+
+  cally_actor = CALLY_ACTOR (obj);
+  priv = cally_actor->priv;
+
+  _cally_actor_clean_action_list (cally_actor);
+
+  if (priv->action_idle_handler)
+    {
+      g_source_remove (priv->action_idle_handler);
+      priv->action_idle_handler = 0;
+    }
+
+  if (priv->action_queue)
+    {
+      g_queue_free (priv->action_queue);
+    }
+
+  if (priv->children)
+    {
+      g_list_free (priv->children);
+      priv->children = NULL;
+    }
+
+  G_OBJECT_CLASS (cally_actor_parent_class)->finalize (obj);
+}
+
+/* AtkObject */
+
+static G_CONST_RETURN gchar*
+cally_actor_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar* name = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (cally_actor_parent_class)->get_name (obj);
+  if (name == NULL)
+    {
+      CallyActor *cally_actor = NULL;
+      ClutterActor *actor = NULL;
+
+      cally_actor = CALLY_ACTOR (obj);
+      actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+      if (actor == NULL) /* State is defunct */
+        name = NULL;
+      else
+        name = clutter_actor_get_name (actor);
+    }
+  return name;
+}
+
+static AtkObject *
+cally_actor_get_parent (AtkObject *obj)
+{
+  ClutterActor *parent_actor = NULL;
+  AtkObject    *parent       = NULL;
+  ClutterActor *actor        = NULL;
+  CallyActor    *cally_actor   = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL);
+
+  /* Check if we have and assigned parent */
+  if (obj->accessible_parent)
+    return obj->accessible_parent;
+
+  /* Try to get it from the clutter parent */
+  cally_actor = CALLY_ACTOR (obj);
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+  if (actor == NULL)  /* Object is defunct */
+    return NULL;
+
+  parent_actor = clutter_actor_get_parent (actor);
+  if (parent_actor == NULL)
+    return NULL;
+
+  parent = clutter_actor_get_accessible (parent_actor);
+
+  /* FIXME: I need to review the clutter-embed, to check if in this case I
+   * should get the widget accessible
+   */
+
+  return parent;
+}
+
+static gint
+cally_actor_get_index_in_parent (AtkObject *obj)
+{
+  CallyActor    *cally_actor   = NULL;
+  ClutterActor *actor        = NULL;
+  ClutterActor *parent_actor = NULL;
+  GList        *children     = NULL;
+  gint          index        = -1;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (obj), -1);
+
+  if (obj->accessible_parent)
+    {
+      gint n_children, i;
+      gboolean found = FALSE;
+
+      n_children = atk_object_get_n_accessible_children (obj->accessible_parent);
+      for (i = 0; i < n_children; i++)
+        {
+          AtkObject *child;
+
+          child = atk_object_ref_accessible_child (obj->accessible_parent, i);
+          if (child == obj)
+            found = TRUE;
+
+          g_object_unref (child);
+          if (found)
+            return i;
+        }
+      return -1;
+    }
+
+  cally_actor = CALLY_ACTOR (obj);
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+  if (actor == NULL) /* Object is defunct */
+    return -1;
+
+  parent_actor = clutter_actor_get_parent(actor);
+  if ((parent_actor == NULL)||(!CLUTTER_IS_CONTAINER(parent_actor)))
+    return -1;
+
+  children = clutter_container_get_children(CLUTTER_CONTAINER(parent_actor));
+
+  index = g_list_index (children, actor);
+  g_list_free (children);
+
+  return index;
+}
+
+static AtkStateSet*
+cally_actor_ref_state_set (AtkObject *obj)
+{
+  ClutterActor         *actor = NULL;
+  AtkStateSet          *state_set = NULL;
+  ClutterStage         *stage = NULL;
+  ClutterActor         *focus_actor = NULL;
+  CallyActor            *cally_actor = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL);
+  cally_actor = CALLY_ACTOR (obj);
+
+  state_set = ATK_OBJECT_CLASS (cally_actor_parent_class)->ref_state_set (obj);
+
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+
+  if (actor == NULL) /* Object is defunct */
+    {
+      atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
+    }
+  else
+    {
+      if (CLUTTER_ACTOR_IS_REACTIVE (actor))
+        {
+          atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
+          atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
+        }
+
+      if (CLUTTER_ACTOR_IS_VISIBLE (actor))
+        {
+          atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
+
+          if (_is_actor_on_screen (actor) &&
+              _cally_actor_all_parents_visible (actor))
+            atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
+        }
+
+      /* See focus section on implementation notes */
+      atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
+
+      stage = CLUTTER_STAGE (clutter_actor_get_stage (actor));
+      /* If for any reason this actor doesn't have a stage
+         associated, we try the default one as fallback */
+      if (stage == NULL)
+          stage = CLUTTER_STAGE (clutter_stage_get_default ());
+
+      focus_actor = clutter_stage_get_key_focus (stage);
+      if (focus_actor == actor)
+        atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
+    }
+
+  return state_set;
+}
+
+static gint
+cally_actor_get_n_children (AtkObject *obj)
+{
+  ClutterActor     *actor    = NULL;
+  CallyActorPrivate *priv     = NULL;
+  GList            *children = NULL;
+  gint              num      = 0;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (obj), 0);
+
+  priv = CALLY_ACTOR (obj)->priv;
+  actor = CALLY_GET_CLUTTER_ACTOR (obj);
+
+  if (actor == NULL) /* State is defunct */
+    return 0;
+
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0);
+
+  if (CLUTTER_IS_CONTAINER (actor))
+    {
+      children = clutter_container_get_children (CLUTTER_CONTAINER (actor));
+      num = g_list_length (children);
+
+      g_list_free (children);
+    }
+  else
+    {
+      num = 0;
+    }
+
+  return num;
+}
+
+static AtkObject*
+cally_actor_ref_child (AtkObject *obj,
+                      gint       i)
+{
+  ClutterActor     *actor    = NULL;
+  ClutterActor     *child    = NULL;
+  CallyActorPrivate *priv     = NULL;
+  GList            *children = NULL;
+  AtkObject        *result   = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL);
+
+  priv = CALLY_ACTOR (obj)->priv;
+  actor = CALLY_GET_CLUTTER_ACTOR (obj);
+
+  if (actor == NULL) /* State is defunct */
+    {
+      return NULL;
+    }
+
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
+
+  if (CLUTTER_IS_CONTAINER (actor))
+    {
+      children = clutter_container_get_children (CLUTTER_CONTAINER (actor));
+      child = g_list_nth_data (children, i);
+
+      result = clutter_actor_get_accessible (child);
+
+      g_object_ref (result);
+      g_list_free (children);
+    }
+  else
+    {
+      result = NULL;
+    }
+
+  return result;
+}
+
+/* ClutterContainer */
+static gint
+cally_actor_add_actor (ClutterActor *container,
+                      ClutterActor *actor,
+                      gpointer      data)
+{
+  CallyActor *cally_actor = CALLY_ACTOR (data);
+  CallyActorClass *klass = NULL;
+
+  klass = CALLY_ACTOR_GET_CLASS (cally_actor);
+
+  if (klass->add_actor)
+    return klass->add_actor (container, actor, data);
+  else
+    return 1;
+}
+
+static gint
+cally_actor_remove_actor (ClutterActor *container,
+                         ClutterActor *actor,
+                         gpointer      data)
+{
+  CallyActor      *cally_actor = CALLY_ACTOR (data);
+  CallyActorClass *klass      = NULL;
+
+  klass = CALLY_ACTOR_GET_CLASS (cally_actor);
+
+  if (klass->remove_actor)
+    return klass->remove_actor (container, actor, data);
+  else
+    return 1;
+}
+
+
+static gint
+cally_actor_real_add_actor (ClutterActor *container,
+                           ClutterActor *actor,
+                           gpointer      data)
+{
+  AtkObject        *atk_parent = ATK_OBJECT (data);
+  AtkObject        *atk_child  = clutter_actor_get_accessible (actor);
+  CallyActor        *cally_actor = CALLY_ACTOR (atk_parent);
+  CallyActorPrivate *priv       = cally_actor->priv;
+  gint              index;
+
+  g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0);
+
+  g_object_notify (G_OBJECT (atk_child), "accessible_parent");
+
+  g_list_free (priv->children);
+
+  priv->children =
+    clutter_container_get_children (CLUTTER_CONTAINER(container));
+
+  index = g_list_index (priv->children, actor);
+  g_signal_emit_by_name (atk_parent, "children_changed::add",
+                         index, atk_child, NULL);
+
+  return 1;
+}
+
+static gint
+cally_actor_real_remove_actor (ClutterActor *container,
+                              ClutterActor *actor,
+                              gpointer      data)
+{
+  AtkPropertyValues  values      = { NULL };
+  AtkObject*         atk_parent  = NULL;
+  AtkObject         *atk_child   = NULL;
+  CallyActorPrivate  *priv        = NULL;
+  gint               index;
+
+  g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), 0);
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0);
+
+  atk_parent = ATK_OBJECT (data);
+  atk_child = clutter_actor_get_accessible (actor);
+
+  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);
+    }
+
+  priv = CALLY_ACTOR (atk_parent)->priv;
+  index = g_list_index (priv->children, actor);
+  g_list_free (priv->children);
+  priv->children = clutter_container_get_children (CLUTTER_CONTAINER(container));
+
+  if (index >= 0 && index <= g_list_length (priv->children))
+    g_signal_emit_by_name (atk_parent, "children_changed::remove",
+                           index, atk_child, NULL);
+
+  return 1;
+}
+
+/* AtkComponent implementation */
+static void
+cally_actor_component_interface_init (AtkComponentIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_extents    = cally_actor_get_extents;
+  iface->get_mdi_zorder = cally_actor_get_mdi_zorder;
+
+  /* focus management */
+  iface->grab_focus           = cally_actor_grab_focus;
+  iface->add_focus_handler    = cally_actor_add_focus_handler;
+  iface->remove_focus_handler = cally_actor_remove_focus_handler;
+}
+
+static void
+cally_actor_get_extents (AtkComponent *component,
+                        gint         *x,
+                        gint         *y,
+                        gint         *width,
+                        gint         *height,
+                        AtkCoordType coord_type)
+{
+  CallyActor   *cally_actor = NULL;
+  ClutterActor *actor      = NULL;
+  gint          top_level_x, top_level_y;
+  gfloat        f_width, f_height;
+  ClutterVertex verts[4];
+
+  g_return_if_fail (CALLY_IS_ACTOR (component));
+
+  cally_actor = CALLY_ACTOR (component);
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+
+  if (actor == NULL) /* actor is defunct */
+    return;
+
+  clutter_actor_get_abs_allocation_vertices (actor, verts);
+  clutter_actor_get_transformed_size (actor, &f_width, &f_height);
+
+  *x = verts[0].x;
+  *y = verts[0].y;
+  *width = ceilf (f_width);
+  *height = ceilf (f_height);
+
+  /* In the ATK_XY_WINDOW case, we consider the stage as the
+   * "top-level-window"
+   *
+   * http://library.gnome.org/devel/atk/stable/AtkUtil.html#AtkCoordType
+   */
+
+  if (coord_type == ATK_XY_SCREEN)
+    {
+      _get_top_level_origin (actor, &top_level_x, &top_level_y);
+
+      *x += top_level_x;
+      *y += top_level_y;
+    }
+
+  return;
+}
+
+static gint
+cally_actor_get_mdi_zorder (AtkComponent *component)
+{
+  CallyActor    *cally_actor = NULL;
+  ClutterActor *actor = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (component), G_MININT);
+
+  cally_actor = CALLY_ACTOR(component);
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+
+  return clutter_actor_get_depth (actor);
+}
+
+static gboolean
+cally_actor_grab_focus (AtkComponent    *component)
+{
+  ClutterActor *actor      = NULL;
+  ClutterActor *stage      = NULL;
+  CallyActor    *cally_actor = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (component), FALSE);
+
+  /* See focus section on implementation notes */
+  cally_actor = CALLY_ACTOR(component);
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+  stage = clutter_actor_get_stage (actor);
+
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage),
+                               actor);
+
+  return TRUE;
+}
+
+/*
+ * These methods are basically taken from gail, as I don't see any
+ * reason to modify it. It makes me wonder why it is really required
+ * to be implemented in the toolkit
+ */
+static guint
+cally_actor_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
+cally_actor_remove_focus_handler (AtkComponent *component,
+                                  guint handler_id)
+{
+  g_signal_handler_disconnect (component, handler_id);
+}
+
+/* This method should check if the actor is currently on screen */
+static gboolean
+_is_actor_on_screen (ClutterActor *actor)
+{
+  /* FIXME: FILL ME!!
+   * You could get some ideas from clutter_actor_is_on_stage, a private clutter
+   * function (note: it doesn't exists in the last versions of clutter)
+   * A occlusion check could be a good idea too
+   */
+
+  return TRUE;
+}
+
+/**
+ *
+ * This gets the top level origin, it is, the position of the stage in
+ * the global screen. You can see it as the absolute display position
+ * of the stage.
+ *
+ * FIXME: only the case with x11 is implemented, other backends are
+ * required
+ *
+ **/
+static void
+_get_top_level_origin (ClutterActor *actor,
+                       gint         *x,
+                       gint         *y)
+{
+  /* default values */
+  *x = 0;
+  *y = 0;
+
+#ifdef HAVE_CLUTTER_X11
+  ClutterActor *stage      = NULL;
+  Display      *display    = NULL;
+  Window        root_window;
+  Window        stage_window;
+  Window        child;
+  gint          return_val = 0;
+
+  stage = clutter_actor_get_stage (actor);
+
+  display = clutter_x11_get_default_display (); /* FIXME: what happens if you use another
+                                                   display with clutter_backend_x11_set_display ?*/
+  root_window = clutter_x11_get_root_window ();
+  stage_window = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
+
+  return_val = XTranslateCoordinates (display, stage_window, root_window,
+                                      0, 0, x, y,
+                                      &child);
+
+  if (!return_val)
+    g_warning ("[x11] We were not able to get proper absolute position of the stage");
+#else
+  static gboolean yet_warned = FALSE;
+
+  if (!yet_warned)
+    {
+      yet_warned = TRUE;
+
+      g_warning ("Using a clutter backend not supported. "
+                 "atk_component_get_extents using ATK_XY_SCREEN could return a wrong screen position");
+    }
+
+#endif
+}
+
+/* AtkAction implementation */
+static void
+cally_actor_action_interface_init (AtkActionIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->do_action       = cally_actor_action_do_action;
+  iface->get_n_actions   = cally_actor_action_get_n_actions;
+  iface->get_description = cally_actor_action_get_description;
+  iface->get_keybinding  = cally_actor_action_get_keybinding;
+  iface->get_name        = cally_actor_action_get_name;
+  iface->set_description = cally_actor_action_set_description;
+}
+
+static gboolean
+cally_actor_action_do_action (AtkAction *action,
+                             gint       index)
+{
+  ClutterActor        *actor      = NULL;
+  CallyActor           *cally_actor = NULL;
+  AtkStateSet         *set        = NULL;
+  CallyActorPrivate    *priv       = NULL;
+  CallyActorActionInfo *info       = NULL;
+
+  cally_actor = CALLY_ACTOR (action);
+  priv = cally_actor->priv;
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+
+  set = atk_object_ref_state_set (ATK_OBJECT (cally_actor));
+
+  if (atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
+    return FALSE;
+
+  if (!atk_state_set_contains_state (set, ATK_STATE_SENSITIVE) ||
+      !atk_state_set_contains_state (set, ATK_STATE_SHOWING))
+    return FALSE;
+
+  g_object_unref (set);
+
+  info = _cally_actor_get_action_info (cally_actor, index);
+
+  if (info == NULL)
+    return FALSE;
+
+  if (info->do_action_func == NULL)
+    return FALSE;
+
+  if (!priv->action_queue)
+    priv->action_queue = g_queue_new ();
+
+  g_queue_push_head (priv->action_queue, info);
+
+  if (!priv->action_idle_handler)
+    priv->action_idle_handler = g_idle_add (idle_do_action, cally_actor);
+
+  return TRUE;
+}
+
+static gboolean
+idle_do_action (gpointer data)
+{
+  CallyActor        *cally_actor = NULL;
+  CallyActorPrivate *priv       = NULL;
+  ClutterActor     *actor      = NULL;
+
+  cally_actor = CALLY_ACTOR (data);
+  priv = cally_actor->priv;
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+  priv->action_idle_handler = 0;
+
+  if (actor == NULL) /* state is defunct*/
+    return FALSE;
+
+  while (!g_queue_is_empty (priv->action_queue))
+    {
+      CallyActorActionInfo *info = NULL;
+
+      info = (CallyActorActionInfo *) g_queue_pop_head (priv->action_queue);
+
+      info->do_action_func (cally_actor);
+    }
+
+  return FALSE;
+}
+
+static gint
+cally_actor_action_get_n_actions (AtkAction *action)
+{
+  CallyActor        *cally_actor = NULL;
+  CallyActorPrivate *priv       = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (action), 0);
+
+  cally_actor = CALLY_ACTOR (action);
+  priv       = cally_actor->priv;
+
+  return g_list_length (priv->action_list);
+}
+
+static G_CONST_RETURN gchar*
+cally_actor_action_get_name (AtkAction *action,
+                            gint       i)
+{
+  CallyActor           *cally_actor = NULL;
+  CallyActorActionInfo *info       = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (action), NULL);
+  cally_actor = CALLY_ACTOR (action);
+  info = _cally_actor_get_action_info (cally_actor, i);
+
+  if (info == NULL)
+    return NULL;
+
+  return info->name;
+}
+
+static G_CONST_RETURN gchar*
+cally_actor_action_get_description (AtkAction *action,
+                                   gint       i)
+{
+  CallyActor           *cally_actor = NULL;
+  CallyActorActionInfo *info       = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (action), NULL);
+  cally_actor = CALLY_ACTOR (action);
+  info = _cally_actor_get_action_info (cally_actor, i);
+
+  if (info == NULL)
+    return NULL;
+
+  return info->description;
+}
+
+static gboolean
+cally_actor_action_set_description (AtkAction   *action,
+                                   gint         i,
+                                   const gchar *desc)
+{
+  CallyActor           *cally_actor = NULL;
+  CallyActorActionInfo *info       = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (action), FALSE);
+  cally_actor = CALLY_ACTOR (action);
+  info = _cally_actor_get_action_info (cally_actor, i);
+
+  if (info == NULL)
+      return FALSE;
+
+  g_free (info->description);
+  info->description = g_strdup (desc);
+
+  return TRUE;
+}
+
+static G_CONST_RETURN gchar*
+cally_actor_action_get_keybinding (AtkAction *action,
+                                  gint       i)
+{
+  CallyActor           *cally_actor = NULL;
+  CallyActorActionInfo *info       = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (action), NULL);
+  cally_actor = CALLY_ACTOR (action);
+  info = _cally_actor_get_action_info (cally_actor, i);
+
+  if (info == NULL)
+    return NULL;
+
+  return info->keybinding;
+}
+
+/* Misc functions */
+
+/**
+ * Checks if the parent actor, and his parent, etc is all visible
+ * Used to check the showing property
+ *
+ * FIXME: the same functionality is implemented on clutter since version 0.8.4
+ * by clutter_actor_get_paint_visibility, so we should change this function
+ * if a clutter version update is made
+ **/
+static gboolean
+_cally_actor_all_parents_visible (ClutterActor *actor)
+{
+  ClutterActor *iter_parent = NULL;
+  gboolean      result      = TRUE;
+  ClutterActor *stage       = NULL;
+
+  stage = clutter_actor_get_stage (actor);
+
+  for (iter_parent = clutter_actor_get_parent(actor); iter_parent;
+       iter_parent = clutter_actor_get_parent(iter_parent))
+    {
+      if (!CLUTTER_ACTOR_IS_VISIBLE (iter_parent))
+        {
+          /* stage parent */
+          if (iter_parent != stage)
+            result = FALSE;
+          else
+            result = TRUE;
+
+          break;
+        }
+    }
+
+  return result;
+}
+
+/*
+ * This function is a signal handler for key_focus_in and
+ * key_focus_out signal which gets emitted on a ClutterActor
+ */
+static gboolean
+cally_actor_focus_clutter (ClutterActor *actor,
+                           gpointer      data)
+{
+  CallyActor      *cally_actor = NULL;
+  CallyActorClass *klass       = NULL;
+
+  cally_actor = CALLY_ACTOR (clutter_actor_get_accessible (actor));
+  klass = CALLY_ACTOR_GET_CLASS (cally_actor);
+  if (klass->focus_clutter)
+    return klass->focus_clutter (actor, data);
+  else
+    return FALSE;
+}
+
+static gboolean
+cally_actor_real_focus_clutter (ClutterActor *actor,
+                                gpointer      data)
+{
+  CallyActor *cally_actor = NULL;
+  gboolean return_val = FALSE;
+  gboolean in = FALSE;
+
+  in = GPOINTER_TO_INT (data);
+  cally_actor = CALLY_ACTOR (clutter_actor_get_accessible (actor));
+
+  g_signal_emit_by_name (cally_actor, "focus_event", in, &return_val);
+  atk_focus_tracker_notify (ATK_OBJECT (cally_actor));
+
+  return FALSE;
+}
+
+/*
+ * This function is a signal handler for notify signal which gets emitted
+ * when a property changes value on the ClutterActor associated with the object.
+ *
+ * It calls a function for the CallyActor type
+ */
+static void
+cally_actor_notify_clutter (GObject    *obj,
+                            GParamSpec *pspec)
+{
+  CallyActor      *cally_actor = NULL;
+  CallyActorClass *klass      = NULL;
+
+  cally_actor = CALLY_ACTOR (clutter_actor_get_accessible (CLUTTER_ACTOR (obj)));
+  klass = CALLY_ACTOR_GET_CLASS (cally_actor);
+
+  if (klass->notify_clutter)
+    klass->notify_clutter (obj, pspec);
+}
+
+/*
+ * This function is a signal handler for notify signal which gets emitted
+ * when a property changes value on the ClutterActor associated with a CallyActor
+ *
+ * It constructs an AtkPropertyValues structure and emits a "property_changed"
+ * signal which causes the user specified AtkPropertyChangeHandler
+ * to be called.
+ */
+static void
+cally_actor_real_notify_clutter (GObject    *obj,
+                                GParamSpec *pspec)
+{
+  ClutterActor* actor   = CLUTTER_ACTOR (obj);
+  AtkObject*    atk_obj = clutter_actor_get_accessible (CLUTTER_ACTOR(obj));
+  AtkState      state;
+  gboolean      value;
+
+  if (strcmp (pspec->name, "visible") == 0)
+    {
+      state = ATK_STATE_VISIBLE;
+      value = CLUTTER_ACTOR_IS_VISIBLE (actor);
+    }
+  else if (strcmp (pspec->name, "reactive") == 0)
+    {
+      state = ATK_STATE_SENSITIVE;
+      value = CLUTTER_ACTOR_IS_REACTIVE (actor);
+    }
+  else
+    return;
+
+  atk_object_notify_state_change (atk_obj, state, value);
+}
+
+static void
+cally_actor_focus_event (AtkObject   *obj,
+                         gboolean    focus_in)
+{
+  atk_object_notify_state_change (obj, ATK_STATE_FOCUSED, focus_in);
+}
+
+
+static void
+_cally_actor_clean_action_list (CallyActor *cally_actor)
+{
+  CallyActorPrivate *priv = NULL;
+
+  priv = cally_actor->priv;
+
+  if (priv->action_list)
+    {
+      g_list_foreach (priv->action_list,
+                      (GFunc) _cally_actor_destroy_action_info,
+                      NULL);
+      g_list_free (priv->action_list);
+      priv->action_list = NULL;
+    }
+}
+
+static CallyActorActionInfo *
+_cally_actor_get_action_info (CallyActor *cally_actor,
+                             gint       index)
+{
+  CallyActorPrivate *priv = NULL;
+  GList            *node = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), NULL);
+
+  priv = cally_actor->priv;
+
+  if (priv->action_list == NULL)
+    return NULL;
+
+  node = g_list_nth (priv->action_list, index);
+
+  if (node == NULL)
+    return NULL;
+
+  return (CallyActorActionInfo *)(node->data);
+}
+
+static void
+_cally_actor_click_action (CallyActor *cally_actor)
+{
+  ClutterEvent  tmp_event;
+  ClutterActor *stage = NULL;
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+  stage = clutter_actor_get_stage (actor);
+
+  /* press */
+  tmp_event.button.type = CLUTTER_BUTTON_PRESS;
+  tmp_event.button.time = CLUTTER_CURRENT_TIME;
+  tmp_event.button.stage = CLUTTER_STAGE (stage);
+  tmp_event.button.source = actor;
+  tmp_event.button.button = 1;
+
+  clutter_actor_event (actor, &tmp_event, FALSE);
+
+  /* release */
+  tmp_event.button.type = CLUTTER_BUTTON_RELEASE;
+
+  clutter_actor_event (actor, &tmp_event, FALSE);
+}
+
+static void
+_cally_actor_press_action (CallyActor *cally_actor)
+{
+  ClutterEvent  tmp_event;
+  ClutterActor *stage = NULL;
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+  stage = clutter_actor_get_stage (actor);
+
+  tmp_event.button.type = CLUTTER_BUTTON_PRESS;
+  tmp_event.button.time = CLUTTER_CURRENT_TIME;
+  tmp_event.button.stage = CLUTTER_STAGE (stage);
+  tmp_event.button.source = actor;
+  tmp_event.button.button = 1;
+
+  clutter_actor_event (actor, &tmp_event, FALSE);
+}
+
+static void
+_cally_actor_release_action (CallyActor *cally_actor)
+{
+  ClutterEvent  tmp_event;
+  ClutterActor *stage = NULL;
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+  stage = clutter_actor_get_stage (actor);
+
+  tmp_event.button.type = CLUTTER_BUTTON_RELEASE;
+  tmp_event.button.time = CLUTTER_CURRENT_TIME;
+  tmp_event.button.stage = CLUTTER_STAGE (stage);
+  tmp_event.button.source = actor;
+  tmp_event.button.button = 1;
+
+  clutter_actor_event (actor, &tmp_event, FALSE);
+}
+
+/**
+ * cally_actor_add_action:
+ * @action_name: the action name
+ * @action_description: the action description
+ * @action_keybinding: the action keybinding
+ * @action_func: the callback of the action, to be executed with do_action
+ *
+ * Adds a new action to be accessed with the AtkAction interface.
+ *
+ * Return value: added action id, or 0 if failure
+ *
+ * Since: 1.2
+ */
+guint
+cally_actor_add_action (CallyActor   *cally_actor,
+                        const gchar *action_name,
+                        const gchar *action_description,
+                        const gchar *action_keybinding,
+                        CallyActionFunc action_func)
+{
+  CallyActorActionInfo *info = NULL;
+  CallyActorPrivate    *priv = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), -1);
+  g_return_val_if_fail (action_func != NULL, -1);
+
+  priv = cally_actor->priv;
+
+  info = g_new (CallyActorActionInfo, 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;
+
+  priv->action_list = g_list_append (priv->action_list, (gpointer) info);
+
+  return g_list_length (priv->action_list);
+}
+
+/**
+ * cally_actor_remove_action:
+ * @action_id: the action id
+ *
+ * Removes a action, using the @action_id returned by cally_actor_add_action
+ *
+ * Return value: TRUE if the operation was succesful, FALSE otherwise
+ *
+ * Since: 1.2
+ */
+gboolean
+cally_actor_remove_action (CallyActor *cally_actor,
+                           gint       action_id)
+{
+  GList            *list_node = NULL;
+  CallyActorPrivate *priv      = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), FALSE);
+  priv = cally_actor->priv;
+
+  list_node = g_list_nth (priv->action_list, action_id - 1);
+
+  if (!list_node)
+    return FALSE;
+
+  _cally_actor_destroy_action_info (list_node->data, NULL);
+
+  priv->action_list = g_list_remove_link (priv->action_list, list_node);
+
+  return TRUE;
+}
+
+/**
+ * cally_actor_remove_action:
+ * @action_name: the name of the action
+ *
+ * Removes a action, using the @action_name used when the action was added
+ * with cally_actor_add_action
+ *
+ * Return value: TRUE if the operation was succesful, FALSE otherwise
+ *
+ * Since: 1.2
+ */
+gboolean
+cally_actor_remove_action_by_name (CallyActor   *cally_actor,
+                                   const gchar *action_name)
+{
+  GList            *node         = NULL;
+  gboolean          action_found = FALSE;
+  CallyActorPrivate *priv         = NULL;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), FALSE);
+  priv = CALLY_ACTOR (cally_actor)->priv;
+
+  for (node = priv->action_list; node && !action_found;
+       node = node->next)
+    {
+      if (!g_strcasecmp (((CallyActorActionInfo *)(node->data))->name, action_name))
+       {
+         action_found = TRUE;
+         break;
+       }
+    }
+  if (!action_found)
+    return FALSE;
+
+  _cally_actor_destroy_action_info (node->data, NULL);
+  priv->action_list = g_list_remove_link (priv->action_list, node);
+
+  return TRUE;
+}
+
+
+static void
+_cally_actor_destroy_action_info (gpointer action_info,
+                                 gpointer user_data)
+{
+  CallyActorActionInfo *info = (CallyActorActionInfo *)action_info;
+
+  g_assert (info != NULL);
+
+  g_free (info->name);
+  g_free (info->description);
+  g_free (info->keybinding);
+
+  g_free (info);
+}
diff --git a/clutter/cally/cally-actor.h b/clutter/cally/cally-actor.h
new file mode 100644 (file)
index 0000000..7078459
--- /dev/null
@@ -0,0 +1,108 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * Some parts are based on GailWidget from GAIL
+ * 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.
+ */
+
+#ifndef __CALLY_ACTOR_H__
+#define __CALLY_ACTOR_H__
+
+#include <atk/atk.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_ACTOR            (cally_actor_get_type ())
+#define CALLY_ACTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_ACTOR, CallyActor))
+#define CALLY_ACTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_ACTOR, CallyActorClass))
+#define CALLY_IS_ACTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_ACTOR))
+#define CALLY_IS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_ACTOR))
+#define CALLY_ACTOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_ACTOR, CallyActorClass))
+
+typedef struct _CallyActor           CallyActor;
+typedef struct _CallyActorClass      CallyActorClass;
+typedef struct _CallyActorPrivate    CallyActorPrivate;
+
+/**
+ * CallyActionFunc:
+ * @cally_actor: a #CallyActor
+ *
+ * Action func, to be used on AtkAction implementation as a individual
+ * action
+ */
+typedef void (*CallyActionFunc) (CallyActor *cally_actor);
+
+struct _CallyActor
+{
+  AtkGObjectAccessible parent;
+
+  /* < private > */
+  CallyActorPrivate *priv;
+};
+
+struct _CallyActorClass
+{
+  AtkGObjectAccessibleClass parent_class;
+
+  /* Signal handler for notify signal on Clutter Actor */
+  void     (*notify_clutter) (GObject    *object,
+                              GParamSpec *pspec);
+
+  /*
+   * Signal handler for key_focus_in and key_focus_out on Clutter Actor
+   */
+  gboolean (*focus_clutter)  (ClutterActor *actor,
+                              gpointer      data);
+
+  gint     (*add_actor)      (ClutterActor *container,
+                              ClutterActor *actor,
+                              gpointer      data);
+
+  gint     (*remove_actor)   (ClutterActor *container,
+                              ClutterActor *actor,
+                              gpointer      data);
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+
+GType      cally_actor_get_type              (void);
+
+AtkObject* cally_actor_new                   (ClutterActor *actor);
+guint      cally_actor_add_action            (CallyActor   *cally_actor,
+                                              const gchar *action_name,
+                                              const gchar *action_description,
+                                              const gchar *action_keybinding,
+                                              CallyActionFunc action_func);
+
+gboolean   cally_actor_remove_action         (CallyActor   *cally_actor,
+                                              gint         action_id);
+
+gboolean   cally_actor_remove_action_by_name (CallyActor   *cally_actor,
+                                              const gchar *action_name);
+
+
+G_END_DECLS
+
+#endif /* __CALLY_ACTOR_H__ */
diff --git a/clutter/cally/cally-clone.c b/clutter/cally/cally-clone.c
new file mode 100644 (file)
index 0000000..0bde120
--- /dev/null
@@ -0,0 +1,105 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2010 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:callyclutterclone
+ * @short_description: Implementation of the ATK interfaces for a #ClutterClone
+ * @see_also: #ClutterClone
+ *
+ * #CallyClutterClone implements the required ATK interfaces of #ClutterClone
+ *
+ * In particular it sets a proper role for the clone, as just a image,
+ * as it is the sanest and simplest approach.
+ *
+ * Check http://lists.o-hand.com/clutter/3797.html for more information
+ */
+
+#include "cally-clone.h"
+#include "cally-actor-private.h"
+
+#define CALLY_CLONE_DEFAULT_DESCRIPTION "ClutterClone accessibility object"
+
+static void cally_clone_class_init (CallyCloneClass *klass);
+static void cally_clone_init       (CallyClone *clone);
+
+/* AtkObject */
+static void                  cally_clone_real_initialize (AtkObject *obj,
+                                                           gpointer   data);
+static G_CONST_RETURN gchar *cally_clone_get_description (AtkObject *obj);
+
+
+G_DEFINE_TYPE (CallyClone, cally_clone, CALLY_TYPE_ACTOR)
+
+static void
+cally_clone_class_init (CallyCloneClass *klass)
+{
+/*   GObjectClass   *gobject_class = G_OBJECT_CLASS (klass); */
+  AtkObjectClass *class         = ATK_OBJECT_CLASS (klass);
+
+  class->initialize      = cally_clone_real_initialize;
+  class->get_description = cally_clone_get_description;
+}
+
+static void
+cally_clone_init (CallyClone *clone)
+{
+  /* nothing to do yet */
+}
+
+AtkObject*
+cally_clone_new (ClutterActor *actor)
+{
+  GObject   *object     = NULL;
+  AtkObject *accessible = NULL;
+
+  g_return_val_if_fail (CLUTTER_IS_CLONE (actor), NULL);
+
+  object = g_object_new (CALLY_TYPE_CLONE, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, actor);
+
+  return accessible;
+}
+
+static void
+cally_clone_real_initialize (AtkObject *obj,
+                              gpointer   data)
+{
+  ATK_OBJECT_CLASS (cally_clone_parent_class)->initialize (obj, data);
+
+  obj->role = ATK_ROLE_IMAGE;
+}
+
+static G_CONST_RETURN gchar *
+cally_clone_get_description (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *description = NULL;
+
+  g_return_val_if_fail (CALLY_IS_CLONE (obj), NULL);
+
+  description = ATK_OBJECT_CLASS (cally_clone_parent_class)->get_description (obj);
+  if (description == NULL)
+    description = CALLY_CLONE_DEFAULT_DESCRIPTION;
+
+  return description;
+}
diff --git a/clutter/cally/cally-clone.h b/clutter/cally/cally-clone.h
new file mode 100644 (file)
index 0000000..7b63dbe
--- /dev/null
@@ -0,0 +1,63 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2010 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+#ifndef __CALLY_CLONE_H__
+#define __CALLY_CLONE_H__
+
+#include "cally-actor.h"
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_CLONE            (cally_clone_get_type ())
+#define CALLY_CLONE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_CLONE, CallyClone))
+#define CALLY_CLONE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_CLONE, CallyCloneClass))
+#define CALLY_IS_CLONE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_CLONE))
+#define CALLY_IS_CLONE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_CLONE))
+#define CALLY_CLONE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_CLONE, CallyCloneClass))
+
+
+typedef struct _CallyClone        CallyClone;
+typedef struct _CallyCloneClass   CallyCloneClass;
+typedef struct _CallyClonePrivate CallyClonePrivate;
+
+struct _CallyClone
+{
+  CallyActor parent;
+
+  /* < private > */
+  CallyClonePrivate *priv;
+};
+
+struct _CallyCloneClass
+{
+  CallyActorClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+GType      cally_clone_get_type (void);
+AtkObject *cally_clone_new      (ClutterActor *actor);
+
+G_END_DECLS
+
+#endif /* __CALLY_CLONE_H__ */
diff --git a/clutter/cally/cally-factory.h b/clutter/cally/cally-factory.h
new file mode 100644 (file)
index 0000000..37e0219
--- /dev/null
@@ -0,0 +1,91 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * Based on gailfactory.h from GAIL
+ * 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.
+ */
+
+#ifndef _CALLY_FACTORY_H__
+#define _CALLY_FACTORY_H__
+
+#include <glib-object.h>
+#include <atk/atkobject.h>
+
+#define CALLY_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)                  \
+{                                                                              \
+  ClutterActor *actor;                                                         \
+  AtkObject *accessible;                                                       \
+                                                                               \
+  g_return_val_if_fail (CLUTTER_ACTOR (obj), NULL);                            \
+                                                                               \
+  actor = CLUTTER_ACTOR (obj);                                                  \
+                                                                               \
+  accessible = opt_create_accessible (actor);                                  \
+                                                                               \
+  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 CALLY_ACTOR_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 /* _CALLY_FACTORY_H__ */
diff --git a/clutter/cally/cally-group.c b/clutter/cally/cally-group.c
new file mode 100644 (file)
index 0000000..ddcd9f8
--- /dev/null
@@ -0,0 +1,138 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * Based on GailContainer from GAIL
+ * 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.
+ */
+
+/**
+ * SECTION:callycluttergroup
+ * @short_description: Implementation of the ATK interfaces for a #ClutterGroup
+ * @see_also: #ClutterGroup
+ *
+ * #CallyClutterGroup implements the required ATK interfaces of #ClutterGroup
+ * In particular it exposes:
+ * <itemizedlist>
+ * <listitem>Each of the Clutter actors contained in the Clutter Group.</listitem>
+ * </itemizedlist>
+ */
+
+#include "cally-group.h"
+#include "cally-actor-private.h"
+
+static void       cally_group_class_init      (CallyGroupClass *klass);
+static void       cally_group_init            (CallyGroup *group);
+static gint       cally_group_get_n_children  (AtkObject *obj);
+static AtkObject* cally_group_ref_child       (AtkObject *obj,
+                                              gint       i);
+static void       cally_group_real_initialize (AtkObject *obj,
+                                              gpointer   data);
+
+G_DEFINE_TYPE (CallyGroup, cally_group, CALLY_TYPE_ACTOR)
+
+static void
+cally_group_class_init (CallyGroupClass *klass)
+{
+/*   GObjectClass   *gobject_class = G_OBJECT_CLASS (klass); */
+  AtkObjectClass *class         = ATK_OBJECT_CLASS (klass);
+
+  class->get_n_children = cally_group_get_n_children;
+  class->ref_child      = cally_group_ref_child;
+  class->initialize     = cally_group_real_initialize;
+}
+
+static void
+cally_group_init (CallyGroup      *group)
+{
+  /* nothing to do yet */
+}
+
+AtkObject*
+cally_group_new (ClutterActor *actor)
+{
+  GObject   *object     = NULL;
+  AtkObject *accessible = NULL;
+
+  g_return_val_if_fail (CLUTTER_IS_GROUP (actor), NULL);
+
+  object = g_object_new (CALLY_TYPE_GROUP, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, actor);
+
+  return accessible;
+}
+
+static gint
+cally_group_get_n_children (AtkObject *obj)
+{
+  ClutterActor *actor = NULL;
+  gint          count = 0;
+
+  g_return_val_if_fail (CALLY_IS_GROUP (obj), count);
+
+  actor = CALLY_GET_CLUTTER_ACTOR (obj);
+
+  if (actor == NULL) /* defunct */
+    return 0;
+
+  g_return_val_if_fail (CLUTTER_IS_GROUP(actor), count);
+
+  count = clutter_group_get_n_children (CLUTTER_GROUP (actor));
+
+  return count;
+}
+
+static AtkObject*
+cally_group_ref_child (AtkObject *obj,
+                       gint       i)
+{
+  AtkObject    *accessible = NULL;
+  ClutterActor *actor      = NULL;
+  ClutterActor *child      = NULL;
+
+  g_return_val_if_fail (CALLY_IS_GROUP (obj), NULL);
+  g_return_val_if_fail ((i >= 0), NULL);
+
+  actor = CALLY_GET_CLUTTER_ACTOR (obj);
+
+  g_return_val_if_fail (CLUTTER_IS_GROUP(actor), NULL);
+  child = clutter_group_get_nth_child (CLUTTER_GROUP(actor), i);
+
+  if (!child)
+    return NULL;
+
+  accessible = clutter_actor_get_accessible (child);
+
+  if (accessible != NULL)
+    g_object_ref (accessible);
+
+  return accessible;
+}
+
+static void
+cally_group_real_initialize (AtkObject *obj,
+                            gpointer   data)
+{
+  ATK_OBJECT_CLASS (cally_group_parent_class)->initialize (obj, data);
+
+  obj->role = ATK_ROLE_PANEL;
+}
diff --git a/clutter/cally/cally-group.h b/clutter/cally/cally-group.h
new file mode 100644 (file)
index 0000000..8692003
--- /dev/null
@@ -0,0 +1,65 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * Based on GailContainer from GAIL
+ * 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.
+ */
+
+#ifndef __CALLY_GROUP_H__
+#define __CALLY_GROUP_H__
+
+#include "cally-actor.h"
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_GROUP                         (cally_group_get_type ())
+#define CALLY_GROUP(obj)                         (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_GROUP, CallyGroup))
+#define CALLY_GROUP_CLASS(klass)                 (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_GROUP, CallyGroupClass))
+#define CALLY_IS_GROUP(obj)                      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_GROUP))
+#define CALLY_IS_GROUP_CLASS(klass)              (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_GROUP))
+#define CALLY_GROUP_GET_CLASS(obj)               (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_GROUP, CallyGroupClass))
+
+typedef struct _CallyGroup        CallyGroup;
+typedef struct _CallyGroupClass   CallyGroupClass;
+typedef struct _CallyGroupPrivate CallyGroupPrivate;
+
+struct _CallyGroup
+{
+  CallyActor parent;
+
+  /* < private > */
+  CallyGroupPrivate *priv;
+};
+
+struct _CallyGroupClass
+{
+  CallyActorClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+GType      cally_group_get_type (void);
+AtkObject* cally_group_new      (ClutterActor *actor);
+
+G_END_DECLS
+
+#endif /* __CALLY_GROUP_H__ */
diff --git a/clutter/cally/cally-rectangle.c b/clutter/cally/cally-rectangle.c
new file mode 100644 (file)
index 0000000..934beb9
--- /dev/null
@@ -0,0 +1,102 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:callyclutterrectangle
+ * @short_description: Implementation of the ATK interfaces for a #ClutterRectangle
+ * @see_also: #ClutterRectangle
+ *
+ * #CallyClutterRectangle implements the required ATK interfaces of #ClutterRectangle
+ *
+ * In particular it sets a proper role for the rectangle.
+ */
+
+#include "cally-rectangle.h"
+#include "cally-actor-private.h"
+
+#define CALLY_RECTANGLE_DEFAULT_DESCRIPTION "A rectangle"
+
+static void cally_rectangle_class_init (CallyRectangleClass *klass);
+static void cally_rectangle_init       (CallyRectangle *rectangle);
+
+/* AtkObject */
+static void                  cally_rectangle_real_initialize (AtkObject *obj,
+                                                             gpointer   data);
+static G_CONST_RETURN gchar *cally_rectangle_get_description (AtkObject *obj);
+
+
+G_DEFINE_TYPE (CallyRectangle, cally_rectangle, CALLY_TYPE_ACTOR)
+
+static void
+cally_rectangle_class_init (CallyRectangleClass *klass)
+{
+/*   GObjectClass   *gobject_class = G_OBJECT_CLASS (klass); */
+  AtkObjectClass *class         = ATK_OBJECT_CLASS (klass);
+
+  class->initialize      = cally_rectangle_real_initialize;
+  class->get_description = cally_rectangle_get_description;
+}
+
+static void
+cally_rectangle_init (CallyRectangle *rectangle)
+{
+  /* nothing to do yet */
+}
+
+AtkObject*
+cally_rectangle_new (ClutterActor *actor)
+{
+  GObject   *object     = NULL;
+  AtkObject *accessible = NULL;
+
+  g_return_val_if_fail (CLUTTER_IS_RECTANGLE (actor), NULL);
+
+  object = g_object_new (CALLY_TYPE_RECTANGLE, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, actor);
+
+  return accessible;
+}
+
+static void
+cally_rectangle_real_initialize (AtkObject *obj,
+                                 gpointer   data)
+{
+  ATK_OBJECT_CLASS (cally_rectangle_parent_class)->initialize (obj, data);
+
+  obj->role = ATK_ROLE_IMAGE;
+}
+
+static G_CONST_RETURN gchar *
+cally_rectangle_get_description                    (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *description = NULL;
+
+  g_return_val_if_fail (CALLY_IS_RECTANGLE (obj), NULL);
+
+  description = ATK_OBJECT_CLASS (cally_rectangle_parent_class)->get_description (obj);
+  if (description == NULL)
+    description = CALLY_RECTANGLE_DEFAULT_DESCRIPTION;
+
+  return description;
+}
diff --git a/clutter/cally/cally-rectangle.h b/clutter/cally/cally-rectangle.h
new file mode 100644 (file)
index 0000000..b2230c3
--- /dev/null
@@ -0,0 +1,63 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+#ifndef __CALLY_RECTANGLE_H__
+#define __CALLY_RECTANGLE_H__
+
+#include "cally-actor.h"
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_RECTANGLE            (cally_rectangle_get_type ())
+#define CALLY_RECTANGLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_RECTANGLE, CallyRectangle))
+#define CALLY_RECTANGLE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_RECTANGLE, CallyRectangleClass))
+#define CALLY_IS_RECTANGLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_RECTANGLE))
+#define CALLY_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_RECTANGLE))
+#define CALLY_RECTANGLE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_RECTANGLE, CallyRectangleClass))
+
+
+typedef struct _CallyRectangle         CallyRectangle;
+typedef struct _CallyRectangleClass    CallyRectangleClass;
+typedef struct _CallyRectanglePrivate  CallyRectanglePrivate;
+
+struct _CallyRectangle
+{
+  CallyActor parent;
+
+  /* < private > */
+  CallyRectanglePrivate *priv;
+};
+
+struct _CallyRectangleClass
+{
+  CallyActorClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+GType      cally_rectangle_get_type (void);
+AtkObject* cally_rectangle_new      (ClutterActor *actor);
+
+G_END_DECLS
+
+#endif /* __CALLY_RECTANGLE_H__ */
diff --git a/clutter/cally/cally-root.c b/clutter/cally/cally-root.c
new file mode 100644 (file)
index 0000000..b789753
--- /dev/null
@@ -0,0 +1,273 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:callyroot
+ * @short_description: Root object for the CALLY toolkit
+ * @see_also: #ClutterStage
+ *
+ * #CallyRoot is the root object of the accessibility tree-like
+ * hierarchy, exposing the application level.
+ *
+ * Somewhat equivalent to GailTopLevel. We consider that this class
+ * expose the a11y information of the ClutterStageManager, as the
+ * children of this object are the different ClutterStage managed (so
+ * the GObject used in the atk_object_initialize is the
+ * ClutterStageManager).
+ *
+ */
+
+#include <clutter/clutter.h>
+#include "cally-root.h"
+
+/* GObject */
+static void cally_root_class_init (CallyRootClass *klass);
+static void cally_root_init       (CallyRoot *root);
+static void cally_root_finalize   (GObject *object);
+
+/* AtkObject.h */
+static void       cally_root_initialize                            (AtkObject *accessible,
+                                                                    gpointer   data);
+static gint       cally_root_get_n_children                        (AtkObject *obj);
+static AtkObject *cally_root_ref_child                             (AtkObject *obj,
+                                                                    gint i);
+static AtkObject *cally_root_get_parent                            (AtkObject *obj);
+
+/* Private */
+static void       cally_util_stage_added_cb                        (ClutterStageManager *stage_manager,
+                                                                    ClutterStage *stage,
+                                                                    gpointer data);
+static void       cally_util_stage_removed_cb                      (ClutterStageManager *stage_manager,
+                                                                    ClutterStage *stage,
+                                                                    gpointer data);
+
+#define CALLY_ROOT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CALLY_TYPE_ROOT, CallyRootPrivate))
+
+G_DEFINE_TYPE (CallyRoot, cally_root,  ATK_TYPE_GOBJECT_ACCESSIBLE)
+
+struct _CallyRootPrivate
+{
+/* We save the CallyStage objects. Other option could save the stage
+ * list, and then just get the a11y object on the ref_child, etc. But
+ * the ref_child is more common that the init and the stage-add,
+ * stage-remove, so we avoid getting the accessible object
+ * constantly
+ */
+  GSList *stage_list;
+
+  /* signals id */
+  guint stage_added_id;
+  guint stage_removed_id;
+};
+
+static void
+cally_root_class_init (CallyRootClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = cally_root_finalize;
+
+  /* AtkObject */
+  class->get_n_children = cally_root_get_n_children;
+  class->ref_child = cally_root_ref_child;
+  class->get_parent = cally_root_get_parent;
+  class->initialize = cally_root_initialize;
+
+  g_type_class_add_private (gobject_class, sizeof (CallyRootPrivate));
+}
+
+static void
+cally_root_init (CallyRoot      *root)
+{
+  root->priv = CALLY_ROOT_GET_PRIVATE (root);
+
+  root->priv->stage_list = NULL;
+  root->priv->stage_added_id = 0;
+  root->priv->stage_removed_id = 0;
+}
+
+AtkObject*
+cally_root_new (void)
+{
+  GObject *object = NULL;
+  AtkObject *accessible = NULL;
+  ClutterStageManager *stage_manager = NULL;
+
+  object = g_object_new (CALLY_TYPE_ROOT, NULL);
+
+  accessible = ATK_OBJECT (object);
+  stage_manager = clutter_stage_manager_get_default ();
+
+  atk_object_initialize (accessible, stage_manager);
+
+  return accessible;
+}
+
+static void
+cally_root_finalize (GObject *object)
+{
+  CallyRoot *root = CALLY_ROOT (object);
+  GObject *stage_manager = NULL;
+
+  g_return_if_fail (CALLY_IS_ROOT (object));
+
+  if (root->priv->stage_list)
+    {
+      g_slist_free (root->priv->stage_list);
+      root->priv->stage_list = NULL;
+    }
+
+  stage_manager = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (root));
+
+  g_signal_handler_disconnect (stage_manager,
+                               root->priv->stage_added_id);
+
+  g_signal_handler_disconnect (stage_manager,
+                               root->priv->stage_added_id);
+
+  G_OBJECT_CLASS (cally_root_parent_class)->finalize (object);
+}
+
+/* AtkObject.h */
+static void
+cally_root_initialize (AtkObject              *accessible,
+                       gpointer                data)
+{
+  ClutterStageManager *stage_manager = NULL;
+  const GSList        *iter          = NULL;
+  const GSList        *stage_list    = NULL;
+  ClutterStage        *clutter_stage = NULL;
+  AtkObject           *cally_stage   = NULL;
+  CallyRoot           *root          = NULL;
+
+  accessible->role = ATK_ROLE_APPLICATION;
+  accessible->name = g_get_prgname();
+  accessible->accessible_parent = NULL;
+
+  /* children initialization */
+  root = CALLY_ROOT (accessible);
+  stage_manager = CLUTTER_STAGE_MANAGER (data);
+  stage_list = clutter_stage_manager_peek_stages (stage_manager);
+
+  for (iter = stage_list; iter != NULL; iter = g_slist_next (iter))
+    {
+      clutter_stage = CLUTTER_STAGE (iter->data);
+      cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (clutter_stage));
+
+      root->priv->stage_list = g_slist_append (root->priv->stage_list,
+                                               cally_stage);
+    }
+
+  root->priv->stage_added_id =
+    g_signal_connect (G_OBJECT (stage_manager), "stage-added",
+                      G_CALLBACK (cally_util_stage_added_cb), root);
+
+  root->priv->stage_removed_id =
+    g_signal_connect (G_OBJECT (stage_manager), "stage-removed",
+                      G_CALLBACK (cally_util_stage_removed_cb), root);
+
+  ATK_OBJECT_CLASS (cally_root_parent_class)->initialize (accessible, data);
+}
+
+
+static gint
+cally_root_get_n_children (AtkObject *obj)
+{
+  CallyRoot *root = CALLY_ROOT (obj);
+
+  return g_slist_length (root->priv->stage_list);
+}
+
+static AtkObject*
+cally_root_ref_child (AtkObject *obj,
+                     gint i)
+{
+  CallyRoot *cally_root = NULL;
+  GSList *stage_list = NULL;
+  gint num = 0;
+  AtkObject *item = NULL;
+
+  cally_root = CALLY_ROOT (obj);
+  stage_list = cally_root->priv->stage_list;
+  num = g_slist_length (stage_list);
+
+  g_return_val_if_fail ((i < num)&&(i >= 0), NULL);
+
+  item = g_slist_nth_data (stage_list, i);
+  if (!item)
+    {
+      return NULL;
+    }
+
+  g_object_ref (item);
+
+  return item;
+}
+
+static AtkObject*
+cally_root_get_parent (AtkObject *obj)
+{
+  return NULL;
+}
+
+/* -------------------------------- PRIVATE --------------------------------- */
+
+static void
+cally_util_stage_added_cb (ClutterStageManager *stage_manager,
+                           ClutterStage *stage,
+                           gpointer data)
+{
+  CallyRoot *root = CALLY_ROOT (data);
+  AtkObject *cally_stage = NULL;
+  gint index = -1;
+
+  cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (stage));
+
+  root->priv->stage_list = g_slist_append (root->priv->stage_list,
+                                           cally_stage);
+
+  index = g_slist_index (root->priv->stage_list, cally_stage);
+  g_signal_emit_by_name (root, "children_changed::add",
+                         index, cally_stage, NULL);
+}
+
+static void
+cally_util_stage_removed_cb (ClutterStageManager *stage_manager,
+                             ClutterStage *stage,
+                             gpointer data)
+{
+  CallyRoot *root = CALLY_ROOT (data);
+  AtkObject *cally_stage = NULL;
+  gint index = -1;
+
+  cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (stage));
+
+  index = g_slist_index (root->priv->stage_list, cally_stage);
+
+  root->priv->stage_list = g_slist_remove (root->priv->stage_list,
+                                           cally_stage);
+
+  index = g_slist_index (root->priv->stage_list, cally_stage);
+  g_signal_emit_by_name (root, "children_changed::remove",
+                         index, cally_stage, NULL);
+}
diff --git a/clutter/cally/cally-root.h b/clutter/cally/cally-root.h
new file mode 100644 (file)
index 0000000..540a742
--- /dev/null
@@ -0,0 +1,64 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+#ifndef __CALLY_ROOT_H__
+#define __CALLY_ROOT_H__
+
+#include <atk/atk.h>
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_ROOT            (cally_root_get_type ())
+#define CALLY_ROOT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_ROOT, CallyRoot))
+#define CALLY_ROOT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_ROOT, CallyRootClass))
+#define CALLY_IS_ROOT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_ROOT))
+#define CALLY_IS_ROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_ROOT))
+#define CALLY_ROOT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_ROOT, CallyRootClass))
+
+typedef struct _CallyRoot        CallyRoot;
+typedef struct _CallyRootClass   CallyRootClass;
+typedef struct _CallyRootPrivate CallyRootPrivate;
+
+struct _CallyRoot
+{
+  AtkGObjectAccessible parent;
+
+  /* < private > */
+  CallyRootPrivate *priv;
+};
+
+struct _CallyRootClass
+{
+  AtkGObjectAccessibleClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+
+GType      cally_root_get_type (void);
+AtkObject *cally_root_new      (void);
+
+
+G_END_DECLS
+
+#endif /* __CALLY_ROOT_H__ */
diff --git a/clutter/cally/cally-stage.c b/clutter/cally/cally-stage.c
new file mode 100644 (file)
index 0000000..57f037b
--- /dev/null
@@ -0,0 +1,258 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:callystage
+ * @short_description: Implementation of the ATK interfaces for a #ClutterStage
+ * @see_also: #ClutterStage
+ *
+ * #CallyStage implements the required ATK interfaces of #ClutterStage
+ *
+ */
+
+#include "cally-stage.h"
+#include "cally-actor-private.h"
+
+enum {
+  ACTIVATE,
+  CREATE,
+  DEACTIVATE,
+  DESTROY,
+  LAST_SIGNAL
+};
+
+static guint cally_stage_signals [LAST_SIGNAL] = { 0, };
+
+static void cally_stage_class_init (CallyStageClass *klass);
+static void cally_stage_init       (CallyStage      *stage);
+
+/* AtkObject.h */
+static G_CONST_RETURN gchar *cally_stage_get_name        (AtkObject *obj);
+static G_CONST_RETURN gchar *cally_stage_get_description (AtkObject *obj);
+static void                  cally_stage_real_initialize (AtkObject *obj,
+                                                          gpointer   data);
+static AtkStateSet*          cally_stage_ref_state_set   (AtkObject *obj);
+
+/* Auxiliar */
+static void                  cally_stage_activate_cb     (ClutterStage *stage,
+                                                          gpointer      data);
+static void                  cally_stage_deactivate_cb   (ClutterStage *stage,
+                                                          gpointer      data);
+
+
+#define CALLY_STAGE_DEFAULT_NAME        "Stage"
+#define CALLY_STAGE_DEFAULT_DESCRIPTION "Top level 'window' on which child actors are placed and manipulated"
+
+G_DEFINE_TYPE (CallyStage, cally_stage, CALLY_TYPE_GROUP);
+
+#define CALLY_STAGE_GET_PRIVATE(obj) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CALLY_TYPE_STAGE, CallyStagePrivate))
+
+struct _CallyStagePrivate
+{
+  gboolean active;
+};
+
+static void
+cally_stage_class_init (CallyStageClass *klass)
+{
+  GObjectClass   *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class         = ATK_OBJECT_CLASS (klass);
+/*   CallyActorClass *cally_class  = CALLY_ACTOR_CLASS (klass); */
+
+  /* AtkObject */
+  class->get_name = cally_stage_get_name;
+  class->get_description = cally_stage_get_description;
+  class->initialize = cally_stage_real_initialize;
+  class->ref_state_set = cally_stage_ref_state_set;
+
+  g_type_class_add_private (gobject_class, sizeof (CallyStagePrivate));
+
+  cally_stage_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);
+  cally_stage_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);
+  cally_stage_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);
+  cally_stage_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);
+}
+
+static void
+cally_stage_init (CallyStage *cally_stage)
+{
+  CallyStagePrivate *priv = CALLY_STAGE_GET_PRIVATE (cally_stage);
+
+  cally_stage->priv = priv;
+
+  priv->active = FALSE;
+}
+
+AtkObject*
+cally_stage_new (ClutterActor *actor)
+{
+  GObject   *object     = NULL;
+  AtkObject *accessible = NULL;
+
+  g_return_val_if_fail (CLUTTER_IS_STAGE (actor), NULL);
+
+  object = g_object_new (CALLY_TYPE_STAGE, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, actor);
+
+  return accessible;
+}
+
+/* AtkObject.h */
+static G_CONST_RETURN gchar *
+cally_stage_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *name = NULL;
+
+  g_return_val_if_fail (CALLY_IS_STAGE (obj), NULL);
+
+  /* parent name */
+  name = ATK_OBJECT_CLASS (cally_stage_parent_class)->get_name (obj);
+
+  if (name == NULL)
+    name = CALLY_STAGE_DEFAULT_NAME;
+
+  return name;
+}
+
+static G_CONST_RETURN gchar *
+cally_stage_get_description (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *description = NULL;
+
+  g_return_val_if_fail (CALLY_IS_STAGE (obj), NULL);
+
+  /* parent description */
+  description = ATK_OBJECT_CLASS (cally_stage_parent_class)->get_description (obj);
+
+  if (description == NULL)
+    description = CALLY_STAGE_DEFAULT_DESCRIPTION;
+
+  return description;
+}
+
+static void
+cally_stage_real_initialize (AtkObject *obj,
+                             gpointer  data)
+{
+  ClutterStage *stage = NULL;
+
+  g_return_if_fail (CALLY_IS_STAGE (obj));
+
+  ATK_OBJECT_CLASS (cally_stage_parent_class)->initialize (obj, data);
+
+  stage = CLUTTER_STAGE (CALLY_GET_CLUTTER_ACTOR (obj));
+
+  g_signal_connect (stage, "activate", G_CALLBACK (cally_stage_activate_cb), obj);
+  g_signal_connect (stage, "deactivate", G_CALLBACK (cally_stage_deactivate_cb), obj);
+
+  obj->role = ATK_ROLE_CANVAS;
+}
+
+static AtkStateSet*
+cally_stage_ref_state_set   (AtkObject *obj)
+{
+  CallyStage   *cally_stage = NULL;
+  AtkStateSet  *state_set   = NULL;
+  ClutterStage *stage       = NULL;
+
+  g_return_val_if_fail (CALLY_IS_STAGE (obj), NULL);
+  cally_stage = CALLY_STAGE (obj);
+
+  state_set = ATK_OBJECT_CLASS (cally_stage_parent_class)->ref_state_set (obj);
+  stage = CLUTTER_STAGE (CALLY_GET_CLUTTER_ACTOR (cally_stage));
+
+  if (stage == NULL)
+    return state_set;
+
+  if (cally_stage->priv->active)
+    atk_state_set_add_state (state_set, ATK_STATE_ACTIVE);
+
+  return state_set;
+}
+
+/* Auxiliar */
+static void
+cally_stage_activate_cb     (ClutterStage *stage,
+                             gpointer      data)
+{
+  CallyStage *cally_stage = NULL;
+
+  g_return_if_fail (CALLY_IS_STAGE (data));
+
+  cally_stage = CALLY_STAGE (data);
+
+  cally_stage->priv->active = TRUE;
+
+  atk_object_notify_state_change (ATK_OBJECT (cally_stage),
+                                  ATK_STATE_ACTIVE, TRUE);
+
+  g_signal_emit (cally_stage, cally_stage_signals [ACTIVATE], 0);
+}
+
+static void
+cally_stage_deactivate_cb   (ClutterStage *stage,
+                             gpointer      data)
+{
+  CallyStage *cally_stage = NULL;
+
+  g_return_if_fail (CALLY_IS_STAGE (data));
+
+  cally_stage = CALLY_STAGE (data);
+
+  cally_stage->priv->active = FALSE;
+
+  atk_object_notify_state_change (ATK_OBJECT (cally_stage),
+                                  ATK_STATE_ACTIVE, FALSE);
+
+  g_signal_emit (cally_stage, cally_stage_signals [DEACTIVATE], 0);
+}
diff --git a/clutter/cally/cally-stage.h b/clutter/cally/cally-stage.h
new file mode 100644 (file)
index 0000000..e95c08e
--- /dev/null
@@ -0,0 +1,62 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+#ifndef __CALLY_STAGE_H__
+#define __CALLY_STAGE_H__
+
+#include "cally-group.h"
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_STAGE            (cally_stage_get_type ())
+#define CALLY_STAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_STAGE, CallyStage))
+#define CALLY_STAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_STAGE, CallyStageClass))
+#define CALLY_IS_STAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_STAGE))
+#define CALLY_IS_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_STAGE))
+#define CALLY_STAGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_STAGE, CallyStageClass))
+
+typedef struct _CallyStage        CallyStage;
+typedef struct _CallyStageClass   CallyStageClass;
+typedef struct _CallyStagePrivate CallyStagePrivate;
+
+struct _CallyStage
+{
+  CallyGroup parent;
+
+  /* < private > */
+  CallyStagePrivate *priv;
+};
+
+struct _CallyStageClass
+{
+  CallyGroupClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+GType      cally_stage_get_type (void);
+AtkObject *cally_stage_new      (ClutterActor *actor);
+
+G_END_DECLS
+
+#endif /* __CALLY_STAGE_H__ */
diff --git a/clutter/cally/cally-text.c b/clutter/cally/cally-text.c
new file mode 100644 (file)
index 0000000..bd55d29
--- /dev/null
@@ -0,0 +1,1255 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * Some parts are based on GailLabel, GailEntry, GailTextView from GAIL
+ * 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.
+ */
+
+/**
+ * SECTION:cally-text
+ * @short_description: Implementation of the ATK interfaces for a #ClutterText
+ * @see_also: #ClutterText
+ *
+ * #CallyClutterText implements the required ATK interfaces of
+ * #ClutterText, #AtkText and #AtkEditableText
+ *
+ *
+ */
+
+/**
+ * IMPLEMENTATION NOTES:
+ *
+ * * AtkText: There are still some methods not implemented yet:
+ *     atk_text_get_default_attributes
+ *     atk_text_get_character_extents
+ *     atk_text_get_offset_at_point
+ *
+ *     See details on bug CB#1733
+ *
+ * * AtkEditableText: some methods will not be implemented
+ *
+ *     * atk_editable_text_set_run_attributes: ClutterText has some
+ *       properties equivalent to the AtkAttributte, but it doesn't
+ *       allow you to define it by
+ *
+ *     * atk_editable_text_copy: Clutter has no Clipboard support
+ *
+ *     * atk_editable_text_paste: Clutter has no Clipboard support
+ *
+ *     * atk_editable_text_cut: Clutter has no Clipboard support. In
+ *           this case, as cut is basically a copy&delete combination,
+ *           we could have implemented it using the delete, but IMHO,
+ *           it would be weird to cut a text, get the text removed and
+ *           then not be able to paste the text
+ *
+ *     See details on bug CB#1734
+ */
+
+#include "cally-text.h"
+#include "cally-actor-private.h"
+
+static void cally_text_class_init (CallyTextClass *klass);
+static void cally_text_init       (CallyText *cally_text);
+static void cally_text_finalize   (GObject *obj);
+
+/* AtkObject */
+static void                   cally_text_real_initialize (AtkObject *obj,
+                                                          gpointer   data);
+static G_CONST_RETURN gchar * cally_text_get_name        (AtkObject *obj);
+static AtkStateSet*           cally_text_ref_state_set   (AtkObject *obj);
+
+/* atkaction */
+
+static void                   _cally_text_activate_action (CallyActor *cally_actor);
+static void                   _check_activate_action      (CallyText   *cally_text,
+                                                           ClutterText *clutter_text);
+
+/* AtkText */
+static void                   cally_text_text_interface_init     (AtkTextIface *iface);
+static gchar*                 cally_text_get_text                (AtkText *text,
+                                                                  gint     start_offset,
+                                                                  gint     end_offset);
+static gunichar               cally_text_get_character_at_offset (AtkText *text,
+                                                                  gint     offset);
+static gchar*                 cally_text_get_text_before_offset  (AtkText       *text,
+                                                                  gint           offset,
+                                                                  AtkTextBoundary  boundary_type,
+                                                                  gint          *start_offset,
+                                                                  gint          *end_offset);
+static gchar*                cally_text_get_text_at_offset      (AtkText        *text,
+                                                                  gint             offset,
+                                                                  AtkTextBoundary  boundary_type,
+                                                                  gint          *start_offset,
+                                                                  gint          *end_offset);
+static gchar*                cally_text_get_text_after_offset   (AtkText        *text,
+                                                                  gint             offset,
+                                                                  AtkTextBoundary  boundary_type,
+                                                                  gint          *start_offset,
+                                                                  gint          *end_offset);
+static gint                   cally_text_get_caret_offset        (AtkText *text);
+static gboolean               cally_text_set_caret_offset        (AtkText *text,
+                                                                  gint offset);
+static gint                   cally_text_get_character_count     (AtkText *text);
+static gint                   cally_text_get_n_selections        (AtkText *text);
+static gchar*                 cally_text_get_selection           (AtkText *text,
+                                                                  gint    selection_num,
+                                                                  gint    *start_offset,
+                                                                  gint    *end_offset);
+static gboolean               cally_text_add_selection           (AtkText *text,
+                                                                  gint     start_offset,
+                                                                  gint     end_offset);
+static gboolean              cally_text_remove_selection         (AtkText *text,
+                                                                  gint    selection_num);
+static gboolean              cally_text_set_selection            (AtkText *text,
+                                                                  gint   selection_num,
+                                                                  gint    start_offset,
+                                                                  gint    end_offset);
+static AtkAttributeSet*      cally_text_get_run_attributes       (AtkText *text,
+                                                                  gint    offset,
+                                                                  gint    *start_offset,
+                                                                  gint    *end_offset);
+static void                  _cally_text_get_selection_bounds    (ClutterText *clutter_text,
+                                                                  gint        *start_offset,
+                                                                  gint        *end_offset);
+static void                  _cally_text_text_changed_cb         (ClutterText *clutter_text,
+                                                                  gpointer     data);
+static void                  _cally_text_insert_text_cb          (ClutterText *clutter_text,
+                                                                  gchar       *new_text,
+                                                                  gint         new_text_length,
+                                                                  gint        *position,
+                                                                  gpointer     data);
+static void                 _cally_text_delete_text_cb           (ClutterText *clutter_text,
+                                                                  gint         start_pos,
+                                                                  gint         end_pos,
+                                                                  gpointer     data);
+static gboolean             _idle_notify_insert                  (gpointer data);
+static void                 _notify_insert                       (CallyText *cally_text);
+static void                 _notify_delete                       (CallyText *cally_text);
+
+/* AtkEditableText */
+static void                 cally_text_editable_text_interface_init (AtkEditableTextIface *iface);
+static void                 cally_text_set_text_contents            (AtkEditableText *text,
+                                                                     const gchar *string);
+static void                 cally_text_insert_text                  (AtkEditableText *text,
+                                                                     const gchar *string,
+                                                                     gint length,
+                                                                     gint *position);
+static void                 cally_text_delete_text                  (AtkEditableText *text,
+                                                                     gint start_pos,
+                                                                     gint end_pos);
+
+/* CallyActor */
+static void                 cally_text_notify_clutter               (GObject    *obj,
+                                                                     GParamSpec *pspec);
+
+static gboolean             _check_for_selection_change             (CallyText *cally_text,
+                                                                     ClutterText *clutter_text);
+
+/* Misc functions */
+static AtkAttributeSet*     _cally_misc_add_attribute (AtkAttributeSet *attrib_set,
+                                                       AtkTextAttribute attr,
+                                                       gchar           *value);
+
+static AtkAttributeSet*     _cally_misc_layout_get_run_attributes (AtkAttributeSet *attrib_set,
+                                                                   PangoLayout     *layout,
+                                                                   gchar           *text,
+                                                                   gint            offset,
+                                                                   gint            *start_offset,
+                                                                   gint            *end_offset);
+
+G_DEFINE_TYPE_WITH_CODE (CallyText,
+                         cally_text,
+                         CALLY_TYPE_ACTOR,
+                         G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT,
+                                                cally_text_text_interface_init)
+                         G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT,
+                                                cally_text_editable_text_interface_init));
+
+#define CALLY_TEXT_GET_PRIVATE(obj) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CALLY_TYPE_TEXT, CallyTextPrivate))
+
+struct _CallyTextPrivate
+{
+  /* Cached ClutterText values*/
+  gint cursor_position;
+  gint selection_bound;
+
+  /* text_changed::insert stuff */
+  gchar *signal_name_insert;
+  gint position_insert;
+  gint length_insert;
+  guint insert_idle_handler;
+
+  /* text_changed::delete stuff */
+  gchar *signal_name_delete;
+  gint position_delete;
+  gint length_delete;
+
+  /* action */
+  guint activate_action_id;
+};
+
+static void
+cally_text_class_init (CallyTextClass *klass)
+{
+  GObjectClass   *gobject_class = G_OBJECT_CLASS (klass);
+  AtkObjectClass *class         = ATK_OBJECT_CLASS (klass);
+  CallyActorClass *cally_class  = CALLY_ACTOR_CLASS (klass);
+
+  gobject_class->finalize = cally_text_finalize;
+
+  class->initialize = cally_text_real_initialize;
+  class->get_name   = cally_text_get_name;
+  class->ref_state_set = cally_text_ref_state_set;
+
+  cally_class->notify_clutter = cally_text_notify_clutter;
+
+  g_type_class_add_private (gobject_class, sizeof (CallyTextPrivate));
+}
+
+static void
+cally_text_init (CallyText *cally_text)
+{
+  CallyTextPrivate *priv = CALLY_TEXT_GET_PRIVATE (cally_text);
+
+  cally_text->priv = priv;
+
+  priv->cursor_position = 0;
+  priv->selection_bound = 0;
+
+  priv->signal_name_insert = NULL;
+  priv->position_insert = -1;
+  priv->length_insert = -1;
+  priv->insert_idle_handler = 0;
+
+  priv->signal_name_delete = NULL;
+  priv->position_delete = -1;
+  priv->length_delete = -1;
+
+  priv->activate_action_id = 0;
+}
+
+static void
+cally_text_finalize   (GObject *obj)
+{
+  CallyText *cally_text = CALLY_TEXT (obj);
+
+/*   g_object_unref (cally_text->priv->textutil); */
+/*   cally_text->priv->textutil = NULL; */
+
+  if (cally_text->priv->insert_idle_handler)
+    {
+      g_source_remove (cally_text->priv->insert_idle_handler);
+      cally_text->priv->insert_idle_handler = 0;
+    }
+
+  G_OBJECT_CLASS (cally_text_parent_class)->finalize (obj);
+}
+
+AtkObject*
+cally_text_new (ClutterActor *actor)
+{
+  GObject   *object     = NULL;
+  AtkObject *accessible = NULL;
+
+  g_return_val_if_fail (CLUTTER_IS_TEXT (actor), NULL);
+
+  object = g_object_new (CALLY_TYPE_TEXT, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, actor);
+
+  return accessible;
+}
+
+/* atkobject.h */
+
+static void
+cally_text_real_initialize(AtkObject *obj,
+                           gpointer   data)
+{
+  ClutterText *clutter_text = NULL;
+  CallyText *cally_text = NULL;
+
+  ATK_OBJECT_CLASS (cally_text_parent_class)->initialize (obj, data);
+
+  g_return_if_fail (CLUTTER_TEXT (data));
+
+  cally_text = CALLY_TEXT (obj);
+  clutter_text = CLUTTER_TEXT (data);
+
+  cally_text->priv->cursor_position = clutter_text_get_cursor_position (clutter_text);
+  cally_text->priv->selection_bound = clutter_text_get_selection_bound (clutter_text);
+
+  g_signal_connect (clutter_text, "text-changed",
+                    G_CALLBACK (_cally_text_text_changed_cb),
+                    cally_text);
+  g_signal_connect (clutter_text, "insert-text",
+                    G_CALLBACK (_cally_text_insert_text_cb),
+                    cally_text);
+  g_signal_connect (clutter_text, "delete-text",
+                    G_CALLBACK (_cally_text_delete_text_cb),
+                    cally_text);
+
+  _check_activate_action (cally_text, clutter_text);
+
+  obj->role = ATK_ROLE_TEXT;
+}
+
+static G_CONST_RETURN gchar *
+cally_text_get_name (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *name;
+
+  g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL);
+
+  name = ATK_OBJECT_CLASS (cally_text_parent_class)->get_name (obj);
+  if (name == NULL)
+    {
+      ClutterActor *actor = NULL;
+
+      actor = CALLY_GET_CLUTTER_ACTOR (obj);
+
+      if (actor == NULL) /* State is defunct */
+        name = NULL;
+      else
+        name = clutter_text_get_text (CLUTTER_TEXT (actor));
+    }
+
+  return name;
+}
+
+static AtkStateSet*
+cally_text_ref_state_set   (AtkObject *obj)
+{
+  AtkStateSet *result = NULL;
+  ClutterActor *actor = NULL;
+
+  result = ATK_OBJECT_CLASS (cally_text_parent_class)->ref_state_set (obj);
+
+  actor = CALLY_GET_CLUTTER_ACTOR (obj);
+
+  if (actor == NULL)
+    return result;
+
+  if (clutter_text_get_editable (CLUTTER_TEXT (actor)))
+    atk_state_set_add_state (result, ATK_STATE_EDITABLE);
+
+  if (clutter_text_get_selectable (CLUTTER_TEXT (actor)))
+    atk_state_set_add_state (result, ATK_STATE_SELECTABLE_TEXT);
+
+  return result;
+}
+
+
+/***** atktext.h ******/
+
+static void
+cally_text_text_interface_init (AtkTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->get_text                = cally_text_get_text;
+  iface->get_character_at_offset = cally_text_get_character_at_offset;
+  iface->get_text_before_offset  = cally_text_get_text_before_offset;
+  iface->get_text_at_offset      = cally_text_get_text_at_offset;
+  iface->get_text_after_offset   = cally_text_get_text_after_offset;
+  iface->get_character_count     = cally_text_get_character_count;
+  iface->get_caret_offset        = cally_text_get_caret_offset;
+  iface->set_caret_offset        = cally_text_set_caret_offset;
+  iface->get_n_selections        = cally_text_get_n_selections;
+  iface->get_selection           = cally_text_get_selection;
+  iface->add_selection           = cally_text_add_selection;
+  iface->remove_selection        = cally_text_remove_selection;
+  iface->set_selection           = cally_text_set_selection;
+  iface->get_run_attributes      = cally_text_get_run_attributes;
+/*   iface->get_default_attributes  = cally_text_get_default_attributes; */
+/*   iface->get_character_extents = */
+/*   iface->get_offset_at_point = */
+
+}
+
+static gchar*
+cally_text_get_text (AtkText *text,
+                     gint start_offset,
+                     gint end_offset)
+{
+  ClutterActor *actor = NULL;
+
+  g_return_val_if_fail (CALLY_IS_TEXT (text), NULL);
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* Object is defunct */
+    return NULL;
+
+  return clutter_text_get_chars (CLUTTER_TEXT (actor),
+                                 start_offset, end_offset);
+}
+
+static gunichar
+cally_text_get_character_at_offset (AtkText *text,
+                                    gint     offset)
+{
+  ClutterActor *actor      = NULL;
+  CallyText    *cally_text = NULL;
+  gchar        *string     = NULL;
+  gchar        *index      = NULL;
+  gunichar      unichar;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return '\0';
+
+  cally_text = CALLY_TEXT (text);
+  string = clutter_text_get_chars (CLUTTER_TEXT (actor), 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 gchar*
+cally_text_get_text_before_offset (AtkText         *text,
+                                  gint             offset,
+                                  AtkTextBoundary  boundary_type,
+                                  gint             *start_offset,
+                                  gint             *end_offset)
+{
+  ClutterActor *actor        = NULL;
+  ClutterText  *clutter_text = NULL;
+  CallyText    *cally_text   = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return NULL;
+
+  clutter_text = CLUTTER_TEXT (actor);
+  cally_text = CALLY_TEXT (text);
+
+/*   return gail_text_util_get_text (cally_text->priv->textutil, */
+/*                                   clutter_text_get_layout (clutter_text), */
+/*                                   GAIL_BEFORE_OFFSET, boundary_type, */
+/*                                   offset, start_offset, end_offset); */
+  return NULL;
+}
+
+static gchar*
+cally_text_get_text_at_offset (AtkText         *text,
+                               gint             offset,
+                               AtkTextBoundary  boundary_type,
+                               gint            *start_offset,
+                               gint            *end_offset)
+{
+  ClutterActor *actor        = NULL;
+  ClutterText  *clutter_text = NULL;
+  CallyText    *cally_text   = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return NULL;
+
+  clutter_text = CLUTTER_TEXT (actor);
+  cally_text = CALLY_TEXT (text);
+
+/*   return gail_text_util_get_text (cally_text->priv->textutil, */
+/*                                   clutter_text_get_layout (clutter_text), GAIL_AT_OFFSET, */
+/*                                   boundary_type, offset, start_offset, end_offset); */
+  return NULL;
+}
+
+static gchar*
+cally_text_get_text_after_offset (AtkText         *text,
+                                  gint             offset,
+                                  AtkTextBoundary  boundary_type,
+                                  gint            *start_offset,
+                                  gint            *end_offset)
+{
+  ClutterActor *actor        = NULL;
+  ClutterText  *clutter_text = NULL;
+  CallyText    *cally_text   = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return NULL;
+
+  clutter_text = CLUTTER_TEXT (actor);
+  cally_text = CALLY_TEXT (text);
+
+/*   return gail_text_util_get_text (cally_text->priv->textutil, */
+/*                                   clutter_text_get_layout (clutter_text), GAIL_AFTER_OFFSET, */
+/*                                   boundary_type, offset, start_offset, end_offset); */
+  return NULL;
+}
+
+static gint
+cally_text_get_caret_offset (AtkText *text)
+{
+  ClutterActor *actor        = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return -1;
+
+  return clutter_text_get_cursor_position (CLUTTER_TEXT (actor));
+}
+
+static gboolean
+cally_text_set_caret_offset (AtkText *text,
+                             gint offset)
+{
+  ClutterActor *actor        = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return FALSE;
+
+  clutter_text_set_cursor_position (CLUTTER_TEXT (actor), offset);
+
+  /* like in gailentry, we suppose that this always works, as clutter text
+     doesn't return anything */
+  return TRUE;
+}
+
+static gint
+cally_text_get_character_count (AtkText *text)
+{
+  ClutterActor *actor = NULL;
+  ClutterText *clutter_text = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return 0;
+
+  clutter_text = CLUTTER_TEXT (actor);
+  return g_utf8_strlen (clutter_text_get_text (clutter_text), -1);
+}
+
+static gint
+cally_text_get_n_selections (AtkText *text)
+{
+  ClutterActor *actor           = NULL;
+  gint          selection_bound = -1;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return 0;
+
+  if (!clutter_text_get_selectable (CLUTTER_TEXT (actor)))
+    return 0;
+
+  selection_bound = clutter_text_get_selection_bound (CLUTTER_TEXT (actor));
+
+  if (selection_bound > 0)
+    return 1;
+  else
+    return 0;
+}
+
+static gchar*
+cally_text_get_selection (AtkText *text,
+                         gint     selection_num,
+                          gint    *start_offset,
+                          gint    *end_offset)
+{
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return NULL;
+
+ /* As in gailentry, only let the user get the selection if one is set, and if
+  * the selection_num is 0.
+  */
+  if (selection_num != 0)
+     return NULL;
+
+  _cally_text_get_selection_bounds (CLUTTER_TEXT (actor), start_offset, end_offset);
+
+  if (*start_offset != *end_offset)
+    return clutter_text_get_selection (CLUTTER_TEXT (actor));
+  else
+     return NULL;
+}
+
+/* ClutterText only allows one selection. So this method will set the selection
+   if no selection exists, but as in gailentry, it will not change the current
+   selection */
+static gboolean
+cally_text_add_selection (AtkText *text,
+                          gint    start_offset,
+                          gint    end_offset)
+{
+  ClutterActor *actor;
+  gint select_start, select_end;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return FALSE;
+
+  _cally_text_get_selection_bounds (CLUTTER_TEXT (actor),
+                                    &select_start, &select_end);
+
+ /* Like in gailentry, if there is already a selection, then don't allow another
+  * to be added, since ClutterText only supports one selected region.
+  */
+  if (select_start == select_end)
+    {
+      clutter_text_set_selection (CLUTTER_TEXT (actor),
+                                  start_offset, end_offset);
+
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+
+static gboolean
+cally_text_remove_selection (AtkText *text,
+                             gint    selection_num)
+{
+  ClutterActor *actor        = NULL;
+  gint          caret_pos    = -1;
+  gint          select_start = -1;
+  gint          select_end   = -1;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return FALSE;
+
+  /* only one selection is allowed */
+  if (selection_num != 0)
+     return FALSE;
+
+  _cally_text_get_selection_bounds (CLUTTER_TEXT (actor),
+                                    &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 = clutter_text_get_cursor_position (CLUTTER_TEXT (actor));
+      clutter_text_set_selection (CLUTTER_TEXT (actor),
+                                  caret_pos, caret_pos);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+cally_text_set_selection (AtkText *text,
+                         gint    selection_num,
+                          gint    start_offset,
+                          gint    end_offset)
+{
+  ClutterActor *actor        = NULL;
+  gint          select_start = -1;
+  gint          select_end   = -1;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return FALSE;
+
+ /* Like in gailentry, only let the user move the selection if one is set,
+  * and if the selection_num is 0
+  */
+  if (selection_num != 0)
+     return FALSE;
+
+  _cally_text_get_selection_bounds (CLUTTER_TEXT (actor),
+                                    &select_start, &select_end);
+
+  if (select_start != select_end)
+    {
+      clutter_text_set_selection (CLUTTER_TEXT (actor),
+                                  start_offset, end_offset);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static AtkAttributeSet*
+cally_text_get_run_attributes (AtkText *text,
+                              gint    offset,
+                               gint    *start_offset,
+                               gint    *end_offset)
+{
+  ClutterActor    *actor        = NULL;
+  ClutterText     *clutter_text = NULL;
+  AtkAttributeSet *at_set       = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL) /* State is defunct */
+    return NULL;
+
+  /* Clutter don't have any reference to the direction*/
+
+  clutter_text = CLUTTER_TEXT (actor);
+
+  at_set = _cally_misc_layout_get_run_attributes (at_set,
+                                                  clutter_text_get_layout (clutter_text),
+                                                  (gchar*)clutter_text_get_text (clutter_text),
+                                                  offset,
+                                                  start_offset,
+                                                  end_offset);
+
+  return at_set;
+}
+
+/******** Auxiliar private methods ******/
+
+/* ClutterText only maintains the current cursor position and a extra selection
+   bound, but this could be before or after the cursor. This method returns
+   the start and end positions in a proper order (so start<=end). This is
+   similar to the function gtk_editable_get_selection_bounds */
+static void
+_cally_text_get_selection_bounds   (ClutterText *clutter_text,
+                                    gint        *start_offset,
+                                    gint        *end_offset)
+{
+  gint pos = -1;
+  gint selection_bound = -1;
+
+  pos = clutter_text_get_cursor_position (clutter_text);
+  selection_bound = clutter_text_get_selection_bound (clutter_text);
+
+  if (pos < selection_bound)
+    {
+      *start_offset = pos;
+      *end_offset = selection_bound;
+    }
+  else
+    {
+      *start_offset = selection_bound;
+      *end_offset = pos;
+    }
+}
+
+static void
+_cally_text_text_changed_cb (ClutterText *clutter_text,
+                             gpointer data)
+{
+  CallyText *cally_text = NULL;
+
+  g_return_if_fail (CALLY_IS_TEXT (data));
+
+  cally_text = CALLY_TEXT (data);
+}
+
+static void
+_cally_text_delete_text_cb (ClutterText *clutter_text,
+                            gint         start_pos,
+                            gint         end_pos,
+                            gpointer     data)
+{
+  CallyText *cally_text = NULL;
+
+  g_return_if_fail (CALLY_IS_TEXT (data));
+
+  /* Ignore zero lengh deletions */
+  if (end_pos - start_pos == 0)
+    return;
+
+  cally_text = CALLY_TEXT (data);
+
+  if (!cally_text->priv->signal_name_delete)
+    {
+      cally_text->priv->signal_name_delete = "text_changed::delete";
+      cally_text->priv->position_delete = start_pos;
+      cally_text->priv->length_delete = end_pos - start_pos;
+    }
+
+  _notify_delete (cally_text);
+}
+
+static void
+_cally_text_insert_text_cb (ClutterText *clutter_text,
+                            gchar       *new_text,
+                            gint         new_text_length,
+                            gint        *position,
+                            gpointer     data)
+{
+  CallyText *cally_text = NULL;
+
+  g_return_if_fail (CALLY_IS_TEXT (data));
+
+  cally_text = CALLY_TEXT (data);
+
+  if (!cally_text->priv->signal_name_insert)
+    {
+      cally_text->priv->signal_name_insert = "text_changed::insert";
+      cally_text->priv->position_insert = *position;
+      cally_text->priv->length_insert = g_utf8_strlen (new_text, new_text_length);
+    }
+
+  /*
+   * The signal will be emitted when the cursor position is updated,
+   * or in an idle handler if it not updated.
+   */
+  if (cally_text->priv->insert_idle_handler == 0)
+    cally_text->priv->insert_idle_handler = clutter_threads_add_idle (_idle_notify_insert,
+                                                                      cally_text);
+}
+
+/***** atkeditabletext.h ******/
+
+static void
+cally_text_editable_text_interface_init (AtkEditableTextIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->set_text_contents = cally_text_set_text_contents;
+  iface->insert_text = cally_text_insert_text;
+  iface->delete_text = cally_text_delete_text;
+
+  /* Not implemented, see IMPLEMENTATION NOTES*/
+  iface->set_run_attributes = NULL;
+  iface->copy_text = NULL;
+  iface->cut_text = NULL;
+  iface->paste_text = NULL;
+}
+
+static void
+cally_text_set_text_contents (AtkEditableText *text,
+                              const gchar *string)
+{
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL)
+    return;
+
+  if (!clutter_text_get_editable (CLUTTER_TEXT (actor)))
+    return;
+
+  clutter_text_set_text (CLUTTER_TEXT (actor),
+                         string);
+}
+
+
+static void
+cally_text_insert_text (AtkEditableText *text,
+                        const gchar *string,
+                        gint length,
+                        gint *position)
+{
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL)
+    return;
+
+  if (!clutter_text_get_editable (CLUTTER_TEXT (actor)))
+    return;
+
+  if (length < 0)
+    length = g_utf8_strlen (string, -1);
+
+  clutter_text_insert_text (CLUTTER_TEXT (actor),
+                            string, *position);
+
+  /* we suppose that the text insertion will be succesful,
+     clutter-text doesn't warn about it. A option would be search for
+     the text, but it seems not really required */
+  *position += length;
+}
+
+static void cally_text_delete_text (AtkEditableText *text,
+                                    gint start_pos,
+                                    gint end_pos)
+{
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (text);
+  if (actor == NULL)
+    return;
+
+  if (!clutter_text_get_editable (CLUTTER_TEXT (actor)))
+    return;
+
+  clutter_text_delete_text (CLUTTER_TEXT (actor),
+                            start_pos, end_pos);
+}
+
+/* CallyActor */
+static void
+cally_text_notify_clutter (GObject    *obj,
+                           GParamSpec *pspec)
+{
+  ClutterText *clutter_text = NULL;
+  CallyText *cally_text = NULL;
+  AtkObject *atk_obj = NULL;
+
+  clutter_text = CLUTTER_TEXT (obj);
+  atk_obj = clutter_actor_get_accessible (CLUTTER_ACTOR (obj));
+  cally_text = CALLY_TEXT (atk_obj);
+
+  if (g_strcmp0 (pspec->name, "position") == 0)
+    {
+      /* the selection can change also for the cursor position */
+      if (_check_for_selection_change (cally_text, clutter_text))
+        g_signal_emit_by_name (atk_obj, "text_selection_changed");
+
+      g_signal_emit_by_name (atk_obj, "text_caret_moved",
+                             clutter_text_get_cursor_position (clutter_text));
+    }
+  else if (g_strcmp0 (pspec->name, "selection-bound") == 0)
+    {
+      if (_check_for_selection_change (cally_text, clutter_text))
+        g_signal_emit_by_name (atk_obj, "text_selection_changed");
+    }
+  else if (g_strcmp0 (pspec->name, "editable") == 0)
+    {
+      atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE,
+                                      clutter_text_get_editable (clutter_text));
+    }
+  else if (g_strcmp0 (pspec->name, "activatable") == 0)
+    {
+      _check_activate_action (cally_text, clutter_text);
+    }
+  else
+    {
+      CALLY_ACTOR_CLASS (cally_text_parent_class)->notify_clutter (obj, pspec);
+    }
+}
+
+static gboolean
+_check_for_selection_change (CallyText *cally_text,
+                             ClutterText *clutter_text)
+{
+  gboolean ret_val = FALSE;
+  gint clutter_pos = -1;
+  gint clutter_bound = -1;
+
+  clutter_pos = clutter_text_get_cursor_position (clutter_text);
+  clutter_bound = clutter_text_get_selection_bound (clutter_text);
+
+  if (clutter_pos != clutter_bound)
+    {
+      if (clutter_pos != cally_text->priv->cursor_position ||
+          clutter_bound != cally_text->priv->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 = (cally_text->priv->cursor_position != cally_text->priv->selection_bound);
+    }
+
+  cally_text->priv->cursor_position = clutter_pos;
+  cally_text->priv->selection_bound = clutter_bound;
+
+  return ret_val;
+}
+
+static gboolean
+_idle_notify_insert (gpointer data)
+{
+  CallyText *cally_text = NULL;
+
+  cally_text = CALLY_TEXT (data);
+  cally_text->priv->insert_idle_handler = 0;
+
+  _notify_insert (cally_text);
+
+  return FALSE;
+}
+
+static void
+_notify_insert (CallyText *cally_text)
+{
+  if (cally_text->priv->signal_name_insert)
+    {
+      g_signal_emit_by_name (cally_text,
+                             cally_text->priv->signal_name_insert,
+                             cally_text->priv->position_insert,
+                             cally_text->priv->length_insert);
+      cally_text->priv->signal_name_insert = NULL;
+    }
+}
+
+static void
+_notify_delete (CallyText *cally_text)
+{
+  if (cally_text->priv->signal_name_delete)
+    {
+      g_signal_emit_by_name (cally_text,
+                             cally_text->priv->signal_name_delete,
+                             cally_text->priv->position_delete,
+                             cally_text->priv->length_delete);
+      cally_text->priv->signal_name_delete = NULL;
+    }
+}
+/* atkaction */
+
+static void
+_cally_text_activate_action (CallyActor *cally_actor)
+{
+  ClutterActor *actor = NULL;
+
+  actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+
+  clutter_text_activate (CLUTTER_TEXT (actor));
+}
+
+static void
+_check_activate_action (CallyText   *cally_text,
+                        ClutterText *clutter_text)
+{
+
+  if (clutter_text_get_activatable (clutter_text))
+    {
+      if (cally_text->priv->activate_action_id != 0)
+        return;
+
+      cally_text->priv->activate_action_id = cally_actor_add_action (CALLY_ACTOR (cally_text),
+                                                                     "activate", NULL, NULL,
+                                                                     _cally_text_activate_action);
+    }
+  else
+    {
+      if (cally_text->priv->activate_action_id == 0)
+        return;
+
+      if (cally_actor_remove_action (CALLY_ACTOR (cally_text),
+                                     cally_text->priv->activate_action_id))
+        {
+          cally_text->priv->activate_action_id = 0;
+        }
+    }
+}
+
+/* GailTextUtil/GailMisc reimplementation methods */
+
+/**
+ * _cally_misc_add_attribute:
+ *
+ * Reimplementation of gail_misc_layout_get_run_attributes (check this
+ * function for more documentation).
+ *
+ * Returns: A pointer to the new #AtkAttributeSet.
+ **/
+static AtkAttributeSet*
+_cally_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;
+}
+
+/**
+ * _cally_misc_layout_get_run_attributes:
+ *
+ * Reimplementation of gail_misc_layout_get_run_attributes (check this
+ * function for more documentation).
+ *
+ * Returns: A pointer to the #AtkAttributeSet.
+ **/
+static AtkAttributeSet*
+_cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_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 = _cally_misc_add_attribute (attrib_set,
+                                            ATK_TEXT_ATTR_BG_COLOR,
+                                            value);
+    }
+  pango_attr_iterator_destroy (iter);
+  return attrib_set;
+}
diff --git a/clutter/cally/cally-text.h b/clutter/cally/cally-text.h
new file mode 100644 (file)
index 0000000..54e15d1
--- /dev/null
@@ -0,0 +1,63 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+#ifndef __CALLY_TEXT_H__
+#define __CALLY_TEXT_H__
+
+#include "cally-actor.h"
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_TEXT           (cally_text_get_type ())
+#define CALLY_TEXT(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_TEXT, CallyText))
+#define CALLY_TEXT_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_TEXT, CallyTextClass))
+#define CALLY_IS_TEXT(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_TEXT))
+#define CALLY_IS_TEXT_CLASS(klass)(G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_TEXT))
+#define CALLY_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_TEXT, CallyTextClass))
+
+
+typedef struct _CallyText         CallyText;
+typedef struct _CallyTextClass    CallyTextClass;
+typedef struct _CallyTextPrivate  CallyTextPrivate;
+
+struct _CallyText
+{
+  CallyActor parent;
+
+  /* < private > */
+  CallyTextPrivate *priv;
+};
+
+struct _CallyTextClass
+{
+  CallyActorClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+GType      cally_text_get_type (void);
+AtkObject* cally_text_new      (ClutterActor *actor);
+
+G_END_DECLS
+
+#endif /* __CALLY_TEXT_H__ */
diff --git a/clutter/cally/cally-texture.c b/clutter/cally/cally-texture.c
new file mode 100644 (file)
index 0000000..13c3a60
--- /dev/null
@@ -0,0 +1,103 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:callycluttertexture
+ * @short_description: Implementation of the ATK interfaces for a #ClutterTexture
+ * @see_also: #ClutterTexture
+ *
+ * #CallyClutterTexture implements the required ATK interfaces of #ClutterTexture
+ *
+ * In particular it sets a proper role for the texture.
+ */
+
+#include "cally-texture.h"
+#include "cally-actor-private.h"
+
+#define CALLY_TEXTURE_DEFAULT_DESCRIPTION "A texture"
+
+static void cally_texture_class_init (CallyTextureClass *klass);
+static void cally_texture_init       (CallyTexture *texture);
+
+/* AtkObject */
+static void                  cally_texture_real_initialize (AtkObject *obj,
+                                                           gpointer   data);
+static G_CONST_RETURN gchar *cally_texture_get_description (AtkObject *obj);
+
+
+G_DEFINE_TYPE (CallyTexture, cally_texture, CALLY_TYPE_ACTOR)
+
+static void
+cally_texture_class_init (CallyTextureClass *klass)
+{
+/*   GObjectClass   *gobject_class = G_OBJECT_CLASS (klass); */
+  AtkObjectClass *class         = ATK_OBJECT_CLASS (klass);
+
+  class->initialize      = cally_texture_real_initialize;
+  class->get_description = cally_texture_get_description;
+}
+
+static void
+cally_texture_init (CallyTexture *texture)
+{
+  /* nothing to do yet */
+}
+
+AtkObject*
+cally_texture_new (ClutterActor *actor)
+{
+  GObject   *object     = NULL;
+  AtkObject *accessible = NULL;
+
+  g_return_val_if_fail (CLUTTER_IS_TEXTURE (actor), NULL);
+
+  object = g_object_new (CALLY_TYPE_TEXTURE, NULL);
+
+  accessible = ATK_OBJECT (object);
+  atk_object_initialize (accessible, actor);
+
+  return accessible;
+}
+
+static void
+cally_texture_real_initialize (AtkObject *obj,
+                              gpointer   data)
+{
+  ATK_OBJECT_CLASS (cally_texture_parent_class)->initialize (obj, data);
+
+  /* default role */
+  obj->role = ATK_ROLE_IMAGE;
+}
+
+static G_CONST_RETURN gchar *
+cally_texture_get_description (AtkObject *obj)
+{
+  G_CONST_RETURN gchar *description = NULL;
+
+  g_return_val_if_fail (CALLY_IS_TEXTURE (obj), NULL);
+
+  description = ATK_OBJECT_CLASS (cally_texture_parent_class)->get_description (obj);
+  if (description == NULL)
+    description = CALLY_TEXTURE_DEFAULT_DESCRIPTION;
+
+  return description;
+}
diff --git a/clutter/cally/cally-texture.h b/clutter/cally/cally-texture.h
new file mode 100644 (file)
index 0000000..6603ee2
--- /dev/null
@@ -0,0 +1,63 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2009 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+#ifndef __CALLY_TEXTURE_H__
+#define __CALLY_TEXTURE_H__
+
+#include "cally-actor.h"
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_TEXTURE            (cally_texture_get_type ())
+#define CALLY_TEXTURE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_TEXTURE, CallyTexture))
+#define CALLY_TEXTURE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_TEXTURE, CallyTextureClass))
+#define CALLY_IS_TEXTURE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_TEXTURE))
+#define CALLY_IS_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_TEXTURE))
+#define CALLY_TEXTURE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_TEXTURE, CallyTextureClass))
+
+
+typedef struct _CallyTexture        CallyTexture;
+typedef struct _CallyTextureClass   CallyTextureClass;
+typedef struct _CallyTexturePrivate CallyTexturePrivate;
+
+struct _CallyTexture
+{
+  CallyActor parent;
+
+  /* < private > */
+  CallyTexturePrivate *priv;
+};
+
+struct _CallyTextureClass
+{
+  CallyActorClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+GType      cally_texture_get_type (void);
+AtkObject *cally_texture_new      (ClutterActor *actor);
+
+G_END_DECLS
+
+#endif /* __CALLY_TEXTURE_H__ */
diff --git a/clutter/cally/cally-util.c b/clutter/cally/cally-util.c
new file mode 100644 (file)
index 0000000..14a4a8e
--- /dev/null
@@ -0,0 +1,557 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * Based on GailUtil from GAIL
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <clutter/clutter.h>
+
+#include "cally-util.h"
+#include "cally-root.h"
+#include "cally-stage.h"
+
+#ifdef HAVE_CLUTTER_X11
+#include <X11/extensions/XKB.h>
+#endif
+
+static void cally_util_class_init (CallyUtilClass      *klass);
+static void cally_util_init       (CallyUtil *cally_util);
+
+/* atkutil.h */
+
+static guint                 cally_util_add_global_event_listener    (GSignalEmissionHook listener,
+                                                                      const gchar*        event_type);
+static void                  cally_util_remove_global_event_listener (guint remove_listener);
+static guint                 cally_util_add_key_event_listener     (AtkKeySnoopFunc listener,
+                                                                     gpointer        data);
+static void                  cally_util_remove_key_event_listener    (guint remove_listener);
+static AtkObject*            cally_util_get_root                           (void);
+static G_CONST_RETURN gchar *cally_util_get_toolkit_name                   (void);
+static G_CONST_RETURN gchar *cally_util_get_toolkit_version          (void);
+
+/* private */
+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                  cally_util_simulate_snooper_install     (void);
+static void                  cally_util_simulate_snooper_remove      (void);
+static gboolean              cally_key_snooper                       (ClutterActor *actor,
+                                                                      ClutterEvent *event,
+                                                                      gpointer      user_data);
+static void                  cally_util_stage_added_cb               (ClutterStageManager *stage_manager,
+                                                                      ClutterStage *stage,
+                                                                      gpointer data);
+static void                  cally_util_stage_removed_cb             (ClutterStageManager *stage_manager,
+                                                                      ClutterStage *stage,
+                                                                      gpointer data);
+static gboolean              notify_hf                               (gpointer key,
+                                                                      gpointer value,
+                                                                      gpointer data);
+static void                  insert_hf                               (gpointer key,
+                                                                      gpointer value,
+                                                                      gpointer data);
+static AtkKeyEventStruct *  atk_key_event_from_clutter_event_key     (ClutterKeyEvent *event);
+static void                 do_window_event_initialization           (void);
+
+
+/* This is just a copy of the Gail one, a shared library or place to
+   define it could be a good idea. */
+typedef struct _CallyUtilListenerInfo CallyUtilListenerInfo;
+typedef struct _CallyKeyEventInfo CallyKeyEventInfo;
+
+struct _CallyUtilListenerInfo
+{
+  gint key;
+  guint signal_id;
+  gulong hook_id;
+};
+
+struct _CallyKeyEventInfo
+{
+  AtkKeySnoopFunc listener;
+  gpointer func_data;
+};
+
+static AtkObject* root = NULL;
+static GHashTable *listener_list = NULL;
+static GHashTable *key_listener_list = NULL;
+static gint listener_idx = 1;
+
+
+G_DEFINE_TYPE (CallyUtil, cally_util, ATK_TYPE_UTIL);
+
+static void
+cally_util_class_init (CallyUtilClass *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    = cally_util_add_global_event_listener;
+  atk_class->remove_global_event_listener = cally_util_remove_global_event_listener;
+  atk_class->add_key_event_listener       = cally_util_add_key_event_listener;
+  atk_class->remove_key_event_listener    = cally_util_remove_key_event_listener;
+  atk_class->get_root                     = cally_util_get_root;
+  atk_class->get_toolkit_name             = cally_util_get_toolkit_name;
+  atk_class->get_toolkit_version          = cally_util_get_toolkit_version;
+
+  /* FIXME: Instead of create this on the class, I think that would
+     worth to implement CallyUtil as a singleton instance, so the
+     class methods will access this instance. This will be a good
+     future enhancement, meanwhile, just using the same *working*
+     implementation used on GailUtil */
+
+  listener_list = g_hash_table_new_full (g_int_hash, g_int_equal, NULL,
+                                         _listener_info_destroy);
+}
+
+static void
+cally_util_init (CallyUtil *cally_util)
+{
+  /* instance init: usually not required */
+}
+
+/* ------------------------------ ATK UTIL METHODS -------------------------- */
+
+static AtkObject*
+cally_util_get_root (void)
+{
+  if (!root)
+    root = cally_root_new ();
+
+  return root;
+}
+
+static G_CONST_RETURN gchar *
+cally_util_get_toolkit_name (void)
+{
+  return "CALLY";
+}
+
+static G_CONST_RETURN gchar *
+cally_util_get_toolkit_version (void)
+{
+  /*
+   * FIXME:
+   * Version is passed in as a -D flag when this file is
+   * compiled.
+   */
+  return "0.1";
+}
+
+
+static guint
+cally_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]))
+        {
+          /* Using ClutterStage as the window equivalent, although
+             several methods (move, etc) are missing. This would be
+             probably defined for other window-related classes (MxWindow)
+
+             FIXME: for this reason, this process should be extendable
+             on the future.*/
+          static gboolean initialized = FALSE;
+
+          if (initialized == FALSE)
+            {
+              do_window_event_initialization ();
+              initialized = TRUE;
+            }
+
+          rc = add_listener (listener, "CallyStage", 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
+cally_util_remove_global_event_listener (guint remove_listener)
+{
+  if (remove_listener > 0)
+    {
+      CallyUtilListenerInfo *listener_info;
+      gint tmp_idx = remove_listener;
+
+      listener_info = (CallyUtilListenerInfo *)
+        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 guint
+cally_util_add_key_event_listener (AtkKeySnoopFunc  listener,
+                                   gpointer         data)
+{
+  static guint key=0;
+  CallyKeyEventInfo *event_info = NULL;
+
+  if (!key_listener_list)
+  {
+    key_listener_list = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+
+    cally_util_simulate_snooper_install ();
+  }
+
+  event_info = g_new (CallyKeyEventInfo, 1);
+  event_info->listener = listener;
+  event_info->func_data = data;
+
+  g_hash_table_insert (key_listener_list, GUINT_TO_POINTER (key++), event_info);
+  /* XXX: we don't check to see if n_listeners > MAXUINT */
+  return key - 1;
+}
+
+static void
+cally_util_remove_key_event_listener (guint remove_listener)
+{
+  if (!g_hash_table_remove (key_listener_list, GUINT_TO_POINTER (remove_listener))) {
+    g_warning ("Not able to remove listener with id %i", remove_listener);
+  }
+
+  if (g_hash_table_size (key_listener_list) == 0)
+    {
+      cally_util_simulate_snooper_remove ();
+    }
+}
+
+/* ------------------------------ PRIVATE FUNCTIONS ------------------------- */
+
+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)
+        {
+          CallyUtilListenerInfo *listener_info;
+
+          rc = listener_idx;
+
+          listener_info = g_new (CallyUtilListenerInfo, 1);
+          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
+        {
+          /* This is mainly because some "window:xxx" methods not
+             implemented on CallyStage */
+          g_debug ("Signal type %s not supported\n", signal);
+        }
+    }
+  else
+    {
+      g_warning("Invalid object type %s\n", object_type);
+    }
+  return rc;
+}
+
+/* Trying to emulate gtk_key_snooper install (a kind of wrapper). This
+   could be implemented without it, but I will maintain it in this
+   way, so if in the future clutter implements it natively it would be
+   easier the transition */
+static void
+cally_util_simulate_snooper_install (void)
+{
+  ClutterStageManager *stage_manager = NULL;
+  ClutterStage *stage = NULL;
+  GSList *stage_list = NULL;
+  GSList *iter = NULL;
+
+  stage_manager = clutter_stage_manager_get_default ();
+  stage_list = clutter_stage_manager_list_stages (stage_manager);
+
+  for (iter = stage_list; iter != NULL; iter = g_slist_next (iter))
+    {
+      stage = CLUTTER_STAGE (iter->data);
+
+      g_signal_connect (G_OBJECT (stage), "captured-event",
+                        G_CALLBACK (cally_key_snooper), NULL);
+    }
+
+  g_signal_connect (G_OBJECT (stage_manager), "stage-added",
+                    G_CALLBACK (cally_util_stage_added_cb), cally_key_snooper);
+  g_signal_connect (G_OBJECT (stage_manager), "stage-removed",
+                    G_CALLBACK (cally_util_stage_removed_cb), cally_key_snooper);
+}
+
+static void
+cally_util_simulate_snooper_remove (void)
+{
+  ClutterStageManager *stage_manager = NULL;
+  ClutterStage *stage = NULL;
+  GSList *stage_list = NULL;
+  GSList *iter = NULL;
+  gint num = 0;
+
+  stage_manager = clutter_stage_manager_get_default ();
+  stage_list = clutter_stage_manager_list_stages (stage_manager);
+
+  for (iter = stage_list; iter != NULL; iter = g_slist_next (iter))
+    {
+      stage = CLUTTER_STAGE (iter->data);
+
+      num += g_signal_handlers_disconnect_by_func (stage, cally_key_snooper, NULL);
+    }
+
+  g_signal_handlers_disconnect_by_func (G_OBJECT (stage_manager),
+                                        G_CALLBACK (cally_util_stage_added_cb),
+                                        cally_key_snooper);
+
+  g_signal_handlers_disconnect_by_func (G_OBJECT (stage_manager),
+                                        G_CALLBACK (cally_util_stage_removed_cb),
+                                        cally_key_snooper);
+
+#ifdef CALLY_DEBUG
+  g_print ("Number of snooper callbacks disconnected: %i\n", num);
+#endif
+}
+
+static AtkKeyEventStruct *
+atk_key_event_from_clutter_event_key (ClutterKeyEvent *clutter_event)
+{
+  AtkKeyEventStruct *atk_event = g_new0 (AtkKeyEventStruct, 1);
+  gunichar key_unichar;
+
+  switch (clutter_event->type)
+    {
+    case CLUTTER_KEY_PRESS:
+      atk_event->type = ATK_KEY_EVENT_PRESS;
+      break;
+    case CLUTTER_KEY_RELEASE:
+      atk_event->type = ATK_KEY_EVENT_RELEASE;
+      break;
+    default:
+      g_assert_not_reached ();
+      return NULL;
+    }
+
+  atk_event->state = clutter_event->modifier_state;
+
+  /* We emit the clutter keyval. This is not exactly the one expected
+     by AtkKeyEventStruct, as it expects a Gdk-like event, with the
+     modifiers applied. But to avoid a dependency to gdk, we delegate
+     that on the AT application.
+     More information: Bug 1952 and bug 2072
+  */
+  atk_event->keyval = clutter_event->keyval;
+
+  /* It is expected to store a key defining string here (ie "Space" in
+     case you press a space). Anyway, there are no function on clutter
+     to obtain that, and we want to avoid a gdk dependency here, so we
+     delegate on the AT application to obtain that string using the
+     rest of the data on the ATK event struct.
+
+     More information: Bug 1952 and 2072
+  */
+
+  key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) clutter_event);
+
+  if (g_unichar_validate (key_unichar) && !g_unichar_iscntrl (key_unichar))
+    {
+      GString *new = NULL;
+
+      new = g_string_new ("");
+      new = g_string_insert_unichar (new, 0, key_unichar);
+      atk_event->string = new->str;
+      g_string_free (new, FALSE);
+    }
+  else
+    atk_event->string = NULL;
+
+  atk_event->length = 0;
+
+  atk_event->keycode = clutter_event->hardware_keycode;
+  atk_event->timestamp = clutter_event->time;
+
+#ifdef CALLY_DEBUG
+
+  g_debug ("CallyKeyEvent:\tsym 0x%x\n\t\tmods %x\n\t\tcode %u\n\t\ttime %lx \n\t\tstring %s\n",
+          (unsigned int) atk_event->keyval,
+          (unsigned int) atk_event->state,
+          (unsigned int) atk_event->keycode,
+          (unsigned long int) atk_event->timestamp,
+           atk_event->string);
+#endif
+
+  return atk_event;
+}
+
+
+static gboolean
+notify_hf (gpointer key, gpointer value, gpointer data)
+{
+  CallyKeyEventInfo *info = (CallyKeyEventInfo *) value;
+  AtkKeyEventStruct *key_event = (AtkKeyEventStruct *)data;
+
+  return (*(AtkKeySnoopFunc) info->listener) (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 gboolean
+cally_key_snooper (ClutterActor *actor,
+                   ClutterEvent *event,
+                   gpointer      user_data)
+{
+  AtkKeyEventStruct *key_event = NULL;
+  gint consumed = 0;
+
+  /* filter key events */
+  if ((event->type != CLUTTER_KEY_PRESS) && (event->type != CLUTTER_KEY_RELEASE))
+    {
+      return FALSE;
+    }
+
+  if (key_listener_list)
+    {
+      GHashTable *new_hash = g_hash_table_new (NULL, NULL);
+
+      g_hash_table_foreach (key_listener_list, insert_hf, new_hash);
+      key_event = atk_key_event_from_clutter_event_key ((ClutterKeyEvent *)event);
+      /* func data is inside the hash table */
+      consumed = g_hash_table_foreach_steal (new_hash, notify_hf, key_event);
+      g_hash_table_destroy (new_hash);
+    }
+
+  g_free (key_event->string);
+  g_free (key_event);
+
+  return (consumed ? 1 : 0);
+}
+
+static void
+cally_util_stage_added_cb (ClutterStageManager *stage_manager,
+                           ClutterStage *stage,
+                           gpointer data)
+{
+  GCallback cally_key_snooper = G_CALLBACK (data);
+  AtkObject *cally_stage = NULL;
+
+  g_signal_connect (G_OBJECT (stage), "captured-event", cally_key_snooper, NULL);
+
+  cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (stage));
+  if (cally_stage != NULL)
+    g_signal_emit_by_name (G_OBJECT(cally_stage), "create", 0);
+}
+
+static void
+cally_util_stage_removed_cb (ClutterStageManager *stage_manager,
+                             ClutterStage *stage,
+                             gpointer data)
+{
+  GCallback cally_key_snooper = G_CALLBACK (data);
+  gint num = 0;
+  AtkObject *cally_stage = NULL;
+
+  num = g_signal_handlers_disconnect_by_func (stage, cally_key_snooper, NULL);
+
+  cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (stage));
+  if (cally_stage != NULL)
+    g_signal_emit_by_name (G_OBJECT(cally_stage), "destroy", 0);
+}
+
+static void
+do_window_event_initialization (void)
+{
+  /*
+   * Ensure that CallyStageClass exists.
+   */
+  g_type_class_unref (g_type_class_ref (CALLY_TYPE_STAGE));
+}
diff --git a/clutter/cally/cally-util.h b/clutter/cally/cally-util.h
new file mode 100644 (file)
index 0000000..dfb6839
--- /dev/null
@@ -0,0 +1,61 @@
+/* CALLY - The Clutter Accessibility Implementation Library
+ *
+ * Copyright (C) 2008 Igalia, S.L.
+ *
+ * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
+ *
+ * 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.
+ */
+
+#ifndef __CALLY_UTIL_H__
+#define __CALLY_UTIL_H__
+
+#include <atk/atk.h>
+
+G_BEGIN_DECLS
+
+#define CALLY_TYPE_UTIL            (cally_util_get_type ())
+#define CALLY_UTIL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_UTIL, CallyUtil))
+#define CALLY_UTIL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_UTIL, CallyUtilClass))
+#define CALLY_IS_UTIL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_UTIL))
+#define CALLY_IS_UTIL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_UTIL))
+#define CALLY_UTIL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_UTIL, CallyUtilClass))
+
+typedef struct _CallyUtil        CallyUtil;
+typedef struct _CallyUtilClass   CallyUtilClass;
+typedef struct _CallyUtilPrivate CallyUtilPrivate;
+
+struct _CallyUtil
+{
+  AtkUtil parent;
+
+  /* < private > */
+  CallyUtilPrivate *priv;
+};
+
+struct _CallyUtilClass
+{
+  AtkUtilClass parent_class;
+
+  /* padding for future expansion */
+  gpointer _padding_dummy[30];
+};
+
+GType cally_util_get_type (void);
+
+G_END_DECLS
+
+#endif /* __CALLY_UTIL_H__ */
diff --git a/clutter/cally/cally.pc.in b/clutter/cally/cally.pc.in
new file mode 100644 (file)
index 0000000..baf0dc8
--- /dev/null
@@ -0,0 +1,18 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+apiversion=@CLUTTER_API_VERSION@
+requires=@CLUTTER_REQUIRES@
+backend=@COGL_WINSYS@ #only kept for backward compatability
+winsys=@COGL_WINSYS@
+cogl=@COGL_DRIVER@ #only kept for backward compatability
+driver=@COGL_DRIVER@
+
+Name: Cally
+Description: Clutter Accessibility Implementation Library
+Version: @VERSION@
+Requires: atk clutter-1.0
+Libs: -L${libdir} -lclutter-${winsys}-${apiversion}
+Cflags: -I${includedir}/clutter-${apiversion}
+Requires: ${requires}
index dc35b08..9a35c82 100644 (file)
@@ -1017,6 +1017,8 @@ AC_CONFIG_FILES([
         clutter/osx/Makefile
         clutter/win32/Makefile
         clutter/win32/clutter-win32.pc
+        clutter/cally/Makefile
+        clutter/cally/cally.pc
         clutter/cogl/Makefile
         clutter/cogl/cogl/Makefile
         clutter/cogl/cogl/cogl-defines.h