view dwt/accessibility/AccessibleFactory.d @ 42:787b5413b0ce

accessibility package
author Frank Benoit <benoit@tionex.de>
date Fri, 11 Jan 2008 05:07:22 +0100
parents
children 8f049b136add
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.accessibility.AccessibleFactory;


import dwt.internal.accessibility.gtk.ATK;
import dwt.internal.gtk.OS;
import dwt.accessibility.Accessible;
import dwt.accessibility.ACC;
import dwt.accessibility.AccessibleObject;
import dwt.accessibility.AccessibleControlEvent;
import dwt.accessibility.AccessibleControlListener;

import dwt.SWT;

import tango.stdc.stringz;
import tango.io.Stdout;

class AccessibleFactory {
	AtkObjectFactory * handle;
	uint objectParentType;
	char* widgetTypeName;

	//Callback atkObjectFactoryCB_create_accessible;
	//Callback gTypeInfo_base_init_factory;
	Accessible[GtkWidget*] accessibles;

	static long[char[]] Types;
	static AccessibleFactory[long] Factories;

    static const uint DefaultParentType; //$NON-NLS-1$
	static const char[] FACTORY_PARENTTYPENAME = "AtkObjectFactory";
	static const char[] SWT_TYPE_PREFIX = "SWT";
	static const char[] CHILD_TYPENAME = "Child";
	static const char[] FACTORY_TYPENAME = "SWTFactory";
	static const int[] actionRoles = [
		ACC.ROLE_CHECKBUTTON, ACC.ROLE_COMBOBOX, ACC.ROLE_LINK,
		ACC.ROLE_MENUITEM, ACC.ROLE_PUSHBUTTON, ACC.ROLE_RADIOBUTTON,
	];
	static const int[] hypertextRoles = [ACC.ROLE_LINK];
	static const int[] selectionRoles = [
		ACC.ROLE_LIST, ACC.ROLE_TABFOLDER, ACC.ROLE_TABLE, ACC.ROLE_TREE,
	];
	static const int[] textRoles = [
		ACC.ROLE_COMBOBOX, ACC.ROLE_LINK, ACC.ROLE_LABEL, ACC.ROLE_TEXT,
	];

	/* AT callbacks*/
	/* interface definitions */
	static GTypeInfo* ObjectIfaceDefinition;
	static const GInterfaceInfo* ActionIfaceDefinition;
	static const GInterfaceInfo* ComponentIfaceDefinition;
	static const GInterfaceInfo* HypertextIfaceDefinition;
	static const GInterfaceInfo* SelectionIfaceDefinition;
	static const GInterfaceInfo* TextIfaceDefinition;

    static this(){
        DefaultParentType = OS.g_type_from_name ("GtkAccessible"); //$NON-NLS-1$
		/* Action interface */
		ActionIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
        ActionIfaceDefinition.interface_init = &AccessibleFactory.initActionIfaceCB;
		/* Component interface */
		ComponentIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
        ComponentIfaceDefinition.interface_init = &AccessibleFactory.initComponentIfaceCB;
		/* Hypertext interface */
		HypertextIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
        HypertextIfaceDefinition.interface_init = &AccessibleFactory.initHypertextIfaceCB;
		/* Selection interface */
		SelectionIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
        SelectionIfaceDefinition.interface_init = &AccessibleFactory.initSelectionIfaceCB;
		/* Text interface */
		TextIfaceDefinition =cast(GInterfaceInfo*) OS.g_malloc (GInterfaceInfo.sizeof);
        TextIfaceDefinition.interface_init = &AccessibleFactory.initTextIfaceCB;
	}

	private this (int /*long*/ widgetType) {
		widgetTypeName = OS.g_type_name (widgetType);
		char[] factoryName = FACTORY_TYPENAME ~ fromUtf8z( widgetTypeName ) ~ \0;
		if (OS.g_type_from_name (factoryName.ptr) is 0) {
			/* register the factory */
			auto registry = ATK.atk_get_default_registry ();
			auto previousFactory = ATK.atk_registry_get_factory (registry, widgetType);
			objectParentType = ATK.atk_object_factory_get_accessible_type (previousFactory);
			if (objectParentType is 0) objectParentType = DefaultParentType;
			auto factoryParentType = OS.g_type_from_name (FACTORY_PARENTTYPENAME.ptr);
            auto typeInfo = cast(GTypeInfo*) OS.g_malloc (GTypeInfo.sizeof);
            typeInfo.base_init = &gTypeInfo_base_init_factory;
			typeInfo.class_size = AtkObjectFactoryClass.sizeof;
			typeInfo.instance_size = AtkObjectFactory.sizeof;
			auto swtFactoryType = OS.g_type_register_static (factoryParentType, factoryName.ptr, typeInfo, 0);
			ATK.atk_registry_set_factory_type (registry, widgetType, swtFactoryType);
			handle = ATK.atk_registry_get_factory (registry, widgetType);
		}
	}

