Re: [g-a-devel] Interfacing a non-GTK application with AT-SPI



On Mon, 2006-12-18 at 11:22 -0500, Rodney Dawes wrote:
> Are these straight GObjects that don't require a display? I had a
> thought this past week, about writing some regression tests for LDTP
> itself, to make sure that all the bits of the protocol between the
> client/server portions are still working, and all that. Ideally, this
> would not require an X display. If what you've done is along those
> lines, it might be a good place for us to start.

Here is my prototype app - I hope you find it useful. It includes some
hacks but served as a good introduction to Atk, and it does work
(registers a button which you can click through dogtail's at-spi
browser).

Run with:
	GTK_MODULES=atk-bridge ./main


-- 
Daniel Drake
Brontes Technologies, A 3M Company
#include <gtk/gtk.h>

GType acsample_widget_get_type();
GType acsample_accessible_factory_get_type();
GType acsample_accessible_get_type();

/***** CUSTOM WIDGET TYPE *****/

#define ACSAMPLE_WIDGET_TYPE (acsample_widget_get_type())
#define ACSAMPLE_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), ACSAMPLE_WIDGET_TYPE))
#define ACSAMPLE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), ACSAMPLE_WIDGET_TYPE, AcsampleWidget))

typedef struct
{
	GObject parent;
} AcsampleWidget;

typedef struct
{
	GObjectClass parent_class;
} AcsampleWidgetClass;

GObject *acsample_widget_new()
{
	return g_object_new(ACSAMPLE_WIDGET_TYPE, NULL);
}

GType acsample_widget_get_type()
{
	static GType type = 0;

	if (!type) {
		static const GTypeInfo tinfo = {
			sizeof(AcsampleWidgetClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) NULL,
			(GClassFinalizeFunc) NULL,
			NULL,
			sizeof(AcsampleWidget),
			0,
			(GInstanceInitFunc) NULL,
			NULL
		};
		type = g_type_register_static(G_TYPE_OBJECT, "AcsampleWidget", &tinfo,
			0);
	}

	return type;
}


/***** ACCESSIBLE OBJECT FOR CUSTOM WIDGET *****/


static AtkGObjectAccessibleClass *goa_parent_class = NULL;

#define ACSAMPLE_ACCESSIBLE_TYPE (acsample_accessible_get_type())
#define ACSAMPLE_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), ACSAMPLE_ACCESSIBLE_TYPE, AcsampleAccessible))

typedef struct
{
	AtkGObjectAccessible parent;
	AtkObject *achild;
	AtkObject *aparent;
} AcsampleAccessible;

typedef struct
{
	AtkGObjectAccessibleClass parent_class;
} AcsampleAccessibleClass;

static void acsample_accessible_real_initialize(AtkObject *obj, gpointer data)
{
	ATK_OBJECT_CLASS(goa_parent_class)->initialize(obj, data);
	obj->role = ATK_ROLE_PUSH_BUTTON;
}

static int acsample_accessible_get_n_children(AtkObject *obj)
{
	AcsampleAccessible *a = ACSAMPLE_ACCESSIBLE(obj);
	if (a->achild == NULL)
		return 0;
	else
		return 1;
}

static AtkObject *acsample_accessible_ref_child(AtkObject *obj, gint i)
{
	AcsampleAccessible *a;
	GtkWidget *widget;
	AtkObject *atk_obj;

	a = ACSAMPLE_ACCESSIBLE(obj);
	atk_obj = a->achild;

	if (atk_obj)
		g_object_ref(atk_obj);
	return atk_obj;
}

