summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMark Doffman <mdoff@silver-wind.(none)>2008-05-28 21:37:20 +0100
committerMark Doffman <mdoff@silver-wind.(none)>2008-05-28 21:37:20 +0100
commitf346af9d38b2a69945543e38e1109ddb8131c886 (patch)
tree88b0eb23a71281ac05a3033fd3c3929d0891b202 /tests
parent0649430a8d6186fb070600b6704b7e9f959ca792 (diff)
downloadat-spi2-atk-f346af9d38b2a69945543e38e1109ddb8131c886.tar.gz
2008-05-28 Mark Doffman <mark.doffman@codethink.co.uk>
* tests/dummyatk Rework the LSB dummy implementation, taken from atk-tests. This is a very simple atk implementation for the purpose of testing at-spi. * tests/testapps Add a test framework for applications used in testing at-spi. Tests will generally make use of the dummy atk implmentaion.
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/dummyatk/Makefile.am33
-rw-r--r--tests/dummyatk/my-atk-action.c221
-rw-r--r--tests/dummyatk/my-atk-action.h56
-rw-r--r--tests/dummyatk/my-atk-component.c403
-rw-r--r--tests/dummyatk/my-atk-component.h41
-rw-r--r--tests/dummyatk/my-atk-hyperlink.c137
-rw-r--r--tests/dummyatk/my-atk-hyperlink.h35
-rw-r--r--tests/dummyatk/my-atk-hypertext.c172
-rw-r--r--tests/dummyatk/my-atk-hypertext.h33
-rw-r--r--tests/dummyatk/my-atk-object.c156
-rw-r--r--tests/dummyatk/my-atk-object.h30
-rw-r--r--tests/dummyatk/my-atk-streamable-content.c95
-rw-r--r--tests/dummyatk/my-atk-streamable-content.h33
-rw-r--r--tests/dummyatk/my-atk-text.c1290
-rw-r--r--tests/dummyatk/my-atk-text.h58
-rw-r--r--tests/dummyatk/my-atk-value.c112
-rw-r--r--tests/dummyatk/my-atk-value.h34
-rw-r--r--tests/dummyatk/my-atk.h14
-rw-r--r--tests/dummyatk/resources_storage.c34
-rw-r--r--tests/dummyatk/resources_storage.h16
-rw-r--r--tests/dummyatk/useful_functions.c29
-rw-r--r--tests/dummyatk/useful_functions.h30
-rw-r--r--tests/dummyatk/user_marshal.c41
-rw-r--r--tests/dummyatk/user_marshal.h60
-rw-r--r--tests/testapps/Makefile.am28
-rw-r--r--tests/testapps/noop-app.c14
-rw-r--r--tests/testapps/object-app.c21
-rw-r--r--tests/testapps/test-application.c146
29 files changed, 3374 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bc906a3..b012e65 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS=dummyatk testapps
+
EXTRA_DIST = \
AccessibleTree.py \
AccessibleTreeCache.py \
diff --git a/tests/dummyatk/Makefile.am b/tests/dummyatk/Makefile.am
new file mode 100644
index 0000000..397460b
--- /dev/null
+++ b/tests/dummyatk/Makefile.am
@@ -0,0 +1,33 @@
+check_LTLIBRARIES = libdummyatk.la
+
+libdummyatk_la_CFLAGS = $(ATK_CFLAGS) \
+ -I$(top_srcdir)
+
+libdummyatk_la_LDFLAGS = -no-undefined \
+ -module \
+ -avoid-version
+
+libdummyatk_la_LIBADD = $(ATK_LIBS)
+
+libdummyatk_la_SOURCES = my-atk-action.c \
+ my-atk-action.h \
+ my-atk-component.c \
+ my-atk-component.h \
+ my-atk-hyperlink.c \
+ my-atk-hyperlink.h \
+ my-atk-hypertext.c \
+ my-atk-hypertext.h \
+ my-atk-object.c \
+ my-atk-object.h \
+ my-atk-streamable-content.c \
+ my-atk-streamable-content.h \
+ my-atk-text.c \
+ my-atk-text.h \
+ my-atk-value.c \
+ my-atk-value.h \
+ resources_storage.c \
+ resources_storage.h \
+ useful_functions.c \
+ useful_functions.h \
+ user_marshal.c \
+ user_marshal.h
diff --git a/tests/dummyatk/my-atk-action.c b/tests/dummyatk/my-atk-action.c
new file mode 100644
index 0000000..048d0b2
--- /dev/null
+++ b/tests/dummyatk/my-atk-action.c
@@ -0,0 +1,221 @@
+#include <stdio.h>
+#include <string.h>
+#include <atk/atk.h>
+
+#include "my-atk-action.h"
+
+static GObjectClass *parent_class = NULL;
+//implementaion of the interface
+static gboolean my_atk_action_do_action(AtkAction *action, gint i)
+{
+ MyAtkAction *self = (MyAtkAction*)action;
+ gboolean result = (i>=0) && (i < self->n);
+ self->last_performed_action = result? i : -1;
+ return result;
+}
+static gint my_atk_action_get_n_actions(AtkAction *action)
+{
+ MyAtkAction *self = (MyAtkAction*)action;
+ return self->n;
+}
+static const gchar* my_atk_action_get_description(AtkAction *action, gint i)
+{
+ MyAtkAction *self = (MyAtkAction*)action;
+ if((i>=0) && (i<self->n))
+ {
+ return self->actions[i].description;
+ }
+ else
+ {
+ printf("get_description: Wrong index.\n");
+ return NULL;
+ }
+}
+static const gchar* my_atk_action_get_name(AtkAction *action, gint i)
+{
+ MyAtkAction *self = (MyAtkAction*)action;
+ if((i >= 0) && (i < self->n))
+ {
+ return self->actions[i].name;
+ }
+ else
+ {
+ printf("get_name: Wrong index.\n");
+ return NULL;
+ }
+}
+static const gchar* my_atk_action_get_localized_name(AtkAction *action, gint i)
+{
+ return my_atk_action_get_name(action,i);
+}
+
+static const gchar* my_atk_action_get_keybinding(AtkAction *action, gint i)
+{
+ MyAtkAction *self = (MyAtkAction*)action;
+ if((i >= 0) && (i < self->n))
+ {
+ gchar* keyb = self->actions[i].keybinding;
+ if(keyb == NULL || keybinding_note_define == NULL)
+ {
+ //anywhere(if action has keybinding or not) NULL will return
+ return NULL;
+ }
+ else
+ {
+ //verify, if string mean "no keybinding"
+ return strcmp(keyb, keybinding_note_define) != 0 ? keyb : NULL;
+ }
+ }
+ else
+ {
+ printf("get_keybinding: Wrong index.\n");
+ return NULL;
+ }
+}
+static gboolean my_atk_action_set_description(AtkAction *action, gint i, const gchar *desc)
+{
+ MyAtkAction *self = (MyAtkAction*)action;
+
+ if(!((i >= 0) && (i < self->n)) )
+ {
+ //index out of range, but this is not application error according documentation
+ return FALSE;
+ }
+ //index in correct range
+ if(self->actions[i].description == desc)
+ {
+ //self assignment - return immediately
+ return TRUE;
+ }
+ if(self->actions[i].description != NULL)
+ {
+ //free old value of description if it is not NULL
+ free(self->actions[i].description);
+ }
+ if(desc != NULL)
+ {
+ //dump new value of description if it is not NULL
+ self->actions[i].description = (gchar*)strdup((const char*)desc);
+ }
+ return TRUE;
+}
+//////////
+static void my_atk_action_instance_init(GTypeInstance *instance, gpointer g_class)
+{
+ int i;
+ MyAtkAction *self = (MyAtkAction*)instance;
+ self->n = DEFAULT_NUMBER_ACTIONS;
+ self->actions = g_new(struct OneAction, self->n);
+ if(self->actions == NULL)
+ {
+ self->n = 0;
+ return;
+ }
+ //init fields of action 0 with values which differ from others actions
+ self->actions[0].name = (gchar*)strdup(FIRST_ACTION_NAME);
+ self->actions[0].description = (gchar*)strdup(FIRST_ACTION_DESCRIPTION);
+ self->actions[0].keybinding = (gchar*)strdup(FIRST_ACTION_KEYBINDING);
+
+ for(i = 1; i < self->n; i++)
+ {
+ self->actions[i].name = (gchar*)strdup(DEFAULT_ACTION_NAME);
+ self->actions[i].description = (gchar*)strdup(DEFAULT_ACTION_DESCRIPTION);
+ self->actions[i].keybinding = (gchar*)strdup(DEFAULT_ACTION_KEYBINDING);
+ }
+ self->disposed = FALSE;
+ self->last_performed_action = -1;
+}
+
+static void
+my_atk_action_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ AtkActionIface *klass = (AtkActionIface *)g_iface;
+
+ klass->do_action = my_atk_action_do_action;
+ klass->get_n_actions = my_atk_action_get_n_actions;
+ klass->get_description = my_atk_action_get_description;
+ klass->get_name = my_atk_action_get_name;
+ klass->get_localized_name = my_atk_action_get_localized_name;
+ klass->get_keybinding = my_atk_action_get_keybinding;
+ klass->set_description = my_atk_action_set_description;
+}
+
+static void
+my_atk_action_dispose(GObject *obj)
+{
+ MyAtkAction *self = (MyAtkAction*)obj;
+
+ if(self->disposed)
+ {
+ return;
+ }
+ self->disposed = TRUE;
+
+ G_OBJECT_CLASS(parent_class)->dispose(obj);
+}
+
+static void
+my_atk_action_finalize(GObject *obj)
+{
+ MyAtkAction *self = (MyAtkAction*)obj;
+ int i;
+
+ for(i = 0; i < self->n; i++)
+ {
+ struct OneAction oneAction = self->actions[i];
+ if(oneAction.name != NULL)
+ free(oneAction.name);
+ if(oneAction.description != NULL)
+ free(oneAction.description);
+ if(oneAction.keybinding != NULL)
+ free(oneAction.keybinding);
+ }
+ if(self->actions != NULL)
+ g_free(self->actions);
+
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+static void
+my_atk_action_class_init (gpointer g_class, gpointer g_class_data)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
+ MyAtkActionClass *klass = MY_ATK_ACTION_CLASS (g_class);
+
+ gobject_class->dispose = my_atk_action_dispose;
+ gobject_class->finalize = my_atk_action_finalize;
+
+ parent_class = g_type_class_peek_parent(klass);
+}
+GType my_atk_action_get_type(void)
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (MyAtkActionClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ my_atk_action_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (MyAtkAction),
+ 0, /* n_preallocs */
+ my_atk_action_instance_init /* instance_init */
+ };
+
+ static const GInterfaceInfo iface_info =
+ {
+ (GInterfaceInitFunc) my_atk_action_interface_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "MyAtkAction",
+ &info, 0);
+ g_type_add_interface_static (type,
+ ATK_TYPE_ACTION,
+ &iface_info);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-action.h b/tests/dummyatk/my-atk-action.h
new file mode 100644
index 0000000..dc4da8b
--- /dev/null
+++ b/tests/dummyatk/my-atk-action.h
@@ -0,0 +1,56 @@
+#ifndef MY_ATK_ACTION_H
+#define MY_ATK_ACTION_H
+//Object, which implement interface AtkAction(all functions)
+#include <glib.h>
+#include <glib-object.h>
+#include <atk/atk.h>
+
+//declarations
+#define MY_TYPE_ATK_ACTION (my_atk_action_get_type ())
+#define MY_ATK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_ACTION, MyAtkAction))
+#define MY_ATK_ACTION_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_ACTION, MyAtkActionClass))
+#define MY_IS_ATK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_ACTION))
+#define MY_IS_ATK_ACTION_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_ACTION))
+#define MY_ATK_ACTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_ACTION, MyAtkActionClass))
+
+static const gchar* keybinding_note_define = "none";
+
+#define FIRST_ACTION_NAME "Default action"
+#define FIRST_ACTION_DESCRIPTION "This action will be perfomed by default"
+#define FIRST_ACTION_KEYBINDING "12345"
+
+#define DEFAULT_NUMBER_ACTIONS 10
+#define DEFAULT_ACTION_NAME "Action"
+#define DEFAULT_ACTION_DESCRIPTION "Description of action"
+#define DEFAULT_ACTION_KEYBINDING keybinding_note_define
+
+
+//for external using
+#define LAST_PERFORMED_ACTION(myAtkAction) (MY_ATK_ACTION(myAtkAction)->last_performed_action)
+#define CLEAR_LAST_PERFOMED_ACTION(myAtkAction) (MY_ATK_ACTION(myAtkAction)->last_performed_action = -1
+
+typedef struct _MyAtkAction MyAtkAction;
+typedef struct _MyAtkActionClass MyAtkActionClass;
+
+struct _MyAtkAction
+{
+ GObject parent;
+
+ gboolean disposed;
+ struct OneAction
+ {
+ gchar *name;
+ gchar *description;
+ gchar *keybinding;
+ }*actions;
+ gint n;
+ gint last_performed_action;//this field is changed when perfoms action
+};
+
+struct _MyAtkActionClass
+{
+ GObjectClass parent;
+};
+GType my_atk_action_get_type(void);
+
+#endif /*MY_ATK_ACTION_H*/
diff --git a/tests/dummyatk/my-atk-component.c b/tests/dummyatk/my-atk-component.c
new file mode 100644
index 0000000..e304c7d
--- /dev/null
+++ b/tests/dummyatk/my-atk-component.c
@@ -0,0 +1,403 @@
+#include <stdio.h>
+#include <atk/atk.h>
+#include <limits.h>
+
+#include "my-atk-object.h"
+#include "my-atk-component.h"
+
+//*************************implementation***********************
+static MyAtkObjectClass *component_parent_class = NULL;
+//current focus object
+static AtkComponent* focus_object = NULL;
+
+static guint focus_signal_id = 0;
+/*
+ * Because of implementation of AtkUtils, we need to ensure that list of focus_trackers
+ * is not empty. Otherwise function atk_focus_tracker_notify will not change focus.
+ */
+static guint focus_tracker_id = 0;
+static void my_event_listener(AtkObject* obj)
+{
+ //simply exist for register as focus_tracker
+}
+/*
+ * If this flag is TRUE, then focus cannot be changed until someone clears the flag
+ * via my_atk_component_set_modal(FALSE).
+ */
+static gboolean is_modal = FALSE;
+//for debug
+void print_extent(AtkRectangle *extent)
+{
+ printf("{%d,%d,%d,%d}", extent->x, extent->y, extent->width, extent->height);
+}
+//for internal use
+static void emit_bounds_changed(MyAtkComponent *component)
+{
+ static guint bounds_changed_id = 0;
+ if(bounds_changed_id == 0)
+ {
+ bounds_changed_id = g_signal_lookup("bounds-changed", ATK_TYPE_COMPONENT);
+ }
+ AtkRectangle *param = g_boxed_copy(ATK_TYPE_RECTANGLE, &(component->extent));
+ g_signal_emit(component, bounds_changed_id, 0, param);
+}
+static void change_focus(AtkComponent* component, gboolean is_gain)
+{
+ const gchar* state_name = atk_state_type_get_name(ATK_STATE_FOCUSED);
+
+ g_signal_emit_by_name(component, "focus-event", is_gain);
+ g_signal_emit_by_name(component, "state-change::focused",
+ state_name, is_gain);
+
+ AtkObject* parent = atk_object_get_parent((AtkObject*)component);
+ if(parent != NULL)
+ {
+ AtkStateSet* stateSet = atk_object_ref_state_set(parent);
+ if(atk_state_set_contains_state(stateSet, ATK_STATE_MANAGES_DESCENDANTS))
+ g_signal_emit_by_name(parent, "active-descendant-changed",
+ atk_get_focus_object());
+ g_object_unref(stateSet);
+ }
+}
+//implementation of virtual functions
+//******************ref_state_set(AtkObject)*****************************
+static AtkStateSet* my_atk_component_ref_state_set(AtkObject *object)
+{
+ MyAtkComponent *self = (MyAtkComponent*)object;
+
+ AtkStateSet* result = ((AtkObjectClass*)component_parent_class)->
+ ref_state_set(object);
+ if(self->is_manage_descendants)
+ atk_state_set_add_state(result, ATK_STATE_MANAGES_DESCENDANTS);
+ return result;
+}
+//******************get_size*******************
+static void my_atk_component_get_size(AtkComponent *component, gint *width, gint *height)
+{
+ g_return_if_fail(MY_IS_ATK_COMPONENT(component));
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+ *width = self->extent.width;
+ *height = self->extent.height;
+}
+//*********************get_position*******************
+static void my_atk_component_get_position(AtkComponent *component, gint *x, gint *y, AtkCoordType coord_type)
+{
+ g_return_if_fail(MY_IS_ATK_COMPONENT(component));
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+ *x = self->extent.x;
+ *y = self->extent.y;
+
+//**********************get_extents*******************
+}
+static void my_atk_component_get_extents(AtkComponent *component, gint *x, gint *y,
+ gint *width, gint *height, AtkCoordType coord_type)
+{
+ g_return_if_fail(MY_IS_ATK_COMPONENT(component));
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+ *x = self->extent.x;
+ *y = self->extent.y;
+ *width = self->extent.width;
+ *height = self->extent.height;
+}
+
+//**************************set_size*******************
+static gboolean my_atk_component_set_size(AtkComponent *component, gint width, gint height)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+ if(self->is_extent_may_changed)
+ {
+ self->extent.width = width;
+ self->extent.height = height;
+
+ emit_bounds_changed(self);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+//**************************set_position********************
+static gboolean my_atk_component_set_position(AtkComponent *component,
+ gint x, gint y, AtkCoordType coord_type)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+ if(self->is_extent_may_changed)
+ {
+ self->extent.x = x;
+ self->extent.y = y;
+
+ emit_bounds_changed(self);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+//*************************************set_extents***************
+static gboolean my_atk_component_set_extents(AtkComponent *component,
+ gint x, gint y, gint width, gint height, AtkCoordType coord_type)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+
+ if(self->is_extent_may_changed)
+ {
+ self->extent.x = x;
+ self->extent.y = y;
+ self->extent.width = width;
+ self->extent.height = height;
+
+ emit_bounds_changed(self);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+//**************************get_layer****************
+static AtkLayer my_atk_component_get_layer(AtkComponent *component)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), ATK_LAYER_INVALID);
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+ return self->layer;
+}
+//**************************get_mdi_zorder****************
+static gint my_atk_component_get_mdi_zorder(AtkComponent *component)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), G_MININT);
+
+ MyAtkComponent *self = MY_ATK_COMPONENT(component);
+ return self->zorder;
+}
+//***********************contains**********************
+static gboolean my_atk_component_contains(AtkComponent *component,
+ gint x, gint y, AtkCoordType coord_type)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
+ //for extract extent
+ gint x_tmp, y_tmp, width_tmp, height_tmp;
+ my_atk_component_get_extents(component, &x_tmp, &y_tmp, &width_tmp, &height_tmp, coord_type);
+
+ if( (x >= x_tmp) &&(y >= y_tmp) &&(x < x_tmp + width_tmp) && (y < y_tmp + height_tmp) )
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+//**********************ref_accessible_at_point***********************
+/*
+ * Retuns accessible child that implements AtkCOmponent and contains the given point.
+ */
+static AtkObject* my_atk_component_ref_accessible_at_point(AtkComponent* component,
+ gint x, gint y, AtkCoordType coord_type)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), NULL);
+ gint i;
+
+ gint n_children = atk_object_get_n_accessible_children((AtkObject*)component);
+ for(i = 0; i < n_children; i++)
+ {
+ AtkObject *child = atk_object_ref_accessible_child((AtkObject*)component, i);
+ if(ATK_IS_COMPONENT(child)
+ && atk_component_contains((AtkComponent*)child, x, y, coord_type))
+ {
+ return child;
+ }
+ g_object_unref(child);
+ }
+ return NULL;
+}
+//*************************************grab_focus*********************************
+static gboolean my_atk_component_grab_focus(AtkComponent* component)
+{
+ if(component == focus_object)
+ {
+ //Already has focus
+ return TRUE;
+ }
+ if(is_modal)
+ {
+ //cannot grab focus
+ return FALSE;
+ }
+ AtkComponent *focus_object_old = focus_object;
+ focus_object = component;
+
+ atk_focus_tracker_notify((AtkObject*)component);
+
+ if(focus_object_old != NULL)
+ {
+ //signals for object which lost focus
+ change_focus(focus_object_old, FALSE);
+ }
+ if(component != NULL)
+ {
+ //signals for object which grab focus
+ change_focus(component, TRUE);
+ }
+ return TRUE;
+}
+//***********************my_atk_component_add_focus_handler*********************
+static guint my_atk_component_add_focus_handler(AtkComponent *component, AtkFocusHandler handler)
+{
+ g_return_val_if_fail(MY_IS_ATK_COMPONENT(component),0);
+ //verify whether handler already connect to object
+ gulong found_handler_id = g_signal_handler_find(component,
+ G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
+ focus_signal_id,
+ 0,
+ NULL,
+ (gpointer)handler,
+ NULL);
+ if(found_handler_id == 0)
+ {
+ //handler hasn't been connected yet
+ return g_signal_connect_closure_by_id(component,
+ focus_signal_id,
+ 0,
+ g_cclosure_new( (GCallback)handler,
+ NULL,
+ NULL),
+ FALSE);
+ }
+ else/* found_handler_id != 0*/
+ {
+ //handler has already been connected
+ return 0;
+ }
+
+}
+//***********************my_atk_component_remove_focus_handler*********************
+static void my_atk_component_remove_focus_handler(AtkComponent *component, guint handler_id)
+{
+ g_signal_handler_disconnect(component, handler_id);
+}
+//***********************my_atk_component_set_modal(my function)***************
+void my_atk_component_set_modal(gboolean value)
+{
+ is_modal = value;
+}
+//******************my_atk_component_set_manage_descendants(my_function)*******
+void my_atk_component_set_manage_descendants(MyAtkComponent* component, gboolean value)
+{
+ if(component->is_manage_descendants == value)return;
+ component->is_manage_descendants = value;
+ g_signal_emit_by_name(component, "state-change::manages-descendants",
+ "manages-descendants", value);
+}
+//Others funtions
+static void my_atk_component_instance_init(GTypeInstance *obj, gpointer g_class)
+{
+ MyAtkComponent *self = (MyAtkComponent*)obj;
+ //set defaults values
+ self->extent.x = 0;
+ self->extent.y = 0;
+ self->extent.width = 10;
+ self->extent.height = 10;
+ self->is_extent_may_changed = TRUE;
+ self->layer = ATK_LAYER_INVALID;
+ self->zorder = -2147;
+}
+static void my_atk_component_instance_finalize(GObject* obj)
+{
+ MyAtkComponent* component = (MyAtkComponent*)obj;
+
+ if(((AtkObject*)component) == atk_get_focus_object())
+ {
+ atk_focus_tracker_notify(NULL);
+ }
+}
+
+static void my_atk_component_class_init(gpointer g_class, gpointer class_data)
+{
+ GObjectClass* g_object_class = (GObjectClass*)g_class;
+ AtkObjectClass* atkObject_class = (AtkObjectClass*)g_class;
+ //GObject virtual table
+ g_object_class->finalize = my_atk_component_instance_finalize;
+ //AtkObject virtual table
+ atkObject_class->ref_state_set = my_atk_component_ref_state_set;
+ //parent_class
+ component_parent_class = g_type_class_peek_parent(g_class);
+ //make focus_tracker's table not empty.
+ focus_tracker_id = atk_add_focus_tracker(my_event_listener);
+ //store "focus-event"-signal id
+ focus_signal_id = g_signal_lookup("focus-event",MY_TYPE_ATK_COMPONENT);
+}
+/*
+ * Though, according to the documentation, this function will never called for
+ * static-registred types.
+ * Base_init function doesn't suite for this work,
+ * because it will called in every derived classes.
+ */
+/*static void my_atk_component_class_finalize(gpointer g_class, gpointer class_data)
+{
+
+ if(focus_tracker_id != 0)
+ {
+ atk_remove_focus_tracker(focus_tracker_id);
+ focus_tracker_id = 0;
+ }
+}*/
+static void my_atk_component_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ AtkComponentIface *klass = (AtkComponentIface*)g_iface;
+
+ klass->get_extents = my_atk_component_get_extents;
+ klass->get_position = my_atk_component_get_position;
+ klass->get_size = my_atk_component_get_size;
+
+ klass->set_extents = my_atk_component_set_extents;
+ klass->set_position = my_atk_component_set_position;
+ klass->set_size = my_atk_component_set_size;
+
+ klass->contains = my_atk_component_contains;
+ klass->ref_accessible_at_point = my_atk_component_ref_accessible_at_point;
+
+ klass->get_layer = my_atk_component_get_layer;
+ klass->get_mdi_zorder = my_atk_component_get_mdi_zorder;
+
+ klass->grab_focus = my_atk_component_grab_focus;
+ klass->add_focus_handler = my_atk_component_add_focus_handler;
+ klass->remove_focus_handler = my_atk_component_remove_focus_handler;
+}
+
+GType my_atk_component_get_type()
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof(MyAtkComponentClass),
+ NULL, //base_init
+ NULL, //base_finalize
+ my_atk_component_class_init, //class_init
+ NULL, //class_finalize
+ NULL, //class_data
+ sizeof(MyAtkComponent),
+ 0, //n_preallocs
+ my_atk_component_instance_init //instance_init
+ };
+
+ static const GInterfaceInfo iface_info =
+ {
+ my_atk_component_interface_init, /* interface_init*/
+ NULL, /* interface_finalize*/
+ NULL /* interface_data */
+ };
+ type = g_type_register_static(MY_TYPE_ATK_OBJECT, "MyAtkComponent", &typeInfo, 0);
+ g_type_add_interface_static(type,
+ ATK_TYPE_COMPONENT,
+ &iface_info);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-component.h b/tests/dummyatk/my-atk-component.h
new file mode 100644
index 0000000..3fa5850
--- /dev/null
+++ b/tests/dummyatk/my-atk-component.h
@@ -0,0 +1,41 @@
+#ifndef MY_ATK_COMPONENT_H
+#define MY_ATK_COMPONENT_H
+/*
+ * MyAtkComponent: derives AtkObject(with parent-child accessibilities)
+ * and implements AtkComponent.
+ */
+#include <atk/atk.h>
+
+#include "my-atk-object.h"
+
+#define MY_TYPE_ATK_COMPONENT (my_atk_component_get_type ())
+#define MY_ATK_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_COMPONENT, MyAtkComponent))
+#define MY_ATK_COMPONENT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_COMPONENT, MyAtkComponentClass))
+#define MY_IS_ATK_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_COMPONENT))
+#define MY_IS_ATK_COMPONENT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_COMPONENT))
+#define MY_ATK_COMPONENT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_COMPONENT, MyAtkComponentClass))
+
+typedef struct _MyAtkComponent MyAtkComponent;
+typedef struct _MyAtkComponentClass MyAtkComponentClass;
+
+struct _MyAtkComponent
+{
+ MyAtkObject parent;
+ //relative coordinates, which coincides with absolute ones
+ AtkRectangle extent;
+ //whether component may be relocated
+ gboolean is_extent_may_changed;
+ //for emit "active-descendant-changed" signal
+ gboolean is_manage_descendants;
+ //
+ AtkLayer layer;
+ gint zorder;
+};
+
+struct _MyAtkComponentClass
+{
+ MyAtkObjectClass parent;
+};
+
+GType my_atk_component_get_type();
+#endif /*MY_ATK_COMPONENT_H*/
diff --git a/tests/dummyatk/my-atk-hyperlink.c b/tests/dummyatk/my-atk-hyperlink.c
new file mode 100644
index 0000000..cb6b435
--- /dev/null
+++ b/tests/dummyatk/my-atk-hyperlink.c
@@ -0,0 +1,137 @@
+#include <atk/atk.h>
+
+#include "my-atk-text.h"
+#include "my-atk-hyperlink.h"
+#include "resources_storage.h"
+
+//***************************implementation****************************************
+static MyAtkTextClass *parent_class_atk_hyperlink = NULL;
+
+// Implementation of virtual functions
+//***************************my_atk_hyperlink_get_uri**************
+gchar* my_atk_hyperlink_get_uri(AtkHyperlink* link_, gint index)
+{
+ MyAtkHyperlink* self = (MyAtkHyperlink*)link_;
+
+ if(index < 0 || index >= self->number_of_anchors) return NULL;
+ return g_strdup(self->uri);
+}
+//**************************my_atk_hyperlink_is_valid**************************
+gboolean my_atk_hyperlink_is_valid(AtkHyperlink* link_)
+{
+ MyAtkHyperlink* self = (MyAtkHyperlink*)link_;
+
+ return (resource_storage_get(self->uri) != NULL);
+}
+//*************************my_atk_hyperlink_get_object************************
+AtkObject* my_atk_hyperlink_get_object(AtkHyperlink* link_, gint index)
+{
+ MyAtkHyperlink* self = (MyAtkHyperlink*)link_;
+
+ if(index < 0 || index >= self->number_of_anchors) return NULL;
+ return resource_storage_get(self->uri);
+}
+//***************************my_atk_hyperlink_get_start_index**************
+gint my_atk_hyperlink_get_start_index(AtkHyperlink* link_)
+{
+ MyAtkHyperlink* self = (MyAtkHyperlink*)link_;
+
+ return self->start_index;
+}
+//***************************my_atk_hyperlink_get_end_index**************
+gint my_atk_hyperlink_get_end_index(AtkHyperlink* link_)
+{
+ MyAtkHyperlink* self = (MyAtkHyperlink*)link_;
+
+ return self->end_index;
+}
+//***************************my_atk_hyperlink_link_state*******************
+guint my_atk_hyperlink_link_state(AtkHyperlink* link_)
+{
+ return 0;
+}
+//***************************my_atk_hyperlink_get_n_anchors*******************
+gboolean my_atk_hyperlink_get_n_anchors(AtkHyperlink* link_)
+{
+ return ((MyAtkHyperlink*)link_)->number_of_anchors;
+}
+//***************************my_atk_hypertlink_is_selected_link***********
+gboolean my_atk_hyperlink_is_selected_link(AtkHyperlink* link_)
+{
+ MyAtkHyperlink* self = (MyAtkHyperlink*)link_;
+
+ return self->is_selected;
+}
+//others functions
+MyAtkHyperlink* my_atk_hyperlink_new(gint start_index, gint end_index,const gchar* uri)
+{
+ MyAtkHyperlink* result = g_object_new(MY_TYPE_ATK_HYPERLINK, NULL);
+ if(result == NULL) return NULL;
+ result->start_index = start_index;
+ result->end_index = end_index;
+ result->uri = g_strdup(uri);
+ result->number_of_anchors = 1;
+ return result;
+}
+void my_atk_hyperlink_activate(MyAtkHyperlink* hyperlink)
+{
+ g_signal_emit_by_name(hyperlink, "link-activated");
+}
+//initialize/finalize functions
+static void my_atk_hyperlink_instance_init(GTypeInstance *obj, gpointer g_class)
+{
+ MyAtkHyperlink *self = (MyAtkHyperlink*)obj;
+
+ self->start_index = self->end_index = 0;
+ self->uri = NULL;
+ self->is_selected = FALSE;
+ self->number_of_anchors = 0;
+}
+static void my_atk_hyperlink_instance_finalize(GObject* obj)
+{
+ MyAtkHyperlink *self = (MyAtkHyperlink*)obj;
+
+ g_free(self->uri);
+}
+
+static void my_atk_hyperlink_class_init(gpointer g_class, gpointer class_data)
+{
+ GObjectClass* g_object_class = (GObjectClass*)g_class;
+ //GObject virtual table
+ g_object_class->finalize = my_atk_hyperlink_instance_finalize;
+ //parent_class
+ parent_class_atk_hyperlink = g_type_class_peek_parent(g_class);
+ //
+ AtkHyperlinkClass* atkHyperlinkClass = (AtkHyperlinkClass*)g_class;
+
+ atkHyperlinkClass->get_uri = my_atk_hyperlink_get_uri;
+ atkHyperlinkClass->get_object = my_atk_hyperlink_get_object;
+ atkHyperlinkClass->get_start_index = my_atk_hyperlink_get_start_index;
+ atkHyperlinkClass->get_end_index = my_atk_hyperlink_get_end_index;
+ atkHyperlinkClass->is_valid = my_atk_hyperlink_is_valid;
+ atkHyperlinkClass->link_state = my_atk_hyperlink_link_state;
+ atkHyperlinkClass->get_n_anchors = my_atk_hyperlink_get_n_anchors;
+ atkHyperlinkClass->is_selected_link = my_atk_hyperlink_is_selected_link;
+}
+
+GType my_atk_hyperlink_get_type()
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof(MyAtkHyperlinkClass),
+ NULL, //base_init
+ NULL, //base_finalize
+ my_atk_hyperlink_class_init, //class_init
+ NULL, //class_finalize
+ NULL, //class_data
+ sizeof(MyAtkHyperlink),
+ 0, //n_preallocs
+ my_atk_hyperlink_instance_init //instance_init
+ };
+ type = g_type_register_static(ATK_TYPE_HYPERLINK, "MyAtkHyperlink", &typeInfo, 0);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-hyperlink.h b/tests/dummyatk/my-atk-hyperlink.h
new file mode 100644
index 0000000..026ba54
--- /dev/null
+++ b/tests/dummyatk/my-atk-hyperlink.h
@@ -0,0 +1,35 @@
+#ifndef MY_ATK_HYPERLINK_H
+#define MY_ATK_HYPERLINK_H
+/*
+ * MyAtkHyperlink: implements AtkHyperlink
+ */
+#include <atk/atk.h>
+
+#define MY_TYPE_ATK_HYPERLINK (my_atk_hyperlink_get_type ())
+#define MY_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_HYPERLINK, MyAtkHyperlink))
+#define MY_ATK_HYPERLINK_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_HYPERLINK, MyAtkHyperlinkClass))
+#define MY_IS_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_HYPERLINK))
+#define MY_IS_ATK_HYPERLINK_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_HYPERLINK))
+#define MY_ATK_HYPERLINK_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_HYPERLINK, MyAtkHyperlinkClass))
+
+typedef struct _MyAtkHyperlink MyAtkHyperlink;
+typedef struct _MyAtkHyperlinkClass MyAtkHyperlinkClass;
+
+struct _MyAtkHyperlink
+{
+ AtkHyperlink parent;
+
+ gint start_index, end_index;
+
+ gchar* uri;
+ gint number_of_anchors;//0 on "clear" hyperlink and 1 after set it
+ gboolean is_selected;
+};
+
+struct _MyAtkHyperlinkClass
+{
+ AtkHyperlinkClass parent;
+};
+
+GType my_atk_hyperlink_get_type();
+#endif /*MY_ATK_HYPERLINK_H*/
diff --git a/tests/dummyatk/my-atk-hypertext.c b/tests/dummyatk/my-atk-hypertext.c
new file mode 100644
index 0000000..1bba620
--- /dev/null
+++ b/tests/dummyatk/my-atk-hypertext.c
@@ -0,0 +1,172 @@
+#include <atk/atk.h>
+
+#include "my-atk-text.h"
+#include "my-atk-hyperlink.h"
+#include "my-atk-hypertext.h"
+
+//***************************implementation****************************************
+static MyAtkTextClass *parent_class_atk_text = NULL;
+
+typedef struct
+{
+ gint start_offset, end_offset;
+ gint index;
+}HyperlinkRange;
+// Implementation of virtual functions
+
+//***************************my_atk_hypertext_get_n_links*************************
+gint my_atk_hypertext_get_n_links(AtkHypertext* hypertext)
+{
+ MyAtkHypertext* self = (MyAtkHypertext*)hypertext;
+
+ return self->hyperlinks->len;
+}
+//***************************my_atk_hypertext_get_link***********************
+AtkHyperlink* my_atk_hypertext_get_link(AtkHypertext* hypertext, gint link_index)
+{
+ MyAtkHypertext* self = (MyAtkHypertext*)hypertext;
+
+ if(link_index < 0 || link_index >= self->hyperlinks->len)
+ return NULL;
+ return g_ptr_array_index(self->hyperlinks, link_index);
+}
+//*************************my_atk_hypertext_get_link_index*******************
+gint my_atk_hypertext_get_link_index(AtkHypertext* hypertext, gint char_index)
+{
+ gint i;
+ MyAtkHypertext* self = (MyAtkHypertext*)hypertext;
+ GArray* ranges = self->hyperlink_ranges;
+ for(i = ranges->len - 1; i >= 0; i--)
+ {
+ HyperlinkRange *range = &g_array_index(ranges, HyperlinkRange, i);
+ if(range->start_offset <= char_index)
+ {
+ if(range->end_offset > char_index)return range->index;
+ break;
+ }
+ }
+ return -1;
+}
+//others functions
+gboolean my_atk_hypertext_add_hyperlink(MyAtkHypertext* hypertext,
+ gint start_index, gint end_index, const gchar* uri)
+{
+ MyAtkHyperlink* new_hyperlink;
+ GArray* ranges = hypertext->hyperlink_ranges;
+ gint i;
+ for(i = 0; i < ranges->len; i++)
+ {
+ HyperlinkRange *range = &g_array_index(ranges, HyperlinkRange, i);
+ if(range->end_offset <= start_index) continue;
+ if(range->start_offset < end_index) return FALSE;
+ break;
+ }
+ new_hyperlink = my_atk_hyperlink_new(start_index, end_index, uri);
+ g_ptr_array_add(hypertext->hyperlinks, new_hyperlink);
+ HyperlinkRange new_range;
+ new_range.start_offset = start_index;
+ new_range.end_offset = end_index;
+ new_range.index = hypertext->hyperlinks->len - 1;
+ g_array_insert_val(ranges, i, new_range);
+ return TRUE;
+}
+//
+void my_atk_hypertext_select_link(MyAtkHypertext* hypertext, gint index)
+{
+ if(index < 0 || index >= my_atk_hypertext_get_n_links((AtkHypertext*)hypertext))
+ return;
+
+ if(hypertext->current_selected_link != -1)
+ {
+ MyAtkHyperlink *selected_link_old =
+ (MyAtkHyperlink*)my_atk_hypertext_get_link(
+ (AtkHypertext*)hypertext, hypertext->current_selected_link);
+ selected_link_old->is_selected = FALSE;
+ }
+
+ hypertext->current_selected_link = index;
+ MyAtkHyperlink *selected_link_new = (MyAtkHyperlink*)my_atk_hypertext_get_link(
+ (AtkHypertext*)hypertext, hypertext->current_selected_link);
+ selected_link_new->is_selected = TRUE;
+
+ g_signal_emit_by_name(hypertext,
+ "link-selected", hypertext->current_selected_link);
+}
+//initialize/finalize functions
+static void my_atk_hypertext_instance_init(GTypeInstance *obj, gpointer g_class)
+{
+ MyAtkHypertext *self = (MyAtkHypertext*)obj;
+
+ self->hyperlink_ranges = g_array_new(FALSE, FALSE, sizeof(HyperlinkRange));
+ self->hyperlinks = g_ptr_array_new();
+
+ self->current_selected_link = -1;
+}
+static void my_atk_hypertext_instance_finalize(GObject* obj)
+{
+ MyAtkHypertext *self = (MyAtkHypertext*)obj;
+
+ g_array_free(self->hyperlink_ranges, FALSE);
+
+ g_ptr_array_foreach(self->hyperlinks,(GFunc)g_object_unref, NULL);
+ g_ptr_array_free(self->hyperlinks, FALSE);
+}
+
+static void my_atk_hypertext_class_init(gpointer g_class, gpointer class_data)
+{
+ GObjectClass* g_object_class = (GObjectClass*)g_class;
+ //GObject virtual table
+ g_object_class->finalize = my_atk_hypertext_instance_finalize;
+ //parent_class
+ parent_class_atk_text = g_type_class_peek_parent(g_class);
+}
+static void my_atk_hypertext_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ AtkHypertextIface *klass = (AtkHypertextIface*)g_iface;
+
+ klass->get_link = my_atk_hypertext_get_link;
+ klass->get_n_links = my_atk_hypertext_get_n_links;
+ klass->get_link_index = my_atk_hypertext_get_link_index;
+}
+
+GType my_atk_hypertext_get_type()
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof(MyAtkHypertextClass),
+ NULL, //base_init
+ NULL, //base_finalize
+ my_atk_hypertext_class_init, //class_init
+ NULL, //class_finalize
+ NULL, //class_data
+ sizeof(MyAtkHypertext),
+ 0, //n_preallocs
+ my_atk_hypertext_instance_init //instance_init
+ };
+
+ static const GInterfaceInfo AtkTextIface_info =
+ {
+ my_atk_text_interface_init, /* interface_init*/
+ NULL, /* interface_finalize*/
+ NULL /* interface_data */
+ };
+ static const GInterfaceInfo AtkHypertextIface_info =
+ {
+ my_atk_hypertext_interface_init,/* interface_init*/
+ NULL, /* interface_finalize*/
+ NULL /* interface_data */
+ };
+ type = g_type_register_static(MY_TYPE_ATK_TEXT, "MyAtkHypertext", &typeInfo, 0);
+ g_type_add_interface_static(type,
+ ATK_TYPE_TEXT,
+ &AtkTextIface_info);
+
+ g_type_add_interface_static(type,
+ ATK_TYPE_HYPERTEXT,
+ &AtkHypertextIface_info);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-hypertext.h b/tests/dummyatk/my-atk-hypertext.h
new file mode 100644
index 0000000..50d02cf
--- /dev/null
+++ b/tests/dummyatk/my-atk-hypertext.h
@@ -0,0 +1,33 @@
+#ifndef MY_ATK_HYPERTEXT_H
+#define MY_ATK_HYPERTEXT_H
+/*
+ * MyAtkHypertext: implements AtkHypertext
+ */
+#include <atk/atk.h>
+#include <my-atk-text.h>
+
+#define MY_TYPE_ATK_HYPERTEXT (my_atk_hypertext_get_type ())
+#define MY_ATK_HYPERTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_HYPERTEXT, MyAtkHypertext))
+#define MY_ATK_HYPERTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_HYPERTEXT, MyAtkHypertextClass))
+#define MY_IS_ATK_HYPERTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_HYPERTEXT))
+#define MY_IS_ATK_HYPERTEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_HYPERTEXT))
+#define MY_ATK_HYPERTEXT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_HYPERTEXT, MyAtkHypertextClass))
+
+typedef struct _MyAtkHypertext MyAtkHypertext;
+typedef struct _MyAtkHypertextClass MyAtkHypertextClass;
+
+struct _MyAtkHypertext
+{
+ MyAtkText parent;
+
+ GArray* hyperlink_ranges;
+ GPtrArray* hyperlinks;
+
+ gint current_selected_link;
+};
+
+struct _MyAtkHypertextClass
+{
+ MyAtkTextClass parent;
+};
+#endif /*MY_ATK_HYPERTEXT_H*/
diff --git a/tests/dummyatk/my-atk-object.c b/tests/dummyatk/my-atk-object.c
new file mode 100644
index 0000000..d45a2ef
--- /dev/null
+++ b/tests/dummyatk/my-atk-object.c
@@ -0,0 +1,156 @@
+
+#include <atk/atk.h>
+
+#include "my-atk-object.h"
+
+static AtkObjectClass *atk_object_parent_class = NULL;
+
+
+//add/remove child to/from array of parent(for internal use)
+static void my_atk_object_add_child(MyAtkObject* parent, MyAtkObject* child)
+{
+ g_ptr_array_add(parent->children, child);
+ g_object_ref(child);
+
+ g_signal_emit_by_name(parent, "children-changed::add",
+ parent->children->len - 1, child);
+}
+
+static void my_atk_object_remove_child(MyAtkObject* parent, MyAtkObject* child)
+{
+ gint i;
+ for(i = parent->children->len - 1; i >= 0; i--)
+ {
+ if(g_ptr_array_index(parent->children, i) == child) break;
+ }
+ if(i < 0)return;
+
+ g_ptr_array_remove_index(parent->children, i);
+ g_object_unref(child);
+ g_signal_emit_by_name(parent, "children-changed::remove",
+ i, child);
+}
+
+static void my_atk_object_set_parent(AtkObject *accessible, AtkObject *parent)
+{
+ //applicable only with corresponding type of parent
+ g_return_if_fail(parent == NULL || MY_IS_ATK_OBJECT(parent));
+
+ MyAtkObject *self = MY_ATK_OBJECT(accessible);
+ AtkObject *parent_old = (atk_object_get_parent(accessible));
+
+ if(parent_old == parent)
+ {
+ //nothing to do because parent does not change
+ return;
+ }
+
+ //set field 'parent' in child using 'base-method'
+ atk_object_parent_class->set_parent(accessible, parent);
+
+ if(parent_old != NULL)
+ {
+ my_atk_object_remove_child((MyAtkObject*)parent_old, self);
+ }
+ if(parent != NULL)
+ {
+ my_atk_object_add_child((MyAtkObject*)parent, self);
+ }
+}
+
+static gint my_atk_object_get_n_children(AtkObject *accessible)
+{
+ return MY_ATK_OBJECT(accessible)->children->len;
+}
+
+static AtkObject* my_atk_object_ref_child(AtkObject *accessible, gint i)
+{
+ MyAtkObject *self = MY_ATK_OBJECT(accessible);
+ if(i < 0 || i >= self->children->len)
+ {
+ printf("ref_child: Incorrect index of child.\n");
+ return NULL;
+ }
+
+ AtkObject* child = (AtkObject*)
+ g_ptr_array_index(self->children, i);
+
+ return (child == NULL) ? NULL : g_object_ref(child);
+}
+
+static gint my_atk_object_get_index_in_parent(AtkObject *accessible)
+{
+ AtkObject *parent = atk_object_get_parent(accessible);
+ if(parent == NULL) return -1;//no parent
+
+ MyAtkObject *parent_my = MY_ATK_OBJECT(parent);
+
+ int i = parent_my->children->len;
+ for(; i>=0; i--)
+ {
+ if(g_ptr_array_index(parent_my->children,i) == accessible)
+ break;
+ }
+ if(i < 0)printf("Something wrong in parent-child strucutre.\n");
+ return i;//if error, i will be equal to -1
+}
+
+//function, needed in instance_finalize()
+static void my_unref1(gpointer data, gpointer user_data)
+{
+ g_object_unref(data);
+}
+
+static void my_atk_object_instance_finalize(GObject *obj)
+{
+ MyAtkObject *self = (MyAtkObject*) obj;
+ //unrefs all children
+ g_ptr_array_foreach(self->children, my_unref1, NULL);
+ //then free array (without frees pointers)
+ g_ptr_array_free(self->children, FALSE);
+ //chain to parent class
+ G_OBJECT_CLASS(atk_object_parent_class)->finalize(obj);
+}
+
+void my_atk_object_class_init(gpointer g_class, gpointer g_class_data)
+{
+ AtkObjectClass *atkObjectClass = (AtkObjectClass*)g_class;
+
+ ((GObjectClass*)g_class)->finalize = my_atk_object_instance_finalize;
+ //set pointers to new functions in table of virtuals functions
+ atkObjectClass->set_parent = my_atk_object_set_parent;
+ atkObjectClass->get_n_children = my_atk_object_get_n_children;
+ atkObjectClass->ref_child = my_atk_object_ref_child;
+ atkObjectClass->get_index_in_parent = my_atk_object_get_index_in_parent;
+
+ atk_object_parent_class = g_type_class_peek_parent(g_class);
+}
+
+static void my_atk_object_instance_init(GTypeInstance *obj, gpointer g_class)
+{
+ MyAtkObject *self = (MyAtkObject*)obj;
+
+ self->children = g_ptr_array_sized_new(10);
+}
+
+GType my_atk_object_get_type()
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof(MyAtkObjectClass),
+ NULL, //base_init
+ NULL, //base_finalize
+ my_atk_object_class_init, //class_init
+ NULL, //class_finalize
+ NULL, //class_data
+ sizeof(MyAtkObject),
+ 0, //n_preallocs
+ my_atk_object_instance_init //instance_init
+ };
+ type = g_type_register_static(ATK_TYPE_OBJECT,"MyAtkObject",&typeInfo,0);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-object.h b/tests/dummyatk/my-atk-object.h
new file mode 100644
index 0000000..3e1eed6
--- /dev/null
+++ b/tests/dummyatk/my-atk-object.h
@@ -0,0 +1,30 @@
+#ifndef MY_ATK_OBJECT_H
+#define MY_ATK_OBJECT_H
+
+#include <atk/atk.h>
+
+#define MY_TYPE_ATK_OBJECT (my_atk_object_get_type ())
+#define MY_ATK_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_OBJECT, MyAtkObject))
+#define MY_ATK_OBJECT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_OBJECT, MyAtkObjectClass))
+#define MY_IS_ATK_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_OBJECT))
+#define MY_IS_ATK_OBJECT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_OBJECT))
+#define MY_ATK_OBJECT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_OBJECT, MyAtkObjectClass))
+
+typedef struct _MyAtkObject MyAtkObject;
+typedef struct _MyAtkObjectClass MyAtkObjectClass;
+
+struct _MyAtkObject
+{
+ AtkObject parent;
+ //array of children
+ GPtrArray* children;
+};
+
+struct _MyAtkObjectClass
+{
+ AtkObjectClass parent;
+};
+
+GType my_atk_object_get_type();
+
+#endif /*MY_ATK_OBJECT_H*/
diff --git a/tests/dummyatk/my-atk-streamable-content.c b/tests/dummyatk/my-atk-streamable-content.c
new file mode 100644
index 0000000..4141344
--- /dev/null
+++ b/tests/dummyatk/my-atk-streamable-content.c
@@ -0,0 +1,95 @@
+#include <atk/atk.h>
+
+#include "my-atk-streamable-content.h"
+
+//*************************implementation***********************
+//implementation of virtual functions
+//*****************get_n_mime_types************
+static gint my_atk_streamable_content_get_n_mime_types(
+ AtkStreamableContent *streamable)
+{
+ g_return_val_if_fail(MY_IS_ATK_STREAMABLE_CONTENT(streamable), 0);
+
+ return sizeof(mime_types) / sizeof(mime_types[0]);
+}
+//*****************get_mime_type****************
+static const gchar* my_atk_streamable_content_get_mime_type(
+ AtkStreamableContent *streamable,
+ gint i)
+{
+ g_return_val_if_fail(MY_IS_ATK_STREAMABLE_CONTENT(streamable), NULL);
+
+ if((i < 0) || (i >= sizeof(mime_types) / sizeof(mime_types[0])))
+ {
+ return NULL;
+ }
+ return mime_types[i];
+}
+//**********************get_stream*******************
+static GIOChannel* my_atk_streamable_content_get_stream(
+ AtkStreamableContent *streamable,
+ const gchar* mime_type)
+{
+ gint i;
+ g_return_val_if_fail(MY_IS_ATK_STREAMABLE_CONTENT(streamable), NULL);
+
+ for(i = 0; i < sizeof(mime_types) / sizeof(mime_types[0]); i++)
+ {
+ if(strcmp(mime_type, mime_types[i]) == 0)
+ {
+ GError *error = NULL;
+ gchar* full_filename = T2C_GET_DATA_PATH(file_names[i]);
+ GIOChannel* channel = g_io_channel_new_file(full_filename, "r", &error);
+ if(error != NULL)
+ {
+ TRACE("Cannot open file '%s' for read: %s", full_filename,
+ error->message);
+ g_error_free(error);
+ }
+ g_free(full_filename);
+ return channel;
+ }
+ }
+ return NULL;
+}
+//others functions
+static void my_atk_streamable_content_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ AtkStreamableContentIface *klass = (AtkStreamableContentIface*)g_iface;
+
+ klass->get_n_mime_types = my_atk_streamable_content_get_n_mime_types;
+ klass->get_mime_type = my_atk_streamable_content_get_mime_type;
+ klass->get_stream = my_atk_streamable_content_get_stream;
+}
+
+GType my_atk_streamable_content_get_type()
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof(MyAtkStreamableContentClass),
+ NULL, //base_init
+ NULL, //base_finalize
+ NULL, //class_init
+ NULL, //class_finalize
+ NULL, //class_data
+ sizeof(MyAtkStreamableContent),
+ 0, //n_preallocs
+ NULL //instance_init
+ };
+
+ static const GInterfaceInfo iface_info =
+ {
+ my_atk_streamable_content_interface_init, /* interface_init*/
+ NULL, /* interface_finalize*/
+ NULL /* interface_data */
+ };
+ type = g_type_register_static(G_TYPE_OBJECT, "MyAtkStreamableContent", &typeInfo, 0);
+ g_type_add_interface_static(type,
+ ATK_TYPE_STREAMABLE_CONTENT,
+ &iface_info);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-streamable-content.h b/tests/dummyatk/my-atk-streamable-content.h
new file mode 100644
index 0000000..d8e0a4e
--- /dev/null
+++ b/tests/dummyatk/my-atk-streamable-content.h
@@ -0,0 +1,33 @@
+#ifndef MY_ATK_STREAMABLE_CONTENT_H
+#define MY_ATK_STREAMABLE_CONTENT_H
+
+/*
+ * MyAtkStreamableContent: derives GObject and implements AtkStreamableContent
+ */
+
+#include <atk/atk.h>
+
+#define MY_TYPE_ATK_STREAMABLE_CONTENT (my_atk_streamable_content_get_type ())
+#define MY_ATK_STREAMABLE_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_STREAMABLE_CONTENT, MyAtkStreamableContent))
+#define MY_ATK_STREAMABLE_CONTENT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_STREAMABLE_CONTENT, MyAtkStreamableContentClass))
+#define MY_IS_ATK_STREAMABLE_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_STREAMABLE_CONTENT))
+#define MY_IS_ATK_STREAMABLE_CONTENT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_STREAMABLE_CONTENT))
+#define MY_ATK_STREAMABLE_CONTENT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_STREAMABLE_CONTENT, MyAtkStreamableContentClass))
+
+typedef struct _MyAtkStreamableContent MyAtkStreamableContent;
+typedef struct _MyAtkStreamableContentClass MyAtkStreamableContentClass;
+
+static const gchar* mime_types[]={"text/plain", "text/richtext"};
+static const gchar* file_names[]={"file1", "file2"};
+struct _MyAtkStreamableContent
+{
+ GObject parent;
+};
+
+struct _MyAtkStreamableContentClass
+{
+ GObjectClass parent;
+};
+
+GType my_atk_streamable_content_get_type();
+#endif /*MY_ATK_STREAMABLE_CONTENT_H*/
diff --git a/tests/dummyatk/my-atk-text.c b/tests/dummyatk/my-atk-text.c
new file mode 100644
index 0000000..caee42e
--- /dev/null
+++ b/tests/dummyatk/my-atk-text.c
@@ -0,0 +1,1290 @@
+
+#include <atk/atk.h>
+#include <string.h>
+#include <limits.h>
+#include <useful_functions.h>
+
+#include "my-atk-text.h"
+//*************************implementation***********************
+
+//Attributes
+/*
+ * Auxiliary functions create/copy/print/free structures
+ * Use the same naming principe, as atk, but without 'atk' prefix
+ */
+ //AtkAttribute
+AtkAttribute* attribute_new(const gchar* name, const gchar* value)
+{
+ AtkAttribute* attr = g_malloc(sizeof(AtkAttribute));
+ if(attr == NULL) return NULL;
+ attr->name = g_strdup(name);
+ attr->value = g_strdup(value);
+ return attr;
+}
+AtkAttribute* attribute_copy(AtkAttribute* attr)
+{
+ return attribute_new(attr->name, attr->value);
+}
+void attribute_print(AtkAttribute* attr)
+{
+ TRACE("name=%s, value=%s", attr->name, attr->value);
+}
+
+//AtkAttributeSet
+AtkAttributeSet* attribute_set_copy(AtkAttributeSet* attr)
+{
+ GSList *tmp;
+ AtkAttributeSet* result = g_slist_copy(attr);
+ for(tmp = result; tmp != NULL; tmp = tmp->next)
+ tmp->data = attribute_copy((AtkAttribute*)tmp->data);
+ return result;
+}
+void attribute_set_print(AtkAttributeSet *set)
+{
+ if(set == NULL)
+ TRACE0("(empty)");
+ else
+ g_slist_foreach(set, (GFunc)attribute_print, NULL);
+}
+
+// STATIC FUNCTIONS
+//
+//auxiliary functions for search tokens
+//Number of different characters
+#define TABLE_SIZE 256
+//modificator static isn't used because this tables will be use in tests
+/*static*/ gboolean table_word_symbols[TABLE_SIZE],
+ table_sentence_symbols[TABLE_SIZE],
+ table_line_symbols[TABLE_SIZE];
+static gboolean *tables[7]={NULL,
+ table_word_symbols,
+ table_word_symbols,
+ table_sentence_symbols,
+ table_sentence_symbols,
+ table_line_symbols,
+ table_line_symbols
+ };
+
+static gboolean current_token(const gchar* str, gint offset, gint *token_start, gint *token_end,
+ const gboolean table_token_symbols[TABLE_SIZE])
+{
+ const gchar *current = str + offset;
+ if(!table_token_symbols[(guchar)*current])
+ {
+ return FALSE;
+ }
+ for( --current; (current >= str) && table_token_symbols[(guchar)*current]; --current);
+ *token_start = current - str + 1;
+ for(current = str + offset + 1;
+ (*current != 0) && table_token_symbols[(guchar)*current]; ++current);
+ *token_end = current - str;
+ return TRUE;
+}
+static gboolean next_token(const gchar* str, gint offset, gint *token_start, gint *token_end,
+ const gboolean table_token_symbols[TABLE_SIZE])
+{
+ const gchar *current = str + offset;
+ for( ; (*current != 0) && table_token_symbols[(guchar)*current]; ++current);
+ if(*current == 0)
+ return FALSE;
+ for(++current ; (*current != 0) && !table_token_symbols[(guchar)*current]; ++current);
+ if(!table_token_symbols[(guchar)*current])
+ return FALSE;
+ return current_token(str, current - str, token_start, token_end, table_token_symbols);
+}
+static gboolean previous_token(const gchar* str, gint offset, gint *token_start, gint *token_end,
+ const gboolean table_token_symbols[TABLE_SIZE])
+{
+ const gchar *current = str + offset;
+ for( ; (current > str) && table_token_symbols[(guchar)*current]; --current);
+ if(current == str)
+ return FALSE;
+ for( ; (current > str) && !table_token_symbols[(guchar)*current]; --current);
+ if(!table_token_symbols[(guchar)*current])
+ return FALSE;
+ return current_token(str, current - str, token_start, token_end, table_token_symbols);
+}
+
+
+//Range: type of data, containing in list of attributes
+typedef struct
+{
+ gint start,end;//range, containing this attributes
+ AtkAttributeSet* attributeSet;
+} Range;
+//auxiliary functions for ranges
+Range* range_new(gint start, gint end)
+{
+ Range *range = g_malloc(sizeof(Range));
+ range->start = start;
+ range->end = end;
+ range->attributeSet = NULL;
+ return range;
+}
+
+void range_free(Range* range)
+{
+ atk_attribute_set_free(range->attributeSet);
+ g_free(range);
+}
+void range_print(const Range*range)
+{
+ TRACE("[%d,%d):", range->start, range->end);
+ attribute_set_print(range->attributeSet);
+}
+//only for correct list of ranges - ranges shouldn't intersect
+gint range_compare(const Range* range1, const Range* range2)
+{
+ return range1->start - range2->start;//never equal
+}
+//Bounds of text
+void text_bounds_init(TextBounds *bounds)
+{
+ bounds->base_x = 0;
+ bounds->base_y = 0;
+ bounds->pixels_above_line = 2;
+ bounds->pixels_below_line = 3;
+ bounds->size = 8;
+ bounds->pixels_between_characters = 1;
+ bounds->width = 3;
+}
+
+//auxiliary function - create new range according to start_offset and end_offset
+AtkTextRange* text_range_new(AtkText* text,
+ gint start_offset, gint end_offset, AtkCoordType coord_type)
+{
+ AtkTextRange* range = g_malloc(sizeof(AtkTextRange));
+ if(range == NULL) return NULL;
+ range->start_offset = start_offset;
+ range->end_offset = end_offset;
+ range->content = atk_text_get_text(text, start_offset, end_offset);
+ atk_text_get_range_extents(text, start_offset, end_offset, coord_type, &range->bounds);
+ return range;
+}
+// Returns number of line, which contain given character.
+// Also return relative offset - offset of this character from start of the line
+gint get_character_line(MyAtkText *text, gint offset, gint *relative_offset)
+{
+ gint result = 0;
+ //simple realization - counts lines from start of the text, until reaches offset
+ const guchar *text_str = (guchar*)text->str;
+ gboolean state_FSM = table_line_symbols[text_str[0]];
+ gint i, last_line_start = 0;
+ for(i = 1; i <= offset; state_FSM = table_line_symbols[text_str[i++]])
+ {
+ if(state_FSM)continue;
+ result++;
+ last_line_start = i;
+ }
+ if(relative_offset != NULL) *relative_offset = offset - last_line_start;
+ return result;
+}
+// Compute extent of character,
+// as it was at line 'line' and at offset 'relative_offset' in that line
+//(geometry)
+void get_extents(MyAtkText *text, gint line, gint relative_offset, AtkTextRectangle *rect)
+{
+ rect->x = text->bounds.base_x + relative_offset *
+ (text->bounds.width + text->bounds.pixels_between_characters);
+ rect->y = text->bounds.base_y + text->bounds.pixels_above_line + line *
+ (text->bounds.size + text->bounds.pixels_below_line + text->bounds.pixels_above_line);
+ rect->width = text->bounds.width;
+ rect->height = text->bounds.size;
+}
+//return line, corresponding to given y-coordinate
+gint get_point_line(MyAtkText *text, gint y)
+{
+ //slightly differ from invers operation
+ if(y - text->bounds.base_y < 0)return -1;
+ return (y - text->bounds.base_y)
+ /(text->bounds.size + text->bounds.pixels_below_line + text->bounds.pixels_above_line);
+}
+// Returns offset from left boundary of text, correspondind to x-coordinate
+gint get_point_relative_offset(MyAtkText *text, gint x)
+{
+ //slightly differ from invers operation
+ if(x - text->bounds.base_x < 0)return -1;
+ return (x - text->bounds.base_x)
+ /(text->bounds.width + text->bounds.pixels_between_characters);
+}
+// Returns offset where given line start(even if this line is empty)
+// If line number too small(<0)return -1, if too big - return length of the text
+gint get_offset_at_line_start(MyAtkText *text, gint line)
+{
+ gint i;
+ if(line < 0)return -1;
+ if(line == 0)return 0;
+ gint len = my_strlen(text->str);
+ guchar *str = (guchar*)text->str;
+ gint current_line = 0;
+ gboolean state_FSM = table_line_symbols[str[0]];
+ for(i = 1; i < len; state_FSM = table_line_symbols[str[i++]])
+ {
+ if(state_FSM || ++current_line != line)continue;
+ return i;
+ }
+ return len;
+
+}
+// Return offset of character at the given line and at the given offset at this line
+// If such character doesn't exist, return -1
+gint get_offset_at_line(MyAtkText *text, gint line, gint relative_offset)
+{
+ gint j;
+ if(line < 0 || relative_offset < 0)return -1;
+ const guchar* str = (guchar*)text->str;
+ gint len = my_strlen(text->str);
+ gint offset_at_line_start = get_offset_at_line_start(text, line);
+ if(offset_at_line_start + relative_offset >= len)return -1;
+ for(j = 0; j <= relative_offset; j++)
+ if(!table_line_symbols[str[offset_at_line_start + j]])
+ return -1;
+ return offset_at_line_start + relative_offset;
+}
+/*
+ * Count ranges of text, which clipping by rel_start_offset and relative_end_offset.
+ * 'offset' stands start of search(start of first line),
+ * number_of_lines - maximum number of lines for search.
+ * If 'ranges' not NULL, writes ranges to it. 'coord_type' used only in this case.
+ */
+gint count_ranges(MyAtkText *text, gint offset, gint rel_start_offset, gint rel_end_offset,
+ gint number_of_lines, AtkTextRange** ranges, AtkCoordType coord_type)
+{
+ guchar *str = (guchar*)text->str;
+ gint len = my_strlen(text->str);
+
+ gint number_of_ranges = 0;
+ gint current_line = 0;
+ gint current_line_start = offset;
+ for(;(current_line < number_of_lines) && (current_line_start < len); current_line ++)
+ {
+ if(!table_line_symbols[str[current_line_start]])
+ {
+ current_line_start++;
+ continue;
+ }
+ gint start_offset,end_offset;
+ gchar *tmp_str = atk_text_get_text_at_offset((AtkText*)text, current_line_start,
+ ATK_TEXT_BOUNDARY_LINE_END, &start_offset, &end_offset);
+ g_free(tmp_str);
+ if(end_offset - current_line_start > rel_start_offset)
+ {
+ if(ranges != NULL)
+ {
+ gint range_start_offset = current_line_start + rel_start_offset;
+ gint range_end_offset = current_line_start + rel_end_offset + 1;
+ if(range_end_offset > end_offset)
+ range_end_offset = end_offset;
+ //add element
+ ranges[number_of_ranges] = text_range_new((AtkText*)text,
+ range_start_offset, range_end_offset, coord_type);
+ }
+ number_of_ranges++;
+ }
+ current_line_start = end_offset + 1;
+ }
+ if(ranges != NULL) ranges[number_of_ranges] = NULL;
+ return number_of_ranges;
+}
+
+//"free"-functions(for internal using, because them don't emit signals)
+void my_atk_text_free_run_attributes(MyAtkText *text)
+{
+ g_list_foreach(text->attributes, (GFunc)range_free, NULL);
+ g_list_free(text->attributes);
+ text->attributes = NULL;
+}
+void my_atk_text_free_default_attributes(MyAtkText *text)
+{
+ atk_attribute_set_free(text->default_attributes);
+ text->default_attributes = NULL;
+}
+void my_atk_text_clear_selections(MyAtkText *text)
+{
+ if(text->selections->len != 0)
+ g_array_remove_range(text->selections, 0, text->selections->len);
+}
+void table_symbols_init()
+{
+ //word
+ gint i;
+ for(i = TABLE_SIZE - 1;i > 0 ; --i)
+ table_word_symbols[i] = g_ascii_isalnum(i);
+ table_word_symbols['\0'] = FALSE;
+ //sentence
+ for(i = TABLE_SIZE - 1;i >= 0x20; --i)
+ table_sentence_symbols[i] = TRUE;
+ table_sentence_symbols['.'] = FALSE;
+ table_sentence_symbols['!'] = FALSE;
+ table_sentence_symbols['?'] = FALSE;
+ for(i = 0x1f;i > 0; --i)
+ table_sentence_symbols[i] = FALSE;
+ table_sentence_symbols['\0'] = FALSE;
+ //line
+ for(i = TABLE_SIZE - 1;i > 0 ; --i)
+ table_line_symbols[i] = TRUE;
+ table_line_symbols['\n'] = FALSE;
+ table_line_symbols['\0'] = FALSE;
+}
+void correct_selections_after_insert(MyAtkText *text, gint position, gint length)
+{
+ gint i;
+ GArray* selections = text->selections;
+ for(i = selections->len - 1; i >=0; i--)
+ {
+ TextSelection* sel = &g_array_index(selections, TextSelection, i);
+ if(sel->end_offset >= position) sel->end_offset+= length;
+ if(sel->start_offset >= position) sel->start_offset+= length;
+ else break;
+ }
+}
+void correct_selections_after_delete(MyAtkText *text, gint position, gint length)
+{
+ gint i;
+ GArray* selections = text->selections;
+ for(i = selections->len - 1; i >=0; i--)
+ {
+ TextSelection* sel = &g_array_index(selections, TextSelection, i);
+ if(sel->start_offset >= position)
+ {
+ if(sel->start_offset >= position + length)
+ {
+ sel->start_offset-= length;
+ sel->end_offset-= length;
+ }
+ //position <= sel->start_offset < position + length
+ else if(sel->end_offset > position + length)
+ {
+ sel->start_offset = position;
+ sel->end_offset -= length;
+ }
+ else
+ {
+ g_array_remove_index(selections, i);
+ }
+ continue;
+ }
+ /*sel->start_offset < position*/
+ if(sel->end_offset > position + length) sel->end_offset-= length;
+ else if(sel->end_offset > position) sel->end_offset = position;
+ break;
+ }
+}
+void correct_attributes_after_insert(MyAtkText* text, gint position, gint length)
+{
+ GList *attributes = text->attributes;
+ GList *tmp;
+ //before inserted position
+ for(tmp = attributes; tmp != NULL; tmp = tmp -> next)
+ {
+ Range* range = (Range*)tmp->data;
+ if(range->end <= position)continue;
+ //range->end > position
+ if(range->start < position)
+ range->start -= length;//will be restore in the next loop
+ break;
+ }
+ //after inserted position
+ for(; tmp != NULL; tmp = tmp -> next)
+ {
+ Range* range = (Range*)tmp->data;
+ range->end += length;
+ range->start += length;
+ }
+}
+void correct_attributes_after_delete(MyAtkText* text, gint position, gint length)
+{
+ GList *attributes = text->attributes;
+ GList *tmp = attributes;
+ //before deleting range
+ for(tmp = attributes; tmp != NULL; tmp = tmp->next)
+ {
+ Range* range = (Range*)tmp->data;
+ if(range->end <= position) continue;
+ if(range->start < position)
+ {
+ if(range->end > position + length) range->end -= length;
+ else range->end = position;
+ tmp = tmp->next;
+ }
+ break;
+ }
+ //at deleting range
+ while(tmp != NULL)
+ {
+ Range* range = (Range*)tmp->data;
+ if(range->start >= position + length) break;
+ if(range->end <= position + length)
+ {
+ GList *tmp1 = tmp->next;
+ range_free(range);
+ attributes = g_list_remove_link(attributes, tmp);
+ tmp = tmp1;
+ continue;
+ }
+ //range->end > position + length
+ //range->start < position + length
+ range->start = position + length;//will be restored in next loop
+ break;
+ }
+ //after deleting range
+ for(;tmp != NULL; tmp = tmp->next)
+ {
+ Range* range = (Range*)tmp->data;
+ range->end -= length;
+ range->start -= length;
+ }
+ text->attributes = attributes;
+}
+void correct_caret_after_insert(MyAtkText* text, gint position, gint length)
+{
+ if(text->caret_offset > position)text->caret_offset += length;
+}
+void correct_caret_after_delete(MyAtkText* text, gint position, gint length)
+{
+ if(text->caret_offset >= position + length)text->caret_offset -= length;
+ else if(text->caret_offset > position) text->caret_offset = position;
+}
+
+// Implementation of virtual functions
+//******************************my_atk_text_get_character_count*************************
+static gint my_atk_text_get_character_count(AtkText *text)
+{
+ MyAtkText *self = (MyAtkText*)text;
+ return my_strlen(self->str);
+}
+//**************************************my_atk_text_get_text*****************************
+static gchar* my_atk_text_get_text(AtkText *text, gint start_offset, gint end_offset)
+{
+ gchar *str = ((MyAtkText*)text)->str;
+ if((start_offset < 0) || (end_offset > my_strlen(str)) || (end_offset <= start_offset))
+ {
+ //incorrect bounds
+ return NULL;
+ }
+ return g_strndup(str + start_offset, end_offset - start_offset);
+
+}
+//*******************************my_atk_text_get_character_at_offset************************
+static gunichar my_atk_text_get_character_at_offset(AtkText *text, gint offset)
+{
+ gchar *str = ((MyAtkText*)text)->str;
+ if(offset < 0 || offset >= my_strlen(str))
+ {
+ return 0;
+ }
+ return (gunichar)str[offset];
+}
+// In the next 3 functions some code is commented for verify tests themselves on 'mutants'
+// in realization.
+//******************************my_atk_text_get_text_after_offset***************************
+static gchar* my_atk_text_get_text_after_offset(AtkText *text, gint offset,
+ AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset)
+{
+ gchar *str = ((MyAtkText*)text)->str;
+ gint len = my_strlen(str);
+ if((offset < 0) || (offset >= len))
+ {
+ return NULL;//incorrect offset
+ }
+
+ // This variable is set in switch statement. If after that statement variable is TRUE,
+ // then return text from 'strat_offset' to 'end_offset'. Otherwise NULL will be returned.
+ gboolean is_successed = TRUE;
+
+ gint start_tmp;
+ gint end_tmp;
+
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ if(offset + 1 == len)
+ {
+ is_successed = FALSE;
+ break;
+ }
+ *start_offset = offset + 1;
+ *end_offset = offset + 2;
+ is_successed = TRUE;
+ break;
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ if(!next_token(str, offset, start_offset, &end_tmp, tables[boundary_type]))
+ {
+ //debug
+// if(current_token(str, offset, start_offset, end_offset, tables[boundary_type]))
+// {
+// is_successed = TRUE;
+// break;
+// }
+ is_successed = FALSE;
+ break;
+ }
+ if(!next_token(str, end_tmp, end_offset, &end_tmp, tables[boundary_type]))
+ {
+ *end_offset = len;
+ }
+ is_successed = TRUE;
+ //debug
+// (*start_offset)++;
+// if(*start_offset > 10) ++(*start_offset);
+ break;
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ if(!current_token(str, offset, &start_tmp, start_offset, tables[boundary_type]))
+ {
+ if(!next_token(str, offset, &start_tmp, start_offset, tables[boundary_type]))
+ {
+ is_successed = FALSE;
+ break;
+ }
+ }
+ //debug
+// else if(*start_offset > strlen(str) - 7)
+// {
+// *end_offset = *start_offset + 3;
+// is_successed = TRUE;
+// break;
+// }
+ if(!next_token(str, *start_offset, &start_tmp, end_offset, tables[boundary_type]))
+ {
+ is_successed = FALSE;
+ break;
+ }
+ //debug
+// --(*start_offset);
+ is_successed = TRUE;
+
+ break;
+ default:
+ is_successed = FALSE;
+ }
+
+ if(is_successed)
+ {
+ return my_atk_text_get_text(text, *start_offset, *end_offset);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+//*******************************my_atk_text_get_text_at_offset*******************************
+static gchar* my_atk_text_get_text_at_offset(AtkText *text, gint offset,
+ AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset)
+{
+ gchar *str = ((MyAtkText*)text)->str;
+ gint len = my_strlen(str);
+ if((offset < 0) || (offset >= len))
+ {
+ return NULL;
+ }
+
+ // This variable is set in switch statement. If after that statement variable is TRUE,
+ // then return text from 'strat_offset' to 'end_offset'. Otherwise NULL will be returned.
+ gboolean is_successed = TRUE;
+
+ gint start_tmp;
+ gint end_tmp;
+
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ *start_offset = offset;
+ *end_offset = offset + 1;
+ is_successed = TRUE;
+ break;
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ if(!current_token(str, offset, start_offset, &end_tmp, tables[boundary_type]))
+ {
+ if(!previous_token(str, offset, start_offset, &end_tmp, tables[boundary_type]))
+ {
+ is_successed = FALSE;
+ break;
+ }
+ }
+ if(!next_token(str, offset, end_offset, &end_tmp, tables[boundary_type]))
+ {
+ *end_offset = len;
+ }
+ is_successed = TRUE;
+ break;
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ if(!current_token(str, offset, &start_tmp, end_offset, tables[boundary_type]))
+ {
+ if(!next_token(str, offset, &start_tmp, end_offset, tables[boundary_type]))
+ {
+ is_successed = FALSE;
+ break;
+ }
+ }
+ if(!previous_token(str, start_tmp, &start_tmp, start_offset, tables[boundary_type]))
+ {
+ *start_offset = 0;
+ }
+ is_successed = TRUE;
+ //debug
+// ++(*start_offset);
+ break;
+ default:
+ is_successed = FALSE;
+ }
+
+ if(is_successed)
+ {
+ //debug
+// if(boundary_type == ATK_TEXT_BOUNDARY_LINE_START)
+// return my_atk_text_get_text(text, ++(*start_offset), *end_offset);
+ return my_atk_text_get_text(text, *start_offset, *end_offset);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+//***********************************my_atk_text_get_text_before_offset******************
+static gchar* my_atk_text_get_text_before_offset(AtkText *text, gint offset,
+ AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset)
+{
+ gchar *str = ((MyAtkText*)text)->str;
+ gint len = my_strlen(str);
+ if((offset < 0) || (offset >= len))
+ {
+ return NULL;
+ }
+
+ // This variable is set in switch statement. If after that statement variable is TRUE,
+ // then return text from 'strat_offset' to 'end_offset'. Otherwise NULL will be returned.
+ gboolean is_successed = TRUE;
+
+ gint start_tmp;
+ gint end_tmp;
+
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ if(offset == 0)
+ {
+ is_successed = FALSE;
+ break;
+ }
+ *start_offset = offset - 1;
+ *end_offset = offset;
+ is_successed = TRUE;
+ break;
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ if(!current_token(str, offset, end_offset, &end_tmp, tables[boundary_type]))
+ {
+ if(!previous_token(str, offset, end_offset, &end_tmp, tables[boundary_type]))
+ {
+ is_successed = FALSE;
+ break;
+ }
+ }
+ if(!previous_token(str, *end_offset, start_offset, &end_tmp, tables[boundary_type]))
+ {
+ is_successed = FALSE;
+ break;
+ }
+ is_successed = TRUE;
+ //debug
+// ++(*start_offset);
+ break;
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ if(!previous_token(str, offset, &start_tmp, end_offset, tables[boundary_type]))
+ {
+ is_successed = FALSE;
+ break;
+ }
+ if(!previous_token(str, start_tmp, &start_tmp, start_offset, tables[boundary_type]))
+ {
+ *start_offset = 0;
+ }
+ is_successed = TRUE;
+ break;
+ default:
+ is_successed = FALSE;
+ }
+
+ if(is_successed)
+ {
+ return my_atk_text_get_text(text, *start_offset, *end_offset);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+//*********************************my_atk_text_get_run_attributes*****************
+AtkAttributeSet* my_atk_text_get_run_attributes(AtkText* text, gint offset,
+ gint *start_offset, gint *end_offset)
+{
+ GList *tmp;
+ GList *attributes = ((MyAtkText*)text)->attributes;
+ if(offset < 0 || offset >= my_atk_text_get_character_count(text))
+ {
+ TRACE0("Incorrect value of offset.");
+ return NULL;
+ }
+ gint start = -1, end = -1;
+ for(tmp = attributes; tmp != NULL; tmp = tmp->next)
+ {
+ Range* range = (Range*)(tmp->data);
+ if(range->end <= offset)
+ {
+ start = range->end;
+ continue;
+ }
+ if(range->start > offset)
+ {
+ end = range->start;
+ break;
+ }
+
+ *start_offset = range->start;
+ *end_offset = range->end;
+ return attribute_set_copy(range->attributeSet);
+ }
+ *start_offset = (start == -1) ? 0 : start;
+ *end_offset = (end == -1) ? my_atk_text_get_character_count(text) : end;
+ return NULL;
+}
+//*********************************my_atk_text_get_default_attributes*****************
+AtkAttributeSet* my_atk_text_get_default_attributes(AtkText* text)
+{
+ return attribute_set_copy(((MyAtkText*)text)->default_attributes);
+}
+//*********************************my_atk_text_get_character_extents*****************
+void my_atk_text_get_character_extents(AtkText* text, gint offset, gint *x, gint *y,
+ gint *width, gint *height, AtkCoordType coord_type)
+{
+ AtkTextRectangle result;
+ gint relative_offset, line;
+ line = get_character_line((MyAtkText*)text, offset, &relative_offset);
+ get_extents((MyAtkText*)text, line, relative_offset, &result);
+ *x = result.x;
+ *y = result.y;
+ *width = result.width;
+ *height = result.height;
+}
+//*******************************my_atk_text_get_range_extents************************
+void my_atk_text_get_range_extents(AtkText *text, gint start_offset, gint end_offset,
+ AtkCoordType coord_type, AtkTextRectangle *rect)
+{
+ //simple - union of extents of the characters, contained in this range
+ AtkTextRectangle result, bounds_tmp;
+ gint i;
+
+ atk_text_get_character_extents (text, start_offset,
+ &result.x, &result.y,
+ &result.width, &result.height,
+ coord_type);
+
+ for (i = start_offset + 1; i < end_offset; i++)
+ {
+ my_atk_text_get_character_extents (text, i,&bounds_tmp.x, &bounds_tmp.y,
+ &bounds_tmp.width, &bounds_tmp.height, coord_type);
+
+ if(bounds_tmp.x < result.x)
+ {
+ //corrects left boundary
+ result.width += result.x - bounds_tmp.x;
+ result.x = bounds_tmp.x;
+ }
+ if(bounds_tmp.x + bounds_tmp.width > result.x + result.width)
+ {
+ //corrects right boundary
+ result.width = bounds_tmp.x + bounds_tmp.width - result.x;
+ }
+ if(bounds_tmp.y < result.y)
+ {
+ //corrects top boundary
+ result.height += result.y - bounds_tmp.y;
+ result.y = bounds_tmp.y;
+ }
+ if(bounds_tmp.y + bounds_tmp.height > result.y + result.height)
+ {
+ //corrects buttom boundary
+ result.height = bounds_tmp.y + bounds_tmp.height - result.y;
+ }
+ }
+ *rect = result;
+}
+//**********************************my_atk_text_get_offset_at_point*********************
+gint my_atk_text_get_offset_at_point(AtkText* text, gint x, gint y, AtkCoordType coord_type)
+{
+ gint line, relative_offset;
+
+ line = get_point_line((MyAtkText*)text, y);
+ relative_offset = get_point_relative_offset((MyAtkText*)text, x);
+
+ return get_offset_at_line((MyAtkText*)text, line, relative_offset);
+}
+//*****************************my_atk_text_get_bounded_ranges******************************
+AtkTextRange** my_atk_text_get_bounded_ranges(AtkText *text, AtkTextRectangle *rect,
+ AtkCoordType coord_type, AtkTextClipType x_clip_type, AtkTextClipType y_clip_type)
+{
+ MyAtkText *self = (MyAtkText*)text;
+
+ gint start_line, end_line, start_rel_offset, end_rel_offset;
+ AtkTextRange** result;
+ gint len = my_strlen(self->str);
+//macro for simplify return empty ranges when fail to do smth
+#define RETURN_EMTPY_RANGES {result = g_malloc(sizeof(AtkTextRange*));result[0] = NULL;return result;}
+ //start line
+ start_line = (y_clip_type == ATK_TEXT_CLIP_NONE) || (y_clip_type == ATK_TEXT_CLIP_MAX)
+ ? 0 : get_point_line(self, rect->y);
+ if(start_line < 0) start_line = 0;
+ //end line
+ end_line = (y_clip_type == ATK_TEXT_CLIP_NONE) || (y_clip_type == ATK_TEXT_CLIP_MIN)
+ ? G_MAXINT/2 : get_point_line(self, rect->y + rect->height);
+ if(end_line < 0) RETURN_EMTPY_RANGES;
+ //start relative offset
+ start_rel_offset = (x_clip_type == ATK_TEXT_CLIP_NONE) || (x_clip_type == ATK_TEXT_CLIP_MAX)
+ ? 0 : get_point_relative_offset(self, rect->x);
+ if(start_rel_offset < 0) start_rel_offset = 0;
+ //end relative offset
+ end_rel_offset = (x_clip_type == ATK_TEXT_CLIP_NONE) || (x_clip_type == ATK_TEXT_CLIP_MIN)
+ ? G_MAXINT/2 : get_point_relative_offset(self, rect->x + rect->width);
+ if(end_rel_offset < 0) RETURN_EMTPY_RANGES;
+ //start offset(at the start of 'start_line')
+ gint start_offset = get_offset_at_line_start(self, start_line);
+ if(start_offset + start_rel_offset >= len) RETURN_EMTPY_RANGES;
+
+ //count ranges
+ gint number_of_ranges = count_ranges(self, start_offset,
+ start_rel_offset, end_rel_offset, end_line - start_line + 1, NULL, coord_type);
+ //create array(with just getting size)
+ result = g_malloc(sizeof(AtkTextRange*) * (number_of_ranges + 1));
+ //write ranges
+ count_ranges(self, start_offset,
+ start_rel_offset, end_rel_offset, end_line - start_line + 1, result, coord_type);
+#undef RETURN_EMPTY_RANGES
+ return result;
+}
+
+//********************************my_atk_text_get_n_selections*******************************
+gint my_atk_text_get_n_selections(AtkText *text)
+{
+ MyAtkText *self = (MyAtkText*)text;
+ return self->selections->len;
+}
+
+//********************************my_atk_text_get_selection*******************************
+gchar* my_atk_text_get_selection(AtkText *text,
+ gint selection_num, gint *start_offset, gint *end_offset)
+{
+ MyAtkText *self = (MyAtkText*)text;
+ GArray *selections = self->selections;
+ if(selection_num < 0 || selection_num >= selections->len) return NULL;
+ *start_offset = g_array_index(selections, TextSelection, selection_num).start_offset;
+ *end_offset = g_array_index(selections, TextSelection, selection_num).end_offset;
+ return my_atk_text_get_text(text, *start_offset, *end_offset);
+}
+//********************************my_atk_text_remove_selection*******************************
+gboolean my_atk_text_remove_selection(AtkText *text, gint selection_num)
+{
+ MyAtkText *self = (MyAtkText*)text;
+ GArray *selections = self->selections;
+ if(selection_num < 0 || selection_num >= selections->len) return FALSE;
+ g_array_remove_index(selections, selection_num);
+
+ g_signal_emit_by_name(text, "text-selection-changed");
+ return TRUE;
+}
+//********************************my_atk_text_add_selection*******************************
+gboolean my_atk_text_add_selection(AtkText *text, gint start_offset, gint end_offset)
+{
+ if(start_offset < 0 || end_offset > my_atk_text_get_character_count(text)
+ || start_offset >= end_offset) return FALSE;
+
+ MyAtkText *self = (MyAtkText*)text;
+ GArray *selections = self->selections;
+ gint i;
+ for(i = 0; i < selections->len; i++)
+ {
+ if(g_array_index(selections, TextSelection, i).start_offset >= start_offset)
+ {
+ if(g_array_index(selections, TextSelection, i).start_offset < end_offset)
+ return FALSE;
+ break;
+ }
+ }
+ TextSelection new_selection;
+ new_selection.start_offset = start_offset;
+ new_selection.end_offset = end_offset;
+ g_array_insert_val(selections, i, new_selection);
+
+ g_signal_emit_by_name(text, "text-selection-changed");
+ return TRUE;
+}
+//********************************my_atk_text_set_selection*******************************
+gboolean my_atk_text_set_selection(AtkText *text,
+ gint selection_num, gint start_offset, gint end_offset)
+{
+ MyAtkText *self = (MyAtkText*)text;
+ GArray *selections = self->selections;
+ if(selection_num < 0 || selection_num >= selections->len) return NULL;
+
+ if((selection_num == 0
+ || g_array_index(selections, TextSelection, selection_num - 1).end_offset <= start_offset)
+ && (selection_num == selections->len - 1
+ || g_array_index(selections, TextSelection, selection_num + 1).start_offset >= end_offset)
+ )
+ {
+ //Arrange of selections won't change
+ g_array_index(selections, TextSelection, selection_num).start_offset =
+ start_offset;
+ g_array_index(selections, TextSelection, selection_num).end_offset =
+ end_offset;
+ g_signal_emit_by_name(text, "text-selection-changed");
+ return TRUE;
+ }
+ gint start_offset_old =
+ g_array_index(selections, TextSelection, selection_num).start_offset;
+ gint end_offset_old =
+ g_array_index(selections, TextSelection, selection_num).end_offset;
+
+ my_atk_text_remove_selection(text, selection_num);
+ if(!my_atk_text_add_selection(text, start_offset, end_offset))
+ {
+ //fail when adding selection. Restore initial state.
+ my_atk_text_add_selection(text, start_offset_old, end_offset_old);
+ return FALSE;
+ }
+ g_signal_emit_by_name(text, "text-selection-changed");
+ return TRUE;
+
+}
+
+//************************************my_atk_text_get_caret_offset******************
+gint my_atk_text_get_caret_offset(AtkText *text)
+{
+ MyAtkText *self = (MyAtkText*)text;
+ return self->caret_offset;
+}
+//************************************my_atk_text_set_caret_offset******************
+gboolean my_atk_text_set_caret_offset(AtkText *text, gint offset)
+{
+ MyAtkText *self = (MyAtkText*)text;
+ //caret may be set just after the last character
+ if(offset < 0 || offset > my_atk_text_get_character_count(text))return FALSE;
+ self->caret_offset = offset;
+ g_signal_emit_by_name(self, "text-caret-moved", offset);
+ return TRUE;
+}
+
+//***********************my_atk_text_insert_text*******************************
+void my_atk_text_insert_text(AtkEditableText* text, const gchar* string,
+ gint length, gint *position)
+{
+ gint i;
+ MyAtkText* myAtkText = (MyAtkText*)text;
+ gchar *str = myAtkText->str;
+ gint strlen_old = my_strlen(str);
+
+ if(string == NULL) return;
+ //correct length
+ for(i = 0; i < length; i ++)
+ {
+ if(string[i] == '\0') {length = i; break;}
+ }
+
+ if(*position < 0 || *position > strlen_old || length <= 0 )return;
+
+
+ gchar *new_str = g_malloc(strlen_old + length + 1);
+ if(new_str == NULL)return;
+
+ if(*position != 0)
+ memcpy(new_str, str, (size_t)*position);
+ memcpy(new_str + *position, string, (size_t)length);
+ if(strlen_old != *position)
+ memcpy(new_str + *position + length, str + *position,
+ (size_t)(strlen_old - *position));
+ new_str[strlen_old + length] = '\0';
+
+ g_free(str);
+ myAtkText->str = new_str;
+ correct_selections_after_insert(myAtkText, *position, length);
+ correct_attributes_after_insert(myAtkText, *position, length);
+ correct_caret_after_insert(myAtkText, *position, length);
+ g_signal_emit_by_name(text, "text-changed::insert", *position, length);
+ g_signal_emit_by_name(text, "text-selection-changed");
+ g_signal_emit_by_name(text, "text-attributes-changed");
+ g_signal_emit_by_name(text, "text-caret-moved", myAtkText->caret_offset);
+
+ (*position) += length;
+}
+//*************************my_atk_text_delete_text*******************
+void my_atk_text_delete_text(AtkEditableText* text, gint start_pos, gint end_pos)
+{
+ MyAtkText* myAtkText = (MyAtkText*)text;
+ gchar *str = myAtkText->str;
+ gint strlen_old = my_strlen(str);
+
+ if(start_pos < 0 || end_pos > strlen_old || start_pos >= end_pos )return;
+ if(strlen_old != end_pos)
+ memmove(str + start_pos, str + end_pos, strlen_old - end_pos);
+ str[start_pos - end_pos + strlen_old] = '\0';
+
+ correct_selections_after_delete(myAtkText, start_pos, end_pos - start_pos);
+ correct_attributes_after_delete(myAtkText, start_pos, end_pos - start_pos);
+ correct_caret_after_delete(myAtkText, start_pos, end_pos - start_pos);
+ g_signal_emit_by_name(text, "text-changed::delete", start_pos, end_pos - start_pos);
+ g_signal_emit_by_name(text, "text-selection-changed");
+ g_signal_emit_by_name(text, "text-attributes-changed");
+ g_signal_emit_by_name(text, "text-caret-moved", myAtkText->caret_offset);
+}
+//***********************my_atk_text_set_text_contents*************************
+void my_atk_text_set_text_contents(AtkEditableText* text, const gchar* string)
+{
+ my_atk_text_delete_text(text, 0, my_atk_text_get_character_count((AtkText*)text));
+ gint position = 0;
+ my_atk_text_insert_text(text, string, my_strlen(string), &position);
+}
+//**********************my_atk_text_copy_text***************************
+void my_atk_text_copy_text(AtkEditableText* text, gint start_pos, gint end_pos)
+{
+ MyAtkText* myAtkText = (MyAtkText*)text;
+ const gchar *str = myAtkText->str;
+ gint strlen_old = my_strlen(str);
+ if(start_pos < 0 || end_pos > strlen_old || start_pos >= end_pos )return;
+
+ MyAtkTextClass *parent = MY_ATK_TEXT_GET_CLASS(text);
+ g_free(parent->clipboard);
+ /*parent->clipboard = g_malloc(end_pos - start_pos + 1);
+
+ strncpy(parent->clipboard, str + start_pos, end_pos - start_pos);
+ parent->clipboard[end_pos - start_pos] = '\0';*/
+ parent->clipboard = g_strndup(str + start_pos, end_pos - start_pos);
+}
+//**********************my_atk_text_paste_text***************************
+void my_atk_text_paste_text(AtkEditableText *text, gint position)
+{
+ //NULL-clipboard process corretly
+ MyAtkTextClass* parent = MY_ATK_TEXT_GET_CLASS(text);
+ my_atk_text_insert_text(text, parent->clipboard, my_strlen(parent->clipboard), &position);
+}
+//**********************my_atk_text_cut_text***************************
+void my_atk_text_cut_text(AtkEditableText* text, gint start_pos, gint end_pos)
+{
+ my_atk_text_copy_text(text, start_pos, end_pos);
+ my_atk_text_delete_text(text, start_pos, end_pos);
+}
+//*********************my_atk_text_set_run_attributes************************
+gboolean my_atk_text_set_run_attributes(AtkEditableText* text, AtkAttributeSet* attrib_set,
+ gint start_offset, gint end_offset)
+{
+ MyAtkText* self = (MyAtkText*)text;
+ gint len = atk_text_get_character_count((AtkText*)text);
+ if(start_offset < 0 || start_offset >= end_offset || end_offset > len)
+ return FALSE;
+ GList *attributes = self->attributes;
+ GList *tmp = attributes;
+
+ while(tmp != NULL)
+ {
+ Range *range = (Range*)tmp->data;
+ if(range->start < start_offset)
+ {
+ if(range->end <= end_offset)
+ {
+ if(range->end > start_offset) range->end = start_offset;
+ tmp = tmp->next;
+ continue;
+ }
+ /*range->end > end_offset*/
+ Range* additional_range = range_new(end_offset, range->end);
+ additional_range->attributeSet = attribute_set_copy(range->attributeSet);
+ range->end = start_offset;
+ attributes = g_list_insert_before(attributes, tmp->next, additional_range);
+ tmp = tmp->next;
+ break;
+ }
+ else/*range->start >= start_offset*/
+ {
+ if(range->end <= end_offset)
+ {
+ GList *tmp1 = tmp->next;
+ attributes = g_list_remove_link(attributes, tmp);
+ tmp = tmp1;
+ continue;
+ }
+ /*range->end > end_offset*/
+ if(range->start < end_offset) range->start = end_offset;
+ break;
+ }
+ }
+ Range *new_range = range_new(start_offset, end_offset);
+ new_range->attributeSet = attribute_set_copy(attrib_set);
+ if(tmp == NULL)attributes = g_list_append(attributes, new_range);
+ else attributes = g_list_insert_before(attributes, tmp, new_range);
+
+ self->attributes = attributes;
+ g_signal_emit_by_name(self, "text_attributes_changed");
+ return TRUE;
+}
+
+//others functions
+//sets default attributes
+void my_atk_text_set_default_attributes(MyAtkText* text, AtkAttributeSet *set)
+{
+ atk_attribute_set_free(text->default_attributes);
+ text->default_attributes = attribute_set_copy(set);
+ g_signal_emit_by_name(text, "text-attributes-changed");
+}
+
+void my_atk_text_print_run_attributes(MyAtkText *text)
+{
+ g_list_foreach(text->attributes, (GFunc)range_print, NULL);
+}
+void my_atk_text_print_default_attributes(MyAtkText *text)
+{
+ attribute_set_print(text->default_attributes);
+}
+//need for separate testing interfaces
+void auxiliary_atk_text_set_text_contents(MyAtkText* text, const gchar* string)
+{
+ my_atk_text_set_text_contents((AtkEditableText*)text, string);
+}
+void auxiliary_atk_text_set_run_attributes(MyAtkText* text, AtkAttributeSet* attrib_set,
+ gint start_offset, gint end_offset)
+{
+ my_atk_text_set_run_attributes((AtkEditableText*)text, attrib_set, start_offset, end_offset);
+}
+
+//initialize/finalize functions
+static void my_atk_text_instance_init(GTypeInstance *obj, gpointer g_class)
+{
+ MyAtkText *self = (MyAtkText*)obj;
+
+ self->str = NULL;
+ self->attributes = NULL;
+ self->default_attributes = NULL;
+ text_bounds_init(&self->bounds);
+
+ self->selections = g_array_new(FALSE, FALSE, sizeof(TextSelection));
+
+ self->caret_offset = 0;
+}
+static void my_atk_text_instance_finalize(GObject* obj)
+{
+ MyAtkText *self = (MyAtkText*)obj;
+ g_free(self->str);
+ my_atk_text_free_run_attributes(self);
+ my_atk_text_free_default_attributes(self);
+ if(self->selections != NULL)g_array_free(self->selections, FALSE);
+}
+
+static void my_atk_text_class_init(gpointer g_class, gpointer class_data)
+{
+ GObjectClass* g_object_class = (GObjectClass*)g_class;
+ //GObject virtual table
+ g_object_class->finalize = my_atk_text_instance_finalize;
+ //Fills tables of symbols
+ table_symbols_init();
+ //initialize clipboard
+ ((MyAtkTextClass*)g_class)->clipboard = NULL;
+}
+//Because of static registration of type, finalization function will never been called
+//And glib prints warning if use it in registration.
+/*static void my_atk_text_class_finalize(gpointer g_class, gpointer class_data)
+{
+ MyAtkTextClass *self = (MyAtkTextClass*)g_class;
+
+ g_free(self->clipboard);
+ self->clipboard = NULL;
+}*/
+void my_atk_text_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ AtkTextIface *klass = (AtkTextIface*)g_iface;
+ //"get_text"
+ klass->get_character_count = my_atk_text_get_character_count;
+ klass->get_text = my_atk_text_get_text;
+ klass->get_character_at_offset = my_atk_text_get_character_at_offset;
+ klass->get_text_after_offset = my_atk_text_get_text_after_offset;
+ klass->get_text_at_offset = my_atk_text_get_text_at_offset;
+ klass->get_text_before_offset = my_atk_text_get_text_before_offset;
+ //"attributes"
+ klass->get_run_attributes = my_atk_text_get_run_attributes;
+ klass->get_default_attributes = my_atk_text_get_default_attributes;
+ //"bounds"
+ klass->get_character_extents = my_atk_text_get_character_extents;
+ klass->get_range_extents = my_atk_text_get_range_extents;
+ klass->get_offset_at_point = my_atk_text_get_offset_at_point;
+ klass->get_bounded_ranges = my_atk_text_get_bounded_ranges;
+ //"selection"
+ klass->get_n_selections = my_atk_text_get_n_selections;
+ klass->get_selection = my_atk_text_get_selection;
+ klass->remove_selection = my_atk_text_remove_selection;
+ klass->add_selection = my_atk_text_add_selection;
+ klass->set_selection = my_atk_text_set_selection;
+ //"caret"
+ klass->get_caret_offset = my_atk_text_get_caret_offset;
+ klass->set_caret_offset = my_atk_text_set_caret_offset;
+}
+
+static void my_atk_editable_text_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ AtkEditableTextIface *klass = (AtkEditableTextIface*)g_iface;
+
+ klass->set_text_contents = my_atk_text_set_text_contents;
+ klass->set_run_attributes = my_atk_text_set_run_attributes;
+ klass->copy_text = my_atk_text_copy_text;
+ klass->insert_text = my_atk_text_insert_text;
+ klass->paste_text = my_atk_text_paste_text;
+ klass->cut_text = my_atk_text_cut_text;
+ klass->delete_text = my_atk_text_delete_text;
+}
+GType my_atk_text_get_type()
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof(MyAtkTextClass),
+ NULL, //base_init
+ NULL, //base_finalize
+ my_atk_text_class_init, //class_init
+ NULL, //class_finalize
+ NULL, //class_data
+ sizeof(MyAtkText),
+ 0, //n_preallocs
+ my_atk_text_instance_init //instance_init
+ };
+
+ static const GInterfaceInfo AtkTextIface_info =
+ {
+ my_atk_text_interface_init, /* interface_init*/
+ NULL, /* interface_finalize*/
+ NULL /* interface_data */
+ };
+ static const GInterfaceInfo AtkEditableTextIface_info =
+ {
+ my_atk_editable_text_interface_init,/* interface_init*/
+ NULL, /* interface_finalize*/
+ NULL /* interface_data */
+ };
+ type = g_type_register_static(ATK_TYPE_OBJECT, "MyAtkText", &typeInfo, 0);
+ g_type_add_interface_static(type,
+ ATK_TYPE_TEXT,
+ &AtkTextIface_info);
+
+ g_type_add_interface_static(type,
+ ATK_TYPE_EDITABLE_TEXT,
+ &AtkEditableTextIface_info);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-text.h b/tests/dummyatk/my-atk-text.h
new file mode 100644
index 0000000..158e5db
--- /dev/null
+++ b/tests/dummyatk/my-atk-text.h
@@ -0,0 +1,58 @@
+#ifndef MY_ATK_TEXT_H
+#define MY_ATK_TEXT_H
+/*
+ * MyAtkText: implements AtkText and AtkEditableText
+ */
+#include <atk/atk.h>
+
+#define MY_TYPE_ATK_TEXT (my_atk_text_get_type ())
+#define MY_ATK_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_TEXT, MyAtkText))
+#define MY_ATK_TEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_TEXT, MyAtkTextClass))
+#define MY_IS_ATK_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_TEXT))
+#define MY_IS_ATK_TEXT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_TEXT))
+#define MY_ATK_TEXT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_TEXT, MyAtkTextClass))
+
+typedef struct _MyAtkText MyAtkText;
+typedef struct _MyAtkTextClass MyAtkTextClass;
+
+//Struct, describing bounds of one selection.
+typedef struct
+{
+ gint start_offset, end_offset;
+}TextSelection;
+//Struct, describing values, needed for determine extent of characters
+typedef struct
+{
+ gint base_x, base_y;//coordinates of the top-left corner of text
+ gint pixels_above_line;
+ gint pixels_below_line;
+ gint size;//size of the character(height in pixels)
+ gint pixels_between_characters;//monoscaped font
+ gint width;//width of character
+}TextBounds;
+
+struct _MyAtkText
+{
+ AtkObject parent;
+
+ gchar* str;//string, containing text
+ GList* attributes;//running atributes
+ AtkAttributeSet *default_attributes;//default attributes
+
+ TextBounds bounds;
+
+ GArray* selections;
+
+ gint caret_offset;
+};
+
+struct _MyAtkTextClass
+{
+ AtkObjectClass parent;
+ gchar* clipboard;
+};
+
+GType my_atk_text_get_type();
+
+void my_atk_text_interface_init(gpointer g_iface, gpointer iface_data);
+#endif /*MY_ATK_TEXT_H*/
diff --git a/tests/dummyatk/my-atk-value.c b/tests/dummyatk/my-atk-value.c
new file mode 100644
index 0000000..d94bd71
--- /dev/null
+++ b/tests/dummyatk/my-atk-value.c
@@ -0,0 +1,112 @@
+#include <atk/atk.h>
+#include <limits.h>
+
+#include "my-atk-value.h"
+
+//*************************implementation***********************
+//implementation of virtual functions
+//******************get_current_value*******************
+static void my_atk_value_get_current_value(AtkValue *obj, GValue *value)
+{
+ g_return_if_fail(MY_IS_ATK_VALUE(obj));
+ MyAtkValue* self = (MyAtkValue*)obj;
+
+ g_value_init(value, G_TYPE_INT);
+ g_value_set_int(value, self->current);
+}
+//******************get_maximum_value*******************
+static void my_atk_value_get_maximum_value(AtkValue *obj, GValue *value)
+{
+ g_return_if_fail(MY_IS_ATK_VALUE(obj));
+ MyAtkValue* self = (MyAtkValue*)obj;
+
+ g_value_init(value, G_TYPE_INT);
+ g_value_set_int(value, self->maximum);
+}
+//******************get_minimum_value*******************
+static void my_atk_value_get_minimum_value(AtkValue *obj, GValue *value)
+{
+ g_return_if_fail(MY_IS_ATK_VALUE(obj));
+ MyAtkValue* self = (MyAtkValue*)obj;
+
+ g_value_init(value, G_TYPE_INT);
+ g_value_set_int(value, self->minimum);
+}
+//******************set_current_value*******************
+static gboolean my_atk_value_set_current_value(AtkValue *obj, const GValue *value)
+{
+ g_return_val_if_fail(MY_IS_ATK_VALUE(obj), FALSE);
+ MyAtkValue* self = (MyAtkValue*)obj;
+
+ if(self->readonly) return FALSE;
+
+ gint new_value = g_value_get_int(value);
+ if(new_value < self->minimum || new_value > self->maximum) return FALSE;
+
+ self->current = new_value;
+ return TRUE;
+}
+
+//others
+MyAtkValue* my_atk_value_new(gint minimum, gint maximum, gint current)
+{
+ MyAtkValue* result = g_object_new(MY_TYPE_ATK_VALUE, NULL);
+ if(result == NULL) return NULL;
+ result->minimum = minimum;
+ result->maximum = maximum;
+ result->current = current;
+
+ return result;
+}
+static void my_atk_value_instance_init(GTypeInstance *obj, gpointer g_class)
+{
+ MyAtkValue *self = (MyAtkValue*)obj;
+
+ self->minimum = 0;
+ self->maximum = 0;
+ self->current = 0;
+
+ self->readonly = FALSE;
+}
+static void my_atk_value_interface_init(gpointer g_iface, gpointer iface_data)
+{
+ AtkValueIface *klass = (AtkValueIface*)g_iface;
+
+ klass->get_current_value = my_atk_value_get_current_value;
+ klass->get_minimum_value = my_atk_value_get_minimum_value;
+ klass->get_maximum_value = my_atk_value_get_maximum_value;
+
+ klass->set_current_value = my_atk_value_set_current_value;
+}
+
+GType my_atk_value_get_type()
+{
+ static GType type = 0;
+ if(type == 0)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof(MyAtkValueClass),
+ NULL, //base_init
+ NULL, //base_finalize
+ NULL, //class_init
+ NULL, //class_finalize
+ NULL, //class_data
+ sizeof(MyAtkValue),
+ 0, //n_preallocs
+ my_atk_value_instance_init //instance_init
+ };
+
+ static const GInterfaceInfo iface_info =
+ {
+ my_atk_value_interface_init, /* interface_init*/
+ NULL, /* interface_finalize*/
+ NULL /* interface_data */
+ };
+ type = g_type_register_static(ATK_TYPE_OBJECT, "MyAtkValue", &typeInfo, 0);
+ g_type_add_interface_static(type,
+ ATK_TYPE_VALUE,
+ &iface_info);
+ }
+ return type;
+}
diff --git a/tests/dummyatk/my-atk-value.h b/tests/dummyatk/my-atk-value.h
new file mode 100644
index 0000000..9e989fb
--- /dev/null
+++ b/tests/dummyatk/my-atk-value.h
@@ -0,0 +1,34 @@
+#ifndef MY_ATK_VALUE_H
+#define MY_ATK_VALUE_H
+/*
+ * MyAtkValue: derives AtkObject
+ * and implements AtkValue
+ */
+#include <atk/atk.h>
+
+#define MY_TYPE_ATK_VALUE (my_atk_value_get_type ())
+#define MY_ATK_VALUE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_ATK_VALUE, MyAtkValue))
+#define MY_ATK_VALUE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MY_TYPE_ATK_VALUE, MyAtkValueClass))
+#define MY_IS_ATK_VALUE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_ATK_VALUE))
+#define MY_IS_ATK_VALUE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MY_TYPE_ATK_VALUE))
+#define MY_ATK_VALUE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MY_TYPE_ATK_VALUE, MyAtkValueClass))
+
+typedef struct _MyAtkValue MyAtkValue;
+typedef struct _MyAtkValueClass MyAtkValueClass;
+
+struct _MyAtkValue
+{
+ AtkObject parent;
+
+ gint minimum, maximum, current;
+ gboolean readonly;
+};
+
+struct _MyAtkValueClass
+{
+ AtkObjectClass parent;
+};
+
+MyAtkValue* my_atk_value_new(gint minimum, gint maximium, gint current);
+GType my_atk_value_get_type();
+#endif /*MY_ATK_VALUE_H*/
diff --git a/tests/dummyatk/my-atk.h b/tests/dummyatk/my-atk.h
new file mode 100644
index 0000000..935d3d8
--- /dev/null
+++ b/tests/dummyatk/my-atk.h
@@ -0,0 +1,14 @@
+#ifndef MY_ATK_H
+#define MY_ATK_H
+
+#include <my-atk-action.h>
+#include <my-atk-component.h>
+#include <my-atk.h>
+#include <my-atk-hyperlink.h>
+#include <my-atk-hypertext.h>
+#include <my-atk-object.h>
+#include <my-atk-streamable-content.h>
+#include <my-atk-text.h>
+#include <my-atk-value.h>
+
+#endif /*MY_ATK_H*/
diff --git a/tests/dummyatk/resources_storage.c b/tests/dummyatk/resources_storage.c
new file mode 100644
index 0000000..e86051d
--- /dev/null
+++ b/tests/dummyatk/resources_storage.c
@@ -0,0 +1,34 @@
+#include <atk/atk.h>
+
+GHashTable* resources = NULL;
+
+void resource_storage_init()
+{
+ if(resources == NULL)
+ resources = g_hash_table_new_full(g_str_hash, g_str_equal,
+ (GDestroyNotify)g_free, (GDestroyNotify)g_object_unref);
+}
+
+void resource_storage_free()
+{
+ if(resources == NULL) return;
+ g_hash_table_destroy(resources);
+ resources = NULL;
+}
+
+void resource_storage_add(const gchar* name, AtkObject* resource)
+{
+ if(resources == NULL) return;
+ g_hash_table_insert(resources, g_strdup(name), g_object_ref(resource));
+}
+
+AtkObject* resource_storage_get(const gchar* name)
+{
+ if(resources == NULL) return NULL;
+ return g_hash_table_lookup(resources, name);
+}
+void resources_storage_remove(const gchar* name)
+{
+ if(resources == NULL) return;
+ g_hash_table_remove(resources, name);
+}
diff --git a/tests/dummyatk/resources_storage.h b/tests/dummyatk/resources_storage.h
new file mode 100644
index 0000000..3decd86
--- /dev/null
+++ b/tests/dummyatk/resources_storage.h
@@ -0,0 +1,16 @@
+#ifndef RESOURCES_STORAGE_H
+#define RESOURCES_STORAGE_H
+
+#include <glib.h>
+
+void resource_storage_init();
+
+void resource_storage_free();
+
+void resource_storage_add(const gchar* name, AtkObject* resource);
+
+AtkObject* resource_storage_get(const gchar* name);
+
+void resources_storage_remove(const gchar* name);
+
+#endif /*RESOURCES_STORAGE_H*/
diff --git a/tests/dummyatk/useful_functions.c b/tests/dummyatk/useful_functions.c
new file mode 100644
index 0000000..49b6a82
--- /dev/null
+++ b/tests/dummyatk/useful_functions.c
@@ -0,0 +1,29 @@
+#include <string.h>
+#include <glib.h>
+/*
+ * Functions and macros widely used in the tests.
+ */
+
+//same as strcmp() == 0 but works properly for NULL pointers
+gboolean my_strcmp(const gchar* str1, const gchar* str2)
+{
+ if(str1 == str2) return TRUE;
+ if(str1 == NULL || str2 == NULL) return FALSE;
+
+ return strcmp(str1,str2) == 0;
+}
+//same as strlen but works properly for NULL pointer and returns gint instead of guint
+gint my_strlen(const gchar* str)
+{
+ if(str == NULL)return 0;
+ return (gint)strlen(str);
+}
+//same as strncmp() == 0 but works properly for NULL pointers
+gboolean my_strncmp(const gchar* str1, const gchar* str2, gint n)
+{
+ if(n <= 0)return TRUE;
+ if(str1 == str2)return TRUE;
+ if(str1 == NULL || str2 == NULL)return FALSE;
+
+ return strncmp(str1, str2, n) == 0;
+}
diff --git a/tests/dummyatk/useful_functions.h b/tests/dummyatk/useful_functions.h
new file mode 100644
index 0000000..4fbce6c
--- /dev/null
+++ b/tests/dummyatk/useful_functions.h
@@ -0,0 +1,30 @@
+#ifndef USEFUL_FUNCTIONS_H
+#define USEFUL_FUNCTIONS_H
+/*
+ * Functions and macros widely used in the tests.
+ */
+
+//macro for creating objects in startup section
+#define OBJECT_NEW(obj, type, type_str) obj = g_object_new(type,NULL);\
+ if(obj == NULL)\
+ {\
+ INIT_FAILED("Cannot create instance of type" type_str ".\n");\
+ }
+//macro for destroying object
+#define OBJECT_UNREF(obj) if(obj != NULL)\
+ {\
+ g_object_unref((gpointer)obj);\
+ }
+//for testing signals
+#define HANDLER_DISCONNECT(obj, h) if((h) != 0)\
+ {\
+ g_signal_handler_disconnect(obj, h);\
+ }
+
+gboolean my_strcmp(const gchar* str1, const gchar* str2);
+
+gint my_strlen(const gchar* str);
+
+gboolean my_strncmp(const gchar* str1, const gchar* str2, gint n);
+
+#endif /*USEFUL_FUNCTIONS_H*/
diff --git a/tests/dummyatk/user_marshal.c b/tests/dummyatk/user_marshal.c
new file mode 100644
index 0000000..1f8ecf0
--- /dev/null
+++ b/tests/dummyatk/user_marshal.c
@@ -0,0 +1,41 @@
+#include <glib-object.h>
+
+/* INT:BOXED (marshal.list:1) */
+void
+g_cclosure_user_marshal_INT__BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef gint (*GMarshalFunc_INT__BOXED) (gpointer data1,
+ gpointer arg_1,
+ gpointer data2);
+ register GMarshalFunc_INT__BOXED callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gint v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_INT__BOXED) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ data2);
+
+ g_value_set_int (return_value, v_return);
+}
+
diff --git a/tests/dummyatk/user_marshal.h b/tests/dummyatk/user_marshal.h
new file mode 100644
index 0000000..a845925
--- /dev/null
+++ b/tests/dummyatk/user_marshal.h
@@ -0,0 +1,60 @@
+#ifndef USER_MARSHAL_H
+#define USER_MARSHAL_H
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+void
+g_cclosure_user_marshal_INT__BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+#endif /*USER_MARSHAL_H*/
diff --git a/tests/testapps/Makefile.am b/tests/testapps/Makefile.am
new file mode 100644
index 0000000..a37699c
--- /dev/null
+++ b/tests/testapps/Makefile.am
@@ -0,0 +1,28 @@
+check_PROGRAMS = test-application
+check_LTLIBRARIES = libnoopapp.la libobjectapp.la
+
+test_application_CFLAGS = $(DBUS_GLIB_CFLAGS) \
+ $(ATK_CFLAGS) \
+ $(GMODULE_CFLAGS) \
+ -I$(top_srcdir)
+
+test_application_LDADD = $(DBUS_GLIB_LIBS) \
+ $(GMODULE_LIBS) \
+ $(ATK_LIBS)
+
+test_application_SOURCES = test-application.c
+
+
+TEST_APP_CFLAGS = $(ATK_CFLAGS) $(GMODULE_CFLAGS) -I$(top_srcdir) -I$(top_srcdir)/tests/dummyatk/
+TEST_APP_LDFLAGS = -no-undefined -module -avoid-version -rpath /a/fake/path
+TEST_APP_LIBADD = $(ATK_LIBS) $(GMODULE_LIBS) $(top_builddir)/tests/dummyatk/libdummyatk.la
+
+libnoopapp_la_CFLAGS = $(TEST_APP_CFLAGS)
+libnoopapp_la_LDFLAGS = $(TEST_APP_LDFLAGS)
+libnoopapp_la_LIBADD = $(TEST_APP_LIBADD)
+libnoopapp_la_SOURCES = noop-app.c
+
+libobjectapp_la_CFLAGS = $(TEST_APP_CFLAGS)
+libobjectapp_la_LDFLAGS = $(TEST_APP_LDFLAGS)
+libobjectapp_la_LIBADD = $(TEST_APP_LIBADD)
+libobjectapp_la_SOURCES = object-app.c
diff --git a/tests/testapps/noop-app.c b/tests/testapps/noop-app.c
new file mode 100644
index 0000000..7b997cc
--- /dev/null
+++ b/tests/testapps/noop-app.c
@@ -0,0 +1,14 @@
+#include <gmodule.h>
+#include <atk/atk.h>
+
+G_MODULE_EXPORT void
+test_init (void)
+{
+ ;
+}
+
+G_MODULE_EXPORT AtkObject *
+test_get_root (void)
+{
+ return NULL;
+}
diff --git a/tests/testapps/object-app.c b/tests/testapps/object-app.c
new file mode 100644
index 0000000..85d4f2c
--- /dev/null
+++ b/tests/testapps/object-app.c
@@ -0,0 +1,21 @@
+#include <gmodule.h>
+#include <atk/atk.h>
+#include <my-atk.h>
+
+static AtkObject *root_accessible;
+
+G_MODULE_EXPORT void
+test_init (void)
+{
+ root_accessible = (AtkObject *) g_object_new(MY_TYPE_ATK_OBJECT, NULL);
+
+ atk_object_set_name(root_accessible, "Root Accessible");
+ atk_object_set_role(root_accessible, ATK_ROLE_ACCEL_LABEL);
+ atk_object_set_description(root_accessible, "A root object for the test tree");
+}
+
+G_MODULE_EXPORT AtkObject *
+test_get_root (void)
+{
+ return root_accessible;
+}
diff --git a/tests/testapps/test-application.c b/tests/testapps/test-application.c
new file mode 100644
index 0000000..a499584
--- /dev/null
+++ b/tests/testapps/test-application.c
@@ -0,0 +1,146 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Testing AT-SPI requires both a test application and AT client.
+ * Test applications are built using the Dummy ATK implementation: MyAtk.
+ * This file contains the entry point for all test applications.
+ * Each test is built as a GModule, and this program loads the
+ * test module, as well as the AT-SPI module. The test module will
+ * provide its own implementation of atk_get_root, and as such provide
+ * all the application state for the test.
+ */
+
+#include <glib.h>
+#include <gmodule.h>
+#include <atk/atk.h>
+#include <dbus/dbus.h>
+
+/* The test module, GModule containing interface for an atk-test */
+static GModule *test_module;
+static gpointer test_module_get_root;
+
+/* Test module interface */
+/*************************/
+
+typedef AtkObject *(*TestModuleGetRoot) (void);
+
+/* Calls into the test module to get the root atk object */
+static AtkObject *
+get_root(void)
+{
+ return ((TestModuleGetRoot) test_module_get_root)();
+}
+
+/*************************/
+
+/* The AtkUtil class is called to find the root accessible and to deal
+ * with events. Its an incomplete class, its v-table needs to be filled in.
+ */
+static void
+setup_atk_util(void)
+{
+ AtkUtilClass *klass;
+
+ klass = g_type_class_ref(ATK_TYPE_UTIL);
+ klass->get_root = get_root;
+ g_type_class_unref(klass);
+}
+
+typedef void (*GtkModuleInit) (int argc, char *argv[]);
+
+/* AT-SPI is a gtk module that must be loaded and initialized */
+static void
+load_atspi_module(const char *path, int argc, char *argv[])
+{
+ GModule *bridge;
+ gpointer init;
+
+ bridge = g_module_open(path, G_MODULE_BIND_LOCAL|G_MODULE_BIND_LAZY);
+ if (!bridge)
+ g_error("Couldn't load atk-bridge module : %s\n", path);
+
+ if (!g_module_symbol(bridge, "gtk_module_init", &init))
+ g_error("Couldn't load symbol \"gtk_module_init\"\n");
+
+ ((GtkModuleInit) init)(argc, argv);
+}
+
+static void
+load_test_module(const char *path, int argc, char *argv[])
+{
+ gpointer init;
+
+ test_module = g_module_open(path, G_MODULE_BIND_LOCAL|G_MODULE_BIND_LAZY);
+ if (!test_module)
+ g_error("Couldn't load test module : %s\n", path);
+
+ if (!g_module_symbol(test_module, "test_init", &init))
+ g_error("Couldn't load symbol \"test_init\"\n");
+
+ if (!g_module_symbol(test_module, "test_get_root", &test_module_get_root))
+ g_error("Couldn't load symbol \"test_get_root\"\n");
+
+ ((GtkModuleInit) init)(argc, argv);
+}
+
+/*Command line data*/
+static gchar *tmodule_path;
+static gchar *amodule_path;
+
+static GOptionEntry optentries[] =
+{
+ {"test-module", 't', 0, G_OPTION_ARG_STRING, &tmodule_path, "Module containing test scenario", NULL},
+ {"atspi-module", 'a', 0, G_OPTION_ARG_STRING, &amodule_path, "Gtk module with atk-atspi adaptor", NULL},
+ {NULL}
+};
+
+/* main
+ *
+ * Entry point for all test applications.
+ */
+main(int argc, char *argv[])
+{
+ GMainLoop *mainloop;
+ GOptionContext *opt;
+ GError *err = NULL;
+
+ /*Parse command options*/
+ opt = g_option_context_new(NULL);
+ g_option_context_add_main_entries(opt, optentries, NULL);
+ if (!g_option_context_parse(opt, &argc, &argv, &err))
+ {
+ g_print("Option parsing failed: %s\n", err->message);
+ exit(1);
+ }
+
+ g_type_init();
+
+ setup_atk_util();
+ load_test_module(tmodule_path, argc, argv);
+ load_atspi_module(amodule_path, argc, argv);
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (mainloop);
+
+ return 0;
+}