	void addAccessible (Accessible accessible) {
		auto controlHandle = accessible.getControlHandle ();
		accessibles[controlHandle] = accessible;
		ATK.atk_object_factory_create_accessible (handle, cast(GObject*)controlHandle);
	}

	private static extern(C) AtkObject* atkObjectFactory_create_accessible (GObject* widget) {
        auto widgetType = OS.G_OBJECT_TYPE ( cast(GTypeInstance*)widget);
        if( auto factory = widgetType in Factories ){
            with( *factory ){
                Accessible accessible = accessibles[ cast(GtkWidget*) widget ];
                if (accessible is null) {
                    /*
                    * we don't care about this control, so create it with the parent's
                    * type so that its accessibility callbacks will not pass though here
                    */
                    auto result = cast(AtkObject*) OS.g_object_new (objectParentType, null);
                    ATK.atk_object_initialize (result, cast(void*)widget);
                    return result;
                }
                /* if an atk object has already been created for this widget then just return it */
                if (accessible.accessibleObject !is null) {
                    return accessible.accessibleObject.handle;
                }
                char[] buffer = fromUtf8z( widgetTypeName ).dup;
                auto type = getType (buffer, accessible, objectParentType, ACC.CHILDID_SELF);
                AccessibleObject object = new AccessibleObject (type, cast(GtkWidget*)widget, accessible, objectParentType, false);
                accessible.accessibleObject = object;
                return object.handle;
            }
        }
        else{
            Stdout.formatln( "AccessibleFactory.atkObjectFactoryCB_create_accessible cannot find factory instance" );
        }
	}

	static int /*long*/ getChildType (Accessible accessible, int childIndex) {
		return getType (CHILD_TYPENAME, accessible, DefaultParentType, childIndex);
	}

	static int /*long*/ getDefaultParentType () {
		return DefaultParentType;
	}

	static int /*long*/ getType (char[] widgetTypeName, Accessible accessible, int /*long*/ parentType, int childId) {
		AccessibleControlEvent event = new AccessibleControlEvent (accessible);
		event.childID = childId;
		AccessibleControlListener[] listeners = accessible.getControlListeners ();
		for (int i = 0; i < listeners.length; i++) {
			listeners [i].getRole (event);
		}
		bool action = false, hypertext = false, selection = false, text = false;
		if (event.detail !is 0) {	/* a role was specified */
			for (int i = 0; i < actionRoles.length; i++) {
				if (event.detail is actionRoles [i]) {
					action = true;
					break;
				}
			}
			for (int i = 0; i < hypertextRoles.length; i++) {
				if (event.detail is hypertextRoles [i]) {
					hypertext = true;
					break;
				}
			}
			for (int i = 0; i < selectionRoles.length; i++) {
				if (event.detail is selectionRoles [i]) {
					selection = true;
					break;
				}
			}
			for (int i = 0; i < textRoles.length; i++) {
				if (event.detail is textRoles [i]) {
					text = true;
					break;
				}
			}
		} else {
			action = hypertext = selection = text = true;
		}
		char[] swtTypeName = SWT_TYPE_PREFIX.dup;
		swtTypeName ~= widgetTypeName;
		if (action) swtTypeName ~= "Action"; //$NON-NLS-1$
		if (hypertext) swtTypeName ~= "Hypertext"; //$NON-NLS-1$
		if (selection) swtTypeName ~= "Selection"; //$NON-NLS-1$
		if (text) swtTypeName ~= "Text"; //$NON-NLS-1$

		int /*long*/ type = 0;
        if (swtTypeName in Types ) {
			type = Types[swtTypeName];
		} else {
			/* define the type */
            GTypeQuery* query = new GTypeQuery ();
			OS.g_type_query (parentType, query);

            GTypeInfo* typeInfo = new GTypeInfo ();
			typeInfo.base_init = &gTypeInfo_base_init_type;
			typeInfo.class_size = query.class_size;
			typeInfo.instance_size = query.instance_size;
			ObjectIfaceDefinition = typeInfo;

			type = OS.g_type_register_static (parentType, toStringz( swtTypeName ), ObjectIfaceDefinition, 0);
			OS.g_type_add_interface_static (type, AccessibleObject.ATK_COMPONENT_TYPE, ComponentIfaceDefinition);
			if (action) OS.g_type_add_interface_static (type, AccessibleObject.ATK_ACTION_TYPE, ActionIfaceDefinition);
			if (hypertext) OS.g_type_add_interface_static (type, AccessibleObject.ATK_HYPERTEXT_TYPE, HypertextIfaceDefinition);
			if (selection) OS.g_type_add_interface_static (type, AccessibleObject.ATK_SELECTION_TYPE, SelectionIfaceDefinition);
			if (text) OS.g_type_add_interface_static (type, AccessibleObject.ATK_TEXT_TYPE, TextIfaceDefinition);
			Types[swtTypeName] = type;
		}
		return type;
	}

