NULL =
-SUBDIRS = cogl $(CLUTTER_WINSYS_BASE) $(CLUTTER_WINSYS)
+SUBDIRS = cogl $(CLUTTER_WINSYS_BASE) $(CLUTTER_WINSYS) cally
if LOCAL_JSON_GLIB
SUBDIRS += json
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 =
INCLUDES = \
-I$(top_srcdir) \
+ -I$(top_srcdir)/clutter/cally \
-I$(top_srcdir)/clutter/cogl \
-I$(top_srcdir)/clutter/cogl/pango \
-I$(top_srcdir)/clutter \
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 \
$(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)
--- /dev/null
+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
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+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}
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