25
|
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 uint objectParentType;
|
|
31 char* widgetTypeName;
|
|
32
|
|
33 //Callback atkObjectFactoryCB_create_accessible;
|
|
34 //Callback gTypeInfo_base_init_factory;
|
|
35 Accessible[GtkWidget*] accessibles;
|
|
36
|
|
37 static long[String] Types;
|
|
38 static AccessibleFactory[long] Factories;
|
|
39
|
|
40 static uint 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 synchronized void static_this(){
|
|
67 AccessibleObject.static_this();
|
|
68 /* Action interface */
|
|
69 if( ActionIfaceDefinition is null ){
|
|
70 DefaultParentType = OS.g_type_from_name ("GtkAccessible"); //$NON-NLS-1$
|
|
71 ActionIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
|
|
72 ActionIfaceDefinition.interface_init = &AccessibleFactory.initActionIfaceCB;
|
|
73 }
|
|
74 /* Component interface */
|
|
75 if( ComponentIfaceDefinition is null ){
|
|
76 ComponentIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
|
|
77 ComponentIfaceDefinition.interface_init = &AccessibleFactory.initComponentIfaceCB;
|
|
78 }
|
|
79 /* Hypertext interface */
|
|
80 if( HypertextIfaceDefinition is null ){
|
|
81 HypertextIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
|
|
82 HypertextIfaceDefinition.interface_init = &AccessibleFactory.initHypertextIfaceCB;
|
|
83 }
|
|
84 /* Selection interface */
|
|
85 if( SelectionIfaceDefinition is null ){
|
|
86 SelectionIfaceDefinition = cast(GInterfaceInfo*)OS.g_malloc (GInterfaceInfo.sizeof);
|
|
87 SelectionIfaceDefinition.interface_init = &AccessibleFactory.initSelectionIfaceCB;
|
|
88 }
|
|
89 /* Text interface */
|
|
90 if( TextIfaceDefinition is null ){
|
|
91 TextIfaceDefinition =cast(GInterfaceInfo*) OS.g_malloc (GInterfaceInfo.sizeof);
|
|
92 TextIfaceDefinition.interface_init = &AccessibleFactory.initTextIfaceCB;
|
|
93 }
|
|
94 }
|
|
95
|
|
96 private this (int /*long*/ widgetType) {
|
|
97 widgetTypeName = OS.g_type_name (widgetType);
|
26
|
98 String factoryName = FACTORY_TYPENAME ~ fromStringz( widgetTypeName ) ~ '\0';
|
25
|
99 if (OS.g_type_from_name (factoryName.ptr) is 0) {
|
|
100 /* register the factory */
|
|
101 auto registry = ATK.atk_get_default_registry ();
|
|
102 auto previousFactory = ATK.atk_registry_get_factory (registry, widgetType);
|
|
103 objectParentType = ATK.atk_object_factory_get_accessible_type (previousFactory);
|
|
104 if (objectParentType is 0) objectParentType = DefaultParentType;
|
|
105 auto factoryParentType = OS.g_type_from_name (FACTORY_PARENTTYPENAME.ptr);
|
|
106 auto typeInfo = cast(GTypeInfo*) OS.g_malloc (GTypeInfo.sizeof);
|
|
107 typeInfo.base_init = &gTypeInfo_base_init_factory;
|
|
108 typeInfo.class_size = AtkObjectFactoryClass.sizeof;
|
|
109 typeInfo.instance_size = AtkObjectFactory.sizeof;
|
|
110 auto swtFactoryType = OS.g_type_register_static (factoryParentType, factoryName.ptr, typeInfo, 0);
|
|
111 ATK.atk_registry_set_factory_type (registry, widgetType, swtFactoryType);
|
|
112 handle = ATK.atk_registry_get_factory (registry, widgetType);
|
|
113 }
|
|
114 }
|
|
115
|
|
116 void addAccessible (Accessible accessible) {
|
|
117 auto controlHandle = accessible.getControlHandle ();
|
|
118 accessibles[controlHandle] = accessible;
|
|
119 ATK.atk_object_factory_create_accessible (handle, cast(GObject*)controlHandle);
|
|
120 }
|
|
121
|
|
122 private static extern(C) AtkObject* atkObjectFactory_create_accessible (GObject* widget) {
|
|
123 auto widgetType = OS.G_OBJECT_TYPE ( cast(GTypeInstance*)widget);
|
|
124 if( auto factory = widgetType in Factories ){
|
|
125 with( *factory ){
|
|
126 Accessible accessible = accessibles[ cast(GtkWidget*) widget ];
|
|
127 if (accessible is null) {
|
|
128 /*
|
|
129 * we don't care about this control, so create it with the parent's
|
|
130 * type so that its accessibility callbacks will not pass though here
|
|
131 */
|
|
132 auto result = cast(AtkObject*) OS.g_object_new (objectParentType, null);
|
|
133 ATK.atk_object_initialize (result, cast(void*)widget);
|
|
134 return result;
|
|
135 }
|
|
136 /* if an atk object has already been created for this widget then just return it */
|
|
137 if (accessible.accessibleObject !is null) {
|
|
138 return accessible.accessibleObject.handle;
|
|
139 }
|
|
140 String buffer = fromStringz( widgetTypeName ).dup;
|
|
141 auto type = getType (buffer, accessible, objectParentType, ACC.CHILDID_SELF);
|
|
142 AccessibleObject object = new AccessibleObject (type, cast(GtkWidget*)widget, accessible, objectParentType, false);
|
|
143 accessible.accessibleObject = object;
|
|
144 return object.handle;
|
|
145 }
|
|
146 }
|
|
147 else{
|
|
148 getDwtLogger().info( __FILE__, __LINE__, "AccessibleFactory.atkObjectFactoryCB_create_accessible cannot find factory instance" );
|
|
149 }
|
|
150 }
|
|
151
|
|
152 static int /*long*/ getChildType (Accessible accessible, int childIndex) {
|
|
153 return getType (CHILD_TYPENAME, accessible, DefaultParentType, childIndex);
|
|
154 }
|
|
155
|
|
156 static int /*long*/ getDefaultParentType () {
|
|
157 return DefaultParentType;
|
|
158 }
|
|
159
|
|
160 static int /*long*/ getType (String widgetTypeName, Accessible accessible, int /*long*/ parentType, int childId) {
|
|
161 AccessibleControlEvent event = new AccessibleControlEvent (accessible);
|
|
162 event.childID = childId;
|
|
163 AccessibleControlListener[] listeners = accessible.getControlListeners ();
|
|
164 for (int i = 0; i < listeners.length; i++) {
|
|
165 listeners [i].getRole (event);
|
|
166 }
|
|
167 bool action = false, hypertext = false, selection = false, text = false;
|
|
168 if (event.detail !is 0) { /* a role was specified */
|
|
169 for (int i = 0; i < actionRoles.length; i++) {
|
|
170 if (event.detail is actionRoles [i]) {
|
|
171 action = true;
|
|
172 break;
|
|
173 }
|
|
174 }
|
|
175 for (int i = 0; i < hypertextRoles.length; i++) {
|
|
176 if (event.detail is hypertextRoles [i]) {
|
|
177 hypertext = true;
|
|
178 break;
|
|
179 }
|
|
180 }
|
|
181 for (int i = 0; i < selectionRoles.length; i++) {
|
|
182 if (event.detail is selectionRoles [i]) {
|
|
183 selection = true;
|
|
184 break;
|
|
185 }
|
|
186 }
|
|
187 for (int i = 0; i < textRoles.length; i++) {
|
|
188 if (event.detail is textRoles [i]) {
|
|
189 text = true;
|
|
190 break;
|
|
191 }
|
|
192 }
|
|
193 } else {
|
|
194 action = hypertext = selection = text = true;
|
|
195 }
|
|
196 String swtTypeName = SWT_TYPE_PREFIX.dup;
|
|
197 swtTypeName ~= widgetTypeName;
|
|
198 if (action) swtTypeName ~= "Action"; //$NON-NLS-1$
|
|
199 if (hypertext) swtTypeName ~= "Hypertext"; //$NON-NLS-1$
|
|
200 if (selection) swtTypeName ~= "Selection"; //$NON-NLS-1$
|
|
201 if (text) swtTypeName ~= "Text"; //$NON-NLS-1$
|
|
202
|
|
203 int /*long*/ type = 0;
|
|
204 if (swtTypeName in Types ) {
|
|
205 type = Types[swtTypeName];
|
|
206 } else {
|
|
207 /* define the type */
|
|
208 GTypeQuery* query = new GTypeQuery ();
|
|
209 OS.g_type_query (parentType, query);
|
|
210
|
|
211 GTypeInfo* typeInfo = new GTypeInfo ();
|
|
212 typeInfo.base_init = &gTypeInfo_base_init_type;
|
|
213 typeInfo.class_size = query.class_size;
|
|
214 typeInfo.instance_size = query.instance_size;
|
|
215 ObjectIfaceDefinition = typeInfo;
|
|
216
|
|
217 type = OS.g_type_register_static (parentType, toStringz( swtTypeName ), ObjectIfaceDefinition, 0);
|
|
218 OS.g_type_add_interface_static (type, AccessibleObject.ATK_COMPONENT_TYPE, ComponentIfaceDefinition);
|
|
219 if (action) OS.g_type_add_interface_static (type, AccessibleObject.ATK_ACTION_TYPE, ActionIfaceDefinition);
|
|
220 if (hypertext) OS.g_type_add_interface_static (type, AccessibleObject.ATK_HYPERTEXT_TYPE, HypertextIfaceDefinition);
|
|
221 if (selection) OS.g_type_add_interface_static (type, AccessibleObject.ATK_SELECTION_TYPE, SelectionIfaceDefinition);
|
|
222 if (text) OS.g_type_add_interface_static (type, AccessibleObject.ATK_TEXT_TYPE, TextIfaceDefinition);
|
|
223 Types[swtTypeName] = type;
|
|
224 }
|
|
225 return type;
|
|
226 }
|
|
227
|
|
228 private static extern(C) void gTypeInfo_base_init_factory (void* klass) {
|
|
229 auto atkObjectFactoryClass = ATK.ATK_OBJECT_FACTORY_CLASS (klass);
|
|
230 atkObjectFactoryClass.create_accessible = &atkObjectFactory_create_accessible;
|
|
231 }
|
|
232
|
|
233 private static extern(C) void gTypeInfo_base_init_type (void* klass) {
|
|
234 auto objectClass = cast(AtkObjectClass*)klass;
|
|
235 objectClass.get_name = &AccessibleObject.atkObject_get_name;
|
|
236 objectClass.get_description = &AccessibleObject.atkObject_get_description;
|
|
237 objectClass.get_n_children = &AccessibleObject.atkObject_get_n_children;
|
|
238 objectClass.get_role = &AccessibleObject.atkObject_get_role;
|
|
239 objectClass.get_parent = &AccessibleObject.atkObject_get_parent;
|
|
240 objectClass.ref_state_set = &AccessibleObject.atkObject_ref_state_set;
|
|
241 objectClass.get_index_in_parent = &AccessibleObject.atkObject_get_index_in_parent;
|
|
242 objectClass.ref_child = &AccessibleObject.atkObject_ref_child;
|
|
243
|
|
244 GObjectClass* gObjectClass = OS.G_OBJECT_CLASS ( cast(GTypeClass*)klass);
|
|
245 gObjectClass.finalize = &AccessibleObject.gObjectClass_finalize;
|
|
246 }
|
|
247
|
|
248 private static extern(C) void initActionIfaceCB ( void* g_iface, void* iface_data ) {
|
|
249 auto iface = cast(AtkActionIface*)g_iface;
|
|
250 iface.get_keybinding = &AccessibleObject.atkAction_get_keybinding;
|
|
251 iface.get_name = &AccessibleObject.atkAction_get_name;
|
|
252 }
|
|
253
|
|
254 private static extern(C) void initComponentIfaceCB ( void* g_iface, void* iface_data ) {
|
|
255 auto iface = cast(AtkComponentIface*)g_iface;
|
|
256 iface.get_extents = &AccessibleObject.atkComponent_get_extents;
|
|
257 iface.get_position = &AccessibleObject.atkComponent_get_position;
|
|
258 iface.get_size = &AccessibleObject.atkComponent_get_size;
|
|
259 iface.ref_accessible_at_point = &AccessibleObject.atkComponent_ref_accessible_at_point;
|
|
260 }
|
|
261
|
|
262 private static extern(C) void initHypertextIfaceCB ( void* g_iface, void* iface_data ) {
|
|
263 auto iface = cast(AtkHypertextIface*)g_iface;
|
|
264 iface.get_link = &AccessibleObject.atkHypertext_get_link;
|
|
265 iface.get_link_index = &AccessibleObject.atkHypertext_get_link_index;
|
|
266 iface.get_n_links = &AccessibleObject.atkHypertext_get_n_links;
|
|
267 }
|
|
268
|
|
269 private static extern(C) void initSelectionIfaceCB ( void* g_iface, void* iface_data ) {
|
|
270 auto iface = cast(AtkSelectionIface*)g_iface;
|
|
271 iface.is_child_selected = &AccessibleObject.atkSelection_is_child_selected;
|
|
272 iface.ref_selection = &AccessibleObject.atkSelection_ref_selection;
|
|
273 }
|
|
274
|
|
275 private static extern(C) void initTextIfaceCB ( void* g_iface, void* iface_data ) {
|
|
276 auto iface = cast(AtkTextIface*)g_iface;
|
|
277 iface.get_caret_offset = &AccessibleObject.atkText_get_caret_offset;
|
|
278 iface.get_character_at_offset = &AccessibleObject.atkText_get_character_at_offset;
|
|
279 iface.get_character_count = &AccessibleObject.atkText_get_character_count;
|
|
280 iface.get_n_selections = &AccessibleObject.atkText_get_n_selections;
|
|
281 iface.get_selection = &AccessibleObject.atkText_get_selection;
|
|
282 iface.get_text = &AccessibleObject.atkText_get_text;
|
|
283 iface.get_text_after_offset = &AccessibleObject.atkText_get_text_after_offset;
|
|
284 iface.get_text_at_offset = &AccessibleObject.atkText_get_text_at_offset;
|
|
285 iface.get_text_before_offset = &AccessibleObject.atkText_get_text_before_offset;
|
|
286 }
|
|
287
|
|
288 static void registerAccessible (Accessible accessible) {
|
|
289 static_this();
|
|
290 /* If DefaultParentType is 0 then OS accessibility is not active */
|
|
291 if (DefaultParentType is 0) return;
|
|
292 auto controlHandle = accessible.getControlHandle ();
|
|
293 auto widgetType = OS.G_OBJECT_TYPE ( cast(GTypeInstance*)controlHandle);
|
|
294 AccessibleFactory factory = Factories[widgetType];
|
|
295 if (factory is null) {
|
|
296 factory = new AccessibleFactory (widgetType);
|
|
297 Factories[widgetType] = factory;
|
|
298 }
|
|
299 factory.addAccessible (accessible);
|
|
300 }
|
|
301
|
|
302 void removeAccessible (Accessible accessible) {
|
|
303 accessibles.remove (accessible.getControlHandle ());
|
|
304 }
|
|
305
|
|
306 static void unregisterAccessible (Accessible accessible) {
|
|
307 auto controlHandle = accessible.getControlHandle ();
|
|
308 auto widgetType = OS.G_OBJECT_TYPE (cast(GTypeInstance*)controlHandle);
|
|
309 if ( auto factory = widgetType in Factories ) {
|
|
310 factory.removeAccessible (accessible);
|
|
311 }
|
|
312 }
|
|
313 }
|