	private static extern(C) void gTypeInfo_base_init_factory (void* klass) {
		auto atkObjectFactoryClass = ATK.ATK_OBJECT_FACTORY_CLASS (klass);
		atkObjectFactoryClass.create_accessible = &atkObjectFactory_create_accessible;
	}

	private static extern(C) void gTypeInfo_base_init_type (void* klass) {
		auto objectClass = cast(AtkObjectClass*)klass;
        objectClass.get_name = &AccessibleObject.atkObject_get_name;
		objectClass.get_description = &AccessibleObject.atkObject_get_description;
		objectClass.get_n_children = &AccessibleObject.atkObject_get_n_children;
		objectClass.get_role = &AccessibleObject.atkObject_get_role;
		objectClass.get_parent = &AccessibleObject.atkObject_get_parent;
		objectClass.ref_state_set = &AccessibleObject.atkObject_ref_state_set;
		objectClass.get_index_in_parent = &AccessibleObject.atkObject_get_index_in_parent;
		objectClass.ref_child = &AccessibleObject.atkObject_ref_child;

        GObjectClass* gObjectClass = OS.G_OBJECT_CLASS ( cast(GTypeClass*)klass);
		gObjectClass.finalize = &AccessibleObject.gObjectClass_finalize;
	}

	private static extern(C) void initActionIfaceCB ( void* g_iface, void* iface_data ) {
        auto iface = cast(AtkActionIface*)g_iface;
		iface.get_keybinding =  &AccessibleObject.atkAction_get_keybinding;
		iface.get_name =  &AccessibleObject.atkAction_get_name;
	}

	private static extern(C) void initComponentIfaceCB ( void* g_iface, void* iface_data ) {
        auto iface = cast(AtkComponentIface*)g_iface;
		iface.get_extents = &AccessibleObject.atkComponent_get_extents;
		iface.get_position = &AccessibleObject.atkComponent_get_position;
		iface.get_size = &AccessibleObject.atkComponent_get_size;
		iface.ref_accessible_at_point = &AccessibleObject.atkComponent_ref_accessible_at_point;
	}

	private static extern(C) void initHypertextIfaceCB ( void* g_iface, void* iface_data ) {
        auto iface = cast(AtkHypertextIface*)g_iface;
		iface.get_link = &AccessibleObject.atkHypertext_get_link;
		iface.get_link_index = &AccessibleObject.atkHypertext_get_link_index;
		iface.get_n_links = &AccessibleObject.atkHypertext_get_n_links;
	}

	private static extern(C) void initSelectionIfaceCB ( void* g_iface, void* iface_data ) {
        auto iface = cast(AtkSelectionIface*)g_iface;
		iface.is_child_selected = &AccessibleObject.atkSelection_is_child_selected;
		iface.ref_selection = &AccessibleObject.atkSelection_ref_selection;
	}

	private static extern(C) void initTextIfaceCB ( void* g_iface, void* iface_data ) {
        auto iface = cast(AtkTextIface*)g_iface;
		iface.get_caret_offset = &AccessibleObject.atkText_get_caret_offset;
		iface.get_character_at_offset = &AccessibleObject.atkText_get_character_at_offset;
		iface.get_character_count = &AccessibleObject.atkText_get_character_count;
		iface.get_n_selections = &AccessibleObject.atkText_get_n_selections;
		iface.get_selection = &AccessibleObject.atkText_get_selection;
		iface.get_text = &AccessibleObject.atkText_get_text;
		iface.get_text_after_offset = &AccessibleObject.atkText_get_text_after_offset;
		iface.get_text_at_offset = &AccessibleObject.atkText_get_text_at_offset;
		iface.get_text_before_offset = &AccessibleObject.atkText_get_text_before_offset;
	}

	static void registerAccessible (Accessible accessible) {
		/* If DefaultParentType is 0 then OS accessibility is not active */
		if (DefaultParentType is 0) return;
		auto controlHandle = accessible.getControlHandle ();
		auto widgetType = OS.G_OBJECT_TYPE ( cast(GTypeInstance*)controlHandle);
		AccessibleFactory factory = Factories[widgetType];
		if (factory is null) {
			factory = new AccessibleFactory (widgetType);
			Factories[widgetType] = factory;
		}
		factory.addAccessible (accessible);
	}

	void removeAccessible (Accessible accessible) {
		accessibles.remove (accessible.getControlHandle ());
	}

	static void unregisterAccessible (Accessible accessible) {
		auto controlHandle = accessible.getControlHandle ();
		auto widgetType = OS.G_OBJECT_TYPE (cast(GTypeInstance*)controlHandle);
		AccessibleFactory factory = Factories[widgetType];
		if (factory !is null) {
			factory.removeAccessible (accessible);
		}
	}
}