static void
acsample_accessible_class_init(AcsampleAccessibleClass *klass)
{
	AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
	goa_parent_class = g_type_class_peek_parent(klass);
	class->initialize = acsample_accessible_real_initialize;
	class->get_n_children = acsample_accessible_get_n_children;
	class->ref_child = acsample_accessible_ref_child;

	g_signal_new("create", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
					0, /* default signal handler */
					NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

static gboolean acsample_accessible_do_action(AtkAction *action, gint i)
{
	printf("DO ACTION!!\n");
}

static gint acsample_accessible_get_n_actions(AtkAction *action)
{
	return 1;
}

static G_CONST_RETURN gchar *acsample_accessible_action_get_name(
	AtkAction *action, gint i)
{
	return "click";
}
static void
acsample_accessible_action_interface_init(AtkActionIface *aiface)
{
	aiface->do_action = acsample_accessible_do_action;
	aiface->get_n_actions = acsample_accessible_get_n_actions;
	aiface->get_name = acsample_accessible_action_get_name;
}

GType acsample_accessible_get_type()
{
	static GType type = 0;

	if (!type) {
		static const GTypeInfo tinfo = {
			sizeof(AcsampleAccessibleClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) acsample_accessible_class_init,
			(GClassFinalizeFunc) NULL,
			NULL,
			sizeof(AcsampleAccessible),
			0,
			(GInstanceInitFunc) NULL,
			NULL /* value table */
		};
		static const GInterfaceInfo atk_action_info =
		{
				(GInterfaceInitFunc) acsample_accessible_action_interface_init,
				(GInterfaceFinalizeFunc) NULL,
				NULL
		};
		static const GInterfaceInfo atk_text_info = {
				(GInterfaceInitFunc) acsample_accessible_text_interface_init,
				(GInterfaceFinalizeFunc) NULL,
				NULL
		};

		type = g_type_register_static(ATK_TYPE_GOBJECT_ACCESSIBLE,
				"AcsampleAccessible", &tinfo, 0);
		g_type_add_interface_static(type, ATK_TYPE_ACTION, &atk_action_info);
	}

	return type;
}

AtkObject *acsample_accessible_new(GObject *obj)
{
	gpointer object;
	AtkObject *atk_object;

	object = g_object_new(ACSAMPLE_ACCESSIBLE_TYPE, NULL);
	atk_object = ATK_OBJECT(object);
	atk_object_initialize(atk_object, obj);
	return atk_object;
}

/***** ACCESSIBLE OBJECT FACTORY TYPE *****/

#define ACSAMPLE_ACCESSIBLE_FACTORY_TYPE (acsample_accessible_factory_get_type())

typedef struct
{
	AtkObjectFactory parent;
} AcsampleAccessibleFactory;

typedef struct
{
	AtkObjectFactoryClass parent_class;
} AcsampleAccessibleFactoryClass;

GObject *acsample_accessible_factory_new()
{
	return g_object_new(ACSAMPLE_ACCESSIBLE_FACTORY_TYPE, NULL);
}

static AtkObject *acsample_accessible_factory_create_accessible(GObject *obj)
{
	printf("creating accessible\n");
	return acsample_accessible_new(obj);
}

static GType acsample_accessible_factory_get_accessible_type()
{
	return ACSAMPLE_ACCESSIBLE_TYPE;
}

static void acsample_accessible_factory_class_init(AcsampleAccessibleFactoryClass *klass)
{
	AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS(klass);
	class->create_accessible = acsample_accessible_factory_create_accessible;
	class->get_accessible_type = acsample_accessible_factory_get_accessible_type;
}

GType acsample_accessible_factory_get_type()
{
	static GType type = 0;

	if (!type) {
		static const GTypeInfo tinfo = {
			sizeof(AcsampleAccessibleFactoryClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) acsample_accessible_factory_class_init,
			(GClassFinalizeFunc) NULL,
			NULL,
			sizeof(AcsampleAccessibleFactory),
			0,
			(GInstanceInitFunc) NULL,
			NULL
		};
		type = g_type_register_static(ATK_TYPE_OBJECT_FACTORY, 
				"AcsampleAccessibleFactory" , &tinfo, 0);
	}

	return type;
}

/***** UTIL CLASS *****/

#define ACSAMPLE_UTIL_TYPE (acsample_util_get_type())

static AtkObject *util_root;

typedef struct
{
	AtkUtil parent;
} AcsampleUtil;

typedef struct
{
	AtkUtilClass parent_class;
} AcsampleUtilClass;

static AtkObject *acsample_util_get_root()
{
	if (util_root == NULL) {
		util_root = g_object_new(ACSAMPLE_ACCESSIBLE_TYPE, NULL);
		util_root->role = ATK_ROLE_APPLICATION;
		util_root->name = g_get_prgname();
		util_root->accessible_parent = NULL;
	}
	return util_root;
}

static int get_signal_id(const char *name, char *type, char *signal)
{
	GType gtype;
	guint sig;

	gtype = g_type_from_name(type);
	if (gtype == 0) {
		printf("unrecognized type %s\n", type);
		return;
	}

	sig = g_signal_lookup(signal, gtype);
	if (sig == 0) {
		printf("unrecognized signal %s\n", signal);
	}

	return sig;
}

static guint acsample_util_add_global_event_listener(
	GSignalEmissionHook listener, const gchar* event_type)
{
	gchar **split = NULL;
	GType type;
	guint sig;

	printf("ADD GLOBAL EVENT LISTENER %s\n");

	split = g_strsplit(event_type, ":", 3);
	if (strcmp(split[0], "window") == 0)
		sig = get_signal_id(event_type, "AcsampleAccessible", split[1]);
	else
		sig = get_signal_id(event_type, split[1], split[2]);

	if (sig > 0) {
		g_signal_add_emission_hook(sig, 0, listener, g_strdup(event_type),
			g_free);
		printf("added\n");
	}
	g_strfreev(split);
}

static G_CONST_RETURN gchar *acsample_util_get_toolkit_name()
{
	return "ACSAMPLE";
}

static void acsample_util_class_init(AcsampleUtilClass *klass)
{
	gpointer data = g_type_class_peek(ATK_TYPE_UTIL);
	AtkUtilClass *atk_class = ATK_UTIL_CLASS(data);

	// Must be loaded before add_global_event_listener is called
	g_type_class_unref(g_type_class_ref(ACSAMPLE_WIDGET_TYPE));

	atk_class->add_global_event_listener = acsample_util_add_global_event_listener;
	atk_class->get_root = acsample_util_get_root;
	atk_class->get_toolkit_name = acsample_util_get_toolkit_name;
}

GType acsample_util_get_type()
{
	static GType type = 0;

	if (!type) {
		static const GTypeInfo tinfo = {
			sizeof(AcsampleUtilClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) acsample_util_class_init,
			(GClassFinalizeFunc) NULL,
			NULL,
			sizeof(AcsampleUtil),
			0,
			(GInstanceInitFunc) NULL,
			NULL
		};

		type = g_type_register_static(ATK_TYPE_UTIL,
				"AcsampleUtil", &tinfo, 0);
	}
	return type;
}

int main(int argc, char **argv)
{
	GObject *widget;
	GObject *factory;
	GObject *window;
	AtkRegistry *registry;
	AtkObject *ao, *root;

	g_type_init();
	g_type_class_unref(g_type_class_ref(ACSAMPLE_UTIL_TYPE));

	gtk_init(&argc, &argv);

	registry = atk_get_default_registry();
	atk_registry_set_factory_type(registry, ACSAMPLE_ACCESSIBLE_TYPE,
			ACSAMPLE_ACCESSIBLE_FACTORY_TYPE);

	printf("ATK toolkit: %s\n", atk_get_toolkit_name());

	root = atk_get_root();

	widget = acsample_widget_new();
	factory = acsample_accessible_factory_new();
	ao = atk_object_factory_create_accessible(ATK_OBJECT_FACTORY(factory), widget);
	atk_object_set_name(ao, "my widget");
	atk_object_set_parent(ao, atk_get_root());
	ACSAMPLE_ACCESSIBLE(root)->achild = ao;

	g_signal_emit_by_name(atk_get_root(), "children_changed::add", 0, ao,
		NULL);

	g_signal_emit_by_name(atk_get_root(), "create", NULL);

	atk_object_notify_state_change(ao, ATK_STATE_VISIBLE, 1);

	printf("entering main loop\n");
	gtk_main();
}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]