1 /******************************************************************************* 2 * Copyright (c) 2000, 2006 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.accessibility.AccessibleFactory; 14 15 import java.lang.all; 16 17 18 import org.eclipse.swt.internal.accessibility.gtk.ATK; 19 import org.eclipse.swt.internal.gtk.OS; 20 import org.eclipse.swt.accessibility.Accessible; 21 import org.eclipse.swt.accessibility.ACC; 22 import org.eclipse.swt.accessibility.AccessibleObject; 23 import org.eclipse.swt.accessibility.AccessibleControlEvent; 24 import org.eclipse.swt.accessibility.AccessibleControlListener; 25 26 import org.eclipse.swt.SWT; 27 28 class AccessibleFactory { 29 AtkObjectFactory * handle; 30 ptrdiff_t objectParentType; 31 char* widgetTypeName; 32 33 //Callback atkObjectFactoryCB_create_accessible; 34 //Callback gTypeInfo_base_init_factory; 35 Accessible[GtkWidget*] accessibles; 36 37 static size_t[String] Types; 38 static AccessibleFactory[size_t] Factories; 39 40 static ptrdiff_t DefaultParentType; //$NON-NLS-1$ 41 static const String FACTORY_PARENTTYPENAME = "AtkObjectFactory"; 42 static const String SWT_TYPE_PREFIX = "SWT"; 43 static const String CHILD_TYPENAME = "Child"; 44 static const String FACTORY_TYPENAME = "SWTFactory"; 45 static const int[] actionRoles = [ 46 ACC.ROLE_CHECKBUTTON, ACC.ROLE_COMBOBOX, ACC.ROLE_LINK, 47 ACC.ROLE_MENUITEM, ACC.ROLE_PUSHBUTTON, ACC.ROLE_RADIOBUTTON, 48 ]; 49 static const int[] hypertextRoles = [ACC.ROLE_LINK]; 50 static const int[] selectionRoles = [ 51 ACC.ROLE_LIST, ACC.ROLE_TABFOLDER, ACC.ROLE_TABLE, ACC.ROLE_TREE, 52 ]; 53 static const int[] textRoles = [ 54 ACC.ROLE_COMBOBOX, ACC.ROLE_LINK, ACC.ROLE_LABEL, ACC.ROLE_TEXT, 55 ]; 56 57 /* AT callbacks*/ 58 /* interface definitions */ 59 private static GTypeInfo* ObjectIfaceDefinition; 60 private static GInterfaceInfo* ActionIfaceDefinition; 61 private static GInterfaceInfo* ComponentIfaceDefinition; 62 private static GInterfaceInfo* HypertextIfaceDefinition; 63 private static GInterfaceInfo* SelectionIfaceDefinition; 64 private static GInterfaceInfo* TextIfaceDefinition; 65 66 private static void static_this(){ 67 synchronized { 68 AccessibleObject.static_this(); 69 /* Action interface */ 70 if( ActionIfaceDefinition is null ){ 71 DefaultParentType = OS.g_type_from_name ("GtkAccessible"); //$NON-NLS-1$ 72 ActionIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof); 73 ActionIfaceDefinition.interface_init = &AccessibleFactory.initActionIfaceCB; 74 } 75 /* Component interface */ 76 if( ComponentIfaceDefinition is null ){ 77 ComponentIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof); 78 ComponentIfaceDefinition.interface_init = &AccessibleFactory.initComponentIfaceCB; 79 } 80 /* Hypertext interface */ 81 if( HypertextIfaceDefinition is null ){ 82 HypertextIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof); 83 HypertextIfaceDefinition.interface_init = &AccessibleFactory.initHypertextIfaceCB; 84 } 85 /* Selection interface */ 86 if( SelectionIfaceDefinition is null ){ 87 SelectionIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof); 88 SelectionIfaceDefinition.interface_init = &AccessibleFactory.initSelectionIfaceCB; 89 } 90 /* Text interface */ 91 if( TextIfaceDefinition is null ){ 92 TextIfaceDefinition =cast(GInterfaceInfo*) OS.g_malloc (GInterfaceInfo.sizeof); 93 TextIfaceDefinition.interface_init = &AccessibleFactory.initTextIfaceCB; 94 } 95 } 96 } 97 98 private this (int widgetType) { 99 widgetTypeName = OS.g_type_name (widgetType); 100 String factoryName = (FACTORY_TYPENAME ~ fromStringz( widgetTypeName ) ~ '\0')._idup(); 101 if (OS.g_type_from_name (factoryName.ptr) is 0) { 102 /* register the factory */ 103 auto registry = ATK.atk_get_default_registry (); 104 auto previousFactory = ATK.atk_registry_get_factory (registry, widgetType); 105 objectParentType = ATK.atk_object_factory_get_accessible_type (previousFactory); 106 if (objectParentType is 0) objectParentType = DefaultParentType; 107 auto factoryParentType = OS.g_type_from_name (FACTORY_PARENTTYPENAME.ptr); 108 auto typeInfo = cast(GTypeInfo*) OS.g_malloc (GTypeInfo.sizeof); 109 typeInfo.base_init = &gTypeInfo_base_init_factory; 110 typeInfo.class_size = AtkObjectFactoryClass.sizeof; 111 typeInfo.instance_size = AtkObjectFactory.sizeof; 112 auto swtFactoryType = OS.g_type_register_static (factoryParentType, factoryName.ptr, typeInfo, 0); 113 ATK.atk_registry_set_factory_type (registry, widgetType, swtFactoryType); 114 handle = ATK.atk_registry_get_factory (registry, widgetType); 115 } 116 } 117 118 void addAccessible (Accessible accessible) { 119 auto controlHandle = accessible.getControlHandle (); 120 accessibles[controlHandle] = accessible; 121 ATK.atk_object_factory_create_accessible (handle, cast(GObject*)controlHandle); 122 } 123 124 private static extern(C) AtkObject* atkObjectFactory_create_accessible (GObject* widget) { 125 auto widgetType = OS.G_OBJECT_TYPE ( cast(GTypeInstance*)widget); 126 if( auto factory = widgetType in Factories ){ 127 with( *factory ){ 128 Accessible accessible = accessibles[ cast(GtkWidget*) widget ]; 129 if (accessible is null) { 130 /* 131 * we don't care about this control, so create it with the parent's 132 * type so that its accessibility callbacks will not pass though here 133 */ 134 auto result = cast(AtkObject*) OS.g_object_new (objectParentType, null); 135 ATK.atk_object_initialize (result, cast(void*)widget); 136 return result; 137 } 138 /* if an atk object has already been created for this widget then just return it */ 139 if (accessible.accessibleObject !is null) { 140 return accessible.accessibleObject.handle; 141 } 142 String buffer = fromStringz( widgetTypeName )._idup(); 143 int type = getType (buffer, accessible, cast(uint)/*64bit*/objectParentType, ACC.CHILDID_SELF); 144 AccessibleObject object = new AccessibleObject (type, cast(GtkWidget*)widget, accessible, cast(uint)/*64bit*/objectParentType, false); 145 accessible.accessibleObject = object; 146 return object.handle; 147 } 148 } 149 else{ 150 getDwtLogger().info( __FILE__, __LINE__, "AccessibleFactory.atkObjectFactoryCB_create_accessible cannot find factory instance" ); 151 return null; 152 } 153 } 154 155 static int getChildType (Accessible accessible, int childIndex) { 156 return getType (CHILD_TYPENAME, accessible, cast(int)/*64bit*/DefaultParentType, childIndex); 157 } 158 159 static int getDefaultParentType () { 160 return cast(int)/*64bit*/DefaultParentType; 161 } 162 163 static int getType (String widgetTypeName, Accessible accessible, int parentType, int childId) { 164 AccessibleControlEvent event = new AccessibleControlEvent (accessible); 165 event.childID = childId; 166 AccessibleControlListener[] listeners = accessible.getControlListeners (); 167 for (int i = 0; i < listeners.length; i++) { 168 listeners [i].getRole (event); 169 } 170 bool action = false, hypertext = false, selection = false, text = false; 171 if (event.detail !is 0) { /* a role was specified */ 172 for (int i = 0; i < actionRoles.length; i++) { 173 if (event.detail is actionRoles [i]) { 174 action = true; 175 break; 176 } 177 } 178 for (int i = 0; i < hypertextRoles.length; i++) { 179 if (event.detail is hypertextRoles [i]) { 180 hypertext = true; 181 break; 182 } 183 } 184 for (int i = 0; i < selectionRoles.length; i++) { 185 if (event.detail is selectionRoles [i]) { 186 selection = true; 187 break; 188 } 189 } 190 for (int i = 0; i < textRoles.length; i++) { 191 if (event.detail is textRoles [i]) { 192 text = true; 193 break; 194 } 195 } 196 } else { 197 action = hypertext = selection = text = true; 198 } 199 String swtTypeName = SWT_TYPE_PREFIX._idup(); 200 swtTypeName ~= widgetTypeName; 201 if (action) swtTypeName ~= "Action"; //$NON-NLS-1$ 202 if (hypertext) swtTypeName ~= "Hypertext"; //$NON-NLS-1$ 203 if (selection) swtTypeName ~= "Selection"; //$NON-NLS-1$ 204 if (text) swtTypeName ~= "Text"; //$NON-NLS-1$ 205 206 size_t type = 0; 207 if (swtTypeName in Types ) { 208 type = Types[swtTypeName]; 209 } else { 210 /* define the type */ 211 GTypeQuery* query = new GTypeQuery (); 212 OS.g_type_query (parentType, query); 213 214 GTypeInfo* typeInfo = new GTypeInfo (); 215 typeInfo.base_init = &gTypeInfo_base_init_type; 216 typeInfo.class_size = cast(ushort) query.class_size; 217 typeInfo.instance_size = cast(ushort) query.instance_size; 218 ObjectIfaceDefinition = typeInfo; 219 220 type = OS.g_type_register_static (parentType, toStringz( swtTypeName ), ObjectIfaceDefinition, 0); 221 OS.g_type_add_interface_static (type, AccessibleObject.ATK_COMPONENT_TYPE, ComponentIfaceDefinition); 222 if (action) OS.g_type_add_interface_static (type, AccessibleObject.ATK_ACTION_TYPE, ActionIfaceDefinition); 223 if (hypertext) OS.g_type_add_interface_static (type, AccessibleObject.ATK_HYPERTEXT_TYPE, HypertextIfaceDefinition); 224 if (selection) OS.g_type_add_interface_static (type, AccessibleObject.ATK_SELECTION_TYPE, SelectionIfaceDefinition); 225 if (text) OS.g_type_add_interface_static (type, AccessibleObject.ATK_TEXT_TYPE, TextIfaceDefinition); 226 Types[swtTypeName] = type; 227 } 228 return cast(int)/*64bit*/type; 229 } 230 231 private static extern(C) void gTypeInfo_base_init_factory (void* klass) { 232 auto atkObjectFactoryClass = ATK.ATK_OBJECT_FACTORY_CLASS (klass); 233 atkObjectFactoryClass.create_accessible = &atkObjectFactory_create_accessible; 234 } 235 236 private static extern(C) void gTypeInfo_base_init_type (void* klass) { 237 auto objectClass = cast(AtkObjectClass*)klass; 238 objectClass.get_name = &AccessibleObject.atkObject_get_name; 239 objectClass.get_description = &AccessibleObject.atkObject_get_description; 240 objectClass.get_n_children = &AccessibleObject.atkObject_get_n_children; 241 objectClass.get_role = &AccessibleObject.atkObject_get_role; 242 objectClass.get_parent = &AccessibleObject.atkObject_get_parent; 243 objectClass.ref_state_set = &AccessibleObject.atkObject_ref_state_set; 244 objectClass.get_index_in_parent = &AccessibleObject.atkObject_get_index_in_parent; 245 objectClass.ref_child = &AccessibleObject.atkObject_ref_child; 246 247 GObjectClass* gObjectClass = OS.G_OBJECT_CLASS ( cast(GTypeClass*)klass); 248 gObjectClass.finalize = &AccessibleObject.gObjectClass_finalize; 249 } 250 251 private static extern(C) void initActionIfaceCB ( void* g_iface, void* iface_data ) { 252 auto iface = cast(AtkActionIface*)g_iface; 253 iface.get_keybinding = &AccessibleObject.atkAction_get_keybinding; 254 iface.get_name = &AccessibleObject.atkAction_get_name; 255 } 256 257 private static extern(C) void initComponentIfaceCB ( void* g_iface, void* iface_data ) { 258 auto iface = cast(AtkComponentIface*)g_iface; 259 iface.get_extents = &AccessibleObject.atkComponent_get_extents; 260 iface.get_position = &AccessibleObject.atkComponent_get_position; 261 iface.get_size = &AccessibleObject.atkComponent_get_size; 262 iface.ref_accessible_at_point = &AccessibleObject.atkComponent_ref_accessible_at_point; 263 } 264 265 private static extern(C) void initHypertextIfaceCB ( void* g_iface, void* iface_data ) { 266 auto iface = cast(AtkHypertextIface*)g_iface; 267 iface.get_link = &AccessibleObject.atkHypertext_get_link; 268 iface.get_link_index = &AccessibleObject.atkHypertext_get_link_index; 269 iface.get_n_links = &AccessibleObject.atkHypertext_get_n_links; 270 } 271 272 private static extern(C) void initSelectionIfaceCB ( void* g_iface, void* iface_data ) { 273 auto iface = cast(AtkSelectionIface*)g_iface; 274 iface.is_child_selected = &AccessibleObject.atkSelection_is_child_selected; 275 iface.ref_selection = &AccessibleObject.atkSelection_ref_selection; 276 } 277 278 private static extern(C) void initTextIfaceCB ( void* g_iface, void* iface_data ) { 279 auto iface = cast(AtkTextIface*)g_iface; 280 iface.get_caret_offset = &AccessibleObject.atkText_get_caret_offset; 281 iface.get_character_at_offset = &AccessibleObject.atkText_get_character_at_offset; 282 iface.get_character_count = &AccessibleObject.atkText_get_character_count; 283 iface.get_n_selections = &AccessibleObject.atkText_get_n_selections; 284 iface.get_selection = &AccessibleObject.atkText_get_selection; 285 iface.get_text = &AccessibleObject.atkText_get_text; 286 iface.get_text_after_offset = &AccessibleObject.atkText_get_text_after_offset; 287 iface.get_text_at_offset = &AccessibleObject.atkText_get_text_at_offset; 288 iface.get_text_before_offset = &AccessibleObject.atkText_get_text_before_offset; 289 } 290 291 static void registerAccessible (Accessible accessible) { 292 static_this(); 293 /* If DefaultParentType is 0 then OS accessibility is not active */ 294 if (DefaultParentType is 0) return; 295 auto controlHandle = accessible.getControlHandle (); 296 auto widgetType = OS.G_OBJECT_TYPE ( cast(GTypeInstance*)controlHandle); 297 AccessibleFactory factory = Factories[widgetType]; 298 if (factory is null) { 299 factory = new AccessibleFactory (cast(int)/*64bit*/widgetType); 300 Factories[widgetType] = factory; 301 } 302 factory.addAccessible (accessible); 303 } 304 305 void removeAccessible (Accessible accessible) { 306 accessibles.remove (accessible.getControlHandle ()); 307 } 308 309 static void unregisterAccessible (Accessible accessible) { 310 auto controlHandle = accessible.getControlHandle (); 311 auto widgetType = OS.G_OBJECT_TYPE (cast(GTypeInstance*)controlHandle); 312 if ( auto factory = widgetType in Factories ) { 313 factory.removeAccessible (accessible); 314 } 315 } 316 }