Mercurial > projects > dwt-linux
diff dwt/accessibility/AccessibleObject.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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/accessibility/AccessibleObject.d Fri Jan 11 05:07:22 2008 +0100 @@ -0,0 +1,1377 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 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.AccessibleObject; + +import dwt.internal.accessibility.gtk.ATK; +import dwt.internal.gtk.OS; +import dwt.accessibility.Accessible; +import dwt.accessibility.AccessibleListener; +import dwt.accessibility.AccessibleControlListener; +import dwt.accessibility.AccessibleTextListener; +import dwt.accessibility.AccessibleEvent; +import dwt.accessibility.AccessibleControlEvent; +import dwt.accessibility.AccessibleTextEvent; +import dwt.accessibility.ACC; +import dwt.accessibility.AccessibleFactory; +import dwt.widgets.Display; +import dwt.dwthelper.Integer; +import tango.io.Stdout; +import tango.stdc.stringz; +import tango.text.Util; +import Math = tango.math.Math; + +class AccessibleObject { + AtkObject* handle; + int /*long*/ parentType; + int index = -1, id = ACC.CHILDID_SELF; + Accessible accessible; + AccessibleObject parent; + AccessibleObject[AtkObject*] children; + /* + * a lightweight object does not correspond to a concrete gtk widget, but + * to a logical child of a widget (eg.- a CTabItem, which is simply drawn) + */ + bool isLightweight = false; + + static char[] actionNamePtr; + static char[] descriptionPtr; + static char[] keybindingPtr; + static char[] namePtr; + static AccessibleObject[AtkObject*] AccessibleObjects; + static const uint ATK_ACTION_TYPE; + static const uint ATK_COMPONENT_TYPE; + static const uint ATK_HYPERTEXT_TYPE; + static const uint ATK_SELECTION_TYPE; + static const uint ATK_TEXT_TYPE; + static const bool DEBUG; + + static this(){ + DEBUG = Display.DEBUG; + ATK_ACTION_TYPE = ATK.g_type_from_name ("AtkAction"); + ATK_COMPONENT_TYPE = ATK.g_type_from_name ("AtkComponent"); + ATK_HYPERTEXT_TYPE = ATK.g_type_from_name ("AtkHypertext"); + ATK_SELECTION_TYPE = ATK.g_type_from_name ("AtkSelection"); + ATK_TEXT_TYPE = ATK.g_type_from_name ("AtkText"); + } + + this (int /*long*/ type, GtkWidget* widget, Accessible accessible, int /*long*/ parentType, bool isLightweight) { + handle = cast(AtkObject*)ATK.g_object_new (type, null); + this.parentType = parentType; + ATK.atk_object_initialize (handle, widget); + this.accessible = accessible; + this.isLightweight = isLightweight; + AccessibleObjects[handle] = this; + if (DEBUG) Stdout.formatln("new AccessibleObject: {}", handle); + } + + void addChild (AccessibleObject child) { + children[child.handle] = child; + child.setParent (this); + } + + package static extern(C) char* atkAction_get_keybinding (void* obj, int index) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkAction_get_keybinding"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + char* parentResult; + if (ATK.g_type_is_a (object.parentType, ATK_ACTION_TYPE)) { + auto superType = cast(AtkActionIface*)ATK.g_type_interface_peek_parent (ATK.ATK_ACTION_GET_IFACE (object.handle)); + AtkActionIface* actionIface = superType; + if (actionIface.get_keybinding !is null) { + parentResult = actionIface.get_keybinding( object.handle, index ); + } + } + AccessibleListener[] listeners = object.getAccessibleListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleEvent event = new AccessibleEvent (object); + event.childID = object.id; + if (parentResult !is null) { + char[] res = fromUtf8z( parentResult ); + event.result = res.dup; + } + for (int i = 0; i < listeners.length; i++) { + listeners [i].getKeyboardShortcut (event); + } + if (event.result is null) return parentResult; + if (keybindingPtr !is null ) OS.g_free (keybindingPtr.ptr); + char[] name = event.result.dup ~ \0; + char* p = cast(char*) OS.g_malloc (name.length); + keybindingPtr = p ? p[ 0 .. name.length ] : null; + return keybindingPtr.ptr; + } + + package static extern(C) char* atkAction_get_name (void* obj, int index) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkAction_get_name"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + char* parentResult; + if (ATK.g_type_is_a (object.parentType, ATK_ACTION_TYPE)) { + auto actionIface = cast(AtkActionIface*)ATK.g_type_interface_peek_parent (ATK.ATK_ACTION_GET_IFACE (object.handle)); + if (actionIface.get_name !is null) { + parentResult = actionIface.get_name( object.handle, index); + } + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + if (parentResult !is null) { + char[] res = fromUtf8z( parentResult ); + event.result = res.dup; + } + for (int i = 0; i < listeners.length; i++) { + listeners [i].getDefaultAction (event); + } + if (event.result is null) return parentResult; + if (actionNamePtr !is null) OS.g_free (actionNamePtr.ptr); + + char[] name = event.result.dup ~ \0; + auto p = cast(char*)OS.g_malloc (name.length); + actionNamePtr = p ? p[ 0 .. name.length ] : null; + return actionNamePtr.ptr; + } + + package static extern(C) void atkComponent_get_extents (void* obj, int* x, int* y, int* width, int* height, int coord_type) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkComponent_get_extents"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + *x = 0; + *y = 0; + *width = 0; + *height = 0; + if (ATK.g_type_is_a (object.parentType, ATK_COMPONENT_TYPE)) { + auto componentIface = cast(AtkComponentIface*) ATK.g_type_interface_peek_parent (ATK.ATK_COMPONENT_GET_IFACE (object.handle)); + if (componentIface.get_extents !is null) { + componentIface.get_extents( object.handle, x, y, width, height, coord_type); + } + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return 0; + + int parentX = *x, parentY = *y; + int parentWidth = *width, parentHeight = *height; + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + event.x = parentX; event.y = parentY; + event.width = parentWidth; event.height = parentHeight; + if (coord_type is ATK.ATK_XY_WINDOW) { + /* translate control -> display, for filling in event to be dispatched */ + auto gtkAccessible = ATK.GTK_ACCESSIBLE (object.handle); + auto topLevel = ATK.gtk_widget_get_toplevel (gtkAccessible.widget); + auto window = OS.GTK_WIDGET_WINDOW (topLevel); + int topWindowX, topWindowY; + OS.gdk_window_get_origin (window, &topWindowX, &topWindowY); + event.x += topWindowX; + event.y += topWindowY; + } + for (int i = 0; i < listeners.length; i++) { + listeners [i].getLocation (event); + } + if (coord_type is ATK.ATK_XY_WINDOW) { + /* translate display -> control, for answering to the OS */ + auto gtkAccessible = ATK.GTK_ACCESSIBLE (object.handle); + auto topLevel = ATK.gtk_widget_get_toplevel (gtkAccessible.widget); + auto window = OS.GTK_WIDGET_WINDOW (topLevel); + int topWindowX, topWindowY; + OS.gdk_window_get_origin (window, &topWindowX, &topWindowY); + event.x -= topWindowX; + event.y -= topWindowY; + } + *x = event.x; + *y = event.y; + *width = event.width; + *height = event.height; + //return 0; + } + + package static extern(C) void atkComponent_get_position (void* obj, int* x, int* y, int coord_type) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkComponent_get_position, object: {} x:{} y:{} coord:{}", atkObject, x, y, coord_type); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + *x=0; + *y=0; + if (ATK.g_type_is_a (object.parentType, ATK_COMPONENT_TYPE)) { + auto componentIface = cast(AtkComponentIface*)ATK.g_type_interface_peek_parent (ATK.ATK_COMPONENT_GET_IFACE (object.handle)); + if (componentIface.get_extents !is null) { + componentIface.get_position( object.handle, x, y, coord_type); + } + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return 0; + + int parentX, parentY; + parentX = *x; + parentY = *y; + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + event.x = parentX; event.y = parentY; + if (coord_type is ATK.ATK_XY_WINDOW) { + /* translate control -> display, for filling in event to be dispatched */ + auto gtkAccessible = ATK.GTK_ACCESSIBLE (object.handle); + auto topLevel = ATK.gtk_widget_get_toplevel (gtkAccessible.widget); + auto window = OS.GTK_WIDGET_WINDOW (topLevel); + int topWindowX, topWindowY; + OS.gdk_window_get_origin (window, &topWindowX, &topWindowY); + event.x += topWindowX; + event.y += topWindowY; + } + for (int i = 0; i < listeners.length; i++) { + listeners [i].getLocation (event); + } + if (coord_type is ATK.ATK_XY_WINDOW) { + /* translate display -> control, for answering to the OS */ + auto gtkAccessible = ATK.GTK_ACCESSIBLE (object.handle); + auto topLevel = ATK.gtk_widget_get_toplevel (gtkAccessible.widget); + auto window = OS.GTK_WIDGET_WINDOW (topLevel); + int topWindowX, topWindowY; + OS.gdk_window_get_origin (window, &topWindowX, &topWindowY); + event.x -= topWindowX; + event.y -= topWindowY; + } + *x=event.x; + *y=event.y; + //return 0; + } + + //PORTING_FIXME: what about the coord_type? componentIface.get_size( object.handle, width, height, coord_type); + //package static extern(C) void atkComponent_get_size (void* obj, int* width, int* height, int coord_type) { + package static extern(C) void atkComponent_get_size (void* obj, int* width, int* height) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkComponent_get_size"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + *width=0; + *height=0; + if (ATK.g_type_is_a (object.parentType, ATK_COMPONENT_TYPE)) { + auto componentIface = cast(AtkComponentIface*)ATK.g_type_interface_peek_parent (ATK.ATK_COMPONENT_GET_IFACE (object.handle)); + if (componentIface.get_extents !is null) { + //PORTING_FIXME: what about the coord_type? componentIface.get_size( object.handle, width, height, coord_type); + componentIface.get_size( object.handle, width, height); + } + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return 0; + + int parentWidth, parentHeight; + parentWidth= *width; + parentHeight= *height; + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + event.width = parentWidth; event.height = parentHeight; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getLocation (event); + } + *width=event.width; + *height=event.height; + //return 0; + } + + package static extern(C) AtkObject* atkComponent_ref_accessible_at_point (void* obj, int x, int y, int coord_type) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkComponent_ref_accessible_at_point"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + AtkObject* parentResult; + if (ATK.g_type_is_a (object.parentType, ATK_COMPONENT_TYPE)) { + auto componentIface = cast(AtkComponentIface*)ATK.g_type_interface_peek_parent (ATK.ATK_COMPONENT_GET_IFACE (object.handle)); + if (componentIface.ref_accessible_at_point !is null) { + parentResult = componentIface.ref_accessible_at_point( object.handle, x, y, coord_type); + } + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + event.x = x; event.y = y; + if (coord_type is ATK.ATK_XY_WINDOW) { + /* translate control -> display, for filling in the event to be dispatched */ + auto gtkAccessible = ATK.GTK_ACCESSIBLE (object.handle); + auto topLevel = ATK.gtk_widget_get_toplevel (gtkAccessible.widget); + auto window = OS.GTK_WIDGET_WINDOW (topLevel); + int topWindowX, topWindowY; + OS.gdk_window_get_origin (window, &topWindowX, &topWindowY); + event.x += topWindowX; + event.y += topWindowY; + } + for (int i = 0; i < listeners.length; i++) { + listeners [i].getChildAtPoint (event); + } + if (event.childID is object.id) event.childID = ACC.CHILDID_SELF; + AccessibleObject accObj = object.getChildByID (event.childID); + if (accObj !is null) { + if (parentResult !is null) OS.g_object_unref (parentResult); + OS.g_object_ref (accObj.handle); + return accObj.handle; + } + return parentResult; + } + + package static extern(C) AtkHyperlink* atkHypertext_get_link (void* obj, int link_index) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkHypertext_get_link"); + return null; + } + + package static extern(C) int atkHypertext_get_n_links (void* obj) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkHypertext_get_n_links"); + return 0; /* read hyperlink's name */ + } + + package static extern(C) int atkHypertext_get_link_index (void* obj, int char_index) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkHypertext_get_link_index"); + return 0; + } + + package static extern(C) char* atkObject_get_description (AtkObject* atkObject) { + if (DEBUG) Stdout.formatln ("-->atkObject_get_description"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + char* parentResult; + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.get_description !is null) { + parentResult = objectClass.get_description(object.handle); + } + AccessibleListener[] listeners = object.getAccessibleListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleEvent event = new AccessibleEvent (object); + event.childID = object.id; + if (parentResult !is null) { + event.result = fromUtf8z( parentResult ).dup; + } + for (int i = 0; i < listeners.length; i++) { + listeners [i].getDescription (event); + } + if (event.result is null) return parentResult; + if (descriptionPtr !is null) OS.g_free (descriptionPtr.ptr); + + char[] name = event.result.dup ~ \0; + char* p = cast(char*)OS.g_malloc (name.length); + descriptionPtr = p ? p[ 0 .. name.length ] : null; + return descriptionPtr.ptr; } + + package static extern(C) char* atkObject_get_name (AtkObject* atkObject) { + if (DEBUG) Stdout.formatln ("-->atkObject_get_name: {}", atkObject); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + char* parentResult; + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.get_name !is null) { + parentResult = objectClass.get_name( object.handle); + } + AccessibleListener[] listeners = object.getAccessibleListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleEvent event = new AccessibleEvent (object); + event.childID = object.id; + if (parentResult !is null) { + event.result = fromUtf8z( parentResult ).dup; + } + for (int i = 0; i < listeners.length; i++) { + listeners [i].getName (event); + } + if (event.result is null) return parentResult; + if (namePtr !is null) OS.g_free (namePtr.ptr); + char[] name = event.result.dup ~ \0; + char* p = cast(char*)OS.g_malloc (name.length); + namePtr = p ? p[ 0 .. name.length ] : null; + return namePtr.ptr; + } + + package static extern(C) int atkObject_get_n_children (AtkObject* atkObject) { + if (DEBUG) Stdout.formatln ("-->atkObject_get_n_children: {}", atkObject); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + int /*long*/ parentResult = 0; + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.get_n_children !is null) { + parentResult = objectClass.get_n_children( object.handle); + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + event.detail = cast(int)/*64*/parentResult; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getChildCount (event); + } + return event.detail; + } + + package static extern(C) int atkObject_get_index_in_parent (AtkObject* atkObject) { + if (DEBUG) Stdout.formatln ("-->atkObjectCB_get_index_in_parent. "); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + if (object.index !is -1) return object.index; + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.get_index_in_parent is null) return 0; + return objectClass.get_index_in_parent(object. handle); + } + + package static extern(C) AtkObject* atkObject_get_parent (AtkObject* atkObject) { + if (DEBUG) Stdout.formatln ("-->atkObject_get_parent: {}", atkObject); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + if (object.parent !is null) return object.parent.handle; + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.get_parent is null) return null; + return objectClass.get_parent( object.handle); + } + + package static extern(C) int atkObject_get_role (AtkObject* atkObject) { + if (DEBUG) Stdout.formatln ("-->atkObject_get_role: {}", atkObject); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + if (object.getAccessibleListeners ().length !is 0) { + AccessibleControlListener[] listeners = object.getControlListeners (); + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + event.detail = -1; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getRole (event); + } + if (event.detail !is -1) { + switch (event.detail) { + /* Convert from win32 role values to atk role values */ + case ACC.ROLE_CHECKBUTTON: return ATK.ATK_ROLE_CHECK_BOX; + case ACC.ROLE_CLIENT_AREA: return ATK.ATK_ROLE_DRAWING_AREA; + case ACC.ROLE_COMBOBOX: return ATK.ATK_ROLE_COMBO_BOX; + case ACC.ROLE_DIALOG: return ATK.ATK_ROLE_DIALOG; + case ACC.ROLE_LABEL: return ATK.ATK_ROLE_LABEL; + case ACC.ROLE_LINK: return ATK.ATK_ROLE_TEXT; + case ACC.ROLE_LIST: return ATK.ATK_ROLE_LIST; + case ACC.ROLE_LISTITEM: return ATK.ATK_ROLE_LIST_ITEM; + case ACC.ROLE_MENU: return ATK.ATK_ROLE_MENU; + case ACC.ROLE_MENUBAR: return ATK.ATK_ROLE_MENU_BAR; + case ACC.ROLE_MENUITEM: return ATK.ATK_ROLE_MENU_ITEM; + case ACC.ROLE_PROGRESSBAR: return ATK.ATK_ROLE_PROGRESS_BAR; + case ACC.ROLE_PUSHBUTTON: return ATK.ATK_ROLE_PUSH_BUTTON; + case ACC.ROLE_SCROLLBAR: return ATK.ATK_ROLE_SCROLL_BAR; + case ACC.ROLE_SEPARATOR: return ATK.ATK_ROLE_SEPARATOR; + case ACC.ROLE_SLIDER: return ATK.ATK_ROLE_SLIDER; + case ACC.ROLE_TABLE: return ATK.ATK_ROLE_TABLE; + case ACC.ROLE_TABLECELL: return ATK.ATK_ROLE_TABLE_CELL; + case ACC.ROLE_TABLECOLUMNHEADER: return ATK.ATK_ROLE_TABLE_COLUMN_HEADER; + case ACC.ROLE_TABLEROWHEADER: return ATK.ATK_ROLE_TABLE_ROW_HEADER; + case ACC.ROLE_TABFOLDER: return ATK.ATK_ROLE_PAGE_TAB_LIST; + case ACC.ROLE_TABITEM: return ATK.ATK_ROLE_PAGE_TAB; + case ACC.ROLE_TEXT: return ATK.ATK_ROLE_TEXT; + case ACC.ROLE_TOOLBAR: return ATK.ATK_ROLE_TOOL_BAR; + case ACC.ROLE_TOOLTIP: return ATK.ATK_ROLE_TOOL_TIP; + case ACC.ROLE_TREE: return ATK.ATK_ROLE_TREE; + case ACC.ROLE_TREEITEM: return ATK.ATK_ROLE_LIST_ITEM; + case ACC.ROLE_RADIOBUTTON: return ATK.ATK_ROLE_RADIO_BUTTON; + case ACC.ROLE_WINDOW: return ATK.ATK_ROLE_WINDOW; + } + } + } + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.get_role is null) return 0; + return objectClass.get_role( object.handle); + } + + package static extern(C) AtkObject* atkObject_ref_child (AtkObject* atkObject, int /*long*/ index) { + if (DEBUG) Stdout.formatln ("-->atkObject_ref_child: {} of: {}", index, atkObject); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + object.updateChildren (); + AccessibleObject accObject = object.getChildByIndex (cast(int)/*64*/index); + if (accObject !is null) { + OS.g_object_ref (accObject.handle); + return accObject.handle; + } + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.ref_child is null) return null; + return objectClass.ref_child( object.handle, index); + } + + package static extern(C) AtkStateSet * atkObject_ref_state_set (AtkObject* atkObject) { + if (DEBUG) Stdout.formatln ("-->atkObject_ref_state_set"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + AtkStateSet* parentResult; + auto objectClass = cast(AtkObjectClass*)ATK.g_type_class_peek (object.parentType); + if (objectClass.ref_state_set !is null) { + parentResult = objectClass.ref_state_set( object.handle); + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return parentResult; + + auto set = parentResult; + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + event.detail = -1; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getState (event); + } + if (event.detail !is -1) { + /* Convert from win32 state values to atk state values */ + int state = event.detail; + if ((state & ACC.STATE_BUSY) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_BUSY); + if ((state & ACC.STATE_CHECKED) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_CHECKED); + if ((state & ACC.STATE_EXPANDED) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_EXPANDED); + if ((state & ACC.STATE_FOCUSABLE) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_FOCUSABLE); + if ((state & ACC.STATE_FOCUSED) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_FOCUSED); + if ((state & ACC.STATE_HOTTRACKED) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_ARMED); + if ((state & ACC.STATE_INVISIBLE) is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_VISIBLE); + if ((state & ACC.STATE_MULTISELECTABLE) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_MULTISELECTABLE); + if ((state & ACC.STATE_OFFSCREEN) is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_SHOWING); + if ((state & ACC.STATE_PRESSED) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_PRESSED); + if ((state & ACC.STATE_READONLY) is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_EDITABLE); + if ((state & ACC.STATE_SELECTABLE) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_SELECTABLE); + if ((state & ACC.STATE_SELECTED) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_SELECTED); + if ((state & ACC.STATE_SIZEABLE) !is 0) ATK.atk_state_set_add_state (set, ATK.ATK_STATE_RESIZABLE); + /* Note: STATE_COLLAPSED, STATE_LINKED and STATE_NORMAL have no ATK equivalents */ + } + return set; + } + + package static extern(C) int atkSelection_is_child_selected (void* obj, int index) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkSelection_is_child_selected"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + int /*long*/ parentResult = 0; + if (ATK.g_type_is_a (object.parentType, ATK_SELECTION_TYPE)) { + auto selectionIface = cast(AtkSelectionIface*)ATK.g_type_interface_peek_parent (ATK.ATK_SELECTION_GET_IFACE (object.handle)); + if (selectionIface.is_child_selected !is null) { + parentResult = selectionIface.is_child_selected( object.handle, index); + } + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getSelection (event); + } + AccessibleObject accessibleObject = object.getChildByID (event.childID); + if (accessibleObject !is null) { + return accessibleObject.index is index ? 1 : 0; + } + return parentResult; + } + + package static extern(C) AtkObject* atkSelection_ref_selection (void* obj, int index) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkSelection_ref_selection"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + AtkObject* parentResult; + if (ATK.g_type_is_a (object.parentType, ATK_SELECTION_TYPE)) { + auto selectionIface = cast(AtkSelectionIface*)ATK.g_type_interface_peek_parent (ATK.ATK_SELECTION_GET_IFACE (object.handle)); + if (selectionIface.ref_selection !is null) { + parentResult = selectionIface.ref_selection( object.handle, index); + } + } + AccessibleControlListener[] listeners = object.getControlListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleControlEvent event = new AccessibleControlEvent (object); + event.childID = object.id; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getSelection (event); + } + AccessibleObject accObj = object.getChildByID (event.childID); + if (accObj !is null) { + if (parentResult !is null) OS.g_object_unref (parentResult); + OS.g_object_ref (accObj.handle); + return accObj.handle; + } + return parentResult; + } + + package static extern(C) int atkText_get_caret_offset (void* obj) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_caret_offset"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + int /*long*/ parentResult = 0; + if (ATK.g_type_is_a (object.parentType, ATK_TEXT_TYPE)) { + auto textIface = cast(AtkTextIface*)ATK.g_type_interface_peek_parent (ATK.ATK_TEXT_GET_IFACE (object.handle)); + if (textIface.get_caret_offset !is null) { + parentResult = textIface.get_caret_offset( object.handle); + } + } + AccessibleTextListener[] listeners = object.getTextListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleTextEvent event = new AccessibleTextEvent (object); + event.childID = object.id; + event.offset = cast(int)/*64*/parentResult; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getCaretOffset (event); + } + return event.offset; + } + + package static extern(C) uint atkText_get_character_at_offset (void* obj, int offset) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_character_at_offset"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + char[] text = object.getText (); + if (text !is null) return text[cast(int)/*64*/offset ]; // TODO + if (ATK.g_type_is_a (object.parentType, ATK_TEXT_TYPE)) { + auto textIface = cast(AtkTextIface*)ATK.g_type_class_peek (object.parentType); + if (textIface.get_character_at_offset !is null) { + return textIface.get_character_at_offset( object.handle, offset); + } + } + return 0; + } + + package static extern(C) int atkText_get_character_count (void* obj) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_character_count"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + char[] text = object.getText (); + if (text !is null) return text.length; + if (ATK.g_type_is_a (object.parentType, ATK_TEXT_TYPE)) { + auto textIface = cast(AtkTextIface*)ATK.g_type_class_peek (object.parentType); + if (textIface.get_character_count !is null) { + return textIface.get_character_count( object.handle); + } + } + return 0; + } + + package static extern(C) int atkText_get_n_selections (void* obj) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln("-->atkText_get_n_selections"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return 0; + int /*long*/ parentResult = 0; + if (ATK.g_type_is_a (object.parentType, ATK_TEXT_TYPE)) { + auto textIface = cast(AtkTextIface*)ATK.g_type_interface_peek_parent (ATK.ATK_TEXT_GET_IFACE (object.handle)); + if (textIface.get_n_selections !is null) { + parentResult = textIface.get_n_selections( object.handle); + } + } + AccessibleTextListener[] listeners = object.getTextListeners (); + if (listeners.length is 0) return parentResult; + + AccessibleTextEvent event = new AccessibleTextEvent (object); + event.childID = object.id; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getSelectionRange (event); + } + return event.length is 0 ? parentResult : 1; + } + + package static extern(C) char* atkText_get_selection (void* obj, int selection_num, int* start_offset, int* end_offset) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_selection"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + *start_offset=0; + *end_offset=0; + if (ATK.g_type_is_a (object.parentType, ATK_TEXT_TYPE)) { + auto textIface = cast(AtkTextIface*)ATK.g_type_interface_peek_parent (ATK.ATK_TEXT_GET_IFACE (object.handle)); + if (textIface.get_selection !is null) { + textIface.get_selection( object.handle, selection_num, start_offset, end_offset ); + } + } + AccessibleTextListener[] listeners = object.getTextListeners (); + if (listeners.length is 0) return null; + + AccessibleTextEvent event = new AccessibleTextEvent (object); + event.childID = object.id; + int parentStart; + int parentEnd; + parentStart= *start_offset; + parentEnd= *end_offset; + event.offset = parentStart; + event.length = parentEnd - parentStart; + for (int i = 0; i < listeners.length; i++) { + listeners [i].getSelectionRange (event); + } + *start_offset = event.offset; + *end_offset = event.offset + event.length; + return null; + } + + package static extern(C) char* atkText_get_text (void* obj, int start_offset, int end_offset) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_text: {},{}", start_offset, end_offset); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + char[] text = object.getText (); + if (text.length > 0) { + if (end_offset is -1) { + end_offset = text.length ; + } else { + end_offset = Math.min (end_offset, text.length ); + } + start_offset = Math.min (start_offset, end_offset); + text = text[ start_offset .. end_offset ]; + auto result = cast(char*)OS.g_malloc (text.length+1); + result[ 0 .. text.length ] = text; + result[ text.length ] = '\0'; + return result; + } + return null; + } + + package static extern(C) char* atkText_get_text_after_offset (void* obj, int offset_value, int boundary_type, int* start_offset, int* end_offset) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_text_after_offset"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + int offset = cast(int)/*64*/offset_value; + char[] text = object.getText (); + if (text.length > 0) { + int length = text.length ; + offset = Math.min (offset, length - 1); + int startBounds = offset; + int endBounds = offset; + switch (cast(int)/*64*/boundary_type) { + case ATK.ATK_TEXT_BOUNDARY_CHAR: { + if (length > offset) endBounds++; + break; + } + case ATK.ATK_TEXT_BOUNDARY_WORD_START: { + int wordStart1 = nextIndexOfChar (text, " !?.\n", offset - 1); + if (wordStart1 is -1) { + startBounds = endBounds = length; + break; + } + wordStart1 = nextIndexOfNotChar (text, " !?.\n", wordStart1); + if (wordStart1 is length) { + startBounds = endBounds = length; + break; + } + startBounds = wordStart1; + int wordStart2 = nextIndexOfChar (text, " !?.\n", wordStart1); + if (wordStart2 is -1) { + endBounds = length; + break; + } + endBounds = nextIndexOfNotChar (text, " !?.\n", wordStart2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_WORD_END: { + int previousWordEnd = previousIndexOfNotChar (text, " \n", offset); + if (previousWordEnd is -1 || previousWordEnd !is offset - 1) { + offset = nextIndexOfNotChar (text, " \n", offset); + } + if (offset is -1) { + startBounds = endBounds = length; + break; + } + int wordEnd1 = nextIndexOfChar (text, " !?.\n", cast(int)/*64*/offset); + if (wordEnd1 is -1) { + startBounds = endBounds = length; + break; + } + wordEnd1 = nextIndexOfNotChar (text, "!?.", wordEnd1); + if (wordEnd1 is length) { + startBounds = endBounds = length; + break; + } + startBounds = wordEnd1; + int wordEnd2 = nextIndexOfNotChar (text, " \n", wordEnd1); + if (wordEnd2 is length) { + startBounds = endBounds = length; + break; + } + wordEnd2 = nextIndexOfChar (text, " !?.\n", wordEnd2); + if (wordEnd2 is -1) { + endBounds = length; + break; + } + endBounds = nextIndexOfNotChar (text, "!?.", wordEnd2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_SENTENCE_START: { + int previousSentenceEnd = previousIndexOfChar (text, "!?.", offset); + int previousText = previousIndexOfNotChar (text, " !?.\n", offset); + int sentenceStart1 = 0; + if (previousSentenceEnd >= previousText) { + sentenceStart1 = nextIndexOfNotChar (text, " !?.\n", offset); + } else { + sentenceStart1 = nextIndexOfChar (text, "!?.", offset); + if (sentenceStart1 is -1) { + startBounds = endBounds = length; + break; + } + sentenceStart1 = nextIndexOfNotChar (text, " !?.\n", sentenceStart1); + } + if (sentenceStart1 is length) { + startBounds = endBounds = length; + break; + } + startBounds = sentenceStart1; + int sentenceStart2 = nextIndexOfChar (text, "!?.", sentenceStart1); + if (sentenceStart2 is -1) { + endBounds = length; + break; + } + endBounds = nextIndexOfNotChar (text, " !?.\n", sentenceStart2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_SENTENCE_END: { + int sentenceEnd1 = nextIndexOfChar (text, "!?.", offset); + if (sentenceEnd1 is -1) { + startBounds = endBounds = length; + break; + } + sentenceEnd1 = nextIndexOfNotChar (text, "!?.", sentenceEnd1); + if (sentenceEnd1 is length) { + startBounds = endBounds = length; + break; + } + startBounds = sentenceEnd1; + int sentenceEnd2 = nextIndexOfNotChar (text, " \n", sentenceEnd1); + if (sentenceEnd2 is length) { + startBounds = endBounds = length; + break; + } + sentenceEnd2 = nextIndexOfChar (text, "!?.", sentenceEnd2); + if (sentenceEnd2 is -1) { + endBounds = length; + break; + } + endBounds = nextIndexOfNotChar (text, "!?.", sentenceEnd2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_LINE_START: { + int lineStart1 = locate( text, '\n' ); + if( lineStart1 == text.length ) lineStart1 = -1; + if (lineStart1 is -1) { + startBounds = endBounds = length; + break; + } + lineStart1 = nextIndexOfNotChar (text, "\n", lineStart1); + if (lineStart1 is length) { + startBounds = endBounds = length; + break; + } + startBounds = lineStart1; + int lineStart2 = locate( text, '\n' ); + if( lineStart2 == text.length ) lineStart2 = -1; + if (lineStart2 is -1) { + endBounds = length; + break; + } + lineStart2 = nextIndexOfNotChar (text, "\n", lineStart2); + endBounds = lineStart2; + break; + } + case ATK.ATK_TEXT_BOUNDARY_LINE_END: { + int lineEnd1 = nextIndexOfChar (text, "\n", offset); + if (lineEnd1 is -1) { + startBounds = endBounds = length; + break; + } + startBounds = lineEnd1; + if (startBounds is length) { + endBounds = length; + break; + } + int lineEnd2 = nextIndexOfChar (text, "\n", lineEnd1 + 1); + if (lineEnd2 is -1) { + endBounds = length; + break; + } + endBounds = lineEnd2; + break; + } + } + *start_offset=startBounds; + *end_offset=endBounds; + text = text[startBounds .. endBounds ]; + auto result = cast(char*)OS.g_malloc (text.length+1); + result[ 0 .. text.length ] = text; + result[ text.length ] = '\0'; + return result; + } + return null; + } + + package static extern(C) char* atkText_get_text_at_offset (void* obj, int offset_value, int boundary_type, int* start_offset, int* end_offset) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_text_at_offset: {} start: {} end: {}", offset_value, start_offset, end_offset); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + int offset = offset_value; + char[] text = object.getText (); + if (text.length > 0) { + int length = text.length; + offset = Math.min (offset, length - 1); + int startBounds = offset; + int endBounds = offset; + switch (boundary_type) { + case ATK.ATK_TEXT_BOUNDARY_CHAR: { + if (length > offset) endBounds++; + break; + } + case ATK.ATK_TEXT_BOUNDARY_WORD_START: { + int wordStart1 = previousIndexOfNotChar (text, " !?.\n", offset); + if (wordStart1 is -1) { + startBounds = endBounds = 0; + break; + } + wordStart1 = previousIndexOfChar (text, " !?.\n", wordStart1) + 1; + if (wordStart1 is -1) { + startBounds = 0; + break; + } + startBounds = wordStart1; + int wordStart2 = nextIndexOfChar (text, " !?.\n", wordStart1); + endBounds = nextIndexOfNotChar (text, " !?.\n", wordStart2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_WORD_END: { + int wordEnd1 = previousIndexOfNotChar (text, "!?.", offset + 1); + wordEnd1 = previousIndexOfChar (text, " !?.\n", wordEnd1); + wordEnd1 = previousIndexOfNotChar (text, " \n", wordEnd1 + 1); + if (wordEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + startBounds = wordEnd1 + 1; + int wordEnd2 = nextIndexOfNotChar (text, " \n", startBounds); + if (wordEnd2 is length) { + endBounds = startBounds; + break; + } + wordEnd2 = nextIndexOfChar (text, " !?.\n", wordEnd2); + if (wordEnd2 is -1) { + endBounds = startBounds; + break; + } + endBounds = nextIndexOfNotChar (text, "!?.", wordEnd2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_SENTENCE_START: { + int sentenceStart1 = previousIndexOfNotChar (text, " !?.\n", offset + 1); + if (sentenceStart1 is -1) { + startBounds = endBounds = 0; + break; + } + sentenceStart1 = previousIndexOfChar (text, "!?.", sentenceStart1) + 1; + startBounds = nextIndexOfNotChar (text, " \n", sentenceStart1); + int sentenceStart2 = nextIndexOfChar (text, "!?.", startBounds); + endBounds = nextIndexOfNotChar (text, " !?.\n", sentenceStart2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_SENTENCE_END: { + int sentenceEnd1 = previousIndexOfNotChar (text, "!?.", offset + 1); + sentenceEnd1 = previousIndexOfChar (text, "!?.", sentenceEnd1); + sentenceEnd1 = previousIndexOfNotChar (text, " \n", sentenceEnd1 + 1); + if (sentenceEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + startBounds = sentenceEnd1 + 1; + int sentenceEnd2 = nextIndexOfNotChar (text, " \n", startBounds); + if (sentenceEnd2 is length) { + endBounds = startBounds; + break; + } + sentenceEnd2 = nextIndexOfChar (text, "!?.", sentenceEnd2); + if (sentenceEnd2 is -1) { + endBounds = startBounds; + break; + } + endBounds = nextIndexOfNotChar (text, "!?.", sentenceEnd2); + break; + } + case ATK.ATK_TEXT_BOUNDARY_LINE_START: { + startBounds = previousIndexOfChar (text, "\n", offset) + 1; + int lineEnd2 = nextIndexOfChar (text, "\n", startBounds); + if (lineEnd2 < length) lineEnd2++; + endBounds = lineEnd2; + break; + } + case ATK.ATK_TEXT_BOUNDARY_LINE_END: { + int lineEnd1 = previousIndexOfChar (text, "\n", offset); + if (lineEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + startBounds = lineEnd1; + endBounds = nextIndexOfChar (text, "\n", lineEnd1 + 1); + } + } + *start_offset=startBounds; + *end_offset=endBounds; + text = text[startBounds .. endBounds]; + auto result = cast(char*) OS.g_malloc (text.length+1); + result[ 0 .. text.length ] = text; + result[ text.length ] = '\0'; + return result; + } + return null; + } + + package static extern(C) char* atkText_get_text_before_offset (void* obj, int offset_value, int boundary_type, int* start_offset, int* end_offset) { + auto atkObject = cast(AtkObject*)obj; + if (DEBUG) Stdout.formatln ("-->atkText_get_text_before_offset"); + AccessibleObject object = getAccessibleObject (atkObject); + if (object is null) return null; + int offset = offset_value; + char[] text = object.getText (); + if (text.length > 0) { + int length = text.length; + offset = Math.min (offset, length - 1); + int startBounds = offset; + int endBounds = offset; + switch (boundary_type) { + case ATK.ATK_TEXT_BOUNDARY_CHAR: { + if (length >= offset && offset > 0) startBounds--; + break; + } + case ATK.ATK_TEXT_BOUNDARY_WORD_START: { + int wordStart1 = previousIndexOfChar (text, " !?.\n", offset - 1); + if (wordStart1 is -1) { + startBounds = endBounds = 0; + break; + } + int wordStart2 = previousIndexOfNotChar (text, " !?.\n", wordStart1); + if (wordStart2 is -1) { + startBounds = endBounds = 0; + break; + } + endBounds = wordStart1 + 1; + startBounds = previousIndexOfChar (text, " !?.\n", wordStart2) + 1; + break; + } + case ATK.ATK_TEXT_BOUNDARY_WORD_END: { + int wordEnd1 =previousIndexOfChar (text, " !?.\n", offset); + if (wordEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + wordEnd1 = previousIndexOfNotChar (text, " \n", wordEnd1 + 1); + if (wordEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + endBounds = wordEnd1 + 1; + int wordEnd2 = previousIndexOfNotChar (text, " !?.\n", endBounds); + wordEnd2 = previousIndexOfChar (text, " !?.\n", wordEnd2); + if (wordEnd2 is -1) { + startBounds = 0; + break; + } + startBounds = previousIndexOfNotChar (text, " \n", wordEnd2 + 1) + 1; + break; + } + case ATK.ATK_TEXT_BOUNDARY_SENTENCE_START: { + int sentenceStart1 = previousIndexOfChar (text, "!?.", offset); + if (sentenceStart1 is -1) { + startBounds = endBounds = 0; + break; + } + int sentenceStart2 = previousIndexOfNotChar (text, "!?.", sentenceStart1); + if (sentenceStart2 is -1) { + startBounds = endBounds = 0; + break; + } + endBounds = sentenceStart1 + 1; + startBounds = previousIndexOfChar (text, "!?.", sentenceStart2) + 1; + break; + } + case ATK.ATK_TEXT_BOUNDARY_SENTENCE_END: { + int sentenceEnd1 = previousIndexOfChar (text, "!?.", offset); + if (sentenceEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + sentenceEnd1 = previousIndexOfNotChar (text, " \n", sentenceEnd1 + 1); + if (sentenceEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + endBounds = sentenceEnd1 + 1; + int sentenceEnd2 = previousIndexOfNotChar (text, "!?.", endBounds); + sentenceEnd2 = previousIndexOfChar (text, "!?.", sentenceEnd2); + if (sentenceEnd2 is -1) { + startBounds = 0; + break; + } + startBounds = previousIndexOfNotChar (text, " \n", sentenceEnd2 + 1) + 1; + break; + } + case ATK.ATK_TEXT_BOUNDARY_LINE_START: { + int lineStart1 = previousIndexOfChar (text, "\n", offset); + if (lineStart1 is -1) { + startBounds = endBounds = 0; + break; + } + endBounds = lineStart1 + 1; + startBounds = previousIndexOfChar (text, "\n", lineStart1) + 1; + break; + } + case ATK.ATK_TEXT_BOUNDARY_LINE_END: { + int lineEnd1 = previousIndexOfChar (text, "\n", offset); + if (lineEnd1 is -1) { + startBounds = endBounds = 0; + break; + } + endBounds = lineEnd1; + startBounds = previousIndexOfChar (text, "\n", lineEnd1); + if (startBounds is -1) startBounds = 0; + break; + } + } + *start_offset=startBounds; + *end_offset=endBounds; + text = text[startBounds .. endBounds]; + auto result = cast(char*)OS.g_malloc (text.length+1); + result[ 0 .. text.length ] = text; + result[ text.length ] = '\0'; + return result; + } + return null; + } + + AccessibleListener[] getAccessibleListeners () { + if (accessible is null) return new AccessibleListener [0]; + AccessibleListener[] result = accessible.getAccessibleListeners (); + return result !is null ? result : new AccessibleListener [0]; + } + + static AccessibleObject getAccessibleObject (AtkObject* atkObject) { + return AccessibleObjects[atkObject]; + } + + AccessibleObject getChildByHandle (AtkObject* handle) { + return children[handle]; + } + + AccessibleObject getChildByID (int childId) { + if (childId is ACC.CHILDID_SELF) return this; + foreach( object; children ){ + if (object.id is childId) return object; + } + return null; + } + + AccessibleObject getChildByIndex (int childIndex) { + foreach( object; children ){ + if (object.index is childIndex) return object; + } + return null; + } + + AccessibleControlListener[] getControlListeners () { + if (accessible is null) return new AccessibleControlListener [0]; + AccessibleControlListener[] result = accessible.getControlListeners (); + return result !is null ? result : new AccessibleControlListener [0]; + } + + char[] getText () { + char* parentResult; + char[] parentText = ""; //$NON-NLS-1$ + if (ATK.g_type_is_a (parentType, ATK_TEXT_TYPE)) { + auto textIface = cast(AtkTextIface*)ATK.g_type_interface_peek_parent (ATK.ATK_TEXT_GET_IFACE (handle)); + int /*long*/ characterCount = 0; + if (textIface.get_character_count !is null) { + characterCount = textIface.get_character_count( handle); + } + if (characterCount > 0 && textIface.get_text !is null) { + parentResult = textIface.get_text( handle, 0, characterCount); + if (parentResult !is null) { + parentText = fromUtf8z( parentResult ).dup; + } + } + } + AccessibleControlListener[] controlListeners = getControlListeners (); + if (controlListeners.length is 0) return parentText; + AccessibleControlEvent event = new AccessibleControlEvent (this); + event.childID = id; + event.result = parentText; + for (int i = 0; i < controlListeners.length; i++) { + controlListeners [i].getValue (event); + } + return event.result; + } + + AccessibleTextListener[] getTextListeners () { + if (accessible is null) return new AccessibleTextListener [0]; + AccessibleTextListener[] result = accessible.getTextListeners (); + return result !is null ? result : new AccessibleTextListener [0]; + } + + private static extern(C) void gObjectClass_finalize (GObject* atkObject) { + auto superType = ATK.g_type_class_peek_parent (ATK.G_OBJECT_GET_CLASS (cast(GTypeInstance*)atkObject)); + auto objectClassStruct = cast(GObjectClass*)ATK.G_OBJECT_CLASS (cast(GTypeClass*)superType); + objectClassStruct.finalize(atkObject); + AccessibleObject object = getAccessibleObject (cast(AtkObject*)atkObject); + if (object !is null) { + AccessibleObjects.remove (cast(AtkObject*)atkObject); + object.release (); + } + } + + static int nextIndexOfChar (char[] string, char[] searchChars, int startIndex) { + int result = string.length; + for (int i = 0; i < searchChars.length; i++) { + char current = searchChars[i]; + int index = locate( string, current, startIndex ); + if (index !is string.length ) result = Math.min (result, index); + } + return result; + } + + static int nextIndexOfNotChar (char[] string, char[] searchChars, int startIndex) { + int length = string.length; + int index = startIndex; + while (index < length) { + char current = string[index]; + if ( !contains( searchChars, current)) break; + index++; + } + return index; + } + + static int previousIndexOfChar (char[] string, char[] searchChars, int startIndex) { + int result = -1; + if (startIndex < 0) return result; + string = string[0 .. startIndex]; + for (int i = 0; i < searchChars.length ; i++) { + char current = searchChars[i]; + int index = locatePrior( string, current); + if (index !is string.length ) result = Math.max (result, index); + } + return result; + } + + static int previousIndexOfNotChar (char[] string, char[] searchChars, int startIndex) { + if (startIndex < 0) return -1; + int index = startIndex - 1; + while (index >= 0) { + char current = string[index]; + if ( !contains(searchChars, current)) break; + index--; + } + return index; + } + + void release () { + if (DEBUG) Stdout.formatln("AccessibleObject.release: {}", handle); + accessible = null; + foreach( child; children ){ + if (child.isLightweight) OS.g_object_unref (child.handle); + } + if (parent !is null) parent.removeChild (this, false); + } + + void removeChild (AccessibleObject child, bool unref) { + children.remove (child.handle); + if (unref && child.isLightweight) OS.g_object_unref (child.handle); + } + + void selectionChanged () { + OS.g_signal_emit_by_name0 (handle, ATK.selection_changed.ptr); + } + + void setFocus (int childID) { + updateChildren (); + AccessibleObject accObject = getChildByID (childID); + if (accObject !is null) { + ATK.atk_focus_tracker_notify (accObject.handle); + } + } + + void setParent (AccessibleObject parent) { + this.parent = parent; + } + + void textCaretMoved(int index) { + OS.g_signal_emit_by_name1 (handle, ATK.text_caret_moved.ptr, index); + } + + void textChanged(int type, int startIndex, int length) { + if (type is ACC.TEXT_DELETE) { + OS.g_signal_emit_by_name2 (handle, ATK.text_changed_delete.ptr, startIndex, length); + } else { + OS.g_signal_emit_by_name2 (handle, ATK.text_changed_insert.ptr, startIndex, length); + } + } + + void textSelectionChanged() { + OS.g_signal_emit_by_name0 (handle, ATK.text_selection_changed.ptr); + } + + void updateChildren () { + if (isLightweight) return; + AccessibleControlListener[] listeners = getControlListeners (); + if (listeners.length is 0) return; + + AccessibleControlEvent event = new AccessibleControlEvent (this); + for (int i = 0; i < listeners.length; i++) { + listeners [i].getChildren (event); + } + if (event.children !is null && event.children.length > 0) { + AtkObject*[] idsToKeep = new AtkObject*[]( children.length ); + idsToKeep.length = 0; + if ( null !is (cast(Integer)event.children[0] )) { + /* an array of child id's (Integers) was answered */ + auto parentType = AccessibleFactory.getDefaultParentType (); + for (int i = 0; i < event.children.length; i++) { + AccessibleObject object = getChildByIndex (i); + if (object is null) { + auto childType = AccessibleFactory.getChildType (accessible, i); + object = new AccessibleObject (childType, null, accessible, parentType, true); + AccessibleObjects[object.handle] = object; + addChild (object); + object.index = i; + } + if( auto intChild = cast(Integer)event.children[i] ){ + object.id = intChild.intValue (); + } + else { + /* a non-ID value was given so don't set the ID */ + } + idsToKeep ~= object.handle; + } + } else { + /* an array of Accessible children was answered */ + int childIndex = 0; + for (int i = 0; i < event.children.length; i++) { + AccessibleObject object = null; + if( auto accChild = cast(Accessible)event.children[i] ){ + object = accChild.accessibleObject; + } else { + /* a non-Accessible value was given so nothing to do here */ + } + if (object !is null) { + object.index = childIndex++; + idsToKeep ~= object.handle; + } + } + } + /* remove old children that were not provided as children anymore */ + foreach( id; children.keys ){ + if ( !tango.core.Array.contains( idsToKeep, id )) { + AccessibleObject object = cast(AccessibleObject) children[id]; + removeChild (object, true); + } + } + } + } +}